共富商城

This commit is contained in:
zjf committed 2025-09-08 15:35:52 +08:00
1 parent 49a5a7161d
commit 056bb95229
9 files changed
+370 -19

No files matched your search

@@ -113,4 +113,10 @@ public class MallCategoryEntity extends Model<MallCategoryEntity> {
*/
@Schema(description="租户编号")
private Long tenantId;
/**
* 商户ID
*/
@Schema(description="商户ID")
private Long merchantId;
}
@@ -95,3 +95,4 @@ public interface MallConstants {
}
@@ -27,6 +27,7 @@ import com.bsd.pjcloud.supermarket.vo.mall.MallCategoryTreeVo;
import com.bsd.pjcloud.supermarket.vo.app.MallProductListAppVo;
import com.bsd.pjcloud.supermarket.vo.app.MallProductDetailAppVo;
import com.bsd.pjcloud.supermarket.vo.app.MallProductSkuAppVo;
import com.bsd.pjcloud.supermarket.vo.app.MallMerchantListAppVo;
import com.bsd.pjcloud.supermarket.dto.SkuStockChangeDTO;
import com.bsd.pjcloud.supermarket.constant.MallConstants;
import io.swagger.v3.oas.annotations.Operation;
@@ -35,6 +36,7 @@ import lombok.RequiredArgsConstructor;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -67,9 +69,12 @@ public class MallAppController {
*/
@GetMapping("/category/tree")
@Operation(summary = "获取分类树", description = "获取所有分类的树结构")
public R<List<MallCategoryTreeVo>> getCategoryTree() {
List<MallCategoryEntity> all = mallCategoryService.list(Wrappers.<MallCategoryEntity>lambdaQuery()
.eq(MallCategoryEntity::getStatus, 1)); // 只查启用状态
public R<List<MallCategoryTreeVo>> getCategoryTree(@RequestParam(required = false) Long merchantId) {
LambdaQueryWrapper<MallCategoryEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(MallCategoryEntity::getStatus, 1); // 只查启用状态
// 添加商户ID过滤条件
wrapper.eq(merchantId != null, MallCategoryEntity::getMerchantId, merchantId);
List<MallCategoryEntity> all = mallCategoryService.list(wrapper);
List<MallCategoryTreeVo> tree = buildCategoryTree(all, 0L);
return R.ok(tree);
}
@@ -79,12 +84,13 @@ public class MallAppController {
*/
@GetMapping("/category/listByParent/{parentId}")
@Operation(summary = "根据父级ID获取子分类", description = "根据父级ID获取子分类列表")
public R<List<MallCategoryEntity>> getCategoryListByParent(@PathVariable("parentId") Long parentId) {
List<MallCategoryEntity> list = mallCategoryService.list(
Wrappers.<MallCategoryEntity>lambdaQuery()
.eq(MallCategoryEntity::getParentId, parentId)
.eq(MallCategoryEntity::getStatus, 1)
);
public R<List<MallCategoryEntity>> getCategoryListByParent(@PathVariable("parentId") Long parentId, @RequestParam(required = false) Long merchantId) {
LambdaQueryWrapper<MallCategoryEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(MallCategoryEntity::getParentId, parentId);
wrapper.eq(MallCategoryEntity::getStatus, 1);
// 添加商户ID过滤条件
wrapper.eq(merchantId != null, MallCategoryEntity::getMerchantId, merchantId);
List<MallCategoryEntity> list = mallCategoryService.list(wrapper);
return R.ok(list);
}
@@ -94,14 +100,112 @@ public class MallAppController {
* 获取商户列表
*/
@GetMapping("/merchant/list")
@Operation(summary = "获取商户列表", description = "获取所有启用的商户列表")
public R<List<MallMerchantEntity>> getMerchantList() {
List<MallMerchantEntity> list = mallMerchantService.list(
@Operation(summary = "获取商户列表", description = "获取所有启用的商户列表,包含特色商品")
public R<List<MallMerchantListAppVo>> getMerchantList(@RequestParam(defaultValue = "3") Integer productLimit) {
// 查询所有启用的商户
List<MallMerchantEntity> merchants = mallMerchantService.list(
Wrappers.<MallMerchantEntity>lambdaQuery()
.eq(MallMerchantEntity::getStatus, 1)
.eq(MallMerchantEntity::getStatus, MallConstants.Status.ENABLED)
.orderByAsc(MallMerchantEntity::getName)
);
return R.ok(list);
if (merchants.isEmpty()) {
return R.ok(List.of());
}
// 获取商户ID列表
List<Long> merchantIds = merchants.stream()
.map(MallMerchantEntity::getId)
.collect(Collectors.toList());
// 查询每个商户的特色商品(按创建时间倒序,取前N个)
LocalDateTime now = LocalDateTime.now();
List<MallProductEntity> products = mallProductService.list(
Wrappers.<MallProductEntity>lambdaQuery()
.in(MallProductEntity::getMerchantId, merchantIds)
.eq(MallProductEntity::getStatus, MallConstants.Status.ENABLED) // 只查上架商品
.and(wrapper -> wrapper
.isNull(MallProductEntity::getSaleStartTime)
.or()
.le(MallProductEntity::getSaleStartTime, now)
)
.and(wrapper -> wrapper
.isNull(MallProductEntity::getSaleEndTime)
.or()
.ge(MallProductEntity::getSaleEndTime, now)
)
.orderByDesc(MallProductEntity::getCreateTime)
);
// 按商户ID分组商品
Map<Long, List<MallProductEntity>> productMap = products.stream()
.collect(Collectors.groupingBy(MallProductEntity::getMerchantId));
// 获取商品ID列表,查询SKU信息
List<Long> productIds = products.stream()
.map(MallProductEntity::getId)
.collect(Collectors.toList());
List<MallProductSkuEntity> skuList = productIds.isEmpty() ? List.of() :
mallProductSkuService.list(
Wrappers.<MallProductSkuEntity>lambdaQuery()
.in(MallProductSkuEntity::getProductId, productIds)
);
// 按商品ID分组SKU
Map<Long, List<MallProductSkuEntity>> skuMap = skuList.stream()
.collect(Collectors.groupingBy(MallProductSkuEntity::getProductId));
// 转换为VO
List<MallMerchantListAppVo> result = merchants.stream().map(merchant -> {
MallMerchantListAppVo vo = BeanUtils.toBean(merchant, MallMerchantListAppVo.class);
// 获取该商户的商品列表
List<MallProductEntity> merchantProducts = productMap.getOrDefault(merchant.getId(), List.of());
// 设置商品总数
vo.setProductCount(merchantProducts.size());
// 获取特色商品(限制数量)
List<MallProductListAppVo> featuredProducts = merchantProducts.stream()
.limit(productLimit)
.map(product -> {
MallProductListAppVo productVo = BeanUtils.toBean(product, MallProductListAppVo.class);
List<MallProductSkuEntity> skus = skuMap.getOrDefault(product.getId(), List.of());
// 计算最低价格
productVo.setMinPrice(skus.stream()
.map(MallProductSkuEntity::getPrice)
.filter(Objects::nonNull)
.min(java.math.BigDecimal::compareTo)
.orElse(java.math.BigDecimal.ZERO));
// 计算总库存
productVo.setTotalStock(skus.stream()
.map(MallProductSkuEntity::getStock)
.filter(Objects::nonNull)
.mapToInt(Integer::intValue)
.sum());
return productVo;
})
.collect(Collectors.toList());
vo.setFeaturedProducts(featuredProducts);
// 设置商户营业时间
if (merchant.getBusinessHours() != null && !merchant.getBusinessHours().trim().isEmpty()) {
vo.setBusinessHours(merchant.getBusinessHours());
} else {
// 默认商户营业时间
vo.setBusinessHours("10:00-22:00");
}
return vo;
}).collect(Collectors.toList());
return R.ok(result);
}
/**
@@ -427,6 +531,116 @@ public class MallAppController {
}
}
// ==================== 商户分类管理接口 ====================
/**
* 商户创建分类
*/
@PostMapping("/merchant/category/create")
@Operation(summary = "商户创建分类", description = "移动端商户创建分类")
public R<String> createCategory(@RequestBody MallCategoryEntity category) {
try {
Long merchantId = validateMerchant();
// 自动设置商户ID
category.setMerchantId(merchantId);
category.setDeptId(SecurityUtils.getUser().getDeptId());
// 创建分类
boolean success = mallCategoryService.save(category);
if (success) {
return R.ok("分类创建成功");
} else {
return R.failed("分类创建失败");
}
} catch (Exception e) {
return R.failed("分类创建失败:" + e.getMessage());
}
}
/**
* 商户更新分类
*/
@PutMapping("/merchant/category/update")
@Operation(summary = "商户更新分类", description = "移动端商户更新分类")
public R<String> updateCategory(@RequestBody MallCategoryEntity category) {
try {
Long merchantId = validateMerchant();
// 验证分类权限
validateCategoryPermission(category.getId(), merchantId);
// 验证分类ID
if (category.getId() == null) {
return R.failed("分类ID不能为空");
}
// 更新分类
boolean success = mallCategoryService.updateById(category);
if (success) {
return R.ok("分类更新成功");
} else {
return R.failed("分类更新失败");
}
} catch (Exception e) {
return R.failed("分类更新失败:" + e.getMessage());
}
}
/**
* 商户删除分类
*/
@DeleteMapping("/merchant/category/{id}")
@Operation(summary = "商户删除分类", description = "移动端商户删除自己的分类")
public R<String> deleteCategory(@PathVariable("id") Long id) {
try {
Long merchantId = validateMerchant();
validateCategoryPermission(id, merchantId);
// 删除分类(逻辑删除)
boolean success = mallCategoryService.removeById(id);
if (success) {
return R.ok("分类删除成功");
} else {
return R.failed("分类删除失败");
}
} catch (Exception e) {
return R.failed("分类删除失败:" + e.getMessage());
}
}
/**
* 商户获取自己的分类列表
*/
@GetMapping("/merchant/category/list")
@Operation(summary = "商户分类列表", description = "移动端商户获取自己的分类列表")
public R<List<MallCategoryEntity>> getMerchantCategoryList(@RequestParam(required = false) Long parentId) {
try {
Long merchantId = validateMerchant();
LambdaQueryWrapper<MallCategoryEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(MallCategoryEntity::getMerchantId, merchantId);
wrapper.eq(parentId != null, MallCategoryEntity::getParentId, parentId);
wrapper.orderByAsc(MallCategoryEntity::getSort);
List<MallCategoryEntity> list = mallCategoryService.list(wrapper);
return R.ok(list);
} catch (Exception e) {
return R.failed("获取分类列表失败:" + e.getMessage());
}
}
/**
* 验证是否有处理该条分类数据的权限
*/
private void validateCategoryPermission(Long categoryId, Long merchantId) {
MallCategoryEntity category = mallCategoryService.getById(categoryId);
if (category == null) {
throw new BusinessException("分类不存在");
}
if (!merchantId.equals(category.getMerchantId())) {
throw new BusinessException("无权限处理此分类");
}
}
// ==================== 库存相关接口 ====================
/**
@@ -52,6 +52,8 @@ public class MallCategoryController {
public R getMallCategoryPage(@ParameterObject Page page, @ParameterObject MallCategoryEntity MallCategory) {
LambdaQueryWrapper<MallCategoryEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(StrUtil.isNotBlank(MallCategory.getName()),MallCategoryEntity::getName,MallCategory.getName());
// 添加商户ID过滤条件
wrapper.eq(MallCategory.getMerchantId() != null, MallCategoryEntity::getMerchantId, MallCategory.getMerchantId());
return R.ok(MallCategoryService.pageScope(page, wrapper));
}
@@ -79,6 +81,13 @@ public class MallCategoryController {
@PreAuthorize("@pms.hasPermission('supermarket_mallCategory_add')" )
public R save(@RequestBody MallCategoryEntity MallCategory) {
MallCategory.setDeptId(SecurityUtils.getUser().getDeptId());
// 设置商户ID
if (MallCategory.getMerchantId() == null) {
return R.failed("商户ID不能为空");
}
// 如果前端没有传商户ID,可以从当前用户信息中获取
// 这里需要根据实际业务逻辑来设置,可能需要从用户关联的商户信息中获取
// MallCategory.setMerchantId(getCurrentUserMerchantId());
return R.ok(MallCategoryService.save(MallCategory));
}
@@ -119,7 +128,11 @@ public class MallCategoryController {
@GetMapping("/export")
@PreAuthorize("@pms.hasPermission('supermarket_mallCategory_export')" )
public List<MallCategoryEntity> export(MallCategoryEntity MallCategory,Long[] ids) {
return MallCategoryService.list(Wrappers.lambdaQuery(MallCategory).in(ArrayUtil.isNotEmpty(ids), MallCategoryEntity::getId, ids));
LambdaQueryWrapper<MallCategoryEntity> wrapper = Wrappers.lambdaQuery(MallCategory);
wrapper.in(ArrayUtil.isNotEmpty(ids), MallCategoryEntity::getId, ids);
// 添加商户ID过滤条件
wrapper.eq(MallCategory.getMerchantId() != null, MallCategoryEntity::getMerchantId, MallCategory.getMerchantId());
return MallCategoryService.list(wrapper);
}
/**
@@ -127,8 +140,11 @@ public class MallCategoryController {
*/
@GetMapping("/tree")
@Operation(summary = "分类树", description = "获取所有分类的树结构")
public R<List<MallCategoryTreeVo>> tree() {
List<MallCategoryEntity> all = MallCategoryService.listScope();
public R<List<MallCategoryTreeVo>> tree(@RequestParam(required = false) Long merchantId) {
LambdaQueryWrapper<MallCategoryEntity> wrapper = Wrappers.lambdaQuery();
// 添加商户ID过滤条件
wrapper.eq(merchantId != null, MallCategoryEntity::getMerchantId, merchantId);
List<MallCategoryEntity> all = MallCategoryService.list(wrapper);
List<MallCategoryTreeVo> tree = buildCategoryTree(all, 0L);
return R.ok(tree);
}
@@ -150,8 +166,12 @@ public class MallCategoryController {
*/
@GetMapping("/listByParent/{parentId}")
@Operation(summary = "根据父级ID查子分类", description = "根据父级ID查子分类")
public R<List<MallCategoryEntity>> listByParent(@PathVariable("parentId") Long parentId) {
List<MallCategoryEntity> list = MallCategoryService.list(Wrappers.<MallCategoryEntity>lambdaQuery().eq(MallCategoryEntity::getParentId, parentId));
public R<List<MallCategoryEntity>> listByParent(@PathVariable("parentId") Long parentId, @RequestParam(required = false) Long merchantId) {
LambdaQueryWrapper<MallCategoryEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(MallCategoryEntity::getParentId, parentId);
// 添加商户ID过滤条件
wrapper.eq(merchantId != null, MallCategoryEntity::getMerchantId, merchantId);
List<MallCategoryEntity> list = MallCategoryService.list(wrapper);
return R.ok(list);
}
@@ -89,6 +89,12 @@ public class MallMerchantEntity extends Model<MallMerchantEntity> {
@Schema(description="备注")
private String remark;
/**
* 营业时间(格式:HH:mm-HH:mm,如:10:30-22:00)
*/
@Schema(description="营业时间(格式:HH:mm-HH:mm)")
private String businessHours;
/**
* 部门ID
*/
@@ -83,3 +83,4 @@ public class MallMerchantUserVo {
}
@@ -0,0 +1,101 @@
package com.bsd.pjcloud.supermarket.vo.app;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 移动端商户列表VO
*
* @author zjf
* @date 2025-01-27
*/
@Data
@Schema(description = "移动端商户列表VO")
public class MallMerchantListAppVo {
/**
* 商户ID
*/
@Schema(description = "商户ID")
private Long id;
/**
* 商户名称
*/
@Schema(description = "商户名称")
private String name;
/**
* 商户简称
*/
@Schema(description = "商户简称")
private String shortName;
/**
* 联系人
*/
@Schema(description = "联系人")
private String contactName;
/**
* 联系电话
*/
@Schema(description = "联系电话")
private String contactPhone;
/**
* 邮箱
*/
@Schema(description = "邮箱")
private String email;
/**
* 状态(1启用 0停用)
*/
@Schema(description = "状态")
private String status;
/**
* 营业执照号
*/
@Schema(description = "营业执照号")
private String licenseNo;
/**
* 详细地址
*/
@Schema(description = "详细地址")
private String address;
/**
* 商户图片URL(逗号分隔)
*/
@Schema(description = "商户图片URL")
private String images;
/**
* 备注
*/
@Schema(description = "备注")
private String remark;
/**
* 特色商品列表(最多显示3个)
*/
@Schema(description = "特色商品列表")
private List<MallProductListAppVo> featuredProducts;
/**
* 商品总数
*/
@Schema(description = "商品总数")
private Integer productCount;
/**
* 商户营业时间(格式:HH:mm-HH:mm,如:10:30-22:00)
*/
@Schema(description = "商户营业时间")
private String businessHours;
}
@@ -104,5 +104,6 @@ public class MallProductListAppVo {
*/
@Schema(description = "最低价格")
private BigDecimal minPrice;
}
@@ -18,5 +18,6 @@
<result property="updateTime" column="update_time"/>
<result property="delFlag" column="del_flag"/>
<result property="tenantId" column="tenant_id"/>
<result property="merchantId" column="merchant_id"/>
</resultMap>
</mapper>