Merge remote-tracking branch 'upstream/master' into dev_lcw

# Conflicts:
#	ruoyi-ui/src/views/index.vue
pull/445/head
hsdllcw 2025-02-11 10:28:39 +08:00
commit 343e5496e3
20 changed files with 424 additions and 284 deletions

View File

@ -78,6 +78,11 @@ public @interface Excel
*/ */
public String prompt() default ""; public String prompt() default "";
/**
*
*/
public boolean wrapText() default false;
/** /**
* . * .
*/ */

View File

@ -225,8 +225,6 @@ public class ExcelUtil<T>
{ {
if (StringUtils.isNotEmpty(title)) if (StringUtils.isNotEmpty(title))
{ {
subMergedFirstRowNum++;
subMergedLastRowNum++;
int titleLastCol = this.fields.size() - 1; int titleLastCol = this.fields.size() - 1;
if (isSubList()) if (isSubList())
{ {
@ -237,7 +235,7 @@ public class ExcelUtil<T>
Cell titleCell = titleRow.createCell(0); Cell titleCell = titleRow.createCell(0);
titleCell.setCellStyle(styles.get("title")); titleCell.setCellStyle(styles.get("title"));
titleCell.setCellValue(title); titleCell.setCellValue(title);
sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol)); sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, titleLastCol));
} }
} }
@ -248,23 +246,31 @@ public class ExcelUtil<T>
{ {
if (isSubList()) if (isSubList())
{ {
subMergedFirstRowNum++;
subMergedLastRowNum++;
Row subRow = sheet.createRow(rownum); Row subRow = sheet.createRow(rownum);
int excelNum = 0; int column = 0;
int subFieldSize = subFields != null ? subFields.size() : 0;
for (Object[] objects : fields) for (Object[] objects : fields)
{ {
Field field = (Field) objects[0];
Excel attr = (Excel) objects[1]; Excel attr = (Excel) objects[1];
Cell headCell1 = subRow.createCell(excelNum); if (Collection.class.isAssignableFrom(field.getType()))
headCell1.setCellValue(attr.name()); {
headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); Cell cell = subRow.createCell(column);
excelNum++; cell.setCellValue(attr.name());
} cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
int headFirstRow = excelNum - 1; if (subFieldSize > 1)
int headLastRow = headFirstRow + subFields.size() - 1; {
if (headLastRow > headFirstRow) CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1);
{ sheet.addMergedRegion(cellAddress);
sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow)); }
column += subFieldSize;
}
else
{
Cell cell = subRow.createCell(column++);
cell.setCellValue(attr.name());
cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
}
} }
rownum++; rownum++;
} }
@ -277,11 +283,23 @@ public class ExcelUtil<T>
* @return * @return
*/ */
public List<T> importExcel(InputStream is) public List<T> importExcel(InputStream is)
{
return importExcel(is, 0);
}
/**
* excellist
*
* @param is
* @param titleNum
* @return
*/
public List<T> importExcel(InputStream is, int titleNum)
{ {
List<T> list = null; List<T> list = null;
try try
{ {
list = importExcel(is, 0); list = importExcel(StringUtils.EMPTY, is, titleNum);
} }
catch (Exception e) catch (Exception e)
{ {
@ -295,18 +313,6 @@ public class ExcelUtil<T>
return list; return list;
} }
/**
* excellist
*
* @param is
* @param titleNum
* @return
*/
public List<T> importExcel(InputStream is, int titleNum) throws Exception
{
return importExcel(StringUtils.EMPTY, is, titleNum);
}
/** /**
* excellist * excellist
* *
@ -589,64 +595,91 @@ public class ExcelUtil<T>
{ {
int startNo = index * sheetSize; int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size()); int endNo = Math.min(startNo + sheetSize, list.size());
int rowNo = (1 + rownum) - startNo; int currentRowNum = rownum + 1; // 从标题行后开始
for (int i = startNo; i < endNo; i++) for (int i = startNo; i < endNo; i++)
{ {
rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo; row = sheet.createRow(currentRowNum);
row = sheet.createRow(rowNo);
// 得到导出对象.
T vo = (T) list.get(i); T vo = (T) list.get(i);
Collection<?> subList = null;
if (isSubList())
{
if (isSubListValue(vo))
{
subList = getListCellValue(vo);
subMergedLastRowNum = subMergedLastRowNum + subList.size();
}
else
{
subMergedFirstRowNum++;
subMergedLastRowNum++;
}
}
int column = 0; int column = 0;
int maxSubListSize = getCurrentMaxSubListSize(vo);
for (Object[] os : fields) for (Object[] os : fields)
{ {
Field field = (Field) os[0]; Field field = (Field) os[0];
Excel excel = (Excel) os[1]; Excel excel = (Excel) os[1];
if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList)) if (Collection.class.isAssignableFrom(field.getType()))
{ {
boolean subFirst = false; try
for (Object obj : subList)
{ {
if (subFirst) Collection<?> subList = (Collection<?>) getTargetValue(vo, field, excel);
if (subList != null && !subList.isEmpty())
{ {
rowNo++; int subIndex = 0;
row = sheet.createRow(rowNo); for (Object subVo : subList)
}
List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class);
int subIndex = 0;
for (Field subField : subFields)
{
if (subField.isAnnotationPresent(Excel.class))
{ {
subField.setAccessible(true); Row subRow = sheet.getRow(currentRowNum + subIndex);
Excel attr = subField.getAnnotation(Excel.class); if (subRow == null)
this.addCell(attr, row, (T) obj, subField, column + subIndex); {
subRow = sheet.createRow(currentRowNum + subIndex);
}
int subColumn = column;
for (Field subField : subFields)
{
Excel subExcel = subField.getAnnotation(Excel.class);
addCell(subExcel, subRow, (T) subVo, subField, subColumn++);
}
subIndex++;
} }
subIndex++; column += subFields.size();
} }
subFirst = true;
} }
this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size(); catch (Exception e)
{
log.error("填充集合数据失败", e);
}
} }
else else
{ {
this.addCell(excel, row, vo, field, column++); // 创建单元格并设置值
addCell(excel, row, vo, field, column);
if (maxSubListSize > 1 && excel.needMerge())
{
sheet.addMergedRegion(new CellRangeAddress(currentRowNum, currentRowNum + maxSubListSize - 1, column, column));
}
column++;
}
}
currentRowNum += maxSubListSize;
}
}
/**
*
*/
private int getCurrentMaxSubListSize(T vo)
{
int maxSubListSize = 1;
for (Object[] os : fields)
{
Field field = (Field) os[0];
if (Collection.class.isAssignableFrom(field.getType()))
{
try
{
Collection<?> subList = (Collection<?>) getTargetValue(vo, field, (Excel) os[1]);
if (subList != null && !subList.isEmpty())
{
maxSubListSize = Math.max(maxSubListSize, subList.size());
}
}
catch (Exception e)
{
log.error("获取集合大小失败", e);
} }
} }
} }
return maxSubListSize;
} }
/** /**
@ -781,7 +814,7 @@ public class ExcelUtil<T>
*/ */
public void annotationDataStyles(Map<String, CellStyle> styles, Field field, Excel excel) public void annotationDataStyles(Map<String, CellStyle> styles, Field field, Excel excel)
{ {
String key = StringUtils.format("data_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType()); String key = StringUtils.format("data_{}_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType(), excel.wrapText());
if (!styles.containsKey(key)) if (!styles.containsKey(key))
{ {
CellStyle style = wb.createCellStyle(); CellStyle style = wb.createCellStyle();
@ -797,6 +830,7 @@ public class ExcelUtil<T>
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND); style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setFillForegroundColor(excel.backgroundColor().getIndex()); style.setFillForegroundColor(excel.backgroundColor().getIndex());
style.setWrapText(excel.wrapText());
Font dataFont = wb.createFont(); Font dataFont = wb.createFont();
dataFont.setFontName("Arial"); dataFont.setFontName("Arial");
dataFont.setFontHeightInPoints((short) 10); dataFont.setFontHeightInPoints((short) 10);
@ -825,7 +859,7 @@ public class ExcelUtil<T>
if (isSubList()) if (isSubList())
{ {
// 填充默认样式,防止合并单元格样式失效 // 填充默认样式,防止合并单元格样式失效
sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType()))); sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
if (attr.needMerge()) if (attr.needMerge())
{ {
sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column)); sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column));
@ -952,10 +986,12 @@ public class ExcelUtil<T>
cell = row.createCell(column); cell = row.createCell(column);
if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge()) if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
{ {
CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column); if (subMergedLastRowNum >= subMergedFirstRowNum)
sheet.addMergedRegion(cellAddress); {
sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column));
}
} }
cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType()))); cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
// 用于读取对象中的属性 // 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr); Object value = getTargetValue(vo, field, attr);
@ -1235,6 +1271,7 @@ public class ExcelUtil<T>
*/ */
private Object getTargetValue(T vo, Field field, Excel excel) throws Exception private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
{ {
field.setAccessible(true);
Object o = field.get(vo); Object o = field.get(vo);
if (StringUtils.isNotEmpty(excel.targetAttr())) if (StringUtils.isNotEmpty(excel.targetAttr()))
{ {
@ -1335,7 +1372,6 @@ public class ExcelUtil<T>
Excel attr = field.getAnnotation(Excel.class); Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{ {
field.setAccessible(true);
fields.add(new Object[] { field, attr }); fields.add(new Object[] { field, attr });
} }
if (Collection.class.isAssignableFrom(field.getType())) if (Collection.class.isAssignableFrom(field.getType()))
@ -1359,7 +1395,6 @@ public class ExcelUtil<T>
if (ArrayUtils.contains(this.includeFields, field.getName() + "." + attr.targetAttr()) if (ArrayUtils.contains(this.includeFields, field.getName() + "." + attr.targetAttr())
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type))) && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
{ {
field.setAccessible(true);
fields.add(new Object[] { field, attr }); fields.add(new Object[] { field, attr });
} }
} }
@ -1368,7 +1403,6 @@ public class ExcelUtil<T>
if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr()) if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type))) && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
{ {
field.setAccessible(true);
fields.add(new Object[] { field, attr }); fields.add(new Object[] { field, attr });
} }
} }

