1. 项目概述:装饰工程管理系统的全栈实现
这个基于Spring Boot+Vue+MySQL的装饰工程管理系统,是我在建筑信息化领域摸爬滚打多年后沉淀出的实战方案。不同于市面上那些花架子管理系统,这套代码从数据库设计到接口优化都经过真实项目验证,特别适合中小型装饰公司快速搭建自己的数字化管理平台。
系统采用经典的前后端分离架构,后端用Spring Boot 2.7.x构建RESTful API,前端用Vue 3+Element Plus实现响应式界面,数据库选用MySQL 8.0。最值得称道的是开箱即用的特性——下载源码后只需配置数据库连接,五分钟内就能看到完整运行的系统。这种"拎包入住"式的体验,对急需管理系统又缺乏技术团队的建筑公司简直是救命稻草。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术栈深度解析
2.1 Spring Boot后端设计精要
后端采用分层架构设计,controller层用@Validated实现参数校验,service层用Spring事务管理保证数据一致性。特别要提的是材料管理模块的数据库设计:
java复制@Entity
@Table(name = "material")
public class Material {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(precision = 10, scale = 2)
private BigDecimal unitPrice;
@Enumerated(EnumType.STRING)
private MaterialType type; // 枚举类定义材料类型
// 关联工程阶段
@ManyToOne
@JoinColumn(name = "project_phase_id")
private ProjectPhase projectPhase;
}
这种设计既满足装饰工程对材料管理的精细化需求,又通过JPA关联实现了业务对象间的自然映射。我在项目里特意加入了BigDecimal类型处理金额计算,避免浮点数精度问题导致的财务误差。
2.2 Vue前端工程化实践
前端采用Vue CLI创建的工程结构,通过axios拦截器统一处理HTTP请求:
javascript复制// src/utils/request.js
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 5000
})
// 请求拦截器
service.interceptors.request.use(config => {
if (store.getters.token) {
config.headers['Authorization'] = `Bearer ${getToken()}`
}
return config
}, error => {
return Promise.reject(error)
})
特别优化了工程进度看板的数据可视化,使用ECharts实现了甘特图与进度曲线的联动展示。在src/views/project/components目录下,你会找到我封装的可复用进度组件,直接传入时间数据就能生成专业图表。
2.3 MySQL性能优化技巧
装饰工程数据的特点是关联性强、历史记录多。针对这个特性,我在数据库设计时做了这些优化:
-
为项目表添加复合索引:
sql复制ALTER TABLE project ADD INDEX idx_status_company (status, company_id); -
材料库存表使用DECIMAL类型存储数量:
sql复制CREATE TABLE material_stock ( material_id BIGINT PRIMARY KEY, quantity DECIMAL(12,3) NOT NULL COMMENT '支持千克/立方米等单位' ); -
为工程变更记录表设计时序分区:
sql复制CREATE TABLE change_log ( id BIGINT AUTO_INCREMENT, project_id BIGINT NOT NULL, change_time DATETIME NOT NULL, -- 其他字段 PRIMARY KEY (id, change_time) ) PARTITION BY RANGE (TO_DAYS(change_time)) ( PARTITION p202301 VALUES LESS THAN (TO_DAYS('2023-02-01')), PARTITION p202302 VALUES LESS THAN (TO_DAYS('2023-03-01')) );
3. 核心功能模块实现
3.1 工程进度四维管控
系统将工程进度分解为四个维度进行管理:
- 时间维度:里程碑节点控制
- 成本维度:预算消耗曲线
- 质量维度:验收问题跟踪
- 人员维度:工时投入分析
后端提供聚合查询接口:
java复制@GetMapping("/projects/{id}/progress")
public ProjectProgressDTO getProjectProgress(@PathVariable Long id) {
// 获取基础进度
ProjectProgress progress = progressService.getByProjectId(id);
// 并行查询关联数据
CompletableFuture<CostAnalysis> costFuture = CompletableFuture.supplyAsync(
() -> costService.analyzeByProject(id));
CompletableFuture<QualityStats> qualityFuture = CompletableFuture.supplyAsync(
() -> qualityService.getStats(id));
// 组合结果
return ProjectProgressDTO.builder()
.timeProgress(progress)
.costAnalysis(costFuture.join())
.qualityStats(qualityFuture.join())
.build();
}
3.2 材料智能预警系统
通过定义材料警戒规则,实现自动预警:
java复制public class MaterialAlertRule {
private Long materialId;
private AlertType type; // 库存不足/价格波动等
private BigDecimal threshold;
private Duration checkFrequency;
@Scheduled(fixedDelayString = "${alert.check.interval}")
public void checkRules() {
rules.forEach(rule -> {
switch(rule.getType()) {
case STOCK:
checkStock(rule);
break;
case PRICE:
checkPrice(rule);
break;
}
});
}
private void checkStock(MaterialAlertRule rule) {
BigDecimal currentStock = stockService.getCurrentStock(rule.getMaterialId());
if (currentStock.compareTo(rule.getThreshold()) < 0) {
alertService.triggerAlert(rule);
}
}
}
4. 部署与运维实战
4.1 一键启动方案
项目根目录下的docker-compose.yml已经配置好全套环境:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: decoration
ports:
- "3306:3306"
volumes:
- ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
frontend:
build: ./frontend
ports:
- "80:80"
执行docker-compose up -d即可启动所有服务。初始化SQL脚本会自动创建表结构和测试数据。
4.2 性能调优参数
在生产环境部署时,建议调整这些JVM参数:
code复制-XX:MetaspaceSize=128m
-XX:MaxMetaspaceSize=256m
-Xms512m
-Xmx1024m
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
对于高并发场景,需要修改Spring Boot的Tomcat配置:
properties复制server.tomcat.max-threads=200
server.tomcat.accept-count=100
spring.datasource.hikari.maximum-pool-size=20
5. 踩坑实录与解决方案
5.1 材料库存并发问题
初期发现库存扣减会出现负数,这是典型的并发问题。最终采用MySQL乐观锁解决:
java复制@Transactional
public void deductStock(Long materialId, BigDecimal quantity) {
MaterialStock stock = stockRepository.findById(materialId)
.orElseThrow(() -> new BusinessException("材料不存在"));
if (stock.getQuantity().compareTo(quantity) < 0) {
throw new BusinessException("库存不足");
}
int updated = stockRepository.deductWithVersion(
materialId, quantity, stock.getVersion());
if (updated == 0) {
throw new ConcurrentUpdateException("库存并发修改,请重试");
}
}
对应的Repository方法:
java复制@Modifying
@Query("UPDATE MaterialStock s SET s.quantity = s.quantity - :quantity,
s.version = s.version + 1
WHERE s.id = :id AND s.version = :version")
int deductWithVersion(@Param("id") Long id,
@Param("quantity") BigDecimal quantity,
@Param("version") Long version);
5.2 工程进度同步延迟
当多个管理员同时更新进度时,会出现状态不一致。我们通过Redis分布式锁解决:
java复制public boolean updateProgress(Long projectId, ProgressUpdateCmd cmd) {
String lockKey = "project:progress:" + projectId;
String requestId = UUID.randomUUID().toString();
try {
// 获取锁,设置10秒过期
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, requestId, 10, TimeUnit.SECONDS);
if (!locked) {
throw new ConcurrentUpdateException("系统正在处理其他进度更新");
}
// 执行业务逻辑
return doUpdateProgress(projectId, cmd);
} finally {
// 释放锁时要验证requestId,避免误删其他请求的锁
String currentValue = redisTemplate.opsForValue().get(lockKey);
if (requestId.equals(currentValue)) {
redisTemplate.delete(lockKey);
}
}
}
6. 扩展开发指南
6.1 对接企业微信
在src/main/java/com/decoration/wechat包下新增企业微信通知功能:
java复制public class WeComNotifier {
private final RestTemplate restTemplate;
public void sendProgressAlert(Long projectId, String message) {
String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={token}";
Map<String, Object> body = new HashMap<>();
body.put("touser", "@all");
body.put("msgtype", "text");
body.put("agentid", weComConfig.getAgentId());
body.put("text", Map.of("content", message));
restTemplate.postForObject(url, body, String.class, getAccessToken());
}
}
6.2 生成工程决算PDF
使用Flying Saucer+Thymeleaf生成PDF报表:
java复制public byte[] generateFinalReport(Long projectId) throws IOException {
Context ctx = new Context();
ctx.setVariable("project", projectService.getById(projectId));
ctx.setVariable("details", costService.getDetails(projectId));
String html = templateEngine.process("report/final", ctx);
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(html);
renderer.layout();
renderer.createPDF(os);
return os.toByteArray();
}
}
模板文件resources/templates/report/final.html使用标准HTML+CSS编写,支持分页符、页眉页脚等专业排版需求。
这套系统经过三个真实项目的迭代,目前已经形成包含132个Java类、89个Vue组件的完整解决方案。特别在材料管理和进度跟踪方面,有很多从实际业务中提炼出的设计细节,比如支持多单位换算的材料库存模型、考虑工序依赖关系的进度计算算法等。对于想要学习Spring Boot+Vue全栈开发的朋友,这个项目能让你看到企业级应用的真实面貌。
