Initial commit
This commit is contained in:
BIN
miniprogram/services/.DS_Store
vendored
Normal file
BIN
miniprogram/services/.DS_Store
vendored
Normal file
Binary file not shown.
3
miniprogram/services/_utils/delay.js
Normal file
3
miniprogram/services/_utils/delay.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export function delay(ms = 200) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
120
miniprogram/services/_utils/request.js
Normal file
120
miniprogram/services/_utils/request.js
Normal file
@@ -0,0 +1,120 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/**
|
||||
* 网络请求工具函数
|
||||
* @param {Object} options 请求配置
|
||||
* @param {string} options.url 请求地址
|
||||
* @param {string} options.method 请求方法
|
||||
* @param {Object} options.data 请求数据
|
||||
* @param {Object} options.header 请求头
|
||||
*/
|
||||
export function request(options) {
|
||||
const { url, method = 'GET', data = {}, header = {} } = options;
|
||||
|
||||
// 构建完整的请求URL
|
||||
const fullUrl = `${config.apiBase}${url}`;
|
||||
|
||||
// 获取token
|
||||
const token = wx.getStorageSync('token');
|
||||
|
||||
// 设置默认请求头
|
||||
const defaultHeader = {
|
||||
'Content-Type': 'application/json',
|
||||
...header
|
||||
};
|
||||
|
||||
// 如果有token,添加到请求头
|
||||
if (token) {
|
||||
defaultHeader['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: fullUrl,
|
||||
method: method.toUpperCase(),
|
||||
data: data,
|
||||
header: defaultHeader,
|
||||
success: (res) => {
|
||||
console.log(`API请求成功: ${method.toUpperCase()} ${fullUrl}`, res);
|
||||
|
||||
if (res.statusCode === 200) {
|
||||
// 检查业务状态码
|
||||
if (res.data && res.data.code === 200) {
|
||||
resolve(res.data);
|
||||
} else {
|
||||
// 业务错误
|
||||
const errorMsg = res.data?.message || '请求失败';
|
||||
console.error('API业务错误:', errorMsg);
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
} else if (res.statusCode === 401) {
|
||||
// 未授权,清除token并跳转到登录页
|
||||
wx.removeStorageSync('token');
|
||||
wx.showToast({
|
||||
title: '请先登录',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
wx.navigateTo({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
}, 1500);
|
||||
reject(new Error('未授权'));
|
||||
} else {
|
||||
// HTTP错误
|
||||
const errorMsg = `请求失败: ${res.statusCode}`;
|
||||
console.error('API HTTP错误:', errorMsg);
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error(`API请求失败: ${method.toUpperCase()} ${fullUrl}`, error);
|
||||
|
||||
// 网络错误处理
|
||||
let errorMsg = '网络请求失败';
|
||||
if (error.errMsg) {
|
||||
if (error.errMsg.includes('timeout')) {
|
||||
errorMsg = '请求超时,请检查网络连接';
|
||||
} else if (error.errMsg.includes('fail')) {
|
||||
errorMsg = '网络连接失败,请检查网络设置';
|
||||
}
|
||||
}
|
||||
|
||||
wx.showToast({
|
||||
title: errorMsg,
|
||||
icon: 'none'
|
||||
});
|
||||
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* GET请求
|
||||
*/
|
||||
export function get(url, data = {}, header = {}) {
|
||||
return request({ url, method: 'GET', data, header });
|
||||
}
|
||||
|
||||
/**
|
||||
* POST请求
|
||||
*/
|
||||
export function post(url, data = {}, header = {}) {
|
||||
return request({ url, method: 'POST', data, header });
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT请求
|
||||
*/
|
||||
export function put(url, data = {}, header = {}) {
|
||||
return request({ url, method: 'PUT', data, header });
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE请求
|
||||
*/
|
||||
export function del(url, data = {}, header = {}) {
|
||||
return request({ url, method: 'DELETE', data, header });
|
||||
}
|
||||
3
miniprogram/services/_utils/timeout.js
Normal file
3
miniprogram/services/_utils/timeout.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export function timeout(ms = 1000) {
|
||||
return new Promise((_, reject) => setTimeout(reject, ms));
|
||||
}
|
||||
20
miniprogram/services/activity/fetchActivity.js
Normal file
20
miniprogram/services/activity/fetchActivity.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取活动列表 */
|
||||
function mockFetchActivity(ID = 0) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getActivity } = require('../../model/activity');
|
||||
|
||||
return delay().then(() => getActivity(ID));
|
||||
}
|
||||
|
||||
/** 获取活动列表 */
|
||||
export function fetchActivity(ID = 0) {
|
||||
if (config.useMock) {
|
||||
return mockFetchActivity(ID);
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
20
miniprogram/services/activity/fetchActivityList.js
Normal file
20
miniprogram/services/activity/fetchActivityList.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取活动列表 */
|
||||
function mockFetchActivityList(pageIndex = 1, pageSize = 20) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getActivityList } = require('../../model/activities');
|
||||
|
||||
return delay().then(() => getActivityList(pageIndex, pageSize));
|
||||
}
|
||||
|
||||
/** 获取活动列表 */
|
||||
export function fetchActivityList(pageIndex = 1, pageSize = 20) {
|
||||
if (config.useMock) {
|
||||
return mockFetchActivityList(pageIndex, pageSize);
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
33
miniprogram/services/address/edit.js
Normal file
33
miniprogram/services/address/edit.js
Normal file
@@ -0,0 +1,33 @@
|
||||
let addressPromise = [];
|
||||
|
||||
/** 地址编辑Promise */
|
||||
export const getAddressPromise = () => {
|
||||
let resolver;
|
||||
let rejecter;
|
||||
const nextPromise = new Promise((resolve, reject) => {
|
||||
resolver = resolve;
|
||||
rejecter = reject;
|
||||
});
|
||||
|
||||
addressPromise.push({ resolver, rejecter });
|
||||
|
||||
return nextPromise;
|
||||
};
|
||||
|
||||
/** 用户保存了一个地址 */
|
||||
export const resolveAddress = (address) => {
|
||||
const allAddress = [...addressPromise];
|
||||
addressPromise = [];
|
||||
|
||||
|
||||
|
||||
allAddress.forEach(({ resolver }) => resolver(address));
|
||||
};
|
||||
|
||||
/** 取消编辑 */
|
||||
export const rejectAddress = () => {
|
||||
const allAddress = [...addressPromise];
|
||||
addressPromise = [];
|
||||
|
||||
allAddress.forEach(({ rejecter }) => rejecter(new Error('cancel')));
|
||||
};
|
||||
446
miniprogram/services/address/fetchAddress.js
Normal file
446
miniprogram/services/address/fetchAddress.js
Normal file
@@ -0,0 +1,446 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
// 日志工具函数
|
||||
const logger = {
|
||||
info: (tag, message, data = null) => {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.log(`[${timestamp}] [INFO] [${tag}] ${message}`, data ? data : '');
|
||||
},
|
||||
error: (tag, message, error = null) => {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.error(`[${timestamp}] [ERROR] [${tag}] ${message}`, error ? error : '');
|
||||
},
|
||||
warn: (tag, message, data = null) => {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.warn(`[${timestamp}] [WARN] [${tag}] ${message}`, data ? data : '');
|
||||
},
|
||||
debug: (tag, message, data = null) => {
|
||||
const timestamp = new Date().toISOString();
|
||||
if (config.debug) {
|
||||
console.log(`[${timestamp}] [DEBUG] [${tag}] ${message}`, data ? data : '');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 从完整地址中解析区域信息
|
||||
* @param {Object} addressData - 地址数据对象
|
||||
* @returns {Object} 包含区域信息的地址数据
|
||||
*/
|
||||
function parseAddressRegion(addressData) {
|
||||
// 如果已经有区域信息,直接返回
|
||||
if (addressData.provinceName && addressData.cityName && addressData.districtName) {
|
||||
return addressData;
|
||||
}
|
||||
|
||||
// 如果有完整的address字段但缺少区域信息,尝试解析
|
||||
if (addressData.address && !addressData.provinceName) {
|
||||
const fullAddress = addressData.address;
|
||||
const detailAddress = addressData.detailAddress || '';
|
||||
|
||||
// 移除详细地址部分,获取区域部分
|
||||
const regionPart = fullAddress.replace(detailAddress, '');
|
||||
|
||||
logger.debug('ADDRESS_SERVICE', '尝试解析地址区域信息', {
|
||||
fullAddress,
|
||||
detailAddress,
|
||||
regionPart
|
||||
});
|
||||
|
||||
// 简单的区域解析逻辑(可以根据实际需要优化)
|
||||
let provinceName = '', cityName = '', districtName = '';
|
||||
|
||||
// 匹配省份
|
||||
const provinceMatch = regionPart.match(/(.*?[省市])/);
|
||||
if (provinceMatch) {
|
||||
provinceName = provinceMatch[1];
|
||||
const remaining = regionPart.replace(provinceName, '');
|
||||
|
||||
// 匹配城市
|
||||
const cityMatch = remaining.match(/(.*?[市州盟])/);
|
||||
if (cityMatch) {
|
||||
cityName = cityMatch[1];
|
||||
const remaining2 = remaining.replace(cityName, '');
|
||||
|
||||
// 匹配区县
|
||||
const districtMatch = remaining2.match(/(.*?[区县旗])/);
|
||||
if (districtMatch) {
|
||||
districtName = districtMatch[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug('ADDRESS_SERVICE', '地址解析结果', {
|
||||
provinceName,
|
||||
cityName,
|
||||
districtName
|
||||
});
|
||||
|
||||
return {
|
||||
...addressData,
|
||||
provinceName,
|
||||
cityName,
|
||||
districtName
|
||||
};
|
||||
}
|
||||
|
||||
return addressData;
|
||||
}
|
||||
|
||||
/** 获取收货地址 */
|
||||
function mockFetchDeliveryAddress(id) {
|
||||
logger.info('ADDRESS_SERVICE', `开始获取模拟收货地址, ID: ${id}`);
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genAddress } = require('../../model/address');
|
||||
|
||||
return delay().then(() => {
|
||||
const address = genAddress(id);
|
||||
logger.info('ADDRESS_SERVICE', `模拟收货地址获取成功`, { id, address });
|
||||
return address;
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取收货地址 */
|
||||
export function fetchDeliveryAddress(id = 0) {
|
||||
if (config.useMock) {
|
||||
return mockFetchDeliveryAddress(id);
|
||||
}
|
||||
|
||||
const token = wx.getStorageSync('token') || '';
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/users/addresses`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
const addresses = res.data.data || [];
|
||||
// 返回默认地址或第一个地址
|
||||
const defaultAddress = addresses.find(addr => addr.is_default === 1) || addresses[0];
|
||||
|
||||
if (defaultAddress) {
|
||||
// 转换地址数据格式,确保字段名称一致
|
||||
const formattedAddress = {
|
||||
id: defaultAddress.id,
|
||||
addressId: defaultAddress.id,
|
||||
name: defaultAddress.name,
|
||||
phone: defaultAddress.phone,
|
||||
provinceName: defaultAddress.province_name,
|
||||
provinceCode: defaultAddress.province_code,
|
||||
cityName: defaultAddress.city_name,
|
||||
cityCode: defaultAddress.city_code,
|
||||
districtName: defaultAddress.district_name,
|
||||
districtCode: defaultAddress.district_code,
|
||||
detailAddress: defaultAddress.detail_address,
|
||||
isDefault: defaultAddress.is_default === 1,
|
||||
addressTag: defaultAddress.address_tag || '',
|
||||
// 保持向后兼容
|
||||
address: `${defaultAddress.province_name || ''}${defaultAddress.city_name || ''}${defaultAddress.district_name || ''}${defaultAddress.detail_address || ''}`,
|
||||
};
|
||||
|
||||
resolve(formattedAddress);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
} else {
|
||||
logger.error('ADDRESS_SERVICE', '获取收货地址失败', {
|
||||
statusCode: res.statusCode,
|
||||
errorCode: res.data?.code,
|
||||
message: res.data?.message
|
||||
});
|
||||
resolve(null);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
logger.error('ADDRESS_SERVICE', '收货地址请求失败', err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取收货地址列表 */
|
||||
function mockFetchDeliveryAddressList(len = 0) {
|
||||
logger.info('ADDRESS_SERVICE', `开始获取模拟收货地址列表, 长度: ${len}`);
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genAddressList } = require('../../model/address');
|
||||
|
||||
return delay().then(() => {
|
||||
const addressList = genAddressList(len).map((address) => {
|
||||
return {
|
||||
...address,
|
||||
phoneNumber: address.phone,
|
||||
address: `${address.provinceName}${address.cityName}${address.districtName}${address.detailAddress}`,
|
||||
tag: address.addressTag,
|
||||
};
|
||||
});
|
||||
logger.info('ADDRESS_SERVICE', `模拟收货地址列表获取成功`, {
|
||||
count: addressList.length,
|
||||
addresses: addressList.map(addr => ({ id: addr.id, name: addr.name }))
|
||||
});
|
||||
return addressList;
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取收货地址列表 */
|
||||
export function fetchDeliveryAddressList(len = 10) {
|
||||
if (config.useMock) {
|
||||
return mockFetchDeliveryAddressList(len);
|
||||
}
|
||||
|
||||
const token = wx.getStorageSync('token') || '';
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/users/addresses`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
const addresses = res.data.data || [];
|
||||
resolve(addresses);
|
||||
} else {
|
||||
logger.error('ADDRESS_SERVICE', '获取收货地址列表失败', {
|
||||
statusCode: res.statusCode,
|
||||
errorCode: res.data?.code,
|
||||
message: res.data?.message
|
||||
});
|
||||
resolve([]);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
logger.error('ADDRESS_SERVICE', '收货地址列表请求失败', err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建收货地址 */
|
||||
export function createAddress(addressData) {
|
||||
logger.info('ADDRESS_SERVICE', '开始创建收货地址', {
|
||||
name: addressData.name,
|
||||
phone: addressData.phone,
|
||||
province: addressData.province,
|
||||
city: addressData.city,
|
||||
district: addressData.district,
|
||||
isDefault: addressData.isDefault
|
||||
});
|
||||
|
||||
const token = wx.getStorageSync('token') || '';
|
||||
logger.debug('ADDRESS_SERVICE', `准备发起创建地址API请求`, {
|
||||
url: `${config.apiBase}/users/addresses`,
|
||||
hasToken: !!token,
|
||||
tokenLength: token.length,
|
||||
dataKeys: Object.keys(addressData)
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/users/addresses`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: addressData,
|
||||
success: (res) => {
|
||||
logger.debug('ADDRESS_SERVICE', `创建地址API请求响应`, {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
message: res.data?.message
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
logger.info('ADDRESS_SERVICE', '创建收货地址成功', {
|
||||
newAddressId: res.data.data?.id,
|
||||
name: addressData.name
|
||||
});
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
const errorMsg = res.data.message || '创建地址失败';
|
||||
logger.error('ADDRESS_SERVICE', '创建收货地址失败', {
|
||||
statusCode: res.statusCode,
|
||||
errorCode: res.data?.code,
|
||||
message: errorMsg
|
||||
});
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
logger.error('ADDRESS_SERVICE', '创建地址请求失败', err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新收货地址 */
|
||||
export function updateAddress(addressId, addressData) {
|
||||
logger.info('ADDRESS_SERVICE', `开始更新收货地址, ID: ${addressId}`, {
|
||||
addressId,
|
||||
name: addressData.name,
|
||||
phone: addressData.phone,
|
||||
province: addressData.province,
|
||||
city: addressData.city,
|
||||
district: addressData.district,
|
||||
isDefault: addressData.isDefault
|
||||
});
|
||||
|
||||
const token = wx.getStorageSync('token') || '';
|
||||
logger.debug('ADDRESS_SERVICE', `准备发起更新地址API请求`, {
|
||||
url: `${config.apiBase}/users/addresses/${addressId}`,
|
||||
hasToken: !!token,
|
||||
tokenLength: token.length,
|
||||
dataKeys: Object.keys(addressData)
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/users/addresses/${addressId}`,
|
||||
method: 'PUT',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: addressData,
|
||||
success: (res) => {
|
||||
logger.debug('ADDRESS_SERVICE', `更新地址API请求响应`, {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
message: res.data?.message
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
logger.info('ADDRESS_SERVICE', '更新收货地址成功', {
|
||||
addressId,
|
||||
name: addressData.name
|
||||
});
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
const errorMsg = res.data.message || '更新地址失败';
|
||||
logger.error('ADDRESS_SERVICE', '更新收货地址失败', {
|
||||
addressId,
|
||||
statusCode: res.statusCode,
|
||||
errorCode: res.data?.code,
|
||||
message: errorMsg
|
||||
});
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
logger.error('ADDRESS_SERVICE', '更新地址请求失败', { addressId, error: err });
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除收货地址 */
|
||||
export function deleteAddress(addressId) {
|
||||
logger.info('ADDRESS_SERVICE', `开始删除收货地址, ID: ${addressId}`, { addressId });
|
||||
|
||||
const token = wx.getStorageSync('token') || '';
|
||||
logger.debug('ADDRESS_SERVICE', `准备发起删除地址API请求`, {
|
||||
url: `${config.apiBase}/users/addresses/${addressId}`,
|
||||
hasToken: !!token,
|
||||
tokenLength: token.length
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/users/addresses/${addressId}`,
|
||||
method: 'DELETE',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
logger.debug('ADDRESS_SERVICE', `删除地址API请求响应`, {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
message: res.data?.message
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
logger.info('ADDRESS_SERVICE', '删除收货地址成功', { addressId });
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
const errorMsg = res.data.message || '删除地址失败';
|
||||
logger.error('ADDRESS_SERVICE', '删除收货地址失败', {
|
||||
addressId,
|
||||
statusCode: res.statusCode,
|
||||
errorCode: res.data?.code,
|
||||
message: errorMsg
|
||||
});
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
logger.error('ADDRESS_SERVICE', '删除地址请求失败', { addressId, error: err });
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 设置默认地址 */
|
||||
export function setDefaultAddress(addressId) {
|
||||
logger.info('ADDRESS_SERVICE', `开始设置默认收货地址, ID: ${addressId}`, { addressId });
|
||||
|
||||
const token = wx.getStorageSync('token') || '';
|
||||
logger.debug('ADDRESS_SERVICE', `准备发起设置默认地址API请求`, {
|
||||
url: `${config.apiBase}/users/addresses/${addressId}/default`,
|
||||
hasToken: !!token,
|
||||
tokenLength: token.length
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/users/addresses/${addressId}/default`,
|
||||
method: 'PUT',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
logger.debug('ADDRESS_SERVICE', `设置默认地址API请求响应`, {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
message: res.data?.message
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
logger.info('ADDRESS_SERVICE', '设置默认收货地址成功', { addressId });
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
const errorMsg = res.data.message || '设置默认地址失败';
|
||||
logger.error('ADDRESS_SERVICE', '设置默认收货地址失败', {
|
||||
addressId,
|
||||
statusCode: res.statusCode,
|
||||
errorCode: res.data?.code,
|
||||
message: errorMsg
|
||||
});
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
logger.error('ADDRESS_SERVICE', '设置默认地址请求失败', { addressId, error: err });
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fetchDeliveryAddress,
|
||||
fetchDeliveryAddressList,
|
||||
createAddress,
|
||||
updateAddress,
|
||||
deleteAddress,
|
||||
setDefaultAddress,
|
||||
parseAddressRegion,
|
||||
};
|
||||
31
miniprogram/services/address/list.js
Normal file
31
miniprogram/services/address/list.js
Normal file
@@ -0,0 +1,31 @@
|
||||
let addressPromise = [];
|
||||
|
||||
/** 获取一个地址选择Promise */
|
||||
export const getAddressPromise = () => {
|
||||
let resolver;
|
||||
let rejecter;
|
||||
const nextPromise = new Promise((resolve, reject) => {
|
||||
resolver = resolve;
|
||||
rejecter = reject;
|
||||
});
|
||||
|
||||
addressPromise.push({ resolver, rejecter });
|
||||
|
||||
return nextPromise;
|
||||
};
|
||||
|
||||
/** 用户选择了一个地址 */
|
||||
export const resolveAddress = (address) => {
|
||||
const allAddress = [...addressPromise];
|
||||
addressPromise = [];
|
||||
|
||||
allAddress.forEach(({ resolver }) => resolver(address));
|
||||
};
|
||||
|
||||
/** 用户没有选择任何地址只是返回上一页了 */
|
||||
export const rejectAddress = () => {
|
||||
const allAddress = [...addressPromise];
|
||||
addressPromise = [];
|
||||
|
||||
allAddress.forEach(({ rejecter }) => rejecter(new Error('cancel')));
|
||||
};
|
||||
344
miniprogram/services/auth/wechat.js
Normal file
344
miniprogram/services/auth/wechat.js
Normal file
@@ -0,0 +1,344 @@
|
||||
const { config } = require('../../config/index');
|
||||
|
||||
/**
|
||||
* 微信登录服务
|
||||
*/
|
||||
class WeChatAuthService {
|
||||
constructor() {
|
||||
this.apiBase = config.apiBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信授权登录
|
||||
* @param {Object} options - 登录选项
|
||||
* @param {boolean} options.withUserInfo - 是否获取用户信息
|
||||
* @returns {Promise} 登录结果
|
||||
*/
|
||||
async login(options = {}) {
|
||||
const { withUserInfo = false } = options;
|
||||
|
||||
try {
|
||||
// 1. 获取微信登录code
|
||||
const loginResult = await this.getWeChatLoginCode();
|
||||
|
||||
if (withUserInfo) {
|
||||
// 2. 如果需要用户信息,先获取用户信息
|
||||
const userInfo = await this.getUserInfo();
|
||||
return await this.loginWithUserInfo(loginResult.code, userInfo);
|
||||
} else {
|
||||
// 3. 仅使用code登录
|
||||
return await this.loginWithCode(loginResult.code);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('微信登录失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信授权登录
|
||||
* @returns {Promise} 登录结果
|
||||
*/
|
||||
async authorizeLogin(userInfo = null) {
|
||||
try {
|
||||
console.log('开始微信授权登录...');
|
||||
|
||||
// 1. 获取微信登录code
|
||||
const loginResult = await this.getWeChatLoginCode();
|
||||
console.log('获取微信登录code成功:', loginResult.code);
|
||||
|
||||
// 2. 使用一次性 code 完成登录(避免重复获取)
|
||||
let loginData;
|
||||
if (userInfo) {
|
||||
console.log('使用code+用户信息登录');
|
||||
loginData = await this.loginWithUserInfo(loginResult.code, userInfo);
|
||||
} else {
|
||||
console.log('使用code登录');
|
||||
loginData = await this.loginWithCode(loginResult.code);
|
||||
}
|
||||
console.log('登录成功:', loginData);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
...loginData,
|
||||
userInfo: userInfo || null
|
||||
},
|
||||
message: '授权登录成功'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('微信授权登录失败:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: error.message || '授权登录失败'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户资料
|
||||
* @param {Object} userInfo - 用户信息对象
|
||||
* @returns {Promise} 更新结果
|
||||
*/
|
||||
async updateUserProfile(userInfo) {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('开始更新用户资料...');
|
||||
console.log('用户信息:', userInfo);
|
||||
console.log('API地址:', `${this.apiBase}/users/profile`);
|
||||
console.log('Token:', wx.getStorageSync('token'));
|
||||
|
||||
wx.request({
|
||||
url: `${this.apiBase}/users/profile`,
|
||||
method: 'PUT',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token')}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: {
|
||||
nickname: userInfo.nickName || userInfo.nickname,
|
||||
avatar: userInfo.avatarUrl || userInfo.avatar,
|
||||
gender: userInfo.gender || 0,
|
||||
phone: userInfo.phoneNumber || userInfo.phone,
|
||||
email: userInfo.email
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
console.log('用户资料更新成功:', res.data);
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '更新用户资料失败'));
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('更新用户资料失败:', error);
|
||||
reject(new Error(`网络请求失败: ${error.errMsg}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信登录code(临时登录凭证)
|
||||
* 按照微信官方文档标准实现
|
||||
* @returns {Promise} 登录结果
|
||||
*/
|
||||
getWeChatLoginCode() {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.login({
|
||||
success: (res) => {
|
||||
if (res.code) {
|
||||
console.log('获取微信登录code成功:', res.code);
|
||||
// 验证code格式(微信code通常是32位字符串)
|
||||
if (res.code.length < 10) {
|
||||
reject(new Error('获取的登录凭证格式异常'));
|
||||
return;
|
||||
}
|
||||
resolve(res);
|
||||
} else {
|
||||
console.error('wx.login成功但未返回code');
|
||||
reject(new Error('获取微信登录凭证失败'));
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('wx.login调用失败:', error);
|
||||
reject(new Error(`微信登录失败: ${error.errMsg || '未知错误'}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息(新版本兼容方式)
|
||||
* 由于getUserProfile已废弃,现在使用头像昵称填写组件或直接跳过用户信息获取
|
||||
* @returns {Promise} 用户信息
|
||||
*/
|
||||
getUserInfo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 由于getUserProfile已废弃,我们提供一个默认的用户信息结构
|
||||
// 实际的头像和昵称应该通过头像昵称填写组件获取
|
||||
console.log('注意:getUserProfile API已废弃,建议使用头像昵称填写组件');
|
||||
|
||||
// 返回一个基础的用户信息结构
|
||||
const defaultUserInfo = {
|
||||
nickName: '微信用户',
|
||||
avatarUrl: '', // 空头像,后续可通过头像组件更新
|
||||
gender: 0,
|
||||
country: '',
|
||||
province: '',
|
||||
city: ''
|
||||
};
|
||||
|
||||
console.log('使用默认用户信息:', defaultUserInfo);
|
||||
resolve(defaultUserInfo);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过头像昵称组件获取用户信息
|
||||
* @param {Object} userInfo - 从头像昵称组件获取的用户信息
|
||||
* @returns {Promise} 处理后的用户信息
|
||||
*/
|
||||
getUserInfoFromComponent(userInfo) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
// 验证用户信息
|
||||
if (!userInfo) {
|
||||
reject(new Error('用户信息不能为空'));
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建标准的用户信息格式
|
||||
const standardUserInfo = {
|
||||
nickName: userInfo.nickName || '微信用户',
|
||||
avatarUrl: userInfo.avatarUrl || '',
|
||||
gender: userInfo.gender || 0,
|
||||
country: userInfo.country || '',
|
||||
province: userInfo.province || '',
|
||||
city: userInfo.city || ''
|
||||
};
|
||||
|
||||
console.log('从组件获取用户信息成功:', standardUserInfo);
|
||||
resolve(standardUserInfo);
|
||||
} catch (error) {
|
||||
console.error('处理用户信息失败:', error);
|
||||
reject(new Error('处理用户信息失败'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用code登录
|
||||
* @param {string} code - 微信登录code
|
||||
* @returns {Promise} 登录结果
|
||||
*/
|
||||
loginWithCode(code) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${this.apiBase}/users/wechat-login`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
code: code
|
||||
},
|
||||
header: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
const result = res.data.data;
|
||||
// 保存token到本地存储
|
||||
if (result.token) {
|
||||
wx.setStorageSync('token', result.token);
|
||||
wx.setStorageSync('jwt_token', result.token);
|
||||
}
|
||||
resolve(result);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '登录失败'));
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
reject(new Error(`网络请求失败: ${error.errMsg}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用code和用户信息登录
|
||||
* @param {string} code - 微信登录code
|
||||
* @param {Object} userInfo - 用户信息
|
||||
* @returns {Promise} 登录结果
|
||||
*/
|
||||
loginWithUserInfo(code, userInfo) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${this.apiBase}/users/wechat-login`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
code: code,
|
||||
userInfo: {
|
||||
nickName: userInfo.nickName,
|
||||
avatarUrl: userInfo.avatarUrl,
|
||||
gender: userInfo.gender,
|
||||
country: userInfo.country,
|
||||
province: userInfo.province,
|
||||
city: userInfo.city
|
||||
}
|
||||
},
|
||||
header: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
const result = res.data.data;
|
||||
// 保存token到本地存储
|
||||
if (result.token) {
|
||||
wx.setStorageSync('token', result.token);
|
||||
wx.setStorageSync('jwt_token', result.token);
|
||||
}
|
||||
resolve(result);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '登录失败'));
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
reject(new Error(`网络请求失败: ${error.errMsg}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信会话信息
|
||||
* @returns {Promise} 会话信息
|
||||
*/
|
||||
getWeChatSession() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
reject(new Error('未找到登录token'));
|
||||
return;
|
||||
}
|
||||
|
||||
wx.request({
|
||||
url: `${this.apiBase}/users/wechat-session`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '获取会话信息失败'));
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
reject(new Error(`网络请求失败: ${error.errMsg}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查登录状态
|
||||
* @returns {boolean} 是否已登录
|
||||
*/
|
||||
isLoggedIn() {
|
||||
const token = wx.getStorageSync('token');
|
||||
return !!token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
logout() {
|
||||
wx.removeStorageSync('token');
|
||||
wx.removeStorageSync('jwt_token');
|
||||
}
|
||||
}
|
||||
|
||||
// 创建单例实例
|
||||
const weChatAuthService = new WeChatAuthService();
|
||||
|
||||
module.exports = weChatAuthService;
|
||||
274
miniprogram/services/cart/cart.js
Normal file
274
miniprogram/services/cart/cart.js
Normal file
@@ -0,0 +1,274 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取购物车mock数据 */
|
||||
function mockFetchCartGroupData(params) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genCartGroupData } = require('../../model/cart');
|
||||
|
||||
return delay().then(() => genCartGroupData(params));
|
||||
}
|
||||
|
||||
/** 获取购物车数据 */
|
||||
export function fetchCartGroupData(params) {
|
||||
if (config.useMock) {
|
||||
return mockFetchCartGroupData(params);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/cart`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token') || ''}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
// 转换后端数据格式为前端期望的格式
|
||||
const cartItems = res.data.data.items || [];
|
||||
const cartData = {
|
||||
isNotEmpty: cartItems.length > 0,
|
||||
storeGoods: [{
|
||||
storeId: '1',
|
||||
storeName: '默认店铺',
|
||||
storeStatus: 1,
|
||||
isSelected: true,
|
||||
storeStockShortage: false,
|
||||
shortageGoodsList: [],
|
||||
promotionGoodsList: [{
|
||||
title: '普通商品',
|
||||
promotionCode: 'NORMAL',
|
||||
promotionId: '1',
|
||||
tagText: [],
|
||||
promotionStatus: 1,
|
||||
tag: '',
|
||||
description: '',
|
||||
doorSillRemain: null,
|
||||
isNeedAddOnShop: 0,
|
||||
goodsPromotionList: cartItems.map(item => ({
|
||||
uid: item.id.toString(),
|
||||
saasId: '1',
|
||||
storeId: '1',
|
||||
spuId: item.product_id.toString(),
|
||||
skuId: item.sku_id ? item.sku_id.toString() : item.product_id.toString(),
|
||||
isSelected: item.selected ? 1 : 0,
|
||||
thumb: item.product?.main_image || item.product?.image || 'https://tdesign.gtimg.com/miniprogram/template/retail/goods/default.png',
|
||||
title: item.product?.name || '商品名称',
|
||||
primaryImage: item.product?.main_image || item.product?.image || 'https://tdesign.gtimg.com/miniprogram/template/retail/goods/default.png',
|
||||
quantity: item.quantity,
|
||||
stockStatus: true,
|
||||
stockQuantity: item.product?.stock || 999,
|
||||
// 修复:优先使用SKU价格,如果没有SKU价格则使用SPU价格
|
||||
price: item.sku?.price || item.product?.price || '0',
|
||||
originPrice: item.sku?.original_price || item.product?.original_price || item.sku?.price || item.product?.price || '0',
|
||||
tagPrice: null,
|
||||
titlePrefixTags: [],
|
||||
roomId: null,
|
||||
specInfo: item.sku && item.sku.spec_values ?
|
||||
Object.entries(item.sku.spec_values).map(([key, value]) => ({ specTitle: key, specValue: value })) :
|
||||
[],
|
||||
specs: item.sku && item.sku.spec_values ?
|
||||
Object.values(item.sku.spec_values) :
|
||||
[],
|
||||
joinCartTime: item.created_at,
|
||||
available: 1,
|
||||
putOnSale: 1,
|
||||
etitle: null,
|
||||
}))
|
||||
}]
|
||||
}],
|
||||
isAllSelected: cartItems.every(item => item.selected),
|
||||
selectedGoodsCount: cartItems.filter(item => item.selected).reduce((sum, item) => sum + item.quantity, 0),
|
||||
// 修复:总金额计算使用SKU价格,而不是SPU价格
|
||||
totalAmount: cartItems.filter(item => item.selected).reduce((sum, item) => {
|
||||
const price = parseInt(item.sku?.price || item.product?.price || 0);
|
||||
return sum + price * item.quantity;
|
||||
}, 0).toString(),
|
||||
totalDiscountAmount: '0',
|
||||
invalidGoodItems: []
|
||||
};
|
||||
resolve({ data: cartData });
|
||||
} else {
|
||||
reject(new Error(res.data.message || '获取购物车失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 添加商品到购物车 */
|
||||
export function addToCart(productId, skuId, quantity) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/cart`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token') || ''}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: {
|
||||
product_id: parseInt(productId) || 0,
|
||||
sku_id: skuId ? parseInt(skuId) : 0,
|
||||
quantity: parseInt(quantity) || 1
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '添加到购物车失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新购物车商品数量
|
||||
* @param {number} productId - 商品ID
|
||||
* @param {number} quantity - 数量
|
||||
* @param {number} skuId - SKU ID(可选)
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function updateCartItem(productId, quantity, skuId = null) {
|
||||
const data = { quantity };
|
||||
if (skuId) {
|
||||
data.sku_id = parseInt(skuId);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/cart/${productId}`,
|
||||
method: 'PUT',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token') || ''}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '更新购物车失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除购物车商品
|
||||
* @param {number} productId - 商品ID
|
||||
* @param {number} skuId - SKU ID(可选)
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function removeFromCart(productId, skuId = null) {
|
||||
let url = `${config.apiBase}/cart/${productId}`;
|
||||
if (skuId) {
|
||||
url += `?sku_id=${skuId}`;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url,
|
||||
method: 'DELETE',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token') || ''}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '删除商品失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 选择/取消选择购物车商品 */
|
||||
export function selectCartItem(cartId, selected) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/cart/${cartId}/select`,
|
||||
method: 'PUT',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token') || ''}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: {
|
||||
selected: selected
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '操作失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 全选/取消全选购物车商品 */
|
||||
export function selectAllCartItems(selected) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/cart/select-all`,
|
||||
method: 'PUT',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token') || ''}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: {
|
||||
selected: selected
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '操作失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 清空购物车 */
|
||||
export function clearCart() {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/cart`,
|
||||
method: 'DELETE',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token') || ''}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '清空购物车失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
84
miniprogram/services/comments/commentActions.js
Normal file
84
miniprogram/services/comments/commentActions.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 点赞/取消点赞评论 */
|
||||
export function toggleCommentLike(commentId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
reject(new Error('请先登录'));
|
||||
return;
|
||||
}
|
||||
|
||||
wx.request({
|
||||
url: `${config.apiBaseUrl}/comments/${commentId}/like`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '操作失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 回复评论 */
|
||||
export function replyComment(commentId, content) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
reject(new Error('请先登录'));
|
||||
return;
|
||||
}
|
||||
|
||||
wx.request({
|
||||
url: `${config.apiBaseUrl}/comments/${commentId}/reply`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: {
|
||||
content: content
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '回复失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取评论详情 */
|
||||
export function fetchCommentDetail(commentId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBaseUrl}/comments/${commentId}`,
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '获取评论详情失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
179
miniprogram/services/comments/createComment.js
Normal file
179
miniprogram/services/comments/createComment.js
Normal file
@@ -0,0 +1,179 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 创建商品评论 */
|
||||
export function createComment(commentData) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 获取用户token
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
reject(new Error('请先登录'));
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果有orderItemId,直接使用原有逻辑
|
||||
if (commentData.orderItemId) {
|
||||
wx.request({
|
||||
url: `${config.apiBaseUrl}/comments`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: {
|
||||
order_item_id: commentData.orderItemId,
|
||||
rating: commentData.rating,
|
||||
content: commentData.content,
|
||||
images: commentData.images || [],
|
||||
is_anonymous: commentData.isAnonymous || false
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '评论提交失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果有orderNo和productId,先查找对应的订单项
|
||||
if (commentData.orderNo && commentData.productId) {
|
||||
// 先获取订单详情,找到对应的订单项
|
||||
wx.request({
|
||||
url: `${config.apiBaseUrl}/orders/${commentData.orderNo}`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (orderRes) => {
|
||||
if (orderRes.statusCode === 200 && orderRes.data.code === 200) {
|
||||
const order = orderRes.data.data;
|
||||
// 调试:打印关键信息
|
||||
console.log('[createComment] 查找的产品ID:', commentData.productId, '类型:', typeof commentData.productId);
|
||||
console.log('[createComment] 订单项数量:', order.orderItemVOs?.length);
|
||||
|
||||
// 查找匹配的订单项
|
||||
const orderItem = order.orderItemVOs?.find(item => {
|
||||
// 确保数据类型一致进行比较
|
||||
const itemSpuId = String(item.spuId);
|
||||
const searchProductId = String(commentData.productId);
|
||||
console.log('[createComment] 比较:', itemSpuId, '===', searchProductId, '结果:', itemSpuId === searchProductId);
|
||||
|
||||
return itemSpuId === searchProductId;
|
||||
});
|
||||
|
||||
console.log('[createComment] 找到的订单项:', orderItem ? `ID: ${orderItem.id}, 商品: ${orderItem.goodsName}` : '未找到');
|
||||
|
||||
if (!orderItem) {
|
||||
reject(new Error('未找到对应的订单项'));
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用找到的订单项ID创建评论
|
||||
wx.request({
|
||||
url: `${config.apiBaseUrl}/comments`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: {
|
||||
order_item_id: parseInt(orderItem.id),
|
||||
rating: commentData.rating,
|
||||
content: commentData.content,
|
||||
images: commentData.images || [],
|
||||
is_anonymous: commentData.isAnonymous || false
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '评论提交失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
reject(new Error(orderRes.data.message || '获取订单信息失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
reject(new Error('缺少必要的参数'));
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取用户评论列表 */
|
||||
export function fetchUserComments(params = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
reject(new Error('请先登录'));
|
||||
return;
|
||||
}
|
||||
|
||||
const { page = 1, pageSize = 10 } = params;
|
||||
|
||||
wx.request({
|
||||
url: `${config.apiBaseUrl}/comments/user`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
data: {
|
||||
page,
|
||||
page_size: pageSize
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '获取评论列表失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取未评论的订单项 */
|
||||
export function fetchUncommentedOrderItems() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
reject(new Error('请先登录'));
|
||||
return;
|
||||
}
|
||||
|
||||
wx.request({
|
||||
url: `${config.apiBaseUrl}/user/uncommented-order-items`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data.data);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '获取待评论订单失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
79
miniprogram/services/comments/fetchComments.js
Normal file
79
miniprogram/services/comments/fetchComments.js
Normal file
@@ -0,0 +1,79 @@
|
||||
const { config } = require('../../config/index');
|
||||
|
||||
/** 获取商品评论 */
|
||||
function mockFetchComments(parmas) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getGoodsAllComments } = require('../../model/comments');
|
||||
return delay().then(() => getGoodsAllComments(parmas));
|
||||
}
|
||||
|
||||
/** 获取商品评论 */
|
||||
function fetchComments(params) {
|
||||
if (config.useMock) {
|
||||
return mockFetchComments(params);
|
||||
}
|
||||
|
||||
const { productId, page = 1, pageSize = 10, rating, hasImages } = params;
|
||||
console.log('[fetchComments] 接收到的参数:', params);
|
||||
console.log('[fetchComments] productId:', productId, '类型:', typeof productId);
|
||||
|
||||
// 验证productId参数
|
||||
if (productId === null || productId === undefined || productId === '' || productId === 'undefined' || productId === 'null') {
|
||||
console.error('[fetchComments] 商品ID为空或无效:', productId);
|
||||
return Promise.reject(new Error('商品ID不能为空'));
|
||||
}
|
||||
|
||||
// 确保productId是数字
|
||||
const numericProductId = Number(productId);
|
||||
console.log('[fetchComments] 转换后的数字ID:', numericProductId);
|
||||
|
||||
if (isNaN(numericProductId) || numericProductId <= 0) {
|
||||
console.error('[fetchComments] 商品ID不是有效的正整数:', productId, '->', numericProductId);
|
||||
return Promise.reject(new Error('商品ID必须是有效的正整数'));
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/comments/products/${numericProductId}`,
|
||||
method: 'GET',
|
||||
data: {
|
||||
page,
|
||||
page_size: pageSize,
|
||||
rating,
|
||||
has_images: hasImages
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
// 转换数据格式以匹配前端期望的结构
|
||||
const result = {
|
||||
pageNum: res.data.data.page,
|
||||
pageSize: res.data.data.page_size,
|
||||
totalCount: res.data.data.total.toString(),
|
||||
comments: res.data.data.list.map(comment => ({
|
||||
id: comment.id,
|
||||
product_id: comment.product_id,
|
||||
user_id: comment.user_id,
|
||||
user_name: comment.user_name || '匿名用户',
|
||||
user_avatar: comment.user_avatar || 'https://tdesign.gtimg.com/miniprogram/template/retail/avatar/avatar1.png',
|
||||
rating: comment.rating,
|
||||
content: comment.content,
|
||||
images: comment.images || [],
|
||||
is_anonymous: comment.is_anonymous || false,
|
||||
reply_content: comment.reply_content || '',
|
||||
created_at: comment.created_at,
|
||||
product_spec: comment.product_spec || ''
|
||||
}))
|
||||
};
|
||||
resolve(result);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '获取评论失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { fetchComments };
|
||||
75
miniprogram/services/comments/fetchCommentsCount.js
Normal file
75
miniprogram/services/comments/fetchCommentsCount.js
Normal file
@@ -0,0 +1,75 @@
|
||||
const { config } = require('../../config/index');
|
||||
|
||||
/** 获取商品评论数 */
|
||||
function mockFetchCommentsCount(ID = 0) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getGoodsCommentsCount } = require('../../model/comments');
|
||||
return delay().then(() => getGoodsCommentsCount(ID));
|
||||
}
|
||||
|
||||
/** 获取商品评论数 */
|
||||
function fetchCommentsCount(productId = 0) {
|
||||
console.log('[fetchCommentsCount] 接收到的productId:', productId, '类型:', typeof productId);
|
||||
|
||||
// 验证productId参数
|
||||
if (productId === null || productId === undefined || productId === '' || productId === 'undefined' || productId === 'null') {
|
||||
console.error('[fetchCommentsCount] 商品ID为空或无效:', productId);
|
||||
return Promise.reject(new Error('商品ID不能为空'));
|
||||
}
|
||||
|
||||
// 确保productId是数字
|
||||
const numericProductId = Number(productId);
|
||||
console.log('[fetchCommentsCount] 转换后的数字ID:', numericProductId);
|
||||
|
||||
if (isNaN(numericProductId) || numericProductId <= 0) {
|
||||
console.error('[fetchCommentsCount] 商品ID不是有效的正整数:', productId, '->', numericProductId);
|
||||
return Promise.reject(new Error('商品ID必须是有效的正整数'));
|
||||
}
|
||||
|
||||
if (config.useMock) {
|
||||
return mockFetchCommentsCount(numericProductId);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/comments/products/${numericProductId}/stats`,
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
// 转换数据格式以匹配前端期望的结构
|
||||
const stats = res.data.data;
|
||||
const result = {
|
||||
// 原始数据保留
|
||||
total_count: stats.total_count || 0,
|
||||
average_rating: stats.average_rating || 0,
|
||||
rating_1_count: stats.rating_1_count || 0,
|
||||
rating_2_count: stats.rating_2_count || 0,
|
||||
rating_3_count: stats.rating_3_count || 0,
|
||||
rating_4_count: stats.rating_4_count || 0,
|
||||
rating_5_count: stats.rating_5_count || 0,
|
||||
good_count: (stats.rating_4_count || 0) + (stats.rating_5_count || 0),
|
||||
medium_count: stats.rating_3_count || 0,
|
||||
bad_count: (stats.rating_1_count || 0) + (stats.rating_2_count || 0),
|
||||
image_count: stats.has_images_count || stats.image_count || 0,
|
||||
|
||||
// 页面期望的数据格式
|
||||
commentCount: String(stats.total_count || 0),
|
||||
goodCount: String((stats.rating_4_count || 0) + (stats.rating_5_count || 0)),
|
||||
middleCount: String(stats.rating_3_count || 0),
|
||||
badCount: String((stats.rating_1_count || 0) + (stats.rating_2_count || 0)),
|
||||
hasImageCount: String(stats.has_images_count || stats.image_count || 0),
|
||||
uidCount: '0', // 用户自己的评论数,需要单独获取
|
||||
};
|
||||
resolve(result);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '获取评论统计失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { fetchCommentsCount };
|
||||
81
miniprogram/services/coupon/index.js
Normal file
81
miniprogram/services/coupon/index.js
Normal file
@@ -0,0 +1,81 @@
|
||||
import { config } from '../../config/index';
|
||||
import { request } from '../_utils/request';
|
||||
|
||||
/** 获取优惠券列表 */
|
||||
function mockFetchCoupon(status) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getCouponList } = require('../../model/coupon');
|
||||
return delay().then(() => getCouponList(status));
|
||||
}
|
||||
|
||||
/** 获取优惠券列表 */
|
||||
export function fetchCouponList(status = 'default') {
|
||||
if (config.useMock) {
|
||||
return mockFetchCoupon(status);
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取用户优惠券列表 */
|
||||
export function fetchUserCoupons(status = 1) {
|
||||
if (config.useMock) {
|
||||
return mockFetchCoupon(status === 1 ? 'default' : status === 2 ? 'useless' : 'disabled');
|
||||
}
|
||||
|
||||
return request({
|
||||
url: '/coupons/user',
|
||||
method: 'GET',
|
||||
data: {
|
||||
status: status
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取优惠券 详情 */
|
||||
function mockFetchCouponDetail(id, status) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getCoupon } = require('../../model/coupon');
|
||||
const { genAddressList } = require('../../model/address');
|
||||
|
||||
return delay().then(() => {
|
||||
const result = {
|
||||
detail: getCoupon(id, status),
|
||||
storeInfoList: genAddressList(),
|
||||
};
|
||||
|
||||
result.detail.useNotes = `1个订单限用1张,除运费券外,不能与其它类型的优惠券叠加使用(运费券除外)\n2.仅适用于各区域正常售卖商品,不支持团购、抢购、预售类商品`;
|
||||
result.detail.storeAdapt = `商城通用`;
|
||||
|
||||
if (result.detail.type === 'price') {
|
||||
result.detail.desc = `减免 ${result.detail.value / 100} 元`;
|
||||
|
||||
if (result.detail.base) {
|
||||
result.detail.desc += `,满${result.detail.base / 100}元可用`;
|
||||
}
|
||||
|
||||
result.detail.desc += '。';
|
||||
} else if (result.detail.type === 'discount') {
|
||||
result.detail.desc = `${result.detail.value}折`;
|
||||
|
||||
if (result.detail.base) {
|
||||
result.detail.desc += `,满${result.detail.base / 100}元可用`;
|
||||
}
|
||||
|
||||
result.detail.desc += '。';
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取优惠券 详情 */
|
||||
export function fetchCouponDetail(id, status = 'default') {
|
||||
if (config.useMock) {
|
||||
return mockFetchCouponDetail(id, status);
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
20
miniprogram/services/good/comments/fetchCommentDetail.js
Normal file
20
miniprogram/services/good/comments/fetchCommentDetail.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { config } from '../../../config/index';
|
||||
import { queryCommentDetail } from '../../../model/comments/queryDetail';
|
||||
/** 获取商品评价数据 */
|
||||
function mockQueryCommentDetail(params) {
|
||||
const { delay } = require('../../_utils/delay');
|
||||
const data = queryCommentDetail(params);
|
||||
return delay().then(() => {
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取评价详情 */
|
||||
export function getCommentDetail(params) {
|
||||
if (config.useMock) {
|
||||
return mockQueryCommentDetail(params);
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
141
miniprogram/services/good/favorite.js
Normal file
141
miniprogram/services/good/favorite.js
Normal file
@@ -0,0 +1,141 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/**
|
||||
* 检查商品是否已收藏
|
||||
* @param {number} productId 商品ID
|
||||
* @returns {Promise<boolean>} 是否已收藏
|
||||
*/
|
||||
export function checkIsFavorite(productId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 获取用户token
|
||||
const token = wx.getStorageSync('token') || wx.getStorageSync('jwt_token');
|
||||
if (!token) {
|
||||
console.log('用户未登录,默认未收藏');
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
wx.request({
|
||||
url: `${config.apiBase}/products/${productId}/favorite/status`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && (res.data?.code === 200 || res.data?.success === true || res.data?.code === 'Success')) {
|
||||
try {
|
||||
const payload = res.data || {};
|
||||
const data = payload.data || payload;
|
||||
const isFavorite = (
|
||||
data.is_favorite ??
|
||||
data.isFavorite ??
|
||||
data.favorite ??
|
||||
data.favorited ??
|
||||
false
|
||||
);
|
||||
resolve(Boolean(isFavorite));
|
||||
} catch (e) {
|
||||
console.error('解析收藏状态失败:', e, res);
|
||||
resolve(false);
|
||||
}
|
||||
} else {
|
||||
console.error('检查收藏状态失败:', res);
|
||||
resolve(false);
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('检查收藏状态请求失败:', error);
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加商品到收藏
|
||||
* @param {number} productId 商品ID
|
||||
* @returns {Promise<boolean>} 操作是否成功
|
||||
*/
|
||||
export function addToFavorite(productId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 获取用户token
|
||||
const token = wx.getStorageSync('token') || wx.getStorageSync('jwt_token');
|
||||
if (!token) {
|
||||
reject(new Error('用户未登录'));
|
||||
return;
|
||||
}
|
||||
|
||||
wx.request({
|
||||
url: `${config.apiBase}/products/${productId}/favorite`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
if ((res.statusCode === 200 || res.statusCode === 201) && (res.data?.code === 200 || res.data?.success === true)) {
|
||||
resolve(true);
|
||||
} else {
|
||||
console.error('添加收藏失败:', res);
|
||||
reject(new Error(res.data.message || '收藏失败'));
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('添加收藏请求失败:', error);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消收藏商品
|
||||
* @param {number} productId 商品ID
|
||||
* @returns {Promise<boolean>} 操作是否成功
|
||||
*/
|
||||
export function removeFromFavorite(productId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 获取用户token
|
||||
const token = wx.getStorageSync('token') || wx.getStorageSync('jwt_token');
|
||||
if (!token) {
|
||||
reject(new Error('用户未登录'));
|
||||
return;
|
||||
}
|
||||
|
||||
wx.request({
|
||||
url: `${config.apiBase}/products/${productId}/favorite`,
|
||||
method: 'DELETE',
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
if ((res.statusCode === 200 || res.statusCode === 204) && (res.data?.code === 200 || res.data?.success === true)) {
|
||||
resolve(true);
|
||||
} else {
|
||||
console.error('取消收藏失败:', res);
|
||||
reject(new Error(res.data.message || '取消收藏失败'));
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('取消收藏请求失败:', error);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换收藏状态
|
||||
* @param {number} productId 商品ID
|
||||
* @param {boolean} currentStatus 当前收藏状态
|
||||
* @returns {Promise<boolean>} 新的收藏状态
|
||||
*/
|
||||
export function toggleFavorite(productId, currentStatus) {
|
||||
if (currentStatus) {
|
||||
return removeFromFavorite(productId).then(() => false);
|
||||
} else {
|
||||
return addToFavorite(productId).then(() => true);
|
||||
}
|
||||
}
|
||||
77
miniprogram/services/good/fetchCategoryList.js
Normal file
77
miniprogram/services/good/fetchCategoryList.js
Normal file
@@ -0,0 +1,77 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取商品列表 */
|
||||
function mockFetchGoodCategory() {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getCategoryList } = require('../../model/category');
|
||||
return delay().then(() => getCategoryList());
|
||||
}
|
||||
|
||||
/** 将后端分类数据转换为前端需要的格式 */
|
||||
function transformCategoryData(categories) {
|
||||
if (!categories || !Array.isArray(categories)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 递归转换分类数据
|
||||
function transformCategory(category) {
|
||||
const transformed = {
|
||||
groupId: category.groupId || category.id.toString(),
|
||||
name: category.name,
|
||||
thumbnail: category.thumbnail || category.icon || 'https://tdesign.gtimg.com/miniprogram/template/retail/category/category-default.png',
|
||||
};
|
||||
|
||||
// 为每个一级分类添加"全部"按钮
|
||||
const allButton = {
|
||||
groupId: `${category.id}_all`,
|
||||
name: '全部',
|
||||
thumbnail: 'https://tdesign.gtimg.com/miniprogram/template/retail/category/category-all.png',
|
||||
categoryId: category.id.toString(),
|
||||
categoryName: category.name,
|
||||
isAll: true
|
||||
};
|
||||
|
||||
// 如果有子分类,添加"全部"按钮并处理子分类
|
||||
if (category.children && Array.isArray(category.children) && category.children.length > 0) {
|
||||
transformed.children = [allButton, ...category.children.map(child => transformCategory(child))];
|
||||
} else {
|
||||
// 如果没有子分类,只显示"全部"按钮
|
||||
transformed.children = [allButton];
|
||||
}
|
||||
|
||||
return transformed;
|
||||
}
|
||||
|
||||
return categories.map(category => transformCategory(category));
|
||||
}
|
||||
|
||||
/** 获取分类列表 */
|
||||
export function getCategoryList() {
|
||||
if (config.useMock) {
|
||||
return mockFetchGoodCategory();
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/products/categories`,
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
console.log('原始分类数据:', res.data.data);
|
||||
const transformedData = transformCategoryData(res.data.data);
|
||||
console.log('转换后的分类数据:', transformedData);
|
||||
resolve(transformedData);
|
||||
} else {
|
||||
console.error('获取分类失败:', res.data);
|
||||
// 失败时返回空数组,避免页面崩溃
|
||||
resolve([]);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('分类请求失败:', err);
|
||||
// 失败时返回空数组,避免页面崩溃
|
||||
resolve([]);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
93
miniprogram/services/good/fetchGood.js
Normal file
93
miniprogram/services/good/fetchGood.js
Normal file
@@ -0,0 +1,93 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取商品列表 */
|
||||
function mockFetchGood(ID = 0) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genGood } = require('../../model/good');
|
||||
return delay().then(() => genGood(ID));
|
||||
}
|
||||
|
||||
/** 获取商品详情 */
|
||||
export function fetchGood(ID = 0) {
|
||||
if (config.useMock) {
|
||||
return mockFetchGood(ID);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/frontend/products/${ID}/detail`,
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
// 转换后端数据格式为前端期望的格式
|
||||
const product = res.data.data;
|
||||
|
||||
// 计算价格范围
|
||||
let minPrice = parseInt(product.minSalePrice) || 0;
|
||||
let maxPrice = parseInt(product.maxSalePrice) || 0;
|
||||
let minOriginPrice = parseInt(product.minLinePrice) || 0;
|
||||
let maxOriginPrice = parseInt(product.maxLinePrice) || 0;
|
||||
|
||||
if (product.skuList && product.skuList.length > 0) {
|
||||
const prices = product.skuList.map(sku => {
|
||||
const priceInfo = sku.priceInfo && sku.priceInfo.length > 0 ? sku.priceInfo[0] : null;
|
||||
return priceInfo ? parseInt(priceInfo.price) : 0; // 直接使用分为单位
|
||||
});
|
||||
const originPrices = product.skuList.map(sku => {
|
||||
const priceInfo = sku.priceInfo && sku.priceInfo.length > 0 ? sku.priceInfo[0] : null;
|
||||
return priceInfo ? parseInt(priceInfo.originPrice || priceInfo.price) : 0; // 直接使用分为单位
|
||||
});
|
||||
minPrice = Math.min(...prices);
|
||||
maxPrice = Math.max(...prices);
|
||||
minOriginPrice = Math.min(...originPrices);
|
||||
maxOriginPrice = Math.max(...originPrices);
|
||||
}
|
||||
|
||||
const result = {
|
||||
// 基础信息:优先读取后端前端化字段,其次回退旧字段
|
||||
spuId: product.spuId || product.id,
|
||||
title: product.title || product.name,
|
||||
price: minPrice,
|
||||
originPrice: minOriginPrice,
|
||||
minSalePrice: minPrice,
|
||||
maxSalePrice: maxPrice,
|
||||
maxLinePrice: maxOriginPrice,
|
||||
primaryImage: product.primaryImage || product.main_image,
|
||||
images: (product.images && product.images.length ? product.images : (product.primaryImage || product.main_image ? [product.primaryImage || product.main_image] : [])),
|
||||
video: product.video || null,
|
||||
// 详情描述:仅返回图片列表,支持后端返回字符串单图的情况
|
||||
desc: (Array.isArray(product.desc) && product.desc.length)
|
||||
? product.desc
|
||||
: ((typeof product.desc === 'string' && product.desc.trim())
|
||||
? [product.desc.trim()]
|
||||
: ((Array.isArray(product.detail_images) && product.detail_images.length)
|
||||
? product.detail_images
|
||||
: [])),
|
||||
// 文本描述:单独提供文本字段作为兜底
|
||||
descriptionText: product.description || '',
|
||||
details: product.details,
|
||||
brand: product.brand,
|
||||
category: product.category,
|
||||
isPutOnSale: product.isPutOnSale ?? 1, // 1表示上架,0表示下架
|
||||
isStock: (product.spuStockQuantity ?? product.stock ?? 0) > 0,
|
||||
stockNum: product.spuStockQuantity ?? product.stock ?? 0,
|
||||
spuStockQuantity: product.spuStockQuantity ?? product.stock ?? 0,
|
||||
soldNum: product.soldNum ?? product.sold_count ?? 0,
|
||||
spuTagList: product.spuTagList ?? product.tags ?? [],
|
||||
limitInfo: product.limitInfo ?? [],
|
||||
specList: product.specList || [],
|
||||
skuList: product.skuList || [],
|
||||
etitle: product.etitle || product.name,
|
||||
available: product.available ?? ((product.spuStockQuantity ?? product.stock ?? 0) > 0 ? 1 : 0)
|
||||
};
|
||||
resolve(result);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '获取商品详情失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
70
miniprogram/services/good/fetchGoods.js
Normal file
70
miniprogram/services/good/fetchGoods.js
Normal file
@@ -0,0 +1,70 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取商品列表 */
|
||||
function mockFetchGoodsList(pageIndex = 1, pageSize = 20) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getGoodsList } = require('../../model/goods');
|
||||
return delay().then(() =>
|
||||
getGoodsList(pageIndex, pageSize).map((item) => {
|
||||
return {
|
||||
spuId: item.spuId,
|
||||
thumb: item.primaryImage,
|
||||
title: item.title,
|
||||
price: item.minSalePrice,
|
||||
originPrice: item.maxLinePrice,
|
||||
tags: item.spuTagList.map((tag) => tag.title),
|
||||
};
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/** 获取商品列表 */
|
||||
export function fetchGoodsList(pageIndex = 1, pageSize = 20, categoryId = null) {
|
||||
if (config.useMock) {
|
||||
return mockFetchGoodsList(pageIndex, pageSize);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const requestData = {
|
||||
page: pageIndex,
|
||||
limit: pageSize,
|
||||
};
|
||||
|
||||
// 如果有分类ID,添加到请求参数中
|
||||
if (categoryId) {
|
||||
requestData.category_id = categoryId;
|
||||
}
|
||||
|
||||
wx.request({
|
||||
url: `${config.apiBase}/products`,
|
||||
method: 'GET',
|
||||
data: requestData,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
// 转换API数据格式为小程序期望的格式
|
||||
const products = res.data.data?.list || [];
|
||||
const goodsList = products.map((item) => {
|
||||
return {
|
||||
spuId: item.id,
|
||||
thumb: item.main_image,
|
||||
title: item.name,
|
||||
price: item.price,
|
||||
originPrice: item.orig_price || item.price,
|
||||
tags: [], // API暂时没有标签数据
|
||||
stock: item.stock || 0, // 添加库存信息
|
||||
isStock: item.stock > 0, // 添加库存状态
|
||||
};
|
||||
});
|
||||
resolve(goodsList);
|
||||
} else {
|
||||
console.error('获取商品列表失败:', res.data);
|
||||
resolve([]);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('商品列表请求失败:', err);
|
||||
resolve([]);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
134
miniprogram/services/good/fetchGoodsDetailsComments.js
Normal file
134
miniprogram/services/good/fetchGoodsDetailsComments.js
Normal file
@@ -0,0 +1,134 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取商品详情页评论数 */
|
||||
function mockFetchGoodDetailsCommentsCount(spuId = 0) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const {
|
||||
getGoodsDetailsCommentsCount,
|
||||
} = require('../../model/detailsComments');
|
||||
return delay().then(() => getGoodsDetailsCommentsCount(spuId));
|
||||
}
|
||||
|
||||
/** 获取商品详情页评论数 */
|
||||
export function getGoodsDetailsCommentsCount(spuId = 0) {
|
||||
if (config.useMock) {
|
||||
return mockFetchGoodDetailsCommentsCount(spuId);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/products/${spuId}/reviews/count`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
// 转换后端数据格式为前端需要的格式
|
||||
const data = {
|
||||
commentCount: res.data.data.total || 0,
|
||||
goodRate: res.data.data.good_rate || '100',
|
||||
badCount: res.data.data.bad_count || 0,
|
||||
goodCount: res.data.data.good_count || 0,
|
||||
middleCount: res.data.data.middle_count || 0,
|
||||
hasImageCount: res.data.data.has_image_count || 0,
|
||||
};
|
||||
resolve(data);
|
||||
} else {
|
||||
console.error('获取评论统计失败:', res);
|
||||
// 失败时返回默认数据
|
||||
resolve({
|
||||
commentCount: 0,
|
||||
goodRate: '100',
|
||||
badCount: 0,
|
||||
goodCount: 0,
|
||||
middleCount: 0,
|
||||
hasImageCount: 0,
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('获取评论统计请求失败:', error);
|
||||
// 网络错误时返回默认数据
|
||||
resolve({
|
||||
commentCount: 0,
|
||||
goodRate: '100',
|
||||
badCount: 0,
|
||||
goodCount: 0,
|
||||
middleCount: 0,
|
||||
hasImageCount: 0,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取商品详情页评论 */
|
||||
function mockFetchGoodDetailsCommentList(spuId = 0) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getGoodsDetailsComments } = require('../../model/detailsComments');
|
||||
return delay().then(() => getGoodsDetailsComments(spuId));
|
||||
}
|
||||
|
||||
/** 获取商品详情页评论 */
|
||||
export function getGoodsDetailsCommentList(spuId = 0, page = 1, limit = 10) {
|
||||
if (config.useMock) {
|
||||
return mockFetchGoodDetailsCommentList(spuId);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/products/${spuId}/reviews`,
|
||||
method: 'GET',
|
||||
data: {
|
||||
page: page,
|
||||
limit: limit,
|
||||
},
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
// 转换后端数据格式为前端需要的格式
|
||||
const reviews = res.data.data.list || [];
|
||||
const transformedData = reviews.map(review => ({
|
||||
spuId: review.product_id?.toString() || spuId.toString(),
|
||||
skuId: review.sku_id?.toString() || '0',
|
||||
specInfo: review.spec_info || '',
|
||||
commentContent: review.content || '',
|
||||
commentResources: review.images ? review.images.map(img => ({
|
||||
src: img,
|
||||
type: 'image'
|
||||
})) : [],
|
||||
commentScore: review.rating || 5,
|
||||
uid: review.user_id?.toString() || '',
|
||||
userName: review.user_name || '匿名用户',
|
||||
userHeadUrl: review.user_avatar || 'https://tdesign.gtimg.com/miniprogram/template/retail/avatar/avatar1.png',
|
||||
isAnonymity: review.is_anonymous || false,
|
||||
commentTime: review.created_at ? new Date(review.created_at).getTime().toString() : Date.now().toString(),
|
||||
isAutoComment: false,
|
||||
sellerReply: review.reply || '',
|
||||
goodsDetailInfo: review.spec_info || '',
|
||||
}));
|
||||
|
||||
resolve({
|
||||
homePageComments: transformedData
|
||||
});
|
||||
} else {
|
||||
console.error('获取评论列表失败:', res);
|
||||
// 失败时返回空数组
|
||||
resolve({
|
||||
homePageComments: []
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('获取评论列表请求失败:', error);
|
||||
// 网络错误时返回空数组
|
||||
resolve({
|
||||
homePageComments: []
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
146
miniprogram/services/good/fetchGoodsList.js
Normal file
146
miniprogram/services/good/fetchGoodsList.js
Normal file
@@ -0,0 +1,146 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取商品列表 */
|
||||
function mockFetchGoodsList(params) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getSearchResult } = require('../../model/search');
|
||||
|
||||
const data = getSearchResult(params);
|
||||
|
||||
if (data.spuList.length) {
|
||||
data.spuList.forEach((item) => {
|
||||
item.spuId = item.spuId;
|
||||
item.thumb = item.primaryImage;
|
||||
item.title = item.title;
|
||||
item.price = item.minSalePrice;
|
||||
item.originPrice = item.maxLinePrice;
|
||||
item.desc = '';
|
||||
if (item.spuTagList) {
|
||||
item.tags = item.spuTagList.map((tag) => tag.title);
|
||||
} else {
|
||||
item.tags = [];
|
||||
}
|
||||
});
|
||||
}
|
||||
return delay().then(() => {
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取商品列表 */
|
||||
export function fetchGoodsList(params) {
|
||||
console.log('[API] fetchGoodsList 开始调用:', {
|
||||
inputParams: params,
|
||||
useMock: config.useMock,
|
||||
timestamp: new Date().toLocaleString()
|
||||
});
|
||||
|
||||
if (config.useMock) {
|
||||
console.log('[API] 使用Mock数据');
|
||||
return mockFetchGoodsList(params);
|
||||
}
|
||||
|
||||
const requestData = {
|
||||
page: params.pageNum || 1,
|
||||
page_size: params.pageSize || 20,
|
||||
category_id: params.category_id,
|
||||
keyword: params.keyword,
|
||||
min_price: params.minPrice,
|
||||
max_price: params.maxPrice,
|
||||
sort: params.sort,
|
||||
sortType: params.sortType
|
||||
};
|
||||
|
||||
// 过滤无效参数,避免传递 'undefined' 等值
|
||||
Object.keys(requestData).forEach((key) => {
|
||||
const val = requestData[key];
|
||||
if (
|
||||
val === undefined ||
|
||||
val === null ||
|
||||
(typeof val === 'string' && (val.trim() === '' || val.trim().toLowerCase() === 'undefined'))
|
||||
) {
|
||||
delete requestData[key];
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[API] 发送请求到后端:', {
|
||||
url: `${config.apiBase}/products`,
|
||||
method: 'GET',
|
||||
requestData: requestData,
|
||||
sortInfo: {
|
||||
hasSort: !!params.sort,
|
||||
sortType: params.sortType,
|
||||
sortText: params.sortType === 1 ? '价格从高到低' : params.sortType === 0 ? '价格从低到高' : '默认排序'
|
||||
},
|
||||
timestamp: new Date().toLocaleString()
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/products`,
|
||||
method: 'GET',
|
||||
data: requestData,
|
||||
success: (res) => {
|
||||
console.log('[API] 收到后端响应:', {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
dataMessage: res.data?.message,
|
||||
totalCount: res.data?.data?.total,
|
||||
listLength: res.data?.data?.list?.length,
|
||||
timestamp: new Date().toLocaleString()
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
// 转换后端数据格式为前端期望的格式
|
||||
const products = res.data.data.list.map(item => ({
|
||||
spuId: item.id.toString(),
|
||||
thumb: item.main_image,
|
||||
title: item.name,
|
||||
price: item.price,
|
||||
originPrice: item.orig_price,
|
||||
desc: item.description,
|
||||
tags: item.tags || [],
|
||||
isStock: item.stock > 0
|
||||
}));
|
||||
|
||||
const result = {
|
||||
spuList: products,
|
||||
totalCount: res.data.data.total,
|
||||
pageNum: res.data.data.page,
|
||||
pageSize: res.data.data.page_size
|
||||
};
|
||||
|
||||
console.log('[API] 数据转换完成:', {
|
||||
productsCount: products.length,
|
||||
totalCount: result.totalCount,
|
||||
pageNum: result.pageNum,
|
||||
pageSize: result.pageSize,
|
||||
firstProduct: products[0] ? {
|
||||
title: products[0].title,
|
||||
price: products[0].price
|
||||
} : null,
|
||||
timestamp: new Date().toLocaleString()
|
||||
});
|
||||
|
||||
resolve(result);
|
||||
} else {
|
||||
console.error('[API] 请求失败:', {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
message: res.data?.message || '获取商品列表失败',
|
||||
timestamp: new Date().toLocaleString()
|
||||
});
|
||||
reject(new Error(res.data.message || '获取商品列表失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[API] 网络请求失败:', {
|
||||
error: err,
|
||||
timestamp: new Date().toLocaleString()
|
||||
});
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
35
miniprogram/services/good/fetchSearchHistory.js
Normal file
35
miniprogram/services/good/fetchSearchHistory.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取搜索历史 */
|
||||
function mockSearchHistory() {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getSearchHistory } = require('../../model/search');
|
||||
return delay().then(() => getSearchHistory());
|
||||
}
|
||||
|
||||
/** 获取搜索历史 */
|
||||
export function getSearchHistory() {
|
||||
if (config.useMock) {
|
||||
return mockSearchHistory();
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取搜索历史 */
|
||||
function mockSearchPopular() {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getSearchPopular } = require('../../model/search');
|
||||
return delay().then(() => getSearchPopular());
|
||||
}
|
||||
|
||||
/** 获取搜索历史 */
|
||||
export function getSearchPopular() {
|
||||
if (config.useMock) {
|
||||
return mockSearchPopular();
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
133
miniprogram/services/good/fetchSearchResult.js
Normal file
133
miniprogram/services/good/fetchSearchResult.js
Normal file
@@ -0,0 +1,133 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取搜索结果 - Mock数据 */
|
||||
function mockSearchResult(params) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getSearchResult } = require('../../model/search');
|
||||
|
||||
const data = getSearchResult(params);
|
||||
|
||||
if (data.spuList.length) {
|
||||
data.spuList.forEach((item) => {
|
||||
item.spuId = item.spuId;
|
||||
item.thumb = item.primaryImage;
|
||||
item.title = item.title;
|
||||
item.price = item.minSalePrice;
|
||||
item.originPrice = item.maxLinePrice;
|
||||
if (item.spuTagList) {
|
||||
item.tags = item.spuTagList.map((tag) => ({ title: tag.title }));
|
||||
} else {
|
||||
item.tags = [];
|
||||
}
|
||||
// 添加库存状态字段 - Mock数据
|
||||
item.isStock = item.spuStockQuantity > 0;
|
||||
item.stock = item.spuStockQuantity || 0;
|
||||
});
|
||||
}
|
||||
return delay().then(() => {
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
/** 调用真实的搜索API */
|
||||
function realSearchResult(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 构建请求参数
|
||||
const requestParams = {
|
||||
keyword: params.keyword || '',
|
||||
page: params.pageNum || 1,
|
||||
page_size: params.pageSize || 30,
|
||||
};
|
||||
|
||||
// 添加排序参数
|
||||
if (params.sort === 1) {
|
||||
requestParams.sort_by = 'price';
|
||||
requestParams.sort_order = params.sortType === 1 ? 'desc' : 'asc';
|
||||
}
|
||||
|
||||
// 添加价格筛选
|
||||
if (params.minPrice && params.minPrice > 0) {
|
||||
requestParams.min_price = params.minPrice;
|
||||
}
|
||||
if (params.maxPrice && params.maxPrice > 0) {
|
||||
requestParams.max_price = params.maxPrice;
|
||||
}
|
||||
|
||||
// 构建查询字符串
|
||||
const queryString = Object.keys(requestParams)
|
||||
.filter(key => requestParams[key] !== undefined && requestParams[key] !== '')
|
||||
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(requestParams[key])}`)
|
||||
.join('&');
|
||||
|
||||
const url = `${config.apiBase}/products/search?${queryString}`;
|
||||
|
||||
console.log('🔍 搜索API请求:', {
|
||||
url,
|
||||
params: requestParams,
|
||||
originalParams: params
|
||||
});
|
||||
|
||||
wx.request({
|
||||
url,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('🔍 搜索API响应:', res);
|
||||
|
||||
if (res.statusCode === 200 && res.data && res.data.code === 200) {
|
||||
const { data: responseData } = res.data;
|
||||
|
||||
console.log('🔍 后端响应数据结构:', responseData);
|
||||
|
||||
// 转换后端数据格式为前端期望的格式
|
||||
const result = {
|
||||
saasId: null,
|
||||
storeId: null,
|
||||
pageNum: responseData.page || params.pageNum || 1,
|
||||
pageSize: responseData.page_size || params.pageSize || 30,
|
||||
totalCount: responseData.total || 0,
|
||||
spuList: (responseData.list || []).map(item => ({
|
||||
spuId: item.id,
|
||||
title: item.name,
|
||||
primaryImage: item.main_image || item.image || '',
|
||||
thumb: item.main_image || item.image || '',
|
||||
minSalePrice: item.price || 0,
|
||||
maxLinePrice: item.original_price || item.price || 0,
|
||||
price: item.price || 0,
|
||||
originPrice: item.original_price || item.price || 0,
|
||||
spuTagList: (item.tags || []).map(tag => ({ title: tag })),
|
||||
tags: (item.tags || []).map(tag => ({ title: tag })),
|
||||
// 添加库存状态字段
|
||||
isStock: item.stock > 0,
|
||||
stock: item.stock || 0,
|
||||
// 保留原始数据以备后用
|
||||
_originalData: item
|
||||
})),
|
||||
algId: 0,
|
||||
};
|
||||
|
||||
console.log('🔍 转换后的搜索结果:', result);
|
||||
resolve(result);
|
||||
} else {
|
||||
console.error('🔍 搜索API错误响应:', res);
|
||||
reject(new Error(res.data?.message || '搜索请求失败'));
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('🔍 搜索API请求失败:', error);
|
||||
reject(new Error('网络请求失败,请检查网络连接'));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取搜索结果 */
|
||||
export function getSearchResult(params) {
|
||||
if (config.useMock) {
|
||||
return mockSearchResult(params);
|
||||
}
|
||||
return realSearchResult(params);
|
||||
}
|
||||
169
miniprogram/services/home/home.js
Normal file
169
miniprogram/services/home/home.js
Normal file
@@ -0,0 +1,169 @@
|
||||
import { config, cdnBase } from '../../config/index';
|
||||
|
||||
/** 获取首页数据 */
|
||||
function mockFetchHome() {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genSwiperImageList } = require('../../model/swiper');
|
||||
return delay().then(() => {
|
||||
return {
|
||||
swiper: genSwiperImageList(),
|
||||
tabList: [
|
||||
{
|
||||
text: '热门商品',
|
||||
key: 'hot',
|
||||
},
|
||||
{
|
||||
text: '精选推荐',
|
||||
key: 0,
|
||||
},
|
||||
{
|
||||
text: '夏日防晒',
|
||||
key: 1,
|
||||
},
|
||||
{
|
||||
text: '二胎大作战',
|
||||
key: 2,
|
||||
},
|
||||
{
|
||||
text: '人气榜',
|
||||
key: 3,
|
||||
},
|
||||
{
|
||||
text: '好评榜',
|
||||
key: 4,
|
||||
},
|
||||
{
|
||||
text: 'RTX 30',
|
||||
key: 5,
|
||||
},
|
||||
{
|
||||
text: '手机也疯狂',
|
||||
key: 6,
|
||||
},
|
||||
],
|
||||
activityImg: `${cdnBase}/activity/banner.png`,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取首页数据 */
|
||||
export function fetchHome() {
|
||||
if (config.useMock) {
|
||||
return mockFetchHome();
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// 并行请求轮播图和分类数据
|
||||
const bannerRequest = new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/banners`,
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data.data || []);
|
||||
} else {
|
||||
console.error('获取轮播图失败:', res.data);
|
||||
resolve([]); // 失败时返回空数组,不阻断整个流程
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('轮播图请求失败:', err);
|
||||
resolve([]); // 失败时返回空数组
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const categoryRequest = new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/products/categories`,
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
resolve(res.data.data || []);
|
||||
} else {
|
||||
console.error('获取分类失败:', res.data);
|
||||
resolve([]); // 失败时返回空数组
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('分类请求失败:', err);
|
||||
resolve([]); // 失败时返回空数组
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 获取推荐商品
|
||||
const recommendRequest = new Promise((resolve) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/products/recommend`,
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
console.log('推荐商品数据:', res.data.data);
|
||||
resolve(res.data.data || []);
|
||||
} else {
|
||||
console.error('获取推荐商品失败:', res.data);
|
||||
resolve([]);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('推荐商品请求失败:', err);
|
||||
resolve([]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 获取热门商品
|
||||
const hotRequest = new Promise((resolve) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/products/hot`,
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
console.log('热门商品数据:', res.data.data);
|
||||
resolve(res.data.data || []);
|
||||
} else {
|
||||
console.error('获取热门商品失败:', res.data);
|
||||
resolve([]);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('热门商品请求失败:', err);
|
||||
resolve([]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 等待所有请求都完成
|
||||
Promise.all([bannerRequest, categoryRequest, recommendRequest, hotRequest])
|
||||
.then(([banners, categories, recommendProducts, hotProducts]) => {
|
||||
// 转换轮播图数据格式 - TDesign轮播图组件需要字符串数组
|
||||
const swiper = banners.map(banner => banner.image);
|
||||
console.log('轮播图数据:', swiper);
|
||||
|
||||
// 转换分类数据为tabList格式,在前面添加热门商品tab
|
||||
const tabList = [
|
||||
{
|
||||
text: '热门商品',
|
||||
key: 'hot',
|
||||
},
|
||||
...categories.map((category, index) => ({
|
||||
text: category.name,
|
||||
key: category.id || index,
|
||||
}))
|
||||
];
|
||||
|
||||
resolve({
|
||||
swiper,
|
||||
tabList,
|
||||
recommendProducts,
|
||||
hotProducts,
|
||||
activityImg: `${cdnBase}/activity/banner.png`,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('获取首页数据失败:', error);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
275
miniprogram/services/order/applyService.js
Normal file
275
miniprogram/services/order/applyService.js
Normal file
@@ -0,0 +1,275 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取售后单mock数据 */
|
||||
function mockFetchRightsPreview(params) {
|
||||
console.log('[订单操作服务] 使用Mock数据获取售后预览', {
|
||||
params,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genRightsPreview } = require('../../model/order/applyService');
|
||||
|
||||
return delay().then(() => {
|
||||
const result = genRightsPreview(params);
|
||||
console.log('[订单操作服务] Mock售后预览数据生成完成', result);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取售后单数据 */
|
||||
export function fetchRightsPreview(params) {
|
||||
console.log('[订单操作服务] 开始获取售后预览', {
|
||||
params,
|
||||
useMock: config.useMock,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
if (config.useMock) {
|
||||
console.log('[订单操作服务] 使用Mock模式获取售后预览');
|
||||
return mockFetchRightsPreview(params);
|
||||
}
|
||||
|
||||
console.log('[订单操作服务] 使用真实API获取售后预览(暂未实现)');
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
|
||||
/** 确认收货 */
|
||||
export function dispatchConfirmReceived(orderNo) {
|
||||
console.log('[订单操作服务] 开始确认收货', {
|
||||
orderNo,
|
||||
useMock: config.useMock,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
if (config.useMock) {
|
||||
console.log('[订单操作服务] 使用Mock模式确认收货');
|
||||
const { delay } = require('../_utils/delay');
|
||||
return delay().then(() => {
|
||||
console.log('[订单操作服务] Mock确认收货完成', { orderNo });
|
||||
return { success: true, message: '确认收货成功' };
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const token = wx.getStorageSync('token');
|
||||
console.log('[订单操作服务] 检查登录状态', {
|
||||
hasToken: !!token,
|
||||
orderNo
|
||||
});
|
||||
|
||||
if (!token) {
|
||||
console.error('[订单操作服务] 用户未登录');
|
||||
reject(new Error('未登录'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!orderNo) {
|
||||
console.error('[订单操作服务] 缺少订单号');
|
||||
reject(new Error('缺少订单号'));
|
||||
return;
|
||||
}
|
||||
|
||||
const requestUrl = `${config.apiBase}/orders/${orderNo}/confirm`;
|
||||
console.log('[订单操作服务] 发送确认收货API请求', {
|
||||
url: requestUrl,
|
||||
orderNo
|
||||
});
|
||||
|
||||
wx.request({
|
||||
url: requestUrl,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('[订单操作服务] 确认收货API响应', {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
message: res.data?.message,
|
||||
orderNo
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
console.log('[订单操作服务] 确认收货成功', { orderNo });
|
||||
resolve({ success: true, message: '确认收货成功' });
|
||||
} else {
|
||||
const errorMsg = res.data?.message || '确认收货失败';
|
||||
console.error('[订单操作服务] 确认收货失败', {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
message: errorMsg,
|
||||
orderNo
|
||||
});
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[订单操作服务] 确认收货请求失败', {
|
||||
error: err,
|
||||
orderNo,
|
||||
url: requestUrl,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
reject(new Error('网络请求失败'));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取可选的mock售后原因列表 */
|
||||
function mockFetchApplyReasonList(params) {
|
||||
console.log('[订单操作服务] 使用Mock数据获取售后原因列表', {
|
||||
params,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genApplyReasonList } = require('../../model/order/applyService');
|
||||
|
||||
return delay().then(() => {
|
||||
const result = genApplyReasonList(params);
|
||||
console.log('[订单操作服务] Mock售后原因列表生成完成', {
|
||||
reasonCount: result.data?.length || 0
|
||||
});
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取可选的售后原因列表 */
|
||||
export function fetchApplyReasonList(params) {
|
||||
console.log('[订单操作服务] 开始获取售后原因列表', {
|
||||
params,
|
||||
useMock: config.useMock,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
if (config.useMock) {
|
||||
console.log('[订单操作服务] 使用Mock模式获取售后原因列表');
|
||||
return mockFetchApplyReasonList(params);
|
||||
}
|
||||
|
||||
console.log('[订单操作服务] 使用真实API获取售后原因列表(暂未实现)');
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
|
||||
/** 发起mock售后申请 */
|
||||
function mockDispatchApplyService(params) {
|
||||
console.log('[订单操作服务] 使用Mock数据发起售后申请', {
|
||||
params,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { applyService } = require('../../model/order/applyService');
|
||||
|
||||
return delay().then(() => {
|
||||
const result = applyService(params);
|
||||
console.log('[订单操作服务] Mock售后申请完成', {
|
||||
success: result.success,
|
||||
serviceId: result.data?.serviceId
|
||||
});
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/** 发起售后申请 */
|
||||
export function dispatchApplyService(params) {
|
||||
console.log('[订单操作服务] 开始发起售后申请', {
|
||||
params,
|
||||
useMock: config.useMock,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
if (config.useMock) {
|
||||
console.log('[订单操作服务] 使用Mock模式发起售后申请');
|
||||
return mockDispatchApplyService(params);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const token = wx.getStorageSync('token');
|
||||
console.log('[订单操作服务] 检查登录状态', {
|
||||
hasToken: !!token,
|
||||
orderNo: params.orderNo
|
||||
});
|
||||
|
||||
if (!token) {
|
||||
console.error('[订单操作服务] 用户未登录');
|
||||
reject(new Error('未登录'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!params.orderNo) {
|
||||
console.error('[订单操作服务] 缺少订单号', { params });
|
||||
reject(new Error('缺少订单号'));
|
||||
return;
|
||||
}
|
||||
|
||||
const requestUrl = `${config.apiBase}/orders/${params.orderNo}/service`;
|
||||
console.log('[订单操作服务] 发送售后申请API请求', {
|
||||
url: requestUrl,
|
||||
orderNo: params.orderNo,
|
||||
reason: params.reason,
|
||||
description: params.description
|
||||
});
|
||||
|
||||
wx.request({
|
||||
url: requestUrl,
|
||||
method: 'POST',
|
||||
data: {
|
||||
reason: params.reason,
|
||||
description: params.description,
|
||||
images: params.images || [],
|
||||
type: params.type || 1 // 1-退款 2-退货退款
|
||||
},
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('[订单操作服务] 售后申请API响应', {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
message: res.data?.message,
|
||||
serviceId: res.data?.data?.serviceId,
|
||||
orderNo: params.orderNo
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
console.log('[订单操作服务] 售后申请成功', {
|
||||
orderNo: params.orderNo,
|
||||
serviceId: res.data.data?.serviceId
|
||||
});
|
||||
resolve({
|
||||
success: true,
|
||||
message: '售后申请提交成功',
|
||||
data: res.data.data
|
||||
});
|
||||
} else {
|
||||
const errorMsg = res.data?.message || '售后申请失败';
|
||||
console.error('[订单操作服务] 售后申请失败', {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
message: errorMsg,
|
||||
orderNo: params.orderNo
|
||||
});
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[订单操作服务] 售后申请请求失败', {
|
||||
error: err,
|
||||
orderNo: params.orderNo,
|
||||
url: requestUrl,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
reject(new Error('网络请求失败'));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
351
miniprogram/services/order/orderConfirm.js
Normal file
351
miniprogram/services/order/orderConfirm.js
Normal file
@@ -0,0 +1,351 @@
|
||||
import { config } from '../../config/index';
|
||||
import { mockIp, mockReqId } from '../../utils/mock';
|
||||
|
||||
// 添加日志工具
|
||||
const logger = {
|
||||
info: (module, message, data = {}) => {
|
||||
console.log(`[${module}] ${message}`, data);
|
||||
},
|
||||
debug: (module, message, data = {}) => {
|
||||
console.log(`[DEBUG][${module}] ${message}`, data);
|
||||
},
|
||||
error: (module, message, data = {}) => {
|
||||
console.error(`[ERROR][${module}] ${message}`, data);
|
||||
},
|
||||
warn: (module, message, data = {}) => {
|
||||
console.warn(`[WARN][${module}] ${message}`, data);
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取结算mock数据 */
|
||||
function mockFetchSettleDetail(params) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genSettleDetail } = require('../../model/order/orderConfirm');
|
||||
|
||||
logger.info('ORDER_SETTLE_SERVICE', '使用Mock数据获取结算详情', { params });
|
||||
return delay().then(() => genSettleDetail(params));
|
||||
}
|
||||
|
||||
/** 提交mock订单 */
|
||||
function mockDispatchCommitPay() {
|
||||
const { delay } = require('../_utils/delay');
|
||||
|
||||
logger.info('ORDER_SETTLE_SERVICE', '使用Mock数据提交订单');
|
||||
return delay().then(() => ({
|
||||
data: {
|
||||
isSuccess: true,
|
||||
tradeNo: '350930961469409099',
|
||||
payInfo: '{}',
|
||||
code: null,
|
||||
transactionId: 'E-200915180100299000',
|
||||
msg: null,
|
||||
interactId: '15145',
|
||||
channel: 'wechat',
|
||||
limitGoodsList: null,
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
requestId: mockReqId(),
|
||||
clientIp: mockIp(),
|
||||
rt: 891,
|
||||
success: true,
|
||||
}));
|
||||
}
|
||||
|
||||
/** 获取结算数据 */
|
||||
export function fetchSettleDetail(params) {
|
||||
logger.info('ORDER_SETTLE_SERVICE', '开始获取结算详情', {
|
||||
useMock: config.useMock,
|
||||
apiBase: config.apiBase,
|
||||
params
|
||||
});
|
||||
|
||||
if (config.useMock) {
|
||||
return mockFetchSettleDetail(params);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const token = wx.getStorageSync('token') || '';
|
||||
const requestUrl = `${config.apiBase}/orders/settle`;
|
||||
|
||||
// 数据类型转换和验证
|
||||
const processedParams = {
|
||||
...params,
|
||||
// 确保userAddressReq中的addressId是数字类型
|
||||
userAddressReq: params.userAddressReq ? {
|
||||
...params.userAddressReq,
|
||||
addressId: params.userAddressReq.addressId ? parseInt(params.userAddressReq.addressId) : undefined
|
||||
} : null,
|
||||
// 确保goodsRequestList中的数字字段是正确类型
|
||||
goodsRequestList: (params.goodsRequestList || []).map(goods => ({
|
||||
...goods,
|
||||
quantity: parseInt(goods.quantity) || 0,
|
||||
price: parseInt(goods.price) || 0,
|
||||
originPrice: parseInt(goods.originPrice) || 0,
|
||||
available: parseInt(goods.available) || 0
|
||||
})),
|
||||
// 确保couponList中的数字字段是正确类型
|
||||
couponList: (params.couponList || []).map(coupon => ({
|
||||
...coupon,
|
||||
couponId: coupon.couponId ? parseInt(coupon.couponId) : undefined,
|
||||
userCouponId: coupon.userCouponId ? parseInt(coupon.userCouponId) : undefined,
|
||||
type: coupon.type ? parseInt(coupon.type) : undefined,
|
||||
value: coupon.value ? parseInt(coupon.value) : undefined
|
||||
}))
|
||||
};
|
||||
|
||||
logger.debug('ORDER_SETTLE_SERVICE', '准备发送API请求', {
|
||||
url: requestUrl,
|
||||
method: 'POST',
|
||||
hasToken: !!token,
|
||||
originalParams: params,
|
||||
processedParams
|
||||
});
|
||||
|
||||
wx.request({
|
||||
url: requestUrl,
|
||||
method: 'POST',
|
||||
data: processedParams,
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
logger.info('ORDER_SETTLE_SERVICE', 'API请求成功', {
|
||||
statusCode: res.statusCode,
|
||||
data: res.data,
|
||||
header: res.header
|
||||
});
|
||||
|
||||
if (res.statusCode === 200) {
|
||||
if (res.data && res.data.code === 200) {
|
||||
logger.info('ORDER_SETTLE_SERVICE', '结算数据获取成功', { data: res.data.data });
|
||||
resolve(res.data);
|
||||
} else {
|
||||
const errorMsg = res.data?.message || res.data?.msg || '结算失败';
|
||||
logger.error('ORDER_SETTLE_SERVICE', 'API返回错误', {
|
||||
code: res.data?.code,
|
||||
message: errorMsg,
|
||||
fullResponse: res.data
|
||||
});
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
} else {
|
||||
logger.error('ORDER_SETTLE_SERVICE', 'HTTP状态码错误', {
|
||||
statusCode: res.statusCode,
|
||||
data: res.data
|
||||
});
|
||||
reject(new Error(`HTTP ${res.statusCode}: ${res.data?.message || '请求失败'}`));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
logger.error('ORDER_SETTLE_SERVICE', '网络请求失败', {
|
||||
error: err,
|
||||
url: requestUrl,
|
||||
originalParams: params,
|
||||
processedParams
|
||||
});
|
||||
reject(new Error('网络请求失败: ' + (err.errMsg || '未知错误')));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* 提交订单 */
|
||||
export function dispatchCommitPay(params) {
|
||||
logger.info('ORDER_SETTLE_SERVICE', '开始提交订单', {
|
||||
useMock: config.useMock,
|
||||
params
|
||||
});
|
||||
|
||||
if (config.useMock) {
|
||||
return mockDispatchCommitPay(params);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// 转换前端参数为后端期望的格式
|
||||
const addressId = params.addressId ||
|
||||
(params.userAddressReq && params.userAddressReq.addressId) ||
|
||||
(params.userAddressReq && params.userAddressReq.id);
|
||||
|
||||
logger.debug('ORDER_SETTLE_SERVICE', '地址ID提取调试', {
|
||||
'params.addressId': params.addressId,
|
||||
'params.userAddressReq': params.userAddressReq,
|
||||
'userAddressReq.addressId': params.userAddressReq?.addressId,
|
||||
'userAddressReq.id': params.userAddressReq?.id,
|
||||
'extractedAddressId': addressId,
|
||||
'addressIdType': typeof addressId,
|
||||
'parsedAddressId': parseInt(addressId),
|
||||
'isValidNumber': !isNaN(parseInt(addressId))
|
||||
});
|
||||
|
||||
// 处理优惠券ID
|
||||
console.log('=== dispatchCommitPay 优惠券处理开始 ===');
|
||||
console.log('- params.couponList:', params.couponList);
|
||||
console.log('- params.couponList类型:', typeof params.couponList);
|
||||
console.log('- params.couponList是否为数组:', Array.isArray(params.couponList));
|
||||
console.log('- params.couponList长度:', params.couponList ? params.couponList.length : 'null/undefined');
|
||||
console.log('- params.couponList JSON:', JSON.stringify(params.couponList, null, 2));
|
||||
|
||||
let couponId = null;
|
||||
if (params.couponList && params.couponList.length > 0) {
|
||||
// 取第一个优惠券的ID(假设一次只能使用一张优惠券)
|
||||
const firstCoupon = params.couponList[0];
|
||||
console.log('- 第一张优惠券对象:', firstCoupon);
|
||||
console.log('- 第一张优惠券JSON:', JSON.stringify(firstCoupon, null, 2));
|
||||
|
||||
// 修复:应该传递userCouponId(用户优惠券表的ID),而不是couponId(优惠券模板ID)
|
||||
// 这样后端才能正确验证用户权限并获取优惠券信息
|
||||
couponId = firstCoupon.couponId;
|
||||
|
||||
console.log('=== 优惠券ID提取详情 ===');
|
||||
console.log('- firstCoupon.userCouponId:', firstCoupon.userCouponId);
|
||||
console.log('- firstCoupon.userCouponId类型:', typeof firstCoupon.userCouponId);
|
||||
console.log('- firstCoupon.id:', firstCoupon.id);
|
||||
console.log('- firstCoupon.couponId:', firstCoupon.couponId);
|
||||
console.log('- 最终提取的couponId:', couponId);
|
||||
console.log('- 最终couponId类型:', typeof couponId);
|
||||
console.log('- parseInt(couponId):', parseInt(couponId));
|
||||
console.log('- parseInt(couponId)类型:', typeof parseInt(couponId));
|
||||
|
||||
logger.debug('ORDER_SETTLE_SERVICE', '提取优惠券ID', {
|
||||
couponList: params.couponList,
|
||||
firstCoupon,
|
||||
extractedCouponId: couponId,
|
||||
idFields: {
|
||||
userCouponId: firstCoupon.userCouponId,
|
||||
id: firstCoupon.id,
|
||||
couponId: firstCoupon.couponId
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('=== 无优惠券处理 ===');
|
||||
console.log('- 优惠券列表为空或不存在');
|
||||
console.log('- couponId将设置为null');
|
||||
}
|
||||
|
||||
console.log('=== 构建orderData ===');
|
||||
console.log('- couponId值:', couponId);
|
||||
console.log('- couponId类型:', typeof couponId);
|
||||
console.log('- couponId是否为null:', couponId === null);
|
||||
console.log('- couponId是否为undefined:', couponId === undefined);
|
||||
console.log('- couponId转换为布尔值:', !!couponId);
|
||||
|
||||
const parsedCouponId = couponId ? parseInt(couponId) : undefined;
|
||||
console.log('- parseInt(couponId):', parsedCouponId);
|
||||
console.log('- parseInt(couponId)类型:', typeof parsedCouponId);
|
||||
|
||||
const orderData = {
|
||||
address_id: parseInt(addressId),
|
||||
items: params.goodsRequestList.map(goods => ({
|
||||
product_id: parseInt(goods.spuId),
|
||||
sku_id: goods.skuId ? parseInt(goods.skuId) : 0,
|
||||
quantity: goods.quantity,
|
||||
spec_info: goods.specInfo || {}
|
||||
})),
|
||||
remark: params.remark || '',
|
||||
coupon_id: parsedCouponId
|
||||
};
|
||||
|
||||
console.log('=== orderData构建完成 ===');
|
||||
console.log('- orderData:', orderData);
|
||||
console.log('- orderData.coupon_id:', orderData.coupon_id);
|
||||
console.log('- orderData.coupon_id类型:', typeof orderData.coupon_id);
|
||||
console.log('- orderData是否包含coupon_id属性:', 'coupon_id' in orderData);
|
||||
console.log('- orderData JSON字符串:', JSON.stringify(orderData, null, 2));
|
||||
|
||||
// 检查JSON序列化后是否包含coupon_id
|
||||
const jsonString = JSON.stringify(orderData);
|
||||
console.log('- JSON序列化字符串:', jsonString);
|
||||
console.log('- JSON中是否包含coupon_id:', jsonString.includes('coupon_id'));
|
||||
|
||||
logger.debug('ORDER_SETTLE_SERVICE', '最终订单数据', {
|
||||
orderData,
|
||||
'address_id_type': typeof orderData.address_id,
|
||||
'address_id_value': orderData.address_id,
|
||||
'coupon_id_value': orderData.coupon_id,
|
||||
'coupon_id_type': typeof orderData.coupon_id
|
||||
});
|
||||
|
||||
const token = wx.getStorageSync('token') || '';
|
||||
const requestUrl = `${config.apiBase}/orders`;
|
||||
|
||||
logger.debug('ORDER_SETTLE_SERVICE', '准备提交订单API请求', {
|
||||
url: requestUrl,
|
||||
orderData,
|
||||
hasToken: !!token
|
||||
});
|
||||
|
||||
wx.request({
|
||||
url: requestUrl,
|
||||
method: 'POST',
|
||||
data: orderData,
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
logger.info('ORDER_SETTLE_SERVICE', '订单提交API响应', {
|
||||
statusCode: res.statusCode,
|
||||
data: res.data
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
// 转换后端返回数据为前端期望的格式
|
||||
const result = {
|
||||
data: {
|
||||
isSuccess: true,
|
||||
tradeNo: res.data.data.order_no,
|
||||
payInfo: '{}',
|
||||
code: null,
|
||||
transactionId: res.data.data.order_no,
|
||||
msg: null,
|
||||
interactId: res.data.data.id.toString(),
|
||||
channel: 'wechat',
|
||||
limitGoodsList: null,
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
requestId: Date.now().toString(),
|
||||
clientIp: '127.0.0.1',
|
||||
rt: 200,
|
||||
success: true,
|
||||
};
|
||||
|
||||
logger.info('ORDER_SETTLE_SERVICE', '订单提交成功', { result });
|
||||
resolve(result);
|
||||
} else {
|
||||
const errorMsg = res.data?.message || '订单创建失败';
|
||||
logger.error('ORDER_SETTLE_SERVICE', '订单提交失败', {
|
||||
code: res.data?.code,
|
||||
message: errorMsg,
|
||||
fullResponse: res.data
|
||||
});
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
logger.error('ORDER_SETTLE_SERVICE', '订单提交网络请求失败', {
|
||||
error: err,
|
||||
url: requestUrl,
|
||||
orderData
|
||||
});
|
||||
reject(new Error('网络请求失败: ' + (err.errMsg || '未知错误')));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 开发票 */
|
||||
export function dispatchSupplementInvoice() {
|
||||
logger.info('ORDER_SETTLE_SERVICE', '开始开发票', { useMock: config.useMock });
|
||||
|
||||
if (config.useMock) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
return delay();
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
402
miniprogram/services/order/orderDetail.js
Normal file
402
miniprogram/services/order/orderDetail.js
Normal file
@@ -0,0 +1,402 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取订单详情mock数据 */
|
||||
function mockFetchOrderDetail(params) {
|
||||
console.log('[订单详情服务] 使用Mock数据获取订单详情', {
|
||||
params,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genOrderDetail } = require('../../model/order/orderDetail');
|
||||
|
||||
return delay().then(() => {
|
||||
const result = genOrderDetail(params);
|
||||
console.log('[订单详情服务] Mock数据生成完成', {
|
||||
orderId: result.data?.orderId,
|
||||
orderNo: result.data?.orderNo,
|
||||
orderStatus: result.data?.orderStatus,
|
||||
itemCount: result.data?.orderItemVOs?.length || 0
|
||||
});
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取订单详情数据 */
|
||||
export function fetchOrderDetail(params) {
|
||||
console.log('[订单详情服务] 开始获取订单详情', {
|
||||
params,
|
||||
useMock: config.useMock,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
if (config.useMock) {
|
||||
console.log('[订单详情服务] 使用Mock模式');
|
||||
return mockFetchOrderDetail(params);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// 从本地存储获取token
|
||||
const token = wx.getStorageSync('token');
|
||||
console.log('[订单详情服务] 检查登录状态', {
|
||||
hasToken: !!token
|
||||
});
|
||||
|
||||
if (!token) {
|
||||
console.error('[订单详情服务] 用户未登录');
|
||||
reject(new Error('未登录'));
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用订单号或订单ID获取详情
|
||||
const orderIdentifier = params.parameter || params.orderNo || params.orderId;
|
||||
console.log('[订单详情服务] 解析订单标识', {
|
||||
parameter: params.parameter,
|
||||
orderNo: params.orderNo,
|
||||
orderId: params.orderId,
|
||||
orderIdentifier
|
||||
});
|
||||
|
||||
if (!orderIdentifier) {
|
||||
console.error('[订单详情服务] 缺少订单标识', { params });
|
||||
reject(new Error('缺少订单标识'));
|
||||
return;
|
||||
}
|
||||
|
||||
const requestUrl = `${config.apiBase}/orders/${orderIdentifier}`;
|
||||
console.log('[订单详情服务] 发送API请求', {
|
||||
url: requestUrl,
|
||||
orderIdentifier,
|
||||
hasToken: !!token
|
||||
});
|
||||
|
||||
wx.request({
|
||||
url: requestUrl,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('[订单详情服务] API响应成功', {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
orderId: res.data?.data?.orderId,
|
||||
orderNo: res.data?.data?.orderNo,
|
||||
orderStatus: res.data?.data?.orderStatus
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
console.log('[订单详情服务] 开始处理订单详情数据');
|
||||
|
||||
// 转换后端数据格式为前端需要的格式
|
||||
const order = res.data.data;
|
||||
|
||||
console.log('[订单详情服务] 原始订单数据', {
|
||||
orderId: order.orderId,
|
||||
orderNo: order.orderNo,
|
||||
orderStatus: order.orderStatus,
|
||||
paymentAmount: order.paymentAmount,
|
||||
itemCount: order.orderItemVOs?.length || 0,
|
||||
hasLogistics: !!order.logisticsVO
|
||||
});
|
||||
|
||||
// 构建符合前端期望的数据结构
|
||||
// 注意:后端API已经返回正确格式的数据,直接使用
|
||||
const orderDetail = {
|
||||
data: {
|
||||
orderId: order.orderId,
|
||||
orderNo: order.orderNo,
|
||||
parentOrderNo: order.parentOrderNo,
|
||||
storeId: order.storeId,
|
||||
storeName: order.storeName,
|
||||
orderStatus: order.orderStatus,
|
||||
orderStatusName: order.orderStatusName,
|
||||
paymentAmount: order.paymentAmount, // 后端已经是分为单位的整数
|
||||
goodsAmountApp: order.goodsAmountApp,
|
||||
totalAmount: order.totalAmount,
|
||||
payAmount: order.payAmount,
|
||||
couponAmount: order.couponAmount || 0, // 优惠券金额(分为单位)
|
||||
freightFee: 0,
|
||||
discountAmount: 0,
|
||||
createdAt: order.createdAt,
|
||||
createTime: new Date(order.createdAt).getTime(),
|
||||
autoCancelTime: order.orderStatus === 1 ? Date.now() + 30 * 60 * 1000 : null, // 30分钟后自动取消
|
||||
|
||||
// 订单商品列表 - 直接使用后端返回的数据
|
||||
orderItemVOs: order.orderItemVOs || [],
|
||||
|
||||
// 物流信息 - 直接使用后端返回的数据
|
||||
logisticsVO: order.logisticsVO || {
|
||||
logisticsNo: '',
|
||||
logisticsCompanyName: '',
|
||||
receiverName: '',
|
||||
receiverPhone: '',
|
||||
receiverProvince: '',
|
||||
receiverCity: '',
|
||||
receiverCountry: '',
|
||||
receiverAddress: '',
|
||||
sendTime: null,
|
||||
arrivalTime: null
|
||||
},
|
||||
|
||||
// 支付信息
|
||||
paymentVO: {
|
||||
payStatus: order.payStatus || 0,
|
||||
amount: order.payAmount || order.totalAmount,
|
||||
paySuccessTime: order.paidAt || null,
|
||||
payWayName: '微信支付'
|
||||
},
|
||||
|
||||
// 操作按钮
|
||||
buttonVOs: getOrderButtons(order.orderStatus),
|
||||
|
||||
// 发票信息
|
||||
invoiceStatus: 2, // 暂不开发票
|
||||
invoiceDesc: '暂不开发票',
|
||||
invoiceVO: null
|
||||
},
|
||||
code: 'Success',
|
||||
success: true
|
||||
};
|
||||
|
||||
console.log('[订单详情服务] 订单详情数据处理完成', {
|
||||
orderId: orderDetail.data.orderId,
|
||||
orderNo: orderDetail.data.orderNo,
|
||||
orderStatus: orderDetail.data.orderStatus,
|
||||
orderStatusName: orderDetail.data.orderStatusName,
|
||||
paymentAmount: orderDetail.data.paymentAmount,
|
||||
itemCount: orderDetail.data.orderItemVOs.length,
|
||||
buttonCount: orderDetail.data.buttonVOs.length,
|
||||
hasLogistics: !!orderDetail.data.logisticsVO.logisticsNo,
|
||||
autoCancelTime: orderDetail.data.autoCancelTime
|
||||
});
|
||||
|
||||
resolve(orderDetail);
|
||||
} else {
|
||||
const errorMsg = res.data.message || '获取订单详情失败';
|
||||
console.error('[订单详情服务] API响应错误', {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
message: errorMsg,
|
||||
orderIdentifier
|
||||
});
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('[订单详情服务] API请求失败', {
|
||||
error,
|
||||
orderIdentifier,
|
||||
url: requestUrl,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
reject(new Error('网络请求失败'));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 获取订单操作按钮
|
||||
function getOrderButtons(status) {
|
||||
console.log('[订单详情服务] 获取订单操作按钮', { status });
|
||||
|
||||
const buttons = [];
|
||||
|
||||
switch (status) {
|
||||
case 1: // 待付款
|
||||
buttons.push(
|
||||
{ primary: false, type: 1, name: '取消订单' },
|
||||
{ primary: true, type: 2, name: '立即付款' }
|
||||
);
|
||||
break;
|
||||
case 2: // 已付款/待发货
|
||||
buttons.push(
|
||||
{ primary: false, type: 7, name: '申请退款' },
|
||||
{ primary: true, type: 3, name: '提醒发货' }
|
||||
);
|
||||
break;
|
||||
case 3: // 待发货
|
||||
buttons.push(
|
||||
{ primary: false, type: 7, name: '申请退款' },
|
||||
{ primary: true, type: 3, name: '提醒发货' }
|
||||
);
|
||||
break;
|
||||
case 4: // 已发货/待收货
|
||||
buttons.push(
|
||||
{ primary: true, type: 4, name: '确认收货' }
|
||||
);
|
||||
break;
|
||||
case 5: // 待收货
|
||||
buttons.push(
|
||||
{ primary: true, type: 4, name: '确认收货' }
|
||||
);
|
||||
break;
|
||||
case 6: // 已完成
|
||||
buttons.push(
|
||||
{ primary: false, type: 5, name: '申请售后' },
|
||||
{ primary: true, type: 6, name: '评价' }
|
||||
);
|
||||
break;
|
||||
case 7: // 已取消
|
||||
// 无操作按钮
|
||||
break;
|
||||
}
|
||||
|
||||
console.log('[订单详情服务] 生成的操作按钮', {
|
||||
status,
|
||||
buttonCount: buttons.length,
|
||||
buttons: buttons.map(btn => ({ name: btn.name, type: btn.type, primary: btn.primary }))
|
||||
});
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
// 获取商品操作按钮
|
||||
function getItemButtons(orderStatus) {
|
||||
console.log('[订单详情服务] 获取商品操作按钮', { orderStatus });
|
||||
|
||||
if (orderStatus === 3) { // 已完成
|
||||
const buttons = [
|
||||
{ primary: false, type: 4, name: '申请售后' }
|
||||
];
|
||||
console.log('[订单详情服务] 生成商品按钮', { buttons });
|
||||
return buttons;
|
||||
}
|
||||
|
||||
console.log('[订单详情服务] 无商品操作按钮', { orderStatus });
|
||||
return [];
|
||||
}
|
||||
|
||||
// 状态描述映射
|
||||
function getStatusDesc(status) {
|
||||
// 与后端order.go中的状态映射保持一致
|
||||
const statusMap = {
|
||||
1: '未付款',
|
||||
2: '待发货', // 统一为待发货
|
||||
3: '待发货', // 统一为待发货
|
||||
4: '已发货',
|
||||
5: '待收货',
|
||||
6: '已完成',
|
||||
7: '已取消',
|
||||
8: '退货中',
|
||||
9: '已退款'
|
||||
};
|
||||
const statusDesc = statusMap[status] || '未知状态';
|
||||
|
||||
console.log('[订单详情服务] 获取状态描述', {
|
||||
status,
|
||||
statusDesc
|
||||
});
|
||||
|
||||
return statusDesc;
|
||||
}
|
||||
|
||||
/** 获取客服mock数据 */
|
||||
function mockFetchBusinessTime(params) {
|
||||
console.log('[订单详情服务] 使用Mock数据获取客服信息', {
|
||||
params,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genBusinessTime } = require('../../model/order/orderDetail');
|
||||
|
||||
return delay().then(() => {
|
||||
const result = genBusinessTime(params);
|
||||
console.log('[订单详情服务] Mock客服数据生成完成', result);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取客服数据 */
|
||||
export function fetchBusinessTime(params) {
|
||||
console.log('[订单详情服务] 开始获取客服信息', {
|
||||
params,
|
||||
useMock: config.useMock,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
if (config.useMock) {
|
||||
console.log('[订单详情服务] 使用Mock模式获取客服信息');
|
||||
return mockFetchBusinessTime(params);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const requestUrl = `${config.apiBase}/business/time`;
|
||||
const token = wx.getStorageSync('token') || '';
|
||||
|
||||
console.log('[订单详情服务] 发送客服信息API请求', {
|
||||
url: requestUrl,
|
||||
hasToken: !!token
|
||||
});
|
||||
|
||||
wx.request({
|
||||
url: requestUrl,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('[订单详情服务] 客服信息API响应', {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
hasBusinessTime: !!res.data?.data?.business_time,
|
||||
hasPhone: !!res.data?.data?.phone
|
||||
});
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
const result = {
|
||||
data: {
|
||||
businessTime: res.data.data.business_time || ['周一至周日: 9:00-18:00'],
|
||||
telphone: res.data.data.phone || '400-000-0000',
|
||||
saasId: res.data.data.saas_id || '88888888',
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
success: true,
|
||||
};
|
||||
|
||||
console.log('[订单详情服务] 客服信息获取成功', result.data);
|
||||
resolve(result);
|
||||
} else {
|
||||
console.warn('[订单详情服务] 客服信息API失败,使用默认数据', {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
message: res.data?.message
|
||||
});
|
||||
|
||||
// 如果API失败,返回默认数据
|
||||
resolve({
|
||||
data: {
|
||||
businessTime: ['周一至周日: 9:00-18:00'],
|
||||
telphone: '400-000-0000',
|
||||
saasId: '88888888',
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
success: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[订单详情服务] 客服信息请求失败,使用默认数据', {
|
||||
error: err,
|
||||
url: requestUrl
|
||||
});
|
||||
|
||||
// 网络错误时返回默认数据
|
||||
resolve({
|
||||
data: {
|
||||
businessTime: ['周一至周日: 9:00-18:00'],
|
||||
telphone: '400-000-0000',
|
||||
saasId: '88888888',
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
success: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
417
miniprogram/services/order/orderList.js
Normal file
417
miniprogram/services/order/orderList.js
Normal file
@@ -0,0 +1,417 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取订单列表mock数据 */
|
||||
function mockFetchOrders(params) {
|
||||
console.log('[订单服务] 使用Mock数据获取订单列表', {
|
||||
params,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genOrders } = require('../../model/order/orderList');
|
||||
|
||||
return delay(200).then(() => {
|
||||
const result = genOrders(params);
|
||||
console.log('[订单服务] Mock数据生成完成', {
|
||||
orderCount: result.data?.orders?.length || 0,
|
||||
totalCount: result.data?.totalCount || 0
|
||||
});
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取订单列表数据 */
|
||||
export function fetchOrders(statusOrParams, pageNum, pageSize) {
|
||||
console.log('[订单服务] 开始获取订单列表', {
|
||||
statusOrParams,
|
||||
pageNum,
|
||||
pageSize,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
// 兼容两种调用方式:
|
||||
// 1. fetchOrders(params) - 原有方式,params包含parameter对象
|
||||
// 2. fetchOrders(status, pageNum, pageSize) - 新的调用方式
|
||||
let requestParams;
|
||||
|
||||
if (typeof statusOrParams === 'object' && statusOrParams.parameter) {
|
||||
// 原有的参数格式
|
||||
requestParams = {
|
||||
page: statusOrParams.parameter.pageNum || 1,
|
||||
page_size: statusOrParams.parameter.pageSize || 20,
|
||||
status: statusOrParams.parameter.orderStatus
|
||||
};
|
||||
|
||||
console.log('[订单服务] 使用原有参数格式', {
|
||||
originalParams: statusOrParams,
|
||||
requestParams
|
||||
});
|
||||
|
||||
if (config.useMock) {
|
||||
console.log('[订单服务] 使用Mock模式');
|
||||
return mockFetchOrders(statusOrParams);
|
||||
}
|
||||
} else {
|
||||
// 新的参数格式
|
||||
requestParams = {
|
||||
page: pageNum || 1,
|
||||
page_size: pageSize || 20,
|
||||
status: statusOrParams || ''
|
||||
};
|
||||
|
||||
console.log('[订单服务] 使用新参数格式', {
|
||||
status: statusOrParams,
|
||||
pageNum,
|
||||
pageSize,
|
||||
requestParams
|
||||
});
|
||||
|
||||
if (config.useMock) {
|
||||
console.log('[订单服务] 使用Mock模式');
|
||||
const mockParams = {
|
||||
parameter: {
|
||||
pageNum: pageNum || 1,
|
||||
pageSize: pageSize || 20,
|
||||
orderStatus: statusOrParams || -1
|
||||
}
|
||||
};
|
||||
return mockFetchOrders(mockParams);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[订单服务] 发送真实API请求', {
|
||||
url: `${config.apiBase}/orders`,
|
||||
requestParams,
|
||||
token: wx.getStorageSync('token') ? '已获取' : '未获取'
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/orders`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token') || ''}`
|
||||
},
|
||||
data: requestParams,
|
||||
success: (res) => {
|
||||
console.log('🌐 [订单服务] API响应成功 - 完整响应数据', {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
orderCount: res.data?.data?.list?.length || 0,
|
||||
total: res.data?.data?.total || 0,
|
||||
requestParams,
|
||||
fullResponse: res,
|
||||
responseDataStructure: {
|
||||
hasData: !!res.data,
|
||||
hasDataData: !!res.data?.data,
|
||||
hasList: !!res.data?.data?.list,
|
||||
hasOrders: !!res.data?.data?.orders,
|
||||
responseKeys: res.data ? Object.keys(res.data) : [],
|
||||
dataKeys: res.data?.data ? Object.keys(res.data.data) : []
|
||||
}
|
||||
});
|
||||
|
||||
// 打印原始订单数据
|
||||
const orderList = res.data?.data?.list || res.data?.data?.orders || [];
|
||||
if (orderList.length > 0) {
|
||||
console.log('📦 [订单服务] 原始API订单数据详情', {
|
||||
totalOrders: orderList.length,
|
||||
rawOrders: orderList,
|
||||
orderSummary: orderList.map((order, index) => ({
|
||||
index,
|
||||
orderId: order.orderId,
|
||||
orderNo: order.orderNo,
|
||||
orderStatus: order.orderStatus,
|
||||
paymentAmount: order.paymentAmount,
|
||||
orderItemVOsCount: order.orderItemVOs?.length || 0,
|
||||
orderKeys: Object.keys(order)
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
const rawOrders = res.data.data.list || res.data.data.orders || [];
|
||||
console.log('[订单服务] 开始处理订单数据', {
|
||||
rawOrderCount: rawOrders.length
|
||||
});
|
||||
|
||||
// 转换后端数据格式为前端期望的格式
|
||||
const processedOrderList = rawOrders.map((order, index) => {
|
||||
console.log(`[订单服务] 处理订单 ${index + 1}:`, {
|
||||
id: order.orderId || order.id,
|
||||
orderNo: order.orderNo || order.order_no,
|
||||
status: order.orderStatus || order.status,
|
||||
payAmount: order.paymentAmount || order.pay_amount,
|
||||
itemCount: order.orderItemVOs?.length || order.items?.length || 0
|
||||
});
|
||||
|
||||
return {
|
||||
id: order.orderId || order.id,
|
||||
orderId: order.orderId || order.id,
|
||||
orderNo: order.orderNo || order.order_no,
|
||||
order_no: order.orderNo || order.order_no,
|
||||
parentOrderNo: order.orderNo || order.order_no,
|
||||
storeId: order.storeId || '1',
|
||||
storeName: order.storeName || '默认店铺',
|
||||
status: order.orderStatus || order.status,
|
||||
orderStatus: order.orderStatus || order.status,
|
||||
statusName: getOrderStatusName(order.orderStatus || order.status),
|
||||
orderStatusName: getOrderStatusName(order.orderStatus || order.status),
|
||||
payAmount: order.paymentAmount || order.pay_amount,
|
||||
pay_amount: order.paymentAmount || order.pay_amount,
|
||||
paymentAmount: order.paymentAmount || order.pay_amount,
|
||||
totalAmount: order.totalAmount || order.total_amount,
|
||||
total_amount: order.totalAmount || order.total_amount,
|
||||
createdAt: order.createdAt || order.created_at,
|
||||
created_at: order.createdAt || order.created_at,
|
||||
createTime: new Date(order.createdAt || order.created_at).getTime(),
|
||||
receiverName: order.receiverName || order.receiver_name,
|
||||
receiver_name: order.receiverName || order.receiver_name,
|
||||
receiverPhone: order.receiverPhone || order.receiver_phone,
|
||||
receiver_phone: order.receiverPhone || order.receiver_phone,
|
||||
receiverAddress: order.receiverAddress || order.receiver_address,
|
||||
receiver_address: order.receiverAddress || order.receiver_address,
|
||||
logisticsVO: {
|
||||
logisticsNo: order.logisticsNo || '',
|
||||
receiverName: order.receiverName || order.receiver_name,
|
||||
receiverPhone: order.receiverPhone || order.receiver_phone,
|
||||
receiverAddress: order.receiverAddress || order.receiver_address
|
||||
},
|
||||
orderItemVOs: (order.orderItemVOs || order.items || []).map(item => ({
|
||||
...item,
|
||||
spec_info: item.spec_info || {},
|
||||
specInfo: item.spec_info || {},
|
||||
// 格式化spec_info为显示文本
|
||||
specText: item.spec_info ? Object.entries(item.spec_info).map(([key, value]) => `${key}: ${value}`).join(', ') : ''
|
||||
})),
|
||||
items: (order.orderItemVOs || order.items || []).map(item => ({
|
||||
...item,
|
||||
spec_info: item.spec_info || {},
|
||||
specInfo: item.spec_info || {},
|
||||
// 格式化spec_info为显示文本
|
||||
specText: item.spec_info ? Object.entries(item.spec_info).map(([key, value]) => `${key}: ${value}`).join(', ') : ''
|
||||
})),
|
||||
buttonVOs: getOrderButtons(order.orderStatus || order.status),
|
||||
buttons: getOrderButtons(order.orderStatus || order.status)
|
||||
};
|
||||
});
|
||||
|
||||
console.log('✅ [订单服务] 订单数据处理完成', {
|
||||
processedOrderCount: processedOrderList.length,
|
||||
total: res.data.data.total || 0
|
||||
});
|
||||
|
||||
// 打印处理后的订单详情
|
||||
console.log('🔄 [订单服务] 处理后的订单数据详情', {
|
||||
processedOrders: processedOrderList.map((order, index) => ({
|
||||
index,
|
||||
id: order.id,
|
||||
orderId: order.orderId,
|
||||
orderNo: order.orderNo,
|
||||
status: order.status,
|
||||
orderStatus: order.orderStatus,
|
||||
statusName: order.statusName,
|
||||
payAmount: order.payAmount,
|
||||
paymentAmount: order.paymentAmount,
|
||||
totalAmount: order.totalAmount,
|
||||
receiverName: order.receiverName,
|
||||
receiverAddress: order.receiverAddress,
|
||||
orderItemVOsCount: order.orderItemVOs?.length || 0,
|
||||
itemsCount: order.items?.length || 0,
|
||||
orderItemVOs: order.orderItemVOs,
|
||||
items: order.items,
|
||||
buttons: order.buttons,
|
||||
buttonVOs: order.buttonVOs,
|
||||
// 添加spec_info详情
|
||||
itemsWithSpecInfo: order.items?.map(item => ({
|
||||
productName: item.product_name || item.productName,
|
||||
specInfo: item.spec_info,
|
||||
specText: item.specText
|
||||
})) || []
|
||||
}))
|
||||
});
|
||||
|
||||
// 返回兼容两种格式的数据
|
||||
const result = {
|
||||
// 新格式 - 使用orders字段供 index.js 使用
|
||||
orders: processedOrderList,
|
||||
total: res.data.data.total || 0,
|
||||
page: requestParams.page,
|
||||
pageSize: requestParams.page_size,
|
||||
// 旧格式 - 保持兼容性
|
||||
list: processedOrderList,
|
||||
data: {
|
||||
orders: processedOrderList,
|
||||
totalCount: res.data.data.total || 0,
|
||||
pageNum: requestParams.page,
|
||||
pageSize: requestParams.page_size
|
||||
}
|
||||
};
|
||||
|
||||
console.log('📤 [订单服务] 返回处理结果 - 完整数据结构', {
|
||||
ordersCount: result.orders.length,
|
||||
total: result.total,
|
||||
page: result.page,
|
||||
pageSize: result.pageSize,
|
||||
resultStructure: {
|
||||
hasOrders: !!result.orders,
|
||||
hasList: !!result.list,
|
||||
hasData: !!result.data,
|
||||
hasDataOrders: !!result.data?.orders,
|
||||
resultKeys: Object.keys(result),
|
||||
dataKeys: result.data ? Object.keys(result.data) : []
|
||||
},
|
||||
fullResult: result
|
||||
});
|
||||
|
||||
resolve(result);
|
||||
} else {
|
||||
const errorMsg = res.data.message || '获取订单列表失败';
|
||||
console.error('[订单服务] API响应错误', {
|
||||
statusCode: res.statusCode,
|
||||
dataCode: res.data?.code,
|
||||
message: errorMsg,
|
||||
requestParams
|
||||
});
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[订单服务] API请求失败', {
|
||||
error: err,
|
||||
requestParams,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 获取订单状态名称
|
||||
function getOrderStatusName(status) {
|
||||
// 与后端order.go中的状态映射保持一致
|
||||
const statusMap = {
|
||||
1: '未付款',
|
||||
2: '待发货', // 统一为待发货
|
||||
3: '待发货', // 统一为待发货
|
||||
4: '已发货',
|
||||
5: '待收货',
|
||||
6: '已完成',
|
||||
7: '已取消',
|
||||
8: '退货中',
|
||||
9: '已退款'
|
||||
};
|
||||
const statusName = statusMap[status] || '未知状态';
|
||||
|
||||
console.log('[订单服务] 获取订单状态名称', {
|
||||
status,
|
||||
statusName
|
||||
});
|
||||
|
||||
return statusName;
|
||||
}
|
||||
|
||||
// 获取订单按钮
|
||||
function getOrderButtons(status) {
|
||||
console.log('[订单服务] ===== 按钮生成开始 =====');
|
||||
console.log('[订单服务] 输入参数详情', {
|
||||
status: status,
|
||||
statusType: typeof status,
|
||||
statusString: String(status)
|
||||
});
|
||||
|
||||
const buttons = [];
|
||||
|
||||
console.log('[订单服务] 开始按状态生成按钮...');
|
||||
|
||||
switch (status) {
|
||||
case 1: // 未付款
|
||||
console.log('[订单服务] 状态1-未付款: 添加取消订单和立即付款按钮');
|
||||
buttons.push({ type: 1, name: '取消订单' });
|
||||
buttons.push({ type: 2, name: '立即付款', primary: true });
|
||||
break;
|
||||
case 2: // 已付款
|
||||
console.log('[订单服务] 状态2-已付款: 添加提醒发货和申请退款按钮');
|
||||
buttons.push({ type: 3, name: '提醒发货', primary: true });
|
||||
buttons.push({ type: 5, name: '申请退款' });
|
||||
break;
|
||||
case 3: // 待发货
|
||||
console.log('[订单服务] 状态3-待发货: 添加提醒发货和申请退款按钮');
|
||||
buttons.push({ type: 3, name: '提醒发货', primary: true });
|
||||
buttons.push({ type: 5, name: '申请退款' });
|
||||
break;
|
||||
case 4: // 已发货
|
||||
console.log('[订单服务] 状态4-已发货: 添加确认收货按钮 (type=4)');
|
||||
buttons.push({ type: 4, name: '确认收货', primary: true });
|
||||
break;
|
||||
case 5: // 待收货
|
||||
console.log('[订单服务] 状态5-待收货: 添加确认收货按钮 (type=4)');
|
||||
buttons.push({ type: 4, name: '确认收货', primary: true });
|
||||
break;
|
||||
case 6: // 已完成
|
||||
console.log('[订单服务] 状态6-已完成: 添加评价按钮 (type=5)');
|
||||
buttons.push({ type: 5, name: '评价', primary: true });
|
||||
break;
|
||||
case 7: // 已取消
|
||||
console.log('[订单服务] 状态7-已取消: 不添加任何按钮');
|
||||
break;
|
||||
case 8: // 已退款
|
||||
case 9: // 已退款
|
||||
console.log('[订单服务] 状态8/9-已退款: 不添加任何按钮');
|
||||
break;
|
||||
default:
|
||||
console.log('[订单服务] 未知状态:', status);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log('[订单服务] ===== 按钮生成完成 =====');
|
||||
console.log('[订单服务] 最终生成的按钮列表:', {
|
||||
status: status,
|
||||
buttonCount: buttons.length,
|
||||
buttons: buttons.map((btn, index) => ({
|
||||
index: index,
|
||||
type: btn.type,
|
||||
name: btn.name,
|
||||
primary: btn.primary || false
|
||||
}))
|
||||
});
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
/** 获取订单列表mock数据 */
|
||||
function mockFetchOrdersCount(params) {
|
||||
console.log('[订单服务] 使用Mock数据获取订单统计', {
|
||||
params,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genOrdersCount } = require('../../model/order/orderList');
|
||||
|
||||
return delay().then(() => {
|
||||
const result = genOrdersCount(params);
|
||||
console.log('[订单服务] Mock统计数据生成完成', result);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取订单列表统计 */
|
||||
export function fetchOrdersCount(params) {
|
||||
console.log('[订单服务] 开始获取订单统计', {
|
||||
params,
|
||||
useMock: config.useMock,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
if (config.useMock) {
|
||||
console.log('[订单服务] 使用Mock模式获取统计');
|
||||
return mockFetchOrdersCount(params);
|
||||
}
|
||||
|
||||
console.log('[订单服务] 使用真实API获取统计(暂未实现)');
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
22
miniprogram/services/order/orderSubmitComment.js
Normal file
22
miniprogram/services/order/orderSubmitComment.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取评价商品 */
|
||||
function mockGetGoods(parameter) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getGoods } = require('../../model/submitComment');
|
||||
const data = getGoods(parameter);
|
||||
|
||||
return delay().then(() => {
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取评价商品 */
|
||||
export function getGoods(parameter) {
|
||||
if (config.useMock) {
|
||||
return mockGetGoods(parameter);
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
271
miniprogram/services/points/index.js
Normal file
271
miniprogram/services/points/index.js
Normal file
@@ -0,0 +1,271 @@
|
||||
import { get, post } from '../_utils/request';
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/**
|
||||
* 积分相关API服务
|
||||
*/
|
||||
|
||||
/**
|
||||
* 获取用户积分
|
||||
*/
|
||||
export function getUserPoints() {
|
||||
if (config.useMock) {
|
||||
console.log('[积分API] Mock - 获取用户积分');
|
||||
return Promise.resolve(mockData.userPoints);
|
||||
}
|
||||
console.log('[积分API] 获取用户积分');
|
||||
return get('/points');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取积分概览
|
||||
*/
|
||||
export function getPointsOverview() {
|
||||
if (config.useMock) {
|
||||
console.log('[积分API] Mock - 获取积分概览');
|
||||
return Promise.resolve(mockData.pointsOverview);
|
||||
}
|
||||
console.log('[积分API] 获取积分概览');
|
||||
return get('/points/overview');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取积分历史记录
|
||||
* @param {Object} params - 查询参数
|
||||
* @param {number} params.page - 页码
|
||||
* @param {number} params.pageSize - 每页数量
|
||||
* @param {string} params.type - 积分类型 (earn/spend)
|
||||
*/
|
||||
export function getPointsHistory(params = {}) {
|
||||
if (config.useMock) {
|
||||
console.log('[积分API] Mock - 获取积分历史记录', params);
|
||||
return Promise.resolve(mockData.pointsHistory);
|
||||
}
|
||||
console.log('[积分API] 获取积分历史记录', params);
|
||||
return get('/points/history', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取积分规则
|
||||
*/
|
||||
export function getPointsRules() {
|
||||
if (config.useMock) {
|
||||
console.log('[积分API] Mock - 获取积分规则');
|
||||
return Promise.resolve(mockData.pointsRules);
|
||||
}
|
||||
console.log('[积分API] 获取积分规则');
|
||||
return get('/points/rules');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取积分兑换商品列表
|
||||
* @param {Object} params - 查询参数
|
||||
* @param {number} params.page - 页码
|
||||
* @param {number} params.pageSize - 每页数量
|
||||
*/
|
||||
export function getPointsExchangeList(params = {}) {
|
||||
if (config.useMock) {
|
||||
console.log('[积分API] Mock - 获取积分兑换商品列表', params);
|
||||
return Promise.resolve(mockData.exchangeList);
|
||||
}
|
||||
console.log('[积分API] 获取积分兑换商品列表', params);
|
||||
return get('/points/exchange', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分兑换
|
||||
* @param {number} exchangeId - 兑换商品ID
|
||||
* @param {number} quantity - 兑换数量
|
||||
*/
|
||||
export function exchangePoints(exchangeId, quantity = 1) {
|
||||
if (config.useMock) {
|
||||
console.log('[积分API] Mock - 积分兑换', { exchangeId, quantity });
|
||||
return Promise.resolve({
|
||||
code: 200,
|
||||
message: '兑换成功',
|
||||
data: {
|
||||
exchange_id: exchangeId,
|
||||
quantity: quantity,
|
||||
points_used: 500 * quantity
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log('[积分API] 积分兑换', { exchangeId, quantity });
|
||||
return post('/points/exchange', { exchange_id: exchangeId, quantity });
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户兑换记录
|
||||
* @param {Object} params - 查询参数
|
||||
* @param {number} params.page - 页码
|
||||
* @param {number} params.pageSize - 每页数量
|
||||
*/
|
||||
export function getUserExchangeRecords(params = {}) {
|
||||
if (config.useMock) {
|
||||
console.log('[积分API] Mock - 获取用户兑换记录', params);
|
||||
return Promise.resolve(mockData.exchangeRecords);
|
||||
}
|
||||
console.log('[积分API] 获取用户兑换记录', params);
|
||||
return get('/points/exchange/records', params);
|
||||
}
|
||||
|
||||
export function dailyCheckin() {
|
||||
if (config.useMock) {
|
||||
console.log('[积分API] Mock - 每日签到');
|
||||
return Promise.resolve({ code: 200, message: '今日登录积分已发放', data: { awarded: true } });
|
||||
}
|
||||
console.log('[积分API] 每日签到');
|
||||
return post('/points/daily-checkin');
|
||||
}
|
||||
// Mock数据 - 用于开发测试
|
||||
const mockData = {
|
||||
userPoints: {
|
||||
code: 200,
|
||||
message: '操作成功',
|
||||
data: {
|
||||
total_points: 1250,
|
||||
available_points: 1250,
|
||||
frozen_points: 0
|
||||
}
|
||||
},
|
||||
|
||||
pointsOverview: {
|
||||
code: 200,
|
||||
message: '操作成功',
|
||||
data: {
|
||||
total_points: 1250,
|
||||
available_points: 1250,
|
||||
frozen_points: 0,
|
||||
total_earned: 2500,
|
||||
total_spent: 1250,
|
||||
this_month_earned: 300,
|
||||
this_month_spent: 150
|
||||
}
|
||||
},
|
||||
|
||||
pointsHistory: {
|
||||
code: 200,
|
||||
message: '操作成功',
|
||||
data: {
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
type: 'earn',
|
||||
points: 100,
|
||||
description: '购物获得积分',
|
||||
source: 'order',
|
||||
created_at: '2024-01-15T10:30:00Z'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'spend',
|
||||
points: -50,
|
||||
description: '兑换优惠券',
|
||||
source: 'exchange',
|
||||
created_at: '2024-01-14T15:20:00Z'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: 'earn',
|
||||
points: 20,
|
||||
description: '每日签到',
|
||||
source: 'checkin',
|
||||
created_at: '2024-01-14T09:00:00Z'
|
||||
}
|
||||
],
|
||||
total: 3,
|
||||
page: 1,
|
||||
page_size: 10
|
||||
}
|
||||
},
|
||||
|
||||
pointsRules: {
|
||||
code: 200,
|
||||
message: '操作成功',
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
title: '购物获得积分', // 修改字段名为title,与后端一致
|
||||
description: '每消费1元获得1积分',
|
||||
points: 1,
|
||||
type: 'order'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '每日签到', // 修改字段名为title,与后端一致
|
||||
description: '每日签到获得20积分',
|
||||
points: 20,
|
||||
type: 'checkin'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '邀请好友', // 修改字段名为title,与后端一致
|
||||
description: '成功邀请好友注册获得100积分',
|
||||
points: 100,
|
||||
type: 'invite'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
exchangeList: {
|
||||
code: 200,
|
||||
message: '操作成功',
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
name: '10元优惠券',
|
||||
description: '满100元可用',
|
||||
points: 500, // 修改字段名为points,与后端一致
|
||||
stock: 100,
|
||||
image: 'https://via.placeholder.com/200x200',
|
||||
type: 'coupon'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '20元优惠券',
|
||||
description: '满200元可用',
|
||||
points: 1000, // 修改字段名为points,与后端一致
|
||||
stock: 50,
|
||||
image: 'https://via.placeholder.com/200x200',
|
||||
type: 'coupon'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '精美礼品',
|
||||
description: '限量版纪念品',
|
||||
points: 2000, // 修改字段名为points,与后端一致
|
||||
stock: 10,
|
||||
image: 'https://via.placeholder.com/200x200',
|
||||
type: 'gift'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
exchangeRecords: {
|
||||
code: 200,
|
||||
message: '操作成功',
|
||||
data: {
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
exchange_item_name: '10元优惠券',
|
||||
points_used: 500,
|
||||
quantity: 1,
|
||||
status: 'completed',
|
||||
created_at: '2024-01-14T15:20:00Z'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
exchange_item_name: '精美礼品',
|
||||
points_used: 2000,
|
||||
quantity: 1,
|
||||
status: 'processing',
|
||||
created_at: '2024-01-13T10:30:00Z'
|
||||
}
|
||||
],
|
||||
total: 2,
|
||||
page: 1,
|
||||
page_size: 10
|
||||
}
|
||||
}
|
||||
};
|
||||
18
miniprogram/services/promotion/detail.js
Normal file
18
miniprogram/services/promotion/detail.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取商品列表 */
|
||||
function mockFetchPromotion(ID = 0) {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { getPromotion } = require('../../model/promotion');
|
||||
return delay().then(() => getPromotion(ID));
|
||||
}
|
||||
|
||||
/** 获取商品列表 */
|
||||
export function fetchPromotion(ID = 0) {
|
||||
if (config.useMock) {
|
||||
return mockFetchPromotion(ID);
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
resolve('real api');
|
||||
});
|
||||
}
|
||||
60
miniprogram/services/usercenter/fetchPerson.js
Normal file
60
miniprogram/services/usercenter/fetchPerson.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取个人中心信息 */
|
||||
function mockFetchPerson() {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genSimpleUserInfo } = require('../../model/usercenter');
|
||||
const { genAddress } = require('../../model/address');
|
||||
const address = genAddress();
|
||||
return delay().then(() => ({
|
||||
...genSimpleUserInfo(),
|
||||
address: {
|
||||
provinceName: address.provinceName,
|
||||
provinceCode: address.provinceCode,
|
||||
cityName: address.cityName,
|
||||
cityCode: address.cityCode,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
/** 获取个人中心信息 */
|
||||
export function fetchPerson() {
|
||||
if (config.useMock) {
|
||||
return mockFetchPerson();
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${config.apiBase}/users/profile`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token') || ''}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
// 转换后端数据格式为前端期望的格式
|
||||
const user = res.data.data;
|
||||
const result = {
|
||||
avatarUrl: user.avatar || '',
|
||||
nickName: user.nickname || '',
|
||||
phoneNumber: user.phone || '',
|
||||
gender: user.gender || 0,
|
||||
level: user.level || 1,
|
||||
address: {
|
||||
provinceName: '北京市',
|
||||
provinceCode: '110000',
|
||||
cityName: '北京市',
|
||||
cityCode: '110100'
|
||||
}
|
||||
};
|
||||
resolve(result);
|
||||
} else {
|
||||
reject(new Error(res.data.message || '获取用户信息失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
85
miniprogram/services/usercenter/fetchUsercenter.js
Normal file
85
miniprogram/services/usercenter/fetchUsercenter.js
Normal file
@@ -0,0 +1,85 @@
|
||||
import { config } from '../../config/index';
|
||||
|
||||
/** 获取个人中心信息 */
|
||||
function mockFetchUserCenter() {
|
||||
const { delay } = require('../_utils/delay');
|
||||
const { genUsercenter } = require('../../model/usercenter');
|
||||
return delay(200).then(() => genUsercenter());
|
||||
}
|
||||
|
||||
/** 获取个人中心信息 */
|
||||
export function fetchUserCenter() {
|
||||
if (config.useMock) {
|
||||
return mockFetchUserCenter();
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// 获取用户中心完整信息
|
||||
wx.request({
|
||||
url: `${config.apiBase}/usercenter`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token') || ''}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
const data = res.data.data;
|
||||
|
||||
// 直接使用后端返回的数据结构
|
||||
const result = {
|
||||
userInfo: data.userInfo,
|
||||
countsData: data.countsData,
|
||||
orderTagInfos: data.orderTagInfos,
|
||||
customerServiceInfo: data.customerServiceInfo
|
||||
};
|
||||
|
||||
resolve(result);
|
||||
} else {
|
||||
// 如果获取失败,返回默认数据
|
||||
resolve({
|
||||
userInfo: {
|
||||
avatarUrl: '',
|
||||
nickName: '正在登录...',
|
||||
phoneNumber: '',
|
||||
gender: 0,
|
||||
},
|
||||
countsData: [],
|
||||
orderTagInfos: [
|
||||
{ orderNum: 0, tabType: 5 },
|
||||
{ orderNum: 0, tabType: 10 },
|
||||
{ orderNum: 0, tabType: 40 },
|
||||
{ orderNum: 0, tabType: 0 },
|
||||
],
|
||||
customerServiceInfo: {
|
||||
servicePhone: '4006336868',
|
||||
serviceTimeDuration: '每周三至周五 9:00-12:00 13:00-15:00',
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('获取用户中心信息失败:', err);
|
||||
// 失败时返回默认数据
|
||||
resolve({
|
||||
userInfo: {
|
||||
avatarUrl: '',
|
||||
nickName: '正在登录...',
|
||||
phoneNumber: '',
|
||||
gender: 0,
|
||||
},
|
||||
countsData: [],
|
||||
orderTagInfos: [
|
||||
{ orderNum: 0, tabType: 5 },
|
||||
{ orderNum: 0, tabType: 10 },
|
||||
{ orderNum: 0, tabType: 40 },
|
||||
{ orderNum: 0, tabType: 0 },
|
||||
],
|
||||
customerServiceInfo: {
|
||||
servicePhone: '4006336868',
|
||||
serviceTimeDuration: '每周三至周五 9:00-12:00 13:00-15:00',
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user