import { Provide } from '@midwayjs/core'; import { In, Like, Not, Repository } from 'typeorm'; import { Product } from '../entity/product.entity'; import { Category } from '../entity/category.entity'; import { paginate } from '../utils/paginate.util'; import { PaginationParams } from '../interface'; import { CreateCategoryDTO, CreateFlavorsDTO, CreateProductDTO, CreateStrengthDTO, UpdateCategoryDTO, UpdateFlavorsDTO, UpdateProductDTO, UpdateStrengthDTO, } from '../dto/product.dto'; import { CategoryPaginatedResponse, FlavorsPaginatedResponse, ProductPaginatedResponse, StrengthPaginatedResponse, } from '../dto/reponse.dto'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { WpProduct } from '../entity/wp_product.entity'; import { Variation } from '../entity/variation.entity'; import { Strength } from '../entity/strength.entity'; import { Flavors } from '../entity/flavors.entity'; @Provide() export class ProductService { @InjectEntityModel(Product) productModel: Repository; @InjectEntityModel(Category) categoryModel: Repository; @InjectEntityModel(Strength) strengthModel: Repository; @InjectEntityModel(Flavors) flavorsModel: Repository; @InjectEntityModel(WpProduct) wpProductModel: Repository; @InjectEntityModel(Variation) variationModel: Repository; // async findProductsByName(name: string): Promise { // const where: any = {}; // const nameFilter = name ? name.split(' ').filter(Boolean) : []; // if (nameFilter.length > 0) { // const nameConditions = nameFilter.map(word => Like(`%${word}%`)); // where.name = And(...nameConditions); // } // if(name){ // where.nameCn = Like(`%${name}%`) // } // where.sku = Not(IsNull()); // // 查询 SKU 不为空且 name 包含关键字的产品,最多返回 50 条 // return this.productModel.find({ // where, // take: 50, // }); // } async findProductsByName(name: string): Promise { const nameFilter = name ? name.split(' ').filter(Boolean) : []; const query = this.productModel.createQueryBuilder('product'); // 保证 sku 不为空 query.where('product.sku IS NOT NULL'); if (nameFilter.length > 0 || name) { const params: Record = {}; const conditions: string[] = []; // 英文名关键词全部匹配(AND) if (nameFilter.length > 0) { const nameConds = nameFilter.map((word, index) => { const key = `name${index}`; params[key] = `%${word}%`; return `product.name LIKE :${key}`; }); conditions.push(`(${nameConds.join(' AND ')})`); } // 中文名模糊匹配 if (name) { params['nameCn'] = `%${name}%`; conditions.push(`product.nameCn LIKE :nameCn`); } // 英文名关键词匹配 OR 中文名匹配 query.andWhere(`(${conditions.join(' OR ')})`, params); } query.take(50); return await query.getMany(); } async findProductBySku(sku: string): Promise { return this.productModel.findOne({ where: { sku, }, }); } async getProductList( pagination: PaginationParams, name?: string, categoryId?: number ): Promise { const nameFilter = name ? name.split(' ').filter(Boolean) : []; const qb = this.productModel .createQueryBuilder('product') .leftJoin(Category, 'category', 'category.id = product.categoryId') .leftJoin(Strength, 'strength', 'strength.id = product.strengthId') .leftJoin(Flavors, 'flavors', 'flavors.id = product.flavorsId') .select([ 'product.id as id', 'product.name as name', 'product.nameCn as nameCn', 'product.description as description', 'product.humidity as humidity', 'product.sku as sku', 'product.createdAt as createdAt', 'product.updatedAt as updatedAt', 'category.name AS categoryName', 'strength.name AS strengthName', 'flavors.name AS flavorsName', ]); // 模糊搜索 name,支持多个关键词 nameFilter.forEach((word, index) => { qb.andWhere(`product.name LIKE :name${index}`, { [`name${index}`]: `%${word}%`, }); }); // 分类过滤 if (categoryId) { qb.andWhere('product.categoryId = :categoryId', { categoryId }); } // 分页 qb.skip((pagination.current - 1) * pagination.pageSize).take( pagination.pageSize ); // 执行查询 const items = await qb.getRawMany(); const total = await qb.getCount(); return { items, total, ...pagination, }; } async createProduct(createProductDTO: CreateProductDTO): Promise { const { name, description, categoryId, strengthId, flavorsId, humidity } = createProductDTO; const isExit = await this.productModel.findOne({ where: { categoryId, strengthId, flavorsId, humidity, }, }); if (isExit) throw new Error('产品已存在'); const product = new Product(); product.name = name; product.description = description; product.categoryId = categoryId; product.strengthId = strengthId; product.flavorsId = flavorsId; product.humidity = humidity; const categoryKey = ( await this.categoryModel.findOne({ where: { id: categoryId } }) ).unique_key; const strengthKey = ( await this.strengthModel.findOne({ where: { id: strengthId } }) ).unique_key; const flavorsKey = ( await this.flavorsModel.findOne({ where: { id: flavorsId } }) ).unique_key; product.sku = `${categoryKey}-${flavorsKey}-${strengthKey}-${humidity}`; return await this.productModel.save(product); } async updateProduct( id: number, updateProductDTO: UpdateProductDTO ): Promise { // 确认产品是否存在 const product = await this.productModel.findOneBy({ id }); if (!product) { throw new Error(`产品 ID ${id} 不存在`); } // 更新产品 await this.productModel.update(id, updateProductDTO); // 返回更新后的产品 return await this.productModel.findOneBy({ id }); } async updateProductNameCn(id: number, nameCn: string): Promise { // 确认产品是否存在 const product = await this.productModel.findOneBy({ id }); if (!product) { throw new Error(`产品 ID ${id} 不存在`); } // 更新产品 await this.productModel.update(id, { nameCn }); // 返回更新后的产品 return await this.productModel.findOneBy({ id }); } async deleteProduct(id: number): Promise { // 检查产品是否存在 const product = await this.productModel.findOneBy({ id }); if (!product) { throw new Error(`产品 ID ${id} 不存在`); } const productSku = product.sku; // 查询 wp_product 表中是否存在与该 SKU 关联的产品 const wpProduct = await this.wpProductModel .createQueryBuilder('wp_product') .where('JSON_CONTAINS(wp_product.constitution, :sku)', { sku: JSON.stringify({ sku: productSku }), }) .getOne(); if (wpProduct) { throw new Error('无法删除,请先删除关联的WP产品'); } const variation = await this.variationModel .createQueryBuilder('variation') .where('JSON_CONTAINS(variation.constitution, :sku)', { sku: JSON.stringify({ sku: productSku }), }) .getOne(); if (variation) { console.log(variation); throw new Error('无法删除,请先删除关联的WP变体'); } // 删除产品 const result = await this.productModel.delete(id); return result.affected > 0; // `affected` 表示删除的行数 } async hasProductsInCategory(categoryId: number): Promise { const count = await this.productModel.count({ where: { categoryId }, }); return count > 0; } async hasCategory(name: string, id?: string): Promise { const where: any = { name }; if (id) where.id = Not(id); const count = await this.categoryModel.count({ where, }); return count > 0; } async getCategoryList( pagination: PaginationParams, name?: string ): Promise { const where: any = {}; if (name) { where.name = Like(`%${name}%`); } return await paginate(this.categoryModel, { pagination, where }); } async getCategoryAll(): Promise { return await this.categoryModel.find(); } async createCategory( createCategoryDTO: CreateCategoryDTO ): Promise { const { name, unique_key } = createCategoryDTO; const category = new Category(); category.name = name; category.unique_key = unique_key; return await this.categoryModel.save(category); } async updateCategory(id: number, updateCategory: UpdateCategoryDTO) { // 确认产品是否存在 const category = await this.categoryModel.findOneBy({ id }); if (!category) { throw new Error(`产品分类 ID ${id} 不存在`); } // 更新产品 await this.categoryModel.update(id, updateCategory); // 返回更新后的产品 return await this.categoryModel.findOneBy({ id }); } async deleteCategory(id: number): Promise { // 检查产品是否存在 const category = await this.categoryModel.findOneBy({ id }); if (!category) { throw new Error(`产品分类 ID ${id} 不存在`); } // 删除产品 const result = await this.categoryModel.delete(id); return result.affected > 0; // `affected` 表示删除的行数 } async hasProductsInFlavors(flavorsId: number): Promise { const count = await this.productModel.count({ where: { flavorsId }, }); return count > 0; } async hasFlavors(name: string, id?: string): Promise { const where: any = { name }; if (id) where.id = Not(id); const count = await this.flavorsModel.count({ where, }); return count > 0; } async getFlavorsList( pagination: PaginationParams, name?: string ): Promise { const where: any = {}; if (name) { where.name = Like(`%${name}%`); } return await paginate(this.flavorsModel, { pagination, where }); } async getFlavorsAll(): Promise { return await this.flavorsModel.find(); } async createFlavors(createFlavorsDTO: CreateFlavorsDTO): Promise { const { name, unique_key } = createFlavorsDTO; const flavors = new Flavors(); flavors.name = name; flavors.unique_key = unique_key; return await this.flavorsModel.save(flavors); } async updateFlavors(id: number, updateFlavors: UpdateFlavorsDTO) { // 确认产品是否存在 const flavors = await this.flavorsModel.findOneBy({ id }); if (!flavors) { throw new Error(`口味 ID ${id} 不存在`); } // 更新产品 await this.flavorsModel.update(id, updateFlavors); // 返回更新后的产品 return await this.flavorsModel.findOneBy({ id }); } async deleteFlavors(id: number): Promise { // 检查产品是否存在 const flavors = await this.flavorsModel.findOneBy({ id }); if (!flavors) { throw new Error(`口味 ID ${id} 不存在`); } // 删除产品 const result = await this.flavorsModel.delete(id); return result.affected > 0; // `affected` 表示删除的行数 } async hasProductsInStrength(strengthId: number): Promise { const count = await this.productModel.count({ where: { strengthId }, }); return count > 0; } async hasStrength(name: string, id?: string): Promise { const where: any = { name }; if (id) where.id = Not(id); const count = await this.strengthModel.count({ where, }); return count > 0; } async getStrengthList( pagination: PaginationParams, name?: string ): Promise { const where: any = {}; if (name) { where.name = Like(`%${name}%`); } return await paginate(this.strengthModel, { pagination, where }); } async getStrengthAll(): Promise { return await this.strengthModel.find(); } async createStrength( createStrengthDTO: CreateStrengthDTO ): Promise { const { name, unique_key } = createStrengthDTO; const strength = new Strength(); strength.name = name; strength.unique_key = unique_key; return await this.strengthModel.save(strength); } async updateStrength(id: number, updateStrength: UpdateStrengthDTO) { // 确认产品是否存在 const strength = await this.strengthModel.findOneBy({ id }); if (!strength) { throw new Error(`口味 ID ${id} 不存在`); } // 更新产品 await this.strengthModel.update(id, updateStrength); // 返回更新后的产品 return await this.strengthModel.findOneBy({ id }); } async deleteStrength(id: number): Promise { // 检查产品是否存在 const strength = await this.strengthModel.findOneBy({ id }); if (!strength) { throw new Error(`口味 ID ${id} 不存在`); } // 删除产品 const result = await this.flavorsModel.delete(id); return result.affected > 0; // `affected` 表示删除的行数 } async batchSetSku(skus: { productId: number; sku: string }[]) { // 提取所有 sku const skuList = skus.map(item => item.sku); // 检查是否存在重复 sku const existingProducts = await this.productModel.find({ where: { sku: In(skuList) }, }); if (existingProducts.length > 0) { const existingSkus = existingProducts.map(product => product.sku); throw new Error(`以下 SKU 已存在: ${existingSkus.join(', ')}`); } // 遍历检查产品 ID 是否存在,并更新 sku for (const { productId, sku } of skus) { const product = await this.productModel.findOne({ where: { id: productId }, }); if (!product) { throw new Error(`产品 ID '${productId}' 不存在`); } product.sku = sku; await this.productModel.save(product); } return `成功更新 ${skus.length} 个 sku`; } }