View File

@ -13,7 +13,7 @@ public class SqlUtil
/** /**
* sql * sql
*/ */
public static String SQL_REGEX = "and |extractvalue|updatexml|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |+|user()"; public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
/** /**
* 线 * 线

View File

@ -37,10 +37,20 @@ public class FastDfsSysFileServiceImpl implements ISysFileService
@Override @Override
public String uploadFile(MultipartFile file) throws Exception public String uploadFile(MultipartFile file) throws Exception
{ {
InputStream inputStream = file.getInputStream(); InputStream inputStream = null;
StorePath storePath = storageClient.uploadFile(inputStream, file.getSize(), try
FileTypeUtils.getExtension(file), null); {
IoUtils.closeQuietly(inputStream); inputStream = file.getInputStream();
return domain + "/" + storePath.getFullPath(); StorePath storePath = storageClient.uploadFile(inputStream, file.getSize(), FileTypeUtils.getExtension(file), null);
return domain + "/" + storePath.getFullPath();
}
catch (Exception e)
{
throw new RuntimeException("FastDfs Failed to upload file", e);
}
finally
{
IoUtils.closeQuietly(inputStream);
}
} }
} }

View File

@ -34,16 +34,27 @@ public class MinioSysFileServiceImpl implements ISysFileService
@Override @Override
public String uploadFile(MultipartFile file) throws Exception public String uploadFile(MultipartFile file) throws Exception
{ {
String fileName = FileUploadUtils.extractFilename(file); InputStream inputStream = null;
InputStream inputStream = file.getInputStream(); try
PutObjectArgs args = PutObjectArgs.builder() {
.bucket(minioConfig.getBucketName()) String fileName = FileUploadUtils.extractFilename(file);
.object(fileName) inputStream = file.getInputStream();
.stream(inputStream, file.getSize(), -1) PutObjectArgs args = PutObjectArgs.builder()
.contentType(file.getContentType()) .bucket(minioConfig.getBucketName())
.build(); .object(fileName)
client.putObject(args); .stream(inputStream, file.getSize(), -1)
IoUtils.closeQuietly(inputStream); .contentType(file.getContentType())
return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName; .build();
client.putObject(args);
return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
}
catch (Exception e)
{
throw new RuntimeException("Minio Failed to upload file", e);
}
finally
{
IoUtils.closeQuietly(inputStream);
}
} }
} }

View File

@ -18,12 +18,15 @@ public class GenConfig
/** 生成包路径 */ /** 生成包路径 */
public static String packageName; public static String packageName;
/** 自动去除表前缀默认是false */ /** 自动去除表前缀 */
public static boolean autoRemovePre; public static boolean autoRemovePre;
/** 表前缀(类名不会包含表前缀) */ /** 表前缀 */
public static String tablePrefix; public static String tablePrefix;
/** 是否允许生成文件覆盖到本地(自定义路径) */
public static boolean allowOverwrite;
public static String getAuthor() public static String getAuthor()
{ {
return author; return author;
@ -63,4 +66,14 @@ public class GenConfig
{ {
GenConfig.tablePrefix = tablePrefix; GenConfig.tablePrefix = tablePrefix;
} }
public static boolean isAllowOverwrite()
{
return allowOverwrite;
}
public void setAllowOverwrite(boolean allowOverwrite)
{
GenConfig.allowOverwrite = allowOverwrite;
}
} }

