style: 统一中文标点符号为英文格式并更新数据库配置

refactor: 修改注释和描述中的中文标点符号为英文格式
chore: 更新本地数据库配置的端口、密码和数据库名
docs: 删除迁移指南和排列组合修复文档
This commit is contained in:
tikkhun 2026-01-08 21:02:57 +08:00
parent 2888d62037
commit a067720c76
25 changed files with 118 additions and 351 deletions

View File

@ -1,49 +0,0 @@
# 数据库迁移指南
为了支持区域坐标功能,需要执行数据库迁移操作,将新增的 `latitude``longitude` 字段添加到数据库表中.
## 执行迁移步骤
### 1. 生成迁移文件
运行以下命令生成迁移文件:
```bash
npm run migration:generate -- ./src/db/migrations/AddCoordinatesToArea
```
### 2. 检查迁移文件
生成的迁移文件会自动包含添加 `latitude``longitude` 字段的SQL语句.您可以检查文件内容确保迁移逻辑正确.
### 3. 执行迁移
运行以下命令执行迁移,将更改应用到数据库:
```bash
npm run migration:run
```
## 手动迁移SQL(可选)
如果需要手动执行SQL,可以使用以下语句:
```sql
ALTER TABLE `area`
ADD COLUMN `latitude` DECIMAL(10,6) NULL AFTER `name`,
ADD COLUMN `longitude` DECIMAL(10,6) NULL AFTER `latitude`;
```
## 回滚迁移(如需)
如果遇到问题,可以使用以下命令回滚迁移:
```bash
npm run typeorm -- migration:revert -d src/db/datasource.ts
```
## 注意事项
- 确保在执行迁移前备份数据库
- 迁移不会影响现有数据,新增字段默认为 NULL
- 迁移后,可以通过API开始为区域添加坐标信息

View File

@ -1,184 +0,0 @@
# Permutation页面列表显示问题分析和修复方案
## 问题分析
经过代码分析,发现了以下几个可能导致列表不显示的问题:
### 1. API路径不匹配
前端代码中引用的API函数名与后端控制器中的路径不一致
- 前端:`productcontrollerGetcategoriesall`、`productcontrollerGetcategoryattributes`、`productcontrollerGetproductlist`
- 后端实际的API路径`/product/categories/all`、`/product/category/:id/attributes`、`/product/list`
### 2. 数据格式问题
- `getCategoryAttributes`返回的数据结构与前端期望的不匹配
- 属性值获取逻辑可能存在问题
### 3. 组合生成逻辑问题
- 在生成排列组合时,数据结构和键值对应可能不正确
## 修复方案
### 后端修复
1. **修改getCategoryAttributes方法** - 在`/Users/zksu/Developer/work/workcode/API/src/service/product.service.ts`中:
```typescript
// 获取分类下的属性配置
async getCategoryAttributes(categoryId: number): Promise<any[]> {
const category = await this.categoryModel.findOne({
where: { id: categoryId },
relations: ['attributes', 'attributes.attributeDict', 'attributes.attributeDict.items'],
});
if (!category) {
return [];
}
// 格式化返回,匹配前端期望的数据结构
return category.attributes.map(attr => ({
id: attr.id,
dictId: attr.attributeDict.id,
name: attr.attributeDict.name, // 用于generateKeyFromPermutation
title: attr.attributeDict.title, // 用于列标题
dict: {
id: attr.attributeDict.id,
name: attr.attributeDict.name,
title: attr.attributeDict.title,
items: attr.attributeDict.items || []
}
}));
}
```
2. **确保dict/items接口可用** - 检查字典项获取接口:
在`/Users/zksu/Developer/work/workcode/API/src/controller/dict.controller.ts`中添加或确认:
```typescript
@Get('/items')
async getDictItems(@Query('dictId') dictId: number) {
try {
const dict = await this.dictModel.findOne({
where: { id: dictId },
relations: ['items']
});
if (!dict) {
return [];
}
return dict.items || [];
} catch (error) {
return errorResponse(error?.message || error);
}
}
```
### 前端修复建议
1. **添加错误处理和调试信息**
```typescript
// 在获取属性值的地方添加错误处理
const fetchData = async () => {
setLoading(true);
try {
// 1. Fetch Attributes
const attrRes = await productcontrollerGetcategoryattributes({
id: categoryId,
});
console.log('Attributes response:', attrRes); // 调试用
const attrs = Array.isArray(attrRes) ? attrRes : attrRes?.data || [];
setAttributes(attrs);
// 2. Fetch Attribute Values (Dict Items)
const valuesMap: Record<string, any[]> = {};
for (const attr of attrs) {
const dictId = attr.dict?.id || attr.dictId;
if (dictId) {
try {
const itemsRes = await request('/dict/items', {
params: { dictId },
});
console.log(`Dict items for ${attr.name}:`, itemsRes); // 调试用
valuesMap[attr.name] = itemsRes || [];
} catch (error) {
console.error(`Failed to fetch items for dict ${dictId}:`, error);
valuesMap[attr.name] = [];
}
}
}
setAttributeValues(valuesMap);
// 3. Fetch Existing Products
await fetchProducts(categoryId);
} catch (error) {
console.error('Error in fetchData:', error);
message.error('获取数据失败');
} finally {
setLoading(false);
}
};
```
2. **修复组合生成逻辑**
```typescript
// 修改generateKeyFromPermutation函数
const generateKeyFromPermutation = (perm: any) => {
const parts = Object.keys(perm).map((attrName) => {
const valItem = perm[attrName];
const val = valItem.name || valItem.value; // 兼容不同的数据格式
return `${attrName}:${val}`;
});
return parts.sort().join('|');
};
// 修改generateAttributeKey函数
const generateAttributeKey = (attrs: any[]) => {
const parts = attrs.map((a) => {
const key = a.dict?.name || a.dictName || a.name;
const val = a.name || a.value;
return `${key}:${val}`;
});
return parts.sort().join('|');
};
```
3. **添加空状态处理**
```typescript
// 在ProTable中添加空状态提示
<ProTable
// ... 其他属性
locale={{
emptyText: permutations.length === 0 && !loading ? '暂无数据,请检查分类属性配置' : '暂无数据'
}}
/>
```
## 调试步骤
1. **检查网络请求**
- 打开浏览器开发者工具
- 检查 `/product/categories/all` 请求是否成功
- 检查 `/product/category/:id/attributes` 请求返回的数据格式
- 检查 `/dict/items?dictId=:id` 请求是否成功
- 检查 `/product/list` 请求是否成功
2. **检查控制台日志**
- 查看属性数据是否正确加载
- 查看属性值是否正确获取
- 查看排列组合是否正确生成
3. **检查数据结构**
- 确认 `attributes` 数组是否正确
- 确认 `attributeValues` 对象是否正确填充
- 确认 `permutations` 数组是否正确生成
## 测试验证
1. 选择一个有属性配置的分类
2. 确认属性有对应的字典项
3. 检查排列组合是否正确显示
4. 验证现有产品匹配是否正确

View File

