1. 项目背景与需求分析
装饰工程行业作为建筑领域的重要组成部分,近年来面临着管理复杂度指数级增长的挑战。一个中型装饰项目通常涉及20-30人的团队协作、上百种材料的调度管理以及多工种交叉作业的进度协调。传统依靠Excel表格和纸质单据的管理方式,经常出现数据不同步、进度不透明等问题。
我在实际项目咨询中发现,超过70%的装饰企业存在以下痛点:
- 材料库存与采购计划脱节,导致停工待料或库存积压
- 项目进度依赖人工汇报,管理层难以及时获取真实情况
- 各环节数据孤立,无法形成有效的决策支持
这套管理系统正是针对这些痛点设计的数字化解决方案。采用前后端分离架构,后端使用SpringBoot提供稳定的业务逻辑处理,前端通过Vue3实现动态数据展示,MySQL作为可靠的数据存储方案。系统特别强化了以下特性:
- 实时材料库存预警机制
- 可视化进度看板
- 多维度数据分析报表
2. 技术架构设计
2.1 后端技术选型
SpringBoot 2.7.x作为后端框架,其自动配置特性大幅减少了传统Spring项目的XML配置工作量。在实际部署中,我们特别优化了以下配置:
java复制# application-prod.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/decoration_db?useSSL=false&serverTimezone=Asia/Shanghai
username: admin
password: 加密密码
hikari:
maximum-pool-size: 20
connection-timeout: 30000
mybatis:
mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: true
关键经验:HikariCP连接池配置需要根据实际服务器CPU核心数调整,一般建议maximum-pool-size = CPU核心数 * 2 + 1
2.2 前端架构设计
Vue3组合式API大幅提升了代码可维护性。项目采用以下目录结构:
code复制src/
├── api/ # 接口定义
├── assets/ # 静态资源
├── components/ # 公共组件
├── composables/ # 组合式函数
├── router/ # 路由配置
├── stores/ # Pinia状态管理
├── utils/ # 工具函数
└── views/ # 页面组件
材料管理模块典型代码示例:
vue复制<script setup>
import { ref } from 'vue'
import { useMaterialStore } from '@/stores/material'
const store = useMaterialStore()
const searchForm = ref({
name: '',
spec: '',
minStock: null
})
const handleSearch = async () => {
await store.fetchMaterials(searchForm.value)
}
</script>
3. 核心功能实现
3.1 项目进度甘特图
基于ECharts实现的动态甘特图组件,关键实现步骤:
- 数据库设计添加进度里程碑表:
sql复制CREATE TABLE project_milestone (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
project_id BIGINT NOT NULL,
name VARCHAR(50) NOT NULL,
plan_start DATE NOT NULL,
plan_end DATE NOT NULL,
actual_start DATE,
actual_end DATE,
completion INT DEFAULT 0,
FOREIGN KEY (project_id) REFERENCES project(project_id)
);
- 后端接口提供进度聚合数据:
java复制@GetMapping("/progress/{projectId}")
public Result getProjectProgress(@PathVariable Long projectId) {
List<MilestoneVO> milestones = milestoneService.listByProject(projectId);
ProjectProgressVO progress = new ProjectProgressVO();
// 计算总体进度
int totalWeight = milestones.stream().mapToInt(MilestoneVO::getWeight).sum();
int completedWeight = milestones.stream()
.filter(m -> m.getCompletion() == 100)
.mapToInt(MilestoneVO::getWeight)
.sum();
progress.setOverallProgress(totalWeight > 0 ?
(int)((double)completedWeight / totalWeight * 100) : 0);
progress.setMilestones(milestones);
return Result.success(progress);
}
3.2 材料库存预警
实现多级库存预警机制:
- 数据库触发器自动检查库存水平
sql复制DELIMITER //
CREATE TRIGGER check_material_stock
AFTER UPDATE ON material_stock
FOR EACH ROW
BEGIN
DECLARE msg VARCHAR(100);
IF NEW.stock_quantity < NEW.min_stock THEN
SET msg = CONCAT('材料ID:', NEW.material_id, ' 库存低于最小值');
INSERT INTO alert_log(content, level, create_time)
VALUES(msg, 'urgent', NOW());
END IF;
END//
DELIMITER ;
- 前端实时显示预警信息
vue复制<template>
<el-alert
v-for="alert in urgentAlerts"
:key="alert.id"
:title="alert.content"
type="error"
show-icon
closable
/>
</template>
<script setup>
import { storeToRefs } from 'pinia'
import { useAlertStore } from '@/stores/alert'
const alertStore = useAlertStore()
const { urgentAlerts } = storeToRefs(alertStore)
// 每30秒轮询一次预警信息
setInterval(() => {
alertStore.fetchAlerts()
}, 30000)
</script>
4. 权限系统设计
4.1 RBAC模型实现
系统采用标准的RBAC(基于角色的访问控制)模型,数据库设计包含五张核心表:
mermaid复制erDiagram
USER ||--o{ USER_ROLE : has
ROLE ||--o{ ROLE_PERMISSION : has
PERMISSION ||--o{ MENU : contains
USER {
bigint user_id PK
varchar(50) username
varchar(100) password
}
ROLE {
bigint role_id PK
varchar(30) role_name
}
PERMISSION {
bigint perm_id PK
varchar(50) perm_code
}
Spring Security配置核心代码:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/material/**").hasAnyRole("PM", "WAREHOUSE")
.antMatchers("/api/project/**").hasRole("PM")
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()));
return http.build();
}
}
重要提示:权限验证一定要在后端做最终校验,前端路由守卫仅作为用户体验优化,不能作为安全依据
5. 性能优化实践
5.1 数据库查询优化
- 为高频查询字段添加索引:
sql复制ALTER TABLE material_stock ADD INDEX idx_material_name (material_name);
ALTER TABLE project_task ADD INDEX idx_project_status (project_id, completion_rate);
- MyBatis二级缓存配置:
xml复制<!-- mapper.xml -->
<cache eviction="LRU" flushInterval="60000" size="1024" readOnly="true"/>
<!-- 对于需要实时性的查询显式关闭缓存 -->
<select id="getCurrentStock" useCache="false">
SELECT * FROM material_stock WHERE material_id = #{id}
</select>
5.2 前端性能优化
- 路由懒加载配置:
javascript复制const routes = [
{
path: '/materials',
component: () => import('@/views/MaterialView.vue')
}
]
- API请求防抖处理:
javascript复制import { debounce } from 'lodash-es'
const searchMaterials = debounce(async (query) => {
const res = await api.searchMaterials(query)
materials.value = res.data
}, 300)
6. 部署与运维
6.1 容器化部署方案
Docker Compose编排文件示例:
yaml复制version: '3.8'
services:
backend:
build: ./backend
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- mysql
frontend:
build: ./frontend
ports:
- "80:80"
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: decoration_db
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
6.2 监控配置
SpringBoot Actuator健康检查端点配置:
properties复制management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always
management.metrics.tags.application=decoration-system
Prometheus监控指标采集配置:
yaml复制scrape_configs:
- job_name: 'decoration-system'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['backend:8080']
7. 典型问题排查
7.1 跨域问题解决方案
完整CORS配置示例:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:8081")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowCredentials(true)
.maxAge(3600);
}
}
7.2 事务失效场景处理
常见事务失效原因及解决方案:
- 自调用问题:通过AopContext解决
java复制public void updateMaterial(Material material) {
((MaterialService) AopContext.currentProxy()).doUpdate(material);
}
@Transactional
public void doUpdate(Material material) {
// 业务逻辑
}
- 异常类型不正确:确保抛出RuntimeException
java复制@Transactional(rollbackFor = Exception.class)
public void batchImport(List<Material> materials) {
try {
// 导入逻辑
} catch (Exception e) {
throw new RuntimeException("导入失败", e);
}
}
8. 扩展开发建议
8.1 微信小程序集成
通过uni-app实现多端兼容的小程序版本:
javascript复制// 对接后端API
const api = {
getProjects() {
return uni.request({
url: 'https://api.example.com/projects',
header: {
'Authorization': 'Bearer ' + getApp().globalData.token
}
})
}
}
8.2 数据分析扩展
使用Apache ECharts实现的项目成本分析看板:
javascript复制option = {
dataset: {
source: [
['项目', '预算', '实际'],
['A项目', 120000, 135000],
['B项目', 80000, 76000]
]
},
xAxis: { type: 'category' },
yAxis: {},
series: [
{ type: 'bar' },
{ type: 'bar' }
]
}
在实际项目部署中,建议采用渐进式迭代策略,先上线核心功能模块,再根据用户反馈逐步扩展。对于中小型装饰企业,可优先实施材料管理和进度跟踪模块,这两个模块通常能带来最直接的管理效率提升。