This commit is contained in:
JyuHsin
2024-12-06 08:47:16 +08:00
parent 035b0a46c7
commit c957e2ddd4
20 changed files with 580 additions and 181 deletions
+1 -2
View File
@@ -84,8 +84,7 @@ public class MainLauncher {
}
public void init() {
Mvcs.X_POWERED_BY = "BudWK-V5 <budwk.com>";
Mvcs.DISABLE_X_POWERED_BY = true;
Globals.AppBase = Mvcs.getServletContext().getContextPath();
Globals.AppRoot = Mvcs.getServletContext().getRealPath("/");
//注册自定义标签
@@ -2,6 +2,7 @@ package io.v.nutz.member.controller;
import cn.wizzer.framework.base.Result;
import io.v.nutz.annontation.ViReturn;
import io.v.nutz.base.utils.Vi;
import io.v.nutz.member.UserMode;
import io.v.nutz.member.model.MemberApplyRecord;
import io.v.nutz.member.model.MemberChangeRecord;
@@ -9,6 +10,7 @@ import io.v.nutz.member.service.MemberService;
import io.v.nutz.service.ViService;
import io.v.nutz.sys.models.Sys_user;
import io.v.nutz.sys.services.SysUserService;
import io.v.nutz.web.commons.utils.ShiroUtil;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
@@ -59,6 +61,9 @@ public class MemberCommonController {
@ViReturn
@Ok("json:{locked:'password|salt',ignoreNull:false}")
public Object userInfo(String userId, String source) {
if (!ShiroUtil.hasAnyRoles("sysadmin,A06")){
userId= ShiroUtil.getUserId();
}
Sql sql = Sqls.create("""
SELECT
u.*,unit.`name` unitname,un.unionname,unit.unionid
@@ -47,7 +47,6 @@ import java.util.List;
@At("/platform/member/group/info")
@Ok("json:full")
@IocBean
@RequiresAuthentication
public class MemberGroupInfoController {
@At("")
@Ok("beetl:/platform/member/info/GroupInfo.html")
@@ -111,11 +110,13 @@ public class MemberGroupInfoController {
}
@At
@RequiresPermissions("member.group.person")
public Integer getMemberHistoryNum(Integer year) {
return memberHistoryService.count(Cnd.where("year", "=", year));
}
@At
@RequiresPermissions("member.group.person")
public Object archive(Integer year) {
try {
@@ -139,12 +140,14 @@ public class MemberGroupInfoController {
@At
@ViReturn
@RequiresPermissions("member.group.person")
public Object pageData(PageForm pageForm, String unionId, String unitId, String[] personTypes, String[] userStates, String campus, String sex, Integer memberStatus, String position, String jobTitle) {
return memberService.list(pageForm, dataSql(pageForm, unionId, unitId, personTypes, userStates, campus, sex, memberStatus, position, jobTitle));
}
@At
@ViReturn
@RequiresPermissions("member.group.person")
public Object delete(String userId) {
UserMode.removeMemberRole(userId);
return null;
@@ -152,7 +155,7 @@ public class MemberGroupInfoController {
@At
@Ok("void")
@RequiresAuthentication
@RequiresPermissions("member.group.person")
public void export(HttpServletResponse response, String props, PageForm pageForm, String unionId, String unitId, String personTypes, String userStates, String campus, String sex, Integer memberStatus, String position, String jobTitle) throws IOException {
ViTool.excelResponse(response, "会员名单.xls");
@@ -45,7 +45,6 @@ import java.util.Map;
@At("/platform/member/inquire/integrate")
@Ok("json:full")
@IocBean
@RequiresAuthentication
public class MemberInquireIntegrateController {
@At("")
@@ -65,6 +64,7 @@ public class MemberInquireIntegrateController {
@At
@ViReturn
@RequiresPermissions("member.inquire.Integrate")
public Object pageData(PageForm pageForm, Integer year, String unionId, String unitId, String[] personTypes, String[] userStates, String[] memberStatus, String campus) {
int yyyy = Calendar.getInstance().get(Calendar.YEAR);
@@ -328,6 +328,7 @@ public class MemberInquireIntegrateController {
@At
@Ok("void")
@RequiresPermissions("member.inquire.Integrate")
public void doExport(HttpServletResponse response, Integer year, String unionId, String unitId, String memberStatus, String personTypes, String userStates) {
try {
int yyyy = Calendar.getInstance().get(Calendar.YEAR);
@@ -385,6 +386,7 @@ public class MemberInquireIntegrateController {
@At
@Ok("void")
@RequiresPermissions("member.inquire.Integrate")
public void doExportByUnion(HttpServletResponse response, Integer year, String unionId, String unitId, String memberStatus, String personTypes, String userStates, String props) {
try {
int yyyy = Calendar.getInstance().get(Calendar.YEAR);
@@ -465,5 +467,4 @@ public class MemberInquireIntegrateController {
}
}
}
@@ -1,5 +1,7 @@
package io.v.nutz.question.controller;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
@@ -31,6 +33,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 问卷H5
@@ -286,6 +289,12 @@ public class QuestionH5Controller {
//判断是否将题目加进去了
Sql issueSql = Sqls.create(" SELECT iid FROM `question_issue` $condition");
issueSql = Sqls.create("""
SELECT iid FROM (
SELECT * FROM `question_issue` $condition
) AS subquery ORDER BY ipxbh ASC;
""");
Cnd commonIssueCnd = Cnd.NEW();
commonIssueCnd.and("iqid", "=", id);
@@ -305,12 +314,17 @@ public class QuestionH5Controller {
QuestionRandomIssue maxQuestionRandomIssue = randomIssues.stream().filter(randomIssue -> randomIssue.getNum() == finalMaxAnswer).findFirst().orElse(null);
if (randomIssues.size() < ranDomSum && Lang.isNotEmpty(maxQuestionRandomIssue) && maxQuestionRandomIssue.getIsFinish()) {
List<String> allIssueIds = randomIssues.stream().flatMap(randomIssue -> randomIssue.getIssueIds().stream()).collect(Collectors.toList());
commonIssueCnd.andEX("iid", "not in", allIssueIds);
//每次都从20题里面去找
// commonIssueCnd.andEX("iid", "not in", allIssueIds);
}else{
needFor = false;
}
}
//固定3题
List<String> fixedIssueIds = new java.util.ArrayList<>(List.of("52e2a5c9d54e4a3ab3e60443b1c961aa", "140388aa1a10445bbcd9e6356c28ef2b", "5f04a8e4f43d46378f012a573001bea9","c81599b8bf5e424bba619de39c5860ca","f701af5766244d788513439b9379f3f0"));
commonIssueCnd.and("iid","not in",fixedIssueIds);
if (ObjectUtil.isAllNotEmpty(ranDomSum, ranDomSingleIssueNum)) {
commonIssueCnd.and(new Static("1=1 order by rand() limit " + ranDomSingleIssueNum));
}
@@ -320,48 +334,31 @@ public class QuestionH5Controller {
issueSql.setCallback(Sqls.callback.strList());
dao.execute(issueSql);
List<String> randomIssueIds = (List<String>) issueSql.getResult();
Collections.shuffle(randomIssueIds);
// Collections.shuffle(randomIssueIds);
List<String> allIssueIds = Stream.concat(fixedIssueIds.stream(), randomIssueIds.stream()).collect(Collectors.toList());
QuestionRandomIssue questionRandomIssue = new QuestionRandomIssue();
questionRandomIssue.setQuestionId(id);
questionRandomIssue.setUserId(ShiroUtil.getUserId());
questionRandomIssue.setIssueIds(randomIssueIds);
questionRandomIssue.setIssueIds(allIssueIds);
questionRandomIssue.setNum(maxAnswer + 1);
questionRandomIssue.setIsFinish(false);
dao.insert(questionRandomIssue);
issueCnd.and("iid", "in", randomIssueIds);
if(maxAnswer==0){
dao.insert(questionRandomIssue);
}
issueCnd.and("iid", "in", allIssueIds);
}else{
// List<String> allIssueIds = randomIssues.stream().flatMap(randomIssue -> randomIssue.getIssueIds().stream()).collect(Collectors.toList());
int finalMaxAnswer1 = maxAnswer;
List<String> allIssueIds = randomIssues.stream().filter(randomIssue -> randomIssue.getNum() == finalMaxAnswer1).flatMap(randomIssue -> randomIssue.getIssueIds().stream()).collect(Collectors.toList());
issueCnd.and("iid", "in", allIssueIds);
}
// if (Lang.isEmpty(randomIssue)) {
//
// Sql issueSql = Sqls.create(" SELECT iid FROM `question_issue` where iqid = @qid $randLimit");
// issueSql.setParam("qid", id);
// if (ranDomSingleIssueNum != null && ranDomSingleIssueNum > 0) {
// issueSql.setVar("randLimit", " order by rand() limit " + ranDomSingleIssueNum);
// }
//
// issueSql.setCallback(Sqls.callback.strList());
// dao.execute(issueSql);
// List<String> randomIssueIds = (List<String>) issueSql.getResult();
// Collections.shuffle(randomIssueIds);
// QuestionRandomIssue questionRandomIssue = new QuestionRandomIssue();
// questionRandomIssue.setQuestionId(id);
// questionRandomIssue.setUserId(ShiroUtil.getUserId());
// questionRandomIssue.setIssueIds(randomIssueIds);
// questionRandomIssue.setNum(null);
// questionRandomIssue.setIsFinish(false);
// dao.insert(questionRandomIssue);
// issueCnd.and("iid", "in", randomIssueIds);
// } else {
// issueCnd.and("iid", "in", randomIssue.getIssueIds());
// }
}
// issueCnd.asc("ipxbh");
// issueCnd.and(new Static("1=1 ORDER BY FIELD(iid,'52e2a5c9d54e4a3ab3e60443b1c961aa', '140388aa1a10445bbcd9e6356c28ef2b', '5f04a8e4f43d46378f012a573001bea9', 'c81599b8bf5e424bba619de39c5860ca', 'f701af5766244d788513439b9379f3f0') DESC"));
issueCnd.desc("ipxbh");
questionService.fetchLinks(question, "issues", issueCnd);
for (Question_issue issue : question.getIssues()) {
questionService.fetchLinks(issue, "wors", Cnd.NEW().asc("wpxbh"));
@@ -435,6 +432,80 @@ public class QuestionH5Controller {
return Result.success();
}
@At
public Result answerAgainCommon(String id){
Question question = questionService.fetch(id);
Cnd issueCnd = Cnd.NEW();
Sql issueSql = Sqls.create(" SELECT iid FROM `question_issue` $condition");
issueSql = Sqls.create("""
SELECT * FROM (
SELECT * FROM `question_issue` $condition
) AS subquery ORDER BY ipxbh ASC;
""");
Cnd commonIssueCnd = Cnd.NEW();
commonIssueCnd.and("iqid", "=", id);
//判断是否要随机
Integer ranDomSum = question.getRanDomSum();
Integer ranDomSingleIssueNum = question.getRanDomSingleIssueNum();
//已经回答最大次数
int maxAnswer = 0;
boolean needFor = true;
List<QuestionRandomIssue> randomIssues = dao.query(QuestionRandomIssue.class, Cnd.where("questionId", "=", question.getQid()).and("userId", "=", ShiroUtil.getUserId()));
if (Lang.isNotEmpty(randomIssues)) {
maxAnswer = randomIssues.stream().mapToInt(QuestionRandomIssue::getNum).max().orElse(0);
int finalMaxAnswer = maxAnswer;
QuestionRandomIssue maxQuestionRandomIssue = randomIssues.stream().filter(randomIssue -> randomIssue.getNum() == finalMaxAnswer).findFirst().orElse(null);
if (randomIssues.size() < ranDomSum && Lang.isNotEmpty(maxQuestionRandomIssue) && maxQuestionRandomIssue.getIsFinish()) {
List<String> allIssueIds = randomIssues.stream().flatMap(randomIssue -> randomIssue.getIssueIds().stream()).collect(Collectors.toList());
//每次都从20题里面去找
// commonIssueCnd.andEX("iid", "not in", allIssueIds);
}else{
needFor = false;
}
}
if (ObjectUtil.isAllNotEmpty(ranDomSum, ranDomSingleIssueNum)) {
commonIssueCnd.and(new Static("1=1 order by rand() limit " + ranDomSingleIssueNum));
}
if(needFor){
issueSql.setCondition(commonIssueCnd);
issueSql.setCallback(Sqls.callback.strList());
dao.execute(issueSql);
List<String> randomIssueIds = (List<String>) issueSql.getResult();
Collections.shuffle(randomIssueIds);
QuestionRandomIssue questionRandomIssue = new QuestionRandomIssue();
questionRandomIssue.setQuestionId(id);
questionRandomIssue.setUserId(ShiroUtil.getUserId());
questionRandomIssue.setIssueIds(randomIssueIds);
questionRandomIssue.setNum(maxAnswer + 1);
questionRandomIssue.setIsFinish(false);
dao.insert(questionRandomIssue);
issueCnd.and("iid", "in", randomIssueIds);
}else{
// List<String> allIssueIds = randomIssues.stream().flatMap(randomIssue -> randomIssue.getIssueIds().stream()).collect(Collectors.toList());
int finalMaxAnswer1 = maxAnswer;
List<String> allIssueIds = randomIssues.stream().filter(randomIssue -> randomIssue.getNum() == finalMaxAnswer1).flatMap(randomIssue -> randomIssue.getIssueIds().stream()).collect(Collectors.toList());
issueCnd.and("iid", "in", allIssueIds);
}
questionService.fetchLinks(question, "issues", issueCnd);
for (Question_issue issue : question.getIssues()) {
questionService.fetchLinks(issue, "wors", Cnd.NEW().asc("wpxbh"));
}
if (question.getDisruptingOrder()) {
Collections.shuffle(question.getIssues());
}
return Result.success(question);
}
@At("/winInfo")
public Object winInfo(String questionId) {
// List<QuestionWinner> winners = dao.query(QuestionWinner.class, Cnd.where("questionId", "=", questionId));
@@ -581,12 +652,26 @@ public class QuestionH5Controller {
} else if (question.getCtMode() == 3) {
QuestionUserScore userScore = dao.fetch(QuestionUserScore.class, Cnd.where("questionId", "=", questionId)
.and("userId", "=", ShiroUtil.getUserId())
.desc(question.getCalcScoreMode() == 1 ? "score" : "answerNum"));
// .desc(question.getCalcScoreMode() == 1 ? "score" : "answerNum"));
.desc("answerNum"));
return Result.success().addData(Optional.ofNullable(userScore).map(v -> v.getScore()).orElse(0));
}
return Result.success();
}
/**
* 仅限常规模式
* @param questionId
* @return
*/
@At
@RequiresAuthentication
public Result historyScore(String questionId){
List<QuestionUserScore> scores = dao.query(QuestionUserScore.class, Cnd.where("questionId", "=", questionId)
.and("userId","=",ShiroUtil.getUserId()).asc("answerNum"));
return Result.success(scores);
}
/**
* 获取用户已回答的轮数 针对单天随机
*
@@ -97,12 +97,44 @@ public class TrainEduStatisticsVideoController {
LEFT JOIN `user` u ON u.id = tevwr.userId
$condition
""");
sql = Sqls.create("""
SELECT
u.username,
u.loginname,
u.unitname,
u.unionname,
tev.qualifiedNum,
SUM(CASE
WHEN sub.cnt > tev.everyDayMaxWatchNum THEN tev.everyDayMaxWatchNum
ELSE sub.cnt
END) AS watchCount
FROM
`train_edu_video_watch_record` tevwr
LEFT JOIN train_edu_video tev ON tev.id = tevwr.videoId
LEFT JOIN train_edu_album tea ON tea.id = tevwr.albumId
LEFT JOIN `user` u ON u.id = tevwr.userId
LEFT JOIN (
SELECT
userId,
albumId,
watchTime,
COUNT(*) AS cnt
FROM
`train_edu_video_watch_record`
WHERE
albumId = @albumId
GROUP BY
userId,
watchTime
) AS sub ON tevwr.userId = sub.userId AND tevwr.albumId = sub.albumId AND tevwr.watchTime = sub.watchTime
$condition
""").setParam("albumId", albumId);
Cnd cnd = Cnd.NEW();
cnd.and("tevwr.albumId", "=", albumId);
cnd.and(new Static("IF(tea.createType = 1, u.unionId = tea.unionId , 1=1)"));
cnd.and(new Static("tevwr.watchTime >= tev.startDate"));
cnd.and(new Static("tevwr.watchTime <= tev.endDate"));
cnd.groupBy("tevwr.userId");
cnd.groupBy("u.username,u.loginname,u.unitname,u.unionname,tev.qualifiedNum");
sql.setCondition(cnd);
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return pagination;
@@ -152,57 +184,70 @@ public class TrainEduStatisticsVideoController {
@At
@Ok("void")
@RequiresPermissions("trainEdu.statistics.video")
public void exportXlsx(String albumId,HttpServletResponse response){
public void exportXlsx(String albumId, HttpServletResponse response) {
Sql sql = Sqls.create("""
SELECT
u.username,
u.loginname,
u.unitname,
u.unionname,
tev.qualifiedNum,
(
SELECT
SUM(IF( cnt > tev.everyDayMaxWatchNum, tev.everyDayMaxWatchNum, cnt )) AS count
FROM
( SELECT watchTime, COUNT( 1 ) AS cnt FROM train_edu_video_watch_record where userId = tevwr.userId and albumId = tevwr.albumId GROUP BY watchTime ) AS subquery
) as watchCount
u.username,
u.loginname,
u.unitname,
u.unionname,
tev.qualifiedNum,
SUM(CASE
WHEN sub.cnt > tev.everyDayMaxWatchNum THEN tev.everyDayMaxWatchNum
ELSE sub.cnt
END) AS watchCount
FROM
`train_edu_video_watch_record` tevwr
LEFT JOIN train_edu_video tev ON tev.id = tevwr.videoId
LEFT JOIN train_edu_album tea on tea.id = tevwr.albumId
LEFT JOIN `user` u ON u.id = tevwr.userId
`train_edu_video_watch_record` tevwr
LEFT JOIN train_edu_video tev ON tev.id = tevwr.videoId
LEFT JOIN train_edu_album tea ON tea.id = tevwr.albumId
LEFT JOIN `user` u ON u.id = tevwr.userId
LEFT JOIN (
SELECT
userId,
albumId,
watchTime,
COUNT(*) AS cnt
FROM
`train_edu_video_watch_record`
WHERE
albumId = @albumId
GROUP BY
userId,
watchTime
) AS sub ON tevwr.userId = sub.userId AND tevwr.albumId = sub.albumId AND tevwr.watchTime = sub.watchTime
$condition
""");
""").setParam("albumId", albumId);
Cnd cnd = Cnd.NEW();
cnd.and("tevwr.albumId", "=", albumId);
cnd.and(new Static("IF(tea.createType = 1, u.unionId = tea.unionId , 1=1)"));
cnd.and(new Static("tevwr.watchTime >= tev.startDate"));
cnd.and(new Static("tevwr.watchTime <= tev.endDate"));
cnd.groupBy("tevwr.userId");
cnd.groupBy("u.username,u.loginname,u.unitname,u.unionname,tev.qualifiedNum");
sql.setCondition(cnd);
List<NutMap> list = baseService.listMap(sql);
List<ExcelExportEntity> excelExportEntities = new ArrayList<>();
excelExportEntities.add(new ExcelExportEntity("序号","no",10));
excelExportEntities.add(new ExcelExportEntity("姓名","username",20));
excelExportEntities.add(new ExcelExportEntity("工号","loginname",20));
excelExportEntities.add(new ExcelExportEntity("单位","unitname",20));
excelExportEntities.add(new ExcelExportEntity("分工会","unionname",20));
excelExportEntities.add(new ExcelExportEntity("学习总次数","watchCount",20));
excelExportEntities.add(new ExcelExportEntity("是否达标","qualifiedNum",20));
excelExportEntities.add(new ExcelExportEntity("序号", "no", 10));
excelExportEntities.add(new ExcelExportEntity("姓名", "username", 20));
excelExportEntities.add(new ExcelExportEntity("工号", "loginname", 20));
excelExportEntities.add(new ExcelExportEntity("单位", "unitname", 20));
excelExportEntities.add(new ExcelExportEntity("分工会", "unionname", 20));
excelExportEntities.add(new ExcelExportEntity("学习总次数", "watchCount", 20));
excelExportEntities.add(new ExcelExportEntity("是否达标", "qualified", 20));
for (int i = 0; i < list.size(); i++) {
list.get(i).put("no",i+1);
list.get(i).put("qualifiedNum",list.get(i).getInt("qualifiedNum",0)==1?"是":"否");
list.get(i).put("no", i + 1);
int watchCount = list.get(i).getInt("watchCount", 0);
int qualifiedNum = list.get(i).getInt("qualifiedNum", 0);
list.get(i).put("qualified", watchCount >= qualifiedNum ? "是" : "否");
}
try{
try {
ViTool.excelResponse(response, "获奖人员名单.xls");
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), excelExportEntities, list);
workbook.write(response.getOutputStream());
}catch (Exception e){
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
@@ -33,27 +33,29 @@ public class GlobalsSettingProcessor extends AbstractProcessor {
@SuppressWarnings("rawtypes")
public void process(ActionContext ac) throws Throwable {
ac.getRequest().setAttribute("AppRoot", Globals.AppRoot);
ac.getRequest().setAttribute("AppBase", Globals.AppBase);
ac.getRequest().setAttribute("AppName", Globals.AppName);
ac.getRequest().setAttribute("AppDomain", Globals.AppDomain);
ac.getRequest().setAttribute("AppShrotName", Globals.AppShrotName);
ac.getRequest().setAttribute("AppFileDomain", Globals.AppFileDomain);
ac.getRequest().setAttribute("config", Globals.MyConfig);
ac.getRequest().setAttribute("shiro", ShiroUtil);
ac.getRequest().setAttribute("date", dateUtil);
ac.getRequest().setAttribute("string", stringUtil);
ac.getRequest().setAttribute("BrandActivityName", Globals.BrandActivityName);
// 如果url中有语言属性则设置
String lang = ac.getRequest().getParameter("lang");
if (!Strings.isEmpty(lang)) {
Mvcs.setLocalizationKey(lang);
} else {
// Mvcs.getLocalizationKey() 1.r.56 版本是null,所以要做两次判断, 1.r.57已修复为默认值 Nutz:Fix issue 1072
lang = Strings.isBlank(Mvcs.getLocalizationKey()) ? Mvcs.getDefaultLocalizationKey() : Mvcs.getLocalizationKey();
}
ac.getRequest().setAttribute("lang", lang);
doNext(ac);
ac.getRequest().setAttribute("AppRoot", Globals.AppRoot);
ac.getRequest().setAttribute("AppBase", Globals.AppBase);
ac.getRequest().setAttribute("AppName", Globals.AppName);
ac.getRequest().setAttribute("AppDomain", Globals.AppDomain);
ac.getRequest().setAttribute("AppShrotName", Globals.AppShrotName);
ac.getRequest().setAttribute("AppFileDomain", Globals.AppFileDomain);
ac.getRequest().setAttribute("config", Globals.MyConfig);
ac.getRequest().setAttribute("shiro", ShiroUtil);
ac.getRequest().setAttribute("date", dateUtil);
ac.getRequest().setAttribute("string", stringUtil);
ac.getRequest().setAttribute("BrandActivityName", Globals.BrandActivityName);
// 如果url中有语言属性则设置
String lang = ac.getRequest().getParameter("lang");
if (!Strings.isEmpty(lang)) {
Mvcs.setLocalizationKey(lang);
} else {
// Mvcs.getLocalizationKey() 1.r.56 版本是null,所以要做两次判断, 1.r.57已修复为默认值 Nutz:Fix issue 1072
lang = Strings.isBlank(Mvcs.getLocalizationKey()) ? Mvcs.getDefaultLocalizationKey() : Mvcs.getLocalizationKey();
}
ac.getRequest().setAttribute("lang", lang);
doNext(ac);
}
}
@@ -1,6 +1,7 @@
package io.v.nutz.web.commons.proc;
import io.v.nutz.base.result.Result;
import org.eclipse.jetty.http.BadMessageException;
import org.nutz.integration.shiro.NutShiro;
import org.nutz.ioc.IocException;
import org.nutz.log.Log;
@@ -35,6 +36,12 @@ public class WkFailProcessor extends ViewProcessor {
new ForwardView(errorUri).render(ac.getRequest(), ac.getResponse(), Mvcs.getMessage(ac.getRequest(), "system.exception"));
}
}
if(ac.getError() instanceof BadMessageException){
NutShiro.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error("表单参数错误"));
}
if(ac.getError() instanceof RuntimeException){
NutShiro.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error("程序异常"));
}
super.process(ac);
}
}
@@ -1,6 +1,8 @@
package io.v.nutz.web.commons.proc;
import cn.hutool.http.HtmlUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.v.nutz.base.result.Result;
import org.apache.commons.lang3.StringUtils;
import org.nutz.integration.shiro.NutShiro;
@@ -16,9 +18,11 @@ import org.nutz.mvc.impl.processor.AbstractProcessor;
import org.nutz.mvc.view.ForwardView;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Pattern;
/**
* SQL XSS拦截
@@ -37,6 +41,13 @@ public class XssSqlFilterProcessor extends AbstractProcessor {
private final static String regxpForImaTagSrcAttrib = "src=\"([^\"]+)\""; // 找出IMG标签的SRC属性
//合法字段
private static final Set<String> ALLOWED_ORDER_FIELDS = new HashSet<>(Arrays.asList(
"createdat", "updatedat"
));
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void init(NutConfig config, ActionInfo ai) throws Throwable {
try {
@@ -66,64 +77,57 @@ public class XssSqlFilterProcessor extends AbstractProcessor {
protected boolean checkParams(ActionContext ac) {
HttpServletRequest req = ac.getRequest();
/* String pageOrderName = req.getParameter("pageOrderName");
if (pageOrderName != null && ALLOWED_ORDER_FIELDS.contains(pageOrderName.toLowerCase())) {
// 如果是预定义的排序字段,直接放行
return false;
}*/
Iterator<String[]> values = req.getParameterMap().values().iterator();// 获取所有的表单参数
Iterator<String[]> values2 = req.getParameterMap().values().iterator();// 因为是游标所以要重新获取
boolean isError = false;
//use remove -|,
String regEx_sql = """
select|update|and|or|delete|insert|trancate|char|chr|into|substr|ascii|declare|exec|count|master|drop|execute
""";
String regEx_xss = "script|iframe|img";
// XSS过滤
String regEx_xss = "script|iframe";
//SQL过滤
while (values.hasNext()) {
String[] valueArray = (String[]) values.next();
for (int i = 0; i < valueArray.length; i++) {
String value = valueArray[i].toLowerCase();
// 不转换为小写,保持原始值进行检查
String value = valueArray[i];
//排除掉base64
if (value.startsWith("data:image/png;base64,")) {
// URL解码
try {
value = URLDecoder.decode(value, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
log.error("URL解码失败", e);
isError = true;
break;
}
//分拆关键字
String[] inj_stra = StringUtils.split(regEx_sql, "\\|");
for (int j = 0; j < inj_stra.length; j++) {
// 判断如果路径参数值中含有关键字则返回true,并且结束循环
// if (value.contains(inj_stra[j] + " ") || value.contains(" " + inj_stra[j] + " ") || value.contains(" " + inj_stra[j])) {
// isError = true;
// log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "SQL关键字过滤:" + value);
// break;
// }
if ("and".equals(inj_stra[j]) || "or".equals(inj_stra[j]) || "into".equals(inj_stra[j])) {
if (value.contains(" " + inj_stra[j] + " ")) {
isError = true;
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "SQL关键字过滤:" + value);
break;
}
} else {
if (value.contains(" " + inj_stra[j] + " ")
|| value.contains(inj_stra[j] + " ")
|| value.contains(inj_stra[j] + "/**/")
|| value.contains(inj_stra[j] + "/*")
|| value.contains("/**/" + inj_stra[j] + "/**/")
|| value.contains(inj_stra[j] + "*/")
) {
isError = true;
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "SQL关键字过滤:" + value);
break;
}
// 检查是否是JSON格式
if (isValidJson(value)) {
// 对JSON内容进行安全检查
if (checkJsonContent(value)) {
isError = true;
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "JSON内容包含危险字符:" + value);
break;
}
// JSON格式验证通过,继续处理下一个参数
continue;
}
if (isError) {
// 非JSON格式,进行普通的SQL注入检查
if (containsSqlInjection(value, false)) {
isError = true;
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "SQL注入风险:" + value);
break;
}
}
if (isError) {
break;
}
if (isError) break;
}
if (!isError) {
// XSS漏洞过滤
@@ -131,14 +135,6 @@ public class XssSqlFilterProcessor extends AbstractProcessor {
String[] valueArray = (String[]) values2.next();
for (int i = 0; i < valueArray.length; i++) {
String value = valueArray[i].toLowerCase();
value = HtmlUtil.escape(value);
if (value.trim().startsWith("<") || value.trim().endsWith(">") ||
value.trim().endsWith("/")) {
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "XSS关键字过滤(已被我转义):" + value);
}
// 分拆关键字
String[] inj_stra = StringUtils.split(regEx_xss, "|");
for (int j = 0; j < inj_stra.length; j++) {
@@ -162,4 +158,197 @@ public class XssSqlFilterProcessor extends AbstractProcessor {
}
return isError;
}
/**
* 验证是否为有效的JSON
*/
private boolean isValidJson(String value) {
try {
objectMapper.readTree(value);
return true;
} catch (Exception e) {
return false;
}
}
/**
* 检查JSON内容是否包含危险字符
*/
private boolean checkJsonContent(String jsonStr) {
try {
JsonNode rootNode = objectMapper.readTree(jsonStr);
return checkJsonNode(rootNode, true);
} catch (Exception e) {
log.error("JSON内容检查失败", e);
return true; // 解析失败当作危险处理
}
}
/**
* 递归检查JSON节点
*/
private boolean checkJsonNode(JsonNode node, boolean isJsonContext) {
if (node.isObject()) {
Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> entry = fields.next();
// JSON对象的键名不需要进行特殊字符检查,因为它们是受控的标识符
// 递归检查值
if (checkJsonNode(entry.getValue(), true)) {
return true;
}
}
} else if (node.isArray()) {
for (JsonNode element : node) {
if (checkJsonNode(element, true)) {
return true;
}
}
} else if (node.isTextual()) {
String value = node.asText();
// 在JSON上下文中使用更宽松的规则
return containsSqlInjection(value, true);
}
return false;
}
/**
* 检查是否包含SQL注入风险
*
* @param value 要检查的值
* @param isJsonContext 是否在JSON上下文中
*/
private boolean containsSqlInjection(String value, boolean isJsonContext) {
if (StringUtils.isBlank(value)) {
return false;
}
// 规范化输入:移除多余的空白字符
value = value.replaceAll("\\s+", " ").trim();
// 检查编码后的特殊字符
String decodedValue = value.replaceAll("%20", " ")
.replaceAll("%2B", "+")
.replaceAll("%2F", "/")
.replaceAll("%3D", "=");
// 检查注释符号和其他危险字符
if (decodedValue.contains("--") ||
decodedValue.contains("/*") ||
decodedValue.contains("*/") ||
decodedValue.contains("#") ||
Pattern.compile("[;'\"\\\\]").matcher(decodedValue).find()) {
return true;
}
// 如果是UUID格式,直接放行
if (value.matches("[a-fA-F0-9]{32}") || value.matches("[a-fA-F0-9-]{36}")) {
return false;
}
// 如果包含HTML标签,使用更宽松的检查规则
if (value.contains("<") && value.contains(">")) {
return checkHtmlContent(value);
}
// 添加对常见标识符的检查
if (isCommonIdentifier(value) || ALLOWED_ORDER_FIELDS.contains(value.toLowerCase())) {
return false;
}
// 检查注释符号
if (value.contains("--") || value.contains("/*") || value.contains("*/")) {
return true;
}
// 检查危险的特殊字符(针对非JSON数据)
if (!isValidJson(value) && containsDangerousChars(value)) {
return true;
}
// 检查SQL关键字,但要避免误判
String valueLower = value.toLowerCase();
for (String keyword : SQL_KEYWORDS) {
// 在JSON上下文中,只有当关键字作为独立单词出现时才判定为危险
if (isJsonContext) {
if (isStandaloneWord(valueLower, keyword)) {
return true;
}
} else if (valueLower.contains(keyword)) {
return true;
}
}
return false;
}
/**
* 判断是否为常见的UUID或标识符格式
*/
private boolean isCommonIdentifier(String value) {
// UUID格式
if (value.matches("[a-fA-F0-9]{32}") || value.matches("[a-fA-F0-9-]{36}")) {
return true;
}
// 常见的标识符格式(字母、数字、下划线、中划线)
if (value.matches("^[a-zA-Z0-9_-]+$")) {
return true;
}
return false;
}
/**
* 检查HTML内容是否包含危险脚本
*/
private boolean checkHtmlContent(String html) {
String lowerHtml = html.toLowerCase();
// 只检查真正危险的脚本标签
return lowerHtml.contains("<script") ||
lowerHtml.contains("javascript:") ||
lowerHtml.contains("onerror=") ||
lowerHtml.contains("onclick=");
}
/**
* 检查是否包含危险的特殊字符
*/
private boolean containsDangerousChars(String value) {
// 定义真正危险的字符(减少误判)
String[] dangerousChars = {
"'", // 单引号
";", // 分号
"\\", // 反斜杠
"@@", // 系统变量前缀
"0x", // 十六进制前缀
"/*", // 注释开始
"*/" // 注释结束
};
for (String dangerous : dangerousChars) {
if (value.contains(dangerous)) {
return true;
}
}
return false;
}
private static final Set<String> SQL_KEYWORDS = new HashSet<>(Arrays.asList(
"select", "update", "delete", "insert", "truncate",
"drop", "execute", "exec", "declare", "union",
"create", "alter", "database", "table", "varchar",
"extractvalue", "concat", "benchmark", "sleep", "delay",
"waitfor", "pg_sleep", "information_schema", "sysobjects",
"load_file", "outfile", "dumpfile"
));
/**
* 检查关键字是否作为独立单词出现
*/
private boolean isStandaloneWord(String text, String keyword) {
String wordBoundary = "\\b" + keyword + "\\b";
return Pattern.compile(wordBoundary).matcher(text).find();
}
}
@@ -32,7 +32,7 @@
}
.van-tabs__line {
background-color: #1867b0;
background-color: #1867b0!important;
}
.font-theme-color {
@@ -273,6 +273,18 @@ var sublime = function () {
},
//2022/02/14 zxy pjax跳转自定义页面
jumpPagePjax(pageUrl) {
// const url = new URL(location.protocol + "//" + location.host + jump_url)
// const pathname = url.pathname
// headerNavBarVueApp.matchMenu(pathname)
// setTimeout(() => {
// const a = document.querySelector('a[href="' + pathname + '"][data-pjax]')
// if (a) {
// a.href = jump_url
// a.click()
// a.href = pathname
// // leftMenuApp.assignmentMenu()
// }
// }, 0)
const index = pageUrl.indexOf("?")
const doMainUrl = index > -1 ? pageUrl.substring(0, index) : pageUrl
const {protocol, host} = window.location
@@ -67,8 +67,8 @@
<script src="${base!}/assets/platform/plugins/echarts/macarons.js"></script><!--主题-->
<script src="${base!}/assets/platform/plugins/echarts/echarts.js"></script>
<script src="${base!}/assets/platform/plugins/echarts/langZH.js"></script>
<!-- <script src="https://cdn.staticfile.org/echarts/5.2.2/echarts.js"></script>-->
<!-- <script src="https://cdn.staticfile.org/echarts/5.2.2/i18n/langZH.js"></script>-->
<!-- <script src="https://cdn.staticfile.org/echarts/5.2.2/echarts.js"></script>-->
<!-- <script src="https://cdn.staticfile.org/echarts/5.2.2/i18n/langZH.js"></script>-->
<script src="${base!}/assets/platform/module/mixins/initTableMixins.js?v=1.0.3"></script>
@@ -441,7 +441,7 @@
secondMenus: {},
userDefaultModuleId: null,
menuPopover: false,
appModuleId:""
appModuleId: ""
}
},
methods: {
@@ -609,13 +609,12 @@
const selectEntranceModuleStr = window.sessionStorage.getItem('selectEntranceModule')
if (selectEntranceModuleStr) {
this.selectEntranceModule = JSON.parse(selectEntranceModuleStr)
this.appModuleId = this.selectEntranceModule.id
}
this.appModuleId=this.selectEntranceModule.id
await this.getEntranceModule()
await this.getFirstMenus(this.selectEntranceModule.id)
await this.getSecondMenus()
this.setAttr()
// let pjax_url = window.sessionStorage.getItem('pjax_url')
// pjax_url = pjax_url.replace(window.location.origin, '')
// $.pjax({
@@ -53,8 +53,8 @@
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script src="${base!}/assets/platform/js/scannerQrCodeJs.js"></script>
<script type="text/javascript"
src="https://webapi.amap.com/maps?v=2.0&key=57f0d098ba1b881ecc436c4cfd23bbbf&plugin=AMap.PolyEditor,AMap.Geolocation"></script>
<!-- <script type="text/javascript"-->
<!-- src="https://webapi.amap.com/maps?v=2.0&key=57f0d098ba1b881ecc436c4cfd23bbbf&plugin=AMap.PolyEditor,AMap.Geolocation"></script>-->
<script src="https://cdn-go.cn/cdn/vod-js-sdk-v6/latest/vod-js-sdk-v6.js"></script>
<link href="https://web.sdk.qcloud.com/player/tcplayer/release/v4.5.2/tcplayer.min.css" rel="stylesheet"/>
@@ -157,26 +157,30 @@ layout("/mobile/platform.html"){
<div class="page-survey" style="touch-action: manipulation;min-height: 100vh;">
<div class="survey-container">
<!-- v-if="questionData.qlx==2 && (questionData.ctMode==1 || questionData.ctMode==2)"-->
<div class="survey-head-top">
<template>
<div v-if="questionData.qlx==2 && questionData.ctMode==2 && isSameDay && randomCount > 0"
class="randomCount"
@click="openRandomCount">
第<span>{{randomCount}}</span>轮
</div>
<div v-if="questionData.qlx==2 && (questionData.ctMode==1 || (questionData.ctMode==2 && !isSameDay))"
class="randomCount"
@click="openRandomCount">
<!--定时定题 可切换时间查看以前的题目-->
<span>{{currentDate}}</span>
</div>
</template>
<div class="survey-head-top" v-if="finishAnswer && ( currentScore || currentScore===0 )">
<!-- <template>-->
<!-- <div v-if="questionData.qlx==2 && questionData.ctMode==2 && isSameDay && randomCount > 0"-->
<!-- class="randomCount"-->
<!-- @click="openRandomCount">-->
<!-- 第<span>{{randomCount}}</span>轮-->
<!-- </div>-->
<!-- <div v-if="questionData.qlx==2 && (questionData.ctMode==1 || (questionData.ctMode==2 && !isSameDay))"-->
<!-- class="randomCount"-->
<!-- @click="openRandomCount">-->
<!-- &lt;!&ndash;定时定题 可切换时间查看以前的题目&ndash;&gt;-->
<!-- <span>{{currentDate}}</span>-->
<!-- </div>-->
<!-- </template>-->
<div class="score" v-if="finishAnswer && ( currentScore || currentScore===0 )">
{{questionData.calcScoreMode==1?'今日最高成绩':'得分'}}{{currentScore}}
最新得分{{currentScore}}
<!-- {{questionData.calcScoreMode==1?'最高成绩':'得分'}}{{currentScore}}-->
</div>
<div class="timer" v-if="questionData.enableTimer && !finishAnswer">
<span>剩余时间:{{remainder}}</span>
<div class="" style="margin-left: 5px;color: #1989fa" @click="viewHistoryScore">
查看历史得分
</div>
<!-- <div class="timer" v-if="questionData.enableTimer && !finishAnswer">-->
<!-- <span>剩余时间:{{remainder}}</span>-->
<!-- </div>-->
</div>
<div class="survey-head">
<div class="title">
@@ -196,8 +200,8 @@ layout("/mobile/platform.html"){
{{issue.iisdx?'单选':'多选'}}
</van-tag>
</template>
<!-- <van-tag v-if="issue.fraction" type="primary" size="large">{{issue.fraction}}分-->
<!-- </van-tag>-->
<van-tag v-if="issue.fraction" type="primary" size="large">{{issue.fraction}}分
</van-tag>
</div>
<h2 class="question-title">
<span class="question-seq">
@@ -267,6 +271,15 @@ layout("/mobile/platform.html"){
close-on-click-action
></van-action-sheet>
<van-action-sheet v-model="historyScorePopup" title="历史得分记录">
<van-cell-group style="min-height: 500px">
<van-cell v-for="item in historyScores">
<div slot="title">第{{item.answerNum}}次</div>
<div style="font-weight: bold;color: #000000">{{item.score}}分</div>
</van-cell>
</van-cell-group>
</van-action-sheet>
</div>
</div>
@@ -310,7 +323,11 @@ layout("/mobile/platform.html"){
//答题时间(使用秒)
countDownSeconds: 0,
//剩余时间
remainder: null
remainder: null,
//历史分数
historyScores:[],
historyScorePopup:false
}
},
@@ -362,6 +379,14 @@ layout("/mobile/platform.html"){
},
methods: {
viewHistoryScore(){
$.get(BASE_URL+"/historyScore",{questionId:this.id}).then(res=>{
if(res.code===0){
this.historyScores = res.data
this.historyScorePopup = true
}
})
},
openRandomCount() {
this.randomCountSheetShow = true
this.randomActions = []
@@ -573,7 +598,20 @@ layout("/mobile/platform.html"){
answerAgain() {
if(this.questionData.ctMode===3){
location.reload()
$.post(BASE_URL+'/answerAgainCommon',{id:this.id}).then(resp=>{
if(resp.code===0){
this.questionData = resp.data
this.finishAnswer = false
setTimeout(() => {
this.questionData.issues.forEach(issue => {
issue.wors.forEach(wor => {
this.$refs['checkboxes' + wor.wid][0].toggle(false)
})
})
}, 0)
this.checkTimer()
}
})
}else{
this.finishAnswer = false
setTimeout(() => {
@@ -653,7 +691,16 @@ layout("/mobile/platform.html"){
} else {
this.countDownSeconds = this.countDownSeconds - 1
}
},
getHistoryScore(){
$.get(BASE_URL+"/historyScore",{questionId:this.id}).then(res=>{
if(res.code===0){
this.historyScores = res.data
}
})
}
},
async created() {
if (this.timerInterval) {
@@ -666,6 +713,7 @@ layout("/mobile/platform.html"){
await this.checkUserFinishAnswer()
await this.getScore()
await this.checkTimer()
this.getHistoryScore()
this.mLoading = false
}
})
@@ -63,7 +63,7 @@ const onlineAnswer = {
<el-col :span="1" v-if="issue.row.fraction">
<span>({{issue.row.fraction}}分)</span>
</el-col>
<el-col :span="23">
<el-col :span="23" style="display: flex">
<span v-html="issue.row.iname"></span>
<span v-if="issue.row.itx===1" size="mini" style="font-weight: bold">
({{issue.row.iisdx ? '单选' : '多选'}})
@@ -74,7 +74,7 @@ const onlineAnswer = {
<div style="color: rgb(160,160,160)" v-html="issue.row.its"
v-if="!isNull(issue.row.its)"></div>
</el-row>
<el-row v-if="issue.row.itx==1">
<el-row>
<el-row v-for="wor,idx in issue.row.wors">
<el-row style="margin-top: 5px" v-if="wor.wimg">
<el-image
@@ -22,8 +22,7 @@ const batchInsert = {
<div style="height: 100%;width: 50%;overflow: auto;padding: 20px 10px 10px">
<div v-for="(issue,index) in issues" :key="index" style="margin-bottom: 10px">
<div style="display: flex">
<div>{{index+1}}、</div>
<div>{{issue.iname}}</div>
<div>{{index+1}}、{{issue.iname}}</div>
</div>
<div v-if="issue.wors">
<el-radio-group v-if="issue.iisdx">
@@ -539,7 +539,7 @@ layout("/layouts/platform.html"){
<div style="color: rgb(160,160,160)" v-html="issue.row.its"
v-if="!isNull(issue.row.its)"></div>
</el-row>
<el-row v-if="issue.row.itx==1">
<el-row v-if="issue.row.itx==1 || issue.row.itx==3">
<el-row v-for="wor,idx in issue.row.wors">
<el-row style="margin-top: 5px" v-if="wor.wimg">
<el-image
@@ -863,7 +863,7 @@ layout("/layouts/platform.html"){
:key="item.x"
:label="item.y"
:value="item.x"
v-for="item in [{x:1,y:'选择题'},{x:2,y:'填空题'}]">
v-for="item in [{x:1,y:'选择题'},{x:2,y:'填空题'},{x:3,y:'判断题'}]">
</el-option>
</el-select>
</div>
@@ -928,9 +928,9 @@ layout("/layouts/platform.html"){
</el-date-picker>
</el-row>
<template v-if="issueData[currentModifyIssueIndex].itx===1">
<template v-if="issueData[currentModifyIssueIndex].itx===1 || issueData[currentModifyIssueIndex].itx===3">
<vi-title2 title="选项设置"></vi-title2>
<el-row v-if="currentModifyIssue.itx==1">
<el-row v-if="currentModifyIssue.itx==1 || currentModifyIssue.itx==3">
<el-table :data="issueData[currentModifyIssueIndex].wors" border
style="width: 100%;margin-top: 10px;">
<el-table-column header-align="center" label="选项文字" property="wtxt">
@@ -942,6 +942,7 @@ layout("/layouts/platform.html"){
</template>
</el-table-column>
<el-table-column label="图片" align="center" header-align="center"
v-if="currentModifyIssue.itx==1"
width="150px">
<template slot-scope="scope">
<el-upload
@@ -967,6 +968,7 @@ layout("/layouts/platform.html"){
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="说明"
v-if="currentModifyIssue.itx==1"
property="wsm" width="250px">
<template slot-scope="scope">
<el-input
@@ -984,6 +986,7 @@ layout("/layouts/platform.html"){
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="链接"
v-if="currentModifyIssue.itx==1"
property="wlj" width="150px">
<template slot-scope="scope">
<el-input
@@ -1007,6 +1010,7 @@ layout("/layouts/platform.html"){
</template>
</el-table-column>-->
<el-table-column align="center" header-align="center" label="默认选中"
v-if="currentModifyIssue.itx==1"
property="wismr"
width="80px">
<template slot-scope="scope">
@@ -7,7 +7,7 @@ const activity = {
<div style="width: 100%">
<div style="background-color: #fff; position: relative; margin-bottom: 10px">
<div style="display: flex; justify-content: center; align-items: center">
<el-image :src="CREATE_PREVIEW_URL(item.cover.id)" alt="" fit="fill"
<el-image :src="'/file_server/fileStreamPreview?id='+item.cover.filepath" alt="" fit="fill"
style="margin: 3px 14px 0 0; width: 100px; height: 70px; border-radius: 8px">
<div slot="error" class="image-slot">
<i class="el-icon-picture-outline"></i>
@@ -39,7 +39,7 @@ const appModule = {
created() {
this.getEntranceModule()
setTimeout(() => {
this.id = headerNavBarVueApp.appModuleId
}, 100)
// this.id = headerNavBarVueApp.appModuleId
}, 400)
}
}
@@ -37,6 +37,7 @@ const quickEntry = {
})*/
},
menuClick(item) {
// location.href=item.url
sublime.jumpPagePjax(item.url)
}
},