@ -405,7 +405,7 @@ export class ShopyyAdapter implements ISiteAdapter {
}
mapUpdateOrderParams(data: Partial<UnifiedOrderDTO>): any {
// 构建 ShopYY 订单更新参数(仅包含传入的字段)
// 构建 ShopYY 订单更新参数(仅包含传入的字段)
const params: any = {};
// 仅当字段存在时才添加到更新参数中
@ -665,7 +665,7 @@ export class ShopyyAdapter implements ISiteAdapter {
const statusMap = {
'pending': '100', // 100 未完成
'processing': '110', // 110 待处理
'completed': "180", // 180 已完成(确认收货)
'completed': "180", // 180 已完成(确认收货)
'cancelled': '190', // 190 取消
};
@ -797,7 +797,7 @@ export class ShopyyAdapter implements ISiteAdapter {
return status === 'publish' ? 1 : 0;
};
// 构建 ShopYY 产品更新参数(仅包含传入的字段)
// 构建 ShopYY 产品更新参数(仅包含传入的字段)
const params: any = {};
// 仅当字段存在时才添加到更新参数中
@ -816,7 +816,7 @@ export class ShopyyAdapter implements ISiteAdapter {
params.inventory_quantity = data.stock_status === 'instock' ? (data.stock_quantity || 1) : 0;
}
// 添加变体信息(如果存在)
// 添加变体信息(如果存在)
if (data.variations && data.variations.length > 0) {
params.variants = data.variations.map((variation: UnifiedProductVariationDTO) => {
const variationParams: any = {};
@ -836,7 +836,7 @@ export class ShopyyAdapter implements ISiteAdapter {
});
}
// 添加图片信息(如果存在)
// 添加图片信息(如果存在)
if (data.images && data.images.length > 0) {
params.images = data.images.map((image: any) => ({
id: image.id,
@ -846,12 +846,12 @@ export class ShopyyAdapter implements ISiteAdapter {
}));
}
// 添加标签信息(如果存在)
// 添加标签信息(如果存在)
if (data.tags && data.tags.length > 0) {
params.tags = data.tags.map((tag: any) => tag.name || '');
}
// 添加分类信息(如果存在)
// 添加分类信息(如果存在)
if (data.categories && data.categories.length > 0) {
params.collections = data.categories.map((category: any) => ({
id: category.id,
@ -1121,7 +1121,7 @@ export class ShopyyAdapter implements ISiteAdapter {
}
mapUpdateVariationParams(data: Partial<UnifiedProductVariationDTO>): any {
// 构建 ShopYY 变体更新参数(仅包含传入的字段)
// 构建 ShopYY 变体更新参数(仅包含传入的字段)
const params: any = {};
// 仅当字段存在时才添加到更新参数中
@ -1292,12 +1292,12 @@ export class ShopyyAdapter implements ISiteAdapter {
return stockStatus === 'instock' ? 1 : 0;
};
shopyyOrderStatusMap = {//订单状态 100 未完成110 待处理180 已完成(确认收货); 190 取消;
shopyyOrderStatusMap = {//订单状态 100 未完成110 待处理180 已完成(确认收货); 190 取消;
[100]: OrderStatus.PENDING, // 100 未完成 转为 pending
[110]: OrderStatus.PROCESSING, // 110 待处理 转为 processing
// 已发货
[180]: OrderStatus.COMPLETED, // 180 已完成(确认收货) 转为 completed
[180]: OrderStatus.COMPLETED, // 180 已完成(确认收货) 转为 completed
[190]: OrderStatus.CANCEL // 190 取消 转为 cancelled
}

View File

@ -609,7 +609,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
// await api.put(`orders/${orderId}`, { status: 'processing' });
// // 添加取消履行的备注
// const note = `订单履行已取消${data.reason ? `,原因${data.reason}` : ''}`;
// const note = `订单履行已取消${data.reason ? `,原因:${data.reason}` : ''}`;
// await api.post(`orders/${orderId}/notes`, { note, customer_note: true });
// return {
@ -698,14 +698,14 @@ export class WooCommerceAdapter implements ISiteAdapter {
}));
}
// 映射变体数据注意WooCommerce API 中变体通常通过单独的端点处理)
// 映射变体数据(注意:WooCommerce API 中变体通常通过单独的端点处理)
// 这里只映射变体的基本信息,具体创建/更新变体需要额外处理
if (data.variations && Array.isArray(data.variations)) {
// 对于WooProduct类型variations字段只存储变体ID
mapped.variations = data.variations.map(variation => variation.id as number);
}
// 映射下载数据(如果产品是可下载的)
// 映射下载数据(如果产品是可下载的)
// if (data.downloads && Array.isArray(data.downloads)) {
// mapped.downloads = data.downloads.map(download => ({
// id: download.id as number,

View File

@ -16,10 +16,10 @@ export default {
dataSource: {
default: {
host: 'localhost',
port: "3306",
port: "23306",
username: 'root',
password: 'root',
database: 'inventory',
password: '12345678',
database: 'inventory_v2',
},
},
},

View File

@ -99,7 +99,7 @@ export class MainConfiguration {
}
/**
*
* ()
*/
private async initializeDatabase(): Promise<void> {
// 使用注入的数据库配置

View File

@ -299,7 +299,7 @@ export class SiteApiController {
}
}
// 平台特性产品导出特殊CSV走平台服务
// 平台特性:产品导出(特殊CSV走平台服务)
@Get('/:siteId/links')
async getLinks(
@Param('siteId') siteId: number
@ -429,7 +429,7 @@ export class SiteApiController {
}
}
// 平台特性产品导入特殊CSV走平台服务
// 平台特性:产品导入(特殊CSV走平台服务)
@Post('/:siteId/products/import-special')
@ApiOkResponse({ type: Object })
async importProductsSpecial(
@ -443,7 +443,7 @@ export class SiteApiController {
const created: any[] = [];
const failed: any[] = [];
if (site.type === 'woocommerce') {
// 解析 CSV 为对象数组(若传入 items 则优先 items
// 解析 CSV 为对象数组(若传入 items 则优先 items)
let payloads = items;
if (!payloads.length && csvText) {
const lines = csvText.split(/\r?\n/).filter(Boolean);

View File

@ -126,7 +126,7 @@ const flavorsData = [
{ name: 'arctic-mint', title: 'arctic mint', titleCn: '北极薄荷', shortName: 'AR' },
{ name: 'baddie-blueberries', title: 'baddie blueberries', titleCn: '时髦蓝莓', shortName: 'BA' },
{ name: 'banana', title: 'banana', titleCn: '香蕉', shortName: 'BA' },
{ name: 'banana-(solid)', title: 'banana (solid)', titleCn: '香蕉(固体)', shortName: 'BA' },
{ name: 'banana-(solid)', title: 'banana (solid)', titleCn: '香蕉(固体)', shortName: 'BA' },
{ name: 'banana-berry', title: 'banana berry', titleCn: '香蕉莓果', shortName: 'BA' },
{ name: 'banana-berry-melon-ice', title: 'banana berry melon ice', titleCn: '香蕉莓果瓜冰', shortName: 'BA' },
{ name: 'banana-blackberry', title: 'banana blackberry', titleCn: '香蕉黑莓', shortName: 'BA' },
@ -137,7 +137,7 @@ const flavorsData = [
{ name: 'bangin-blood-orange-iced', title: 'bangin blood orange iced', titleCn: '爆炸血橙冰', shortName: 'BA' },
{ name: 'berries-in-the-6ix', title: 'berries in the 6ix', titleCn: '多伦多莓果', shortName: 'BE' },
{ name: 'berry-burst', title: 'berry burst', titleCn: '浆果爆发', shortName: 'BE' },
{ name: 'berry-burst-(thermal)', title: 'berry burst (thermal)', titleCn: '浆果爆发(热感)', shortName: 'BE' },
{ name: 'berry-burst-(thermal)', title: 'berry burst (thermal)', titleCn: '浆果爆发(热感)', shortName: 'BE' },
{ name: 'berry-ice', title: 'berry ice', titleCn: '浆果冰', shortName: 'BE' },
{ name: 'berry-lime-ice', title: 'berry lime ice', titleCn: '浆果青柠冰', shortName: 'BE' },
{ name: 'berry-trio-ice', title: 'berry trio ice', titleCn: '三重浆果冰', shortName: 'BE' },
@ -145,7 +145,7 @@ const flavorsData = [
{ name: 'black-cherry', title: 'black cherry', titleCn: '黑樱桃', shortName: 'BL' },
{ name: 'blackcherry', title: 'blackcherry', titleCn: '黑樱桃混合', shortName: 'BL' },
{ name: 'blackcurrant-ice', title: 'blackcurrant ice', titleCn: '黑加仑冰', shortName: 'BL' },
{ name: 'black-currant-ice', title: 'black currant ice', titleCn: '黑加仑冰(空格版)', shortName: 'BL' },
{ name: 'black-currant-ice', title: 'black currant ice', titleCn: '黑加仑冰(空格版)', shortName: 'BL' },
{ name: 'black-licorice', title: 'black licorice', titleCn: '黑甘草', shortName: 'BL' },
{ name: 'black-tea', title: 'black tea', titleCn: '红茶', shortName: 'BL' },
{ name: 'blackberry-ice', title: 'blackberry ice', titleCn: '黑莓冰', shortName: 'BL' },
@ -168,7 +168,7 @@ const flavorsData = [
{ name: 'blue-razz', title: 'blue razz', titleCn: '蓝覆盆子', shortName: 'BL' },
{ name: 'blue-razz-hype', title: 'blue razz hype', titleCn: '蓝覆盆子热情', shortName: 'BL' },
{ name: 'blue-razz-ice', title: 'blue razz ice', titleCn: '蓝覆盆子冰', shortName: 'BL' },
{ name: 'blue-razz-ice-(solid)', title: 'blue razz ice (solid)', titleCn: '蓝覆盆子冰(固体)', shortName: 'BL' },
{ name: 'blue-razz-ice-(solid)', title: 'blue razz ice (solid)', titleCn: '蓝覆盆子冰(固体)', shortName: 'BL' },
{ name: 'blue-razz-ice-glace', title: 'blue razz ice glace', titleCn: '蓝覆盆子冰格', shortName: 'BL' },
{ name: 'blue-razz-lemon-ice', title: 'blue razz lemon ice', titleCn: '蓝覆盆子柠檬冰', shortName: 'BL' },
{ name: 'blue-razz-lemonade', title: 'blue razz lemonade', titleCn: '蓝覆盆子柠檬水', shortName: 'BL' },
@ -196,7 +196,7 @@ const flavorsData = [
{ name: 'bumpin-blackcurrant-iced', title: 'bumpin blackcurrant iced', titleCn: '黑加仑热烈冰', shortName: 'BU' },
{ name: 'burst-ice', title: 'burst ice', titleCn: '爆炸冰', shortName: 'BU' },
{ name: 'bussin-banana-iced', title: 'bussin banana iced', titleCn: '香蕉热烈冰', shortName: 'BU' },
{ name: 'bussin-banana-iced', title: 'bussin banana iced', titleCn: '香蕉热烈冰(重复)', shortName: 'BU' },
{ name: 'bussin-banana-iced', title: 'bussin banana iced', titleCn: '香蕉热烈冰(重复)', shortName: 'BU' },
{ name: 'california-cherry', title: 'california cherry', titleCn: '加州樱桃', shortName: 'CA' },
{ name: 'cantaloupe-mango-banana', title: 'cantaloupe mango banana', titleCn: '香瓜芒果香蕉', shortName: 'CA' },
{ name: 'caramel', title: 'caramel', titleCn: '焦糖', shortName: 'CA' },
@ -230,7 +230,7 @@ const flavorsData = [
{ name: 'citrus-chill', title: 'citrus chill', titleCn: '柑橘清凉', shortName: 'CI' },
{ name: 'citrus-smash-ice', title: 'citrus smash ice', titleCn: '柑橘冲击冰', shortName: 'CI' },
{ name: 'citrus-sunrise', title: 'citrus sunrise', titleCn: '柑橘日出', shortName: 'CI' },
{ name: 'citrus-sunrise-(thermal)', title: 'citrus sunrise (thermal)', titleCn: '柑橘日出(热感)', shortName: 'CI' },
{ name: 'citrus-sunrise-(thermal)', title: 'citrus sunrise (thermal)', titleCn: '柑橘日出(热感)', shortName: 'CI' },
{ name: 'classic', title: 'classic', titleCn: '经典', shortName: 'CL' },
{ name: 'classic-ice', title: 'classic ice', titleCn: '经典冰', shortName: 'CL' },
{ name: 'classic-mint-ice', title: 'classic mint ice', titleCn: '经典薄荷冰', shortName: 'CL' },
@ -310,7 +310,7 @@ const flavorsData = [
{ name: 'fizzy', title: 'fizzy', titleCn: '汽水', shortName: 'FI' },
{ name: 'flavourless', title: 'flavourless', titleCn: '无味', shortName: 'FL' },
{ name: 'flippin-fruit-flash', title: 'flippin fruit flash', titleCn: '翻转水果闪电', shortName: 'FL' },
{ name: 'flippin-fruit-flash-(rainbow-burst)', title: 'flippin fruit flash (rainbow burst)', titleCn: '翻转水果闪电(彩虹爆发)', shortName: 'FL' },
{ name: 'flippin-fruit-flash-(rainbow-burst)', title: 'flippin fruit flash (rainbow burst)', titleCn: '翻转水果闪电(彩虹爆发)', shortName: 'FL' },
{ name: 'forest-fruits', title: 'forest fruits', titleCn: '森林水果', shortName: 'FO' },
{ name: 'fragrant-grapefruit', title: 'fragrant grapefruit', titleCn: '香气葡萄柚', shortName: 'FR' },
{ name: 'freeze', title: 'freeze', titleCn: '冰冻', shortName: 'FR' },
@ -340,14 +340,14 @@ const flavorsData = [
{ name: 'fuji-melon-ice', title: 'fuji melon ice', titleCn: '富士瓜冰', shortName: 'FU' },
{ name: 'full-charge', title: 'full charge', titleCn: '满电', shortName: 'FU' },
{ name: 'gb', title: 'gb', titleCn: '软糖', shortName: 'GB' },
{ name: 'gb(gummy-bear)', title: 'gb(gummy bear)', titleCn: '软糖Gummy Bear', shortName: 'GB' },
{ name: 'gb(gummy-bear)', title: 'gb(gummy bear)', titleCn: '软糖(Gummy Bear)', shortName: 'GB' },
{ name: 'gentle-mint', title: 'gentle mint', titleCn: '温和薄荷', shortName: 'GE' },
{ name: 'ghost-cola-&-vanilla', title: 'ghost cola & vanilla', titleCn: '幽灵可乐香草', shortName: 'GH' },
{ name: 'ghost-cola-ice', title: 'ghost cola ice', titleCn: '幽灵可乐冰', shortName: 'GH' },
{ name: 'ghost-mango', title: 'ghost mango', titleCn: '幽灵芒果', shortName: 'GH' },
{ name: 'ghost-original', title: 'ghost original', titleCn: '幽灵原味', shortName: 'GH' },
{ name: 'ghost-watermelon-ice', title: 'ghost watermelon ice', titleCn: '幽灵西瓜冰', shortName: 'GH' },
{ name: 'gnarly-green-d-(green-dew)', title: 'gnarly green d (green dew)', titleCn: '狂野绿 D(绿色露水)', shortName: 'GN' },
{ name: 'gnarly-green-d-(green-dew)', title: 'gnarly green d (green dew)', titleCn: '狂野绿 D(绿色露水)', shortName: 'GN' },
{ name: 'gold-edition', title: 'gold edition', titleCn: '金版', shortName: 'GO' },
{ name: 'grape', title: 'grape', titleCn: '葡萄', shortName: 'GR' },
{ name: 'grape-cherry', title: 'grape cherry', titleCn: '葡萄樱桃', shortName: 'GR' },
@ -492,13 +492,13 @@ const flavorsData = [
{ name: 'mixed-fruit', title: 'mixed fruit', titleCn: '混合水果', shortName: 'MI' },
{ name: 'mocha-ice', title: 'mocha ice', titleCn: '摩卡冰', shortName: 'MO' },
{ name: 'morocco-mint', title: 'morocco mint', titleCn: '摩洛哥薄荷', shortName: 'MO' },
{ name: 'morocco-mint-(thermal)', title: 'morocco mint (thermal)', titleCn: '摩洛哥薄荷(热感)', shortName: 'MO' },
{ name: 'morocco-mint-(thermal)', title: 'morocco mint (thermal)', titleCn: '摩洛哥薄荷(热感)', shortName: 'MO' },
{ name: 'mung-beans', title: 'mung beans', titleCn: '绿豆', shortName: 'MU' },
{ name: 'nasty-tropic', title: 'nasty tropic', titleCn: '恶搞热带', shortName: 'NA' },
{ name: 'nectarine-ice', title: 'nectarine ice', titleCn: '油桃冰', shortName: 'NE' },
{ name: 'night-rider', title: 'night rider', titleCn: '夜骑', shortName: 'NI' },
{ name: 'nirvana', title: 'nirvana', titleCn: '宁静蓝莓', shortName: 'NI' },
{ name: 'north-american-style(root-beer)', title: 'north american style(root beer)', titleCn: '北美风格(根啤)', shortName: 'NO' },
{ name: 'north-american-style(root-beer)', title: 'north american style(root beer)', titleCn: '北美风格(根啤)', shortName: 'NO' },
{ name: 'northern-blue-razz', title: 'northern blue razz', titleCn: '北方蓝覆盆子', shortName: 'NO' },
{ name: 'nutty-virginia', title: 'nutty virginia', titleCn: '坚果弗吉尼亚', shortName: 'NU' },
{ name: 'orange', title: 'orange', titleCn: '橙子', shortName: 'OR' },
@ -508,12 +508,12 @@ const flavorsData = [
{ name: 'orange-mango-guava', title: 'orange mango guava', titleCn: '橙子芒果番石榴', shortName: 'OR' },
{ name: 'orange-mango-pineapple-ice', title: 'orange mango pineapple ice', titleCn: '橙子芒果菠萝冰', shortName: 'OR' },
{ name: 'orange-p', title: 'orange p', titleCn: '橙子 P', shortName: 'OR' },
{ name: 'orange-p(fanta)', title: 'orange p(fanta)', titleCn: '橙子 P(芬达)', shortName: 'OR' },
{ name: 'orange-p(fanta)', title: 'orange p(fanta)', titleCn: '橙子 P(芬达)', shortName: 'OR' },
{ name: 'orange-spark', title: 'orange spark', titleCn: '橙色火花', shortName: 'OR' },
{ name: 'orange-tangerine', title: 'orange tangerine', titleCn: '橙子柑橘', shortName: 'OR' },
{ name: 'original', title: 'original', titleCn: '原味', shortName: 'OR' },
{ name: 'packin-peach-berry', title: 'packin peach berry', titleCn: '装满桃浆果', shortName: 'PA' },
{ name: 'packin-peach-berry-(popn-peach-berry)', title: 'packin peach berry (popn peach berry)', titleCn: '装满桃浆果Popn 桃浆果)', shortName: 'PA' },
{ name: 'packin-peach-berry-(popn-peach-berry)', title: 'packin peach berry (popn peach berry)', titleCn: '装满桃浆果(Popn 桃浆果)', shortName: 'PA' },
{ name: 'papio', title: 'papio', titleCn: 'Papio', shortName: 'PA' },
{ name: 'paradise', title: 'paradise', titleCn: '天堂', shortName: 'PA' },
{ name: 'paradise-iced', title: 'paradise iced', titleCn: '天堂冰', shortName: 'PA' },
@ -603,7 +603,7 @@ const flavorsData = [
{ name: 'red-fruits', title: 'red fruits', titleCn: '红色水果', shortName: 'RE' },
{ name: 'red-lightning', title: 'red lightning', titleCn: '红色闪电', shortName: 'RE' },
{ name: 'red-line', title: 'red line', titleCn: '红线', shortName: 'RE' },
{ name: 'red-line-(energy-drink)', title: 'red line (energy drink)', titleCn: '红线(能量饮料)', shortName: 'RE' },
{ name: 'red-line-(energy-drink)', title: 'red line (energy drink)', titleCn: '红线(能量饮料)', shortName: 'RE' },
{ name: 'red-magic', title: 'red magic', titleCn: '红魔', shortName: 'RE' },
{ name: 'rich-tobacco', title: 'rich tobacco', titleCn: '浓烈烟草', shortName: 'RI' },
{ name: 'root-beer', title: 'root beer', titleCn: '根啤', shortName: 'RO' },
@ -625,8 +625,8 @@ const flavorsData = [
{ name: 'sic-strawberry-iced', title: 'sic strawberry iced', titleCn: '意大利草莓冰', shortName: 'SI' },
{ name: 'simply-spearmint', title: 'simply spearmint', titleCn: '清爽留兰香', shortName: 'SI' },
{ name: 'skc', title: 'skc', titleCn: 'SKC', shortName: 'SK' },
{ name: 'skc(skittles-candy)', title: 'skc(skittles candy)', titleCn: 'SKC(彩虹糖)', shortName: 'SK' },
{ name: 'slammin-sts-(sour-snap)', title: 'slammin sts (sour snap)', titleCn: '热烈 STS(酸糖)', shortName: 'SL' },
{ name: 'skc(skittles-candy)', title: 'skc(skittles candy)', titleCn: 'SKC(彩虹糖)', shortName: 'SK' },
{ name: 'slammin-sts-(sour-snap)', title: 'slammin sts (sour snap)', titleCn: '热烈 STS(酸糖)', shortName: 'SL' },
{ name: 'slammin-sts-iced', title: 'slammin sts iced', titleCn: '热烈 STS 冰', shortName: 'SL' },
{ name: 'smooth', title: 'smooth', titleCn: '顺滑', shortName: 'SM' },
{ name: 'smooth-mint', title: 'smooth mint', titleCn: '顺滑薄荷', shortName: 'SM' },
@ -664,7 +664,7 @@ const flavorsData = [
{ name: 'strawberry-jasmine-t', title: 'strawberry jasmine t', titleCn: '草莓茉莉茶', shortName: 'ST' },
{ name: 'strawberry-jasmine-tea', title: 'strawberry jasmine tea', titleCn: '草莓茉莉茶', shortName: 'ST' },
{ name: 'strawberry-kiwi', title: 'strawberry kiwi', titleCn: '草莓奇异果', shortName: 'ST' },
{ name: 'strawberry-kiwi-(solid)', title: 'strawberry kiwi (solid)', titleCn: '草莓奇异果(固体)', shortName: 'ST' },
{ name: 'strawberry-kiwi-(solid)', title: 'strawberry kiwi (solid)', titleCn: '草莓奇异果(固体)', shortName: 'ST' },
{ name: 'strawberry-kiwi-banana-ice', title: 'strawberry kiwi banana ice', titleCn: '草莓奇异果香蕉冰', shortName: 'ST' },
{ name: 'strawberry-kiwi-guava-ice', title: 'strawberry kiwi guava ice', titleCn: '草莓奇异果番石榴冰', shortName: 'ST' },
{ name: 'strawberry-kiwi-ice', title: 'strawberry kiwi ice', titleCn: '草莓奇异果冰', shortName: 'ST' },
@ -680,10 +680,10 @@ const flavorsData = [
{ name: 'strawberry-watermelon', title: 'strawberry watermelon', titleCn: '草莓西瓜', shortName: 'ST' },
{ name: 'strawberry-watermelon-ice', title: 'strawberry watermelon ice', titleCn: '草莓西瓜冰', shortName: 'ST' },
{ name: 'strawmelon-peach', title: 'strawmelon peach', titleCn: '草莓桃', shortName: 'ST' },
{ name: 'strawmelon-peach-(solid)', title: 'strawmelon peach (solid)', titleCn: '草莓桃(固体)', shortName: 'ST' },
{ name: 'strawmelon-peach-(solid)', title: 'strawmelon peach (solid)', titleCn: '草莓桃(固体)', shortName: 'ST' },
{ name: 'strawnana-orange', title: 'strawnana orange', titleCn: '草莓香蕉橙', shortName: 'ST' },
{ name: 'summer-grape', title: 'summer grape', titleCn: '夏日葡萄', shortName: 'SU' },
{ name: 'summer-grape-(thermal)', title: 'summer grape (thermal)', titleCn: '夏日葡萄(热感)', shortName: 'SU' },
{ name: 'summer-grape-(thermal)', title: 'summer grape (thermal)', titleCn: '夏日葡萄(热感)', shortName: 'SU' },
{ name: 'super-sour-blueberry-iced', title: 'super sour blueberry iced', titleCn: '超级酸蓝莓冰', shortName: 'SU' },
{ name: 'super-spearmint', title: 'super spearmint', titleCn: '超级留兰香', shortName: 'SU' },
{ name: 'super-spearmint-iced', title: 'super spearmint iced', titleCn: '超级留兰香冰', shortName: 'SU' },
@ -704,7 +704,7 @@ const flavorsData = [
{ name: 'tropical-orang-ice', title: 'tropical orang ice', titleCn: '热带橙冰', shortName: 'TR' },
{ name: 'tropical-prism-blast', title: 'tropical prism blast', titleCn: '热带棱镜爆炸', shortName: 'TR' },
{ name: 'tropical-splash', title: 'tropical splash', titleCn: '热带飞溅', shortName: 'TR' },
{ name: 'tropical-splash-(solid)', title: 'tropical splash (solid)', titleCn: '热带飞溅(固体)', shortName: 'TR' },
{ name: 'tropical-splash-(solid)', title: 'tropical splash (solid)', titleCn: '热带飞溅(固体)', shortName: 'TR' },
{ name: 'tropical-storm-ice', title: 'tropical storm ice', titleCn: '热带风暴冰', shortName: 'TR' },
{ name: 'tropical-summer', title: 'tropical summer', titleCn: '热带夏日', shortName: 'TR' },
{ name: 'tropika', title: 'tropika', titleCn: '热带果', shortName: 'TR' },
@ -728,7 +728,7 @@ const flavorsData = [
{ name: 'watermelon-cantaloupe-honeydew-ice', title: 'watermelon cantaloupe honeydew ice', titleCn: '西瓜香瓜蜜瓜冰', shortName: 'WA' },
{ name: 'watermelon-g', title: 'watermelon g', titleCn: '西瓜 G', shortName: 'WA' },
{ name: 'watermelon-ice', title: 'watermelon ice', titleCn: '西瓜冰', shortName: 'WA' },
{ name: 'watermelon-ice-(solid)', title: 'watermelon ice (solid)', titleCn: '西瓜冰(固体)', shortName: 'WA' },
{ name: 'watermelon-ice-(solid)', title: 'watermelon ice (solid)', titleCn: '西瓜冰(固体)', shortName: 'WA' },
{ name: 'watermelon-lime-ice', title: 'watermelon lime ice', titleCn: '西瓜青柠冰', shortName: 'WA' },
{ name: 'watermelon-mango-tango', title: 'watermelon mango tango', titleCn: '西瓜芒果探戈', shortName: 'WA' },
{ name: 'watermelona-cg', title: 'watermelona cg', titleCn: '西瓜 CG', shortName: 'WA' },
@ -750,7 +750,7 @@ const flavorsData = [
{ name: 'wild-strawberry-watermelon', title: 'wild strawberry watermelon', titleCn: '野生草莓西瓜', shortName: 'WI' },
{ name: 'wild-white-grape', title: 'wild white grape', titleCn: '野生白葡萄', shortName: 'WI' },
{ name: 'wild-white-grape-ice', title: 'wild white grape ice', titleCn: '野生白葡萄冰', shortName: 'WI' },
{ name: 'wild-white-grape-iced', title: 'wild white grape iced', titleCn: '野生白葡萄冰(冷饮)', shortName: 'WI' },
{ name: 'wild-white-grape-iced', title: 'wild white grape iced', titleCn: '野生白葡萄冰(冷饮)', shortName: 'WI' },
{ name: 'winter-berry-ice', title: 'winter berry ice', titleCn: '冬季浆果冰', shortName: 'WI' },
{ name: 'winter-green', title: 'winter green', titleCn: '冬青', shortName: 'WI' },
{ name: 'wintergreen', title: 'wintergreen', titleCn: '冬青薄荷', shortName: 'WI' },

View File

@ -56,7 +56,7 @@ export class UnifiedSearchParamsDTO<Where=Record<string, any>> {
*
*/
export interface BatchErrorItem {
// 错误项标识可以是ID、邮箱等
// 错误项标识(可以是ID、邮箱等)
identifier: string;
// 错误信息
error: string;
@ -76,7 +76,7 @@ export interface BatchOperationResult {
updated?: number;
// 删除数量
deleted?: number;
// 跳过的数量(如数据已存在或无需处理)
// 跳过的数量(如数据已存在或无需处理)
skipped?: number;
// 错误列表
errors: BatchErrorItem[];
@ -101,7 +101,7 @@ export class SyncOperationResult implements BatchOperationResult {
* DTO
*/
export class BatchErrorItemDTO {
@ApiProperty({ description: '错误项标识如ID、邮箱等', type: String })
@ApiProperty({ description: '错误项标识(如ID、邮箱等)', type: String })
@Rule(RuleType.string().required())
identifier: string;
@ -164,7 +164,7 @@ export class SyncParamsDTO {
@Rule(RuleType.string().optional())
endDate?: string;
@ApiProperty({ description: '强制同步(忽略缓存)', type: Boolean, required: false, default: false })
@ApiProperty({ description: '强制同步(忽略缓存)', type: Boolean, required: false, default: false })
@Rule(RuleType.boolean().optional())
force?: boolean = false;
}
@ -183,7 +183,7 @@ export class BatchQueryDTO {
}
/**
*
* ()
*/
export class BatchOperationResultDTOGeneric<T> extends BatchOperationResultDTO {
@ApiProperty({ description: '操作成功的数据列表', type: Array })
@ -191,7 +191,7 @@ export class BatchOperationResultDTOGeneric<T> extends BatchOperationResultDTO {
}
/**
*
* ()
*/
export class SyncOperationResultDTOGeneric<T> extends SyncOperationResultDTO {
@ApiProperty({ description: '同步成功的数据列表', type: Array })

View File

@ -5,7 +5,7 @@ import { Rule, RuleType } from '@midwayjs/validate';
*
*/
export interface BatchErrorItem {
// 错误项标识可以是ID、邮箱等
// 错误项标识(可以是ID、邮箱等)
identifier: string;
// 错误信息
error: string;
@ -25,7 +25,7 @@ export interface BatchOperationResult {
updated?: number;
// 删除数量
deleted?: number;
// 跳过的数量(如数据已存在或无需处理)
// 跳过的数量(如数据已存在或无需处理)
skipped?: number;
// 错误列表
errors: BatchErrorItem[];
@ -43,7 +43,7 @@ export interface SyncOperationResult extends BatchOperationResult {
* DTO
*/
export class BatchErrorItemDTO {
@ApiProperty({ description: '错误项标识如ID、邮箱等', type: String })
@ApiProperty({ description: '错误项标识(如ID、邮箱等)', type: String })
@Rule(RuleType.string().required())
identifier: string;
@ -114,7 +114,7 @@ export class BatchDeleteDTO {
}
/**
* DTO
* DTO()
*/
export class BatchOperationDTO<T = any> {
@ApiProperty({ description: '要创建的数据列表', type: Array, required: false })
@ -175,7 +175,7 @@ export class SyncParamsDTO {
@Rule(RuleType.string().optional())
endDate?: string;
@ApiProperty({ description: '强制同步(忽略缓存)', type: Boolean, required: false, default: false })
@ApiProperty({ description: '强制同步(忽略缓存)', type: Boolean, required: false, default: false })
@Rule(RuleType.boolean().optional())
force?: boolean = false;
}
@ -194,7 +194,7 @@ export class BatchQueryDTO {
}
/**
*
* ()
*/
export class BatchOperationResultDTOGeneric<T> extends BatchOperationResultDTO {
@ApiProperty({ description: '操作成功的数据列表', type: Array })
@ -202,7 +202,7 @@ export class BatchOperationResultDTOGeneric<T> extends BatchOperationResultDTO {
}
/**
*
* ()
*/
export class SyncOperationResultDTOGeneric<T> extends SyncOperationResultDTO {
@ApiProperty({ description: '同步成功的数据列表', type: Array })

View File

@ -2,7 +2,7 @@ import { ApiProperty } from '@midwayjs/swagger';
import { UnifiedSearchParamsDTO } from './api.dto';
import { Customer } from '../entity/customer.entity';
// 客户基本信息DTO(用于响应)
// 客户基本信息DTO(用于响应)
export class CustomerDTO extends Customer{
@ApiProperty({ description: '客户ID' })
id: number;
@ -163,11 +163,11 @@ export class UpdateCustomerDTO {
tags?: string[];
}
// 查询单个客户响应DTO(继承基本信息)
// 查询单个客户响应DTO(继承基本信息)
export class GetCustomerDTO extends CustomerDTO {
// 可以添加额外的详细信息字段
}
// 客户统计信息DTO(包含订单统计)
// 客户统计信息DTO(包含订单统计)
export class CustomerStatisticDTO extends CustomerDTO {
@ApiProperty({ description: '创建日期' })
date_created: Date;
@ -209,7 +209,7 @@ export class CustomerStatisticWhereDTO {
customerId?: number;
}
// 客户统计查询参数DTO(继承通用查询参数)
// 客户统计查询参数DTO(继承通用查询参数)
export type CustomerStatisticQueryParamsDTO = UnifiedSearchParamsDTO<CustomerStatisticWhereDTO>;
// 客户统计列表响应DTO
@ -259,7 +259,7 @@ export class BatchDeleteCustomerDTO {
// ====================== 查询操作 ======================
// 客户查询条件DTO用于UnifiedSearchParamsDTO的where参数
// 客户查询条件DTO(用于UnifiedSearchParamsDTO的where参数)
export class CustomerWhereDTO {
@ApiProperty({ description: '邮箱筛选', required: false })
email?: string;
@ -284,10 +284,10 @@ export class CustomerWhereDTO {
role?: string;
}
// 客户查询参数DTO(继承通用查询参数)
// 客户查询参数DTO(继承通用查询参数)
export type CustomerQueryParamsDTO = UnifiedSearchParamsDTO<CustomerWhereDTO>;
// 客户列表响应DTO参考site-api.dto.ts中的分页格式
// 客户列表响应DTO(参考site-api.dto.ts中的分页格式)
export class CustomerListResponseDTO {
@ApiProperty({ description: '客户列表', type: [CustomerDTO] })
items: CustomerDTO[];
@ -359,6 +359,6 @@ export class SyncCustomersDTO {
@ApiProperty({ description: '站点ID' })
siteId: number;
@ApiProperty({ description: '查询参数支持where和orderBy', type: UnifiedSearchParamsDTO, required: false })
@ApiProperty({ description: '查询参数(支持where和orderBy)', type: UnifiedSearchParamsDTO, required: false })
params?: UnifiedSearchParamsDTO<CustomerWhereDTO>;
}

View File

@ -22,7 +22,7 @@ export class ShopyyAllProductQuery {
id?: string;
/** 商品标题,支持模糊查询 */
title?: string;
/** 商品状态,例如:上架、下架、删除等(具体值参考 Shopyy 接口文档) */
/** 商品状态,例如:上架、下架、删除等(具体值参考 Shopyy 接口文档) */
status?: string;
/** 商品SKU编码库存保有单位精确或模糊匹配 */
sku?: string;
@ -34,21 +34,21 @@ export class ShopyyAllProductQuery {
variant_price_min?: string;
/** 变体价格最大值,筛选变体价格小于等于该值的商品 */
variant_price_max?: string;
/** 变体划线价(原价)最小值,筛选变体划线价大于等于该值的商品 */
/** 变体划线价(原价)最小值,筛选变体划线价大于等于该值的商品 */
variant_compare_at_price_min?: string;
/** 变体划线价(原价)最大值,筛选变体划线价小于等于该值的商品 */
/** 变体划线价(原价)最大值,筛选变体划线价小于等于该值的商品 */
variant_compare_at_price_max?: string;
/** 变体重量最小值,筛选变体重量大于等于该值的商品(单位参考接口文档) */
/** 变体重量最小值,筛选变体重量大于等于该值的商品(单位参考接口文档) */
variant_weight_min?: string;
/** 变体重量最大值,筛选变体重量小于等于该值的商品(单位参考接口文档) */
/** 变体重量最大值,筛选变体重量小于等于该值的商品(单位参考接口文档) */
variant_weight_max?: string;
/** 商品创建时间最小值,格式参考接口文档YYYY-MM-DD HH:mm:ss */
/** 商品创建时间最小值,格式参考接口文档(如:YYYY-MM-DD HH:mm:ss) */
created_at_min?: string;
/** 商品创建时间最大值,格式参考接口文档YYYY-MM-DD HH:mm:ss */
/** 商品创建时间最大值,格式参考接口文档(如:YYYY-MM-DD HH:mm:ss) */
created_at_max?: string;
/** 商品更新时间最小值,格式参考接口文档YYYY-MM-DD HH:mm:ss */
/** 商品更新时间最小值,格式参考接口文档(如:YYYY-MM-DD HH:mm:ss) */
updated_at_min?: string;
/** 商品更新时间最大值,格式参考接口文档YYYY-MM-DD HH:mm:ss */
/** 商品更新时间最大值,格式参考接口文档(如:YYYY-MM-DD HH:mm:ss) */
updated_at_max?: string;
}
// 产品类型
@ -133,9 +133,9 @@ export interface ShopyyVariant {
//
// 订单查询参数类型
export interface ShopyyOrderQuery {
// 订单ID集合 多个ID用','联接 例1,2,3
// 订单ID集合 多个ID用','联接 例:1,2,3
ids?: string;
// 订单状态 100 未完成110 待处理180 已完成(确认收货); 190 取消;
// 订单状态 100 未完成110 待处理180 已完成(确认收货); 190 取消;
status?: string;
// 物流状态 300 未发货310 部分发货320 已发货330(确认收货)
fulfillment_status?: string;
@ -159,9 +159,9 @@ export interface ShopyyOrderQuery {
page?: string;
// 每页条数
limit?: string;
// 排序字段默认id id=订单ID updated_at=最后更新时间 pay_at=支付时间
// 排序字段(默认id) id=订单ID updated_at=最后更新时间 pay_at=支付时间
order_field?: string;
// 排序方式默认desc desc=降序 asc=升序
// 排序方式(默认desc) desc=降序 asc=升序
order_by?: string;
// 订单列表类型
group?: string;
@ -513,7 +513,7 @@ export class ShopyyFulfillmentDTO {
"tracking_number": string;
"courier_code": number;
"note": string;
"mode": "replace" | 'cover' | null// 模式 replace(替换) cover (覆盖) 空(新增)
"mode": "replace" | 'cover' | null// 模式 replace(替换) cover (覆盖) 空(新增)
}
// https://www.apizza.net/project/e114fb8e628e0f604379f5b26f0d8330/browse
export class ShopyPartFulfillmentDTO {

View File

@ -141,7 +141,7 @@ export class UnifiedProductAttributeDTO {
@ApiProperty({ description: '属性选项', type: [String] })
options: string[];
@ApiProperty({ description: '变体属性值(单个值)', required: false })
@ApiProperty({ description: '变体属性值(单个值)', required: false })
option?: string;
// 这个是属性的父级字典项
dict?: Dict;

View File

@ -152,7 +152,7 @@ export class QuerySiteDTO {
@Rule(RuleType.boolean().optional())
isDisabled?: boolean;
@ApiProperty({ description: '站点ID列表(逗号分隔)', required: false })
@ApiProperty({ description: '站点ID列表(逗号分隔)', required: false })
@Rule(RuleType.string().optional())
ids?: string;
}

View File

@ -8,11 +8,11 @@ export interface WooProduct {
id: number;
// 创建时间
date_created: string;
// 创建时间GMT
// 创建时间(GMT)
date_created_gmt: string;
// 更新时间
date_modified: string;
// 更新时间GMT
// 更新时间(GMT)
date_modified_gmt: string;
// 产品类型 simple grouped external variable
type: string;
@ -20,7 +20,7 @@ export interface WooProduct {
status: string;
// 是否为特色产品
featured: boolean;
// 目录可见性选项visible, catalog, search and hidden. Default is visible.
// 目录可见性选项:visible, catalog, search and hidden. Default is visible.
catalog_visibility: string;
// 常规价格
@ -130,11 +130,11 @@ export interface WooVariation {
id: number;
// 创建时间
date_created: string;
// 创建时间GMT
// 创建时间(GMT)
date_created_gmt: string;
// 更新时间
date_modified: string;
// 更新时间GMT
// 更新时间(GMT)
date_modified_gmt: string;
// 变体描述
description: string;
@ -150,11 +150,11 @@ export interface WooVariation {
price_html?: string;
// 促销开始日期
date_on_sale_from?: string;
// 促销开始日期GMT
// 促销开始日期(GMT)
date_on_sale_from_gmt?: string;
// 促销结束日期
date_on_sale_to?: string;
// 促销结束日期GMT
// 促销结束日期(GMT)
date_on_sale_to_gmt?: string;
// 是否在促销中
on_sale: boolean;

View File

@ -42,7 +42,7 @@ export enum OrderStatus {
REFUNDED = 'refunded', // 已退款
FAILED = 'failed', // 失败订单
DRAFT = 'draft', // 草稿
AUTO_DRAFT = 'auto-draft', // 自动草稿TODO:不知道为什么出现)
AUTO_DRAFT = 'auto-draft', // 自动草稿(TODO:不知道为什么出现)
// TRASH = 'trash',
// refund 也就是退款相关的状态

View File

@ -53,7 +53,7 @@ export interface IPlatformService {
getOrder(siteId: number, orderId: string): Promise<any>;
/**
*
* ()
* @param siteId ID
* @returns
*/

View File

@ -66,7 +66,7 @@ export class CustomerService {
}
if (typeof dateValue === 'number') {
// 处理Unix时间戳(秒或毫秒)
// 处理Unix时间戳(秒或毫秒)
return new Date(dateValue > 9999999999 ? dateValue : dateValue * 1000);
}
@ -95,7 +95,7 @@ export class CustomerService {
}
/**
* upsert
* (upsert)
*
*/
async upsertCustomer(
@ -157,24 +157,24 @@ export class CustomerService {
/**
*
* adapter获取站点客户数据
* upsertManyCustomers保存这些客户
* 第一步:调用adapter获取站点客户数据
* 第二步:通过upsertManyCustomers保存这些客户
*/
async syncCustomersFromSite(
siteId: number,
params?: UnifiedSearchParamsDTO
): Promise<SyncOperationResult> {
try {
// 第一步获取适配器并从站点获取客户数据
// 第一步:获取适配器并从站点获取客户数据
const adapter = await this.siteApiService.getAdapter(siteId);
const siteCustomers = await adapter.getAllCustomers(params || {});
// 第二步将站点客户数据转换为客户实体数据
// 第二步:将站点客户数据转换为客户实体数据
const customersData = siteCustomers.map(siteCustomer => {
return this.mapSiteCustomerToCustomer(siteCustomer, siteId);
})
// 第三步批量upsert客户数据
// 第三步:批量upsert客户数据
const upsertResult = await this.upsertManyCustomers(customersData);
return {
total: siteCustomers.length,
@ -192,7 +192,7 @@ export class CustomerService {
}
/**
*
* ()
*
* 使SQL查询实现复杂的统计逻辑
*/
@ -363,7 +363,7 @@ export class CustomerService {
}
/**
*
* ()
*
* 使TypeORM查询构建器实现
*/

View File

@ -239,7 +239,7 @@ export class DictService {
}
// 更新或创建字典项 (Upsert)
// 如果字典项已存在(根据 name 和 dictId 判断),则更新;否则创建新的
// 如果字典项已存在(根据 name 和 dictId 判断),则更新;否则创建新的
async upsertDictItem(dictId: number, itemData: {
name: string;
title: string;
@ -252,7 +252,7 @@ export class DictService {
// 格式化 name
const formattedName = this.formatName(itemData.name);
// 查找是否已存在该字典项(根据 name 和 dictId
// 查找是否已存在该字典项(根据 name 和 dictId)
const existingItem = await this.dictItemModel.findOne({
where: {
name: formattedName,

View File

@ -479,7 +479,7 @@ export class OrderService {
// 如果不能更新 ERP 状态,则保留原有的 orderStatus
entity.orderStatus = existingOrder.orderStatus;
}
// 更新订单数据(包括 shipping、billing 等字段)
// 更新订单数据(包括 shipping、billing 等字段)
await this.orderModel.update(existingOrder.id, entity);
entity.id = existingOrder.id;
return entity;
@ -2567,8 +2567,8 @@ export class OrderService {
* CSV格式
* @param {any[]} data
* @param {Object} options
* @param {string} [options.type='string'] 'string' | 'buffer'
* @param {string} [options.fileName] 使
* @param {string} [options.type='string'] :'string' | 'buffer'
* @param {string} [options.fileName] (使)
* @param {boolean} [options.writeFile=false]
* @returns {string|Buffer} type返回字符串或Buffer
*/
@ -2617,7 +2617,7 @@ async exportToCsv(data: any[], options: { type?: 'string' | 'buffer'; fileName?:
// 获取当前用户目录
const userHomeDir = os.homedir();
// 构建目标路径(下载目录)
// 构建目标路径(下载目录)
const downloadsDir = path.join(userHomeDir, 'Downloads');
// 确保下载目录存在

View File

@ -235,7 +235,7 @@ export class ProductService {
.leftJoinAndSelect('product.attributes', 'attribute')
.leftJoinAndSelect('attribute.dict', 'dict')
.leftJoinAndSelect('product.category', 'category');
// 处理分页参数(支持新旧两种格式)
// 处理分页参数(支持新旧两种格式)
const page = query.page || 1;
const pageSize = query.per_page || 10;
@ -393,7 +393,7 @@ export class ProductService {
qb.andWhere('product.updatedAt <= :whereUpdatedAtEnd', { whereUpdatedAtEnd: new Date(query.where.updatedAtEnd) });
}
// 品牌过滤(向后兼容)
// 品牌过滤(向后兼容)
if (brandId) {
qb.andWhere(qb => {
const subQuery = qb
@ -423,7 +423,7 @@ export class ProductService {
});
}
// 分类过滤(向后兼容)
// 分类过滤(向后兼容)
if (categoryId) {
qb.andWhere('product.categoryId = :categoryId', { categoryId });
}
@ -443,7 +443,7 @@ export class ProductService {
qb.andWhere('product.categoryId IN (:...whereCategoryIds)', { whereCategoryIds: query.where.categoryIds });
}
// 处理排序(支持新旧两种格式)
// 处理排序(支持新旧两种格式)
if (orderBy) {
if (typeof orderBy === 'string') {
// 如果orderBy是字符串尝试解析JSON
@ -1765,7 +1765,7 @@ export class ProductService {
}
// 根据ID获取产品详情包含站点SKU
// 根据ID获取产品详情(包含站点SKU)
async getProductById(id: number): Promise<Product> {
const product = await this.productModel.findOne({
where: { id },

View File

@ -128,7 +128,7 @@ export class ShopyyService {
* @returns URL
*/
private buildURL(baseUrl: string, endpoint: string): string {
// ShopYY API URL格式https://{shop}.shopyy.com/openapi/{version}/{endpoint}
// ShopYY API URL格式:https://{shop}.shopyy.com/openapi/{version}/{endpoint}
const base = baseUrl.replace(/\/$/, '');
const end = endpoint.replace(/^\//, '');
return `${base}/${end}`;

View File

@ -152,7 +152,7 @@ export class SiteApiService {
const result = await this.upsertProduct(siteId, product);
// 判断是创建还是更新
if (result && result.id) {
// 简单判断如果产品原本没有ID而现在有了说明是创建的
// 简单判断:如果产品原本没有ID而现在有了说明是创建的
if (!product.id || !product.id.toString().trim()) {
results.created.push(result);
} else {

View File

@ -254,7 +254,7 @@ export class WPService implements IPlatformService {
}
// 导出 WooCommerce 产品为特殊CSV(平台特性)
// 导出 WooCommerce 产品为特殊CSV(平台特性)
async exportProductsCsvSpecial(site: any, page: number = 1, pageSize: number = 100): Promise<string> {
const list = await this.getProducts(site, { page, per_page: pageSize });
const header = ['id','name','type','status','sku','regular_price','sale_price','stock_status','stock_quantity'];

View File

@ -10,12 +10,12 @@
### 2. 根据站点SKU查询产品
**接口**: `GET /product/site-sku/:siteSku`
**功能**: 根据站点SKU代码查询对应的产品信息
**返回**: 完整的产品对象包含站点SKU、分类、属性等关联数据
**返回**: 完整的产品对象(包含站点SKU、分类、属性等关联数据)
### 3. 根据产品ID获取产品详情
**接口**: `GET /product/:id`
**功能**: 获取产品的完整详情信息
**返回**: 完整的产品对象包含站点SKU、分类、属性、组成等关联数据
**返回**: 完整的产品对象(包含站点SKU、分类、属性、组成等关联数据)
### 4. 现有接口的增强
@ -54,7 +54,7 @@
1. **findProductsByName(name: string)**: 现在包含站点SKU数据
2. **findProductBySku(sku: string)**: 现在包含站点SKU数据
3. **getProductList**: 已经包含站点SKU数据(无需更改)
3. **getProductList**: 已经包含站点SKU数据(无需更改)
## 使用示例
@ -77,7 +77,7 @@
```javascript
// GET /product/site-sku/SITE-SKU-001
// 返回完整的产品对象,包含:
// - 基本信息SKU、名称、价格等
// - 基本信息(SKU、名称、价格等)
// - 分类信息
// - 属性信息
// - 站点SKU列表
@ -92,14 +92,14 @@
## 数据库查询优化
所有新增和更新的方法都使用了TypeORM的关联查询确保
所有新增和更新的方法都使用了TypeORM的关联查询确保:
- 一次查询获取所有需要的数据
- 避免N+1查询问题
- 包含必要的关联关系分类、属性、站点SKU、组成
- 包含必要的关联关系(分类、属性、站点SKU、组成)
## 错误处理
所有方法都包含适当的错误处理
所有方法都包含适当的错误处理:
- 产品不存在时抛出明确的错误信息
- 站点SKU不存在时抛出明确的错误信息
- 控制器层统一处理错误并返回适当的HTTP响应