功能概述
商品更新记录功能用于跟踪小象买菜系统中商品信息的变更历史,包括价格调整、库存变化、商品上下架等操作,便于审计和问题追溯。
数据库设计
商品更新记录表(product_update_log)
```sql
CREATE TABLE product_update_log (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 记录ID,
product_id BIGINT NOT NULL COMMENT 商品ID,
update_type VARCHAR(20) NOT NULL COMMENT 更新类型(price/stock/status/info),
old_value TEXT COMMENT 旧值(JSON格式),
new_value TEXT COMMENT 新值(JSON格式),
update_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 更新时间,
operator_id BIGINT COMMENT 操作人ID,
operator_name VARCHAR(50) COMMENT 操作人姓名,
ip_address VARCHAR(50) COMMENT 操作IP,
remark VARCHAR(255) COMMENT 备注
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=商品更新记录表;
```
后端实现
1. 使用AOP切面记录更新
```java
@Aspect
@Component
public class ProductUpdateAspect {
@Autowired
private ProductUpdateLogService productUpdateLogService;
// 记录商品价格更新
@AfterReturning(pointcut = "execution(* com.xiaoxiang.service.ProductService.updatePrice(..))",
returning = "result")
public void afterPriceUpdate(JoinPoint joinPoint, Object result) {
Object[] args = joinPoint.getArgs();
if (args.length >= 2) {
Long productId = (Long) args[0];
BigDecimal newPrice = (BigDecimal) args[1];
// 获取旧价格(需要从数据库查询)
Product product = productService.getById(productId);
BigDecimal oldPrice = product.getPrice();
// 创建更新记录
ProductUpdateLog log = new ProductUpdateLog();
log.setProductId(productId);
log.setUpdateType("price");
log.setOldValue(oldPrice.toString());
log.setNewValue(newPrice.toString());
// 设置其他字段...
productUpdateLogService.save(log);
}
}
// 类似实现其他更新类型的切面
}
```
2. 使用事件驱动模式
```java
// 定义商品更新事件
public class ProductUpdateEvent {
private Product oldProduct;
private Product newProduct;
private String updateType;
// 构造方法、getter/setter...
}
// 发布事件的服务
@Service
public class ProductService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void updatePrice(Long productId, BigDecimal newPrice) {
Product product = getById(productId);
BigDecimal oldPrice = product.getPrice();
// 更新价格逻辑...
// 发布更新事件
ProductUpdateEvent event = new ProductUpdateEvent(product, product, "price");
eventPublisher.publishEvent(event);
}
}
// 事件监听器
@Component
public class ProductUpdateEventListener {
@Autowired
private ProductUpdateLogService productUpdateLogService;
@EventListener
public void handleProductUpdate(ProductUpdateEvent event) {
ProductUpdateLog log = new ProductUpdateLog();
log.setProductId(event.getNewProduct().getId());
log.setUpdateType(event.getUpdateType());
// 根据更新类型构建oldValue和newValue
switch (event.getUpdateType()) {
case "price":
Product oldP = event.getOldProduct();
Product newP = event.getNewProduct();
log.setOldValue(oldP.getPrice().toString());
log.setNewValue(newP.getPrice().toString());
break;
// 其他更新类型处理...
}
productUpdateLogService.save(log);
}
}
```
3. 直接在Service层记录
```java
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductUpdateLogService productUpdateLogService;
@Override
@Transactional
public boolean updatePrice(Long productId, BigDecimal newPrice, Long operatorId) {
Product product = productMapper.selectById(productId);
if (product == null) {
throw new RuntimeException("商品不存在");
}
BigDecimal oldPrice = product.getPrice();
if (oldPrice.compareTo(newPrice) == 0) {
return false; // 价格未变化
}
// 更新价格
product.setPrice(newPrice);
productMapper.updateById(product);
// 记录更新日志
ProductUpdateLog log = new ProductUpdateLog();
log.setProductId(productId);
log.setUpdateType("price");
log.setOldValue(oldPrice.toString());
log.setNewValue(newPrice.toString());
log.setOperatorId(operatorId);
// 设置其他字段...
productUpdateLogService.save(log);
return true;
}
}
```
前端实现
商品更新记录列表页面
```javascript
// Vue组件示例
export default {
data() {
return {
updateLogs: [],
pagination: {
currentPage: 1,
pageSize: 10,
total: 0
},
productId: null
}
},
created() {
this.productId = this.$route.params.productId;
this.fetchUpdateLogs();
},
methods: {
fetchUpdateLogs() {
const params = {
productId: this.productId,
pageNum: this.pagination.currentPage,
pageSize: this.pagination.pageSize
};
api.getProductUpdateLogs(params).then(response => {
this.updateLogs = response.data.list;
this.pagination.total = response.data.total;
});
},
handlePageChange(page) {
this.pagination.currentPage = page;
this.fetchUpdateLogs();
}
}
}
```
更新记录展示组件
```html
{{ formatDateTime(scope.row.updateTime) }}
{{ formatUpdateType(scope.row.updateType) }}
{{ formatValue(scope.row.oldValue) }}
{{ formatValue(scope.row.newValue) }}
@current-change="handlePageChange"
:current-page="pagination.currentPage"
:page-size="pagination.pageSize"
:total="pagination.total"
layout="total, prev, pager, next">
<script>
export default {
methods: {
formatUpdateType(type) {
const typeMap = {
price: 价格,
stock: 库存,
status: 状态,
info: 信息
};
return typeMap[type] || type;
},
formatValue(value) {
try {
const obj = JSON.parse(value);
return JSON.stringify(obj, null, 2);
} catch (e) {
return value;
}
},
getTagType(type) {
const typeMap = {
price: warning,
stock: danger,
status: info,
info:
};
return typeMap[type] || ;
}
}
}
```
高级功能扩展
1. 差异对比:对于复杂对象更新,可以高亮显示具体字段的变化
2. 批量操作记录:记录批量导入、导出等操作
3. 回滚功能:根据更新记录回滚到指定版本
4. 操作趋势分析:统计各类更新操作的频率和模式
5. 实时推送:商品更新时实时通知相关人员
性能优化建议
1. 对于高频更新的字段(如库存),考虑异步记录日志
2. 使用消息队列缓冲日志写入操作
3. 定期归档历史日志到单独的表或存储系统
4. 对JSON字段进行压缩存储
安全考虑
1. 记录操作IP和设备信息
2. 对敏感字段(如成本价)进行脱敏处理
3. 实现细粒度的权限控制,谁可以看哪些日志
以上实现方案可以根据小象买菜系统的具体技术栈和业务需求进行调整。