功能概述 商品更新记录功能用于跟踪小象买菜系统中商品信息的变更历史,包括价格调整、库存变化、商品上下架等操作记录。这对于系统审计、数据分析和问题排查都非常重要。 数据库设计 商品更新记录表(product_update_log) ```sql CREATETABLE
功能概述
商品更新记录功能用于跟踪小象买菜系统中商品信息的变更历史,包括价格调整、库存变化、商品上下架等操作记录。这对于系统审计、数据分析和问题排查都非常重要。
数据库设计
商品更新记录表(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 NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 更新时间,
operator_id BIGINT COMMENT 操作人ID,
operator_name VARCHAR(50) COMMENT 操作人姓名,
remark VARCHAR(255) COMMENT 备注,
INDEX idx_product_id (product_id),
INDEX idx_update_time (update_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=商品更新记录表;
```
实现方案
1. 基于AOP的实现方式(推荐)
```java
@Aspect
@Component
public class ProductUpdateAspect {
@Autowired
private ProductUpdateLogService productUpdateLogService;
@Autowired
private OperatorContext operatorContext; // 假设有操作人上下文
// 拦截商品服务中的更新方法
@AfterReturning(pointcut = "execution(* com.xiaoxiang.service.ProductService.update*(..)) && args(productId,..)",
returning = "result")
public void afterProductUpdate(JoinPoint joinPoint, Long productId, boolean result) {
if (!result) return;
// 获取方法名判断更新类型
String methodName = joinPoint.getSignature().getName();
String updateType = "";
Map
oldValues = new HashMap<>();
Map newValues = new HashMap<>();
// 根据方法名确定更新类型和获取新旧值
switch (methodName) {
case "updatePrice":
updateType = "price";
// 从参数中获取新旧价格
Object[] args = joinPoint.getArgs();
// 假设参数顺序为productId, oldPrice, newPrice
oldValues.put("price", args[1]);
newValues.put("price", args[2]);
break;
case "updateStock":
updateType = "stock";
// 类似处理库存更新
break;
case "updateStatus":
updateType = "status";
// 处理上下架状态
break;
case "updateProductInfo":
updateType = "info";
// 处理商品信息更新
break;
default:
return;
}
// 记录更新日志
ProductUpdateLog log = new ProductUpdateLog();
log.setProductId(productId);
log.setUpdateType(updateType);
log.setOldValue(JSON.toJSONString(oldValues));
log.setNewValue(JSON.toJSONString(newValues));
log.setOperatorId(operatorContext.getOperatorId());
log.setOperatorName(operatorContext.getOperatorName());
productUpdateLogService.save(log);
}
}
```
2. 手动记录方式(适用于简单场景)
```java
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductUpdateLogService productUpdateLogService;
@Autowired
private OperatorContext operatorContext;
@Override
public boolean updatePrice(Long productId, BigDecimal oldPrice, BigDecimal newPrice) {
// 1. 执行价格更新逻辑
boolean result = productMapper.updatePrice(productId, newPrice) > 0;
// 2. 记录更新日志
if (result) {
ProductUpdateLog log = new ProductUpdateLog();
log.setProductId(productId);
log.setUpdateType("price");
log.setOldValue(oldPrice.toString());
log.setNewValue(newPrice.toString());
log.setOperatorId(operatorContext.getOperatorId());
log.setOperatorName(operatorContext.getOperatorName());
productUpdateLogService.save(log);
}
return result;
}
// 其他更新方法类似...
}
```
3. 商品更新记录服务实现
```java
@Service
public class ProductUpdateLogServiceImpl implements ProductUpdateLogService {
@Autowired
private ProductUpdateLogMapper productUpdateLogMapper;
@Override
public void save(ProductUpdateLog log) {
productUpdateLogMapper.insert(log);
}
@Override
public List getUpdateHistory(Long productId, Date startTime, Date endTime) {
return productUpdateLogMapper.selectByProductIdAndTimeRange(productId, startTime, endTime);
}
@Override
public PageInfo getUpdateHistoryPage(Long productId, PageParam pageParam) {
PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize());
List logs = productUpdateLogMapper.selectByProductId(productId);
return new PageInfo<>(logs);
}
}
```
前端展示实现
商品更新历史页面
```javascript
// Vue组件示例
export default {
data() {
return {
productId: null,
updateLogs: [],
pagination: {
currentPage: 1,
pageSize: 10,
total: 0
}
}
},
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;
});
},
formatUpdateType(type) {
const typeMap = {
price: 价格调整,
stock: 库存变更,
status: 上下架状态,
info: 商品信息
};
return typeMap[type] || type;
},
formatValue(value) {
try {
const json = JSON.parse(value);
return Object.entries(json).map(([key, val]) => `${key}: ${val}`).join(, );
} catch (e) {
return value;
}
}
},
mounted() {
this.productId = this.$route.params.productId;
this.fetchUpdateLogs();
}
}
```
模板示例
```html
商品更新历史
更新时间 |
更新类型 |
旧值 |
新值 |
操作人 |
|---|
{{ formatDateTime(log.updateTime) }} |
{{ formatUpdateType(log.updateType) }} |
{{ formatValue(log.oldValue) }} |
{{ formatValue(log.newValue) }} |
{{ log.operatorName }} |
:current-page="pagination.currentPage"
:page-size="pagination.pageSize"
:total="pagination.total"
@page-change="fetchUpdateLogs">
```
高级功能扩展
1. 变更对比:在前端实现新旧值的差异高亮显示
2. 批量导出:支持将更新记录导出为Excel
3. 变更通知:重要变更(如价格大幅调整)自动发送通知
4. 操作回滚:基于更新记录实现部分操作的回滚功能
5. 数据可视化:对价格、库存等历史数据进行图表展示
注意事项
1. 性能考虑:高频更新的商品可能会产生大量记录,需考虑分表或归档策略
2. 数据安全:敏感信息(如成本价)不应直接记录在日志中
3. 一致性:确保在事务回滚时也能正确处理更新记录
4. 存储优化:对于频繁更新的字段,可考虑单独建表或使用更高效的存储格式
通过实现商品更新记录功能,小象买菜系统可以更好地追踪商品信息的变化,提高系统可维护性和数据可靠性。