若依(ruoyi)前后端分离项目集成积木报表,并解决积木大屏部署到服务器加载不出来的问题,目前整体使用感觉还是
分享于 点击 43200 次 点评:213
若依(ruoyi)前后端分离项目集成积木报表,并解决积木大屏部署到服务器加载不出来的问题,目前整体使用感觉还是
若依(ruoyi)前后端分离项目集成积木报表
致敬:
1:若依开源项目(本文使用的是前后端分离版本:3.8.9)
若依官网:https://www.ruoyi.vip/
2:积木开源项目
积木报表官网:https://www.jimureport.com/
3:CSDN大神的文章(我是根据他的原文一步步配置的,前端配置有一些改动,如有版权问题,可随时联系本人删除)
原文地址:https://blog.csdn.net/qq_55896432/article/details/145060090
背景:
写在前面:
若依官网:https://www.ruoyi.vip/
积木报表官网:https://www.jimureport.com/
原文地址:https://blog.csdn.net/qq_55896432/article/details/145060090
搭建这个项目是因为自己想记录日常使用的一些数据(练琴统计,钢琴课程数量,花费等等这些),然后找了一些BI发现都不是很适合,目前积木是最适合的(开源且集成程度高),所以记录了一下整体的操作步骤。
目前整体使用感觉还是可以的,数据源数据集设置都很方便,必要的控件也都够用。
项目运行的前提条件:
能正常运行若依前后端分离版本就OK.
效果(部分截图)
手搓的首页
普通报表管理菜单
普通报表设计
数据源&数据集设置
大屏报表管理菜单
大屏设计
数据源&数据集设置
后端配置
ruoyi-common模块下pom.xml文件添加依赖
<!-- 积木报表 -->
<dependency>
<groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimureport-spring-boot-starter</artifactId>
<version>1.9.2</version>
</dependency>
<!--积木BI大屏-->
<dependency>
<groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimubi-spring-boot-starter</artifactId>
<version>1.9.1</version>
</dependency>
添加完重新加载maven
ruoyi-admin模块修改application.yml文件,新增积木报表相关配置
jeecg :
# 权限配置
permission:
# 报表权限配置
report:
# 查询权限符号,配置此权限代表只能查看报表
query: jeecg:report:query
# 修改权限符号,配置此权限代表拥有报表所有权限
edit: jeecg:report:edit
# 大屏权限配置
drag:
# 查询权限符号,配置此权限代表只能查看大屏
query: jeecg:drag:query
# 修改权限符号,配置此权限代表拥有大屏所有权限
edit: jeecg:drag:edit
jmreport:
#自定义项目前缀
# 现在是开发环境下的前端访问前缀,部署项目时,需要切换到生成环境访问前缀
customPrePath: /dev-api
注意:
1.目前报表和大屏分别设置两个类型的权限,其中query权限表示只能查看,edit权限表示用于一切权限。
2.customPrePath是用来配置前端访问后端的接口的前缀,当前是开发环境配置为/dev-api没问题。
3.项目发布时,一定将这个配置改为生产环境下访问前缀,如:/prod-api。
允许匿名访问ruoyi-framework模块下修改SecurityConfig.java文件
增加积木报表和大屏匿名访问权限。
, "/jmreport/**", "/drag/**"
新建积木报表相关配置类
在com.ruoyi.framework包下增加包report,在report包下新增config包,在cofig包下新增ReportConfig.java类,并在此类中添加以下代码。
package com.ruoyi.framework.report.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class ReportConfig {
// 报表查询权限
@Value("${jeecg.permission.report.query}")
private String reportQueryPermission;
// 报表修改权限
@Value("${jeecg.permission.report.edit}")
private String reportEditPermission;
// 大屏查看权限
@Value("${jeecg.permission.drag.query}")
private String dragQueryPermission;
//大屏修改权限
@Value("${jeecg.permission.drag.edit}")
private String dragEditPermission;
public String getReportQueryPermission() {
return reportQueryPermission;
}
public void setReportQueryPermission(String reportQueryPermission) {
this.reportQueryPermission = reportQueryPermission;
}
public String getReportEditPermission() {
return reportEditPermission;
}
public void setReportEditPermission(String reportEditPermission) {
this.reportEditPermission = reportEditPermission;
}
public String getDragQueryPermission() {
return dragQueryPermission;
}
public void setDragQueryPermission(String dragQueryPermission) {
this.dragQueryPermission = dragQueryPermission;
}
public String getDragEditPermission() {
return dragEditPermission;
}
public void setDragEditPermission(String dragEditPermission) {
this.dragEditPermission = dragEditPermission;
}
}
重写若依框架getLoginUser()方法
打开web.service包下的TokenService.java文件,将自带的getLoginUser方法注释掉
新增代码
/***************************积木报表修改,注释掉了原来的getLoginUser*******************************/
// 修改
public LoginUser getLoginUser(HttpServletRequest request) {
// 获取请求携带的令牌
String token = getToken(request);
return getLoginUser(token);
}
public LoginUser getLoginUser(String token) {
if (StringUtils.isNotEmpty(token)) {
try {
Claims claims = parseToken(token);
// 解析对应的权限以及用户信息
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
LoginUser user = redisCache.getCacheObject(userKey);
return user;
} catch (Exception e) {
log.error("获取用户信息异常'{}'", e.getMessage());
}
}
return null;
}
/***************************积木报表修改,注释掉了原来的getLoginUser*******************************/
在report包下新增service包下,在service包下新增ReportTokenService.java类,并且在此类中添加以下代码
package com.ruoyi.framework.report.service;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.report.config.ReportConfig;
import com.ruoyi.framework.web.service.TokenService;
import org.jeecg.modules.jmreport.api.JmReportTokenServiceI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Component
public class ReportTokenService implements JmReportTokenServiceI {
// 若依框架token
@Value("${token.header}")
private String ryHeader;
// 积木报表token
private String jmHeader = "X-Access-Token";
@Autowired
private ReportConfig reportConfig;
@Autowired
private TokenService tokenService;
@Override
public String getUsername(String s) {
LoginUser loginUser = tokenService.getLoginUser(s);
return loginUser.getUsername();
}
@Override
public String[] getRoles(String s) {
LoginUser loginUser = tokenService.getLoginUser(s);
SysUser user = loginUser.getUser();
List<SysRole> roles = user.getRoles();
String[] roleNameArray = roles.stream().map(SysRole::getRoleName).toArray(String[]::new);
return roleNameArray;
}
@Override
public Boolean verifyToken(String s) {
LoginUser loginUser = tokenService.getLoginUser(s);
if (StringUtils.isNotNull(loginUser)){
tokenService.refreshToken(loginUser);
SysUser user = loginUser.getUser();
// 超级管理员放权
if (StringUtils.isNotNull(user) && user.isAdmin()) {
return true;
} else {
Set<String> permissions = loginUser.getPermissions();
if (StringUtils.isNotNull(permissions) && (permissions.contains(reportConfig.getReportQueryPermission()) || permissions.contains(reportConfig.getReportEditPermission()) || permissions.contains(reportConfig.getDragQueryPermission()) || permissions.contains(reportConfig.getDragEditPermission()))) {
return true;
}
}
}
return false;
}
@Override
public String getToken(HttpServletRequest request) {
String token = request.getParameter("token");
if (StringUtils.isNull(token)) {
token = request.getHeader(jmHeader);
}
if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
{
token = token.replace(Constants.TOKEN_PREFIX, "");
}
return token;
}
@Override
public Map<String, Object> getUserInfo(String token) {
token = token.replace(Constants.TOKEN_PREFIX, "");
LoginUser loginUser = tokenService.getLoginUser(token);
Map<String, Object> map = new HashMap<>();
map.put(SYS_USER_CODE, loginUser.getUserId());
map.put(SYS_ORG_CODE, loginUser.getDeptId());
return map;
}
@Override
public HttpHeaders customApiHeader() {
HttpHeaders headers = new HttpHeaders();
headers.add(ryHeader, Constants.TOKEN_PREFIX + getToken());
headers.add(jmHeader, getToken());
return headers;
}
}
贴一下原作者的注意事项:
配置拦截器
在report包下新增interceptor包,在interceptor包下新增ReportInterceptor.java类,并且在此类中添加以下代码
package com.ruoyi.framework.report.interceptor;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.report.config.ReportConfig;
import com.ruoyi.framework.report.service.ReportTokenService;
import com.ruoyi.framework.web.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
@Component
public class ReportInterceptor implements HandlerInterceptor {
@Autowired
private TokenService tokenService;
@Autowired
private ReportConfig reportConfig;
@Autowired
private ReportTokenService reportTokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = reportTokenService.getToken(request);
LoginUser loginUser = tokenService.getLoginUser(token);
// String uri = request.getRequestURI();
// System.out.println(uri);
if (StringUtils.isNotNull(loginUser)) {
SysUser user = loginUser.getUser();
// 超级管理员放权
if (StringUtils.isNotNull(user) && user.isAdmin()) {
return true;
} else {
//获取权限集合
Set<String> permissions = loginUser.getPermissions();
//如果拥有设计器的权限,则无需view权限,也可以通过校验
if (StringUtils.isNotNull(permissions)) {
String uri = request.getRequestURI();
// 如果访问报表
if (uri.contains("/jmreport/")) {
// 如果有操作权限,直接放行
if (permissions.contains(reportConfig.getReportEditPermission())) {
return true;
} else {
// 设置查询报表的路径,没有带报表编码的路径
Set<String> queryReportSet = new HashSet<>();
queryReportSet.add("/jmreport/getQueryInfo");
queryReportSet.add("/jmreport/show");
// 设置查询报表的路径,带报表编码的路径
ArrayList<String> queryReportList = new ArrayList<>();
queryReportList.add("/jmreport/view/");
queryReportList.add("/jmreport/addViewCount/");
queryReportList.add("/jmreport/checkParam/");
// 如果有查询权限
if (permissions.contains(reportConfig.getReportQueryPermission())) {
// 如果是没有报表编码的路径,放行
if (queryReportSet.contains(uri)) {
return true;
} else {
// 如果是带报表编码的路径,放行
for (int i = 0; i < queryReportList.size(); i++) {
String s = queryReportList.get(i);
if (uri.contains(s)) {
return true;
}
}
}
}
}
//如果访问大屏
} else if (uri.contains("/drag/")) {
// 如果有操作权限,直接放行
if (permissions.contains(reportConfig.getDragEditPermission())) {
return true;
} else {
// 设置查询大屏的路径,完全路径
Set<String> queryDragSet = new HashSet<>();
queryDragSet.add("/drag/page/queryById");
queryDragSet.add("/drag/page/addVisitsNumber");
// 设置查询大屏的路径,带有包含部分路径
ArrayList<String> queryDragList = new ArrayList<>();
queryDragList.add("/drag/share/view/");
queryDragList.add("/drag/mock/json/");
// 如果有查询权限,并且访问的查询接口,放行
if (permissions.contains(reportConfig.getDragQueryPermission()) && queryDragSet.contains(uri)) {
return true;
}
}
// 拦截非报表和大屏路径处理,正确配置,不会出现此情况。
} else {
return true;
}
}
}
}
AjaxResult ajaxResult = AjaxResult.error(403, "当前操作没有权限");
ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
return false;
}
}
原作者说的注意事项:
打开config包下的ResourcesConfig.java文件,注入ReportInterceptor拦截器,并且注册拦截器和设置拦截规则
修改addInterceptors()方法
/**
* 自定义拦截规则
*/
@Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**")
// 积木报表新增:不拦截静态资源
.excludePathPatterns("/*.**, /**/*.html, /**/*.css, /**/*.js, /**/*.png, /**/*.jpg, /**/*.woff, /**/*.woff2, /**/*.ttf, /**/*.svg, /**/*.ico, /**/*.map" )
;
}
如果出现未设置的静态资源,需要自己进行设置。
实现数据格式转换器
在report包下新增adapter包,在adapter包下,新增ReportDataConvertAdapter.java文件,并且在此类中添加以下代码
package com.ruoyi.framework.report.adapter;
import com.alibaba.fastjson.JSONObject;
import org.jeecg.modules.jmreport.desreport.render.handler.convert.ApiDataConvertAdapter;
import org.springframework.stereotype.Component;
@Component("reportDataConvertAdapter")
public class ReportDataConvertAdapter implements ApiDataConvertAdapter {
@Override
public String getData(JSONObject jsonObject) {
if(jsonObject.containsKey("data")){
String data = jsonObject.getString("data");
return data;
}else if(jsonObject.containsKey("rows")){
return jsonObject.getString("rows");
}else {
return jsonObject.toJSONString();
}
}
}
去官网拿积木的数据结构,在数据库执行
官网地址:
https://github.com/jeecgboot/jimureport/blob/master/db/jimureport.mysql5.7.create.sql
再贴个云盘地址吧(最好去官网拿最新版本)
https://www.alipan.com/s/PqaE77FUK28
前端配置
新建jeecg文件夹,并且jeecg文件夹下,新增request.js文件,并且在此文件中添加以下代码
import axios from 'axios'
import { Notification, MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams } from "@/utils/ruoyi";
import cache from '@/plugins/cache'
// 是否显示重新登录
export let isRelogin = { show: false };
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
const service = axios.create({
// axios中请求配置有baseURL选项,表示请求URL公共部分
baseURL: process.env.VUE_APP_BASE_API,
// 超时
timeout: 10000
})
// request拦截器
service.interceptors.request.use(config => {
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
// 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
if (getToken() && !isToken) {
config.headers['X-Access-Token'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?' + tansParams(config.params);
url = url.slice(0, -1);
config.params = {};
config.url = url;
}
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
const requestObj = {
url: config.url,
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime()
}
const sessionObj = cache.session.getJSON('sessionObj')
if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
cache.session.setJSON('sessionObj', requestObj)
} else {
const s_url = sessionObj.url; // 请求地址
const s_data = sessionObj.data; // 请求数据
const s_time = sessionObj.time; // 请求时间
const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交';
console.warn(`[${s_url}]: ` + message)
return Promise.reject(new Error(message))
} else {
cache.session.setJSON('sessionObj', requestObj)
}
}
}
return config
}, error => {
console.log(error)
Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use(res => {
// 未设置状态码则默认成功状态
const code = res.data.code || 200;
// 获取错误信息
const msg = errorCode[code] || res.data.msg || res.data.message || errorCode['default']
// 二进制数据则直接返回
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
return res
}
if (code === 401) {
if (!isRelogin.show) {
isRelogin.show = true;
MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
isRelogin.show = false;
store.dispatch('LogOut').then(() => {
location.href = '/index';
})
}).catch(() => {
isRelogin.show = false;
});
}
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
Message({ message: msg, type: 'error' })
return Promise.reject(new Error(msg))
} else if (code === 601) {
Message({ message: msg, type: 'warning' })
return Promise.reject('error')
} else if (code !== 200) {
Notification.error({ title: msg })
return Promise.reject('error')
} else {
return res.data
}
},
error => {
console.log('err' + error)
let { message } = error;
if (message == "Network Error") {
message = "后端接口连接异常";
} else if (message.includes("timeout")) {
message = "系统接口请求超时";
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常";
}
Message({ message: message, type: 'error', duration: 5 * 1000 })
return Promise.reject(error)
}
)
export default service
在jeecg文件夹下,新增report.js文件,并且在此文件中添加以下代码
import request from "@/api/jeecg/request";
let jmreportUrl = "/jmreport";
import { getToken } from "@/utils/auth";
let paramObj = {
token: "Bearer " + getToken()
}
// 获取填报报表
export function listReport(queryParams) {
let params = {
...paramObj,
...queryParams
}
return request({
url: jmreportUrl + "/excelQuery",
method: 'get',
params: params
})
}
// 获取填报报表列表
export function listFillReport(queryParams) {
paramObj["reportType"] = "1011126161407836160";
let params = {
...paramObj,
...queryParams
}
return request({
url: jmreportUrl + "/excelQuery",
method: 'get',
params: params
})
}
在src/view文件夹下新增jeecg文件夹,在jeecg文件夹下新增report文件夹,在report文件夹下新增index.vue文件,并且在此文件中添加以下代码
<template>
<div>
<i-frame :src="reportUrl"></i-frame>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
import iFrame from "@/components/iFrame/index";
export default {
name: "PyJeecgReport",
components: { iFrame },
data() {
return {
reportUrl: process.env.VUE_APP_BASE_API + "/jmreport/list?token=Bearer " + getToken()
}
}
}
</script>
在report文件夹下新增view文件夹,在view文件夹下新增index.vue文件,并且在此文件中添加以下代码。
<template>
<div>
<i-frame :src="reportUrl"></i-frame>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
import iFrame from "@/components/iFrame/index";
export default {
name: "PyJeecgReportView",
components: { iFrame },
data() {
return {
reportUrl: ""
}
},
created() {
let query = this.$route.query;
let code = undefined;
let paramsString = "";
if (query) {
for (const key in query) {
if (Object.hasOwnProperty.call(query, key)) {
const param = query[key];
if (key == "code") {
code = param;
} else {
if (paramsString != "") {
paramsString += paramsString + "&" + key + "=" + param;
} else {
paramsString = "&" + key + "=" + param;
}
}
}
}
}
if (code) {
this.reportUrl = process.env.VUE_APP_BASE_API + "/jmreport/view/" + code + "?token=Bearer " + getToken() + paramsString;
} else {
this.$modal.msgError("报表编码(code)为空,无法打开报表");
}
}
}
</script>
在jeecg文件夹下新增drag文件夹,在drag文件夹下新增index.vue文件,并且在此文件中添加以下代码
<template>
<div>
<i-frame :src="dragUrl"></i-frame>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
import iFrame from "@/components/iFrame/index";
export default {
name: "PyJeecgDrag",
components: { iFrame },
data() {
return {
dragUrl: process.env.VUE_APP_BASE_API + "/drag/list?token=Bearer " + getToken()
}
}
}
</script>
在drag文件夹下新增view文件夹,在view文件夹下新增index.vue文件,并且在此文件中添加以下代码。
<template>
<div>
<i-frame :src="dragUrl"></i-frame>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
import iFrame from "@/components/iFrame/index";
export default {
name: "PyJeecgDragView",
components: { iFrame },
data() {
return {
dragUrl: ""
}
},
created() {
let query = this.$route.query;
let code = undefined;
let paramsString = "";
if (query) {
for (const key in query) {
if (Object.hasOwnProperty.call(query, key)) {
const param = query[key];
if (key == "code") {
code = param;
} else {
if (paramsString != "") {
paramsString += paramsString + "&" + key + "=" + param;
} else {
paramsString = "&" + key + "=" + param;
}
}
}
}
}
if (code) {
this.dragUrl = process.env.VUE_APP_BASE_API + "/drag/share/view/" + code + "?token=Bearer " + getToken() + paramsString;
} else {
this.$modal.msgError("大屏编码(code)为空,无法打开大屏");
}
}
}
</script>
执行创建菜单的SQL
-- 主目录
INSERT INTO `lucas`.`sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `route_name`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1083, '报表管理', 0, 7, 'jeecg', NULL, NULL, '', 1, 0, 'M', '0', '0', NULL, 'chart', 'admin', '2025-03-27 01:49:40', '', NULL, '');
-- 基础报表菜单
INSERT INTO `lucas`.`sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `route_name`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1084, '报表管理', 1083, 0, 'report', 'jeecg/report/index', NULL, '', 1, 0, 'C', '0', '0', 'jeecg:report:edit', 'druid', 'admin', '2025-03-27 01:51:44', 'admin', '2025-03-27 05:12:06', '');
-- 大屏报表菜单
INSERT INTO `lucas`.`sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `route_name`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1085, '大屏管理', 1083, 1, 'drag', 'jeecg/drag/index', NULL, '', 1, 0, 'C', '0', '0', 'jeecg:drag:edit', 'druid', 'admin', '2025-03-27 01:53:17', 'admin', '2025-03-27 05:12:13', '');
-- 基础报表查看菜单
INSERT INTO `lucas`.`sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `route_name`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1086, '报表查看', 1083, 2, 'report/view', 'jeecg/report/view/index', NULL, '', 1, 0, 'C', '1', '0', 'jeecg:report:query', 'eye-open', 'admin', '2025-03-27 01:54:41', 'admin', '2025-03-27 05:12:19', '');
-- 大屏报表查看菜单
INSERT INTO `lucas`.`sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `route_name`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1087, '大屏查看', 1083, 3, 'drag/view', 'jeecg/drag/view/index', NULL, '', 1, 0, 'C', '1', '0', 'jeecg:drag:query', 'eye-open', 'admin', '2025-03-27 01:55:46', 'admin', '2025-03-27 05:12:24', '');
修改Nginx配置
部署到服务器发现大屏报表一直加载不出来,本地打开没问题,就像这种:
然后看了下请求,发现大屏的几个接口没加对应的prod-api的前缀,怀疑接口其实是没获取到数据的。
所以就想了想nginx要加大屏报表对应的配置,于是修改nginx配置文件:在nginx.conf加上下面这些配置(proxy_pass那里换成对应的后端接口地址)
location /drag/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:8080/drag/;
proxy_http_version 1.1;
proxy_set_header Upgrade websocket;
proxy_set_header Connection Upgrade;
}
完成之后重启nginx服务:
systemctl restart nginx.service
用户点评