This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
package com.example.building.controller;
|
||||
|
||||
import com.example.building.common.Result;
|
||||
import com.example.building.entity.CategoryAttribute;
|
||||
import com.example.building.service.CategoryAttributeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 种类属性控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/category-attributes")
|
||||
public class CategoryAttributeController {
|
||||
|
||||
@Autowired
|
||||
private CategoryAttributeService categoryAttributeService;
|
||||
|
||||
/**
|
||||
* 获取种类的属性列表
|
||||
*/
|
||||
@GetMapping("/category/{categoryId}")
|
||||
public Result<List<CategoryAttribute>> getByCategoryId(@PathVariable String categoryId) {
|
||||
return Result.success(categoryAttributeService.getByCategoryId(categoryId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存种类属性
|
||||
*/
|
||||
@PostMapping("/category/{categoryId}")
|
||||
public Result<Void> saveAttributes(@PathVariable String categoryId, @RequestBody List<CategoryAttribute> attrs) {
|
||||
categoryAttributeService.saveAttributes(categoryId, attrs);
|
||||
return Result.success();
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import com.example.building.common.Result;
|
||||
import com.example.building.entity.Category;
|
||||
import com.example.building.entity.Product;
|
||||
import com.example.building.service.ProductService;
|
||||
import com.example.building.service.CategoryAttributeService;
|
||||
import com.example.building.service.ProductAttributeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -22,6 +24,12 @@ public class ProductController {
|
||||
@Autowired
|
||||
private ProductService productService;
|
||||
|
||||
@Autowired
|
||||
private CategoryAttributeService categoryAttributeService;
|
||||
|
||||
@Autowired
|
||||
private ProductAttributeService productAttributeService;
|
||||
|
||||
/**
|
||||
* 获取分类列表
|
||||
*/
|
||||
@@ -131,4 +139,52 @@ public class ProductController {
|
||||
public Result<List<Map<String, Object>>> getStockAlerts() {
|
||||
return Result.success(productService.getStockAlerts());
|
||||
}
|
||||
|
||||
// ============ 属性相关 ============
|
||||
|
||||
/**
|
||||
* 获取种类的属性定义
|
||||
*/
|
||||
@GetMapping("/categories/{categoryId}/attributes")
|
||||
public Result<List> getCategoryAttributes(@PathVariable String categoryId) {
|
||||
return Result.success(categoryAttributeService.getByCategoryId(categoryId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存种类的属性定义
|
||||
*/
|
||||
@PostMapping("/categories/{categoryId}/attributes")
|
||||
public Result<Void> saveCategoryAttributes(
|
||||
@PathVariable String categoryId,
|
||||
@RequestBody List attributes,
|
||||
@RequestHeader(value = "X-User-Role", required = false) String role) {
|
||||
if (!"admin".equals(role)) {
|
||||
return Result.error("只有管理员可以操作");
|
||||
}
|
||||
categoryAttributeService.saveAttributes(categoryId, attributes);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品的属性值
|
||||
*/
|
||||
@GetMapping("/{productId}/attributes")
|
||||
public Result<List> getProductAttributes(@PathVariable String productId) {
|
||||
return Result.success(productAttributeService.getByProductId(productId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存商品的属性值
|
||||
*/
|
||||
@PostMapping("/{productId}/attributes")
|
||||
public Result<Void> saveProductAttributes(
|
||||
@PathVariable String productId,
|
||||
@RequestBody List<Map<String, Object>> attrs,
|
||||
@RequestHeader(value = "X-User-Role", required = false) String role) {
|
||||
if (!"admin".equals(role)) {
|
||||
return Result.error("只有管理员可以操作");
|
||||
}
|
||||
productAttributeService.saveProductAttributes(productId, attrs);
|
||||
return Result.success();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.example.building.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 种类属性定义实体
|
||||
*/
|
||||
@Data
|
||||
@TableName("category_attributes")
|
||||
public class CategoryAttribute {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String attrId;
|
||||
|
||||
/**
|
||||
* 种类ID
|
||||
*/
|
||||
private String categoryId;
|
||||
|
||||
/**
|
||||
* 属性名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 属性类型: number=数字, text=文本, formula=公式
|
||||
*/
|
||||
private String attrType;
|
||||
|
||||
/**
|
||||
* 单位
|
||||
*/
|
||||
private String unit;
|
||||
|
||||
/**
|
||||
* 公式表达式(如:length*width)
|
||||
*/
|
||||
private String formula;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Integer sortOrder;
|
||||
|
||||
/**
|
||||
* 是否必填
|
||||
*/
|
||||
private Integer required;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.example.building.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 商品属性值实体
|
||||
*/
|
||||
@Data
|
||||
@TableName("product_attributes")
|
||||
public class ProductAttribute {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 商品ID
|
||||
*/
|
||||
private String productId;
|
||||
|
||||
/**
|
||||
* 属性定义ID
|
||||
*/
|
||||
private String attrId;
|
||||
|
||||
/**
|
||||
* 属性名称(冗余)
|
||||
*/
|
||||
private String attrName;
|
||||
|
||||
/**
|
||||
* 属性值
|
||||
*/
|
||||
private String attrValue;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.example.building.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.example.building.entity.CategoryAttribute;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface CategoryAttributeMapper extends BaseMapper<CategoryAttribute> {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.example.building.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.example.building.entity.ProductAttribute;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface ProductAttributeMapper extends BaseMapper<ProductAttribute> {
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.example.building.service;
|
||||
|
||||
import com.example.building.entity.CategoryAttribute;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 种类属性服务接口
|
||||
*/
|
||||
public interface CategoryAttributeService extends IService<CategoryAttribute> {
|
||||
|
||||
/**
|
||||
* 获取种类的所有属性
|
||||
*/
|
||||
List<CategoryAttribute> getByCategoryId(String categoryId);
|
||||
|
||||
/**
|
||||
* 保存属性
|
||||
*/
|
||||
void saveAttributes(String categoryId, List<CategoryAttribute> attrs);
|
||||
|
||||
/**
|
||||
* 删除种类的所有属性
|
||||
*/
|
||||
void deleteByCategoryId(String categoryId);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.example.building.service;
|
||||
|
||||
import com.example.building.entity.ProductAttribute;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 商品属性服务接口
|
||||
*/
|
||||
public interface ProductAttributeService extends IService<ProductAttribute> {
|
||||
|
||||
/**
|
||||
* 获取商品的属性值
|
||||
*/
|
||||
List<ProductAttribute> getByProductId(String productId);
|
||||
|
||||
/**
|
||||
* 保存商品属性值
|
||||
*/
|
||||
void saveProductAttributes(String productId, List<Map<String, Object>> attrs);
|
||||
|
||||
/**
|
||||
* 删除商品的所有属性
|
||||
*/
|
||||
void deleteByProductId(String productId);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.example.building.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.example.building.entity.CategoryAttribute;
|
||||
import com.example.building.mapper.CategoryAttributeMapper;
|
||||
import com.example.building.service.CategoryAttributeService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 种类属性服务实现
|
||||
*/
|
||||
@Service
|
||||
public class CategoryAttributeServiceImpl implements CategoryAttributeService {
|
||||
|
||||
@Override
|
||||
public List<CategoryAttribute> getByCategoryId(String categoryId) {
|
||||
return this.list(new LambdaQueryWrapper<CategoryAttribute>()
|
||||
.eq(CategoryAttribute::getCategoryId, categoryId)
|
||||
.orderByAsc(CategoryAttribute::getSortOrder));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void saveAttributes(String categoryId, List<CategoryAttribute> attrs) {
|
||||
// 删除旧属性
|
||||
this.remove(new LambdaQueryWrapper<CategoryAttribute>()
|
||||
.eq(CategoryAttribute::getCategoryId, categoryId));
|
||||
|
||||
// 保存新属性
|
||||
if (attrs != null && !attrs.isEmpty()) {
|
||||
for (int i = 0; i < attrs.size(); i++) {
|
||||
CategoryAttribute attr = attrs.get(i);
|
||||
attr.setAttrId(UUID.randomUUID().toString());
|
||||
attr.setCategoryId(categoryId);
|
||||
attr.setSortOrder(i);
|
||||
this.save(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteByCategoryId(String categoryId) {
|
||||
this.remove(new LambdaQueryWrapper<CategoryAttribute>()
|
||||
.eq(CategoryAttribute::getCategoryId, categoryId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.example.building.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.example.building.entity.ProductAttribute;
|
||||
import com.example.building.mapper.ProductAttributeMapper;
|
||||
import com.example.building.service.ProductAttributeService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 商品属性服务实现
|
||||
*/
|
||||
@Service
|
||||
public class ProductAttributeServiceImpl implements ProductAttributeService {
|
||||
|
||||
@Override
|
||||
public List<ProductAttribute> getByProductId(String productId) {
|
||||
return this.list(new LambdaQueryWrapper<ProductAttribute>()
|
||||
.eq(ProductAttribute::getProductId, productId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void saveProductAttributes(String productId, List<Map<String, Object>> attrs) {
|
||||
// 删除旧属性
|
||||
this.remove(new LambdaQueryWrapper<ProductAttribute>()
|
||||
.eq(ProductAttribute::getProductId, productId));
|
||||
|
||||
// 保存新属性
|
||||
if (attrs != null && !attrs.isEmpty()) {
|
||||
for (Map<String, Object> attr : attrs) {
|
||||
ProductAttribute pa = new ProductAttribute();
|
||||
pa.setId(UUID.randomUUID().toString());
|
||||
pa.setProductId(productId);
|
||||
pa.setAttrId((String) attr.get("attrId"));
|
||||
pa.setAttrName((String) attr.get("attrName"));
|
||||
pa.setAttrValue(String.valueOf(attr.get("attrValue")));
|
||||
this.save(pa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteByProductId(String productId) {
|
||||
this.remove(new LambdaQueryWrapper<ProductAttribute>()
|
||||
.eq(ProductAttribute::getProductId, productId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
-- 种类属性定义表
|
||||
CREATE TABLE IF NOT EXISTS category_attributes (
|
||||
attr_id VARCHAR(36) PRIMARY KEY,
|
||||
category_id VARCHAR(36) NOT NULL,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
attr_type VARCHAR(20) DEFAULT 'number',
|
||||
unit VARCHAR(20),
|
||||
formula VARCHAR(200),
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
required INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (category_id) REFERENCES categories(category_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 商品属性值表
|
||||
CREATE TABLE IF NOT EXISTS product_attributes (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
product_id VARCHAR(36) NOT NULL,
|
||||
attr_id VARCHAR(36) NOT NULL,
|
||||
attr_name VARCHAR(50),
|
||||
attr_value VARCHAR(200),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (product_id) REFERENCES products(product_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (attr_id) REFERENCES category_attributes(attr_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 商品表增加默认单位字段
|
||||
ALTER TABLE products ADD COLUMN default_unit VARCHAR(20);
|
||||
Reference in New Issue
Block a user