View File

@ -23,6 +23,7 @@ import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.gen.config.GenConfig;
import com.ruoyi.gen.domain.GenTable; import com.ruoyi.gen.domain.GenTable;
import com.ruoyi.gen.domain.GenTableColumn; import com.ruoyi.gen.domain.GenTableColumn;
import com.ruoyi.gen.service.IGenTableColumnService; import com.ruoyi.gen.service.IGenTableColumnService;
@ -168,6 +169,10 @@ public class GenController extends BaseController
@GetMapping("/genCode/{tableName}") @GetMapping("/genCode/{tableName}")
public AjaxResult genCode(@PathVariable("tableName") String tableName) public AjaxResult genCode(@PathVariable("tableName") String tableName)
{ {
if (!GenConfig.isAllowOverwrite())
{
return AjaxResult.error("【系统预设】不允许生成文件覆盖到本地");
}
genTableService.generatorCode(tableName); genTableService.generatorCode(tableName);
return success(); return success();
} }

View File

@ -1,6 +1,7 @@
package com.ruoyi.system.controller; package com.ruoyi.system.controller;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -93,11 +94,13 @@ public class SysProfileController extends BaseController
*/ */
@Log(title = "个人信息", businessType = BusinessType.UPDATE) @Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping("/updatePwd") @PutMapping("/updatePwd")
public AjaxResult updatePwd(String oldPassword, String newPassword) public AjaxResult updatePwd(@RequestBody Map<String, String> params)
{ {
String username = SecurityUtils.getUsername(); String oldPassword = params.get("oldPassword");
SysUser user = userService.selectUserByUserName(username); String newPassword = params.get("newPassword");
String password = user.getPassword(); LoginUser loginUser = SecurityUtils.getLoginUser();
String userName = loginUser.getUsername();
String password = loginUser.getSysUser().getPassword();
if (!SecurityUtils.matchesPassword(oldPassword, password)) if (!SecurityUtils.matchesPassword(oldPassword, password))
{ {
return error("修改密码失败,旧密码错误"); return error("修改密码失败,旧密码错误");
@ -107,10 +110,9 @@ public class SysProfileController extends BaseController
return error("新密码不能与旧密码相同"); return error("新密码不能与旧密码相同");
} }
newPassword = SecurityUtils.encryptPassword(newPassword); newPassword = SecurityUtils.encryptPassword(newPassword);
if (userService.resetUserPwd(username, newPassword) > 0) if (userService.resetUserPwd(userName, newPassword) > 0)
{ {
// 更新缓存用户密码 // 更新缓存用户密码
LoginUser loginUser = SecurityUtils.getLoginUser();
loginUser.getSysUser().setPassword(newPassword); loginUser.getSysUser().setPassword(newPassword);
tokenService.setLoginUser(loginUser); tokenService.setLoginUser(loginUser);
return success(); return success();

View File

@ -4,6 +4,8 @@ import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.system.api.domain.SysDept; import com.ruoyi.system.api.domain.SysDept;
import com.ruoyi.system.domain.SysMenu; import com.ruoyi.system.domain.SysMenu;
@ -22,6 +24,9 @@ public class TreeSelect implements Serializable
/** 节点名称 */ /** 节点名称 */
private String label; private String label;
/** 节点禁用 */
private boolean disabled = false;
/** 子节点 */ /** 子节点 */
@JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<TreeSelect> children; private List<TreeSelect> children;
@ -35,6 +40,7 @@ public class TreeSelect implements Serializable
{ {
this.id = dept.getDeptId(); this.id = dept.getDeptId();
this.label = dept.getDeptName(); this.label = dept.getDeptName();
this.disabled = StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus());
this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList()); this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
} }
@ -65,6 +71,16 @@ public class TreeSelect implements Serializable
this.label = label; this.label = label;
} }
public boolean isDisabled()
{
return disabled;
}
public void setDisabled(boolean disabled)
{
this.disabled = disabled;
}
public List<TreeSelect> getChildren() public List<TreeSelect> getChildren()
{ {
return children; return children;

File diff suppressed because one or more lines are too long

View File

@ -96,7 +96,7 @@ export function updateUserPwd(oldPassword, newPassword) {
return request({ return request({
url: '/system/user/profile/updatePwd', url: '/system/user/profile/updatePwd',
method: 'put', method: 'put',
params: data data: data
}) })
} }

View File

@ -8,7 +8,6 @@
</template> </template>
<script> <script>
const version = require('element-ui/package.json').version // element-ui version from node_modules
const ORIGINAL_THEME = '#409EFF' // default color const ORIGINAL_THEME = '#409EFF' // default color
export default { export default {
@ -39,7 +38,6 @@ export default {
this.setTheme(this.defaultTheme) this.setTheme(this.defaultTheme)
} }
}, },
methods: { methods: {
async setTheme(val) { async setTheme(val) {
const oldVal = this.chalk ? this.theme : ORIGINAL_THEME const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
@ -63,12 +61,11 @@ export default {
} }
if (!this.chalk) { if (!this.chalk) {
const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css` const url = `/styles/theme-chalk/index.css`
await this.getCSSString(url, 'chalk') await this.getCSSString(url, 'chalk')
} }
const chalkHandler = getHandler('chalk', 'chalk-style') const chalkHandler = getHandler('chalk', 'chalk-style')
chalkHandler() chalkHandler()
const styles = [].slice.call(document.querySelectorAll('style')) const styles = [].slice.call(document.querySelectorAll('style'))

View File

@ -96,8 +96,8 @@ export default {
let activePath = path; let activePath = path;
if (path !== undefined && path.lastIndexOf("/") > 0 && hideList.indexOf(path) === -1) { if (path !== undefined && path.lastIndexOf("/") > 0 && hideList.indexOf(path) === -1) {
const tmpPath = path.substring(1, path.length); const tmpPath = path.substring(1, path.length);
activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
if (!this.$route.meta.link) { if (!this.$route.meta.link) {
activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
this.$store.dispatch('app/toggleSideBarHide', false); this.$store.dispatch('app/toggleSideBarHide', false);
} }
} else if(!this.$route.children) { } else if(!this.$route.children) {

View File

@ -4,12 +4,17 @@ import { Message } from 'element-ui'
import NProgress from 'nprogress' import NProgress from 'nprogress'
import 'nprogress/nprogress.css' import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { isPathMatch } from '@/utils/validate'
import { isRelogin } from '@/utils/request' import { isRelogin } from '@/utils/request'
NProgress.configure({ showSpinner: false }) NProgress.configure({ showSpinner: false })
const whiteList = ['/login', '/register'] const whiteList = ['/login', '/register']
const isWhiteList = (path) => {
return whiteList.some(pattern => isPathMatch(pattern, path))
}
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
NProgress.start() NProgress.start()
if (getToken()) { if (getToken()) {
@ -18,7 +23,7 @@ router.beforeEach((to, from, next) => {
if (to.path === '/login') { if (to.path === '/login') {
next({ path: '/' }) next({ path: '/' })
NProgress.done() NProgress.done()
} else if (whiteList.indexOf(to.path) !== -1) { } else if (isWhiteList(to.path)) {
next() next()
} else { } else {
if (store.getters.roles.length === 0) { if (store.getters.roles.length === 0) {
@ -43,7 +48,7 @@ router.beforeEach((to, from, next) => {
} }
} else { } else {
// 没有token // 没有token
if (whiteList.indexOf(to.path) !== -1) { if (isWhiteList(to.path)) {
// 在免登录白名单,直接进入 // 在免登录白名单,直接进入
next() next()
} else { } else {

View File

@ -1,3 +1,15 @@
/**
* 路径匹配器
* @param {string} pattern
* @param {string} path
* @returns {Boolean}
*/
export function isPathMatch(pattern, path) {
const regexPattern = pattern.replace(/\//g, '\\/').replace(/\*\*/g, '.*').replace(/\*/g, '[^\\/]*')
const regex = new RegExp(`^${regexPattern}$`)
return regex.test(path)
}
/** /**
* 判断value字符串是否为空 * 判断value字符串是否为空
* @param {string} value * @param {string} value
@ -5,9 +17,9 @@
*/ */
export function isEmpty(value) { export function isEmpty(value) {
if (value == null || value == "" || value == undefined || value == "undefined") { if (value == null || value == "" || value == undefined || value == "undefined") {
return true; return true
} }
return false; return false
} }
/** /**
@ -87,7 +99,7 @@ export function validEmail(email) {
* @returns {Boolean} * @returns {Boolean}
*/ */
export function isString(str) { export function isString(str) {
return typeof str === 'string' || str instanceof String; return typeof str === 'string' || str instanceof String
} }
/** /**

View File

@ -56,7 +56,7 @@
</el-form> </el-form>
<!-- 底部 --> <!-- 底部 -->
<div class="el-login-footer"> <div class="el-login-footer">
<span>Copyright © 2018-2024 ruoyi.vip All Rights Reserved.</span> <span>Copyright © 2018-2025 ruoyi.vip All Rights Reserved.</span>
</div> </div>
</div> </div>
</template> </template>

View File

@ -61,7 +61,7 @@
</el-form> </el-form>
<!-- 底部 --> <!-- 底部 -->
<div class="el-register-footer"> <div class="el-register-footer">
<span>Copyright © 2018-2024 ruoyi.vip All Rights Reserved.</span> <span>Copyright © 2018-2025 ruoyi.vip All Rights Reserved.</span>
</div> </div>
</div> </div>
</template> </template>

View File

@ -117,6 +117,8 @@
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="菜单类型" prop="menuType"> <el-form-item label="菜单类型" prop="menuType">
<el-radio-group v-model="form.menuType"> <el-radio-group v-model="form.menuType">
@ -126,6 +128,8 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row>
<el-col :span="24" v-if="form.menuType != 'F'"> <el-col :span="24" v-if="form.menuType != 'F'">
<el-form-item label="菜单图标" prop="icon"> <el-form-item label="菜单图标" prop="icon">
<el-popover <el-popover
@ -147,6 +151,8 @@
</el-popover> </el-popover>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="菜单名称" prop="menuName"> <el-form-item label="菜单名称" prop="menuName">
<el-input v-model="form.menuName" placeholder="请输入菜单名称" /> <el-input v-model="form.menuName" placeholder="请输入菜单名称" />
@ -157,6 +163,8 @@
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" /> <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row>
<el-col :span="12" v-if="form.menuType != 'F'"> <el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item prop="isFrame"> <el-form-item prop="isFrame">
<span slot="label"> <span slot="label">
@ -182,6 +190,8 @@
<el-input v-model="form.path" placeholder="请输入路由地址" /> <el-input v-model="form.path" placeholder="请输入路由地址" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row>
<el-col :span="12" v-if="form.menuType == 'C'"> <el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item prop="component"> <el-form-item prop="component">
<span slot="label"> <span slot="label">
@ -204,6 +214,8 @@
</span> </span>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row>
<el-col :span="12" v-if="form.menuType == 'C'"> <el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item prop="query"> <el-form-item prop="query">
<el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" /> <el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
@ -229,6 +241,8 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row>
<el-col :span="12" v-if="form.menuType != 'F'"> <el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item prop="visible"> <el-form-item prop="visible">
<span slot="label"> <span slot="label">

View File

@ -105,7 +105,7 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="归属部门" prop="deptId"> <el-form-item label="归属部门" prop="deptId">
<treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" placeholder="请选择归属部门" /> <treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true" placeholder="请选择归属部门" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -230,8 +230,10 @@ export default {
userList: null, userList: null,
// //
title: "", title: "",
// //
deptOptions: undefined, deptOptions: undefined,
//
enabledDeptOptions: undefined,
// //
open: false, open: false,
// //
@ -343,6 +345,19 @@ export default {
getDeptTree() { getDeptTree() {
deptTreeSelect().then(response => { deptTreeSelect().then(response => {
this.deptOptions = response.data; this.deptOptions = response.data;
this.enabledDeptOptions = this.filterDisabledDept(JSON.parse(JSON.stringify(response.data)));
});
},
//
filterDisabledDept(deptList) {
return deptList.filter(dept => {
if (dept.disabled) {
return false;
}
if (dept.children && dept.children.length) {
dept.children = this.filterDisabledDept(dept.children);
}
return true;
}); });
}, },
// //

View File

@ -38,7 +38,7 @@ insert into config_info(id, data_id, group_id, content, md5, gmt_create, gmt_mod
(3,'ruoyi-auth-dev.yml','DEFAULT_GROUP','spring:\n redis:\n host: localhost\n port: 6379\n password: \n','a03e7632a0a74520eeb4fbedd6d82d97','2020-11-20 00:00:00','2024-09-02 12:13:58','nacos','0:0:0:0:0:0:0:1','','','认证中心','null','null','yaml','',''), (3,'ruoyi-auth-dev.yml','DEFAULT_GROUP','spring:\n redis:\n host: localhost\n port: 6379\n password: \n','a03e7632a0a74520eeb4fbedd6d82d97','2020-11-20 00:00:00','2024-09-02 12:13:58','nacos','0:0:0:0:0:0:0:1','','','认证中心','null','null','yaml','',''),
(4,'ruoyi-monitor-dev.yml','DEFAULT_GROUP','# spring\nspring:\n security:\n user:\n name: ruoyi\n password: 123456\n boot:\n admin:\n ui:\n title: 若依服务状态监控\n','6f122fd2bfb8d45f858e7d6529a9cd44','2020-11-20 00:00:00','2024-08-29 12:15:11','nacos','0:0:0:0:0:0:0:1','','','监控中心','null','null','yaml','',''), (4,'ruoyi-monitor-dev.yml','DEFAULT_GROUP','# spring\nspring:\n security:\n user:\n name: ruoyi\n password: 123456\n boot:\n admin:\n ui:\n title: 若依服务状态监控\n','6f122fd2bfb8d45f858e7d6529a9cd44','2020-11-20 00:00:00','2024-08-29 12:15:11','nacos','0:0:0:0:0:0:0:1','','','监控中心','null','null','yaml','',''),
(5,'ruoyi-system-dev.yml','DEFAULT_GROUP','# spring配置\nspring:\n redis:\n host: localhost\n port: 6379\n password: \n datasource:\n druid:\n stat-view-servlet:\n enabled: true\n loginUsername: ruoyi\n loginPassword: 123456\n dynamic:\n druid:\n initial-size: 5\n min-idle: 5\n maxActive: 20\n maxWait: 60000\n connectTimeout: 30000\n socketTimeout: 60000\n timeBetweenEvictionRunsMillis: 60000\n minEvictableIdleTimeMillis: 300000\n validationQuery: SELECT 1 FROM DUAL\n testWhileIdle: true\n testOnBorrow: false\n testOnReturn: false\n poolPreparedStatements: true\n maxPoolPreparedStatementPerConnectionSize: 20\n filters: stat,slf4j\n connectionProperties: druid.stat.mergeSql\\=true;druid.stat.slowSqlMillis\\=5000\n datasource:\n # 主库数据源\n master:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\n username: root\n password: password\n # 从库数据源\n # slave:\n # username: \n # password: \n # url: \n # driver-class-name: \n\n# mybatis配置\nmybatis:\n # 搜索指定包别名\n typeAliasesPackage: com.ruoyi.system\n # 配置mapper的扫描找到所有的mapper.xml映射文件\n mapperLocations: classpath:mapper/**/*.xml\n\n# springdoc配置\nspringdoc:\n gatewayUrl: http://localhost:8080/${spring.application.name}\n api-docs:\n # 是否开启接口文档\n enabled: true\n info:\n # 标题\n title: \'\'\n # 描述\n description: \'\'\n # 作者信息\n contact:\n name: RuoYi\n url: https://ruoyi.vip\n','786c7daf4543411fc65c3e48dfb15243','2020-11-20 00:00:00','2024-09-02 12:14:33','nacos','0:0:0:0:0:0:0:1','','','系统模块','null','null','yaml','',''), (5,'ruoyi-system-dev.yml','DEFAULT_GROUP','# spring配置\nspring:\n redis:\n host: localhost\n port: 6379\n password: \n datasource:\n druid:\n stat-view-servlet:\n enabled: true\n loginUsername: ruoyi\n loginPassword: 123456\n dynamic:\n druid:\n initial-size: 5\n min-idle: 5\n maxActive: 20\n maxWait: 60000\n connectTimeout: 30000\n socketTimeout: 60000\n timeBetweenEvictionRunsMillis: 60000\n minEvictableIdleTimeMillis: 300000\n validationQuery: SELECT 1 FROM DUAL\n testWhileIdle: true\n testOnBorrow: false\n testOnReturn: false\n poolPreparedStatements: true\n maxPoolPreparedStatementPerConnectionSize: 20\n filters: stat,slf4j\n connectionProperties: druid.stat.mergeSql\\=true;druid.stat.slowSqlMillis\\=5000\n datasource:\n # 主库数据源\n master:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\n username: root\n password: password\n # 从库数据源\n # slave:\n # username: \n # password: \n # url: \n # driver-class-name: \n\n# mybatis配置\nmybatis:\n # 搜索指定包别名\n typeAliasesPackage: com.ruoyi.system\n # 配置mapper的扫描找到所有的mapper.xml映射文件\n mapperLocations: classpath:mapper/**/*.xml\n\n# springdoc配置\nspringdoc:\n gatewayUrl: http://localhost:8080/${spring.application.name}\n api-docs:\n # 是否开启接口文档\n enabled: true\n info:\n # 标题\n title: \'\'\n # 描述\n description: \'\'\n # 作者信息\n contact:\n name: RuoYi\n url: https://ruoyi.vip\n','786c7daf4543411fc65c3e48dfb15243','2020-11-20 00:00:00','2024-09-02 12:14:33','nacos','0:0:0:0:0:0:0:1','','','系统模块','null','null','yaml','',''),
(6,'ruoyi-gen-dev.yml','DEFAULT_GROUP','# spring配置\nspring:\n redis:\n host: localhost\n port: 6379\n password: \n datasource:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\n username: root\n password: password\n\n# mybatis配置\nmybatis:\n # 搜索指定包别名\n typeAliasesPackage: com.ruoyi.gen.domain\n # 配置mapper的扫描找到所有的mapper.xml映射文件\n mapperLocations: classpath:mapper/**/*.xml\n\n# springdoc配置\nspringdoc:\n gatewayUrl: http://localhost:8080/${spring.application.name}\n api-docs:\n # 是否开启接口文档\n enabled: true\n info:\n # 标题\n title: \'\'\n # 描述\n description: \'\'\n # 作者信息\n contact:\n name: RuoYi\n url: https://ruoyi.vip\n\n# 代码生成\ngen:\n # 作者\n author: ruoyi\n # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool\n packageName: com.ruoyi.system\n # 自动去除表前缀默认是false\n autoRemovePre: false\n # 表前缀(生成类名不会包含表前缀,多个用逗号分隔)\n tablePrefix: sys_\n','14d41dda290bf445b7ed06c5667e8e88','2020-11-20 00:00:00','2024-09-02 12:14:48','nacos','0:0:0:0:0:0:0:1','','','代码生成','null','null','yaml','',''), (6,'ruoyi-gen-dev.yml','DEFAULT_GROUP','# spring配置\nspring:\n redis:\n host: localhost\n port: 6379\n password: \n datasource:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\n username: root\n password: password\n\n# mybatis配置\nmybatis:\n # 搜索指定包别名\n typeAliasesPackage: com.ruoyi.gen.domain\n # 配置mapper的扫描找到所有的mapper.xml映射文件\n mapperLocations: classpath:mapper/**/*.xml\n\n# springdoc配置\nspringdoc:\n gatewayUrl: http://localhost:8080/${spring.application.name}\n api-docs:\n # 是否开启接口文档\n enabled: true\n info:\n # 标题\n title: \'\'\n # 描述\n description: \'\'\n # 作者信息\n contact:\n name: RuoYi\n url: https://ruoyi.vip\n\n# 代码生成\ngen:\n # 作者\n author: ruoyi\n # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool\n packageName: com.ruoyi.system\n # 自动去除表前缀默认是false\n autoRemovePre: false\n # 表前缀(生成类名不会包含表前缀,多个用逗号分隔)\n tablePrefix: sys_\n # 是否允许生成文件覆盖到本地(自定义路径),默认不允许\n allowOverwrite: false','43d807aa0a4accbb193b6dc7e38ac8a3','2020-11-20 00:00:00','2024-12-25 08:29:33','nacos','0:0:0:0:0:0:0:1','','','代码生成','null','null','yaml','',''),
(7,'ruoyi-job-dev.yml','DEFAULT_GROUP','# spring配置\nspring:\n redis:\n host: localhost\n port: 6379\n password: \n datasource:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\n username: root\n password: password\n\n# mybatis配置\nmybatis:\n # 搜索指定包别名\n typeAliasesPackage: com.ruoyi.job.domain\n # 配置mapper的扫描找到所有的mapper.xml映射文件\n mapperLocations: classpath:mapper/**/*.xml\n\n# springdoc配置\nspringdoc:\n gatewayUrl: http://localhost:8080/${spring.application.name}\n api-docs:\n # 是否开启接口文档\n enabled: true\n info:\n # 标题\n title: \'\'\n # 描述\n description: \'\'\n # 作者信息\n contact:\n name: RuoYi\n url: https://ruoyi.vip\n','f78483f845777335b9ed4a9f84758848','2020-11-20 00:00:00','2024-09-02 12:14:56','nacos','0:0:0:0:0:0:0:1','','','定时任务','null','null','yaml','',''), (7,'ruoyi-job-dev.yml','DEFAULT_GROUP','# spring配置\nspring:\n redis:\n host: localhost\n port: 6379\n password: \n datasource:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\n username: root\n password: password\n\n# mybatis配置\nmybatis:\n # 搜索指定包别名\n typeAliasesPackage: com.ruoyi.job.domain\n # 配置mapper的扫描找到所有的mapper.xml映射文件\n mapperLocations: classpath:mapper/**/*.xml\n\n# springdoc配置\nspringdoc:\n gatewayUrl: http://localhost:8080/${spring.application.name}\n api-docs:\n # 是否开启接口文档\n enabled: true\n info:\n # 标题\n title: \'\'\n # 描述\n description: \'\'\n # 作者信息\n contact:\n name: RuoYi\n url: https://ruoyi.vip\n','f78483f845777335b9ed4a9f84758848','2020-11-20 00:00:00','2024-09-02 12:14:56','nacos','0:0:0:0:0:0:0:1','','','定时任务','null','null','yaml','',''),
(8,'ruoyi-file-dev.yml','DEFAULT_GROUP','# 本地文件上传 \r\nfile:\r\n domain: http://127.0.0.1:9300\r\n path: D:/ruoyi/uploadPath\r\n prefix: /statics\r\n\r\n# FastDFS配置\r\nfdfs:\r\n domain: http://8.129.231.12\r\n soTimeout: 3000\r\n connectTimeout: 2000\r\n trackerList: 8.129.231.12:22122\r\n\r\n# Minio配置\r\nminio:\r\n url: http://8.129.231.12:9000\r\n accessKey: minioadmin\r\n secretKey: minioadmin\r\n bucketName: test','5382b93f3d8059d6068c0501fdd41195','2020-11-20 00:00:00','2020-12-21 21:01:59',NULL,'0:0:0:0:0:0:0:1','','','文件服务','null','null','yaml',NULL,''), (8,'ruoyi-file-dev.yml','DEFAULT_GROUP','# 本地文件上传 \r\nfile:\r\n domain: http://127.0.0.1:9300\r\n path: D:/ruoyi/uploadPath\r\n prefix: /statics\r\n\r\n# FastDFS配置\r\nfdfs:\r\n domain: http://8.129.231.12\r\n soTimeout: 3000\r\n connectTimeout: 2000\r\n trackerList: 8.129.231.12:22122\r\n\r\n# Minio配置\r\nminio:\r\n url: http://8.129.231.12:9000\r\n accessKey: minioadmin\r\n secretKey: minioadmin\r\n bucketName: test','5382b93f3d8059d6068c0501fdd41195','2020-11-20 00:00:00','2020-12-21 21:01:59',NULL,'0:0:0:0:0:0:0:1','','','文件服务','null','null','yaml',NULL,''),
(9,'sentinel-ruoyi-gateway','DEFAULT_GROUP','[\r\n {\r\n \"resource\": \"ruoyi-auth\",\r\n \"count\": 500,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n },\r\n {\r\n \"resource\": \"ruoyi-system\",\r\n \"count\": 1000,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n },\r\n {\r\n \"resource\": \"ruoyi-gen\",\r\n \"count\": 200,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n },\r\n {\r\n \"resource\": \"ruoyi-job\",\r\n \"count\": 300,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n }\r\n]','9f3a3069261598f74220bc47958ec252','2020-11-20 00:00:00','2020-11-20 00:00:00',NULL,'0:0:0:0:0:0:0:1','','','限流策略','null','null','json',NULL,''); (9,'sentinel-ruoyi-gateway','DEFAULT_GROUP','[\r\n {\r\n \"resource\": \"ruoyi-auth\",\r\n \"count\": 500,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n },\r\n {\r\n \"resource\": \"ruoyi-system\",\r\n \"count\": 1000,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n },\r\n {\r\n \"resource\": \"ruoyi-gen\",\r\n \"count\": 200,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n },\r\n {\r\n \"resource\": \"ruoyi-job\",\r\n \"count\": 300,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n }\r\n]','9f3a3069261598f74220bc47958ec252','2020-11-20 00:00:00','2020-11-20 00:00:00',NULL,'0:0:0:0:0:0:0:1','','','限流策略','null','null','json',NULL,'');