跳到主要内容
企业级供应商管理系统开发实践与技术选型总结 | 极客日志
Java AI java
企业级供应商管理系统开发实践与技术选型总结 综述由AI生成 一套基于 Spring Boot 和 AI 辅助开发工具构建的企业级供应商管理系统的实践过程。涵盖环境搭建、核心模块设计(实体类、服务层、控制器)、系统架构分层及扩展性保障。通过引入智能编码助手,团队在满足高并发、数据一致性及权限控制要求的同时,显著提升了编码效率与代码规范性。项目成果验证了人机协同模式在企业级复杂业务系统中的可行性,为后续对接 ERP 与财务系统奠定了良好基础。
墨染流年 发布于 2026/2/9 更新于 2026/5/27 20 浏览一、背景与选型考量
作为一名从业 20 余年的开发者,我亲历了从 JSP+Servlet 到 Spring Boot 微服务的技术迭代。近期受朋友所托,为其企业开发一套供应商管理系统,用于处理采购订单、供应商评级与合同管理等核心业务。这类系统看似常规,但涉及多角色权限控制、复杂审批流程与数据一致性保障,对代码规范性和可维护性要求极高。
初期规划时,团队面临两个现实问题:一是核心开发人员仅 3 人,需在 3 个月内完成上线;二是系统后续需对接 ERP 与财务系统,架构扩展性至关重要。朋友极力推荐 AI 辅助开发工具,称其"能生成企业级规范代码,且支持复杂业务逻辑"。说实话,作为习惯手写代码的老程序员,我对这类 AI 工具本持怀疑态度——见过太多只能生成 Demo 级代码的工具,实际项目中反而增加重构成本。
抱着试用心态,我在 IntelliJ IDEA 中安装了 AI 插件。首次使用便发现其与众不同:它并非简单的代码生成器,而是能基于业务需求进行结构化分析,生成包含实体类、DTO、Service、Controller 的完整模块,且代码风格贴近阿里开发手册规范。这让我意识到,或许能借助它解决团队人力不足的困境。
二、开发环境与工具适配
对于企业级项目,开发环境的稳定性与工具链兼容性至关重要。我们基于现有技术栈做了如下配置,全程未出现工具冲突问题:
1. 基础环境搭建
开发团队统一使用 IntelliJ IDEA 2023.2 版本(企业版),配合 JDK 17(LTS 版本,确保长期支持)与 Maven 3.8.6。服务器环境采用 CentOS 7.9,数据库使用 MySQL 8.0(开启 InnoDB 事务引擎与行级锁,保障高并发场景下的数据一致性)。
2. AI 插件配置
在 IDEA 中安装 AI 辅助插件后,需注意两个关键配置:一是在插件设置中开启"企业级代码规范"(默认关闭,开启后生成的代码会包含完整的参数校验与异常处理);二是配置数据库连接信息,使其能自动生成符合表结构的实体类与 Mapper 接口。
3. 版本控制与协作配置
考虑到多人协作,我们使用 GitLab 进行版本控制,并在 AI 插件中配置了"代码生成后自动格式化"功能(基于 Google Java Format),确保不同开发者生成的代码风格一致。同时通过 IDEA 的 Git 插件,实现生成代码与手动编写代码的无缝融合提交。
三、核心模块设计与实现
企业级供应商管理系统的核心在于"流程严谨性"与"数据安全性"。我们借助 AI 辅助工具,高效实现了供应商管理、采购订单、审批流程三大核心模块,以下是具体实现过程:
1. 需求分析与模块拆分
在 AI 工具的"需求编辑器"中,我输入了如下业务描述(使用企业常用的业务术语):
'开发供应商管理系统核心模块,支持三级角色(系统管理员、采购专员、财务审核员);实现供应商全生命周期管理(注册、资质审核、评级、黑名单);采购订单流程(创建、部门审批、财务审核、供应商确认、发货、验收);合同管理(关联订单、电子签章、到期提醒)。技术栈:Spring Boot 3.1 + Spring Security + MyBatis-Plus + MySQL 8.0,要求代码符合 GB/T 34944-2017《信息技术 软件生存周期过程》规范,包含完整的日志、事务与异常处理。'
提交需求后,AI 工具在 15 秒内完成分析,输出了包含 8 个模块的结构化设计方案,其中 3 个核心模块的边界定义尤为清晰:
供应商管理模块:包含基础信息 CRUD、资质文件上传与审核、信用评级算法实现
采购订单模块:支持订单状态流转(8 个状态)、多级审批、订单与合同关联
权限管理模块:基于 RBAC 模型,实现数据权限(如采购专员只能查看本部门订单)与功能权限控制
2. 核心代码实现与技术亮点
AI 工具生成的代码并非简单的 CRUD 模板,而是包含了企业级系统必需的设计模式与安全考量。以下是几个核心模块的代码示例与技术分析:
(1)实体类设计(带审计字段与枚举约束)
Supplier.java(供应商实体)
package com.enterprise.supplier.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.enterprise.supplier.enums.SupplierStatusEnum;
import com.enterprise.supplier.enums.CreditRatingEnum;
lombok.Data;
java.time.LocalDateTime;
{
Long id;
String supplierCode;
String supplierName;
String creditCode;
SupplierStatusEnum status;
CreditRatingEnum creditRating;
LocalDateTime cooperationStartTime;
LocalDateTime lastRatingTime;
Integer deleted;
String createBy;
LocalDateTime createTime;
String updateBy;
LocalDateTime updateTime;
}
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
import
import
@Data
@TableName("supplier")
public
class
Supplier
@TableId(type = IdType.ASSIGN_ID)
private
@TableField(unique = true, nullable = false)
private
@TableField(nullable = false)
private
@TableField(unique = true, nullable = false)
private
@TableField(nullable = false)
private
@TableField(nullable = false)
private
private
private
@TableLogic
private
@TableField(fill = FieldFill.INSERT)
private
@TableField(fill = FieldFill.INSERT)
private
@TableField(fill = FieldFill.INSERT_UPDATE)
private
@TableField(fill = FieldFill.INSERT_UPDATE)
private
使用枚举类 SupplierStatusEnum 约束状态值,避免魔法数字(老项目中常见问题)
加入审计字段(createBy、updateBy 等),满足企业数据追溯需求
采用逻辑删除(@TableLogic),符合企业数据归档规范
字段注释包含业务含义说明,便于后期维护
(2)服务层实现(带事务控制与业务校验) PurchaseOrderServiceImpl.java(采购订单服务)
package com.enterprise.supplier.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.enterprise.supplier.entity.PurchaseOrder;
import com.enterprise.supplier.entity.PurchaseOrderItem;
import com.enterprise.supplier.entity.Supplier;
import com.enterprise.supplier.enums.OrderStatusEnum;
import com.enterprise.supplier.enums.AuditStatusEnum;
import com.enterprise.supplier.mapper.PurchaseOrderMapper;
import com.enterprise.supplier.mapper.PurchaseOrderItemMapper;
import com.enterprise.supplier.mapper.SupplierMapper;
import com.enterprise.supplier.service.PurchaseOrderService;
import com.enterprise.supplier.service.AuditService;
import com.enterprise.supplier.dto.OrderCreateDTO;
import com.enterprise.supplier.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor
public class PurchaseOrderServiceImpl extends ServiceImpl <PurchaseOrderMapper, PurchaseOrder> implements PurchaseOrderService {
private final PurchaseOrderMapper orderMapper;
private final PurchaseOrderItemMapper orderItemMapper;
private final SupplierMapper supplierMapper;
private final AuditService auditService;
@Override
@Transactional(rollbackFor = Exception.class)
public PurchaseOrder createOrder (OrderCreateDTO createDTO, String operator) {
log.info("创建采购订单:操作员={}, 供应商 ID={}" , operator, createDTO.getSupplierId());
Supplier supplier = supplierMapper.selectById(createDTO.getSupplierId());
if (supplier == null ) {
throw new BusinessException ("S001" , "供应商不存在" );
}
if (!supplier.getStatus().equals(SupplierStatusEnum.NORMAL)) {
throw new BusinessException ("S002" , String.format("供应商状态异常(当前状态:%s),无法创建订单" , supplier.getStatus().getDesc()));
}
if (createDTO.getItems().isEmpty()) {
throw new BusinessException ("O001" , "订单明细不能为空" );
}
createDTO.getItems().forEach(item -> {
if (item.getQuantity() <= 0 ) {
throw new BusinessException ("O002" , String.format("商品 ID=%s 的采购数量必须大于 0" , item.getProductId()));
}
});
String orderNo = generateOrderNo();
PurchaseOrder order = new PurchaseOrder ();
order.setOrderNo(orderNo);
order.setSupplierId(createDTO.getSupplierId());
order.setSupplierName(supplier.getSupplierName());
order.setDepartmentId(createDTO.getDepartmentId());
order.setTotalAmount(calculateTotalAmount(createDTO.getItems()));
order.setStatus(OrderStatusEnum.DRAFT);
order.setCreateBy(operator);
order.setCreateTime(LocalDateTime.now());
orderMapper.insert(order);
List<PurchaseOrderItem> orderItems = createDTO.getItems().stream().map(item -> {
PurchaseOrderItem orderItem = new PurchaseOrderItem ();
orderItem.setOrderId(order.getId());
orderItem.setProductId(item.getProductId());
orderItem.setProductName(item.getProductName());
orderItem.setQuantity(item.getQuantity());
orderItem.setUnitPrice(item.getUnitPrice());
orderItem.setTotalPrice(item.getUnitPrice().multiply(item.getQuantity()));
return orderItem;
}).collect(Collectors.toList());
orderItemMapper.batchInsert(orderItems);
log.info("采购订单创建成功:订单号={}, ID={}" , orderNo, order.getId());
return order;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void submitOrder (Long orderId, String operator) {
PurchaseOrder order = orderMapper.selectById(orderId);
validateOrderStatus(order, OrderStatusEnum.DRAFT, "只有草稿状态的订单可提交审批" );
order.setStatus(OrderStatusEnum.PENDING_AUDIT);
order.setUpdateBy(operator);
order.setUpdateTime(LocalDateTime.now());
orderMapper.updateById(order);
auditService.initiateAudit(orderId, "PURCHASE" , operator, order.getDepartmentId());
log.info("订单提交审批成功:订单号={}, 审批单已创建" , order.getOrderNo());
}
private void validateOrderStatus (PurchaseOrder order, OrderStatusEnum expectedStatus, String errorMsg) {
if (order == null ) {
throw new BusinessException ("O003" , "订单不存在" );
}
if (!order.getStatus().equals(expectedStatus)) {
throw new BusinessException ("O004" , String.format("%s(当前状态:%s)" , errorMsg, order.getStatus().getDesc()));
}
}
private synchronized String generateOrderNo () {
return "" ;
}
private BigDecimal calculateTotalAmount (List<OrderCreateDTO.OrderItemDTO> items) {
return BigDecimal.ZERO;
}
}
采用 @Transactional(rollbackFor = Exception.class) 确保事务完整性,符合企业级数据一致性要求
封装 validateOrderStatus 通用方法,避免状态校验的重复代码(老项目中常见的代码冗余问题)
使用自定义 BusinessException(带错误码),便于前端错误提示与后端问题定位
订单编号生成方法添加 synchronized 关键字,解决并发场景下的编号重复问题
总金额从明细重新计算,避免前端传参篡改(企业系统安全考量)
(3)控制器实现(带权限控制与参数校验) SupplierController.java(供应商管理控制器)
package com.enterprise.supplier.controller;
import com.enterprise.supplier.dto.SupplierDTO;
import com.enterprise.supplier.dto.SupplierQueryDTO;
import com.enterprise.supplier.service.SupplierService;
import com.enterprise.supplier.vo.SupplierVO;
import com.enterprise.supplier.vo.PageResultVO;
import com.enterprise.supplier.vo.ResultVO;
import com.enterprise.supplier.annotation.RequirePermission;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@RestController
@RequestMapping("/api/v1/suppliers")
@Api(tags = "供应商管理接口")
@RequiredArgsConstructor
public class SupplierController {
private final SupplierService supplierService;
@PostMapping
@ApiOperation("新增供应商")
@RequirePermission("supplier:add")
public ResultVO<Long> addSupplier (@ApiParam("供应商信息") @Valid @RequestBody SupplierDTO supplierDTO, @RequestHeader("X-Operator") String operator) {
Long supplierId = supplierService.createSupplier(supplierDTO, operator);
return ResultVO.success("供应商创建成功" , supplierId);
}
@PostMapping("/{id}/qualifications")
@ApiOperation("上传供应商资质文件")
@RequirePermission("supplier:upload")
public ResultVO<String> uploadQualification (@ApiParam("供应商 ID") @PathVariable Long id, @ApiParam("资质文件") @RequestParam("file") MultipartFile file, @RequestHeader("X-Operator") String operator) {
String fileUrl = supplierService.uploadQualification(id, file, operator);
return ResultVO.success("资质文件上传成功" , fileUrl);
}
@GetMapping
@ApiOperation("分页查询供应商")
@RequirePermission("supplier:view")
public ResultVO<PageResultVO<SupplierVO>> querySuppliers (@ApiParam("查询条件") SupplierQueryDTO queryDTO, @ApiParam("页码") @RequestParam(defaultValue = "1") Integer pageNum, @ApiParam("每页条数") @RequestParam(defaultValue = "10") Integer pageSize) {
PageResultVO<SupplierVO> pageResult = supplierService.querySuppliers(queryDTO, pageNum, pageSize);
return ResultVO.success("查询成功" , pageResult);
}
@PutMapping("/{id}/audit")
@ApiOperation("供应商资质审核")
@RequirePermission("supplier:audit")
public ResultVO<Void> auditSupplier (@ApiParam("供应商 ID") @PathVariable Long id, @ApiParam("审核状态(1-通过 2-驳回)") @RequestParam Integer auditStatus, @ApiParam("审核意见") @RequestParam(required = false) String auditOpinion, @RequestHeader("X-Operator") String operator) {
supplierService.auditSupplier(id, auditStatus, auditOpinion, operator);
return ResultVO.success(auditStatus == 1 ? "审核通过" : "审核驳回" );
}
}
使用自定义 @RequirePermission 注解实现细粒度权限控制,符合企业 RBAC 权限模型
接口参数添加 @Valid 校验,配合 DTO 中的 @NotNull 等注解,实现入参合法性检查
通过 @RequestHeader("X-Operator") 获取操作人信息,便于审计日志记录
集成 Swagger 生成 API 文档,减少前后端沟通成本(企业级项目必备)
文件上传单独作为接口,便于单独控制权限与添加限流逻辑
(4)网页端 <!DOCTYPE html >
<html lang ="zh-CN" >
<head >
<meta charset ="UTF-8" >
<meta name ="viewport" content ="width=device-width, initial-scale=1.0" >
<title > 企业级供应商管理系统</title >
<script src ="https://cdn.tailwindcss.com" > </script >
<link href ="https://cdn.jsdelivr.net/npm/[email protected] /css/font-awesome.min.css" rel ="stylesheet" >
<script src ="https://cdn.jsdelivr.net/npm/[email protected] /dist/chart.umd.min.js" > </script >
<script >
tailwind.config = { theme : { extend : { colors : { primary : '#165DFF' , secondary : '#36CFC9' , success : '#52C41A' , warning : '#FAAD14' , danger : '#FF4D4F' , info : '#4E5969' , light : '#F2F3F5' , dark : '#1D2129' }, fontFamily : { sans : ['Inter' , 'system-ui' , 'sans-serif' ], } } } }
</script >
<style type ="text/tailwindcss" >
@layer utilities {
.content-auto { content-visibility : auto; }
.sidebar-item { @apply flex items-center gap-3 px-4 py-3 text-gray-600 hover :bg-primary/10 hover :text-primary rounded-lg transition-all duration-200 ; }
.sidebar-item .active { @apply bg-primary/10 text-primary font-medium border-l-4 border-primary; }
.card-shadow { @apply shadow-sm hover :shadow-md transition-shadow duration-300 ; }
.btn-primary { @apply bg-primary text-white px-4 py-2 rounded-lg hover :bg-primary/90 transition-colors duration-200 ; }
.btn-secondary { @apply bg-white text-gray-700 border border-gray-300 px-4 py-2 rounded-lg hover :bg-gray-50 transition-colors duration-200 ; }
.table-row-hover { @apply hover :bg-gray-50 transition-colors duration-150 ; }
}
</style >
</head >
<body class ="bg-gray-50 text-gray-800 font-sans" >
<div class ="flex h-screen overflow-hidden" >
<aside class ="w-64 bg-white border-r border-gray-200 flex-shrink-0 hidden md:block" >
<div class ="h-16 flex items-center justify-center border-b border-gray-200" >
<div class ="flex items-center gap-2" >
<div class ="w-8 h-8 bg-primary rounded-lg flex items-center justify-center" > <i class ="fa fa-cubes text-white" > </i > </div >
<span class ="text-lg font-semibold text-gray-800" > 供应商管理系统</span >
</div >
</div >
<div class ="p-4" >
<p class ="text-xs text-gray-400 uppercase mb-2 px-4" > 主菜单</p >
<div class ="space-y-1" >
<a href ="#" class ="sidebar-item active" > <i class ="fa fa-tachometer w-5 text-center" > </i > <span > 控制台</span > </a >
<a href ="#" class ="sidebar-item" > <i class ="fa fa-building w-5 text-center" > </i > <span > 供应商管理</span > </a >
<a href ="#" class ="sidebar-item" > <i class ="fa fa-file-text w-5 text-center" > </i > <span > 采购订单</span > </a >
<a href ="#" class ="sidebar-item" > <i class ="fa fa-handshake-o w-5 text-center" > </i > <span > 合同管理</span > </a >
<a href ="#" class ="sidebar-item" > <i class ="fa fa-line-chart w-5 text-center" > </i > <span > 数据分析</span > </a >
</div >
<p class ="text-xs text-gray-400 uppercase mb-2 px-4 mt-6" > 系统管理</p >
<div class ="space-y-1" >
<a href ="#" class ="sidebar-item" > <i class ="fa fa-users w-5 text-center" > </i > <span > 用户管理</span > </a >
<a href ="#" class ="sidebar-item" > <i class ="fa fa-key w-5 text-center" > </i > <span > 权限设置</span > </a >
<a href ="#" class ="sidebar-item" > <i class ="fa fa-cog w-5 text-center" > </i > <span > 系统配置</span > </a >
</div >
</div >
</aside >
<div class ="flex-1 flex flex-col overflow-hidden" >
<header class ="h-16 bg-white border-b border-gray-200 flex items-center justify-between px-6" >
<button class ="md:hidden text-gray-500 hover:text-primary" > <i class ="fa fa-bars text-xl" > </i > </button >
<div class ="flex items-center gap-6" >
<div class ="relative hidden md:block" >
<input type ="text" placeholder ="搜索..." class ="pl-10 pr-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/30 focus:border-primary w-64 text-sm" >
<i class ="fa fa-search absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" > </i >
</div >
<div class ="relative" >
<button class ="text-gray-500 hover:text-primary relative" > <i class ="fa fa-bell text-xl" > </i > <span class ="absolute -top-1 -right-1 w-4 h-4 bg-danger rounded-full text-white text-xs flex items-center justify-center" > 3</span > </button >
</div >
<div class ="flex items-center gap-3 cursor-pointer group" >
<img src ="https://picsum.photos/id/1005/40/40" alt ="用户头像" class ="w-8 h-8 rounded-full object-cover border-2 border-transparent group-hover:border-primary transition-colors duration-200" >
<div class ="hidden md:block text-left" >
<p class ="text-sm font-medium" > 张经理</p >
<p class ="text-xs text-gray-500" > 采购部主管</p >
</div >
<i class ="fa fa-angle-down text-gray-500 group-hover:text-primary transition-colors duration-200" > </i >
</div >
</div >
</header >
<main class ="flex-1 overflow-y-auto p-6 bg-gray-50" >
<div class ="mb-6" >
<h1 class ="text-[clamp(1.5rem,3vw,2rem)] font-bold text-gray-800" > 控制台</h1 >
<p class ="text-gray-500 mt-1" > 欢迎回来,张经理!以下是系统关键数据概览</p >
</div >
<div class ="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6" >
<div class ="bg-white rounded-xl p-6 card-shadow" >
<div class ="flex justify-between items-start" >
<div >
<p class ="text-gray-500 text-sm" > 供应商总数</p >
<h3 class ="text-3xl font-bold mt-2 mb-1" > 286</h3 >
<p class ="text-success text-sm flex items-center" > <i class ="fa fa-arrow-up mr-1" > </i > 12% <span class ="text-gray-500 ml-1" > 较上月</span > </p >
</div >
<div class ="w-12 h-12 rounded-lg bg-primary/10 flex items-center justify-center text-primary" > <i class ="fa fa-building text-xl" > </i > </div >
</div >
</div >
<div class ="bg-white rounded-xl p-6 card-shadow" >
<div class ="flex justify-between items-start" >
<div >
<p class ="text-gray-500 text-sm" > 活跃供应商</p >
<h3 class ="text-3xl font-bold mt-2 mb-1" > 154</h3 >
<p class ="text-success text-sm flex items-center" > <i class ="fa fa-arrow-up mr-1" > </i > 8% <span class ="text-gray-500 ml-1" > 较上月</span > </p >
</div >
<div class ="w-12 h-12 rounded-lg bg-secondary/10 flex items-center justify-center text-secondary" > <i class ="fa fa-check-circle text-xl" > </i > </div >
</div >
</div >
<div class ="bg-white rounded-xl p-6 card-shadow" >
<div class ="flex justify-between items-start" >
<div >
<p class ="text-gray-500 text-sm" > 本月订单</p >
<h3 class ="text-3xl font-bold mt-2 mb-1" > ¥286.5K</h3 >
<p class ="text-danger text-sm flex items-center" > <i class ="fa fa-arrow-down mr-1" > </i > 3% <span class ="text-gray-500 ml-1" > 较上月</span > </p >
</div >
<div class ="w-12 h-12 rounded-lg bg-warning/10 flex items-center justify-center text-warning" > <i class ="fa fa-file-text text-xl" > </i > </div >
</div >
</div >
<div class ="bg-white rounded-xl p-6 card-shadow" >
<div class ="flex justify-between items-start" >
<div >
<p class ="text-gray-500 text-sm" > 待处理事项</p >
<h3 class ="text-3xl font-bold mt-2 mb-1" > 18</h3 >
<p class ="text-danger text-sm flex items-center" > <i class ="fa fa-arrow-up mr-1" > </i > 5 <span class ="text-gray-500 ml-1" > 较昨日</span > </p >
</div >
<div class ="w-12 h-12 rounded-lg bg-danger/10 flex items-center justify-center text-danger" > <i class ="fa fa-exclamation-circle text-xl" > </i > </div >
</div >
</div >
</div >
<div class ="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6" >
<div class ="bg-white rounded-xl p-6 card-shadow lg:col-span-2" >
<div class ="flex justify-between items-center mb-6" >
<h3 class ="font-semibold text-gray-800" > 采购金额趋势</h3 >
<div class ="flex gap-2" >
<button class ="text-sm px-3 py-1 rounded-full bg-primary/10 text-primary" > 月度</button >
<button class ="text-sm px-3 py-1 rounded-full hover:bg-gray-100" > 季度</button >
<button class ="text-sm px-3 py-1 rounded-full hover:bg-gray-100" > 年度</button >
</div >
</div >
<div class ="h-80" > <canvas id ="purchaseTrendChart" > </canvas > </div >
</div >
<div class ="bg-white rounded-xl p-6 card-shadow" >
<div class ="flex justify-between items-center mb-6" >
<h3 class ="font-semibold text-gray-800" > 供应商分类占比</h3 >
<button class ="text-gray-400 hover:text-primary" > <i class ="fa fa-ellipsis-v" > </i > </button >
</div >
<div class ="h-80 flex items-center justify-center" > <canvas id ="supplierCategoryChart" > </canvas > </div >
</div >
</div >
<div class ="bg-white rounded-xl p-6 card-shadow mb-6" >
<div class ="flex justify-between items-center mb-6" >
<h3 class ="font-semibold text-gray-800" > 最近新增供应商</h3 >
<button class ="btn-primary flex items-center gap-2" > <i class ="fa fa-plus" > </i > <span > 新增供应商</span > </button >
</div >
<div class ="overflow-x-auto" >
<table class ="w-full text-sm" >
<thead >
<tr class ="border-b border-gray-200" >
<th class ="text-left py-3 px-4 font-medium text-gray-500" > 供应商名称</th >
<th class ="text-left py-3 px-4 font-medium text-gray-500" > 联系人</th >
<th class ="text-left py-3 px-4 font-medium text-gray-500" > 联系方式</th >
<th class ="text-left py-3 px-4 font-medium text-gray-500" > 分类</th >
<th class ="text-left py-3 px-4 font-medium text-gray-500" > 信用评级</th >
<th class ="text-left py-3 px-4 font-medium text-gray-500" > 状态</th >
<th class ="text-left py-3 px-4 font-medium text-gray-500" > 操作</th >
</tr >
</thead >
<tbody >
<tr class ="border-b border-gray-100 table-row-hover" >
<td class ="py-3 px-4" > <div class ="flex items-center gap-3" > <div class ="w-8 h-8 bg-primary/10 rounded flex items-center justify-center text-primary" > <i class ="fa fa-building" > </i > </div > <span > 上海恒通电子科技有限公司</span > </div > </td >
<td class ="py-3 px-4" > 李明</td >
<td class ="py-3 px-4" > 13812345678</td >
<td class ="py-3 px-4" > 电子元器件</td >
<td class ="py-3 px-4" > <span class ="px-2 py-1 rounded-full text-xs bg-success/10 text-success" > AAA</span > </td >
<td class ="py-3 px-4" > <span class ="px-2 py-1 rounded-full text-xs bg-success/10 text-success" > 正常</span > </td >
<td class ="py-3 px-4" > <div class ="flex gap-2" > <button class ="text-primary hover:text-primary/80" title ="查看详情" > <i class ="fa fa-eye" > </i > </button > <button class ="text-gray-500 hover:text-gray-700" title ="编辑" > <i class ="fa fa-edit" > </i > </button > <button class ="text-danger hover:text-danger/80" title ="删除" > <i class ="fa fa-trash" > </i > </button > </div > </td >
</tr >
<tr class ="border-b border-gray-100 table-row-hover" >
<td class ="py-3 px-4" > <div class ="flex items-center gap-3" > <div class ="w-8 h-8 bg-primary/10 rounded flex items-center justify-center text-primary" > <i class ="fa fa-building" > </i > </div > <span > 北京盛世办公设备有限公司</span > </div > </td >
<td class ="py-3 px-4" > 王芳</td >
<td class ="py-3 px-4" > 13987654321</td >
<td class ="py-3 px-4" > 办公设备</td >
<td class ="py-3 px-4" > <span class ="px-2 py-1 rounded-full text-xs bg-secondary/10 text-secondary" > AA</span > </td >
<td class ="py-3 px-4" > <span class ="px-2 py-1 rounded-full text-xs bg-success/10 text-success" > 正常</span > </td >
<td class ="py-3 px-4" > <div class ="flex gap-2" > <button class ="text-primary hover:text-primary/80" title ="查看详情" > <i class ="fa fa-eye" > </i > </button > <button class ="text-gray-500 hover:text-gray-700" title ="编辑" > <i class ="fa fa-edit" > </i > </button > <button class ="text-danger hover:text-danger/80" title ="删除" > <i class ="fa fa-trash" > </i > </button > </div > </td >
</tr >
<tr class ="border-b border-gray-100 table-row-hover" >
<td class ="py-3 px-4" > <div class ="flex items-center gap-3" > <div class ="w-8 h-8 bg-primary/10 rounded flex items-center justify-center text-primary" > <i class ="fa fa-building" > </i > </div > <span > 广州瑞丰原材料贸易有限公司</span > </div > </td >
<td class ="py-3 px-4" > 张伟</td >
<td class ="py-3 px-4" > 13765432189</td >
<td class ="py-3 px-4" > 原材料</td >
<td class ="py-3 px-4" > <span class ="px-2 py-1 rounded-full text-xs bg-warning/10 text-warning" > A</span > </td >
<td class ="py-3 px-4" > <span class ="px-2 py-1 rounded-full text-xs bg-warning/10 text-warning" > 待审核</span > </td >
<td class ="py-3 px-4" > <div class ="flex gap-2" > <button class ="text-primary hover:text-primary/80" title ="查看详情" > <i class ="fa fa-eye" > </i > </button > <button class ="text-gray-500 hover:text-gray-700" title ="编辑" > <i class ="fa fa-edit" > </i > </button > <button class ="text-danger hover:text-danger/80" title ="删除" > <i class ="fa fa-trash" > </i > </button > </div > </td >
</tr >
<tr class ="border-b border-gray-100 table-row-hover" >
<td class ="py-3 px-4" > <div class ="flex items-center gap-3" > <div class ="w-8 h-8 bg-primary/10 rounded flex items-center justify-center text-primary" > <i class ="fa fa-building" > </i > </div > <span > 深圳创新包装制品有限公司</span > </div > </td >
<td class ="py-3 px-4" > 刘静</td >
<td class ="py-3 px-4" > 13678901234</td >
<td class ="py-3 px-4" > 包装材料</td >
<td class ="py-3 px-4" > <span class ="px-2 py-1 rounded-full text-xs bg-warning/10 text-warning" > A</span > </td >
<td class ="py-3 px-4" > <span class ="px-2 py-1 rounded-full text-xs bg-success/10 text-success" > 正常</span > </td >
<td class ="py-3 px-4" > <div class ="flex gap-2" > <button class ="text-primary hover:text-primary/80" title ="查看详情" > <i class ="fa fa-eye" > </i > </button > <button class ="text-gray-500 hover:text-gray-700" title ="编辑" > <i class ="fa fa-edit" > </i > </button > <button class ="text-danger hover:text-danger/80" title ="删除" > <i class ="fa fa-trash" > </i > </button > </div > </td >
</tr >
</tbody >
</table >
</div >
<div class ="flex justify-between items-center mt-6" >
<p class ="text-sm text-gray-500" > 显示 1 至 4 条,共 286 条记录</p >
<div class ="flex gap-1" >
<button class ="w-9 h-9 flex items-center justify-center rounded border border-gray-300 text-gray-400 hover:border-primary hover:text-primary disabled:opacity-50" disabled > <i class ="fa fa-angle-left" > </i > </button >
<button class ="w-9 h-9 flex items-center justify-center rounded bg-primary text-white" > 1</button >
<button class ="w-9 h-9 flex items-center justify-center rounded border border-gray-300 hover:border-primary hover:text-primary" > 2</button >
<button class ="w-9 h-9 flex items-center justify-center rounded border border-gray-300 hover:border-primary hover:text-primary" > 3</button >
<button class ="w-9 h-9 flex items-center justify-center rounded border border-gray-300 hover:border-primary hover:text-primary" > 4</button >
<button class ="w-9 h-9 flex items-center justify-center rounded border border-gray-300 hover:border-primary hover:text-primary" > 5</button >
<button class ="w-9 h-9 flex items-center justify-center rounded border border-gray-300 hover:border-primary hover:text-primary" > <i class ="fa fa-angle-right" > </i > </button >
</div >
</div >
</div >
<div class ="bg-white rounded-xl p-6 card-shadow" >
<div class ="flex justify-between items-center mb-6" >
<h3 class ="font-semibold text-gray-800" > 待处理订单</h3 >
<button class ="text-primary hover:text-primary/80 flex items-center gap-1 text-sm" > <span > 查看全部</span > <i class ="fa fa-angle-right" > </i > </button >
</div >
<div class ="space-y-4" >
<div class ="border border-gray-100 rounded-lg p-4 hover:border-primary/30 transition-colors duration-200" >
<div class ="flex justify-between items-start" >
<div >
<div class ="flex items-center gap-2 mb-2" > <span class ="text-sm font-medium" > 订单编号:PO20230615008</span > <span class ="px-2 py-0.5 rounded-full text-xs bg-warning/10 text-warning" > 待审批</span > </div >
<p class ="text-sm text-gray-500" > 供应商:上海恒通电子科技有限公司</p >
</div >
<div class ="text-right" >
<p class ="text-lg font-semibold" > ¥32,500.00</p >
<p class ="text-sm text-gray-500" > 2023-06-15</p >
</div >
</div >
<div class ="mt-4 pt-4 border-t border-gray-100 flex justify-between items-center" >
<p class ="text-sm" > <span class ="text-gray-500" > 审批人:</span > <span > 李总监</span > </p >
<div class ="flex gap-2" >
<button class ="btn-secondary text-sm px-3 py-1" > <i class ="fa fa-eye mr-1" > </i > 查看 </button >
<button class ="btn-primary text-sm px-3 py-1" > <i class ="fa fa-check mr-1" > </i > 审批 </button >
</div >
</div >
</div >
<div class ="border border-gray-100 rounded-lg p-4 hover:border-primary/30 transition-colors duration-200" >
<div class ="flex justify-between items-start" >
<div >
<div class ="flex items-center gap-2 mb-2" > <span class ="text-sm font-medium" > 订单编号:PO20230614056</span > <span class ="px-2 py-0.5 rounded-full text-xs bg-warning/10 text-warning" > 待确认</span > </div >
<p class ="text-sm text-gray-500" > 供应商:北京盛世办公设备有限公司</p >
</div >
<div class ="text-right" >
<p class ="text-lg font-semibold" > ¥8,750.00</p >
<p class ="text-sm text-gray-500" > 2023-06-14</p >
</div >
</div >
<div class ="mt-4 pt-4 border-t border-gray-100 flex justify-between items-center" >
<p class ="text-sm" > <span class ="text-gray-500" > 供应商确认截止:</span > <span class ="text-danger" > 2023-06-17</span > </p >
<div class ="flex gap-2" >
<button class ="btn-secondary text-sm px-3 py-1" > <i class ="fa fa-eye mr-1" > </i > 查看 </button >
<button class ="btn-primary text-sm px-3 py-1" > <i class ="fa fa-phone mr-1" > </i > 催单 </button >
</div >
</div >
</div >
<div class ="border border-gray-100 rounded-lg p-4 hover:border-primary/30 transition-colors duration-200" >
<div class ="flex justify-between items-start" >
<div >
<div class ="flex items-center gap-2 mb-2" > <span class ="text-sm font-medium" > 订单编号:PO20230612034</span > <span class ="px-2 py-0.5 rounded-full text-xs bg-danger/10 text-danger" > 已逾期</span > </div >
<p class ="text-sm text-gray-500" > 供应商:广州瑞丰原材料贸易有限公司</p >
</div >
<div class ="text-right" >
<p class ="text-lg font-semibold" > ¥56,200.00</p >
<p class ="text-sm text-gray-500" > 2023-06-12</p >
</div >
</div >
<div class ="mt-4 pt-4 border-t border-gray-100 flex justify-between items-center" >
<p class ="text-sm" > <span class ="text-gray-500" > 预计到货日期:</span > <span class ="text-danger" > 2023-06-15(已逾期 3 天)</span > </p >
<div class ="flex gap-2" >
<button class ="btn-secondary text-sm px-3 py-1" > <i class ="fa fa-eye mr-1" > </i > 查看 </button >
<button class ="btn-primary text-sm px-3 py-1" > <i class ="fa fa-exclamation-circle mr-1" > </i > 处理 </button >
</div >
</div >
</div >
</div >
</div >
</main >
</div >
</div >
<script >
document .addEventListener ('DOMContentLoaded' , function ( ) {
const purchaseCtx = document .getElementById ('purchaseTrendChart' ).getContext ('2d' );
new Chart (purchaseCtx, {
type : 'line' ,
data : {
labels : ['1 月' , '2 月' , '3 月' , '4 月' , '5 月' , '6 月' , '7 月' , '8 月' , '9 月' , '10 月' , '11 月' , '12 月' ],
datasets : [
{ label : '2023 年采购金额' , data : [185000 , 210000 , 235000 , 220000 , 245000 , 286500 , 0 , 0 , 0 , 0 , 0 , 0 ], borderColor : '#165DFF' , backgroundColor : 'rgba(22, 93, 255, 0.1)' , tension : 0.4 , fill : true },
{ label : , : [ , , , , , , , , , , , ], : , : , : , : , : [ , ] }
]
},
: {
: ,
: ,
: {
: { : , },
: {
: , : ,
: {
: ( ) {
label = context. . || ;
(label) { label += ; }
(context. . !== ) { label += . ( , { : , : }). (context. . ); }
label;
}
}
}
},
: {
: { : , : { : ( ) { + (value / ) + ; } } }
}
}
});
categoryCtx = . ( ). ( );
(categoryCtx, {
: ,
: {
: [ , , , , ],
: [{ : [ , , , , ], : [ , , , , ], : , : }]
},
: {
: ,
: ,
: {
: { : , },
: {
: {
: ( ) { context. + + context. + ; }
}
}
},
:
}
});
menuButton = . ( );
sidebar = . ( );
menuButton. ( , ( ) {
sidebar. . ( );
sidebar. . ( );
sidebar. . ( );
sidebar. . ( );
});
});
</script >
</body >
</html >
四、系统架构与扩展性设计 企业级系统的生命力在于可扩展性。借助 AI 辅助工具生成的模块化代码,我们构建了如下架构,确保后续能平滑对接 ERP 与财务系统:
1. 分层架构设计 系统采用经典的"表现层 - 业务层 - 数据访问层"三层架构,各层职责清晰:
表现层(Controller):处理 HTTP 请求,负责参数校验与权限控制
业务层(Service):实现核心业务逻辑,包含事务控制与状态流转
数据访问层(Mapper):基于 MyBatis-Plus 实现数据库操作,屏蔽 SQL 细节
特别值得一提的是,AI 工具自动生成了 DTO、VO 与 Entity 的分层模型:
DTO(Data Transfer Object):用于接收前端请求参数,带完整校验注解
VO(View Object):用于向前端返回数据,隐藏敏感字段(如密码、内部编码)
Entity:与数据库表映射,包含审计字段与逻辑删除标识
这种分层设计避免了"直接使用 Entity 接收请求"的常见问题,为后续系统扩展奠定基础。
2. 接口设计规范 为确保系统可集成性,我们基于 AI 工具生成的接口,制定了如下企业级接口规范:
统一响应格式:所有接口返回 ResultVO,包含 code(状态码)、msg(消息)、data(数据)
版本控制:URL 中包含版本号(如 /api/v1/suppliers),便于接口迭代
错误码规范:采用"业务域 + 序号"格式(如 S001=供应商相关错误,O001=订单相关错误)
分页参数统一:所有分页接口使用 pageNum(页码)与 pageSize(每页条数)作为参数
这些规范确保了系统接口的一致性,降低了后续对接 ERP 系统的集成成本。
3. 扩展性保障 为满足未来业务增长,系统在三个层面做了扩展性设计:
数据库层面:使用分表策略(基于 Sharding-JDBC),按年度拆分订单表(如 purchase_order_2023)
缓存层面:核心数据(供应商信息、商品基础数据)添加 Redis 缓存,减轻数据库压力
服务层面:预留消息队列接口(基于 RabbitMQ),后续可异步处理订单状态变更通知
AI 工具生成的代码中已预留了缓存注解与异步处理的代码骨架,我们仅需补充具体实现即可,这大大缩短了架构落地时间。
五、资深开发者视角的工具评价 作为从业 20 余年的开发者,我对 AI 辅助工具的评价是"真正理解企业级开发痛点的工具",具体体现在以下三个方面:
1. 代码规范性与可维护性 AI 工具生成的代码严格遵循《阿里巴巴 Java 开发手册》,包含:
命名规范:类名使用 UpperCamelCase,方法名使用 lowerCamelCase
注释完整:每个类、方法、核心字段都有业务含义说明
异常处理:统一使用自定义异常,避免 try-catch 嵌套
安全考量:防 SQL 注入(使用参数绑定)、防 XSS 攻击(前端参数过滤)
这比很多初级开发者手写的代码质量更高,大幅降低了后期维护成本。
2. 对企业级业务的理解深度
自动识别状态流转逻辑,生成状态校验方法
考虑并发场景,在订单编号生成等关键处添加同步控制
预留审计日志与数据权限的扩展点
支持复杂查询条件(多表关联、范围查询)
这些都不是简单的代码模板能实现的,背后必然有对大量企业级项目的学习与总结。
3. 与资深开发者工作流的适配性 作为老程序员,我习惯"先设计后编码"的工作方式,AI 工具很好地适配了这一点:
支持先输出设计方案,开发者确认后再生成代码
生成的代码保留扩展点,便于手动添加复杂业务逻辑
不强制使用特定框架,可与现有技术栈无缝融合
代码可阅读性强,并非不可维护的"机器码"
这与某些"黑箱式"AI 工具不同,它更像是"高级助理",而非"替代开发者"。
六、项目成果与经验总结 从技术角度看,AI 辅助工具帮助团队节省了约 40% 的编码时间,让我们能专注于业务逻辑与架构设计。特别是在权限管理、状态流转等企业级系统的"基础设施"开发上,工具的优势尤为明显。
作为资深开发者,我认为使用这类 AI 工具的关键在于"人机协同":开发者负责需求分析、架构设计与复杂业务逻辑实现,工具负责生成规范化的基础代码。这种模式既能发挥 AI 的高效率,又能保留开发者的经验与判断,是企业级项目开发的理想模式。
最后给同行的建议:不要抵触 AI 工具,而要学会利用其提升效率。但同时要保持对代码质量的把控,定期进行代码评审,确保 AI 生成的代码符合企业规范。毕竟,工具是辅助,开发者的经验与思考才是系统成功的核心。
'2022 年采购金额'
data
150000
175000
200000
190000
210000
230000
245000
260000
255000
270000
280000
310000
borderColor
'#8C8C8C'
backgroundColor
'rgba(140, 140, 140, 0.05)'
tension
0.4
fill
true
borderDash
5
5
options
responsive
true
maintainAspectRatio
false
plugins
legend
position
'top'
tooltip
mode
'index'
intersect
false
callbacks
label
function
context
let
dataset
label
''
if
': '
if
parsed
y
null
new
Intl
NumberFormat
'zh-CN'
style
'currency'
currency
'CNY'
format
parsed
y
return
scales
y
beginAtZero
true
ticks
callback
function
value
return
'¥'
10000
'万'
const
document
getElementById
'supplierCategoryChart'
getContext
'2d'
new
Chart
type
'doughnut'
data
labels
'电子元器件'
'办公设备'
'原材料'
'包装材料'
'其他'
datasets
data
35
25
20
15
5
backgroundColor
'#165DFF'
'#36CFC9'
'#FAAD14'
'#722ED1'
'#8C8C8C'
borderWidth
0
hoverOffset
5
options
responsive
true
maintainAspectRatio
false
plugins
legend
position
'bottom'
tooltip
callbacks
label
function
context
return
label
': '
parsed
'%'
cutout
'70%'
const
document
querySelector
'button.md\:hidden'
const
document
querySelector
'aside'
addEventListener
'click'
function
classList
toggle
'hidden'
classList
toggle
'absolute'
classList
toggle
'z-50'
classList
toggle
'h-full'