一、概述
在现代制造企业的数字化转型中,生产过程数据、设备状态、质量监控等信息需要以直观的方式呈现给管理者和一线人员。数据可视化大屏因此成为 MES(Manufacturing Execution System)系统的标配模块之一。
本文结合我在 MES 行业的开发与业务经验,分享如何将开源 go-view 大屏设计器无缝集成到现有 MES 项目中,并实现与企业级登录权限、业务数据接口的打通。
二、背景
传统 MES 系统的数据展示多依赖报表或固定页面,迭代慢、交互差,难以满足生产现场对实时、灵活展示的需求。
而 go-view 作为一款基于 Vue3 + TypeScript 的开源大屏设计器,支持可视化拖拽、组件化管理、动态数据绑定等特性,可以帮助开发团队快速构建炫酷、实时的数据大屏。
优势总结:
- 开源免费,二次开发成本低
- 丰富的图表与组件生态,支持实时数据刷新
- 支持自定义接口与多种数据源,便于和 MES、WMS、QMS、EAM 等模块对接
三、功能介绍
在本次集成方案中,我们的目标包括:
- 可视化设计:运维或业务人员可在浏览器中拖拽组件,自由排版,配置数据源。
- 数据实时渲染:对接 MES 项目的接口,展示产线 OEE、设备稼动率、WMS 库存等关键指标。
- 统一权限管理:兼容原有的企业 SSO 或 Token 认证体系,保证数据安全。
- 附件与资源管理:支持从项目后台读取图片、视频等静态资源,满足丰富的展示需求。
以下是集成后界面展示:
以下是项目中案例展示
四、开发设计
1. 引入 go-view
- 将 go-view 作为独立子应用部署,建议使用
vite打包产物。 - 通过 iframe 方式挂载到 MES 前端框架中,确保与现有路由不冲突。
git clone https://gitee.com/dromara/go-view.git
cd go-view
pnpm install
pnpm build
注意: 这里使用的是go-view的1.x版本,在项目上出现了情况,由于有些电视的浏览器版本过低使用 2.x 版本的话可能会导致 go-view运行报错。
2. 改造数据接口
后端
/**
* 大屏项目Controller
* * @author fwj * @since 2025-08-08 */@Slf4j
@Tag(name = "大屏项目控制器", description = "大屏项目控制器")
@RestController
@RequestMapping("/goview/project")
public class GoviewProjectController {
@Autowired
private GoviewProjectService goviewProjectService;
@Autowired
private GoviewProjectDataService goviewProjectDataService;
@Autowired
private GoviewFileService goviewFileService;
@Autowired
private FileServiceContext fileServiceContext;
@Operation(summary = "查询大屏项目列表", description = "查询大屏项目列表")
@PostMapping("/pageList")
public Result<IPage<GoviewProject>> pageList(@Parameter(description = "查询参数") @RequestBody GoviewProjectParam goviewProjectParam) {
Page<GoviewProject> page = new Page<>(goviewProjectParam.getPage(), goviewProjectParam.getPageSize());
GoviewProject goviewProject = new GoviewProject();
BeanUtils.copyProperties(goviewProjectParam, goviewProject);
QueryWrapper<GoviewProject> wrapper = QueryWrapperUtil.build(goviewProject);
IPage<GoviewProject> list = goviewProjectService.page(page, wrapper);
return Result.success(list);
}
@Operation(summary = "获取大屏项目详细信息", description = "获取大屏项目详细信息")
@GetMapping(value = "/{id}")
public Result getInfo(@Parameter(description = "大屏项目ID") @PathVariable("id") Long id) {
return Result.success(goviewProjectService.getById(id));
}
@Operation(summary = "新增大屏项目", description = "新增大屏项目")
@PostMapping
public Result<?> save(@Parameter(description = "大屏项目") @RequestBody GoviewProjectVo goviewProject) {
goviewProjectService.saveProject(goviewProject);
return Result.success("保存成功", goviewProject.getId());
}
@Operation(summary = "修改大屏项目", description = "修改大屏项目")
@PutMapping
public Result<?> update(@Parameter(description = "大屏项目") @RequestBody GoviewProjectVo goviewProject) {
goviewProjectService.updateProject(goviewProject);
return Result.success("保存成功", goviewProject.getId());
}
@Operation(summary = "删除大屏项目", description = "删除大屏项目")
@DeleteMapping
public Result<?> remove(@Parameter(description = "删除ID") @RequestParam("ids") Long[] ids) {
return Result.success(goviewProjectService.removeByIds(Arrays.asList(ids)));
}
@Operation(summary = "项目重命名", description = "项目重命名")
@PostMapping("/rename")
public Result rename(@RequestBody GoviewProject goviewProject)
{
LambdaUpdateWrapper<GoviewProject> updateWrapper= new LambdaUpdateWrapper<>();
updateWrapper.eq(GoviewProject::getId, goviewProject.getId());
updateWrapper.set(GoviewProject::getProjectName, goviewProject.getProjectName());
goviewProjectService.update(updateWrapper);
return Result.success();
}
@Operation(summary="发布/取消项目状态", description="Customize Toolbar…")
@PutMapping("/publish")
public Result updateVisible(@RequestBody GoviewProject goviewProject){
if (goviewProject.getId() == null) {
throw new BizException("项目ID不能为空!");
}
if(goviewProject.getState()==1||goviewProject.getState()==0) {
LambdaUpdateWrapper<GoviewProject> updateWrapper=new LambdaUpdateWrapper<GoviewProject>();
updateWrapper.eq(GoviewProject::getId, goviewProject.getId());
updateWrapper.set(GoviewProject::getState, goviewProject.getState());
goviewProjectService.update(updateWrapper);
return Result.success();
}
return Result.error("警告非法字段");
}
@Operation(summary = "获取项目存储数据", description = "获取项目存储数据")
@GetMapping("/getData")
public Result getData(@RequestParam("projectId") Long projectId)
{
GoviewProject goviewProject= goviewProjectService.getById(projectId);
GoviewProjectVo goviewProjectVo=new GoviewProjectVo();
BeanUtils.copyProperties(goviewProject,goviewProjectVo);
GoviewProjectData blogText=goviewProjectDataService.getByProjectId(projectId);
if(blogText!=null) {
goviewProjectVo.setContent(blogText.getContent());
}
return Result.success(goviewProjectVo);
}
/**
* 上传文件
* @param file 文件流对象
* @return 文件信息
*/
@Operation(summary="上传文件", description="上传文件")
@PostMapping("/upload")
public Result upload(@RequestParam("file") MultipartFile file) {
String fileName = file.getOriginalFilename();
//默认文件格式
String suffixName = ".png";
String mediaKey="";
Long filesize= file.getSize();
//文件名字
String fileSuffixName="";
if(fileName.lastIndexOf(".")!=-1) {//有后缀
suffixName = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
}
String path = fileServiceContext.uploadFile(file, "goview");
GoviewFile goviewFile=new GoviewFile();
goviewFile.setFileName(fileName);
goviewFile.setFileSize(filesize);
goviewFile.setFileSuffix(fileSuffixName);
goviewFile.setFilePath(path);
goviewFileService.save(goviewFile);
return Result.success("上传成功", goviewFile.getId());
}
/**
* 下载文件
*
* @param attachmentId 附件ID
*/ @GetMapping("/download/{fileId}")
public void fileDownload(@PathVariable("fileId") Long fileId, HttpServletResponse response, HttpServletRequest request)
{
try
{
GoviewFile goviewFile = goviewFileService.getById(fileId);
if (goviewFile == null) {
throw new FileException("获取文件失败!");
}
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, goviewFile.getFileName());
byte[] bytes = fileServiceContext.downloadFile(goviewFile.getFilePath());
FileUtils.writeBytes(bytes, response.getOutputStream());
}catch (Exception e){
log.error("下载文件失败", e);
throw new FileException("下载文件失败!", e);
}
}
}
数据库设计
大屏项目 (data_goview_project)
| 字段名 | 数据类型 | 允许空值 | 主键 | 注释 |
|---|---|---|---|---|
| id | bigint | 否 | 是 | 主键 |
| project_name | varchar(256) | 否 | 否 | 项目名 |
| state | int | 是 | 否 | 状态 |
| is_delete | int | 是 | 否 | 是否删除 |
| index_image | varchar(1024) | 是 | 否 | 封面 |
| remark | varchar(1024) | 是 | 否 | 备注 |
| create_by | bigint | 是 | 否 | |
| create_time | datetime | 是 | 否 | 创建时间 |
| update_by | bigint | 是 | 否 | 更新人 |
| update_time | datetime | 是 | 否 | 更新时间 |
| **大屏项目数据 (data_goview_project_data) ** |
| 字段名 | 数据类型 | 允许空值 | 主键 | 注释 |
|---|---|---|---|---|
| id | bigint | 否 | 是 | 主键 |
| project_id | bigint | 否 | 否 | 项目ID |
| content | text | 是 | 否 | 项目数据 |
| create_time | datetime | 是 | 否 | 创建时间 |
| create_by | bigint | 是 | 否 | 创建人 |
| 大屏图片 (data_goview_file) |
| 字段名 | 数据类型 | 允许空值 | 主键 | 注释 |
|---|---|---|---|---|
| id | bigint | 否 | 是 | 主键 |
| file_name | varchar(128) | 是 | 否 | 文件名 |
| file_size | int | 是 | 否 | 文件大小 |
| file_suffix | varchar(128) | 是 | 否 | 文件后缀 |
| file_path | varchar(1024) | 是 | 否 | 文件路径 |
| create_by | bigint | 是 | 否 | 创建人 |
| create_time | datetime | 是 | 否 | 创建时间 |
前端改造
- 修改
/src/views/project/items/components/ProjectItemsList/index.vue获取列表数据、发布、编辑、删除的方法,调用新的API和项目后端做交互。 - 修改
/src/views/project/items/components/ProjectItemsCard/index.vue卡片图片显示的src,修改成后后端获取到图片的接口。 - 修改
/src/views/chart/ContentEdit/components/EditTools/index.vue保存、更新、文件上传、获取项目接口。
3. 统一登录与权限
为保证安全与一致的用户体验,需要解决 go-view 与原系统登录体系不一致 的问题。 方案:使用后端签发的 秘钥 获取 Token,再由大屏设计器在请求头中携带。 流程如下:
- 首先在系统中为数据大屏新建一个web令牌 ![[Pasted image 20250912172316.png]]
- MES 后端提供
/system/token/login接口,使用sa-token工具,登录之后会自动把token写入到请求头中。 - go-view 在初始化时调用该接口
- 在axios拦截器中先判断时候有token,如果没有先请求获取token的方法。
// 通过秘钥获取token
export const getJwtToken = async (data: { appCode: string; secret: string }) => {
return await http(RequestHttpEnum.POST)('/system/token/login', data);
};
4. 部署与运维
- 前端:大屏设计器前端可独立部署在 Nginx 上,通过子路径(如
/bigscreen/)访问。 - 后端:接口与 MES 后端共用一套微服务架构,复用现有日志、监控、权限系统。
五、总结
在 MES 项目中集成 go-view 大屏设计器,不仅能快速构建高可视化、可拖拽的生产数据大屏,还能通过秘钥登录、接口改造实现与现有权限、数据体系的无缝衔接。
这一方案极大提升了生产现场的可视化水平与运维灵活性,对于需要统一管理 WMS、QMS、EAM、CRM、SCM 等模块的制造企业具有很高的实践价值。
本文源码已上传Gitee 开源项目地址:
欢迎在评论区分享你的技术选型经验,或对本文方案的改进建议!
关注公众号「慧工云创」