diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/PigxJobAdminApplication.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/PigxJobAdminApplication.java index f4f2bd689..022ee8b0e 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/PigxJobAdminApplication.java +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/PigxJobAdminApplication.java @@ -13,4 +13,4 @@ public class PigxJobAdminApplication { SpringApplication.run(PigxJobAdminApplication.class, args); } -} +} \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/constant/Consts.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/constant/Consts.java new file mode 100644 index 000000000..640350ac4 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/constant/Consts.java @@ -0,0 +1,7 @@ +package com.xxl.job.admin.constant; + +public class Consts { + + public static final String ADMIN_ROLE = "ADMIN"; + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/constant/TriggerStatus.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/constant/TriggerStatus.java new file mode 100644 index 000000000..de13e009c --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/constant/TriggerStatus.java @@ -0,0 +1,32 @@ +package com.xxl.job.admin.constant; + +public enum TriggerStatus { + + STOPPED(0, "stopped"), + RUNNING(1, "running"); + + private int value; + private String desc; + + TriggerStatus(int value, String desc) { + this.value = value; + this.desc = desc; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java deleted file mode 100644 index 202d9c866..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.xxl.job.admin.controller; - -import com.xxl.job.admin.controller.annotation.PermissionLimit; -import com.xxl.job.admin.service.XxlJobService; -import com.xxl.job.admin.service.impl.LoginService; -import com.xxl.job.core.biz.model.ReturnT; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.beans.propertyeditors.CustomDateEditor; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.servlet.view.RedirectView; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Map; - -/** - * index controller - * - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -public class IndexController { - - @Resource - private XxlJobService xxlJobService; - - @Resource - private LoginService loginService; - - @RequestMapping("/") - public String index(Model model) { - - Map dashboardMap = xxlJobService.dashboardInfo(); - model.addAllAttributes(dashboardMap); - - return "index"; - } - - @RequestMapping("/chartInfo") - @ResponseBody - public ReturnT> chartInfo(@RequestParam("startDate") Date startDate, - @RequestParam("endDate") Date endDate) { - ReturnT> chartInfo = xxlJobService.chartInfo(startDate, endDate); - return chartInfo; - } - - @RequestMapping("/toLogin") - @PermissionLimit(limit = false) - public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) { - if (loginService.ifLogin(request, response) != null) { - modelAndView.setView(new RedirectView("/", true, false)); - return modelAndView; - } - return new ModelAndView("login"); - } - - @RequestMapping(value = "login", method = RequestMethod.POST) - @ResponseBody - @PermissionLimit(limit = false) - public ReturnT loginDo(HttpServletRequest request, HttpServletResponse response, - @RequestParam("userName") String userName, @RequestParam("password") String password, - @RequestParam(value = "ifRemember", required = false) String ifRemember) { - - boolean ifRem = (ifRemember != null && ifRemember.trim().length() > 0 && "on".equals(ifRemember)) ? true - : false; - return loginService.login(request, response, userName, password, ifRem); - } - - @RequestMapping(value = "logout", method = RequestMethod.POST) - @ResponseBody - @PermissionLimit(limit = false) - public ReturnT logout(HttpServletRequest request, HttpServletResponse response) { - return loginService.logout(request, response); - } - - @RequestMapping("/help") - public String help() { - - /* - * if (!PermissionInterceptor.ifLogin(request)) { return "redirect:/toLogin"; } - */ - - return "help"; - } - - @InitBinder - public void initBinder(WebDataBinder binder) { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - dateFormat.setLenient(false); - binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java deleted file mode 100644 index 23d52bd9e..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.xxl.job.admin.controller; - -import com.xxl.job.admin.controller.annotation.PermissionLimit; -import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -import com.xxl.job.core.biz.AdminBiz; -import com.xxl.job.core.biz.model.HandleCallbackParam; -import com.xxl.job.core.biz.model.RegistryParam; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.util.GsonTool; -import com.xxl.job.core.util.XxlJobRemotingUtil; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; - -import java.util.List; - -/** - * Created by xuxueli on 17/5/10. - */ -@Controller -@RequestMapping("/api") -public class JobApiController { - - @Resource - private AdminBiz adminBiz; - - /** - * api - * @param uri - * @param data - * @return - */ - @RequestMapping("/{uri}") - @ResponseBody - @PermissionLimit(limit = false) - public ReturnT api(HttpServletRequest request, @PathVariable("uri") String uri, - @RequestBody(required = false) String data) { - - // valid - if (!"POST".equalsIgnoreCase(request.getMethod())) { - return new ReturnT(ReturnT.FAIL_CODE, "invalid request, HttpMethod not support."); - } - if (uri == null || uri.trim().length() == 0) { - return new ReturnT(ReturnT.FAIL_CODE, "invalid request, uri-mapping empty."); - } - if (XxlJobAdminConfig.getAdminConfig().getAccessToken() != null - && XxlJobAdminConfig.getAdminConfig().getAccessToken().trim().length() > 0 - && !XxlJobAdminConfig.getAdminConfig() - .getAccessToken() - .equals(request.getHeader(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN))) { - return new ReturnT(ReturnT.FAIL_CODE, "The access token is wrong."); - } - - // services mapping - if ("callback".equals(uri)) { - List callbackParamList = GsonTool.fromJson(data, List.class, - HandleCallbackParam.class); - return adminBiz.callback(callbackParamList); - } - else if ("registry".equals(uri)) { - RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class); - return adminBiz.registry(registryParam); - } - else if ("registryRemove".equals(uri)) { - RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class); - return adminBiz.registryRemove(registryParam); - } - else { - return new ReturnT(ReturnT.FAIL_CODE, "invalid request, uri-mapping(" + uri + ") not found."); - } - - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java deleted file mode 100644 index 25218e0b2..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.xxl.job.admin.controller; - -import com.xxl.job.admin.controller.interceptor.PermissionInterceptor; -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.core.model.XxlJobLogGlue; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.admin.dao.XxlJobInfoDao; -import com.xxl.job.admin.dao.XxlJobLogGlueDao; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.glue.GlueTypeEnum; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import java.util.Date; -import java.util.List; - -/** - * job code controller - * - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/jobcode") -public class JobCodeController { - - @Resource - private XxlJobInfoDao xxlJobInfoDao; - - @Resource - private XxlJobLogGlueDao xxlJobLogGlueDao; - - @RequestMapping - public String index(HttpServletRequest request, Model model, @RequestParam("jobId") int jobId) { - XxlJobInfo jobInfo = xxlJobInfoDao.loadById(jobId); - List jobLogGlues = xxlJobLogGlueDao.findByJobId(jobId); - - if (jobInfo == null) { - throw new RuntimeException(I18nUtil.getString("jobinfo_glue_jobid_unvalid")); - } - if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType())) { - throw new RuntimeException(I18nUtil.getString("jobinfo_glue_gluetype_unvalid")); - } - - // valid permission - PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup()); - - // Glue类型-字典 - model.addAttribute("GlueTypeEnum", GlueTypeEnum.values()); - - model.addAttribute("jobInfo", jobInfo); - model.addAttribute("jobLogGlues", jobLogGlues); - return "jobcode/jobcode.index"; - } - - @RequestMapping("/save") - @ResponseBody - public ReturnT save(HttpServletRequest request, @RequestParam("id") int id, - @RequestParam("glueSource") String glueSource, @RequestParam("glueRemark") String glueRemark) { - - // valid - if (glueRemark == null) { - return new ReturnT(500, - (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_remark"))); - } - if (glueRemark.length() < 4 || glueRemark.length() > 100) { - return new ReturnT(500, I18nUtil.getString("jobinfo_glue_remark_limit")); - } - XxlJobInfo existsJobInfo = xxlJobInfoDao.loadById(id); - if (existsJobInfo == null) { - return new ReturnT(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid")); - } - - // valid permission - PermissionInterceptor.validJobGroupPermission(request, existsJobInfo.getJobGroup()); - - // update new code - existsJobInfo.setGlueSource(glueSource); - existsJobInfo.setGlueRemark(glueRemark); - existsJobInfo.setGlueUpdatetime(new Date()); - - existsJobInfo.setUpdateTime(new Date()); - xxlJobInfoDao.update(existsJobInfo); - - // log old code - XxlJobLogGlue xxlJobLogGlue = new XxlJobLogGlue(); - xxlJobLogGlue.setJobId(existsJobInfo.getId()); - xxlJobLogGlue.setGlueType(existsJobInfo.getGlueType()); - xxlJobLogGlue.setGlueSource(glueSource); - xxlJobLogGlue.setGlueRemark(glueRemark); - - xxlJobLogGlue.setAddTime(new Date()); - xxlJobLogGlue.setUpdateTime(new Date()); - xxlJobLogGlueDao.save(xxlJobLogGlue); - - // remove code backup more than 30 - xxlJobLogGlueDao.removeOld(existsJobInfo.getId(), 30); - - return ReturnT.SUCCESS; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java deleted file mode 100644 index 6b4394b9c..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java +++ /dev/null @@ -1,213 +0,0 @@ -package com.xxl.job.admin.controller; - -import com.xxl.job.admin.controller.annotation.PermissionLimit; -import com.xxl.job.admin.core.model.XxlJobGroup; -import com.xxl.job.admin.core.model.XxlJobRegistry; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.admin.dao.XxlJobGroupDao; -import com.xxl.job.admin.dao.XxlJobInfoDao; -import com.xxl.job.admin.dao.XxlJobRegistryDao; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.enums.RegistryConfig; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import java.util.*; - -/** - * job group controller - * - * @author xuxueli 2016-10-02 20:52:56 - */ -@Controller -@RequestMapping("/jobgroup") -public class JobGroupController { - - @Resource - public XxlJobInfoDao xxlJobInfoDao; - - @Resource - public XxlJobGroupDao xxlJobGroupDao; - - @Resource - private XxlJobRegistryDao xxlJobRegistryDao; - - @RequestMapping - @PermissionLimit(adminuser = true) - public String index(Model model) { - return "jobgroup/jobgroup.index"; - } - - @RequestMapping("/pageList") - @ResponseBody - @PermissionLimit(adminuser = true) - public Map pageList(HttpServletRequest request, - @RequestParam(value = "start", required = false, defaultValue = "0") int start, - @RequestParam(value = "length", required = false, defaultValue = "10") int length, - @RequestParam("appname") String appname, @RequestParam("title") String title) { - - // page query - List list = xxlJobGroupDao.pageList(start, length, appname, title); - int list_count = xxlJobGroupDao.pageListCount(start, length, appname, title); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/save") - @ResponseBody - @PermissionLimit(adminuser = true) - public ReturnT save(XxlJobGroup xxlJobGroup) { - - // valid - if (xxlJobGroup.getAppname() == null || xxlJobGroup.getAppname().trim().length() == 0) { - return new ReturnT(500, (I18nUtil.getString("system_please_input") + "AppName")); - } - if (xxlJobGroup.getAppname().length() < 4 || xxlJobGroup.getAppname().length() > 64) { - return new ReturnT(500, I18nUtil.getString("jobgroup_field_appname_length")); - } - if (xxlJobGroup.getAppname().contains(">") || xxlJobGroup.getAppname().contains("<")) { - return new ReturnT(500, "AppName" + I18nUtil.getString("system_unvalid")); - } - if (xxlJobGroup.getTitle() == null || xxlJobGroup.getTitle().trim().length() == 0) { - return new ReturnT(500, - (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title"))); - } - if (xxlJobGroup.getTitle().contains(">") || xxlJobGroup.getTitle().contains("<")) { - return new ReturnT(500, - I18nUtil.getString("jobgroup_field_title") + I18nUtil.getString("system_unvalid")); - } - if (xxlJobGroup.getAddressType() != 0) { - if (xxlJobGroup.getAddressList() == null || xxlJobGroup.getAddressList().trim().length() == 0) { - return new ReturnT(500, I18nUtil.getString("jobgroup_field_addressType_limit")); - } - if (xxlJobGroup.getAddressList().contains(">") || xxlJobGroup.getAddressList().contains("<")) { - return new ReturnT(500, - I18nUtil.getString("jobgroup_field_registryList") + I18nUtil.getString("system_unvalid")); - } - - String[] addresss = xxlJobGroup.getAddressList().split(","); - for (String item : addresss) { - if (item == null || item.trim().length() == 0) { - return new ReturnT(500, I18nUtil.getString("jobgroup_field_registryList_unvalid")); - } - } - } - - // process - xxlJobGroup.setUpdateTime(new Date()); - - int ret = xxlJobGroupDao.save(xxlJobGroup); - return (ret > 0) ? ReturnT.SUCCESS : ReturnT.FAIL; - } - - @RequestMapping("/update") - @ResponseBody - @PermissionLimit(adminuser = true) - public ReturnT update(XxlJobGroup xxlJobGroup) { - // valid - if (xxlJobGroup.getAppname() == null || xxlJobGroup.getAppname().trim().length() == 0) { - return new ReturnT(500, (I18nUtil.getString("system_please_input") + "AppName")); - } - if (xxlJobGroup.getAppname().length() < 4 || xxlJobGroup.getAppname().length() > 64) { - return new ReturnT(500, I18nUtil.getString("jobgroup_field_appname_length")); - } - if (xxlJobGroup.getTitle() == null || xxlJobGroup.getTitle().trim().length() == 0) { - return new ReturnT(500, - (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title"))); - } - if (xxlJobGroup.getAddressType() == 0) { - // 0=自动注册 - List registryList = findRegistryByAppName(xxlJobGroup.getAppname()); - String addressListStr = null; - if (registryList != null && !registryList.isEmpty()) { - Collections.sort(registryList); - addressListStr = ""; - for (String item : registryList) { - addressListStr += item + ","; - } - addressListStr = addressListStr.substring(0, addressListStr.length() - 1); - } - xxlJobGroup.setAddressList(addressListStr); - } - else { - // 1=手动录入 - if (xxlJobGroup.getAddressList() == null || xxlJobGroup.getAddressList().trim().length() == 0) { - return new ReturnT(500, I18nUtil.getString("jobgroup_field_addressType_limit")); - } - String[] addresss = xxlJobGroup.getAddressList().split(","); - for (String item : addresss) { - if (item == null || item.trim().length() == 0) { - return new ReturnT(500, I18nUtil.getString("jobgroup_field_registryList_unvalid")); - } - } - } - - // process - xxlJobGroup.setUpdateTime(new Date()); - - int ret = xxlJobGroupDao.update(xxlJobGroup); - return (ret > 0) ? ReturnT.SUCCESS : ReturnT.FAIL; - } - - private List findRegistryByAppName(String appnameParam) { - HashMap> appAddressMap = new HashMap>(); - List list = xxlJobRegistryDao.findAll(RegistryConfig.DEAD_TIMEOUT, new Date()); - if (list != null) { - for (XxlJobRegistry item : list) { - if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) { - String appname = item.getRegistryKey(); - List registryList = appAddressMap.get(appname); - if (registryList == null) { - registryList = new ArrayList(); - } - - if (!registryList.contains(item.getRegistryValue())) { - registryList.add(item.getRegistryValue()); - } - appAddressMap.put(appname, registryList); - } - } - } - return appAddressMap.get(appnameParam); - } - - @RequestMapping("/remove") - @ResponseBody - @PermissionLimit(adminuser = true) - public ReturnT remove(@RequestParam("id") int id) { - - // valid - int count = xxlJobInfoDao.pageListCount(0, 10, id, -1, null, null, null); - if (count > 0) { - return new ReturnT(500, I18nUtil.getString("jobgroup_del_limit_0")); - } - - List allList = xxlJobGroupDao.findAll(); - if (allList.size() == 1) { - return new ReturnT(500, I18nUtil.getString("jobgroup_del_limit_1")); - } - - int ret = xxlJobGroupDao.remove(id); - return (ret > 0) ? ReturnT.SUCCESS : ReturnT.FAIL; - } - - @RequestMapping("/loadById") - @ResponseBody - @PermissionLimit(adminuser = true) - public ReturnT loadById(@RequestParam("id") int id) { - XxlJobGroup jobGroup = xxlJobGroupDao.load(id); - return jobGroup != null ? new ReturnT(jobGroup) - : new ReturnT(ReturnT.FAIL_CODE, null); - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java deleted file mode 100644 index f8e6e17c7..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java +++ /dev/null @@ -1,170 +0,0 @@ -package com.xxl.job.admin.controller; - -import com.xxl.job.admin.controller.interceptor.PermissionInterceptor; -import com.xxl.job.admin.core.exception.XxlJobException; -import com.xxl.job.admin.core.model.XxlJobGroup; -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.core.model.XxlJobUser; -import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; -import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum; -import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum; -import com.xxl.job.admin.core.thread.JobScheduleHelper; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.admin.dao.XxlJobGroupDao; -import com.xxl.job.admin.service.XxlJobService; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; -import com.xxl.job.core.glue.GlueTypeEnum; -import com.xxl.job.core.util.DateUtil; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - -/** - * index controller - * - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/jobinfo") -public class JobInfoController { - - private static Logger logger = LoggerFactory.getLogger(JobInfoController.class); - - @Resource - private XxlJobGroupDao xxlJobGroupDao; - - @Resource - private XxlJobService xxlJobService; - - @RequestMapping - public String index(HttpServletRequest request, Model model, - @RequestParam(value = "jobGroup", required = false, defaultValue = "-1") int jobGroup) { - - // 枚举-字典 - model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values()); // 路由策略-列表 - model.addAttribute("GlueTypeEnum", GlueTypeEnum.values()); // Glue类型-字典 - model.addAttribute("ExecutorBlockStrategyEnum", ExecutorBlockStrategyEnum.values()); // 阻塞处理策略-字典 - model.addAttribute("ScheduleTypeEnum", ScheduleTypeEnum.values()); // 调度类型 - model.addAttribute("MisfireStrategyEnum", MisfireStrategyEnum.values()); // 调度过期策略 - - // 执行器列表 - List jobGroupList_all = xxlJobGroupDao.findAll(); - - // filter group - List jobGroupList = PermissionInterceptor.filterJobGroupByRole(request, jobGroupList_all); - if (jobGroupList == null || jobGroupList.size() == 0) { - throw new XxlJobException(I18nUtil.getString("jobgroup_empty")); - } - - model.addAttribute("JobGroupList", jobGroupList); - model.addAttribute("jobGroup", jobGroup); - - return "jobinfo/jobinfo.index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(value = "start", required = false, defaultValue = "0") int start, - @RequestParam(value = "length", required = false, defaultValue = "10") int length, - @RequestParam("jobGroup") int jobGroup, @RequestParam("triggerStatus") int triggerStatus, - @RequestParam("jobDesc") String jobDesc, @RequestParam("executorHandler") String executorHandler, - @RequestParam("author") String author) { - - return xxlJobService.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author); - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request, XxlJobInfo jobInfo) { - // valid permission - PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup()); - - // opt - XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request); - return xxlJobService.add(jobInfo, loginUser); - } - - @RequestMapping("/update") - @ResponseBody - public ReturnT update(HttpServletRequest request, XxlJobInfo jobInfo) { - // valid permission - PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup()); - - // opt - XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request); - return xxlJobService.update(jobInfo, loginUser); - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(@RequestParam("id") int id) { - return xxlJobService.remove(id); - } - - @RequestMapping("/stop") - @ResponseBody - public ReturnT pause(@RequestParam("id") int id) { - return xxlJobService.stop(id); - } - - @RequestMapping("/start") - @ResponseBody - public ReturnT start(@RequestParam("id") int id) { - return xxlJobService.start(id); - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(HttpServletRequest request, @RequestParam("id") int id, - @RequestParam("executorParam") String executorParam, @RequestParam("addressList") String addressList) { - - // login user - XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request); - // trigger - return xxlJobService.trigger(loginUser, id, executorParam, addressList); - } - - @RequestMapping("/nextTriggerTime") - @ResponseBody - public ReturnT> nextTriggerTime(@RequestParam("scheduleType") String scheduleType, - @RequestParam("scheduleConf") String scheduleConf) { - - XxlJobInfo paramXxlJobInfo = new XxlJobInfo(); - paramXxlJobInfo.setScheduleType(scheduleType); - paramXxlJobInfo.setScheduleConf(scheduleConf); - - List result = new ArrayList<>(); - try { - Date lastTime = new Date(); - for (int i = 0; i < 5; i++) { - lastTime = JobScheduleHelper.generateNextValidTime(paramXxlJobInfo, lastTime); - if (lastTime != null) { - result.add(DateUtil.formatDateTime(lastTime)); - } - else { - break; - } - } - } - catch (Exception e) { - logger.error("nextTriggerTime error. scheduleType = {}, scheduleConf= {}", scheduleType, scheduleConf, e); - return new ReturnT>(ReturnT.FAIL_CODE, - (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")) + e.getMessage()); - } - return new ReturnT>(result); - - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java deleted file mode 100644 index 66cfc2810..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java +++ /dev/null @@ -1,312 +0,0 @@ -package com.xxl.job.admin.controller; - -import com.xxl.job.admin.controller.interceptor.PermissionInterceptor; -import com.xxl.job.admin.core.complete.XxlJobCompleter; -import com.xxl.job.admin.core.exception.XxlJobException; -import com.xxl.job.admin.core.model.XxlJobGroup; -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.core.model.XxlJobLog; -import com.xxl.job.admin.core.scheduler.XxlJobScheduler; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.admin.dao.XxlJobGroupDao; -import com.xxl.job.admin.dao.XxlJobInfoDao; -import com.xxl.job.admin.dao.XxlJobLogDao; -import com.xxl.job.core.biz.ExecutorBiz; -import com.xxl.job.core.biz.model.KillParam; -import com.xxl.job.core.biz.model.LogParam; -import com.xxl.job.core.biz.model.LogResult; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.util.DateUtil; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.util.StringUtils; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.util.HtmlUtils; - -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * index controller - * - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/joblog") -public class JobLogController { - - private static Logger logger = LoggerFactory.getLogger(JobLogController.class); - - @Resource - private XxlJobGroupDao xxlJobGroupDao; - - @Resource - public XxlJobInfoDao xxlJobInfoDao; - - @Resource - public XxlJobLogDao xxlJobLogDao; - - @RequestMapping - public String index(HttpServletRequest request, Model model, - @RequestParam(value = "jobId", required = false, defaultValue = "0") Integer jobId) { - - // 执行器列表 - List jobGroupList_all = xxlJobGroupDao.findAll(); - - // filter group - List jobGroupList = PermissionInterceptor.filterJobGroupByRole(request, jobGroupList_all); - if (jobGroupList == null || jobGroupList.size() == 0) { - throw new XxlJobException(I18nUtil.getString("jobgroup_empty")); - } - - model.addAttribute("JobGroupList", jobGroupList); - - // 任务 - if (jobId > 0) { - XxlJobInfo jobInfo = xxlJobInfoDao.loadById(jobId); - if (jobInfo == null) { - throw new RuntimeException( - I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_unvalid")); - } - - model.addAttribute("jobInfo", jobInfo); - - // valid permission - PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup()); - } - - return "joblog/joblog.index"; - } - - @RequestMapping("/getJobsByGroup") - @ResponseBody - public ReturnT> getJobsByGroup(@RequestParam("jobGroup") int jobGroup) { - List list = xxlJobInfoDao.getJobsByGroup(jobGroup); - return new ReturnT>(list); - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(HttpServletRequest request, - @RequestParam(value = "start", required = false, defaultValue = "0") int start, - @RequestParam(value = "length", required = false, defaultValue = "10") int length, - @RequestParam("jobGroup") int jobGroup, @RequestParam("jobId") int jobId, - @RequestParam("logStatus") int logStatus, @RequestParam("filterTime") String filterTime) { - - // valid permission - PermissionInterceptor.validJobGroupPermission(request, jobGroup); // 仅管理员支持查询全部;普通用户仅支持查询有权限的 - // jobGroup - - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (filterTime != null && filterTime.trim().length() > 0) { - String[] temp = filterTime.split(" - "); - if (temp.length == 2) { - triggerTimeStart = DateUtil.parseDateTime(temp[0]); - triggerTimeEnd = DateUtil.parseDateTime(temp[1]); - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, - logStatus); - int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, - logStatus); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/logDetailPage") - public String logDetailPage(HttpServletRequest request, @RequestParam("id") int id, Model model) { - - // base check - XxlJobLog jobLog = xxlJobLogDao.load(id); - if (jobLog == null) { - throw new RuntimeException(I18nUtil.getString("joblog_logid_unvalid")); - } - - // valid permission - PermissionInterceptor.validJobGroupPermission(request, jobLog.getJobGroup()); - - // data - model.addAttribute("triggerCode", jobLog.getTriggerCode()); - model.addAttribute("handleCode", jobLog.getHandleCode()); - model.addAttribute("logId", jobLog.getId()); - return "joblog/joblog.detail"; - } - - @RequestMapping("/logDetailCat") - @ResponseBody - public ReturnT logDetailCat(@RequestParam("logId") long logId, - @RequestParam("fromLineNum") int fromLineNum) { - try { - // valid - XxlJobLog jobLog = xxlJobLogDao.load(logId); // todo, need to improve - // performance - if (jobLog == null) { - return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_logid_unvalid")); - } - - // log cat - ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(jobLog.getExecutorAddress()); - ReturnT logResult = executorBiz - .log(new LogParam(jobLog.getTriggerTime().getTime(), logId, fromLineNum)); - - // is end - if (logResult.getContent() != null - && logResult.getContent().getFromLineNum() > logResult.getContent().getToLineNum()) { - if (jobLog.getHandleCode() > 0) { - logResult.getContent().setEnd(true); - } - } - - // fix xss - if (logResult.getContent() != null && StringUtils.hasText(logResult.getContent().getLogContent())) { - String newLogContent = filter(logResult.getContent().getLogContent()); - logResult.getContent().setLogContent(newLogContent); - } - - return logResult; - } - catch (Exception e) { - logger.error(e.getMessage(), e); - return new ReturnT(ReturnT.FAIL_CODE, e.getMessage()); - } - } - - /** - * filter xss tag - * @param originData - * @return - */ - private String filter(String originData) { - - // exclude tag - Map excludeTagMap = new HashMap(); - excludeTagMap.put("
", "###TAG_BR###"); - excludeTagMap.put("", "###TAG_BOLD###"); - excludeTagMap.put("", "###TAG_BOLD_END###"); - - // replace - for (String key : excludeTagMap.keySet()) { - String value = excludeTagMap.get(key); - originData = originData.replaceAll(key, value); - } - - // htmlEscape - originData = HtmlUtils.htmlEscape(originData, "UTF-8"); - - // replace back - for (String key : excludeTagMap.keySet()) { - String value = excludeTagMap.get(key); - originData = originData.replaceAll(value, key); - } - - return originData; - } - - @RequestMapping("/logKill") - @ResponseBody - public ReturnT logKill(@RequestParam("id") int id) { - // base check - XxlJobLog log = xxlJobLogDao.load(id); - XxlJobInfo jobInfo = xxlJobInfoDao.loadById(log.getJobId()); - if (jobInfo == null) { - return new ReturnT(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid")); - } - if (ReturnT.SUCCESS_CODE != log.getTriggerCode()) { - return new ReturnT(500, I18nUtil.getString("joblog_kill_log_limit")); - } - - // request of kill - ReturnT runResult = null; - try { - ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(log.getExecutorAddress()); - runResult = executorBiz.kill(new KillParam(jobInfo.getId())); - } - catch (Exception e) { - logger.error(e.getMessage(), e); - runResult = new ReturnT(500, e.getMessage()); - } - - if (ReturnT.SUCCESS_CODE == runResult.getCode()) { - log.setHandleCode(ReturnT.FAIL_CODE); - log.setHandleMsg(I18nUtil.getString("joblog_kill_log_byman") + ":" - + (runResult.getMsg() != null ? runResult.getMsg() : "")); - log.setHandleTime(new Date()); - XxlJobCompleter.updateHandleInfoAndFinish(log); - return new ReturnT(runResult.getMsg()); - } - else { - return new ReturnT(500, runResult.getMsg()); - } - } - - @RequestMapping("/clearLog") - @ResponseBody - public ReturnT clearLog(HttpServletRequest request, @RequestParam("jobGroup") int jobGroup, - @RequestParam("jobId") int jobId, @RequestParam("type") int type) { - // valid permission - PermissionInterceptor.validJobGroupPermission(request, jobGroup); - - // opt - Date clearBeforeTime = null; - int clearBeforeNum = 0; - if (type == 1) { - clearBeforeTime = DateUtil.addMonths(new Date(), -1); // 清理一个月之前日志数据 - } - else if (type == 2) { - clearBeforeTime = DateUtil.addMonths(new Date(), -3); // 清理三个月之前日志数据 - } - else if (type == 3) { - clearBeforeTime = DateUtil.addMonths(new Date(), -6); // 清理六个月之前日志数据 - } - else if (type == 4) { - clearBeforeTime = DateUtil.addYears(new Date(), -1); // 清理一年之前日志数据 - } - else if (type == 5) { - clearBeforeNum = 1000; // 清理一千条以前日志数据 - } - else if (type == 6) { - clearBeforeNum = 10000; // 清理一万条以前日志数据 - } - else if (type == 7) { - clearBeforeNum = 30000; // 清理三万条以前日志数据 - } - else if (type == 8) { - clearBeforeNum = 100000; // 清理十万条以前日志数据 - } - else if (type == 9) { - clearBeforeNum = 0; // 清理所有日志数据 - } - else { - return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_clean_type_unvalid")); - } - - List logIds = null; - do { - logIds = xxlJobLogDao.findClearLogIds(jobGroup, jobId, clearBeforeTime, clearBeforeNum, 1000); - if (logIds != null && logIds.size() > 0) { - xxlJobLogDao.clearLog(logIds); - } - } - while (logIds != null && logIds.size() > 0); - - return ReturnT.SUCCESS; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobUserController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobUserController.java deleted file mode 100644 index 5b14525f5..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobUserController.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.xxl.job.admin.controller; - -import com.xxl.job.admin.controller.annotation.PermissionLimit; -import com.xxl.job.admin.controller.interceptor.PermissionInterceptor; -import com.xxl.job.admin.core.model.XxlJobGroup; -import com.xxl.job.admin.core.model.XxlJobUser; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.admin.dao.XxlJobGroupDao; -import com.xxl.job.admin.dao.XxlJobUserDao; -import com.xxl.job.core.biz.model.ReturnT; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.util.DigestUtils; -import org.springframework.util.StringUtils; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @author xuxueli 2019-05-04 16:39:50 - */ -@Controller -@RequestMapping("/user") -public class JobUserController { - - @Resource - private XxlJobUserDao xxlJobUserDao; - - @Resource - private XxlJobGroupDao xxlJobGroupDao; - - @RequestMapping - @PermissionLimit(adminuser = true) - public String index(Model model) { - - // 执行器列表 - List groupList = xxlJobGroupDao.findAll(); - model.addAttribute("groupList", groupList); - - return "user/user.index"; - } - - @RequestMapping("/pageList") - @ResponseBody - @PermissionLimit(adminuser = true) - public Map pageList(@RequestParam(value = "start", required = false, defaultValue = "0") int start, - @RequestParam(value = "length", required = false, defaultValue = "10") int length, - @RequestParam("username") String username, @RequestParam("role") int role) { - - // page list - List list = xxlJobUserDao.pageList(start, length, username, role); - int list_count = xxlJobUserDao.pageListCount(start, length, username, role); - - // filter - if (list != null && list.size() > 0) { - for (XxlJobUser item : list) { - item.setPassword(null); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - @PermissionLimit(adminuser = true) - public ReturnT add(XxlJobUser xxlJobUser) { - - // valid username - if (!StringUtils.hasText(xxlJobUser.getUsername())) { - return new ReturnT(ReturnT.FAIL_CODE, - I18nUtil.getString("system_please_input") + I18nUtil.getString("user_username")); - } - xxlJobUser.setUsername(xxlJobUser.getUsername().trim()); - if (!(xxlJobUser.getUsername().length() >= 4 && xxlJobUser.getUsername().length() <= 20)) { - return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]"); - } - // valid password - if (!StringUtils.hasText(xxlJobUser.getPassword())) { - return new ReturnT(ReturnT.FAIL_CODE, - I18nUtil.getString("system_please_input") + I18nUtil.getString("user_password")); - } - xxlJobUser.setPassword(xxlJobUser.getPassword().trim()); - if (!(xxlJobUser.getPassword().length() >= 4 && xxlJobUser.getPassword().length() <= 20)) { - return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]"); - } - // md5 password - xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes())); - - // check repeat - XxlJobUser existUser = xxlJobUserDao.loadByUserName(xxlJobUser.getUsername()); - if (existUser != null) { - return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("user_username_repeat")); - } - - // write - xxlJobUserDao.save(xxlJobUser); - return ReturnT.SUCCESS; - } - - @RequestMapping("/update") - @ResponseBody - @PermissionLimit(adminuser = true) - public ReturnT update(HttpServletRequest request, XxlJobUser xxlJobUser) { - - // avoid opt login seft - XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request); - if (loginUser.getUsername().equals(xxlJobUser.getUsername())) { - return new ReturnT(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit")); - } - - // valid password - if (StringUtils.hasText(xxlJobUser.getPassword())) { - xxlJobUser.setPassword(xxlJobUser.getPassword().trim()); - if (!(xxlJobUser.getPassword().length() >= 4 && xxlJobUser.getPassword().length() <= 20)) { - return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]"); - } - // md5 password - xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes())); - } - else { - xxlJobUser.setPassword(null); - } - - // write - xxlJobUserDao.update(xxlJobUser); - return ReturnT.SUCCESS; - } - - @RequestMapping("/remove") - @ResponseBody - @PermissionLimit(adminuser = true) - public ReturnT remove(HttpServletRequest request, @RequestParam("id") int id) { - - // avoid opt login seft - XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request); - if (loginUser.getId() == id) { - return new ReturnT(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit")); - } - - xxlJobUserDao.delete(id); - return ReturnT.SUCCESS; - } - - @RequestMapping("/updatePwd") - @ResponseBody - public ReturnT updatePwd(HttpServletRequest request, @RequestParam("password") String password, - @RequestParam("oldPassword") String oldPassword) { - - // valid - if (oldPassword == null || oldPassword.trim().length() == 0) { - return new ReturnT(ReturnT.FAIL.getCode(), - I18nUtil.getString("system_please_input") + I18nUtil.getString("change_pwd_field_oldpwd")); - } - if (password == null || password.trim().length() == 0) { - return new ReturnT(ReturnT.FAIL.getCode(), - I18nUtil.getString("system_please_input") + I18nUtil.getString("change_pwd_field_oldpwd")); - } - password = password.trim(); - if (!(password.length() >= 4 && password.length() <= 20)) { - return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]"); - } - - // md5 password - String md5OldPassword = DigestUtils.md5DigestAsHex(oldPassword.getBytes()); - String md5Password = DigestUtils.md5DigestAsHex(password.getBytes()); - - // valid old pwd - XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request); - XxlJobUser existUser = xxlJobUserDao.loadByUserName(loginUser.getUsername()); - if (!md5OldPassword.equals(existUser.getPassword())) { - return new ReturnT(ReturnT.FAIL.getCode(), - I18nUtil.getString("change_pwd_field_oldpwd") + I18nUtil.getString("system_unvalid")); - } - - // write new - existUser.setPassword(md5Password); - xxlJobUserDao.update(existUser); - - return ReturnT.SUCCESS; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/annotation/PermissionLimit.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/annotation/PermissionLimit.java deleted file mode 100644 index e60ea1ccc..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/annotation/PermissionLimit.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.xxl.job.admin.controller.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * 权限限制 - * - * @author xuxueli 2015-12-12 18:29:02 - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface PermissionLimit { - - /** - * 登录拦截 (默认拦截) - */ - boolean limit() default true; - - /** - * 要求管理员权限 - * @return - */ - boolean adminuser() default false; - -} \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/base/IndexController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/base/IndexController.java new file mode 100644 index 000000000..4b00df558 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/base/IndexController.java @@ -0,0 +1,127 @@ +package com.xxl.job.admin.controller.base; + +import com.xxl.job.admin.constant.Consts; +import com.xxl.job.admin.model.dto.XxlBootResourceDTO; +import com.xxl.job.admin.service.XxlJobService; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.sso.core.annotation.XxlSso; +import com.xxl.sso.core.helper.XxlSsoHelper; +import com.xxl.sso.core.model.LoginInfo; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.response.Response; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; + +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; + +/** + * index controller + * + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +public class IndexController { + + @Resource + private XxlJobService xxlJobService; + + /** + * index + */ + @RequestMapping("/") + @XxlSso + public String index(HttpServletRequest request, Model model) { + + // menu resource + List resourceList = findResourceList(request); + model.addAttribute("resourceList", resourceList); + + return "base/index"; + } + + /** + * fill menu data + */ + private List findResourceList(HttpServletRequest request) { + // login check + Response loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request); + // init menu-list + List resourceDTOList = Arrays.asList( + new XxlBootResourceDTO(1, 0, I18nUtil.getString("job_dashboard_name"), 1, "", "/dashboard", "fa-home", 1, 0, null), + new XxlBootResourceDTO(2, 0, I18nUtil.getString("jobinfo_name"), 1, "", "/jobinfo", " fa-clock-o", 2, 0, null), + new XxlBootResourceDTO(3, 0, I18nUtil.getString("joblog_name"), 1, "", "/joblog", " fa-database", 3, 0, null), + new XxlBootResourceDTO(4, 0, I18nUtil.getString("jobgroup_name"), 1, Consts.ADMIN_ROLE, "/jobgroup", " fa-cloud", 4, 0, null), + new XxlBootResourceDTO(5, 0, I18nUtil.getString("user_manage"), 1, Consts.ADMIN_ROLE, "/user", "fa-users", 5, 0, null), + new XxlBootResourceDTO(9, 0, I18nUtil.getString("admin_help"), 1, "", "/help", "fa-book", 6, 0, null) + ); + + // filter by role + if (!XxlSsoHelper.hasRole(loginInfoResponse.getData(), Consts.ADMIN_ROLE).isSuccess()) { + resourceDTOList = resourceDTOList.stream() + .filter(resourceDTO -> StringTool.isBlank(resourceDTO.getPermission())) // normal user had no permission + .collect(Collectors.toList()); + } + resourceDTOList.stream().sorted(Comparator.comparing(XxlBootResourceDTO::getOrder)).toList(); + return resourceDTOList; + } + + /** + * dashboard + */ + @RequestMapping("/dashboard") + @XxlSso + public String dashboard(HttpServletRequest request, Model model) { + + Map dashboardMap = xxlJobService.dashboardInfo(); + model.addAllAttributes(dashboardMap); + + return "base/dashboard"; + } + + @RequestMapping("/chartInfo") + @ResponseBody + public Response> chartInfo(@RequestParam("startDate") Date startDate, @RequestParam("endDate") Date endDate) { + Response> chartInfo = xxlJobService.chartInfo(startDate, endDate); + return chartInfo; + } + + /** + * help + */ + @RequestMapping("/help") + @XxlSso + public String help() { + return "base/help"; + } + + @RequestMapping(value = "/errorpage") + @XxlSso(login = false) + public ModelAndView errorPage(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) { + + String exceptionMsg = "HTTP Status Code: " + response.getStatus(); + + mv.addObject("exceptionMsg", exceptionMsg); + mv.setViewName("common/common.errorpage"); + return mv; + } + + @InitBinder + public void initBinder(WebDataBinder binder) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/base/LoginController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/base/LoginController.java new file mode 100644 index 000000000..1a1b10f03 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/base/LoginController.java @@ -0,0 +1,125 @@ +package com.xxl.job.admin.controller.base; + +import com.xxl.job.admin.mapper.XxlJobUserMapper; +import com.xxl.job.admin.model.XxlJobUser; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.sso.core.annotation.XxlSso; +import com.xxl.sso.core.helper.XxlSsoHelper; +import com.xxl.sso.core.model.LoginInfo; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.crypto.Sha256Tool; +import com.xxl.tool.id.UUIDTool; +import com.xxl.tool.response.Response; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.view.RedirectView; + +/** + * index controller + * + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/auth") +public class LoginController { + + @Resource + private XxlJobUserMapper xxlJobUserMapper; + + @RequestMapping("/login") + @XxlSso(login = false) + public ModelAndView login(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) { + + // xxl-sso, logincheck + Response loginInfoResponse = XxlSsoHelper.loginCheckWithCookie(request, response); + + if (loginInfoResponse.isSuccess()) { + modelAndView.setView(new RedirectView("/", true, false)); + return modelAndView; + } + return new ModelAndView("base/login"); + } + + @RequestMapping(value = "/doLogin", method = RequestMethod.POST) + @ResponseBody + @XxlSso(login = false) + public Response doLogin(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember) { + + // param + boolean ifRem = StringTool.isNotBlank(ifRemember) && "on".equals(ifRemember); + if (StringTool.isBlank(userName) || StringTool.isBlank(password)) { + return Response.ofFail(I18nUtil.getString("login_param_empty")); + } + + // valid user、status + XxlJobUser xxlJobUser = xxlJobUserMapper.loadByUserName(userName); + if (xxlJobUser == null) { + return Response.ofFail(I18nUtil.getString("login_param_invalid")); + } + + // valid passowrd + String passwordHash = Sha256Tool.sha256(password); + if (!passwordHash.equals(xxlJobUser.getPassword())) { + return Response.ofFail(I18nUtil.getString("login_param_invalid")); + } + + // xxl-sso, do login + LoginInfo loginInfo = new LoginInfo(String.valueOf(xxlJobUser.getId()), UUIDTool.getSimpleUUID()); + Response result = XxlSsoHelper.loginWithCookie(loginInfo, response, ifRem); + + return Response.of(result.getCode(), result.getMsg()); + } + + @RequestMapping(value = "/logout", method = RequestMethod.POST) + @ResponseBody + @XxlSso(login = false) + public Response logout(HttpServletRequest request, HttpServletResponse response) { + + // xxl-sso, do logout + Response result = XxlSsoHelper.logoutWithCookie(request, response); + + return Response.of(result.getCode(), result.getMsg()); + } + + @RequestMapping("/updatePwd") + @ResponseBody + @XxlSso + public Response updatePwd(HttpServletRequest request, String oldPassword, String password) { + + // valid + if (oldPassword == null || oldPassword.trim().isEmpty()) { + return Response.ofFail(I18nUtil.getString("system_please_input") + I18nUtil.getString("change_pwd_field_oldpwd")); + } + if (password == null || password.trim().isEmpty()) { + return Response.ofFail(I18nUtil.getString("system_please_input") + I18nUtil.getString("change_pwd_field_oldpwd")); + } + password = password.trim(); + if (!(password.length() >= 4 && password.length() <= 20)) { + return Response.ofFail(I18nUtil.getString("system_length_limit") + "[4-20]"); + } + + // md5 password + String oldPasswordHash = Sha256Tool.sha256(oldPassword); + String passwordHash = Sha256Tool.sha256(password); + + // valid old pwd + Response loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request); + XxlJobUser existUser = xxlJobUserMapper.loadByUserName(loginInfoResponse.getData().getUserName()); + if (!oldPasswordHash.equals(existUser.getPassword())) { + return Response.ofFail(I18nUtil.getString("change_pwd_field_oldpwd") + I18nUtil.getString("system_invalid")); + } + + // write new + existUser.setPassword(passwordHash); + xxlJobUserMapper.update(existUser); + + return Response.ofSuccess(); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobCodeController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobCodeController.java new file mode 100644 index 000000000..4b9372f30 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobCodeController.java @@ -0,0 +1,118 @@ +package com.xxl.job.admin.controller.biz; + +import com.xxl.job.admin.mapper.XxlJobInfoMapper; +import com.xxl.job.admin.mapper.XxlJobLogGlueMapper; +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.model.XxlJobLogGlue; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.job.admin.util.JobGroupPermissionUtil; +import com.xxl.job.core.glue.GlueTypeEnum; +import com.xxl.sso.core.model.LoginInfo; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.json.GsonTool; +import com.xxl.tool.response.Response; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.Date; +import java.util.List; + +/** + * job code controller + * + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobcode") +public class JobCodeController { + private static final Logger logger = LoggerFactory.getLogger(JobCodeController.class); + + @Resource + private XxlJobInfoMapper xxlJobInfoMapper; + @Resource + private XxlJobLogGlueMapper xxlJobLogGlueMapper; + + @RequestMapping + public String index(HttpServletRequest request, Model model, @RequestParam("jobId") int jobId) { + XxlJobInfo jobInfo = xxlJobInfoMapper.loadById(jobId); + List jobLogGlues = xxlJobLogGlueMapper.findByJobId(jobId); + + if (jobInfo == null) { + throw new RuntimeException(I18nUtil.getString("jobinfo_glue_jobid_invalid")); + } + if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType())) { + throw new RuntimeException(I18nUtil.getString("jobinfo_glue_gluetype_invalid")); + } + + // valid jobGroup permission + JobGroupPermissionUtil.validJobGroupPermission(request, jobInfo.getJobGroup()); + + // Glue类型-字典 + model.addAttribute("GlueTypeEnum", GlueTypeEnum.values()); + + model.addAttribute("jobInfo", jobInfo); + model.addAttribute("jobLogGlues", jobLogGlues); + return "biz/job.code"; + } + + @RequestMapping("/save") + @ResponseBody + public Response save(HttpServletRequest request, + @RequestParam("id") int id, + @RequestParam("glueSource") String glueSource, + @RequestParam("glueRemark") String glueRemark) { + + // valid + if (StringTool.isBlank(glueSource)) { + return Response.ofFail((I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_source"))); + } + if (glueRemark == null) { + return Response.ofFail((I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_remark"))); + } + if (glueRemark.length() < 4 || glueRemark.length() > 100) { + return Response.ofFail(I18nUtil.getString("jobinfo_glue_remark_limit")); + } + XxlJobInfo existsJobInfo = xxlJobInfoMapper.loadById(id); + if (existsJobInfo == null) { + return Response.ofFail(I18nUtil.getString("jobinfo_glue_jobid_invalid")); + } + + // valid jobGroup permission + LoginInfo loginInfo = JobGroupPermissionUtil.validJobGroupPermission(request, existsJobInfo.getJobGroup()); + + // update new code + existsJobInfo.setGlueSource(glueSource); + existsJobInfo.setGlueRemark(glueRemark); + existsJobInfo.setGlueUpdatetime(new Date()); + + existsJobInfo.setUpdateTime(new Date()); + xxlJobInfoMapper.update(existsJobInfo); + + // log old code + XxlJobLogGlue xxlJobLogGlue = new XxlJobLogGlue(); + xxlJobLogGlue.setJobId(existsJobInfo.getId()); + xxlJobLogGlue.setGlueType(existsJobInfo.getGlueType()); + xxlJobLogGlue.setGlueSource(glueSource); + xxlJobLogGlue.setGlueRemark(glueRemark); + + xxlJobLogGlue.setAddTime(new Date()); + xxlJobLogGlue.setUpdateTime(new Date()); + xxlJobLogGlueMapper.save(xxlJobLogGlue); + + // remove code backup more than 30 + xxlJobLogGlueMapper.removeOld(existsJobInfo.getId(), 30); + + // write operation log + logger.info(">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}", + loginInfo.getUserName(), "jobcode-update", GsonTool.toJson(xxlJobLogGlue)); + return Response.ofSuccess(); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobGroupController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobGroupController.java new file mode 100644 index 000000000..9d96feb92 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobGroupController.java @@ -0,0 +1,226 @@ +package com.xxl.job.admin.controller.biz; + +import com.xxl.job.admin.constant.Consts; +import com.xxl.job.admin.mapper.XxlJobGroupMapper; +import com.xxl.job.admin.mapper.XxlJobInfoMapper; +import com.xxl.job.admin.mapper.XxlJobRegistryMapper; +import com.xxl.job.admin.model.XxlJobGroup; +import com.xxl.job.admin.model.XxlJobRegistry; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.job.core.constant.Const; +import com.xxl.job.core.constant.RegistType; +import com.xxl.sso.core.annotation.XxlSso; +import com.xxl.tool.core.CollectionTool; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.http.HttpTool; +import com.xxl.tool.response.PageModel; +import com.xxl.tool.response.Response; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.*; + +/** + * job group controller + * + * @author xuxueli 2016-10-02 20:52:56 + */ +@Controller +@RequestMapping("/jobgroup") +public class JobGroupController { + + @Resource + public XxlJobInfoMapper xxlJobInfoMapper; + @Resource + public XxlJobGroupMapper xxlJobGroupMapper; + @Resource + private XxlJobRegistryMapper xxlJobRegistryMapper; + + @RequestMapping + @XxlSso(role = Consts.ADMIN_ROLE) + public String index(Model model) { + return "biz/group.list"; + } + + @RequestMapping("/pageList") + @ResponseBody + @XxlSso(role = Consts.ADMIN_ROLE) + public Response> pageList(@RequestParam(required = false, defaultValue = "0") int offset, + @RequestParam(required = false, defaultValue = "10") int pagesize, + String appname, + String title) { + + // page query + List list = xxlJobGroupMapper.pageList(offset, pagesize, appname, title); + int list_count = xxlJobGroupMapper.pageListCount(offset, pagesize, appname, title); + + // package result + PageModel pageModel = new PageModel<>(); + pageModel.setData(list); + pageModel.setTotal(list_count); + + return Response.ofSuccess(pageModel); + } + + @RequestMapping("/insert") + @ResponseBody + @XxlSso(role = Consts.ADMIN_ROLE) + public Response insert(XxlJobGroup xxlJobGroup) { + + // valid + if (StringTool.isBlank(xxlJobGroup.getAppname())) { + return Response.ofFail((I18nUtil.getString("system_please_input") + "AppName")); + } + if (xxlJobGroup.getAppname().length() < 4 || xxlJobGroup.getAppname().length() > 64) { + return Response.ofFail(I18nUtil.getString("jobgroup_field_appname_length")); + } + if (xxlJobGroup.getAppname().contains(">") || xxlJobGroup.getAppname().contains("<")) { + return Response.ofFail("AppName" + I18nUtil.getString("system_invalid")); + } + if (StringTool.isBlank(xxlJobGroup.getTitle())) { + return Response.ofFail((I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title"))); + } + if (xxlJobGroup.getTitle().contains(">") || xxlJobGroup.getTitle().contains("<")) { + return Response.ofFail(I18nUtil.getString("jobgroup_field_title") + I18nUtil.getString("system_invalid")); + } + if (xxlJobGroup.getAddressType() != 0) { + if (StringTool.isBlank(xxlJobGroup.getAddressList())) { + return Response.ofFail(I18nUtil.getString("jobgroup_field_addressType_limit")); + } + if (xxlJobGroup.getAddressList().contains(">") || xxlJobGroup.getAddressList().contains("<")) { + return Response.ofFail(I18nUtil.getString("jobgroup_field_registryList") + I18nUtil.getString("system_invalid")); + } + + String[] addresss = xxlJobGroup.getAddressList().split(","); + for (String item : addresss) { + if (StringTool.isBlank(item)) { + return Response.ofFail(I18nUtil.getString("jobgroup_field_registryList_invalid")); + } + if (!(HttpTool.isHttp(item) || HttpTool.isHttps(item))) { + return Response.ofFail(I18nUtil.getString("jobgroup_field_registryList_invalid") + "[2]"); + } + } + } + + // process + xxlJobGroup.setUpdateTime(new Date()); + + int ret = xxlJobGroupMapper.save(xxlJobGroup); + return (ret > 0) ? Response.ofSuccess() : Response.ofFail(); + } + + @RequestMapping("/update") + @ResponseBody + @XxlSso(role = Consts.ADMIN_ROLE) + public Response update(XxlJobGroup xxlJobGroup) { + // valid + if (StringTool.isBlank(xxlJobGroup.getAppname())) { + return Response.ofFail((I18nUtil.getString("system_please_input") + "AppName")); + } + if (xxlJobGroup.getAppname().length() < 4 || xxlJobGroup.getAppname().length() > 64) { + return Response.ofFail(I18nUtil.getString("jobgroup_field_appname_length")); + } + if (StringTool.isBlank(xxlJobGroup.getTitle())) { + return Response.ofFail((I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title"))); + } + if (xxlJobGroup.getAddressType() == 0) { + // 0=自动注册 + List registryList = findRegistryByAppName(xxlJobGroup.getAppname()); + String addressListStr = null; + if (CollectionTool.isNotEmpty(registryList)) { + Collections.sort(registryList); + addressListStr = String.join(",", registryList); + } + xxlJobGroup.setAddressList(addressListStr); + } else { + // 1=手动录入 + if (StringTool.isBlank(xxlJobGroup.getAddressList())) { + return Response.ofFail(I18nUtil.getString("jobgroup_field_addressType_limit")); + } + String[] addresss = xxlJobGroup.getAddressList().split(","); + for (String item : addresss) { + if (StringTool.isBlank(item)) { + return Response.ofFail(I18nUtil.getString("jobgroup_field_registryList_invalid")); + } + if (!(HttpTool.isHttp(item) || HttpTool.isHttps(item))) { + return Response.ofFail(I18nUtil.getString("jobgroup_field_registryList_invalid") + "[2]"); + } + } + } + + // process + xxlJobGroup.setUpdateTime(new Date()); + + int ret = xxlJobGroupMapper.update(xxlJobGroup); + return (ret > 0) ? Response.ofSuccess() : Response.ofFail(); + } + + private List findRegistryByAppName(String appnameParam) { + HashMap> appAddressMap = new HashMap<>(); + List list = xxlJobRegistryMapper.findAll(Const.DEAD_TIMEOUT, new Date()); + if (CollectionTool.isNotEmpty(list)) { + for (XxlJobRegistry item : list) { + if (!RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) { + continue; + } + + String appname = item.getRegistryKey(); + List registryList = appAddressMap.computeIfAbsent(appname, k -> new ArrayList<>()); + + if (!registryList.contains(item.getRegistryValue())) { + registryList.add(item.getRegistryValue()); + } + } + } + return appAddressMap.get(appnameParam); + } + + @RequestMapping("/delete") + @ResponseBody + @XxlSso(role = Consts.ADMIN_ROLE) + public Response delete(@RequestParam("ids[]") List ids) { + + // parse id + if (CollectionTool.isEmpty(ids) || ids.size() != 1) { + return Response.ofFail(I18nUtil.getString("system_please_choose") + I18nUtil.getString("system_one") + I18nUtil.getString("system_data")); + } + int id = ids.get(0); + + // valid repeat operation + XxlJobGroup xxlJobGroup = xxlJobGroupMapper.load(id); + if (xxlJobGroup == null) { + return Response.ofSuccess(); + } + + // whether exists job + int count = xxlJobInfoMapper.pageListCount(0, 10, id, -1, null, null, null); + if (count > 0) { + return Response.ofFail(I18nUtil.getString("jobgroup_del_limit_0")); + } + + // whether only exists one group + List allList = xxlJobGroupMapper.findAll(); + if (allList.size() == 1) { + return Response.ofFail(I18nUtil.getString("jobgroup_del_limit_1")); + } + + // remove group + int ret = xxlJobGroupMapper.remove(id); + // remove registry-data + xxlJobRegistryMapper.removeByRegistryGroupAndKey(RegistType.EXECUTOR.name(), xxlJobGroup.getAppname()); + return (ret > 0) ? Response.ofSuccess() : Response.ofFail(); + } + + @RequestMapping("/loadById") + @ResponseBody + //@XxlSso(role = Consts.ADMIN_ROLE) // open to default user, support show registry nodes + public Response loadById(@RequestParam("id") int id) { + XxlJobGroup jobGroup = xxlJobGroupMapper.load(id); + return jobGroup != null ? Response.ofSuccess(jobGroup) : Response.ofFail(); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobInfoController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobInfoController.java new file mode 100644 index 000000000..c78b0b46a --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobInfoController.java @@ -0,0 +1,212 @@ +package com.xxl.job.admin.controller.biz; + +import com.xxl.job.admin.mapper.XxlJobGroupMapper; +import com.xxl.job.admin.model.XxlJobGroup; +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.scheduler.exception.XxlJobException; +import com.xxl.job.admin.scheduler.misfire.MisfireStrategyEnum; +import com.xxl.job.admin.scheduler.route.ExecutorRouteStrategyEnum; +import com.xxl.job.admin.scheduler.type.ScheduleTypeEnum; +import com.xxl.job.admin.service.XxlJobService; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.job.admin.util.JobGroupPermissionUtil; +import com.xxl.job.core.constant.ExecutorBlockStrategyEnum; +import com.xxl.job.core.glue.GlueTypeEnum; +import com.xxl.sso.core.helper.XxlSsoHelper; +import com.xxl.sso.core.model.LoginInfo; +import com.xxl.tool.core.CollectionTool; +import com.xxl.tool.core.DateTool; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.response.PageModel; +import com.xxl.tool.response.Response; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * index controller + * + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + private static Logger logger = LoggerFactory.getLogger(JobInfoController.class); + + @Resource + private XxlJobGroupMapper xxlJobGroupMapper; + @Resource + private XxlJobService xxlJobService; + + @RequestMapping + public String index(HttpServletRequest request, Model model, @RequestParam(value = "jobGroup", required = false, defaultValue = "-1") int jobGroup) { + + // 枚举-字典 + model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values()); // 路由策略-列表 + model.addAttribute("GlueTypeEnum", GlueTypeEnum.values()); // Glue类型-字典 + model.addAttribute("ExecutorBlockStrategyEnum", ExecutorBlockStrategyEnum.values()); // 阻塞处理策略-字典 + model.addAttribute("ScheduleTypeEnum", ScheduleTypeEnum.values()); // 调度类型 + model.addAttribute("MisfireStrategyEnum", MisfireStrategyEnum.values()); // 调度过期策略 + + // 执行器列表 + List jobGroupListTotal = xxlJobGroupMapper.findAll(); + + // filter group + List jobGroupList = JobGroupPermissionUtil.filterJobGroupByPermission(request, jobGroupListTotal); + if (CollectionTool.isEmpty(jobGroupList)) { + throw new XxlJobException(I18nUtil.getString("jobgroup_empty")); + } + + // parse jobGroup + if (!(CollectionTool.isNotEmpty(jobGroupList) + && jobGroupList.stream().map(XxlJobGroup::getId).toList().contains(jobGroup))) { + jobGroup = -1; + } + + model.addAttribute("JobGroupList", jobGroupList); + model.addAttribute("jobGroup", jobGroup); + + return "biz/job.list"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Response> pageList(HttpServletRequest request, + @RequestParam(required = false, defaultValue = "0") int offset, + @RequestParam(required = false, defaultValue = "10") int pagesize, + @RequestParam int jobGroup, + @RequestParam int triggerStatus, + @RequestParam String jobDesc, + @RequestParam String executorHandler, + @RequestParam String author) { + + // valid jobGroup permission + JobGroupPermissionUtil.validJobGroupPermission(request, jobGroup); + + // page + return xxlJobService.pageList(offset, pagesize, jobGroup, triggerStatus, jobDesc, executorHandler, author); + } + + @RequestMapping("/insert") + @ResponseBody + public Response add(HttpServletRequest request, XxlJobInfo jobInfo) { + // valid permission + LoginInfo loginInfo = JobGroupPermissionUtil.validJobGroupPermission(request, jobInfo.getJobGroup()); + + // opt + return xxlJobService.add(jobInfo, loginInfo); + } + + @RequestMapping("/update") + @ResponseBody + public Response update(HttpServletRequest request, XxlJobInfo jobInfo) { + // valid permission + LoginInfo loginInfo = JobGroupPermissionUtil.validJobGroupPermission(request, jobInfo.getJobGroup()); + + // opt + return xxlJobService.update(jobInfo, loginInfo); + } + + @RequestMapping("/delete") + @ResponseBody + public Response delete(HttpServletRequest request, @RequestParam("ids[]") List ids) { + + // valid + if (CollectionTool.isEmpty(ids) || ids.size() != 1) { + return Response.ofFail(I18nUtil.getString("system_please_choose") + I18nUtil.getString("system_one") + I18nUtil.getString("system_data")); + } + + // invoke + Response loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request); + return xxlJobService.remove(ids.get(0), loginInfoResponse.getData()); + } + + @RequestMapping("/stop") + @ResponseBody + public Response pause(HttpServletRequest request, @RequestParam("ids[]") List ids) { + + // valid + if (CollectionTool.isEmpty(ids) || ids.size() != 1) { + return Response.ofFail(I18nUtil.getString("system_please_choose") + I18nUtil.getString("system_one") + I18nUtil.getString("system_data")); + } + + // invoke + Response loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request); + return xxlJobService.stop(ids.get(0), loginInfoResponse.getData()); + } + + @RequestMapping("/start") + @ResponseBody + public Response start(HttpServletRequest request, @RequestParam("ids[]") List ids) { + + // valid + if (CollectionTool.isEmpty(ids) || ids.size() != 1) { + return Response.ofFail(I18nUtil.getString("system_please_choose") + I18nUtil.getString("system_one") + I18nUtil.getString("system_data")); + } + + // invoke + Response loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request); + return xxlJobService.start(ids.get(0), loginInfoResponse.getData()); + } + + @RequestMapping("/trigger") + @ResponseBody + public Response triggerJob(HttpServletRequest request, + @RequestParam("id") int id, + @RequestParam("executorParam") String executorParam, + @RequestParam("addressList") String addressList) { + Response loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request); + return xxlJobService.trigger(loginInfoResponse.getData(), id, executorParam, addressList); + } + + @RequestMapping("/nextTriggerTime") + @ResponseBody + public Response> nextTriggerTime(@RequestParam("scheduleType") String scheduleType, + @RequestParam("scheduleConf") String scheduleConf) { + + // valid + if (StringTool.isBlank(scheduleType) || StringTool.isBlank(scheduleConf)) { + return Response.ofSuccess(new ArrayList<>()); + } + + // param + XxlJobInfo paramXxlJobInfo = new XxlJobInfo(); + paramXxlJobInfo.setScheduleType(scheduleType); + paramXxlJobInfo.setScheduleConf(scheduleConf); + + // generate + List result = new ArrayList<>(); + try { + Date lastTime = new Date(); + for (int i = 0; i < 5; i++) { + + // generate next trigger time + ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(paramXxlJobInfo.getScheduleType(), ScheduleTypeEnum.NONE); + lastTime = scheduleTypeEnum.getScheduleType().generateNextTriggerTime(paramXxlJobInfo, lastTime); + + // collect data + if (lastTime != null) { + result.add(DateTool.formatDateTime(lastTime)); + } else { + break; + } + } + } catch (Exception e) { + logger.error(">>>>>>>>>>> nextTriggerTime error. scheduleType = {}, scheduleConf= {}, error:{} ", scheduleType, scheduleConf, e.getMessage()); + return Response.ofFail((I18nUtil.getString("schedule_type") + I18nUtil.getString("system_invalid")) + e.getMessage()); + } + return Response.ofSuccess(result); + + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobLogController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobLogController.java new file mode 100644 index 000000000..651e54b99 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobLogController.java @@ -0,0 +1,325 @@ +package com.xxl.job.admin.controller.biz; + +import com.xxl.job.admin.mapper.XxlJobGroupMapper; +import com.xxl.job.admin.mapper.XxlJobInfoMapper; +import com.xxl.job.admin.mapper.XxlJobLogMapper; +import com.xxl.job.admin.model.XxlJobGroup; +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.model.XxlJobLog; +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.admin.scheduler.exception.XxlJobException; +import com.xxl.job.admin.service.XxlJobService; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.job.admin.util.JobGroupPermissionUtil; +import com.xxl.job.core.context.XxlJobContext; +import com.xxl.job.core.openapi.ExecutorBiz; +import com.xxl.job.core.openapi.model.KillRequest; +import com.xxl.job.core.openapi.model.LogRequest; +import com.xxl.job.core.openapi.model.LogResult; +import com.xxl.tool.core.CollectionTool; +import com.xxl.tool.core.DateTool; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.response.PageModel; +import com.xxl.tool.response.Response; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.util.HtmlUtils; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * index controller + * + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/joblog") +public class JobLogController { + private static final Logger logger = LoggerFactory.getLogger(JobLogController.class); + + @Resource + private XxlJobGroupMapper xxlJobGroupMapper; + @Resource + public XxlJobInfoMapper xxlJobInfoMapper; + @Resource + public XxlJobLogMapper xxlJobLogMapper; + @Autowired + private XxlJobService xxlJobService; + + @RequestMapping + public String index(HttpServletRequest request, + Model model, + @RequestParam(value = "jobGroup", required = false, defaultValue = "0") Integer jobGroup, + @RequestParam(value = "jobId", required = false, defaultValue = "0") Integer jobId) { + + // 1、init JobGroupList + // find all jobGroup + List jobGroupListTotal = xxlJobGroupMapper.findAll(); + + // filter JobGroupList + List jobGroupList = JobGroupPermissionUtil.filterJobGroupByPermission(request, jobGroupListTotal); + if (CollectionTool.isEmpty(jobGroupList)) { + throw new XxlJobException(I18nUtil.getString("jobgroup_empty")); + } + List jobGroupIds = jobGroupList.stream().map(XxlJobGroup::getId).toList(); + + // 2、check jobId + if (jobId > 0) { + // valid jobId + XxlJobInfo jobInfo = xxlJobInfoMapper.loadById(jobId); + if (jobInfo == null) { + throw new RuntimeException(I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_invalid")); + } + // valid jobGroup + jobGroup = jobInfo.getJobGroup(); + } + + // 3、init jobGroup, default first 1 + if (!jobGroupIds.contains(jobGroup)) { + jobGroup = jobGroupList.get(0).getId(); + } + + // 4、init jobInfoList + List jobInfoList = xxlJobInfoMapper.getJobsByGroup(jobGroup); + List jobIds = jobInfoList.stream().map(XxlJobInfo::getId).toList(); + + // 5、init JobId, default 0 + if (!jobIds.contains(jobId)) { + jobId = 0; + } + + // write + model.addAttribute("JobGroupList", jobGroupList); + model.addAttribute("jobInfoList", jobInfoList); + model.addAttribute("jobGroup", jobGroup); + model.addAttribute("jobId", jobId); + + return "biz/log.list"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Response> pageList(HttpServletRequest request, + @RequestParam(required = false, defaultValue = "0") int offset, + @RequestParam(required = false, defaultValue = "10") int pagesize, + @RequestParam int jobGroup, + @RequestParam int jobId, + @RequestParam int logStatus, + @RequestParam String filterTime) { + + // valid jobGroup permission + JobGroupPermissionUtil.validJobGroupPermission(request, jobGroup); + + // valid jobId + /*if (jobId < 1) { + return Response.ofFail(I18nUtil.getString("system_please_choose") + I18nUtil.getString("jobinfo_job")); + }*/ + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringTool.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp.length == 2) { + triggerTimeStart = DateTool.parseDateTime(temp[0]); + triggerTimeEnd = DateTool.parseDateTime(temp[1]); + } + } + + // page query + List list = xxlJobLogMapper.pageList(offset, pagesize, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus); + int list_count = xxlJobLogMapper.pageListCount(offset, pagesize, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus); + + // package result + PageModel pageModel = new PageModel<>(); + pageModel.setData(list); + pageModel.setTotal(list_count); + + return Response.ofSuccess(pageModel); + } + + /** + * filter xss tag + */ + private String filter(String originData) { + + // exclude tag + Map excludeTagMap = new HashMap(); + excludeTagMap.put("
", "###TAG_BR###"); + excludeTagMap.put("", "###TAG_BOLD###"); + excludeTagMap.put("", "###TAG_BOLD_END###"); + + // replace + for (String key : excludeTagMap.keySet()) { + String value = excludeTagMap.get(key); + originData = originData.replaceAll(key, value); + } + + // htmlEscape + originData = HtmlUtils.htmlEscape(originData, "UTF-8"); + + // replace back + for (String key : excludeTagMap.keySet()) { + String value = excludeTagMap.get(key); + originData = originData.replaceAll(value, key); + } + + return originData; + } + + @RequestMapping("/logKill") + @ResponseBody + public Response logKill(HttpServletRequest request, @RequestParam("id") long id) { + // base check + XxlJobLog log = xxlJobLogMapper.load(id); + XxlJobInfo jobInfo = xxlJobInfoMapper.loadById(log.getJobId()); + if (jobInfo == null) { + return Response.ofFail(I18nUtil.getString("jobinfo_glue_jobid_invalid")); + } + if (XxlJobContext.HANDLE_CODE_SUCCESS != log.getTriggerCode()) { + return Response.ofFail(I18nUtil.getString("joblog_kill_log_limit")); + } + + // valid JobGroup permission + JobGroupPermissionUtil.validJobGroupPermission(request, jobInfo.getJobGroup()); + + // request of kill + Response runResult = null; + try { + ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(log.getExecutorAddress()); + runResult = executorBiz.kill(new KillRequest(jobInfo.getId())); + } catch (Exception e) { + logger.error(e.getMessage(), e); + runResult = Response.ofFail(e.getMessage()); + } + + if (XxlJobContext.HANDLE_CODE_SUCCESS == runResult.getCode()) { + log.setHandleCode(XxlJobContext.HANDLE_CODE_FAIL); + log.setHandleMsg(I18nUtil.getString("joblog_kill_log_byman") + ":" + (runResult.getMsg() != null ? runResult.getMsg() : "")); + log.setHandleTime(new Date()); + XxlJobAdminBootstrap.getInstance().getJobCompleter().complete(log); + return Response.ofSuccess(runResult.getMsg()); + } else { + return Response.ofFail(runResult.getMsg()); + } + } + + @RequestMapping("/clearLog") + @ResponseBody + public Response clearLog(HttpServletRequest request, + @RequestParam("jobGroup") int jobGroup, + @RequestParam("jobId") int jobId, + @RequestParam("type") int type) { + // valid JobGroup permission + JobGroupPermissionUtil.validJobGroupPermission(request, jobGroup); + + // valid jobId + /*if (jobId < 1) { + return Response.ofFail(I18nUtil.getString("system_please_choose") + I18nUtil.getString("jobinfo_job")); + }*/ + + // opt + Date clearBeforeTime = null; + int clearBeforeNum = 0; + if (type == 1) { + clearBeforeTime = DateTool.addMonths(new Date(), -1); // 清理一个月之前日志数据 + } else if (type == 2) { + clearBeforeTime = DateTool.addMonths(new Date(), -3); // 清理三个月之前日志数据 + } else if (type == 3) { + clearBeforeTime = DateTool.addMonths(new Date(), -6); // 清理六个月之前日志数据 + } else if (type == 4) { + clearBeforeTime = DateTool.addYears(new Date(), -1); // 清理一年之前日志数据 + } else if (type == 5) { + clearBeforeNum = 1000; // 清理一千条以前日志数据 + } else if (type == 6) { + clearBeforeNum = 10000; // 清理一万条以前日志数据 + } else if (type == 7) { + clearBeforeNum = 30000; // 清理三万条以前日志数据 + } else if (type == 8) { + clearBeforeNum = 100000; // 清理十万条以前日志数据 + } else if (type == 9) { + clearBeforeNum = 0; // 清理所有日志数据 + } else { + return Response.ofFail(I18nUtil.getString("joblog_clean_type_invalid")); + } + + List logIds = null; + do { + logIds = xxlJobLogMapper.findClearLogIds(jobGroup, jobId, clearBeforeTime, clearBeforeNum, 1000); + if (logIds != null && !logIds.isEmpty()) { + xxlJobLogMapper.clearLog(logIds); + } + } while (logIds != null && !logIds.isEmpty()); + + return Response.ofSuccess(); + } + + @RequestMapping("/logDetailPage") + public String logDetailPage(HttpServletRequest request, @RequestParam("id") long id, Model model) { + + // base check + XxlJobLog jobLog = xxlJobLogMapper.load(id); + if (jobLog == null) { + throw new RuntimeException(I18nUtil.getString("joblog_logid_invalid")); + } + + // valid permission + JobGroupPermissionUtil.validJobGroupPermission(request, jobLog.getJobGroup()); + + // load jobInfo + XxlJobInfo jobInfo = xxlJobInfoMapper.loadById(jobLog.getJobId()); + + // data + model.addAttribute("triggerCode", jobLog.getTriggerCode()); + model.addAttribute("handleCode", jobLog.getHandleCode()); + model.addAttribute("logId", jobLog.getId()); + model.addAttribute("jobInfo", jobInfo); + return "biz/log.detail"; + } + + @RequestMapping("/logDetailCat") + @ResponseBody + public Response logDetailCat(@RequestParam("logId") long logId, @RequestParam("fromLineNum") int fromLineNum) { + try { + // valid + XxlJobLog jobLog = xxlJobLogMapper.load(logId); // todo, need to improve performance + if (jobLog == null) { + return Response.ofFail(I18nUtil.getString("joblog_logid_invalid")); + } + + // log cat + ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(jobLog.getExecutorAddress()); + Response logResult = executorBiz.log(new LogRequest(jobLog.getTriggerTime().getTime(), logId, fromLineNum)); + + // is end + if (logResult.getData() != null && logResult.getData().getFromLineNum() > logResult.getData().getToLineNum()) { + if (jobLog.getHandleCode() > 0) { + logResult.getData().setEnd(true); + } + } + + // fix xss + if (logResult.getData() != null && StringTool.isNotBlank(logResult.getData().getLogContent())) { + String newLogContent = filter(logResult.getData().getLogContent()); + logResult.getData().setLogContent(newLogContent); + } + + return logResult; + } catch (Exception e) { + logger.error("logId({}) logDetailCat error: {}", logId, e.getMessage(), e); + return Response.ofFail(e.getMessage()); + } + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobUserController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobUserController.java new file mode 100644 index 000000000..164eb6a8e --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobUserController.java @@ -0,0 +1,198 @@ +package com.xxl.job.admin.controller.biz; + +import com.xxl.job.admin.constant.Consts; +import com.xxl.job.admin.mapper.XxlJobGroupMapper; +import com.xxl.job.admin.mapper.XxlJobUserMapper; +import com.xxl.job.admin.model.XxlJobGroup; +import com.xxl.job.admin.model.XxlJobUser; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.sso.core.annotation.XxlSso; +import com.xxl.sso.core.helper.XxlSsoHelper; +import com.xxl.sso.core.model.LoginInfo; +import com.xxl.tool.core.CollectionTool; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.crypto.Sha256Tool; +import com.xxl.tool.response.PageModel; +import com.xxl.tool.response.Response; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.List; + +/** + * @author xuxueli 2019-05-04 16:39:50 + */ +@Controller +@RequestMapping("/user") +public class JobUserController { + + @Resource + private XxlJobUserMapper xxlJobUserMapper; + @Resource + private XxlJobGroupMapper xxlJobGroupMapper; + + @RequestMapping + @XxlSso(role = Consts.ADMIN_ROLE) + public String index(Model model) { + + // 执行器列表 + List groupList = xxlJobGroupMapper.findAll(); + model.addAttribute("groupList", groupList); + + return "biz/user.list"; + } + + @RequestMapping("/pageList") + @ResponseBody + @XxlSso(role = Consts.ADMIN_ROLE) + public Response> pageList(@RequestParam(required = false, defaultValue = "0") int offset, + @RequestParam(required = false, defaultValue = "10") int pagesize, + @RequestParam String username, + @RequestParam int role) { + + // page list + List list = xxlJobUserMapper.pageList(offset, pagesize, username, role); + int list_count = xxlJobUserMapper.pageListCount(offset, pagesize, username, role); + + // filter + if (list != null && !list.isEmpty()) { + for (XxlJobUser item : list) { + item.setPassword(null); + } + } + + // package result + PageModel pageModel = new PageModel<>(); + pageModel.setData(list); + pageModel.setTotal(list_count); + + return Response.ofSuccess(pageModel); + } + + @RequestMapping("/insert") + @ResponseBody + @XxlSso(role = Consts.ADMIN_ROLE) + public Response insert(XxlJobUser xxlJobUser) { + + // valid username + if (StringTool.isBlank(xxlJobUser.getUsername())) { + return Response.ofFail(I18nUtil.getString("system_please_input") + I18nUtil.getString("user_username")); + } + xxlJobUser.setUsername(xxlJobUser.getUsername().trim()); + if (!(xxlJobUser.getUsername().length() >= 4 && xxlJobUser.getUsername().length() <= 20)) { + return Response.ofFail(I18nUtil.getString("system_length_limit") + "[4-20]"); + } + // valid password + if (StringTool.isBlank(xxlJobUser.getPassword())) { + return Response.ofFail(I18nUtil.getString("system_please_input") + I18nUtil.getString("user_password")); + } + xxlJobUser.setPassword(xxlJobUser.getPassword().trim()); + if (!(xxlJobUser.getPassword().length() >= 4 && xxlJobUser.getPassword().length() <= 20)) { + return Response.ofFail(I18nUtil.getString("system_length_limit") + "[4-20]"); + } + // md5 password + String passwordHash = Sha256Tool.sha256(xxlJobUser.getPassword()); + xxlJobUser.setPassword(passwordHash); + + // check repeat + XxlJobUser existUser = xxlJobUserMapper.loadByUserName(xxlJobUser.getUsername()); + if (existUser != null) { + return Response.ofFail(I18nUtil.getString("user_username_repeat")); + } + + // write + xxlJobUserMapper.save(xxlJobUser); + return Response.ofSuccess(); + } + + @RequestMapping("/update") + @ResponseBody + @XxlSso(role = Consts.ADMIN_ROLE) + public Response update(HttpServletRequest request, XxlJobUser xxlJobUser) { + + // avoid opt login seft + Response loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request); + if (loginInfoResponse.getData().getUserName().equals(xxlJobUser.getUsername())) { + return Response.ofFail(I18nUtil.getString("user_update_loginuser_limit")); + } + + // valid password + if (StringTool.isNotBlank(xxlJobUser.getPassword())) { + xxlJobUser.setPassword(xxlJobUser.getPassword().trim()); + if (!(xxlJobUser.getPassword().length() >= 4 && xxlJobUser.getPassword().length() <= 20)) { + return Response.ofFail(I18nUtil.getString("system_length_limit") + "[4-20]"); + } + // md5 password + String passwordHash = Sha256Tool.sha256(xxlJobUser.getPassword()); + xxlJobUser.setPassword(passwordHash); + } else { + xxlJobUser.setPassword(null); + } + + // write + xxlJobUserMapper.update(xxlJobUser); + return Response.ofSuccess(); + } + + @RequestMapping("/delete") + @ResponseBody + @XxlSso(role = Consts.ADMIN_ROLE) + public Response delete(HttpServletRequest request, @RequestParam("ids[]") List ids) { + + // valid + if (CollectionTool.isEmpty(ids) || ids.size() != 1) { + return Response.ofFail(I18nUtil.getString("system_please_choose") + I18nUtil.getString("system_one") + I18nUtil.getString("system_data")); + } + + // avoid opt login seft + Response loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request); + if (ids.contains(Integer.parseInt(loginInfoResponse.getData().getUserId()))) { + return Response.ofFail(I18nUtil.getString("user_update_loginuser_limit")); + } + + xxlJobUserMapper.delete(ids.get(0)); + return Response.ofSuccess(); + } + + /*@RequestMapping("/updatePwd") + @ResponseBody + public Response updatePwd(HttpServletRequest request, + @RequestParam("password") String password, + @RequestParam("oldPassword") String oldPassword){ + + // valid + if (oldPassword==null || oldPassword.trim().isEmpty()){ + return Response.ofFail(I18nUtil.getString("system_please_input") + I18nUtil.getString("change_pwd_field_oldpwd")); + } + if (password==null || password.trim().isEmpty()){ + return Response.ofFail(I18nUtil.getString("system_please_input") + I18nUtil.getString("change_pwd_field_oldpwd")); + } + password = password.trim(); + if (!(password.length()>=4 && password.length()<=20)) { + return Response.ofFail(I18nUtil.getString("system_length_limit")+"[4-20]" ); + } + + // md5 password + String oldPasswordHash = Sha256Tool.sha256(oldPassword); + String passwordHash = Sha256Tool.sha256(password); + + // valid old pwd + Response loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request); + XxlJobUser existUser = xxlJobUserMapper.loadByUserName(loginInfoResponse.getData().getUserName()); + if (!oldPasswordHash.equals(existUser.getPassword())) { + return Response.ofFail(I18nUtil.getString("change_pwd_field_oldpwd") + I18nUtil.getString("system_invalid")); + } + + // write new + existUser.setPassword(passwordHash); + xxlJobUserMapper.update(existUser); + + return Response.ofSuccess(); + }*/ + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java deleted file mode 100644 index baf09bccc..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.xxl.job.admin.controller.interceptor; - -import com.xxl.job.admin.core.util.FtlUtil; -import com.xxl.job.admin.core.util.I18nUtil; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.stereotype.Component; -import org.springframework.web.servlet.AsyncHandlerInterceptor; -import org.springframework.web.servlet.ModelAndView; - -import java.util.HashMap; - -/** - * push cookies to model as cookieMap - * - * @author xuxueli 2015-12-12 18:09:04 - */ -@Component -public class CookieInterceptor implements AsyncHandlerInterceptor { - - @Override - public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, - ModelAndView modelAndView) throws Exception { - - // cookie - if (modelAndView != null && request.getCookies() != null && request.getCookies().length > 0) { - HashMap cookieMap = new HashMap(); - for (Cookie ck : request.getCookies()) { - cookieMap.put(ck.getName(), ck); - } - modelAndView.addObject("cookieMap", cookieMap); - } - - // static method - if (modelAndView != null) { - modelAndView.addObject("I18nUtil", FtlUtil.generateStaticModel(I18nUtil.class.getName())); - } - - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java deleted file mode 100644 index 4a5c8859f..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.xxl.job.admin.controller.interceptor; - -import com.xxl.job.admin.controller.annotation.PermissionLimit; -import com.xxl.job.admin.core.model.XxlJobGroup; -import com.xxl.job.admin.core.model.XxlJobUser; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.admin.service.impl.LoginService; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.stereotype.Component; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.AsyncHandlerInterceptor; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * 权限拦截 - * - * @author xuxueli 2015-12-12 18:09:04 - */ -@Component -public class PermissionInterceptor implements AsyncHandlerInterceptor { - - @Resource - private LoginService loginService; - - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) - throws Exception { - - if (!(handler instanceof HandlerMethod)) { - return true; // proceed with the next interceptor - } - - // if need login - boolean needLogin = true; - boolean needAdminuser = false; - HandlerMethod method = (HandlerMethod) handler; - PermissionLimit permission = method.getMethodAnnotation(PermissionLimit.class); - if (permission != null) { - needLogin = permission.limit(); - needAdminuser = permission.adminuser(); - } - - if (needLogin) { - XxlJobUser loginUser = loginService.ifLogin(request, response); - if (loginUser == null) { - response.setStatus(302); - response.setHeader("location", request.getContextPath() + "/toLogin"); - return false; - } - if (needAdminuser && loginUser.getRole() != 1) { - throw new RuntimeException(I18nUtil.getString("system_permission_limit")); - } - - // set loginUser, with request - setLoginUser(request, loginUser); - } - - return true; // proceed with the next interceptor - } - - // -------------------- permission tool -------------------- - - /** - * set loginUser - * @param request - * @param loginUser - */ - private static void setLoginUser(HttpServletRequest request, XxlJobUser loginUser) { - request.setAttribute("loginUser", loginUser); - } - - /** - * get loginUser - * @param request - * @return - */ - public static XxlJobUser getLoginUser(HttpServletRequest request) { - XxlJobUser loginUser = (XxlJobUser) request.getAttribute("loginUser"); // get - // loginUser, - // with - // request - return loginUser; - } - - /** - * valid permission by JobGroup - * @param request - * @param jobGroup - */ - public static void validJobGroupPermission(HttpServletRequest request, int jobGroup) { - XxlJobUser loginUser = getLoginUser(request); - if (!loginUser.validPermission(jobGroup)) { - throw new RuntimeException( - I18nUtil.getString("system_permission_limit") + "[username=" + loginUser.getUsername() + "]"); - } - } - - /** - * filter XxlJobGroup by role - * @param request - * @param jobGroupList_all - * @return - */ - public static List filterJobGroupByRole(HttpServletRequest request, - List jobGroupList_all) { - List jobGroupList = new ArrayList<>(); - if (jobGroupList_all != null && jobGroupList_all.size() > 0) { - XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request); - if (loginUser.getRole() == 1) { - jobGroupList = jobGroupList_all; - } - else { - List groupIdStrs = new ArrayList<>(); - if (loginUser.getPermission() != null && loginUser.getPermission().trim().length() > 0) { - groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(",")); - } - for (XxlJobGroup groupItem : jobGroupList_all) { - if (groupIdStrs.contains(String.valueOf(groupItem.getId()))) { - jobGroupList.add(groupItem); - } - } - } - } - return jobGroupList; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java deleted file mode 100644 index a84e3d3ba..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.xxl.job.admin.controller.interceptor; - -import jakarta.annotation.Resource; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -/** - * web mvc config - * - * @author xuxueli 2018-04-02 20:48:20 - */ -@Configuration -public class WebMvcConfig implements WebMvcConfigurer { - - @Resource - private PermissionInterceptor permissionInterceptor; - - @Resource - private CookieInterceptor cookieInterceptor; - - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(permissionInterceptor).addPathPatterns("/**"); - registry.addInterceptor(cookieInterceptor).addPathPatterns("/**"); - } - -} \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarm.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarm.java deleted file mode 100644 index a4d40ab90..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarm.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.xxl.job.admin.core.alarm; - -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.core.model.XxlJobLog; - -/** - * @author xuxueli 2020-01-19 - */ -public interface JobAlarm { - - /** - * job alarm - * @param info - * @param jobLog - * @return - */ - public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog); - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarmer.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarmer.java deleted file mode 100644 index ca05c1858..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarmer.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.xxl.job.admin.core.alarm; - -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.core.model.XxlJobLog; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -@Component -public class JobAlarmer implements ApplicationContextAware, InitializingBean { - - private static Logger logger = LoggerFactory.getLogger(JobAlarmer.class); - - private ApplicationContext applicationContext; - - private List jobAlarmList; - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - @Override - public void afterPropertiesSet() throws Exception { - Map serviceBeanMap = applicationContext.getBeansOfType(JobAlarm.class); - if (serviceBeanMap != null && serviceBeanMap.size() > 0) { - jobAlarmList = new ArrayList(serviceBeanMap.values()); - } - } - - /** - * job alarm - * @param info - * @param jobLog - * @return - */ - public boolean alarm(XxlJobInfo info, XxlJobLog jobLog) { - - boolean result = false; - if (jobAlarmList != null && jobAlarmList.size() > 0) { - result = true; // success means all-success - for (JobAlarm alarm : jobAlarmList) { - boolean resultItem = false; - try { - resultItem = alarm.doAlarm(info, jobLog); - } - catch (Exception e) { - logger.error(e.getMessage(), e); - } - if (!resultItem) { - result = false; - } - } - } - - return result; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/impl/EmailJobAlarm.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/impl/EmailJobAlarm.java deleted file mode 100644 index c169dc535..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/impl/EmailJobAlarm.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.xxl.job.admin.core.alarm.impl; - -import com.xxl.job.admin.core.alarm.JobAlarm; -import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -import com.xxl.job.admin.core.model.XxlJobGroup; -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.core.model.XxlJobLog; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.core.biz.model.ReturnT; -import jakarta.mail.internet.MimeMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.mail.javamail.MimeMessageHelper; -import org.springframework.stereotype.Component; - -import java.text.MessageFormat; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -/** - * job alarm by email - * - * @author xuxueli 2020-01-19 - */ -@Component -public class EmailJobAlarm implements JobAlarm { - - private static Logger logger = LoggerFactory.getLogger(EmailJobAlarm.class); - - /** - * fail alarm - * @param jobLog - */ - @Override - public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog) { - boolean alarmResult = true; - - // send monitor email - if (info != null && info.getAlarmEmail() != null && info.getAlarmEmail().trim().length() > 0) { - - // alarmContent - String alarmContent = "Alarm Job LogId=" + jobLog.getId(); - if (jobLog.getTriggerCode() != ReturnT.SUCCESS_CODE) { - alarmContent += "
TriggerMsg=
" + jobLog.getTriggerMsg(); - } - if (jobLog.getHandleCode() > 0 && jobLog.getHandleCode() != ReturnT.SUCCESS_CODE) { - alarmContent += "
HandleCode=" + jobLog.getHandleMsg(); - } - - // email info - XxlJobGroup group = XxlJobAdminConfig.getAdminConfig() - .getXxlJobGroupDao() - .load(Integer.valueOf(info.getJobGroup())); - String personal = I18nUtil.getString("admin_name_full"); - String title = I18nUtil.getString("jobconf_monitor"); - String content = MessageFormat.format(loadEmailJobAlarmTemplate(), - group != null ? group.getTitle() : "null", info.getId(), info.getJobDesc(), alarmContent); - - Set emailSet = new HashSet(Arrays.asList(info.getAlarmEmail().split(","))); - for (String email : emailSet) { - - // make mail - try { - MimeMessage mimeMessage = XxlJobAdminConfig.getAdminConfig().getMailSender().createMimeMessage(); - - MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); - helper.setFrom(XxlJobAdminConfig.getAdminConfig().getEmailFrom(), personal); - helper.setTo(email); - helper.setSubject(title); - helper.setText(content, true); - - XxlJobAdminConfig.getAdminConfig().getMailSender().send(mimeMessage); - } - catch (Exception e) { - logger.error(">>>>>>>>>>> xxl-job, job fail alarm email send error, JobLogId:{}", jobLog.getId(), - e); - - alarmResult = false; - } - - } - } - - return alarmResult; - } - - /** - * load email job alarm template - * @return - */ - private static final String loadEmailJobAlarmTemplate() { - String mailBodyTemplate = "
" + I18nUtil.getString("jobconf_monitor_detail") + ":" - + "\n" - + " " + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" + " \n" + " \n" + " \n" + " \n" - + " \n" + " \n" + " \n" + " \n" - + " \n" + " \n" + "
" + I18nUtil.getString("jobinfo_field_jobgroup") + "" + I18nUtil.getString("jobinfo_field_id") + "" + I18nUtil.getString("jobinfo_field_jobdesc") + "" + I18nUtil.getString("jobconf_monitor_alarm_title") + "" + I18nUtil.getString("jobconf_monitor_alarm_content") + "
{0}{1}{2}" - + I18nUtil.getString("jobconf_monitor_alarm_type") + "{3}
"; - - return mailBodyTemplate; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/complete/XxlJobCompleter.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/complete/XxlJobCompleter.java deleted file mode 100644 index 88798244d..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/complete/XxlJobCompleter.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.xxl.job.admin.core.complete; - -import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.core.model.XxlJobLog; -import com.xxl.job.admin.core.thread.JobTriggerPoolHelper; -import com.xxl.job.admin.core.trigger.TriggerTypeEnum; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.context.XxlJobContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.text.MessageFormat; - -/** - * @author xuxueli 2020-10-30 20:43:10 - */ -public class XxlJobCompleter { - - private static Logger logger = LoggerFactory.getLogger(XxlJobCompleter.class); - - /** - * common fresh handle entrance (limit only once) - * @param xxlJobLog - * @return - */ - public static int updateHandleInfoAndFinish(XxlJobLog xxlJobLog) { - - // finish - finishJob(xxlJobLog); - - // text最大64kb 避免长度过长 - if (xxlJobLog.getHandleMsg().length() > 15000) { - xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg().substring(0, 15000)); - } - - // fresh handle - return XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateHandleInfo(xxlJobLog); - } - - /** - * do somethind to finish job - */ - private static void finishJob(XxlJobLog xxlJobLog) { - - // 1、handle success, to trigger child job - String triggerChildMsg = null; - if (XxlJobContext.HANDLE_CODE_SUCCESS == xxlJobLog.getHandleCode()) { - XxlJobInfo xxlJobInfo = XxlJobAdminConfig.getAdminConfig() - .getXxlJobInfoDao() - .loadById(xxlJobLog.getJobId()); - if (xxlJobInfo != null && xxlJobInfo.getChildJobId() != null - && xxlJobInfo.getChildJobId().trim().length() > 0) { - triggerChildMsg = "

>>>>>>>>>>>" - + I18nUtil.getString("jobconf_trigger_child_run") + "<<<<<<<<<<<
"; - - String[] childJobIds = xxlJobInfo.getChildJobId().split(","); - for (int i = 0; i < childJobIds.length; i++) { - int childJobId = (childJobIds[i] != null && childJobIds[i].trim().length() > 0 - && isNumeric(childJobIds[i])) ? Integer.valueOf(childJobIds[i]) : -1; - if (childJobId > 0) { - // valid - if (childJobId == xxlJobLog.getJobId()) { - logger.debug( - ">>>>>>>>>>> xxl-job, XxlJobCompleter-finishJob ignore childJobId, childJobId {} is self.", - childJobId); - continue; - } - - // trigger child job - JobTriggerPoolHelper.trigger(childJobId, TriggerTypeEnum.PARENT, -1, null, null, null); - ReturnT triggerChildResult = ReturnT.SUCCESS; - - // add msg - triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"), - (i + 1), childJobIds.length, childJobIds[i], - (triggerChildResult.getCode() == ReturnT.SUCCESS_CODE - ? I18nUtil.getString("system_success") : I18nUtil.getString("system_fail")), - triggerChildResult.getMsg()); - } - else { - triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"), - (i + 1), childJobIds.length, childJobIds[i]); - } - } - - } - } - - if (triggerChildMsg != null) { - xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg() + triggerChildMsg); - } - - // 2、fix_delay trigger next - // on the way - - } - - private static boolean isNumeric(String str) { - try { - int result = Integer.valueOf(str); - return true; - } - catch (NumberFormatException e) { - return false; - } - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java deleted file mode 100644 index 3220f86d4..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java +++ /dev/null @@ -1,170 +0,0 @@ -package com.xxl.job.admin.core.conf; - -import com.xxl.job.admin.core.alarm.JobAlarmer; -import com.xxl.job.admin.core.scheduler.XxlJobScheduler; -import com.xxl.job.admin.dao.*; -import jakarta.annotation.Resource; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.mail.javamail.JavaMailSender; -import org.springframework.stereotype.Component; - -import javax.sql.DataSource; -import java.util.Arrays; - -/** - * xxl-job config - * - * @author xuxueli 2017-04-28 - */ - -@Component -public class XxlJobAdminConfig implements InitializingBean, DisposableBean { - - private static XxlJobAdminConfig adminConfig = null; - - public static XxlJobAdminConfig getAdminConfig() { - return adminConfig; - } - - // ---------------------- XxlJobScheduler ---------------------- - - private XxlJobScheduler xxlJobScheduler; - - @Override - public void afterPropertiesSet() throws Exception { - adminConfig = this; - - xxlJobScheduler = new XxlJobScheduler(); - xxlJobScheduler.init(); - } - - @Override - public void destroy() throws Exception { - xxlJobScheduler.destroy(); - } - - // ---------------------- XxlJobScheduler ---------------------- - - // conf - @Value("${xxl.job.i18n}") - private String i18n; - - @Value("${xxl.job.accessToken:}") - private String accessToken; - - @Value("${xxl.job.timeout:3}") - private int timeout; - - @Value("${spring.mail.from}") - private String emailFrom; - - @Value("${xxl.job.triggerpool.fast.max}") - private int triggerPoolFastMax; - - @Value("${xxl.job.triggerpool.slow.max}") - private int triggerPoolSlowMax; - - @Value("${xxl.job.logretentiondays}") - private int logretentiondays; - - // dao, service - - @Resource - private XxlJobLogDao xxlJobLogDao; - - @Resource - private XxlJobInfoDao xxlJobInfoDao; - - @Resource - private XxlJobRegistryDao xxlJobRegistryDao; - - @Resource - private XxlJobGroupDao xxlJobGroupDao; - - @Resource - private XxlJobLogReportDao xxlJobLogReportDao; - - @Resource - private JavaMailSender mailSender; - - @Resource - private DataSource dataSource; - - @Resource - private JobAlarmer jobAlarmer; - - public String getI18n() { - if (!Arrays.asList("zh_CN", "zh_TC", "en").contains(i18n)) { - return "zh_CN"; - } - return i18n; - } - - public String getAccessToken() { - return accessToken; - } - - public int getTimeout() { - return timeout; - } - - public String getEmailFrom() { - return emailFrom; - } - - public int getTriggerPoolFastMax() { - if (triggerPoolFastMax < 200) { - return 200; - } - return triggerPoolFastMax; - } - - public int getTriggerPoolSlowMax() { - if (triggerPoolSlowMax < 100) { - return 100; - } - return triggerPoolSlowMax; - } - - public int getLogretentiondays() { - if (logretentiondays < 3) { - return -1; // Limit greater than or equal to 3, otherwise close - } - return logretentiondays; - } - - public XxlJobLogDao getXxlJobLogDao() { - return xxlJobLogDao; - } - - public XxlJobInfoDao getXxlJobInfoDao() { - return xxlJobInfoDao; - } - - public XxlJobRegistryDao getXxlJobRegistryDao() { - return xxlJobRegistryDao; - } - - public XxlJobGroupDao getXxlJobGroupDao() { - return xxlJobGroupDao; - } - - public XxlJobLogReportDao getXxlJobLogReportDao() { - return xxlJobLogReportDao; - } - - public JavaMailSender getMailSender() { - return mailSender; - } - - public DataSource getDataSource() { - return dataSource; - } - - public JobAlarmer getJobAlarmer() { - return jobAlarmer; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/cron/CronExpression.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/cron/CronExpression.java deleted file mode 100644 index 559edfc93..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/cron/CronExpression.java +++ /dev/null @@ -1,1653 +0,0 @@ -package com.xxl.job.admin.core.cron; - -import java.io.Serializable; -import java.text.ParseException; -import java.util.*; - -/** - * Provides a parser and evaluator for unix-like cron expressions. Cron expressions - * provide the ability to specify complex time combinations such as "At 8:00am every - * Monday through Friday" or "At 1:30am every last Friday of the month". - *

- * Cron expressions are comprised of 6 required fields and one optional field separated by - * white space. The fields respectively are described as follows: - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Examples of cron expressions and their meanings.
Field Name Allowed Values Allowed Special Characters
Seconds 0-59 , - * /
Minutes 0-59 , - * /
Hours 0-23 , - * /
Day-of-month 1-31 , - * ? / L W
Month 0-11 or JAN-DEC , - * /
Day-of-Week 1-7 or SUN-SAT , - * ? / L #
Year (Optional) empty, 1970-2199 , - * /
- *

- * The '*' character is used to specify all values. For example, "*" in the - * minute field means "every minute". - *

- *

- * The '?' character is allowed for the day-of-month and day-of-week fields. It is used to - * specify 'no specific value'. This is useful when you need to specify something in one - * of the two fields, but not the other. - *

- * The '-' character is used to specify ranges For example "10-12" in the hour - * field means "the hours 10, 11 and 12". - *

- * The ',' character is used to specify additional values. For example - * "MON,WED,FRI" in the day-of-week field means "the days Monday, - * Wednesday, and Friday". - *

- *

- * The '/' character is used to specify increments. For example "0/15" in the - * seconds field means "the seconds 0, 15, 30, and 45". And "5/15" in - * the seconds field means "the seconds 5, 20, 35, and 50". Specifying '*' - * before the '/' is equivalent to specifying 0 is the value to start with. Essentially, - * for each field in the expression, there is a set of numbers that can be turned on or - * off. For seconds and minutes, the numbers range from 0 to 59. For hours 0 to 23, for - * days of the month 0 to 31, and for months 0 to 11 (JAN to DEC). The "/" - * character simply helps you turn on every "nth" value in the given set. Thus - * "7/6" in the month field only turns on month "7", it does NOT mean - * every 6th month, please note that subtlety. - *

- *

- * The 'L' character is allowed for the day-of-month and day-of-week fields. This - * character is short-hand for "last", but it has different meaning in each of - * the two fields. For example, the value "L" in the day-of-month field means - * "the last day of the month" - day 31 for January, day 28 for February on - * non-leap years. If used in the day-of-week field by itself, it simply means - * "7" or "SAT". But if used in the day-of-week field after another - * value, it means "the last xxx day of the month" - for example "6L" - * means "the last friday of the month". You can also specify an offset from the - * last day of the month, such as "L-3" which would mean the third-to-last day of the - * calendar month. When using the 'L' option, it is important not to specify lists, or - * ranges of values, as you'll get confusing/unexpected results. - *

- *

- * The 'W' character is allowed for the day-of-month field. This character is used to - * specify the weekday (Monday-Friday) nearest the given day. As an example, if you were - * to specify "15W" as the value for the day-of-month field, the meaning is: - * "the nearest weekday to the 15th of the month". So if the 15th is a Saturday, - * the trigger will fire on Friday the 14th. If the 15th is a Sunday, the trigger will - * fire on Monday the 16th. If the 15th is a Tuesday, then it will fire on Tuesday the - * 15th. However if you specify "1W" as the value for day-of-month, and the 1st - * is a Saturday, the trigger will fire on Monday the 3rd, as it will not 'jump' over the - * boundary of a month's days. The 'W' character can only be specified when the - * day-of-month is a single day, not a range or list of days. - *

- *

- * The 'L' and 'W' characters can also be combined for the day-of-month expression to - * yield 'LW', which translates to "last weekday of the month". - *

- *

- * The '#' character is allowed for the day-of-week field. This character is used to - * specify "the nth" XXX day of the month. For example, the value of - * "6#3" in the day-of-week field means the third Friday of the month (day 6 = - * Friday and "#3" = the 3rd one in the month). Other examples: "2#1" - * = the first Monday of the month and "4#5" = the fifth Wednesday of the month. - * Note that if you specify "#5" and there is not 5 of the given day-of-week in - * the month, then no firing will occur that month. If the '#' character is used, there - * can only be one expression in the day-of-week field ("3#1,6#3" is not valid, - * since there are two expressions). - *

- * - *

- * The legal characters and the names of months and days of the week are not case - * sensitive. - * - *

- * NOTES: - *

- *
    - *
  • Support for specifying both a day-of-week and a day-of-month value is not complete - * (you'll need to use the '?' character in one of these fields).
  • - *
  • Overflowing ranges is supported - that is, having a larger number on the left hand - * side than the right. You might do 22-2 to catch 10 o'clock at night until 2 o'clock in - * the morning, or you might have NOV-FEB. It is very important to note that overuse of - * overflowing ranges creates ranges that don't make sense and no effort has been made to - * determine which interpretation CronExpression chooses. An example would be "0 0 14-6 ? - * * FRI-MON".
  • - *
- * - * @author Sharada Jambula, James House - * @author Contributions from Mads Henderson - * @author Refactoring from CronTrigger to CronExpression by Aaron Craven - * - * Borrowed from quartz v2.5.0 - */ -public final class CronExpression implements Serializable, Cloneable { - - private static final long serialVersionUID = 12423409423L; - - protected static final int SECOND = 0; - - protected static final int MINUTE = 1; - - protected static final int HOUR = 2; - - protected static final int DAY_OF_MONTH = 3; - - protected static final int MONTH = 4; - - protected static final int DAY_OF_WEEK = 5; - - protected static final int YEAR = 6; - - protected static final int ALL_SPEC_INT = 99; // '*' - - protected static final int NO_SPEC_INT = 98; // '?' - - protected static final int MAX_LAST_DAY_OFFSET = 30; - - protected static final int LAST_DAY_OFFSET_START = 32; // "L-30" - - protected static final int LAST_DAY_OFFSET_END = LAST_DAY_OFFSET_START + MAX_LAST_DAY_OFFSET; // 'L' - - protected static final Integer ALL_SPEC = ALL_SPEC_INT; - - protected static final Integer NO_SPEC = NO_SPEC_INT; - - protected static final Map monthMap = new HashMap<>(20); - - protected static final Map dayMap = new HashMap<>(60); - static { - monthMap.put("JAN", 0); - monthMap.put("FEB", 1); - monthMap.put("MAR", 2); - monthMap.put("APR", 3); - monthMap.put("MAY", 4); - monthMap.put("JUN", 5); - monthMap.put("JUL", 6); - monthMap.put("AUG", 7); - monthMap.put("SEP", 8); - monthMap.put("OCT", 9); - monthMap.put("NOV", 10); - monthMap.put("DEC", 11); - - dayMap.put("SUN", 1); - dayMap.put("MON", 2); - dayMap.put("TUE", 3); - dayMap.put("WED", 4); - dayMap.put("THU", 5); - dayMap.put("FRI", 6); - dayMap.put("SAT", 7); - } - - private final String cronExpression; - - private TimeZone timeZone = null; - - protected transient TreeSet seconds; - - protected transient TreeSet minutes; - - protected transient TreeSet hours; - - protected transient TreeSet daysOfMonth; - - protected transient TreeSet nearestWeekdays; - - protected transient TreeSet months; - - protected transient TreeSet daysOfWeek; - - protected transient TreeSet years; - - protected transient boolean lastDayOfWeek = false; - - protected transient int nthDayOfWeek = 0; - - protected transient boolean expressionParsed = false; - - public static final int MAX_YEAR = Calendar.getInstance().get(Calendar.YEAR) + 100; - - /** - * Constructs a new CronExpression based on the specified parameter. - * @param cronExpression String representation of the cron expression the new object - * should represent - * @throws java.text.ParseException if the string expression cannot be parsed into a - * valid CronExpression - */ - public CronExpression(String cronExpression) throws ParseException { - if (cronExpression == null) { - throw new IllegalArgumentException("cronExpression cannot be null"); - } - - this.cronExpression = cronExpression.toUpperCase(Locale.US); - - buildExpression(this.cronExpression); - } - - /** - * Constructs a new {@code CronExpression} as a copy of an existing instance. - * @param expression The existing cron expression to be copied - */ - public CronExpression(CronExpression expression) { - /* - * We don't call the other constructor here since we need to swallow the - * ParseException. We also elide some of the sanity checking as it is not - * logically trippable. - */ - this.cronExpression = expression.getCronExpression(); - try { - buildExpression(cronExpression); - } - catch (ParseException ex) { - throw new AssertionError("Could not parse expression!", ex); - } - if (expression.getTimeZone() != null) { - setTimeZone((TimeZone) expression.getTimeZone().clone()); - } - } - - /** - * Indicates whether the given date satisfies the cron expression. Note that - * milliseconds are ignored, so two Dates falling on different milliseconds of the - * same second will always have the same result here. - * @param date the date to evaluate - * @return a boolean indicating whether the given date satisfies the cron expression - */ - public boolean isSatisfiedBy(Date date) { - Calendar testDateCal = Calendar.getInstance(getTimeZone()); - testDateCal.setTime(date); - testDateCal.set(Calendar.MILLISECOND, 0); - Date originalDate = testDateCal.getTime(); - - testDateCal.add(Calendar.SECOND, -1); - - Date timeAfter = getTimeAfter(testDateCal.getTime()); - - return ((timeAfter != null) && (timeAfter.equals(originalDate))); - } - - /** - * Returns the next date/time after the given date/time which satisfies the - * cron expression. - * @param date the date/time at which to begin the search for the next valid date/time - * @return the next valid date/time - */ - public Date getNextValidTimeAfter(Date date) { - return getTimeAfter(date); - } - - /** - * Returns the next date/time after the given date/time which does not - * satisfy the expression - * @param date the date/time at which to begin the search for the next invalid - * date/time - * @return the next valid date/time - */ - public Date getNextInvalidTimeAfter(Date date) { - long difference = 1000; - - // move back to the nearest second so differences will be accurate - Calendar adjustCal = Calendar.getInstance(getTimeZone()); - adjustCal.setTime(date); - adjustCal.set(Calendar.MILLISECOND, 0); - Date lastDate = adjustCal.getTime(); - - Date newDate; - - // FUTURE_TODO: (QUARTZ-481) IMPROVE THIS! The following is a BAD solution to this - // problem. Performance will be very bad here, depending on the cron expression. - // It is, however A solution. - - // keep getting the next included time until it's farther than one second - // apart. At that point, lastDate is the last valid fire time. We return - // the second immediately following it. - while (difference == 1000) { - newDate = getTimeAfter(lastDate); - if (newDate == null) - break; - - difference = newDate.getTime() - lastDate.getTime(); - - if (difference == 1000) { - lastDate = newDate; - } - } - - return new Date(lastDate.getTime() + 1000); - } - - /** - * Returns the time zone for which this CronExpression will be resolved. - */ - public TimeZone getTimeZone() { - if (timeZone == null) { - timeZone = TimeZone.getDefault(); - } - - return timeZone; - } - - /** - * Sets the time zone for which this CronExpression will be resolved. - */ - public void setTimeZone(TimeZone timeZone) { - this.timeZone = timeZone; - } - - /** - * Returns the string representation of the CronExpression - * @return a string representation of the CronExpression - */ - @Override - public String toString() { - return cronExpression; - } - - /** - * Indicates whether the specified cron expression can be parsed into a valid cron - * expression - * @param cronExpression the expression to evaluate - * @return a boolean indicating whether the given expression is a valid cron - * expression - */ - public static boolean isValidExpression(String cronExpression) { - - try { - new CronExpression(cronExpression); - } - catch (ParseException pe) { - return false; - } - - return true; - } - - public static void validateExpression(String cronExpression) throws ParseException { - - new CronExpression(cronExpression); - } - - //////////////////////////////////////////////////////////////////////////// - // - // Expression Parsing Functions - // - //////////////////////////////////////////////////////////////////////////// - - protected void buildExpression(String expression) throws ParseException { - expressionParsed = true; - - try { - - if (seconds == null) { - seconds = new TreeSet<>(); - } - if (minutes == null) { - minutes = new TreeSet<>(); - } - if (hours == null) { - hours = new TreeSet<>(); - } - if (daysOfMonth == null) { - daysOfMonth = new TreeSet<>(); - } - if (nearestWeekdays == null) { - nearestWeekdays = new TreeSet<>(); - } - if (months == null) { - months = new TreeSet<>(); - } - if (daysOfWeek == null) { - daysOfWeek = new TreeSet<>(); - } - if (years == null) { - years = new TreeSet<>(); - } - - int exprOn = SECOND; - - StringTokenizer exprsTok = new StringTokenizer(expression, " \t", false); - - if (exprsTok.countTokens() > 7) { - throw new ParseException("Invalid expression has too many terms: " + expression, -1); - } - - while (exprsTok.hasMoreTokens() && exprOn <= YEAR) { - String expr = exprsTok.nextToken().trim(); - - // throw an exception if L is used with other days of the week - if (exprOn == DAY_OF_WEEK && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(",")) { - throw new ParseException( - "Support for specifying 'L' with other days of the week is not implemented", -1); - } - if (exprOn == DAY_OF_WEEK && expr.indexOf('#') != -1 - && expr.indexOf('#', expr.indexOf('#') + 1) != -1) { - throw new ParseException("Support for specifying multiple \"nth\" days is not implemented.", -1); - } - - StringTokenizer vTok = new StringTokenizer(expr, ","); - while (vTok.hasMoreTokens()) { - String v = vTok.nextToken(); - storeExpressionVals(0, v, exprOn); - } - - exprOn++; - } - - if (exprOn <= DAY_OF_WEEK) { - throw new ParseException("Unexpected end of expression.", expression.length()); - } - - if (exprOn <= YEAR) { - storeExpressionVals(0, "*", YEAR); - } - - TreeSet dow = getSet(DAY_OF_WEEK); - TreeSet dom = getSet(DAY_OF_MONTH); - - // Copying the logic from the UnsupportedOperationException below - boolean dayOfMSpec = !dom.contains(NO_SPEC); - boolean dayOfWSpec = !dow.contains(NO_SPEC); - - if (!dayOfMSpec || dayOfWSpec) { - if (!dayOfWSpec || dayOfMSpec) { - throw new ParseException( - "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.", - 0); - } - } - } - catch (ParseException pe) { - throw pe; - } - catch (Exception e) { - throw new ParseException("Illegal cron expression format (" + e + ")", 0); - } - } - - protected int storeExpressionVals(int pos, String s, int type) throws ParseException { - - int incr = 0; - int i = skipWhiteSpace(pos, s); - if (i >= s.length()) { - return i; - } - char c = s.charAt(i); - if ((c >= 'A') && (c <= 'Z') && (!s.equals("L")) && (!s.equals("LW")) && (!s.matches("^L-[0-9]*[W]?"))) { - String sub = s.substring(i, i + 3); - int sval = -1; - int eval = -1; - if (type == MONTH) { - sval = getMonthNumber(sub) + 1; - if (sval <= 0) { - throw new ParseException("Invalid Month value: '" + sub + "'", i); - } - if (s.length() > i + 3) { - c = s.charAt(i + 3); - if (c == '-') { - i += 4; - sub = s.substring(i, i + 3); - eval = getMonthNumber(sub) + 1; - if (eval <= 0) { - throw new ParseException("Invalid Month value: '" + sub + "'", i); - } - } - } - } - else if (type == DAY_OF_WEEK) { - sval = getDayOfWeekNumber(sub); - if (sval < 0) { - throw new ParseException("Invalid Day-of-Week value: '" + sub + "'", i); - } - if (s.length() > i + 3) { - c = s.charAt(i + 3); - if (c == '-') { - i += 4; - sub = s.substring(i, i + 3); - eval = getDayOfWeekNumber(sub); - if (eval < 0) { - throw new ParseException("Invalid Day-of-Week value: '" + sub + "'", i); - } - } - else if (c == '#') { - try { - i += 4; - nthDayOfWeek = Integer.parseInt(s.substring(i)); - if (nthDayOfWeek < 1 || nthDayOfWeek > 5) { - throw new Exception(); - } - } - catch (Exception e) { - throw new ParseException("A numeric value between 1 and 5 must follow the '#' option", i); - } - } - else if (c == 'L') { - lastDayOfWeek = true; - i++; - } - } - - } - else { - throw new ParseException("Illegal characters for this position: '" + sub + "'", i); - } - if (eval != -1) { - incr = 1; - } - addToSet(sval, eval, incr, type); - return (i + 3); - } - - if (c == '?') { - i++; - if ((i + 1) < s.length() && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\t')) { - throw new ParseException("Illegal character after '?': " + s.charAt(i), i); - } - if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) { - throw new ParseException("'?' can only be specified for Day-of-Month or Day-of-Week.", i); - } - if (type == DAY_OF_WEEK) { - if (!daysOfMonth.isEmpty() && daysOfMonth.last() == NO_SPEC_INT) { - throw new ParseException("'?' can only be specified for Day-of-Month -OR- Day-of-Week.", i); - } - } - - addToSet(NO_SPEC_INT, -1, 0, type); - return i; - } - - if (c == '*' || c == '/') { - if (c == '*' && (i + 1) >= s.length()) { - addToSet(ALL_SPEC_INT, -1, incr, type); - return i + 1; - } - else if (c == '/' && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s.charAt(i + 1) == '\t')) { - throw new ParseException("'/' must be followed by an integer.", i); - } - else if (c == '*') { - i++; - } - c = s.charAt(i); - if (c == '/') { // is an increment specified? - i++; - if (i >= s.length()) { - throw new ParseException("Unexpected end of string.", i); - } - - incr = getNumericValue(s, i); - - i++; - if (incr > 10) { - i++; - } - checkIncrementRange(incr, type, i); - } - else { - incr = 1; - } - - addToSet(ALL_SPEC_INT, -1, incr, type); - return i; - } - else if (c == 'L') { - i++; - if (type == DAY_OF_WEEK) { - addToSet(7, 7, 0, type); - } - if (type == DAY_OF_MONTH) { - int dom = LAST_DAY_OFFSET_END; - boolean nearestWeekday = false; - if (s.length() > i) { - c = s.charAt(i); - if (c == '-') { - ValueSet vs = getValue(0, s, i + 1); - int offset = vs.value; - if (offset > MAX_LAST_DAY_OFFSET) - throw new ParseException("Offset from last day must be <= " + MAX_LAST_DAY_OFFSET, i + 1); - dom -= offset; - i = vs.pos; - } - if (s.length() > i) { - c = s.charAt(i); - if (c == 'W') { - nearestWeekday = true; - i++; - } - } - } - if (nearestWeekday) { - nearestWeekdays.add(dom); - } - else { - daysOfMonth.add(dom); - } - } - return i; - } - else if (c >= '0' && c <= '9') { - int val = Integer.parseInt(String.valueOf(c)); - i++; - if (i >= s.length()) { - addToSet(val, -1, -1, type); - } - else { - c = s.charAt(i); - if (c >= '0' && c <= '9') { - ValueSet vs = getValue(val, s, i); - val = vs.value; - i = vs.pos; - } - i = checkNext(i, s, val, type); - return i; - } - } - else { - throw new ParseException("Unexpected character: " + c, i); - } - - return i; - } - - private void checkIncrementRange(int incr, int type, int idxPos) throws ParseException { - if (incr > 59 && (type == SECOND || type == MINUTE)) { - throw new ParseException("Increment > 60 : " + incr, idxPos); - } - else if (incr > 23 && (type == HOUR)) { - throw new ParseException("Increment > 24 : " + incr, idxPos); - } - else if (incr > 31 && (type == DAY_OF_MONTH)) { - throw new ParseException("Increment > 31 : " + incr, idxPos); - } - else if (incr > 7 && (type == DAY_OF_WEEK)) { - throw new ParseException("Increment > 7 : " + incr, idxPos); - } - else if (incr > 12 && (type == MONTH)) { - throw new ParseException("Increment > 12 : " + incr, idxPos); - } - } - - protected int checkNext(int pos, String s, int val, int type) throws ParseException { - - int end = -1; - int i = pos; - - if (i >= s.length()) { - addToSet(val, end, -1, type); - return i; - } - - char c = s.charAt(pos); - - if (c == 'L') { - if (type == DAY_OF_WEEK) { - if (val < 1 || val > 7) - throw new ParseException("Day-of-Week values must be between 1 and 7", -1); - lastDayOfWeek = true; - } - else { - throw new ParseException("'L' option is not valid here. (pos=" + i + ")", i); - } - TreeSet set = getSet(type); - set.add(val); - i++; - return i; - } - - if (c == 'W') { - if (type != DAY_OF_MONTH) { - throw new ParseException("'W' option is not valid here. (pos=" + i + ")", i); - } - if (val > 31) - throw new ParseException( - "The 'W' option does not make sense with values larger than 31 (max number of days in a month)", - i); - nearestWeekdays.add(val); - i++; - return i; - } - - if (c == '#') { - if (type != DAY_OF_WEEK) { - throw new ParseException("'#' option is not valid here. (pos=" + i + ")", i); - } - i++; - try { - nthDayOfWeek = Integer.parseInt(s.substring(i)); - if (nthDayOfWeek < 1 || nthDayOfWeek > 5) { - throw new Exception(); - } - } - catch (Exception e) { - throw new ParseException("A numeric value between 1 and 5 must follow the '#' option", i); - } - - TreeSet set = getSet(type); - set.add(val); - i++; - return i; - } - - if (c == '-') { - i++; - c = s.charAt(i); - int v = Integer.parseInt(String.valueOf(c)); - end = v; - i++; - if (i >= s.length()) { - addToSet(val, end, 1, type); - return i; - } - c = s.charAt(i); - if (c >= '0' && c <= '9') { - ValueSet vs = getValue(v, s, i); - end = vs.value; - i = vs.pos; - } - if (i < s.length() && ((c = s.charAt(i)) == '/')) { - i++; - c = s.charAt(i); - int v2 = Integer.parseInt(String.valueOf(c)); - i++; - if (i >= s.length()) { - addToSet(val, end, v2, type); - return i; - } - c = s.charAt(i); - if (c >= '0' && c <= '9') { - ValueSet vs = getValue(v2, s, i); - int v3 = vs.value; - addToSet(val, end, v3, type); - i = vs.pos; - return i; - } - else { - addToSet(val, end, v2, type); - return i; - } - } - else { - addToSet(val, end, 1, type); - return i; - } - } - - if (c == '/') { - if ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s.charAt(i + 1) == '\t') { - throw new ParseException("'/' must be followed by an integer.", i); - } - - i++; - c = s.charAt(i); - int v2 = Integer.parseInt(String.valueOf(c)); - i++; - if (i >= s.length()) { - checkIncrementRange(v2, type, i); - addToSet(val, end, v2, type); - return i; - } - c = s.charAt(i); - if (c >= '0' && c <= '9') { - ValueSet vs = getValue(v2, s, i); - int v3 = vs.value; - checkIncrementRange(v3, type, i); - addToSet(val, end, v3, type); - i = vs.pos; - return i; - } - else { - throw new ParseException("Unexpected character '" + c + "' after '/'", i); - } - } - - addToSet(val, end, 0, type); - i++; - return i; - } - - public String getCronExpression() { - return cronExpression; - } - - public String getExpressionSummary() { - StringBuilder buf = new StringBuilder(); - - buf.append("seconds: "); - buf.append(getExpressionSetSummary(seconds)); - buf.append("\n"); - buf.append("minutes: "); - buf.append(getExpressionSetSummary(minutes)); - buf.append("\n"); - buf.append("hours: "); - buf.append(getExpressionSetSummary(hours)); - buf.append("\n"); - buf.append("daysOfMonth: "); - buf.append(getExpressionSetSummary(daysOfMonth)); - buf.append("\n"); - buf.append("nearestWeekdays: "); - buf.append(getExpressionSetSummary(nearestWeekdays)); - buf.append("\n"); - buf.append("months: "); - buf.append(getExpressionSetSummary(months)); - buf.append("\n"); - buf.append("daysOfWeek: "); - buf.append(getExpressionSetSummary(daysOfWeek)); - buf.append("\n"); - buf.append("lastDayOfWeek: "); - buf.append(lastDayOfWeek); - buf.append("\n"); - buf.append("NthDayOfWeek: "); - buf.append(nthDayOfWeek); - buf.append("\n"); - buf.append("years: "); - buf.append(getExpressionSetSummary(years)); - buf.append("\n"); - - return buf.toString(); - } - - protected String getExpressionSetSummary(java.util.Set set) { - - if (set.contains(NO_SPEC)) { - return "?"; - } - if (set.contains(ALL_SPEC)) { - return "*"; - } - - StringBuilder buf = new StringBuilder(); - - Iterator itr = set.iterator(); - boolean first = true; - while (itr.hasNext()) { - Integer iVal = itr.next(); - String val = iVal.toString(); - if (!first) { - buf.append(","); - } - buf.append(val); - first = false; - } - - return buf.toString(); - } - - protected String getExpressionSetSummary(java.util.ArrayList list) { - - if (list.contains(NO_SPEC)) { - return "?"; - } - if (list.contains(ALL_SPEC)) { - return "*"; - } - - StringBuilder buf = new StringBuilder(); - - Iterator itr = list.iterator(); - boolean first = true; - while (itr.hasNext()) { - Integer iVal = itr.next(); - String val = iVal.toString(); - if (!first) { - buf.append(","); - } - buf.append(val); - first = false; - } - - return buf.toString(); - } - - protected int skipWhiteSpace(int i, String s) { - for (; i < s.length() && (s.charAt(i) == ' ' || s.charAt(i) == '\t'); i++) { - } - - return i; - } - - protected int findNextWhiteSpace(int i, String s) { - for (; i < s.length() && (s.charAt(i) != ' ' || s.charAt(i) != '\t'); i++) { - } - - return i; - } - - protected void addToSet(int val, int end, int incr, int type) throws ParseException { - - TreeSet set = getSet(type); - - if (type == SECOND || type == MINUTE) { - if ((val < 0 || val > 59 || end > 59) && (val != ALL_SPEC_INT)) { - throw new ParseException("Minute and Second values must be between 0 and 59", -1); - } - } - else if (type == HOUR) { - if ((val < 0 || val > 23 || end > 23) && (val != ALL_SPEC_INT)) { - throw new ParseException("Hour values must be between 0 and 23", -1); - } - } - else if (type == DAY_OF_MONTH) { - if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT) && (val != NO_SPEC_INT)) { - throw new ParseException("Day of month values must be between 1 and 31", -1); - } - } - else if (type == MONTH) { - if ((val < 1 || val > 12 || end > 12) && (val != ALL_SPEC_INT)) { - throw new ParseException("Month values must be between 1 and 12", -1); - } - } - else if (type == DAY_OF_WEEK) { - if ((val == 0 || val > 7 || end > 7) && (val != ALL_SPEC_INT) && (val != NO_SPEC_INT)) { - throw new ParseException("Day-of-Week values must be between 1 and 7", -1); - } - } - - if ((incr == 0 || incr == -1) && val != ALL_SPEC_INT) { - if (val != -1) { - set.add(val); - } - else { - set.add(NO_SPEC); - } - - return; - } - - int startAt = val; - int stopAt = end; - - if (val == ALL_SPEC_INT && incr <= 0) { - incr = 1; - set.add(ALL_SPEC); // put in a marker, but also fill values - } - - if (type == SECOND || type == MINUTE) { - if (stopAt == -1) { - stopAt = 59; - } - if (startAt == -1 || startAt == ALL_SPEC_INT) { - startAt = 0; - } - } - else if (type == HOUR) { - if (stopAt == -1) { - stopAt = 23; - } - if (startAt == -1 || startAt == ALL_SPEC_INT) { - startAt = 0; - } - } - else if (type == DAY_OF_MONTH) { - if (stopAt == -1) { - stopAt = 31; - } - if (startAt == -1 || startAt == ALL_SPEC_INT) { - startAt = 1; - } - } - else if (type == MONTH) { - if (stopAt == -1) { - stopAt = 12; - } - if (startAt == -1 || startAt == ALL_SPEC_INT) { - startAt = 1; - } - } - else if (type == DAY_OF_WEEK) { - if (stopAt == -1) { - stopAt = 7; - } - if (startAt == -1 || startAt == ALL_SPEC_INT) { - startAt = 1; - } - } - else if (type == YEAR) { - if (stopAt == -1) { - stopAt = MAX_YEAR; - } - if (startAt == -1 || startAt == ALL_SPEC_INT) { - startAt = 1970; - } - } - - // if the end of the range is before the start, then we need to overflow into - // the next day, month etc. This is done by adding the maximum amount for that - // type, and using modulus max to determine the value being added. - int max = -1; - if (stopAt < startAt) { - switch (type) { - case SECOND: - max = 60; - break; - case MINUTE: - max = 60; - break; - case HOUR: - max = 24; - break; - case MONTH: - max = 12; - break; - case DAY_OF_WEEK: - max = 7; - break; - case DAY_OF_MONTH: - max = 31; - break; - case YEAR: - throw new IllegalArgumentException("Start year must be less than stop year"); - default: - throw new IllegalArgumentException("Unexpected type encountered"); - } - stopAt += max; - } - - for (int i = startAt; i <= stopAt; i += incr) { - if (max == -1) { - // ie: there's no max to overflow over - set.add(i); - } - else { - // take the modulus to get the real value - int i2 = i % max; - - // 1-indexed ranges should not include 0, and should include their max - if (i2 == 0 && (type == MONTH || type == DAY_OF_WEEK || type == DAY_OF_MONTH)) { - i2 = max; - } - - set.add(i2); - } - } - } - - TreeSet getSet(int type) { - switch (type) { - case SECOND: - return seconds; - case MINUTE: - return minutes; - case HOUR: - return hours; - case DAY_OF_MONTH: - return daysOfMonth; - case MONTH: - return months; - case DAY_OF_WEEK: - return daysOfWeek; - case YEAR: - return years; - default: - return null; - } - } - - protected ValueSet getValue(int v, String s, int i) { - char c = s.charAt(i); - StringBuilder s1 = new StringBuilder(String.valueOf(v)); - while (c >= '0' && c <= '9') { - s1.append(c); - i++; - if (i >= s.length()) { - break; - } - c = s.charAt(i); - } - ValueSet val = new ValueSet(); - - val.pos = (i < s.length()) ? i : i + 1; - val.value = Integer.parseInt(s1.toString()); - return val; - } - - protected int getNumericValue(String s, int i) { - int endOfVal = findNextWhiteSpace(i, s); - String val = s.substring(i, endOfVal); - return Integer.parseInt(val); - } - - protected int getMonthNumber(String s) { - Integer integer = monthMap.get(s); - - if (integer == null) { - return -1; - } - - return integer; - } - - protected int getDayOfWeekNumber(String s) { - Integer integer = dayMap.get(s); - - if (integer == null) { - return -1; - } - - return integer; - } - - //////////////////////////////////////////////////////////////////////////// - // - // Computation Functions - // - //////////////////////////////////////////////////////////////////////////// - - public Date getTimeAfter(Date afterTime) { - - // Computation is based on Gregorian year only. - Calendar cl = new java.util.GregorianCalendar(getTimeZone()); - - // move ahead one second, since we're computing the time *after* the - // given time - afterTime = new Date(afterTime.getTime() + 1000); - // CronTrigger does not deal with milliseconds - cl.setTime(afterTime); - cl.set(Calendar.MILLISECOND, 0); - - boolean gotOne = false; - // loop until we've computed the next time, or we've past the endTime - while (!gotOne) { - - // if (endTime != null && cl.getTime().after(endTime)) return null; - if (cl.get(Calendar.YEAR) > 2999) { // prevent endless loop... - return null; - } - - SortedSet st = null; - int t = 0; - - int sec = cl.get(Calendar.SECOND); - int min = cl.get(Calendar.MINUTE); - - // get second................................................. - st = seconds.tailSet(sec); - if (st != null && !st.isEmpty()) { - sec = st.first(); - } - else { - sec = seconds.first(); - min++; - cl.set(Calendar.MINUTE, min); - } - cl.set(Calendar.SECOND, sec); - - min = cl.get(Calendar.MINUTE); - int hr = cl.get(Calendar.HOUR_OF_DAY); - t = -1; - - // get minute................................................. - st = minutes.tailSet(min); - if (st != null && !st.isEmpty()) { - t = min; - min = st.first(); - } - else { - min = minutes.first(); - hr++; - } - if (min != t) { - cl.set(Calendar.SECOND, 0); - cl.set(Calendar.MINUTE, min); - setCalendarHour(cl, hr); - continue; - } - cl.set(Calendar.MINUTE, min); - - hr = cl.get(Calendar.HOUR_OF_DAY); - int day = cl.get(Calendar.DAY_OF_MONTH); - t = -1; - - // get hour................................................... - st = hours.tailSet(hr); - if (st != null && !st.isEmpty()) { - t = hr; - hr = st.first(); - } - else { - hr = hours.first(); - day++; - } - if (hr != t) { - cl.set(Calendar.SECOND, 0); - cl.set(Calendar.MINUTE, 0); - cl.set(Calendar.DAY_OF_MONTH, day); - setCalendarHour(cl, hr); - continue; - } - cl.set(Calendar.HOUR_OF_DAY, hr); - - day = cl.get(Calendar.DAY_OF_MONTH); - int mon = cl.get(Calendar.MONTH) + 1; - // '+ 1' because calendar is 0-based for this field, and we are - // 1-based - t = -1; - int tmon = mon; - - // get day................................................... - boolean dayOfMSpec = !daysOfMonth.contains(NO_SPEC); - boolean dayOfWSpec = !daysOfWeek.contains(NO_SPEC); - if (dayOfMSpec && !dayOfWSpec) { // get day by day of month rule - Optional smallestDay = findSmallestDay(day, mon, cl.get(Calendar.YEAR), daysOfMonth); - Optional smallestDayForWeekday = findSmallestDay(day, mon, cl.get(Calendar.YEAR), - nearestWeekdays); - t = day; - day = -1; - if (smallestDayForWeekday.isPresent()) { - day = smallestDayForWeekday.get(); - - java.util.Calendar tcal = java.util.Calendar.getInstance(getTimeZone()); - tcal.set(Calendar.SECOND, 0); - tcal.set(Calendar.MINUTE, 0); - tcal.set(Calendar.HOUR_OF_DAY, 0); - tcal.set(Calendar.DAY_OF_MONTH, day); - tcal.set(Calendar.MONTH, mon - 1); - tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR)); - - int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); - int dow = tcal.get(Calendar.DAY_OF_WEEK); - - if (dow == Calendar.SATURDAY && day == 1) { - day += 2; - } - else if (dow == Calendar.SATURDAY) { - day -= 1; - } - else if (dow == Calendar.SUNDAY && day == ldom) { - day -= 2; - } - else if (dow == Calendar.SUNDAY) { - day += 1; - } - - tcal.set(Calendar.SECOND, sec); - tcal.set(Calendar.MINUTE, min); - tcal.set(Calendar.HOUR_OF_DAY, hr); - tcal.set(Calendar.DAY_OF_MONTH, day); - tcal.set(Calendar.MONTH, mon - 1); - Date nTime = tcal.getTime(); - if (nTime.before(afterTime)) { - day = -1; - } - } - if (smallestDay.isPresent()) { - if (day == -1 || smallestDay.get() < day) { - day = smallestDay.get(); - } - } - else if (day == -1) { - day = 1; - mon++; - } - if (day != t || mon != tmon) { - cl.set(Calendar.SECOND, 0); - cl.set(Calendar.MINUTE, 0); - cl.set(Calendar.HOUR_OF_DAY, 0); - cl.set(Calendar.DAY_OF_MONTH, day); - cl.set(Calendar.MONTH, mon - 1); - // '- 1' because calendar is 0-based for this field, and we - // are 1-based - continue; - } - } - else if (dayOfWSpec && !dayOfMSpec) { // get day by day of week rule - if (lastDayOfWeek) { // are we looking for the last XXX day of - // the month? - int dow = daysOfWeek.first(); // desired - // d-o-w - int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w - int daysToAdd = 0; - if (cDow < dow) { - daysToAdd = dow - cDow; - } - if (cDow > dow) { - daysToAdd = dow + (7 - cDow); - } - - int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); - - if (day + daysToAdd > lDay) { // did we already miss the - // last one? - cl.set(Calendar.SECOND, 0); - cl.set(Calendar.MINUTE, 0); - cl.set(Calendar.HOUR_OF_DAY, 0); - cl.set(Calendar.DAY_OF_MONTH, 1); - cl.set(Calendar.MONTH, mon); - // no '- 1' here because we are promoting the month - continue; - } - - // find date of last occurrence of this day in this month... - while ((day + daysToAdd + 7) <= lDay) { - daysToAdd += 7; - } - - day += daysToAdd; - - if (daysToAdd > 0) { - cl.set(Calendar.SECOND, 0); - cl.set(Calendar.MINUTE, 0); - cl.set(Calendar.HOUR_OF_DAY, 0); - cl.set(Calendar.DAY_OF_MONTH, day); - cl.set(Calendar.MONTH, mon - 1); - // '- 1' here because we are not promoting the month - continue; - } - - } - else if (nthDayOfWeek != 0) { - // are we looking for the Nth XXX day in the month? - int dow = daysOfWeek.first(); // desired - // d-o-w - int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w - int daysToAdd = 0; - if (cDow < dow) { - daysToAdd = dow - cDow; - } - else if (cDow > dow) { - daysToAdd = dow + (7 - cDow); - } - - boolean dayShifted = daysToAdd > 0; - - day += daysToAdd; - int weekOfMonth = day / 7; - if (day % 7 > 0) { - weekOfMonth++; - } - - daysToAdd = (nthDayOfWeek - weekOfMonth) * 7; - day += daysToAdd; - if (daysToAdd < 0 || day > getLastDayOfMonth(mon, cl.get(Calendar.YEAR))) { - cl.set(Calendar.SECOND, 0); - cl.set(Calendar.MINUTE, 0); - cl.set(Calendar.HOUR_OF_DAY, 0); - cl.set(Calendar.DAY_OF_MONTH, 1); - cl.set(Calendar.MONTH, mon); - // no '- 1' here because we are promoting the month - continue; - } - else if (daysToAdd > 0 || dayShifted) { - cl.set(Calendar.SECOND, 0); - cl.set(Calendar.MINUTE, 0); - cl.set(Calendar.HOUR_OF_DAY, 0); - cl.set(Calendar.DAY_OF_MONTH, day); - cl.set(Calendar.MONTH, mon - 1); - // '- 1' here because we are NOT promoting the month - continue; - } - } - else { - int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w - int dow = daysOfWeek.first(); // desired - // d-o-w - st = daysOfWeek.tailSet(cDow); - if (st != null && !st.isEmpty()) { - dow = st.first(); - } - - int daysToAdd = 0; - if (cDow < dow) { - daysToAdd = dow - cDow; - } - if (cDow > dow) { - daysToAdd = dow + (7 - cDow); - } - - int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); - - if (day + daysToAdd > lDay) { // will we pass the end of - // the month? - cl.set(Calendar.SECOND, 0); - cl.set(Calendar.MINUTE, 0); - cl.set(Calendar.HOUR_OF_DAY, 0); - cl.set(Calendar.DAY_OF_MONTH, 1); - cl.set(Calendar.MONTH, mon); - // no '- 1' here because we are promoting the month - continue; - } - else if (daysToAdd > 0) { // are we switching days? - cl.set(Calendar.SECOND, 0); - cl.set(Calendar.MINUTE, 0); - cl.set(Calendar.HOUR_OF_DAY, 0); - cl.set(Calendar.DAY_OF_MONTH, day + daysToAdd); - cl.set(Calendar.MONTH, mon - 1); - // '- 1' because calendar is 0-based for this field, - // and we are 1-based - continue; - } - } - } - else { // dayOfWSpec && !dayOfMSpec - throw new UnsupportedOperationException( - "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented."); - } - cl.set(Calendar.DAY_OF_MONTH, day); - - mon = cl.get(Calendar.MONTH) + 1; - // '+ 1' because calendar is 0-based for this field, and we are - // 1-based - int year = cl.get(Calendar.YEAR); - t = -1; - - // test for expressions that never generate a valid fire date, - // but keep looping... - if (year > MAX_YEAR) { - return null; - } - - // get month................................................... - st = months.tailSet(mon); - if (st != null && !st.isEmpty()) { - t = mon; - mon = st.first(); - } - else { - mon = months.first(); - year++; - } - if (mon != t) { - cl.set(Calendar.SECOND, 0); - cl.set(Calendar.MINUTE, 0); - cl.set(Calendar.HOUR_OF_DAY, 0); - cl.set(Calendar.DAY_OF_MONTH, 1); - cl.set(Calendar.MONTH, mon - 1); - // '- 1' because calendar is 0-based for this field, and we are - // 1-based - cl.set(Calendar.YEAR, year); - continue; - } - cl.set(Calendar.MONTH, mon - 1); - // '- 1' because calendar is 0-based for this field, and we are - // 1-based - - year = cl.get(Calendar.YEAR); - t = -1; - - // get year................................................... - st = years.tailSet(year); - if (st != null && !st.isEmpty()) { - t = year; - year = st.first(); - } - else { - return null; // ran out of years... - } - - if (year != t) { - cl.set(Calendar.SECOND, 0); - cl.set(Calendar.MINUTE, 0); - cl.set(Calendar.HOUR_OF_DAY, 0); - cl.set(Calendar.DAY_OF_MONTH, 1); - cl.set(Calendar.MONTH, 0); - // '- 1' because calendar is 0-based for this field, and we are - // 1-based - cl.set(Calendar.YEAR, year); - continue; - } - cl.set(Calendar.YEAR, year); - - gotOne = true; - } // while( !done ) - - return cl.getTime(); - } - - /** - * Advance the calendar to the particular hour paying particular attention to daylight - * saving problems. - * @param cal the calendar to operate on - * @param hour the hour to set - */ - protected void setCalendarHour(Calendar cal, int hour) { - cal.set(java.util.Calendar.HOUR_OF_DAY, hour); - if (cal.get(java.util.Calendar.HOUR_OF_DAY) != hour && hour != 24) { - cal.set(java.util.Calendar.HOUR_OF_DAY, hour + 1); - } - } - - /** - * NOT YET IMPLEMENTED: Returns the time before the given time that the - * CronExpression matches. - */ - public Date getTimeBefore(Date endTime) { - // FUTURE_TODO: implement QUARTZ-423 - return null; - } - - /** - * NOT YET IMPLEMENTED: Returns the final time that the CronExpression - * will match. - */ - public Date getFinalFireTime() { - // FUTURE_TODO: implement QUARTZ-423 - return null; - } - - protected boolean isLeapYear(int year) { - return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)); - } - - protected int getLastDayOfMonth(int monthNum, int year) { - - switch (monthNum) { - case 1: - return 31; - case 2: - return (isLeapYear(year)) ? 29 : 28; - case 3: - return 31; - case 4: - return 30; - case 5: - return 31; - case 6: - return 30; - case 7: - return 31; - case 8: - return 31; - case 9: - return 30; - case 10: - return 31; - case 11: - return 30; - case 12: - return 31; - default: - throw new IllegalArgumentException("Illegal month number: " + monthNum); - } - } - - private Optional findSmallestDay(int day, int mon, int year, TreeSet set) { - if (set.isEmpty()) { - return Optional.empty(); - } - - final int lastDay = getLastDayOfMonth(mon, year); - // For "L", "L-1", etc. - int smallestDay = Optional.ofNullable(set.ceiling(LAST_DAY_OFFSET_END - (lastDay - day))) - .map(d -> d - LAST_DAY_OFFSET_START + 1) - .orElse(Integer.MAX_VALUE); - - // For "1", "2", etc. - SortedSet st = set.subSet(day, LAST_DAY_OFFSET_START); - // make sure we don't over-run a short month, such as february - if (!st.isEmpty() && st.first() < smallestDay && st.first() <= lastDay) { - smallestDay = st.first(); - } - - return smallestDay == Integer.MAX_VALUE ? Optional.empty() : Optional.of(smallestDay); - } - - private void readObject(java.io.ObjectInputStream stream) throws java.io.IOException, ClassNotFoundException { - - stream.defaultReadObject(); - try { - buildExpression(cronExpression); - } - catch (Exception ignore) { - } // never happens - } - - @Override - @Deprecated - public Object clone() { - return new CronExpression(this); - } - -} - -class ValueSet { - - public int value; - - public int pos; - -} \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/exception/XxlJobException.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/exception/XxlJobException.java deleted file mode 100644 index bf4eff6c5..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/exception/XxlJobException.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.xxl.job.admin.core.exception; - -/** - * @author xuxueli 2019-05-04 23:19:29 - */ -public class XxlJobException extends RuntimeException { - - public XxlJobException() { - } - - public XxlJobException(String message) { - super(message); - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java deleted file mode 100644 index e0257c7d5..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.xxl.job.admin.core.model; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; - -/** - * Created by xuxueli on 16/9/30. - */ -public class XxlJobGroup { - - private int id; - - private String appname; - - private String title; - - private int addressType; // 执行器地址类型:0=自动注册、1=手动录入 - - private String addressList; // 执行器地址列表,多地址逗号分隔(手动录入) - - private Date updateTime; - - // registry list - private List registryList; // 执行器地址列表(系统注册) - - public List getRegistryList() { - if (addressList != null && addressList.trim().length() > 0) { - registryList = new ArrayList(Arrays.asList(addressList.split(","))); - } - return registryList; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getAppname() { - return appname; - } - - public void setAppname(String appname) { - this.appname = appname; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public int getAddressType() { - return addressType; - } - - public void setAddressType(int addressType) { - this.addressType = addressType; - } - - public String getAddressList() { - return addressList; - } - - public Date getUpdateTime() { - return updateTime; - } - - public void setUpdateTime(Date updateTime) { - this.updateTime = updateTime; - } - - public void setAddressList(String addressList) { - this.addressList = addressList; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogReport.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogReport.java deleted file mode 100644 index bf7907f8c..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogReport.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.xxl.job.admin.core.model; - -import java.util.Date; - -public class XxlJobLogReport { - - private int id; - - private Date triggerDay; - - private int runningCount; - - private int sucCount; - - private int failCount; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public Date getTriggerDay() { - return triggerDay; - } - - public void setTriggerDay(Date triggerDay) { - this.triggerDay = triggerDay; - } - - public int getRunningCount() { - return runningCount; - } - - public void setRunningCount(int runningCount) { - this.runningCount = runningCount; - } - - public int getSucCount() { - return sucCount; - } - - public void setSucCount(int sucCount) { - this.sucCount = sucCount; - } - - public int getFailCount() { - return failCount; - } - - public void setFailCount(int failCount) { - this.failCount = failCount; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobRegistry.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobRegistry.java deleted file mode 100644 index d8e5da2fa..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobRegistry.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.xxl.job.admin.core.model; - -import java.util.Date; - -/** - * Created by xuxueli on 16/9/30. - */ -public class XxlJobRegistry { - - private int id; - - private String registryGroup; - - private String registryKey; - - private String registryValue; - - private Date updateTime; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getRegistryGroup() { - return registryGroup; - } - - public void setRegistryGroup(String registryGroup) { - this.registryGroup = registryGroup; - } - - public String getRegistryKey() { - return registryKey; - } - - public void setRegistryKey(String registryKey) { - this.registryKey = registryKey; - } - - public String getRegistryValue() { - return registryValue; - } - - public void setRegistryValue(String registryValue) { - this.registryValue = registryValue; - } - - public Date getUpdateTime() { - return updateTime; - } - - public void setUpdateTime(Date updateTime) { - this.updateTime = updateTime; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/RemoteHttpJobBean.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/RemoteHttpJobBean.java deleted file mode 100644 index 3cc0b51cf..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/RemoteHttpJobBean.java +++ /dev/null @@ -1,33 +0,0 @@ -// package com.xxl.job.admin.core.jobbean; -// -// import com.xxl.job.admin.core.thread.JobTriggerPoolHelper; -// import com.xxl.job.admin.core.trigger.TriggerTypeEnum; -// import org.quartz.JobExecutionContext; -// import org.quartz.JobExecutionException; -// import org.quartz.JobKey; -// import org.slf4j.Logger; -// import org.slf4j.LoggerFactory; -// import org.springframework.scheduling.quartz.QuartzJobBean; -// -/// ** -// * http job bean -// * “@DisallowConcurrentExecution” disable concurrent, thread size can not be only one, -// better given more -// * @author xuxueli 2015-12-17 18:20:34 -// */ -//// @DisallowConcurrentExecution -// public class RemoteHttpJobBean extends QuartzJobBean { -// private static Logger logger = LoggerFactory.getLogger(RemoteHttpJobBean.class); -// -// @Override -// protected void executeInternal(JobExecutionContext context) -// throws JobExecutionException { -// -// // load jobId -// JobKey jobKey = context.getTrigger().getJobKey(); -// Integer jobId = Integer.valueOf(jobKey.getName()); -// -// -// } -// -// } \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobDynamicScheduler.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobDynamicScheduler.java deleted file mode 100644 index b321f6c73..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobDynamicScheduler.java +++ /dev/null @@ -1,430 +0,0 @@ -// package com.xxl.job.admin.core.schedule; -// -// import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -// import com.xxl.job.admin.core.jobbean.RemoteHttpJobBean; -// import com.xxl.job.admin.core.model.XxlJobInfo; -// import com.xxl.job.admin.core.thread.JobFailMonitorHelper; -// import com.xxl.job.admin.core.thread.JobRegistryMonitorHelper; -// import com.xxl.job.admin.core.thread.JobTriggerPoolHelper; -// import com.xxl.job.admin.core.util.I18nUtil; -// import com.xxl.job.core.biz.AdminBiz; -// import com.xxl.job.core.biz.ExecutorBiz; -// import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; -// import com.xxl.rpc.remoting.invoker.XxlRpcInvokerFactory; -// import com.xxl.rpc.remoting.invoker.call.CallType; -// import com.xxl.rpc.remoting.invoker.reference.XxlRpcReferenceBean; -// import com.xxl.rpc.remoting.invoker.route.LoadBalance; -// import com.xxl.rpc.remoting.net.NetEnum; -// import com.xxl.rpc.remoting.net.impl.servlet.server.ServletServerHandler; -// import com.xxl.rpc.remoting.provider.XxlRpcProviderFactory; -// import com.xxl.rpc.serialize.Serializer; -// import org.quartz.*; -// import org.quartz.Trigger.TriggerState; -// import org.quartz.impl.triggers.CronTriggerImpl; -// import org.slf4j.Logger; -// import org.slf4j.LoggerFactory; -// import org.springframework.util.Assert; -// -// import javax.servlet.ServletException; -// import javax.servlet.http.HttpServletRequest; -// import javax.servlet.http.HttpServletResponse; -// import java.io.IOException; -// import java.util.Date; -// import java.util.concurrent.ConcurrentHashMap; -// -/// ** -// * base quartz scheduler util -// * @author xuxueli 2015-12-19 16:13:53 -// */ -// public final class XxlJobDynamicScheduler { -// private static final Logger logger = -// LoggerFactory.getLogger(XxlJobDynamicScheduler_old.class); -// -// // ---------------------- param ---------------------- -// -// // scheduler -// private static Scheduler scheduler; -// public void setScheduler(Scheduler scheduler) { -// XxlJobDynamicScheduler_old.scheduler = scheduler; -// } -// -// -// // ---------------------- init + destroy ---------------------- -// public void start() throws Exception { -// // valid -// Assert.notNull(scheduler, "quartz scheduler is null"); -// -// // init i18n -// initI18n(); -// -// // admin registry monitor run -// JobRegistryMonitorHelper.getInstance().start(); -// -// // admin monitor run -// JobFailMonitorHelper.getInstance().start(); -// -// // admin-server -// initRpcProvider(); -// -// logger.info(">>>>>>>>> init xxl-job admin success."); -// } -// -// -// public void destroy() throws Exception { -// // admin trigger pool stop -// JobTriggerPoolHelper.toStop(); -// -// // admin registry stop -// JobRegistryMonitorHelper.getInstance().toStop(); -// -// // admin monitor stop -// JobFailMonitorHelper.getInstance().toStop(); -// -// // admin-server -// stopRpcProvider(); -// } -// -// -// // ---------------------- I18n ---------------------- -// -// private void initI18n(){ -// for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) { -// item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name()))); -// } -// } -// -// -// // ---------------------- admin rpc provider (no server version) ---------------------- -// private static ServletServerHandler servletServerHandler; -// private void initRpcProvider(){ -// // init -// XxlRpcProviderFactory xxlRpcProviderFactory = new XxlRpcProviderFactory(); -// xxlRpcProviderFactory.initConfig( -// NetEnum.NETTY_HTTP, -// Serializer.SerializeEnum.HESSIAN.getSerializer(), -// null, -// 0, -// XxlJobAdminConfig.getAdminConfig().getAccessToken(), -// null, -// null); -// -// // add services -// xxlRpcProviderFactory.addService(AdminBiz.class.getName(), null, -// XxlJobAdminConfig.getAdminConfig().getAdminBiz()); -// -// // servlet handler -// servletServerHandler = new ServletServerHandler(xxlRpcProviderFactory); -// } -// private void stopRpcProvider() throws Exception { -// XxlRpcInvokerFactory.getInstance().stop(); -// } -// public static void invokeAdminService(HttpServletRequest request, HttpServletResponse -// response) throws IOException, ServletException { -// servletServerHandler.handle(null, request, response); -// } -// -// -// // ---------------------- executor-client ---------------------- -// private static ConcurrentHashMap executorBizRepository = new -// ConcurrentHashMap(); -// public static ExecutorBiz getExecutorBiz(String address) throws Exception { -// // valid -// if (address==null || address.trim().length()==0) { -// return null; -// } -// -// // load-cache -// address = address.trim(); -// ExecutorBiz executorBiz = executorBizRepository.get(address); -// if (executorBiz != null) { -// return executorBiz; -// } -// -// // set-cache -// executorBiz = (ExecutorBiz) new XxlRpcReferenceBean( -// NetEnum.NETTY_HTTP, -// Serializer.SerializeEnum.HESSIAN.getSerializer(), -// CallType.SYNC, -// LoadBalance.ROUND, -// ExecutorBiz.class, -// null, -// 5000, -// address, -// XxlJobAdminConfig.getAdminConfig().getAccessToken(), -// null, -// null).getObject(); -// -// executorBizRepository.put(address, executorBiz); -// return executorBiz; -// } -// -// -// // ---------------------- schedule util ---------------------- -// -// /** -// * fill job info -// * -// * @param jobInfo -// */ -// public static void fillJobInfo(XxlJobInfo jobInfo) { -// -// String name = String.valueOf(jobInfo.getId()); -// -// // trigger key -// TriggerKey triggerKey = TriggerKey.triggerKey(name); -// try { -// -// // trigger cron -// Trigger trigger = scheduler.getTrigger(triggerKey); -// if (trigger!=null && trigger instanceof CronTriggerImpl) { -// String cronExpression = ((CronTriggerImpl) trigger).getCronExpression(); -// jobInfo.setJobCron(cronExpression); -// } -// -// // trigger state -// TriggerState triggerState = scheduler.getTriggerState(triggerKey); -// if (triggerState!=null) { -// jobInfo.setJobStatus(triggerState.name()); -// } -// -// //JobKey jobKey = new JobKey(jobInfo.getJobName(), -// String.valueOf(jobInfo.getJobGroup())); -// //JobDetail jobDetail = scheduler.getJobDetail(jobKey); -// //String jobClass = jobDetail.getJobClass().getName(); -// -// } catch (SchedulerException e) { -// logger.error(e.getMessage(), e); -// } -// } -// -// -// /** -// * add trigger + job -// * -// * @param jobName -// * @param cronExpression -// * @return -// * @throws SchedulerException -// */ -// public static boolean addJob(String jobName, String cronExpression) throws -// SchedulerException { -// // 1、job key -// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); -// JobKey jobKey = new JobKey(jobName); -// -// // 2、valid -// if (scheduler.checkExists(triggerKey)) { -// return true; // PASS -// } -// -// // 3、corn trigger -// CronScheduleBuilder cronScheduleBuilder = -// CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing(); -// // withMisfireHandlingInstructionDoNothing 忽略掉调度终止过程中忽略的调度 -// CronTrigger cronTrigger = -// TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build(); -// -// // 4、job detail -// Class jobClass_ = RemoteHttpJobBean.class; // -// Class.forName(jobInfo.getJobClass()); -// JobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).build(); -// -// /*if (jobInfo.getJobData()!=null) { -// JobDataMap jobDataMap = jobDetail.getJobDataMap(); -// jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class)); -// // JobExecutionContext context.getMergedJobDataMap().get("mailGuid"); -// }*/ -// -// // 5、schedule job -// Date date = scheduler.scheduleJob(jobDetail, cronTrigger); -// -// logger.info(">>>>>>>>>>> addJob success(quartz), jobDetail:{}, cronTrigger:{}, -// date:{}", jobDetail, cronTrigger, date); -// return true; -// } -// -// -// /** -// * remove trigger + job -// * -// * @param jobName -// * @return -// * @throws SchedulerException -// */ -// public static boolean removeJob(String jobName) throws SchedulerException { -// -// JobKey jobKey = new JobKey(jobName); -// scheduler.deleteJob(jobKey); -// -// /*TriggerKey triggerKey = TriggerKey.triggerKey(jobName); -// if (scheduler.checkExists(triggerKey)) { -// scheduler.unscheduleJob(triggerKey); // trigger + job -// }*/ -// -// logger.info(">>>>>>>>>>> removeJob success(quartz), jobKey:{}", jobKey); -// return true; -// } -// -// -// /** -// * updateJobCron -// * -// * @param jobName -// * @param cronExpression -// * @return -// * @throws SchedulerException -// */ -// public static boolean updateJobCron(String jobName, String cronExpression) throws -// SchedulerException { -// -// // 1、job key -// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); -// -// // 2、valid -// if (!scheduler.checkExists(triggerKey)) { -// return true; // PASS -// } -// -// CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); -// -// // 3、avoid repeat cron -// String oldCron = oldTrigger.getCronExpression(); -// if (oldCron.equals(cronExpression)){ -// return true; // PASS -// } -// -// // 4、new cron trigger -// CronScheduleBuilder cronScheduleBuilder = -// CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing(); -// oldTrigger = -// oldTrigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build(); -// -// // 5、rescheduleJob -// scheduler.rescheduleJob(triggerKey, oldTrigger); -// -// /* -// JobKey jobKey = new JobKey(jobName); -// -// // old job detail -// JobDetail jobDetail = scheduler.getJobDetail(jobKey); -// -// // new trigger -// HashSet triggerSet = new HashSet(); -// triggerSet.add(cronTrigger); -// // cover trigger of job detail -// scheduler.scheduleJob(jobDetail, triggerSet, true);*/ -// -// logger.info(">>>>>>>>>>> resumeJob success, JobName:{}", jobName); -// return true; -// } -// -// -// /** -// * pause -// * -// * @param jobName -// * @return -// * @throws SchedulerException -// */ -// /*public static boolean pauseJob(String jobName) throws SchedulerException { -// -// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); -// -// boolean result = false; -// if (scheduler.checkExists(triggerKey)) { -// scheduler.pauseTrigger(triggerKey); -// result = true; -// } -// -// logger.info(">>>>>>>>>>> pauseJob {}, triggerKey:{}", -// (result?"success":"fail"),triggerKey); -// return result; -// }*/ -// -// -// /** -// * resume -// * -// * @param jobName -// * @return -// * @throws SchedulerException -// */ -// /*public static boolean resumeJob(String jobName) throws SchedulerException { -// -// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); -// -// boolean result = false; -// if (scheduler.checkExists(triggerKey)) { -// scheduler.resumeTrigger(triggerKey); -// result = true; -// } -// -// logger.info(">>>>>>>>>>> resumeJob {}, triggerKey:{}", (result?"success":"fail"), -// triggerKey); -// return result; -// }*/ -// -// -// /** -// * run -// * -// * @param jobName -// * @return -// * @throws SchedulerException -// */ -// /*public static boolean triggerJob(String jobName) throws SchedulerException { -// // TriggerKey : name + group -// JobKey jobKey = new JobKey(jobName); -// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); -// -// boolean result = false; -// if (scheduler.checkExists(triggerKey)) { -// scheduler.triggerJob(jobKey); -// result = true; -// logger.info(">>>>>>>>>>> runJob success, jobKey:{}", jobKey); -// } else { -// logger.info(">>>>>>>>>>> runJob fail, jobKey:{}", jobKey); -// } -// return result; -// }*/ -// -// -// /** -// * finaAllJobList -// * -// * @return -// *//* -// @Deprecated -// public static List> finaAllJobList(){ -// List> jobList = new ArrayList>(); -// -// try { -// if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) { -// return null; -// } -// String groupName = scheduler.getJobGroupNames().get(0); -// Set jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName)); -// if (jobKeys!=null && jobKeys.size()>0) { -// for (JobKey jobKey : jobKeys) { -// TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), -// Scheduler.DEFAULT_GROUP); -// Trigger trigger = scheduler.getTrigger(triggerKey); -// JobDetail jobDetail = scheduler.getJobDetail(jobKey); -// TriggerState triggerState = scheduler.getTriggerState(triggerKey); -// Map jobMap = new HashMap(); -// jobMap.put("TriggerKey", triggerKey); -// jobMap.put("Trigger", trigger); -// jobMap.put("JobDetail", jobDetail); -// jobMap.put("TriggerState", triggerState); -// jobList.add(jobMap); -// } -// } -// -// } catch (SchedulerException e) { -// logger.error(e.getMessage(), e); -// return null; -// } -// return jobList; -// }*/ -// -// } \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobThreadPool.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobThreadPool.java deleted file mode 100644 index daf02128f..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobThreadPool.java +++ /dev/null @@ -1,58 +0,0 @@ -// package com.xxl.job.admin.core.quartz; -// -// import org.quartz.SchedulerConfigException; -// import org.quartz.spi.ThreadPool; -// -/// ** -// * single thread pool, for async trigger -// * -// * @author xuxueli 2019-03-06 -// */ -// public class XxlJobThreadPool implements ThreadPool { -// -// @Override -// public boolean runInThread(Runnable runnable) { -// -// // async run -// runnable.run(); -// return true; -// -// //return false; -// } -// -// @Override -// public int blockForAvailableThreads() { -// return 1; -// } -// -// @Override -// public void initialize() throws SchedulerConfigException { -// -// } -// -// @Override -// public void shutdown(boolean waitForJobsToComplete) { -// -// } -// -// @Override -// public int getPoolSize() { -// return 1; -// } -// -// @Override -// public void setInstanceId(String schedInstId) { -// -// } -// -// @Override -// public void setInstanceName(String schedName) { -// -// } -// -// // support -// public void setThreadCount(int count) { -// // -// } -// -// } diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java deleted file mode 100644 index b747003de..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.xxl.job.admin.core.route; - -import com.xxl.job.admin.core.route.strategy.*; -import com.xxl.job.admin.core.util.I18nUtil; - -/** - * Created by xuxueli on 17/3/10. - */ -public enum ExecutorRouteStrategyEnum { - - FIRST(I18nUtil.getString("jobconf_route_first"), new ExecutorRouteFirst()), - LAST(I18nUtil.getString("jobconf_route_last"), new ExecutorRouteLast()), - ROUND(I18nUtil.getString("jobconf_route_round"), new ExecutorRouteRound()), - RANDOM(I18nUtil.getString("jobconf_route_random"), new ExecutorRouteRandom()), - CONSISTENT_HASH(I18nUtil.getString("jobconf_route_consistenthash"), new ExecutorRouteConsistentHash()), - LEAST_FREQUENTLY_USED(I18nUtil.getString("jobconf_route_lfu"), new ExecutorRouteLFU()), - LEAST_RECENTLY_USED(I18nUtil.getString("jobconf_route_lru"), new ExecutorRouteLRU()), - FAILOVER(I18nUtil.getString("jobconf_route_failover"), new ExecutorRouteFailover()), - BUSYOVER(I18nUtil.getString("jobconf_route_busyover"), new ExecutorRouteBusyover()), - SHARDING_BROADCAST(I18nUtil.getString("jobconf_route_shard"), null); - - ExecutorRouteStrategyEnum(String title, ExecutorRouter router) { - this.title = title; - this.router = router; - } - - private String title; - - private ExecutorRouter router; - - public String getTitle() { - return title; - } - - public ExecutorRouter getRouter() { - return router; - } - - public static ExecutorRouteStrategyEnum match(String name, ExecutorRouteStrategyEnum defaultItem) { - if (name != null) { - for (ExecutorRouteStrategyEnum item : ExecutorRouteStrategyEnum.values()) { - if (item.name().equals(name)) { - return item; - } - } - } - return defaultItem; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java deleted file mode 100644 index 9765719d4..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.xxl.job.admin.core.route; - -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.biz.model.TriggerParam; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; - -/** - * Created by xuxueli on 17/3/10. - */ -public abstract class ExecutorRouter { - - protected static Logger logger = LoggerFactory.getLogger(ExecutorRouter.class); - - /** - * route address - * @param addressList - * @return ReturnT.content=address - */ - public abstract ReturnT route(TriggerParam triggerParam, List addressList); - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java deleted file mode 100644 index 3a5dd759e..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.xxl.job.admin.core.route.strategy; - -import com.xxl.job.admin.core.route.ExecutorRouter; -import com.xxl.job.admin.core.scheduler.XxlJobScheduler; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.core.biz.ExecutorBiz; -import com.xxl.job.core.biz.model.IdleBeatParam; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.biz.model.TriggerParam; - -import java.util.List; - -/** - * Created by xuxueli on 17/3/10. - */ -public class ExecutorRouteBusyover extends ExecutorRouter { - - @Override - public ReturnT route(TriggerParam triggerParam, List addressList) { - StringBuffer idleBeatResultSB = new StringBuffer(); - for (String address : addressList) { - // beat - ReturnT idleBeatResult = null; - try { - ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address); - idleBeatResult = executorBiz.idleBeat(new IdleBeatParam(triggerParam.getJobId())); - } - catch (Exception e) { - logger.error(e.getMessage(), e); - idleBeatResult = new ReturnT(ReturnT.FAIL_CODE, "" + e); - } - idleBeatResultSB.append((idleBeatResultSB.length() > 0) ? "

" : "") - .append(I18nUtil.getString("jobconf_idleBeat") + ":") - .append("
address:") - .append(address) - .append("
code:") - .append(idleBeatResult.getCode()) - .append("
msg:") - .append(idleBeatResult.getMsg()); - - // beat success - if (idleBeatResult.getCode() == ReturnT.SUCCESS_CODE) { - idleBeatResult.setMsg(idleBeatResultSB.toString()); - idleBeatResult.setContent(address); - return idleBeatResult; - } - } - - return new ReturnT(ReturnT.FAIL_CODE, idleBeatResultSB.toString()); - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java deleted file mode 100644 index e60790280..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.xxl.job.admin.core.route.strategy; - -import com.xxl.job.admin.core.route.ExecutorRouter; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.biz.model.TriggerParam; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.List; -import java.util.SortedMap; -import java.util.TreeMap; - -/** - * 分组下机器地址相同,不同JOB均匀散列在不同机器上,保证分组下机器分配JOB平均;且每个JOB固定调度其中一台机器; a、virtual node:解决不均衡问题 - * b、hash method replace hashCode:String的hashCode可能重复,需要进一步扩大hashCode的取值范围 Created by - * xuxueli on 17/3/10. - */ -public class ExecutorRouteConsistentHash extends ExecutorRouter { - - private static int VIRTUAL_NODE_NUM = 100; - - /** - * get hash code on 2^32 ring (md5散列的方式计算hash值) - * @param key - * @return - */ - private static long hash(String key) { - - // md5 byte - MessageDigest md5; - try { - md5 = MessageDigest.getInstance("MD5"); - } - catch (NoSuchAlgorithmException e) { - throw new RuntimeException("MD5 not supported", e); - } - md5.reset(); - byte[] keyBytes = null; - try { - keyBytes = key.getBytes("UTF-8"); - } - catch (UnsupportedEncodingException e) { - throw new RuntimeException("Unknown string :" + key, e); - } - - md5.update(keyBytes); - byte[] digest = md5.digest(); - - // hash code, Truncate to 32-bits - long hashCode = ((long) (digest[3] & 0xFF) << 24) | ((long) (digest[2] & 0xFF) << 16) - | ((long) (digest[1] & 0xFF) << 8) | (digest[0] & 0xFF); - - long truncateHashCode = hashCode & 0xffffffffL; - return truncateHashCode; - } - - public String hashJob(int jobId, List addressList) { - - // ------A1------A2-------A3------ - // -----------J1------------------ - TreeMap addressRing = new TreeMap(); - for (String address : addressList) { - for (int i = 0; i < VIRTUAL_NODE_NUM; i++) { - long addressHash = hash("SHARD-" + address + "-NODE-" + i); - addressRing.put(addressHash, address); - } - } - - long jobHash = hash(String.valueOf(jobId)); - SortedMap lastRing = addressRing.tailMap(jobHash); - if (!lastRing.isEmpty()) { - return lastRing.get(lastRing.firstKey()); - } - return addressRing.firstEntry().getValue(); - } - - @Override - public ReturnT route(TriggerParam triggerParam, List addressList) { - String address = hashJob(triggerParam.getJobId(), addressList); - return new ReturnT(address); - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java deleted file mode 100644 index f6d815188..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.xxl.job.admin.core.route.strategy; - -import com.xxl.job.admin.core.route.ExecutorRouter; -import com.xxl.job.admin.core.scheduler.XxlJobScheduler; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.core.biz.ExecutorBiz; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.biz.model.TriggerParam; - -import java.util.List; - -/** - * Created by xuxueli on 17/3/10. - */ -public class ExecutorRouteFailover extends ExecutorRouter { - - @Override - public ReturnT route(TriggerParam triggerParam, List addressList) { - - StringBuffer beatResultSB = new StringBuffer(); - for (String address : addressList) { - // beat - ReturnT beatResult = null; - try { - ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address); - beatResult = executorBiz.beat(); - } - catch (Exception e) { - logger.error(e.getMessage(), e); - beatResult = new ReturnT(ReturnT.FAIL_CODE, "" + e); - } - beatResultSB.append((beatResultSB.length() > 0) ? "

" : "") - .append(I18nUtil.getString("jobconf_beat") + ":") - .append("
address:") - .append(address) - .append("
code:") - .append(beatResult.getCode()) - .append("
msg:") - .append(beatResult.getMsg()); - - // beat success - if (beatResult.getCode() == ReturnT.SUCCESS_CODE) { - - beatResult.setMsg(beatResultSB.toString()); - beatResult.setContent(address); - return beatResult; - } - } - return new ReturnT(ReturnT.FAIL_CODE, beatResultSB.toString()); - - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java deleted file mode 100644 index f5630c33c..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.xxl.job.admin.core.route.strategy; - -import com.xxl.job.admin.core.route.ExecutorRouter; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.biz.model.TriggerParam; - -import java.util.List; - -/** - * Created by xuxueli on 17/3/10. - */ -public class ExecutorRouteFirst extends ExecutorRouter { - - @Override - public ReturnT route(TriggerParam triggerParam, List addressList) { - return new ReturnT(addressList.get(0)); - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java deleted file mode 100644 index fb0eab633..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.xxl.job.admin.core.route.strategy; - -import com.xxl.job.admin.core.route.ExecutorRouter; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.biz.model.TriggerParam; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * 单个JOB对应的每个执行器,使用频率最低的优先被选举 a(*)、LFU(Least Frequently Used):最不经常使用,频率/次数 b、LRU(Least - * Recently Used):最近最久未使用,时间 - * - * Created by xuxueli on 17/3/10. - */ -public class ExecutorRouteLFU extends ExecutorRouter { - - private static ConcurrentMap> jobLfuMap = new ConcurrentHashMap>(); - - private static long CACHE_VALID_TIME = 0; - - public String route(int jobId, List addressList) { - - // cache clear - if (System.currentTimeMillis() > CACHE_VALID_TIME) { - jobLfuMap.clear(); - CACHE_VALID_TIME = System.currentTimeMillis() + 1000 * 60 * 60 * 24; - } - - // lfu item init - HashMap lfuItemMap = jobLfuMap.get(jobId); // Key排序可以用TreeMap+构造入参Compare;Value排序暂时只能通过ArrayList; - if (lfuItemMap == null) { - lfuItemMap = new HashMap(); - jobLfuMap.putIfAbsent(jobId, lfuItemMap); // 避免重复覆盖 - } - - // put new - for (String address : addressList) { - if (!lfuItemMap.containsKey(address) || lfuItemMap.get(address) > 1000000) { - lfuItemMap.put(address, new Random().nextInt(addressList.size())); // 初始化时主动Random一次,缓解首次压力 - } - } - // remove old - List delKeys = new ArrayList<>(); - for (String existKey : lfuItemMap.keySet()) { - if (!addressList.contains(existKey)) { - delKeys.add(existKey); - } - } - if (delKeys.size() > 0) { - for (String delKey : delKeys) { - lfuItemMap.remove(delKey); - } - } - - // load least userd count address - List> lfuItemList = new ArrayList>(lfuItemMap.entrySet()); - Collections.sort(lfuItemList, new Comparator>() { - @Override - public int compare(Map.Entry o1, Map.Entry o2) { - return o1.getValue().compareTo(o2.getValue()); - } - }); - - Map.Entry addressItem = lfuItemList.get(0); - String minAddress = addressItem.getKey(); - addressItem.setValue(addressItem.getValue() + 1); - - return addressItem.getKey(); - } - - @Override - public ReturnT route(TriggerParam triggerParam, List addressList) { - String address = route(triggerParam.getJobId(), addressList); - return new ReturnT(address); - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java deleted file mode 100644 index 59b48f5ab..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.xxl.job.admin.core.route.strategy; - -import com.xxl.job.admin.core.route.ExecutorRouter; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.biz.model.TriggerParam; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * 单个JOB对应的每个执行器,最久为使用的优先被选举 a、LFU(Least Frequently Used):最不经常使用,频率/次数 b(*)、LRU(Least - * Recently Used):最近最久未使用,时间 - * - * Created by xuxueli on 17/3/10. - */ -public class ExecutorRouteLRU extends ExecutorRouter { - - private static ConcurrentMap> jobLRUMap = new ConcurrentHashMap>(); - - private static long CACHE_VALID_TIME = 0; - - public String route(int jobId, List addressList) { - - // cache clear - if (System.currentTimeMillis() > CACHE_VALID_TIME) { - jobLRUMap.clear(); - CACHE_VALID_TIME = System.currentTimeMillis() + 1000 * 60 * 60 * 24; - } - - // init lru - LinkedHashMap lruItem = jobLRUMap.get(jobId); - if (lruItem == null) { - /** - * LinkedHashMap a、accessOrder:true=访问顺序排序(get/put时排序);false=插入顺序排期; - * b、removeEldestEntry:新增元素时将会调用,返回true时会删除最老元素;可封装LinkedHashMap并重写该方法,比如定义最大容量,超出是返回true即可实现固定长度的LRU算法; - */ - lruItem = new LinkedHashMap(16, 0.75f, true); - jobLRUMap.putIfAbsent(jobId, lruItem); - } - - // put new - for (String address : addressList) { - if (!lruItem.containsKey(address)) { - lruItem.put(address, address); - } - } - // remove old - List delKeys = new ArrayList<>(); - for (String existKey : lruItem.keySet()) { - if (!addressList.contains(existKey)) { - delKeys.add(existKey); - } - } - if (delKeys.size() > 0) { - for (String delKey : delKeys) { - lruItem.remove(delKey); - } - } - - // load - String eldestKey = lruItem.entrySet().iterator().next().getKey(); - String eldestValue = lruItem.get(eldestKey); - return eldestValue; - } - - @Override - public ReturnT route(TriggerParam triggerParam, List addressList) { - String address = route(triggerParam.getJobId(), addressList); - return new ReturnT(address); - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java deleted file mode 100644 index 431815b08..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.xxl.job.admin.core.route.strategy; - -import com.xxl.job.admin.core.route.ExecutorRouter; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.biz.model.TriggerParam; - -import java.util.List; - -/** - * Created by xuxueli on 17/3/10. - */ -public class ExecutorRouteLast extends ExecutorRouter { - - @Override - public ReturnT route(TriggerParam triggerParam, List addressList) { - return new ReturnT(addressList.get(addressList.size() - 1)); - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java deleted file mode 100644 index 298c95908..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.xxl.job.admin.core.route.strategy; - -import com.xxl.job.admin.core.route.ExecutorRouter; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.biz.model.TriggerParam; - -import java.util.List; -import java.util.Random; - -/** - * Created by xuxueli on 17/3/10. - */ -public class ExecutorRouteRandom extends ExecutorRouter { - - private static Random localRandom = new Random(); - - @Override - public ReturnT route(TriggerParam triggerParam, List addressList) { - String address = addressList.get(localRandom.nextInt(addressList.size())); - return new ReturnT(address); - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java deleted file mode 100644 index 234da4f23..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.xxl.job.admin.core.route.strategy; - -import com.xxl.job.admin.core.route.ExecutorRouter; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.biz.model.TriggerParam; - -import java.util.List; -import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Created by xuxueli on 17/3/10. - */ -public class ExecutorRouteRound extends ExecutorRouter { - - private static ConcurrentMap routeCountEachJob = new ConcurrentHashMap<>(); - - private static long CACHE_VALID_TIME = 0; - - private static int count(int jobId) { - // cache clear - if (System.currentTimeMillis() > CACHE_VALID_TIME) { - routeCountEachJob.clear(); - CACHE_VALID_TIME = System.currentTimeMillis() + 1000 * 60 * 60 * 24; - } - - AtomicInteger count = routeCountEachJob.get(jobId); - if (count == null || count.get() > 1000000) { - // 初始化时主动Random一次,缓解首次压力 - count = new AtomicInteger(new Random().nextInt(100)); - } - else { - // count++ - count.addAndGet(1); - } - routeCountEachJob.put(jobId, count); - return count.get(); - } - - @Override - public ReturnT route(TriggerParam triggerParam, List addressList) { - String address = addressList.get(count(triggerParam.getJobId()) % addressList.size()); - return new ReturnT(address); - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/MisfireStrategyEnum.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/MisfireStrategyEnum.java deleted file mode 100644 index 900fa768d..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/MisfireStrategyEnum.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.xxl.job.admin.core.scheduler; - -import com.xxl.job.admin.core.util.I18nUtil; - -/** - * @author xuxueli 2020-10-29 21:11:23 - */ -public enum MisfireStrategyEnum { - - /** - * do nothing - */ - DO_NOTHING(I18nUtil.getString("misfire_strategy_do_nothing")), - - /** - * fire once now - */ - FIRE_ONCE_NOW(I18nUtil.getString("misfire_strategy_fire_once_now")); - - private String title; - - MisfireStrategyEnum(String title) { - this.title = title; - } - - public String getTitle() { - return title; - } - - public static MisfireStrategyEnum match(String name, MisfireStrategyEnum defaultItem) { - for (MisfireStrategyEnum item : MisfireStrategyEnum.values()) { - if (item.name().equals(name)) { - return item; - } - } - return defaultItem; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/ScheduleTypeEnum.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/ScheduleTypeEnum.java deleted file mode 100644 index f97bbac6f..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/ScheduleTypeEnum.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.xxl.job.admin.core.scheduler; - -import com.xxl.job.admin.core.util.I18nUtil; - -/** - * @author xuxueli 2020-10-29 21:11:23 - */ -public enum ScheduleTypeEnum { - - NONE(I18nUtil.getString("schedule_type_none")), - - /** - * schedule by cron - */ - CRON(I18nUtil.getString("schedule_type_cron")), - - /** - * schedule by fixed rate (in seconds) - */ - FIX_RATE(I18nUtil.getString("schedule_type_fix_rate")), - - /** - * schedule by fix delay (in seconds), after the last time - */ - /* FIX_DELAY(I18nUtil.getString("schedule_type_fix_delay")) */; - - private String title; - - ScheduleTypeEnum(String title) { - this.title = title; - } - - public String getTitle() { - return title; - } - - public static ScheduleTypeEnum match(String name, ScheduleTypeEnum defaultItem) { - for (ScheduleTypeEnum item : ScheduleTypeEnum.values()) { - if (item.name().equals(name)) { - return item; - } - } - return defaultItem; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/XxlJobScheduler.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/XxlJobScheduler.java deleted file mode 100644 index 4177d9bab..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/XxlJobScheduler.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.xxl.job.admin.core.scheduler; - -import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -import com.xxl.job.admin.core.thread.*; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.core.biz.ExecutorBiz; -import com.xxl.job.core.biz.client.ExecutorBizClient; -import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * @author xuxueli 2018-10-28 00:18:17 - */ - -public class XxlJobScheduler { - - private static final Logger logger = LoggerFactory.getLogger(XxlJobScheduler.class); - - public void init() throws Exception { - // init i18n - initI18n(); - - // admin trigger pool start - JobTriggerPoolHelper.toStart(); - - // admin registry monitor run - JobRegistryHelper.getInstance().start(); - - // admin fail-monitor run - JobFailMonitorHelper.getInstance().start(); - - // admin lose-monitor run ( depend on JobTriggerPoolHelper ) - JobCompleteHelper.getInstance().start(); - - // admin log report start - JobLogReportHelper.getInstance().start(); - - // start-schedule ( depend on JobTriggerPoolHelper ) - JobScheduleHelper.getInstance().start(); - - logger.info(">>>>>>>>> init xxl-job admin success."); - } - - public void destroy() throws Exception { - - // stop-schedule - JobScheduleHelper.getInstance().toStop(); - - // admin log report stop - JobLogReportHelper.getInstance().toStop(); - - // admin lose-monitor stop - JobCompleteHelper.getInstance().toStop(); - - // admin fail-monitor stop - JobFailMonitorHelper.getInstance().toStop(); - - // admin registry stop - JobRegistryHelper.getInstance().toStop(); - - // admin trigger pool stop - JobTriggerPoolHelper.toStop(); - - } - - // ---------------------- I18n ---------------------- - - private void initI18n() { - for (ExecutorBlockStrategyEnum item : ExecutorBlockStrategyEnum.values()) { - item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name()))); - } - } - - // ---------------------- executor-client ---------------------- - private static ConcurrentMap executorBizRepository = new ConcurrentHashMap(); - - public static ExecutorBiz getExecutorBiz(String address) throws Exception { - // valid - if (address == null || address.trim().length() == 0) { - return null; - } - - // load-cache - address = address.trim(); - ExecutorBiz executorBiz = executorBizRepository.get(address); - if (executorBiz != null) { - return executorBiz; - } - - // set-cache - executorBiz = new ExecutorBizClient(address, XxlJobAdminConfig.getAdminConfig().getAccessToken(), - XxlJobAdminConfig.getAdminConfig().getTimeout()); - - executorBizRepository.put(address, executorBiz); - return executorBiz; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobCompleteHelper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobCompleteHelper.java deleted file mode 100644 index 256521e15..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobCompleteHelper.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.xxl.job.admin.core.thread; - -import com.xxl.job.admin.core.complete.XxlJobCompleter; -import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -import com.xxl.job.admin.core.model.XxlJobLog; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.core.biz.model.HandleCallbackParam; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.util.DateUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Date; -import java.util.List; -import java.util.concurrent.*; - -/** - * job lose-monitor instance - * - * @author xuxueli 2015-9-1 18:05:56 - */ -public class JobCompleteHelper { - - private static Logger logger = LoggerFactory.getLogger(JobCompleteHelper.class); - - private static JobCompleteHelper instance = new JobCompleteHelper(); - - public static JobCompleteHelper getInstance() { - return instance; - } - - // ---------------------- monitor ---------------------- - - private ThreadPoolExecutor callbackThreadPool = null; - - private Thread monitorThread; - - private volatile boolean toStop = false; - - public void start() { - - // for callback - callbackThreadPool = new ThreadPoolExecutor(2, 20, 30L, TimeUnit.SECONDS, - new LinkedBlockingQueue(3000), new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - return new Thread(r, "xxl-job, admin JobLosedMonitorHelper-callbackThreadPool-" + r.hashCode()); - } - }, new RejectedExecutionHandler() { - @Override - public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { - r.run(); - logger.warn( - ">>>>>>>>>>> xxl-job, callback too fast, match threadpool rejected handler(run now)."); - } - }); - - // for monitor - monitorThread = new Thread(new Runnable() { - - @Override - public void run() { - - // wait for JobTriggerPoolHelper-init - try { - TimeUnit.MILLISECONDS.sleep(50); - } - catch (Throwable e) { - if (!toStop) { - logger.error(e.getMessage(), e); - } - } - - // monitor - while (!toStop) { - try { - // 任务结果丢失处理:调度记录停留在 "运行中" 状态超过10min,且对应执行器心跳注册失败不在线,则将本地调度主动标记失败; - Date losedTime = DateUtil.addMinutes(new Date(), -10); - List losedJobIds = XxlJobAdminConfig.getAdminConfig() - .getXxlJobLogDao() - .findLostJobIds(losedTime); - - if (losedJobIds != null && losedJobIds.size() > 0) { - for (Long logId : losedJobIds) { - - XxlJobLog jobLog = new XxlJobLog(); - jobLog.setId(logId); - - jobLog.setHandleTime(new Date()); - jobLog.setHandleCode(ReturnT.FAIL_CODE); - jobLog.setHandleMsg(I18nUtil.getString("joblog_lost_fail")); - - XxlJobCompleter.updateHandleInfoAndFinish(jobLog); - } - - } - } - catch (Throwable e) { - if (!toStop) { - logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e); - } - } - - try { - TimeUnit.SECONDS.sleep(60); - } - catch (Throwable e) { - if (!toStop) { - logger.error(e.getMessage(), e); - } - } - - } - - logger.info(">>>>>>>>>>> xxl-job, JobLosedMonitorHelper stop"); - - } - }); - monitorThread.setDaemon(true); - monitorThread.setName("xxl-job, admin JobLosedMonitorHelper"); - monitorThread.start(); - } - - public void toStop() { - toStop = true; - - // stop registryOrRemoveThreadPool - callbackThreadPool.shutdownNow(); - - // stop monitorThread (interrupt and wait) - monitorThread.interrupt(); - try { - monitorThread.join(); - } - catch (Throwable e) { - logger.error(e.getMessage(), e); - } - } - - // ---------------------- helper ---------------------- - - public ReturnT callback(List callbackParamList) { - - callbackThreadPool.execute(new Runnable() { - @Override - public void run() { - for (HandleCallbackParam handleCallbackParam : callbackParamList) { - ReturnT callbackResult = callback(handleCallbackParam); - logger.debug(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}", - (callbackResult.getCode() == ReturnT.SUCCESS_CODE ? "success" : "fail"), - handleCallbackParam, callbackResult); - } - } - }); - - return ReturnT.SUCCESS; - } - - private ReturnT callback(HandleCallbackParam handleCallbackParam) { - // valid log item - XxlJobLog log = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().load(handleCallbackParam.getLogId()); - if (log == null) { - return new ReturnT(ReturnT.FAIL_CODE, "log item not found."); - } - if (log.getHandleCode() > 0) { - return new ReturnT(ReturnT.FAIL_CODE, "log repeate callback."); // avoid - // repeat - // callback, - // trigger - // child - // job - // etc - } - - // handle msg - StringBuffer handleMsg = new StringBuffer(); - if (log.getHandleMsg() != null) { - handleMsg.append(log.getHandleMsg()).append("
"); - } - if (handleCallbackParam.getHandleMsg() != null) { - handleMsg.append(handleCallbackParam.getHandleMsg()); - } - - // success, save log - log.setHandleTime(new Date()); - log.setHandleCode(handleCallbackParam.getHandleCode()); - log.setHandleMsg(handleMsg.toString()); - XxlJobCompleter.updateHandleInfoAndFinish(log); - - return ReturnT.SUCCESS; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java deleted file mode 100644 index 722aaed6a..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.xxl.job.admin.core.thread; - -import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.core.model.XxlJobLog; -import com.xxl.job.admin.core.trigger.TriggerTypeEnum; -import com.xxl.job.admin.core.util.I18nUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * job monitor instance - * - * @author xuxueli 2015-9-1 18:05:56 - */ -public class JobFailMonitorHelper { - - private static Logger logger = LoggerFactory.getLogger(JobFailMonitorHelper.class); - - private static JobFailMonitorHelper instance = new JobFailMonitorHelper(); - - public static JobFailMonitorHelper getInstance() { - return instance; - } - - // ---------------------- monitor ---------------------- - - private Thread monitorThread; - - private volatile boolean toStop = false; - - public void start() { - monitorThread = new Thread(new Runnable() { - - @Override - public void run() { - - // monitor - while (!toStop) { - try { - - List failLogIds = XxlJobAdminConfig.getAdminConfig() - .getXxlJobLogDao() - .findFailJobLogIds(1000); - if (failLogIds != null && !failLogIds.isEmpty()) { - for (long failLogId : failLogIds) { - - // lock log - int lockRet = XxlJobAdminConfig.getAdminConfig() - .getXxlJobLogDao() - .updateAlarmStatus(failLogId, 0, -1); - if (lockRet < 1) { - continue; - } - XxlJobLog log = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().load(failLogId); - XxlJobInfo info = XxlJobAdminConfig.getAdminConfig() - .getXxlJobInfoDao() - .loadById(log.getJobId()); - - // 1、fail retry monitor - if (log.getExecutorFailRetryCount() > 0) { - JobTriggerPoolHelper.trigger(log.getJobId(), TriggerTypeEnum.RETRY, - (log.getExecutorFailRetryCount() - 1), log.getExecutorShardingParam(), - log.getExecutorParam(), null); - String retryMsg = "

>>>>>>>>>>>" - + I18nUtil.getString("jobconf_trigger_type_retry") - + "<<<<<<<<<<<
"; - log.setTriggerMsg(log.getTriggerMsg() + retryMsg); - XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateTriggerInfo(log); - } - - // 2、fail alarm monitor - int newAlarmStatus = 0; // 告警状态:0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败 - if (info != null) { - boolean alarmResult = XxlJobAdminConfig.getAdminConfig() - .getJobAlarmer() - .alarm(info, log); - newAlarmStatus = alarmResult ? 2 : 3; - } - else { - newAlarmStatus = 1; - } - - XxlJobAdminConfig.getAdminConfig() - .getXxlJobLogDao() - .updateAlarmStatus(failLogId, -1, newAlarmStatus); - } - } - - } - catch (Throwable e) { - if (!toStop) { - logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e); - } - } - - try { - TimeUnit.SECONDS.sleep(10); - } - catch (Throwable e) { - if (!toStop) { - logger.error(e.getMessage(), e); - } - } - - } - - logger.info(">>>>>>>>>>> xxl-job, job fail monitor thread stop"); - - } - }); - monitorThread.setDaemon(true); - monitorThread.setName("xxl-job, admin JobFailMonitorHelper"); - monitorThread.start(); - } - - public void toStop() { - toStop = true; - // interrupt and wait - monitorThread.interrupt(); - try { - monitorThread.join(); - } - catch (Throwable e) { - logger.error(e.getMessage(), e); - } - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobLogReportHelper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobLogReportHelper.java deleted file mode 100644 index a4df7a59a..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobLogReportHelper.java +++ /dev/null @@ -1,170 +0,0 @@ -package com.xxl.job.admin.core.thread; - -import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -import com.xxl.job.admin.core.model.XxlJobLogReport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -/** - * job log report helper - * - * @author xuxueli 2019-11-22 - */ -public class JobLogReportHelper { - - private static Logger logger = LoggerFactory.getLogger(JobLogReportHelper.class); - - private static JobLogReportHelper instance = new JobLogReportHelper(); - - public static JobLogReportHelper getInstance() { - return instance; - } - - private Thread logrThread; - - private volatile boolean toStop = false; - - public void start() { - logrThread = new Thread(new Runnable() { - - @Override - public void run() { - - // last clean log time - long lastCleanLogTime = 0; - - while (!toStop) { - - // 1、log-report refresh: refresh log report in 3 days - try { - - for (int i = 0; i < 3; i++) { - - // today - Calendar itemDay = Calendar.getInstance(); - itemDay.add(Calendar.DAY_OF_MONTH, -i); - itemDay.set(Calendar.HOUR_OF_DAY, 0); - itemDay.set(Calendar.MINUTE, 0); - itemDay.set(Calendar.SECOND, 0); - itemDay.set(Calendar.MILLISECOND, 0); - - Date todayFrom = itemDay.getTime(); - - itemDay.set(Calendar.HOUR_OF_DAY, 23); - itemDay.set(Calendar.MINUTE, 59); - itemDay.set(Calendar.SECOND, 59); - itemDay.set(Calendar.MILLISECOND, 999); - - Date todayTo = itemDay.getTime(); - - // refresh log-report every minute - XxlJobLogReport xxlJobLogReport = new XxlJobLogReport(); - xxlJobLogReport.setTriggerDay(todayFrom); - xxlJobLogReport.setRunningCount(0); - xxlJobLogReport.setSucCount(0); - xxlJobLogReport.setFailCount(0); - - Map triggerCountMap = XxlJobAdminConfig.getAdminConfig() - .getXxlJobLogDao() - .findLogReport(todayFrom, todayTo); - if (triggerCountMap != null && triggerCountMap.size() > 0) { - int triggerDayCount = triggerCountMap.containsKey("triggerDayCount") - ? Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCount"))) : 0; - int triggerDayCountRunning = triggerCountMap.containsKey("triggerDayCountRunning") - ? Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCountRunning"))) - : 0; - int triggerDayCountSuc = triggerCountMap.containsKey("triggerDayCountSuc") - ? Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCountSuc"))) - : 0; - int triggerDayCountFail = triggerDayCount - triggerDayCountRunning - triggerDayCountSuc; - - xxlJobLogReport.setRunningCount(triggerDayCountRunning); - xxlJobLogReport.setSucCount(triggerDayCountSuc); - xxlJobLogReport.setFailCount(triggerDayCountFail); - } - - // do refresh - int ret = XxlJobAdminConfig.getAdminConfig() - .getXxlJobLogReportDao() - .update(xxlJobLogReport); - if (ret < 1) { - XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao().save(xxlJobLogReport); - } - } - - } - catch (Throwable e) { - if (!toStop) { - logger.error(">>>>>>>>>>> xxl-job, job log report thread error:{}", e); - } - } - - // 2、log-clean: switch open & once each day - if (XxlJobAdminConfig.getAdminConfig().getLogretentiondays() > 0 - && System.currentTimeMillis() - lastCleanLogTime > 24 * 60 * 60 * 1000) { - - // expire-time - Calendar expiredDay = Calendar.getInstance(); - expiredDay.add(Calendar.DAY_OF_MONTH, - -1 * XxlJobAdminConfig.getAdminConfig().getLogretentiondays()); - expiredDay.set(Calendar.HOUR_OF_DAY, 0); - expiredDay.set(Calendar.MINUTE, 0); - expiredDay.set(Calendar.SECOND, 0); - expiredDay.set(Calendar.MILLISECOND, 0); - Date clearBeforeTime = expiredDay.getTime(); - - // clean expired log - List logIds = null; - do { - logIds = XxlJobAdminConfig.getAdminConfig() - .getXxlJobLogDao() - .findClearLogIds(0, 0, clearBeforeTime, 0, 1000); - if (logIds != null && logIds.size() > 0) { - XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().clearLog(logIds); - } - } - while (logIds != null && logIds.size() > 0); - - // update clean time - lastCleanLogTime = System.currentTimeMillis(); - } - - try { - TimeUnit.MINUTES.sleep(1); - } - catch (Throwable e) { - if (!toStop) { - logger.error(e.getMessage(), e); - } - } - - } - - logger.info(">>>>>>>>>>> xxl-job, job log report thread stop"); - - } - }); - logrThread.setDaemon(true); - logrThread.setName("xxl-job, admin JobLogReportHelper"); - logrThread.start(); - } - - public void toStop() { - toStop = true; - // interrupt and wait - logrThread.interrupt(); - try { - logrThread.join(); - } - catch (Throwable e) { - logger.error(e.getMessage(), e); - } - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryHelper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryHelper.java deleted file mode 100644 index c10947b6a..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryHelper.java +++ /dev/null @@ -1,228 +0,0 @@ -package com.xxl.job.admin.core.thread; - -import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -import com.xxl.job.admin.core.model.XxlJobGroup; -import com.xxl.job.admin.core.model.XxlJobRegistry; -import com.xxl.job.core.biz.model.RegistryParam; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.enums.RegistryConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; - -import java.util.*; -import java.util.concurrent.*; - -/** - * job registry instance - * - * @author xuxueli 2016-10-02 19:10:24 - */ -public class JobRegistryHelper { - - private static Logger logger = LoggerFactory.getLogger(JobRegistryHelper.class); - - private static JobRegistryHelper instance = new JobRegistryHelper(); - - private ThreadPoolExecutor registryOrRemoveThreadPool = null; - - private Thread registryMonitorThread; - - private volatile boolean toStop = false; - - public static JobRegistryHelper getInstance() { - return instance; - } - - public void start() { - - // for registry or remove - registryOrRemoveThreadPool = new ThreadPoolExecutor(2, 10, 30L, TimeUnit.SECONDS, - new LinkedBlockingQueue(2000), new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - return new Thread(r, - "xxl-job, admin JobRegistryMonitorHelper-registryOrRemoveThreadPool-" + r.hashCode()); - } - }, new RejectedExecutionHandler() { - @Override - public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { - r.run(); - logger.warn( - ">>>>>>>>>>> xxl-job, registry or remove too fast, match threadpool rejected handler(run now)."); - } - }); - - // for monitor - registryMonitorThread = new Thread(new Runnable() { - @Override - public void run() { - while (!toStop) { - try { - // auto registry group - List groupList = XxlJobAdminConfig.getAdminConfig() - .getXxlJobGroupDao() - .findByAddressType(0); - if (groupList != null && !groupList.isEmpty()) { - - // remove dead address (admin/executor) - List ids = XxlJobAdminConfig.getAdminConfig() - .getXxlJobRegistryDao() - .findDead(RegistryConfig.DEAD_TIMEOUT, new Date()); - if (ids != null && ids.size() > 0) { - XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().removeDead(ids); - } - - // fresh online address (admin/executor) - HashMap> appAddressMap = new HashMap>(); - List list = XxlJobAdminConfig.getAdminConfig() - .getXxlJobRegistryDao() - .findAll(RegistryConfig.DEAD_TIMEOUT, new Date()); - if (list != null) { - for (XxlJobRegistry item : list) { - if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) { - String appname = item.getRegistryKey(); - List registryList = appAddressMap.get(appname); - if (registryList == null) { - registryList = new ArrayList(); - } - - if (!registryList.contains(item.getRegistryValue())) { - registryList.add(item.getRegistryValue()); - } - appAddressMap.put(appname, registryList); - } - } - } - - // fresh group address - for (XxlJobGroup group : groupList) { - List registryList = appAddressMap.get(group.getAppname()); - String addressListStr = null; - if (registryList != null && !registryList.isEmpty()) { - Collections.sort(registryList); - StringBuilder addressListSB = new StringBuilder(); - for (String item : registryList) { - addressListSB.append(item).append(","); - } - addressListStr = addressListSB.toString(); - addressListStr = addressListStr.substring(0, addressListStr.length() - 1); - } - group.setAddressList(addressListStr); - group.setUpdateTime(new Date()); - - XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().update(group); - } - } - } - catch (Throwable e) { - if (!toStop) { - logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e); - } - } - try { - TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT); - } - catch (Throwable e) { - if (!toStop) { - logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e); - } - } - } - logger.info(">>>>>>>>>>> xxl-job, job registry monitor thread stop"); - } - }); - registryMonitorThread.setDaemon(true); - registryMonitorThread.setName("xxl-job, admin JobRegistryMonitorHelper-registryMonitorThread"); - registryMonitorThread.start(); - } - - public void toStop() { - toStop = true; - - // stop registryOrRemoveThreadPool - registryOrRemoveThreadPool.shutdownNow(); - - // stop monitir (interrupt and wait) - registryMonitorThread.interrupt(); - try { - registryMonitorThread.join(); - } - catch (Throwable e) { - logger.error(e.getMessage(), e); - } - } - - // ---------------------- helper ---------------------- - - public ReturnT registry(RegistryParam registryParam) { - - // valid - if (!StringUtils.hasText(registryParam.getRegistryGroup()) - || !StringUtils.hasText(registryParam.getRegistryKey()) - || !StringUtils.hasText(registryParam.getRegistryValue())) { - return new ReturnT(ReturnT.FAIL_CODE, "Illegal Argument."); - } - - // async execute - registryOrRemoveThreadPool.execute(new Runnable() { - @Override - public void run() { - // 0-fail; 1-save suc; 2-update suc; - int ret = XxlJobAdminConfig.getAdminConfig() - .getXxlJobRegistryDao() - .registrySaveOrUpdate(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), - registryParam.getRegistryValue(), new Date()); - if (ret == 1) { - // fresh (add) - freshGroupRegistryInfo(registryParam); - } - /* - * int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao(). - * registryUpdate(registryParam.getRegistryGroup(), - * registryParam.getRegistryKey(), registryParam.getRegistryValue(), new - * Date()); if (ret < 1) { - * XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registrySave( - * registryParam.getRegistryGroup(), registryParam.getRegistryKey(), - * registryParam.getRegistryValue(), new Date()); - * - * // fresh freshGroupRegistryInfo(registryParam); } - */ - } - }); - - return ReturnT.SUCCESS; - } - - public ReturnT registryRemove(RegistryParam registryParam) { - - // valid - if (!StringUtils.hasText(registryParam.getRegistryGroup()) - || !StringUtils.hasText(registryParam.getRegistryKey()) - || !StringUtils.hasText(registryParam.getRegistryValue())) { - return new ReturnT(ReturnT.FAIL_CODE, "Illegal Argument."); - } - - // async execute - registryOrRemoveThreadPool.execute(new Runnable() { - @Override - public void run() { - int ret = XxlJobAdminConfig.getAdminConfig() - .getXxlJobRegistryDao() - .registryDelete(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), - registryParam.getRegistryValue()); - if (ret > 0) { - // fresh (delete) - freshGroupRegistryInfo(registryParam); - } - } - }); - - return ReturnT.SUCCESS; - } - - private void freshGroupRegistryInfo(RegistryParam registryParam) { - // Under consideration, prevent affecting core tables - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java deleted file mode 100644 index 62dbf9ea5..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java +++ /dev/null @@ -1,427 +0,0 @@ -package com.xxl.job.admin.core.thread; - -import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -import com.xxl.job.admin.core.cron.CronExpression; -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum; -import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum; -import com.xxl.job.admin.core.trigger.TriggerTypeEnum; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -/** - * @author xuxueli 2019-05-21 - */ -public class JobScheduleHelper { - - private static Logger logger = LoggerFactory.getLogger(JobScheduleHelper.class); - - private static JobScheduleHelper instance = new JobScheduleHelper(); - - public static JobScheduleHelper getInstance() { - return instance; - } - - public static final long PRE_READ_MS = 5000; // pre read - - private Thread scheduleThread; - - private Thread ringThread; - - private volatile boolean scheduleThreadToStop = false; - - private volatile boolean ringThreadToStop = false; - - private volatile static Map> ringData = new ConcurrentHashMap<>(); - - public void start() { - - // schedule thread - scheduleThread = new Thread(new Runnable() { - @Override - public void run() { - - try { - TimeUnit.MILLISECONDS.sleep(5000 - System.currentTimeMillis() % 1000); - } - catch (Throwable e) { - if (!scheduleThreadToStop) { - logger.error(e.getMessage(), e); - } - } - logger.info(">>>>>>>>> init xxl-job admin scheduler success."); - - // pre-read count: treadpool-size * trigger-qps (each trigger cost 50ms, - // qps = 1000/50 = 20) - int preReadCount = (XxlJobAdminConfig.getAdminConfig().getTriggerPoolFastMax() - + XxlJobAdminConfig.getAdminConfig().getTriggerPoolSlowMax()) * 20; - - while (!scheduleThreadToStop) { - - // Scan Job - long start = System.currentTimeMillis(); - - Connection conn = null; - Boolean connAutoCommit = null; - PreparedStatement preparedStatement = null; - - boolean preReadSuc = true; - try { - - conn = XxlJobAdminConfig.getAdminConfig().getDataSource().getConnection(); - connAutoCommit = conn.getAutoCommit(); - conn.setAutoCommit(false); - - preparedStatement = conn.prepareStatement( - "select * from xxl_job_lock where lock_name = 'schedule_lock' for update"); - preparedStatement.execute(); - - // tx start - - // 1、pre read - long nowTime = System.currentTimeMillis(); - List scheduleList = XxlJobAdminConfig.getAdminConfig() - .getXxlJobInfoDao() - .scheduleJobQuery(nowTime + PRE_READ_MS, preReadCount); - if (scheduleList != null && scheduleList.size() > 0) { - // 2、push time-ring - for (XxlJobInfo jobInfo : scheduleList) { - - // time-ring jump - if (nowTime > jobInfo.getTriggerNextTime() + PRE_READ_MS) { - // 2.1、trigger-expire > 5s:pass && make - // next-trigger-time - logger.warn(">>>>>>>>>>> xxl-job, schedule misfire, jobId = " + jobInfo.getId()); - - // 1、misfire match - MisfireStrategyEnum misfireStrategyEnum = MisfireStrategyEnum - .match(jobInfo.getMisfireStrategy(), MisfireStrategyEnum.DO_NOTHING); - if (MisfireStrategyEnum.FIRE_ONCE_NOW == misfireStrategyEnum) { - // FIRE_ONCE_NOW 》 trigger - JobTriggerPoolHelper.trigger(jobInfo.getId(), TriggerTypeEnum.MISFIRE, -1, null, - null, null); - logger.debug(">>>>>>>>>>> xxl-job, schedule push trigger : jobId = " - + jobInfo.getId()); - } - - // 2、fresh next - refreshNextValidTime(jobInfo, new Date()); - - } - else if (nowTime > jobInfo.getTriggerNextTime()) { - // 2.2、trigger-expire < 5s:direct-trigger && make - // next-trigger-time - - // 1、trigger - JobTriggerPoolHelper.trigger(jobInfo.getId(), TriggerTypeEnum.CRON, -1, null, null, - null); - logger.debug( - ">>>>>>>>>>> xxl-job, schedule push trigger : jobId = " + jobInfo.getId()); - - // 2、fresh next - refreshNextValidTime(jobInfo, new Date()); - - // next-trigger-time in 5s, pre-read again - if (jobInfo.getTriggerStatus() == 1 - && nowTime + PRE_READ_MS > jobInfo.getTriggerNextTime()) { - - // 1、make ring second - int ringSecond = (int) ((jobInfo.getTriggerNextTime() / 1000) % 60); - - // 2、push time ring - pushTimeRing(ringSecond, jobInfo.getId()); - - // 3、fresh next - refreshNextValidTime(jobInfo, new Date(jobInfo.getTriggerNextTime())); - - } - - } - else { - // 2.3、trigger-pre-read:time-ring trigger && make - // next-trigger-time - - // 1、make ring second - int ringSecond = (int) ((jobInfo.getTriggerNextTime() / 1000) % 60); - - // 2、push time ring - pushTimeRing(ringSecond, jobInfo.getId()); - - // 3、fresh next - refreshNextValidTime(jobInfo, new Date(jobInfo.getTriggerNextTime())); - - } - - } - - // 3、update trigger info - for (XxlJobInfo jobInfo : scheduleList) { - XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleUpdate(jobInfo); - } - - } - else { - preReadSuc = false; - } - - // tx stop - - } - catch (Throwable e) { - if (!scheduleThreadToStop) { - logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread error:{}", e); - } - } - finally { - - // commit - if (conn != null) { - try { - conn.commit(); - } - catch (Throwable e) { - if (!scheduleThreadToStop) { - logger.error(e.getMessage(), e); - } - } - try { - conn.setAutoCommit(connAutoCommit); - } - catch (Throwable e) { - if (!scheduleThreadToStop) { - logger.error(e.getMessage(), e); - } - } - try { - conn.close(); - } - catch (Throwable e) { - if (!scheduleThreadToStop) { - logger.error(e.getMessage(), e); - } - } - } - - // close PreparedStatement - if (null != preparedStatement) { - try { - preparedStatement.close(); - } - catch (Throwable e) { - if (!scheduleThreadToStop) { - logger.error(e.getMessage(), e); - } - } - } - } - long cost = System.currentTimeMillis() - start; - - // Wait seconds, align second - if (cost < 1000) { // scan-overtime, not wait - try { - // pre-read period: success > scan each second; fail > skip - // this period; - TimeUnit.MILLISECONDS - .sleep((preReadSuc ? 1000 : PRE_READ_MS) - System.currentTimeMillis() % 1000); - } - catch (Throwable e) { - if (!scheduleThreadToStop) { - logger.error(e.getMessage(), e); - } - } - } - - } - - logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread stop"); - } - }); - scheduleThread.setDaemon(true); - scheduleThread.setName("xxl-job, admin JobScheduleHelper#scheduleThread"); - scheduleThread.start(); - - // ring thread - ringThread = new Thread(new Runnable() { - @Override - public void run() { - - while (!ringThreadToStop) { - - // align second - try { - TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis() % 1000); - } - catch (Throwable e) { - if (!ringThreadToStop) { - logger.error(e.getMessage(), e); - } - } - - try { - // second data - List ringItemData = new ArrayList<>(); - int nowSecond = Calendar.getInstance().get(Calendar.SECOND); // 避免处理耗时太长,跨过刻度,向前校验一个刻度; - for (int i = 0; i < 2; i++) { - List tmpData = ringData.remove((nowSecond + 60 - i) % 60); - if (tmpData != null) { - ringItemData.addAll(tmpData); - } - } - - // ring trigger - logger.debug(">>>>>>>>>>> xxl-job, time-ring beat : " + nowSecond + " = " - + Arrays.asList(ringItemData)); - if (ringItemData.size() > 0) { - // do trigger - for (int jobId : ringItemData) { - // do trigger - JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.CRON, -1, null, null, null); - } - // clear - ringItemData.clear(); - } - } - catch (Throwable e) { - if (!ringThreadToStop) { - logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread error:{}", e); - } - } - } - logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread stop"); - } - }); - ringThread.setDaemon(true); - ringThread.setName("xxl-job, admin JobScheduleHelper#ringThread"); - ringThread.start(); - } - - private void refreshNextValidTime(XxlJobInfo jobInfo, Date fromTime) { - try { - Date nextValidTime = generateNextValidTime(jobInfo, fromTime); - if (nextValidTime != null) { - jobInfo.setTriggerStatus(-1); // pass, may be Inaccurate - jobInfo.setTriggerLastTime(jobInfo.getTriggerNextTime()); - jobInfo.setTriggerNextTime(nextValidTime.getTime()); - } - else { - // generateNextValidTime fail, stop job - jobInfo.setTriggerStatus(0); - jobInfo.setTriggerLastTime(0); - jobInfo.setTriggerNextTime(0); - logger.error( - ">>>>>>>>>>> xxl-job, refreshNextValidTime fail for job: jobId={}, scheduleType={}, scheduleConf={}", - jobInfo.getId(), jobInfo.getScheduleType(), jobInfo.getScheduleConf()); - } - } - catch (Throwable e) { - // generateNextValidTime error, stop job - jobInfo.setTriggerStatus(0); - jobInfo.setTriggerLastTime(0); - jobInfo.setTriggerNextTime(0); - - logger.error( - ">>>>>>>>>>> xxl-job, refreshNextValidTime error for job: jobId={}, scheduleType={}, scheduleConf={}", - jobInfo.getId(), jobInfo.getScheduleType(), jobInfo.getScheduleConf(), e); - } - } - - private void pushTimeRing(int ringSecond, int jobId) { - // push async ring - List ringItemData = ringData.get(ringSecond); - if (ringItemData == null) { - ringItemData = new ArrayList(); - ringData.put(ringSecond, ringItemData); - } - ringItemData.add(jobId); - - logger.debug( - ">>>>>>>>>>> xxl-job, schedule push time-ring : " + ringSecond + " = " + Arrays.asList(ringItemData)); - } - - public void toStop() { - - // 1、stop schedule - scheduleThreadToStop = true; - try { - TimeUnit.SECONDS.sleep(1); // wait - } - catch (Throwable e) { - logger.error(e.getMessage(), e); - } - if (scheduleThread.getState() != Thread.State.TERMINATED) { - // interrupt and wait - scheduleThread.interrupt(); - try { - scheduleThread.join(); - } - catch (Throwable e) { - logger.error(e.getMessage(), e); - } - } - - // if has ring data - boolean hasRingData = false; - if (!ringData.isEmpty()) { - for (int second : ringData.keySet()) { - List tmpData = ringData.get(second); - if (tmpData != null && tmpData.size() > 0) { - hasRingData = true; - break; - } - } - } - if (hasRingData) { - try { - TimeUnit.SECONDS.sleep(8); - } - catch (Throwable e) { - logger.error(e.getMessage(), e); - } - } - - // stop ring (wait job-in-memory stop) - ringThreadToStop = true; - try { - TimeUnit.SECONDS.sleep(1); - } - catch (Throwable e) { - logger.error(e.getMessage(), e); - } - if (ringThread.getState() != Thread.State.TERMINATED) { - // interrupt and wait - ringThread.interrupt(); - try { - ringThread.join(); - } - catch (Throwable e) { - logger.error(e.getMessage(), e); - } - } - - logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper stop"); - } - - // ---------------------- tools ---------------------- - public static Date generateNextValidTime(XxlJobInfo jobInfo, Date fromTime) throws Exception { - ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null); - if (ScheduleTypeEnum.CRON == scheduleTypeEnum) { - Date nextValidTime = new CronExpression(jobInfo.getScheduleConf()).getNextValidTimeAfter(fromTime); - return nextValidTime; - } - else if (ScheduleTypeEnum.FIX_RATE == scheduleTypeEnum /* - * || ScheduleTypeEnum. - * FIX_DELAY == - * scheduleTypeEnum - */) { - return new Date(fromTime.getTime() + Long.parseLong(jobInfo.getScheduleConf()) * 1000L); - } - return null; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobTriggerPoolHelper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobTriggerPoolHelper.java deleted file mode 100644 index b42c83d04..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobTriggerPoolHelper.java +++ /dev/null @@ -1,154 +0,0 @@ -package com.xxl.job.admin.core.thread; - -import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -import com.xxl.job.admin.core.trigger.TriggerTypeEnum; -import com.xxl.job.admin.core.trigger.XxlJobTrigger; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * job trigger thread pool helper - * - * @author xuxueli 2018-07-03 21:08:07 - */ -public class JobTriggerPoolHelper { - - private static Logger logger = LoggerFactory.getLogger(JobTriggerPoolHelper.class); - - // ---------------------- trigger pool ---------------------- - - // fast/slow thread pool - private ThreadPoolExecutor fastTriggerPool = null; - - private ThreadPoolExecutor slowTriggerPool = null; - - public void start() { - fastTriggerPool = new ThreadPoolExecutor(10, XxlJobAdminConfig.getAdminConfig().getTriggerPoolFastMax(), 60L, - TimeUnit.SECONDS, new LinkedBlockingQueue(2000), new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-fastTriggerPool-" + r.hashCode()); - } - }, new RejectedExecutionHandler() { - @Override - public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { - logger.error( - ">>>>>>>>>>> xxl-job, admin JobTriggerPoolHelper-fastTriggerPool execute too fast, Runnable=" - + r.toString()); - } - }); - - slowTriggerPool = new ThreadPoolExecutor(10, XxlJobAdminConfig.getAdminConfig().getTriggerPoolSlowMax(), 60L, - TimeUnit.SECONDS, new LinkedBlockingQueue(5000), new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-slowTriggerPool-" + r.hashCode()); - } - }, new RejectedExecutionHandler() { - @Override - public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { - logger.error( - ">>>>>>>>>>> xxl-job, admin JobTriggerPoolHelper-slowTriggerPool execute too fast, Runnable=" - + r.toString()); - } - }); - } - - public void stop() { - // triggerPool.shutdown(); - fastTriggerPool.shutdownNow(); - slowTriggerPool.shutdownNow(); - logger.info(">>>>>>>>> xxl-job trigger thread pool shutdown success."); - } - - // job timeout count - private volatile long minTim = System.currentTimeMillis() / 60000; // ms > min - - private volatile ConcurrentMap jobTimeoutCountMap = new ConcurrentHashMap<>(); - - /** - * add trigger - */ - public void addTrigger(final int jobId, final TriggerTypeEnum triggerType, final int failRetryCount, - final String executorShardingParam, final String executorParam, final String addressList) { - - // choose thread pool - ThreadPoolExecutor triggerPool_ = fastTriggerPool; - AtomicInteger jobTimeoutCount = jobTimeoutCountMap.get(jobId); - if (jobTimeoutCount != null && jobTimeoutCount.get() > 10) { // job-timeout 10 - // times in 1 min - triggerPool_ = slowTriggerPool; - } - - // trigger - triggerPool_.execute(new Runnable() { - @Override - public void run() { - - long start = System.currentTimeMillis(); - - try { - // do trigger - XxlJobTrigger.trigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, - addressList); - } - catch (Throwable e) { - logger.error(e.getMessage(), e); - } - finally { - - // check timeout-count-map - long minTim_now = System.currentTimeMillis() / 60000; - if (minTim != minTim_now) { - minTim = minTim_now; - jobTimeoutCountMap.clear(); - } - - // incr timeout-count-map - long cost = System.currentTimeMillis() - start; - if (cost > 500) { // ob-timeout threshold 500ms - AtomicInteger timeoutCount = jobTimeoutCountMap.putIfAbsent(jobId, new AtomicInteger(1)); - if (timeoutCount != null) { - timeoutCount.incrementAndGet(); - } - } - - } - - } - - @Override - public String toString() { - return "Job Runnable, jobId:" + jobId; - } - }); - } - - // ---------------------- helper ---------------------- - - private static JobTriggerPoolHelper helper = new JobTriggerPoolHelper(); - - public static void toStart() { - helper.start(); - } - - public static void toStop() { - helper.stop(); - } - - /** - * @param jobId - * @param triggerType - * @param failRetryCount >=0: use this param <0: use param from job info config - * @param executorShardingParam - * @param executorParam null: use job param not null: cover job param - */ - public static void trigger(int jobId, TriggerTypeEnum triggerType, int failRetryCount, String executorShardingParam, - String executorParam, String addressList) { - helper.addTrigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, addressList); - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/TriggerTypeEnum.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/TriggerTypeEnum.java deleted file mode 100644 index a07672698..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/TriggerTypeEnum.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.xxl.job.admin.core.trigger; - -import com.xxl.job.admin.core.util.I18nUtil; - -/** - * trigger type enum - * - * @author xuxueli 2018-09-16 04:56:41 - */ -public enum TriggerTypeEnum { - - MANUAL(I18nUtil.getString("jobconf_trigger_type_manual")), CRON(I18nUtil.getString("jobconf_trigger_type_cron")), - RETRY(I18nUtil.getString("jobconf_trigger_type_retry")), PARENT(I18nUtil.getString("jobconf_trigger_type_parent")), - API(I18nUtil.getString("jobconf_trigger_type_api")), MISFIRE(I18nUtil.getString("jobconf_trigger_type_misfire")); - - private TriggerTypeEnum(String title) { - this.title = title; - } - - private String title; - - public String getTitle() { - return title; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java deleted file mode 100644 index e0b660f18..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java +++ /dev/null @@ -1,252 +0,0 @@ -package com.xxl.job.admin.core.trigger; - -import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -import com.xxl.job.admin.core.model.XxlJobGroup; -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.core.model.XxlJobLog; -import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; -import com.xxl.job.admin.core.scheduler.XxlJobScheduler; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.core.biz.ExecutorBiz; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.biz.model.TriggerParam; -import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; -import com.xxl.job.core.util.IpUtil; -import com.xxl.job.core.util.ThrowableUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Date; - -/** - * xxl-job trigger Created by xuxueli on 17/7/13. - */ -public class XxlJobTrigger { - - private static Logger logger = LoggerFactory.getLogger(XxlJobTrigger.class); - - /** - * trigger job - * @param jobId - * @param triggerType - * @param failRetryCount >=0: use this param <0: use param from job info config - * @param executorShardingParam - * @param executorParam null: use job param not null: cover job param - * @param addressList null: use executor addressList not null: cover - */ - public static void trigger(int jobId, TriggerTypeEnum triggerType, int failRetryCount, String executorShardingParam, - String executorParam, String addressList) { - - // load data - XxlJobInfo jobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(jobId); - if (jobInfo == null) { - logger.warn(">>>>>>>>>>>> trigger fail, jobId invalid,jobId={}", jobId); - return; - } - if (executorParam != null) { - jobInfo.setExecutorParam(executorParam); - } - int finalFailRetryCount = failRetryCount >= 0 ? failRetryCount : jobInfo.getExecutorFailRetryCount(); - XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(jobInfo.getJobGroup()); - - // cover addressList - if (addressList != null && addressList.trim().length() > 0) { - group.setAddressType(1); - group.setAddressList(addressList.trim()); - } - - // sharding param - int[] shardingParam = null; - if (executorShardingParam != null) { - String[] shardingArr = executorShardingParam.split("/"); - if (shardingArr.length == 2 && isNumeric(shardingArr[0]) && isNumeric(shardingArr[1])) { - shardingParam = new int[2]; - shardingParam[0] = Integer.valueOf(shardingArr[0]); - shardingParam[1] = Integer.valueOf(shardingArr[1]); - } - } - if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == ExecutorRouteStrategyEnum - .match(jobInfo.getExecutorRouteStrategy(), null) && group.getRegistryList() != null - && !group.getRegistryList().isEmpty() && shardingParam == null) { - for (int i = 0; i < group.getRegistryList().size(); i++) { - processTrigger(group, jobInfo, finalFailRetryCount, triggerType, i, group.getRegistryList().size()); - } - } - else { - if (shardingParam == null) { - shardingParam = new int[] { 0, 1 }; - } - processTrigger(group, jobInfo, finalFailRetryCount, triggerType, shardingParam[0], shardingParam[1]); - } - - } - - private static boolean isNumeric(String str) { - try { - int result = Integer.valueOf(str); - return true; - } - catch (NumberFormatException e) { - return false; - } - } - - /** - * @param group job group, registry list may be empty - * @param jobInfo - * @param finalFailRetryCount - * @param triggerType - * @param index sharding index - * @param total sharding index - */ - private static void processTrigger(XxlJobGroup group, XxlJobInfo jobInfo, int finalFailRetryCount, - TriggerTypeEnum triggerType, int index, int total) { - - // param - ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), - ExecutorBlockStrategyEnum.SERIAL_EXECUTION); // block strategy - ExecutorRouteStrategyEnum executorRouteStrategyEnum = ExecutorRouteStrategyEnum - .match(jobInfo.getExecutorRouteStrategy(), null); // route strategy - String shardingParam = (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum) - ? String.valueOf(index).concat("/").concat(String.valueOf(total)) : null; - - // 1、save log-id - XxlJobLog jobLog = new XxlJobLog(); - jobLog.setJobGroup(jobInfo.getJobGroup()); - jobLog.setJobId(jobInfo.getId()); - jobLog.setTriggerTime(new Date()); - XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().save(jobLog); - logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId()); - - // 2、init trigger-param - TriggerParam triggerParam = new TriggerParam(); - triggerParam.setJobId(jobInfo.getId()); - triggerParam.setExecutorHandler(jobInfo.getExecutorHandler()); - triggerParam.setExecutorParams(jobInfo.getExecutorParam()); - triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); - triggerParam.setExecutorTimeout(jobInfo.getExecutorTimeout()); - triggerParam.setLogId(jobLog.getId()); - triggerParam.setLogDateTime(jobLog.getTriggerTime().getTime()); - triggerParam.setGlueType(jobInfo.getGlueType()); - triggerParam.setGlueSource(jobInfo.getGlueSource()); - triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime()); - triggerParam.setBroadcastIndex(index); - triggerParam.setBroadcastTotal(total); - - // 3、init address - String address = null; - ReturnT routeAddressResult = null; - if (group.getRegistryList() != null && !group.getRegistryList().isEmpty()) { - if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum) { - if (index < group.getRegistryList().size()) { - address = group.getRegistryList().get(index); - } - else { - address = group.getRegistryList().get(0); - } - } - else { - routeAddressResult = executorRouteStrategyEnum.getRouter().route(triggerParam, group.getRegistryList()); - if (routeAddressResult.getCode() == ReturnT.SUCCESS_CODE) { - address = routeAddressResult.getContent(); - } - } - } - else { - routeAddressResult = new ReturnT(ReturnT.FAIL_CODE, - I18nUtil.getString("jobconf_trigger_address_empty")); - } - - // 4、trigger remote executor - ReturnT triggerResult = null; - if (address != null) { - triggerResult = runExecutor(triggerParam, address); - } - else { - triggerResult = new ReturnT(ReturnT.FAIL_CODE, null); - } - - // 5、collection trigger info - StringBuffer triggerMsgSb = new StringBuffer(); - triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_type")).append(":").append(triggerType.getTitle()); - triggerMsgSb.append("
") - .append(I18nUtil.getString("jobconf_trigger_admin_adress")) - .append(":") - .append(IpUtil.getIp()); - triggerMsgSb.append("
") - .append(I18nUtil.getString("jobconf_trigger_exe_regtype")) - .append(":") - .append((group.getAddressType() == 0) ? I18nUtil.getString("jobgroup_field_addressType_0") - : I18nUtil.getString("jobgroup_field_addressType_1")); - triggerMsgSb.append("
") - .append(I18nUtil.getString("jobconf_trigger_exe_regaddress")) - .append(":") - .append(group.getRegistryList()); - triggerMsgSb.append("
") - .append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")) - .append(":") - .append(executorRouteStrategyEnum.getTitle()); - if (shardingParam != null) { - triggerMsgSb.append("(" + shardingParam + ")"); - } - triggerMsgSb.append("
") - .append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")) - .append(":") - .append(blockStrategy.getTitle()); - triggerMsgSb.append("
") - .append(I18nUtil.getString("jobinfo_field_timeout")) - .append(":") - .append(jobInfo.getExecutorTimeout()); - triggerMsgSb.append("
") - .append(I18nUtil.getString("jobinfo_field_executorFailRetryCount")) - .append(":") - .append(finalFailRetryCount); - - triggerMsgSb - .append("

>>>>>>>>>>>" + I18nUtil.getString("jobconf_trigger_run") - + "<<<<<<<<<<<
") - .append((routeAddressResult != null && routeAddressResult.getMsg() != null) - ? routeAddressResult.getMsg() + "

" : "") - .append(triggerResult.getMsg() != null ? triggerResult.getMsg() : ""); - - // 6、save log trigger-info - jobLog.setExecutorAddress(address); - jobLog.setExecutorHandler(jobInfo.getExecutorHandler()); - jobLog.setExecutorParam(jobInfo.getExecutorParam()); - jobLog.setExecutorShardingParam(shardingParam); - jobLog.setExecutorFailRetryCount(finalFailRetryCount); - // jobLog.setTriggerTime(); - jobLog.setTriggerCode(triggerResult.getCode()); - jobLog.setTriggerMsg(triggerMsgSb.toString()); - XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateTriggerInfo(jobLog); - - logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId()); - } - - /** - * run executor - * @param triggerParam - * @param address - * @return - */ - public static ReturnT runExecutor(TriggerParam triggerParam, String address) { - ReturnT runResult = null; - try { - ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address); - runResult = executorBiz.run(triggerParam); - } - catch (Exception e) { - logger.error(">>>>>>>>>>> xxl-job trigger error, please check if the executor[{}] is running.", address, e); - runResult = new ReturnT(ReturnT.FAIL_CODE, ThrowableUtil.toString(e)); - } - - StringBuffer runResultSB = new StringBuffer(I18nUtil.getString("jobconf_trigger_run") + ":"); - runResultSB.append("
address:").append(address); - runResultSB.append("
code:").append(runResult.getCode()); - runResultSB.append("
msg:").append(runResult.getMsg()); - - runResult.setMsg(runResultSB.toString()); - return runResult; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java deleted file mode 100644 index 53f27f754..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.xxl.job.admin.core.util; - -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -/** - * Cookie.Util - * - * @author xuxueli 2015-12-12 18:01:06 - */ -public class CookieUtil { - - // 默认缓存时间,单位/秒, 2H - private static final int COOKIE_MAX_AGE = Integer.MAX_VALUE; - - // 保存路径,根路径 - private static final String COOKIE_PATH = "/"; - - /** - * 保存 - * @param response - * @param key - * @param value - * @param ifRemember - */ - public static void set(HttpServletResponse response, String key, String value, boolean ifRemember) { - int age = ifRemember ? COOKIE_MAX_AGE : -1; - set(response, key, value, null, COOKIE_PATH, age, true); - } - - /** - * 保存 - * @param response - * @param key - * @param value - * @param maxAge - */ - private static void set(HttpServletResponse response, String key, String value, String domain, String path, - int maxAge, boolean isHttpOnly) { - Cookie cookie = new Cookie(key, value); - if (domain != null) { - cookie.setDomain(domain); - } - cookie.setPath(path); - cookie.setMaxAge(maxAge); - cookie.setHttpOnly(isHttpOnly); - response.addCookie(cookie); - } - - /** - * 查询value - * @param request - * @param key - * @return - */ - public static String getValue(HttpServletRequest request, String key) { - Cookie cookie = get(request, key); - if (cookie != null) { - return cookie.getValue(); - } - return null; - } - - /** - * 查询Cookie - * @param request - * @param key - */ - private static Cookie get(HttpServletRequest request, String key) { - Cookie[] arr_cookie = request.getCookies(); - if (arr_cookie != null && arr_cookie.length > 0) { - for (Cookie cookie : arr_cookie) { - if (cookie.getName().equals(key)) { - return cookie; - } - } - } - return null; - } - - /** - * 删除Cookie - * @param request - * @param response - * @param key - */ - public static void remove(HttpServletRequest request, HttpServletResponse response, String key) { - Cookie cookie = get(request, key); - if (cookie != null) { - set(response, key, "", null, COOKIE_PATH, 0, true); - } - } - -} \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java deleted file mode 100644 index 7ee1830d3..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.xxl.job.admin.core.util; - -import freemarker.ext.beans.BeansWrapper; -import freemarker.ext.beans.BeansWrapperBuilder; -import freemarker.template.Configuration; -import freemarker.template.TemplateHashModel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * ftl util - * - * @author xuxueli 2018-01-17 20:37:48 - */ -public class FtlUtil { - - private static Logger logger = LoggerFactory.getLogger(FtlUtil.class); - - private static BeansWrapper wrapper = new BeansWrapperBuilder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS) - .build(); // BeansWrapper.getDefaultInstance(); - - public static TemplateHashModel generateStaticModel(String packageName) { - try { - TemplateHashModel staticModels = wrapper.getStaticModels(); - TemplateHashModel fileStatics = (TemplateHashModel) staticModels.get(packageName); - return fileStatics; - } - catch (Exception e) { - logger.error(e.getMessage(), e); - } - return null; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java deleted file mode 100644 index 4cc3ed3e8..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.xxl.job.admin.core.util; - -import com.xxl.job.admin.core.conf.XxlJobAdminConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.EncodedResource; -import org.springframework.core.io.support.PropertiesLoaderUtils; - -import java.io.IOException; -import java.text.MessageFormat; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -/** - * i18n util - * - * @author xuxueli 2018-01-17 20:39:06 - */ -public class I18nUtil { - - private static Logger logger = LoggerFactory.getLogger(I18nUtil.class); - - private static Properties prop = null; - - public static Properties loadI18nProp() { - if (prop != null) { - return prop; - } - try { - // build i18n prop - String i18n = XxlJobAdminConfig.getAdminConfig().getI18n(); - String i18nFile = MessageFormat.format("i18n/message_{0}.properties", i18n); - - // load prop - Resource resource = new ClassPathResource(i18nFile); - EncodedResource encodedResource = new EncodedResource(resource, "UTF-8"); - prop = PropertiesLoaderUtils.loadProperties(encodedResource); - } - catch (IOException e) { - logger.error(e.getMessage(), e); - } - return prop; - } - - /** - * get val of i18n key - * @param key - * @return - */ - public static String getString(String key) { - return loadI18nProp().getProperty(key); - } - - /** - * get mult val of i18n mult key, as json - * @param keys - * @return - */ - public static String getMultString(String... keys) { - Map map = new HashMap(); - - Properties prop = loadI18nProp(); - if (keys != null && keys.length > 0) { - for (String key : keys) { - map.put(key, prop.getProperty(key)); - } - } - else { - for (String key : prop.stringPropertyNames()) { - map.put(key, prop.getProperty(key)); - } - } - - String json = JacksonUtil.writeValueAsString(map); - return json; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JacksonUtil.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JacksonUtil.java deleted file mode 100644 index 4a015bd67..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JacksonUtil.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.xxl.job.admin.core.util; - -import com.fasterxml.jackson.core.JsonGenerationException; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; - -/** - * Jackson util - * - * 1、obj need private and set/get; 2、do not support inner class; - * - * @author xuxueli 2015-9-25 18:02:56 - */ -public class JacksonUtil { - - private static Logger logger = LoggerFactory.getLogger(JacksonUtil.class); - - private final static ObjectMapper objectMapper = new ObjectMapper(); - - public static ObjectMapper getInstance() { - return objectMapper; - } - - /** - * bean、array、List、Map --> json - * @param obj - * @return json string - * @throws Exception - */ - public static String writeValueAsString(Object obj) { - try { - return getInstance().writeValueAsString(obj); - } - catch (JsonGenerationException e) { - logger.error(e.getMessage(), e); - } - catch (JsonMappingException e) { - logger.error(e.getMessage(), e); - } - catch (IOException e) { - logger.error(e.getMessage(), e); - } - return null; - } - - /** - * string --> bean、Map、List(array) - * @param jsonStr - * @param clazz - * @return obj - * @throws Exception - */ - public static T readValue(String jsonStr, Class clazz) { - try { - return getInstance().readValue(jsonStr, clazz); - } - catch (JsonParseException e) { - logger.error(e.getMessage(), e); - } - catch (JsonMappingException e) { - logger.error(e.getMessage(), e); - } - catch (IOException e) { - logger.error(e.getMessage(), e); - } - return null; - } - - /** - * string --> List... - * @param jsonStr - * @param parametrized - * @param parameterClasses - * @param - * @return - */ - public static T readValue(String jsonStr, Class parametrized, Class... parameterClasses) { - try { - JavaType javaType = getInstance().getTypeFactory().constructParametricType(parametrized, parameterClasses); - return getInstance().readValue(jsonStr, javaType); - } - catch (JsonParseException e) { - logger.error(e.getMessage(), e); - } - catch (JsonMappingException e) { - logger.error(e.getMessage(), e); - } - catch (IOException e) { - logger.error(e.getMessage(), e); - } - return null; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java deleted file mode 100644 index 23b4c5813..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.xxl.job.admin.core.util; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * local cache tool - * - * @author xuxueli 2018-01-22 21:37:34 - */ -public class LocalCacheUtil { - - private static ConcurrentMap cacheRepository = new ConcurrentHashMap(); // 类型建议用抽象父类,兼容性更好; - - private static class LocalCacheData { - - private String key; - - private Object val; - - private long timeoutTime; - - public LocalCacheData() { - } - - public LocalCacheData(String key, Object val, long timeoutTime) { - this.key = key; - this.val = val; - this.timeoutTime = timeoutTime; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public Object getVal() { - return val; - } - - public void setVal(Object val) { - this.val = val; - } - - public long getTimeoutTime() { - return timeoutTime; - } - - public void setTimeoutTime(long timeoutTime) { - this.timeoutTime = timeoutTime; - } - - } - - /** - * set cache - * @param key - * @param val - * @param cacheTime - * @return - */ - public static boolean set(String key, Object val, long cacheTime) { - - // clean timeout cache, before set new cache (avoid cache too much) - cleanTimeoutCache(); - - // set new cache - if (key == null || key.trim().length() == 0) { - return false; - } - if (val == null) { - remove(key); - } - if (cacheTime <= 0) { - remove(key); - } - long timeoutTime = System.currentTimeMillis() + cacheTime; - LocalCacheData localCacheData = new LocalCacheData(key, val, timeoutTime); - cacheRepository.put(localCacheData.getKey(), localCacheData); - return true; - } - - /** - * remove cache - * @param key - * @return - */ - public static boolean remove(String key) { - if (key == null || key.trim().length() == 0) { - return false; - } - cacheRepository.remove(key); - return true; - } - - /** - * get cache - * @param key - * @return - */ - public static Object get(String key) { - if (key == null || key.trim().length() == 0) { - return null; - } - LocalCacheData localCacheData = cacheRepository.get(key); - if (localCacheData != null && System.currentTimeMillis() < localCacheData.getTimeoutTime()) { - return localCacheData.getVal(); - } - else { - remove(key); - return null; - } - } - - /** - * clean timeout cache - * @return - */ - public static boolean cleanTimeoutCache() { - if (!cacheRepository.keySet().isEmpty()) { - for (String key : cacheRepository.keySet()) { - LocalCacheData localCacheData = cacheRepository.get(key); - if (localCacheData != null && System.currentTimeMillis() >= localCacheData.getTimeoutTime()) { - cacheRepository.remove(key); - } - } - } - return true; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java deleted file mode 100644 index 246924f1e..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.xxl.job.admin.dao; - -import com.xxl.job.admin.core.model.XxlJobGroup; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * Created by xuxueli on 16/9/30. - */ -@Mapper -public interface XxlJobGroupDao { - - public List findAll(); - - public List findByAddressType(@Param("addressType") int addressType); - - public int save(XxlJobGroup xxlJobGroup); - - public int update(XxlJobGroup xxlJobGroup); - - public int remove(@Param("id") int id); - - public XxlJobGroup load(@Param("id") int id); - - public List pageList(@Param("offset") int offset, @Param("pagesize") int pagesize, - @Param("appname") String appname, @Param("title") String title); - - public int pageListCount(@Param("offset") int offset, @Param("pagesize") int pagesize, - @Param("appname") String appname, @Param("title") String title); - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java deleted file mode 100644 index 4e54daec1..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.xxl.job.admin.dao; - -import com.xxl.job.admin.core.model.XxlJobInfo; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * job info - * - * @author xuxueli 2016-1-12 18:03:45 - */ -@Mapper -public interface XxlJobInfoDao { - - public List pageList(@Param("offset") int offset, @Param("pagesize") int pagesize, - @Param("jobGroup") int jobGroup, @Param("triggerStatus") int triggerStatus, - @Param("jobDesc") String jobDesc, @Param("executorHandler") String executorHandler, - @Param("author") String author); - - public int pageListCount(@Param("offset") int offset, @Param("pagesize") int pagesize, - @Param("jobGroup") int jobGroup, @Param("triggerStatus") int triggerStatus, - @Param("jobDesc") String jobDesc, @Param("executorHandler") String executorHandler, - @Param("author") String author); - - public int save(XxlJobInfo info); - - public XxlJobInfo loadById(@Param("id") int id); - - public int update(XxlJobInfo xxlJobInfo); - - public int delete(@Param("id") long id); - - public List getJobsByGroup(@Param("jobGroup") int jobGroup); - - public int findAllCount(); - - /** - * find schedule job, limit "trigger_status = 1" - * @param maxNextTime - * @param pagesize - * @return - */ - public List scheduleJobQuery(@Param("maxNextTime") long maxNextTime, @Param("pagesize") int pagesize); - - /** - * update schedule job - * - * 1、can only update "trigger_status = 1", Avoid stopping tasks from being opened - * 2、valid "triggerStatus gte 0", filter illegal state - * @param xxlJobInfo - * @return - */ - public int scheduleUpdate(XxlJobInfo xxlJobInfo); - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java deleted file mode 100644 index a42c08b0c..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.xxl.job.admin.dao; - -import com.xxl.job.admin.core.model.XxlJobLog; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.util.Date; -import java.util.List; -import java.util.Map; - -/** - * job log - * - * @author xuxueli 2016-1-12 18:03:06 - */ -@Mapper -public interface XxlJobLogDao { - - // exist jobId not use jobGroup, not exist use jobGroup - public List pageList(@Param("offset") int offset, @Param("pagesize") int pagesize, - @Param("jobGroup") int jobGroup, @Param("jobId") int jobId, - @Param("triggerTimeStart") Date triggerTimeStart, @Param("triggerTimeEnd") Date triggerTimeEnd, - @Param("logStatus") int logStatus); - - public int pageListCount(@Param("offset") int offset, @Param("pagesize") int pagesize, - @Param("jobGroup") int jobGroup, @Param("jobId") int jobId, - @Param("triggerTimeStart") Date triggerTimeStart, @Param("triggerTimeEnd") Date triggerTimeEnd, - @Param("logStatus") int logStatus); - - public XxlJobLog load(@Param("id") long id); - - public long save(XxlJobLog xxlJobLog); - - public int updateTriggerInfo(XxlJobLog xxlJobLog); - - public int updateHandleInfo(XxlJobLog xxlJobLog); - - public int delete(@Param("jobId") int jobId); - - public Map findLogReport(@Param("from") Date from, @Param("to") Date to); - - public List findClearLogIds(@Param("jobGroup") int jobGroup, @Param("jobId") int jobId, - @Param("clearBeforeTime") Date clearBeforeTime, @Param("clearBeforeNum") int clearBeforeNum, - @Param("pagesize") int pagesize); - - public int clearLog(@Param("logIds") List logIds); - - public List findFailJobLogIds(@Param("pagesize") int pagesize); - - public int updateAlarmStatus(@Param("logId") long logId, @Param("oldAlarmStatus") int oldAlarmStatus, - @Param("newAlarmStatus") int newAlarmStatus); - - public List findLostJobIds(@Param("losedTime") Date losedTime); - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogReportDao.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogReportDao.java deleted file mode 100644 index 9d1d9e369..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogReportDao.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.xxl.job.admin.dao; - -import com.xxl.job.admin.core.model.XxlJobLogReport; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.util.Date; -import java.util.List; - -/** - * job log - * - * @author xuxueli 2019-11-22 - */ -@Mapper -public interface XxlJobLogReportDao { - - public int save(XxlJobLogReport xxlJobLogReport); - - public int update(XxlJobLogReport xxlJobLogReport); - - public List queryLogReport(@Param("triggerDayFrom") Date triggerDayFrom, - @Param("triggerDayTo") Date triggerDayTo); - - public XxlJobLogReport queryLogReportTotal(); - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobRegistryDao.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobRegistryDao.java deleted file mode 100644 index ee1562edb..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobRegistryDao.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.xxl.job.admin.dao; - -import com.xxl.job.admin.core.model.XxlJobRegistry; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.util.Date; -import java.util.List; - -/** - * Created by xuxueli on 16/9/30. - */ -@Mapper -public interface XxlJobRegistryDao { - - public List findDead(@Param("timeout") int timeout, @Param("nowTime") Date nowTime); - - public int removeDead(@Param("ids") List ids); - - public List findAll(@Param("timeout") int timeout, @Param("nowTime") Date nowTime); - - public int registrySaveOrUpdate(@Param("registryGroup") String registryGroup, - @Param("registryKey") String registryKey, @Param("registryValue") String registryValue, - @Param("updateTime") Date updateTime); - - /* - * public int registryUpdate(@Param("registryGroup") String registryGroup, - * - * @Param("registryKey") String registryKey, - * - * @Param("registryValue") String registryValue, - * - * @Param("updateTime") Date updateTime); - * - * public int registrySave(@Param("registryGroup") String registryGroup, - * - * @Param("registryKey") String registryKey, - * - * @Param("registryValue") String registryValue, - * - * @Param("updateTime") Date updateTime); - */ - - public int registryDelete(@Param("registryGroup") String registryGroup, @Param("registryKey") String registryKey, - @Param("registryValue") String registryValue); - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobUserDao.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobUserDao.java deleted file mode 100644 index c21c3c1fe..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobUserDao.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.xxl.job.admin.dao; - -import com.xxl.job.admin.core.model.XxlJobUser; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import java.util.List; - -/** - * @author xuxueli 2019-05-04 16:44:59 - */ -@Mapper -public interface XxlJobUserDao { - - public List pageList(@Param("offset") int offset, @Param("pagesize") int pagesize, - @Param("username") String username, @Param("role") int role); - - public int pageListCount(@Param("offset") int offset, @Param("pagesize") int pagesize, - @Param("username") String username, @Param("role") int role); - - public XxlJobUser loadByUserName(@Param("username") String username); - - public int save(XxlJobUser xxlJobUser); - - public int update(XxlJobUser xxlJobUser); - - public int delete(@Param("id") int id); - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobGroupMapper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobGroupMapper.java new file mode 100644 index 000000000..f220f2e2d --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobGroupMapper.java @@ -0,0 +1,37 @@ +package com.xxl.job.admin.mapper; + +import com.xxl.job.admin.model.XxlJobGroup; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * Created by xuxueli on 16/9/30. + */ +@Mapper +public interface XxlJobGroupMapper { + + public List findAll(); + + public List findByAddressType(@Param("addressType") int addressType); + + public int save(XxlJobGroup xxlJobGroup); + + public int update(XxlJobGroup xxlJobGroup); + + public int remove(@Param("id") int id); + + public XxlJobGroup load(@Param("id") int id); + + public List pageList(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("appname") String appname, + @Param("title") String title); + + public int pageListCount(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("appname") String appname, + @Param("title") String title); + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobInfoMapper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobInfoMapper.java new file mode 100644 index 000000000..70672e8a8 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobInfoMapper.java @@ -0,0 +1,74 @@ +package com.xxl.job.admin.mapper; + +import com.xxl.job.admin.model.XxlJobInfo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + + +/** + * job info + * + * @author xuxueli 2016-1-12 18:03:45 + */ +@Mapper +public interface XxlJobInfoMapper { + + public List pageList(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("jobGroup") int jobGroup, + @Param("triggerStatus") int triggerStatus, + @Param("jobDesc") String jobDesc, + @Param("executorHandler") String executorHandler, + @Param("author") String author); + + public int pageListCount(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("jobGroup") int jobGroup, + @Param("triggerStatus") int triggerStatus, + @Param("jobDesc") String jobDesc, + @Param("executorHandler") String executorHandler, + @Param("author") String author); + + public int save(XxlJobInfo info); + + public XxlJobInfo loadById(@Param("id") int id); + + public int update(XxlJobInfo xxlJobInfo); + + public int delete(@Param("id") long id); + + public List getJobsByGroup(@Param("jobGroup") int jobGroup); + + public int findAllCount(); + + /** + * find schedule job, limit "trigger_status = 1" + * + * @param maxNextTime + * @param pagesize + * @return + */ + public List scheduleJobQuery(@Param("maxNextTime") long maxNextTime, @Param("pagesize") int pagesize); + + /** + * update schedule job + *

+ * 1、can only update "trigger_status = 1", Avoid stopping tasks from being opened + * 2、valid "triggerStatus gte 0", filter illegal state + * + * @param xxlJobInfo + * @return + */ + public int scheduleUpdate(XxlJobInfo xxlJobInfo); + + /** + * batch update job info + * + * @param jobInfoList + * @return + */ + public int scheduleBatchUpdate(@Param("list") List jobInfoList); + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLockMapper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLockMapper.java new file mode 100644 index 000000000..27d2cbbc2 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLockMapper.java @@ -0,0 +1,18 @@ +package com.xxl.job.admin.mapper; + +import org.apache.ibatis.annotations.Mapper; + +/** + * job lock + * + * @author xuxueli 2016-1-12 18:03:45 + */ +@Mapper +public interface XxlJobLockMapper { + + /** + * get schedule lock + */ + String scheduleLock(); + +} \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogGlueDao.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLogGlueMapper.java similarity index 78% rename from pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogGlueDao.java rename to pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLogGlueMapper.java index d426f65f8..c2d70574b 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogGlueDao.java +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLogGlueMapper.java @@ -1,6 +1,6 @@ -package com.xxl.job.admin.dao; +package com.xxl.job.admin.mapper; -import com.xxl.job.admin.core.model.XxlJobLogGlue; +import com.xxl.job.admin.model.XxlJobLogGlue; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -8,12 +8,11 @@ import java.util.List; /** * job log for glue - * * @author xuxueli 2016-5-19 18:04:56 */ @Mapper -public interface XxlJobLogGlueDao { - +public interface XxlJobLogGlueMapper { + public int save(XxlJobLogGlue xxlJobLogGlue); public List findByJobId(@Param("jobId") int jobId); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLogMapper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLogMapper.java new file mode 100644 index 000000000..2c9d443cd --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLogMapper.java @@ -0,0 +1,65 @@ +package com.xxl.job.admin.mapper; + +import com.xxl.job.admin.model.XxlJobLog; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * job log + * + * @author xuxueli 2016-1-12 18:03:06 + */ +@Mapper +public interface XxlJobLogMapper { + + // exist jobId not use jobGroup, not exist use jobGroup + public List pageList(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("jobGroup") int jobGroup, + @Param("jobId") int jobId, + @Param("triggerTimeStart") Date triggerTimeStart, + @Param("triggerTimeEnd") Date triggerTimeEnd, + @Param("logStatus") int logStatus); + + public int pageListCount(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("jobGroup") int jobGroup, + @Param("jobId") int jobId, + @Param("triggerTimeStart") Date triggerTimeStart, + @Param("triggerTimeEnd") Date triggerTimeEnd, + @Param("logStatus") int logStatus); + + public XxlJobLog load(@Param("id") long id); + + public long save(XxlJobLog xxlJobLog); + + public int updateTriggerInfo(XxlJobLog xxlJobLog); + + public int updateHandleInfo(XxlJobLog xxlJobLog); + + public int delete(@Param("jobId") int jobId); + + public Map findLogReport(@Param("from") Date from, + @Param("to") Date to); + + public List findClearLogIds(@Param("jobGroup") int jobGroup, + @Param("jobId") int jobId, + @Param("clearBeforeTime") Date clearBeforeTime, + @Param("clearBeforeNum") int clearBeforeNum, + @Param("pagesize") int pagesize); + + public int clearLog(@Param("logIds") List logIds); + + public List findFailJobLogIds(@Param("pagesize") int pagesize); + + public int updateAlarmStatus(@Param("logId") long logId, + @Param("oldAlarmStatus") int oldAlarmStatus, + @Param("newAlarmStatus") int newAlarmStatus); + + public List findLostJobIds(@Param("losedTime") Date losedTime); + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLogReportMapper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLogReportMapper.java new file mode 100644 index 000000000..984de71d7 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLogReportMapper.java @@ -0,0 +1,29 @@ +package com.xxl.job.admin.mapper; + +import com.xxl.job.admin.model.XxlJobLogReport; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Date; +import java.util.List; + +/** + * job log + * + * @author xuxueli 2019-11-22 + */ +@Mapper +public interface XxlJobLogReportMapper { + + /*public int save(XxlJobLogReport xxlJobLogReport); + + public int update(XxlJobLogReport xxlJobLogReport);*/ + + public int saveOrUpdate(XxlJobLogReport xxlJobLogReport); + + public List queryLogReport(@Param("triggerDayFrom") Date triggerDayFrom, + @Param("triggerDayTo") Date triggerDayTo); + + public XxlJobLogReport queryLogReportTotal(); + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobRegistryMapper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobRegistryMapper.java new file mode 100644 index 000000000..c3be20316 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobRegistryMapper.java @@ -0,0 +1,46 @@ +package com.xxl.job.admin.mapper; + +import com.xxl.job.admin.model.XxlJobRegistry; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Date; +import java.util.List; + +/** + * Created by xuxueli on 16/9/30. + */ +@Mapper +public interface XxlJobRegistryMapper { + + public List findDead(@Param("timeout") int timeout, + @Param("nowTime") Date nowTime); + + public int removeDead(@Param("ids") List ids); + + public List findAll(@Param("timeout") int timeout, + @Param("nowTime") Date nowTime); + + public int registrySaveOrUpdate(@Param("registryGroup") String registryGroup, + @Param("registryKey") String registryKey, + @Param("registryValue") String registryValue, + @Param("updateTime") Date updateTime); + + /*public int registryUpdate(@Param("registryGroup") String registryGroup, + @Param("registryKey") String registryKey, + @Param("registryValue") String registryValue, + @Param("updateTime") Date updateTime); + + public int registrySave(@Param("registryGroup") String registryGroup, + @Param("registryKey") String registryKey, + @Param("registryValue") String registryValue, + @Param("updateTime") Date updateTime);*/ + + public int registryDelete(@Param("registryGroup") String registryGroup, + @Param("registryKey") String registryKey, + @Param("registryValue") String registryValue); + + public int removeByRegistryGroupAndKey(@Param("registryGroup") String registryGroup, + @Param("registryKey") String registryKey); + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobUserMapper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobUserMapper.java new file mode 100644 index 000000000..4a0f52178 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobUserMapper.java @@ -0,0 +1,37 @@ +package com.xxl.job.admin.mapper; + +import com.xxl.job.admin.model.XxlJobUser; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * @author xuxueli 2019-05-04 16:44:59 + */ +@Mapper +public interface XxlJobUserMapper { + + public List pageList(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("username") String username, + @Param("role") int role); + + public int pageListCount(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("username") String username, + @Param("role") int role); + + public XxlJobUser loadByUserName(@Param("username") String username); + + public XxlJobUser loadById(@Param("id") int id); + + public int save(XxlJobUser xxlJobUser); + + public int update(XxlJobUser xxlJobUser); + + public int delete(@Param("id") int id); + + public int updateToken(@Param("id") int id, @Param("token") String token); + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobGroup.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobGroup.java new file mode 100644 index 000000000..e52443a0e --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobGroup.java @@ -0,0 +1,80 @@ +package com.xxl.job.admin.model; + +import com.xxl.tool.core.StringTool; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +/** + * Created by xuxueli on 16/9/30. + */ +public class XxlJobGroup { + + private int id; + private String appname; + private String title; + private int addressType; // 执行器地址类型:0=自动注册、1=手动录入 + private String addressList; // 执行器地址列表,多地址逗号分隔(手动录入) + private Date updateTime; + + // registry list + private List registryList; // 执行器地址列表(系统注册) + + public List getRegistryList() { + if (StringTool.isNotBlank(addressList)) { + registryList = new ArrayList<>(Arrays.asList(addressList.split(","))); + } + return registryList; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getAppname() { + return appname; + } + + public void setAppname(String appname) { + this.appname = appname; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getAddressType() { + return addressType; + } + + public void setAddressType(int addressType) { + this.addressType = addressType; + } + + public String getAddressList() { + return addressList; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public void setAddressList(String addressList) { + this.addressList = addressList; + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobInfo.java similarity index 72% rename from pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java rename to pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobInfo.java index db3c5573f..d563b46e9 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobInfo.java @@ -1,61 +1,47 @@ -package com.xxl.job.admin.core.model; +package com.xxl.job.admin.model; import java.util.Date; /** * xxl-job info * - * @author xuxueli 2016-1-12 18:25:49 + * @author xuxueli 2016-1-12 18:25:49 */ public class XxlJobInfo { - private int id; // 主键ID - - private int jobGroup; // 执行器主键ID + private int id; // 主键ID + private int jobGroup; // 执行器主键ID private String jobDesc; private Date addTime; - private Date updateTime; - private String author; // 负责人 + private String author; // 负责人 + private String alarmEmail; // 报警邮件 - private String alarmEmail; // 报警邮件 + private String scheduleType; // 调度类型:ScheduleTypeEnum + private String scheduleConf; // 调度配置,值含义取决于调度类型 + private String misfireStrategy; // 调度过期策略:MisfireStrategyEnum - private String scheduleType; // 调度类型 + private String executorRouteStrategy; // 执行器路由策略:ExecutorRouteStrategyEnum + private String executorHandler; // 执行器,任务Handler名称 + private String executorParam; // 执行器,任务参数 + private String executorBlockStrategy; // 阻塞处理策略:ExecutorBlockStrategyEnum + private int executorTimeout; // 任务执行超时时间,单位秒 + private int executorFailRetryCount; // 失败重试次数 - private String scheduleConf; // 调度配置,值含义取决于调度类型 + private String glueType; // GLUE类型:GlueTypeEnum + private String glueSource; // GLUE源代码 + private String glueRemark; // GLUE备注 + private Date glueUpdatetime; // GLUE更新时间 - private String misfireStrategy; // 调度过期策略 + private String childJobId; // 子任务ID,多个逗号分隔 - private String executorRouteStrategy; // 执行器路由策略 + private int triggerStatus; // 调度状态:TriggerStatus + private long triggerLastTime; // 上次调度时间 + private long triggerNextTime; // 下次调度时间 - private String executorHandler; // 执行器,任务Handler名称 - - private String executorParam; // 执行器,任务参数 - - private String executorBlockStrategy; // 阻塞处理策略 - - private int executorTimeout; // 任务执行超时时间,单位秒 - - private int executorFailRetryCount; // 失败重试次数 - - private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum - - private String glueSource; // GLUE源代码 - - private String glueRemark; // GLUE备注 - - private Date glueUpdatetime; // GLUE更新时间 - - private String childJobId; // 子任务ID,多个逗号分隔 - - private int triggerStatus; // 调度状态:0-停止,1-运行 - - private long triggerLastTime; // 上次调度时间 - - private long triggerNextTime; // 下次调度时间 public int getId() { return id; @@ -248,5 +234,4 @@ public class XxlJobInfo { public void setTriggerNextTime(long triggerNextTime) { this.triggerNextTime = triggerNextTime; } - } diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobLog.java similarity index 96% rename from pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java rename to pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobLog.java index a9da03fc2..13fbec330 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobLog.java @@ -1,11 +1,10 @@ -package com.xxl.job.admin.core.model; +package com.xxl.job.admin.model; import java.util.Date; /** * xxl-job log, used to track trigger process - * - * @author xuxueli 2015-12-19 23:19:09 + * @author xuxueli 2015-12-19 23:19:09 */ public class XxlJobLog { @@ -13,32 +12,23 @@ public class XxlJobLog { // job info private int jobGroup; - private int jobId; // execute info private String executorAddress; - private String executorHandler; - private String executorParam; - private String executorShardingParam; - private int executorFailRetryCount; // trigger info private Date triggerTime; - private int triggerCode; - private String triggerMsg; // handle info private Date handleTime; - private int handleCode; - private String handleMsg; // alarm info diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogGlue.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobLogGlue.java similarity index 87% rename from pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogGlue.java rename to pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobLogGlue.java index 040cab06d..6db2d5557 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogGlue.java +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobLogGlue.java @@ -1,26 +1,19 @@ -package com.xxl.job.admin.core.model; +package com.xxl.job.admin.model; import java.util.Date; /** * xxl-job log for glue, used to track job code process - * * @author xuxueli 2016-5-19 17:57:46 */ public class XxlJobLogGlue { private int id; - - private int jobId; // 任务主键ID - - private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum - + private int jobId; // 任务主键ID + private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum private String glueSource; - private String glueRemark; - private Date addTime; - private Date updateTime; public int getId() { diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobLogReport.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobLogReport.java new file mode 100644 index 000000000..92faada23 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobLogReport.java @@ -0,0 +1,64 @@ +package com.xxl.job.admin.model; + +import java.util.Date; + +public class XxlJobLogReport { + + private int id; + private Date triggerDay; + + private int runningCount; + private int sucCount; + private int failCount; + + private Date updateTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Date getTriggerDay() { + return triggerDay; + } + + public void setTriggerDay(Date triggerDay) { + this.triggerDay = triggerDay; + } + + public int getRunningCount() { + return runningCount; + } + + public void setRunningCount(int runningCount) { + this.runningCount = runningCount; + } + + public int getSucCount() { + return sucCount; + } + + public void setSucCount(int sucCount) { + this.sucCount = sucCount; + } + + public int getFailCount() { + return failCount; + } + + public void setFailCount(int failCount) { + this.failCount = failCount; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobRegistry.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobRegistry.java new file mode 100644 index 000000000..84aefdf1e --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobRegistry.java @@ -0,0 +1,55 @@ +package com.xxl.job.admin.model; + +import java.util.Date; + +/** + * Created by xuxueli on 16/9/30. + */ +public class XxlJobRegistry { + + private long id; + private String registryGroup; + private String registryKey; + private String registryValue; + private Date updateTime; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getRegistryGroup() { + return registryGroup; + } + + public void setRegistryGroup(String registryGroup) { + this.registryGroup = registryGroup; + } + + public String getRegistryKey() { + return registryKey; + } + + public void setRegistryKey(String registryKey) { + this.registryKey = registryKey; + } + + public String getRegistryValue() { + return registryValue; + } + + public void setRegistryValue(String registryValue) { + this.registryValue = registryValue; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobUser.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobUser.java similarity index 51% rename from pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobUser.java rename to pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobUser.java index 04e64d27e..d69089a63 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobUser.java +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobUser.java @@ -1,6 +1,4 @@ -package com.xxl.job.admin.core.model; - -import org.springframework.util.StringUtils; +package com.xxl.job.admin.model; /** * @author xuxueli 2019-05-04 16:43:12 @@ -8,14 +6,11 @@ import org.springframework.util.StringUtils; public class XxlJobUser { private int id; - - private String username; // 账号 - - private String password; // 密码 - - private int role; // 角色:0-普通用户、1-管理员 - - private String permission; // 权限:执行器ID列表,多个逗号分割 + private String username; // 账号 + private String password; // 密码 + private String token; // 登录token + private int role; // 角色:0-普通用户、1-管理员 + private String permission; // 权限:执行器ID列表,多个逗号分割 public int getId() { return id; @@ -41,6 +36,14 @@ public class XxlJobUser { this.password = password; } + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + public int getRole() { return role; } @@ -57,22 +60,4 @@ public class XxlJobUser { this.permission = permission; } - // plugin - public boolean validPermission(int jobGroup) { - if (this.role == 1) { - return true; - } - else { - if (StringUtils.hasText(this.permission)) { - for (String permissionItem : this.permission.split(",")) { - if (String.valueOf(jobGroup).equals(permissionItem)) { - return true; - } - } - } - return false; - } - - } - } diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/dto/XxlBootResourceDTO.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/dto/XxlBootResourceDTO.java new file mode 100644 index 000000000..2c140571c --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/model/dto/XxlBootResourceDTO.java @@ -0,0 +1,186 @@ +package com.xxl.job.admin.model.dto; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * XxlBootResource DTO + *

+ * Created by xuxueli on 2024-08-04 + */ +public class XxlBootResourceDTO implements Serializable { + private static final long serialVersionUID = 42L; + + /** + * 资源ID + */ + private int id; + + /** + * 父节点ID + */ + private int parentId; + + /** + * 名称 + */ + private String name; + + /** + * 类型:0-目录, 1-菜单, 2-按钮 + */ + private int type; + + /** + * 权限标识 + */ + private String permission; + + /** + * 菜单地址 + */ + private String url; + + /** + * ICON + */ + private String icon; + + /** + * 顺序 + */ + private int order; + + /** + * 状态:0-正常、1-禁用 + */ + private int status; + + /** + * 新增时间 + */ + private Date addTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * child data + */ + private List children; + + public XxlBootResourceDTO() { + } + + public XxlBootResourceDTO(int id, int parentId, String name, int type, String permission, String url, String icon, int order, int status, List children) { + this.id = id; + this.parentId = parentId; + this.name = name; + this.type = type; + this.permission = permission; + this.url = url; + this.icon = icon; + this.order = order; + this.status = status; + this.children = children; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getParentId() { + return parentId; + } + + public void setParentId(int parentId) { + this.parentId = parentId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String getPermission() { + return permission; + } + + public void setPermission(String permission) { + this.permission = permission; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public Date getAddTime() { + return addTime; + } + + public void setAddTime(Date addTime) { + this.addTime = addTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/alarm/JobAlarm.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/alarm/JobAlarm.java new file mode 100644 index 000000000..d7f61773e --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/alarm/JobAlarm.java @@ -0,0 +1,20 @@ +package com.xxl.job.admin.scheduler.alarm; + +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.model.XxlJobLog; + +/** + * @author xuxueli 2020-01-19 + */ +public interface JobAlarm { + + /** + * job alarm + * + * @param info + * @param jobLog + * @return + */ + public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog); + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/alarm/JobAlarmer.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/alarm/JobAlarmer.java new file mode 100644 index 000000000..9562189a1 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/alarm/JobAlarmer.java @@ -0,0 +1,67 @@ +package com.xxl.job.admin.scheduler.alarm; + +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.model.XxlJobLog; +import com.xxl.tool.core.CollectionTool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * xxl-job alarmer + * + * @author xuxueli 17/7/13. + */ +@Component +public class JobAlarmer { + private static final Logger logger = LoggerFactory.getLogger(JobAlarmer.class); + + @Autowired + private List jobAlarmList; + + /** + * job alarm + */ + public boolean alarm(XxlJobInfo info, XxlJobLog jobLog) { + + boolean result = false; + if (CollectionTool.isNotEmpty(jobAlarmList)) { + result = true; // success means all-success + for (JobAlarm alarm : jobAlarmList) { + boolean resultItem = false; + try { + resultItem = alarm.doAlarm(info, jobLog); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + if (!resultItem) { + result = false; + } + } + } + + return result; + } + + /* + // implements SmartInitializingSingleton + // implements ApplicationContextAware, InitializingBean + private ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public void afterPropertiesSet() throws Exception { + Map serviceBeanMap = applicationContext.getBeansOfType(JobAlarm.class); + if (MapTool.isNotEmpty(serviceBeanMap)) { + jobAlarmList = new ArrayList<>(serviceBeanMap.values()); + } + }*/ + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/alarm/impl/EmailJobAlarm.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/alarm/impl/EmailJobAlarm.java new file mode 100644 index 000000000..6404afadb --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/alarm/impl/EmailJobAlarm.java @@ -0,0 +1,118 @@ +package com.xxl.job.admin.scheduler.alarm.impl; + +import com.xxl.job.admin.model.XxlJobGroup; +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.model.XxlJobLog; +import com.xxl.job.admin.scheduler.alarm.JobAlarm; +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.job.core.context.XxlJobContext; +import jakarta.mail.internet.MimeMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Component; + +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * job alarm by email + * + * @author xuxueli 2020-01-19 + */ +@Component +public class EmailJobAlarm implements JobAlarm { + private static Logger logger = LoggerFactory.getLogger(EmailJobAlarm.class); + + /** + * fail alarm + * + * @param jobLog + */ + @Override + public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog) { + boolean alarmResult = true; + + // send monitor email + if (info != null && info.getAlarmEmail() != null && !info.getAlarmEmail().trim().isEmpty()) { + + // alarmContent + String alarmContent = "Alarm Job LogId=" + jobLog.getId(); + if (jobLog.getTriggerCode() != XxlJobContext.HANDLE_CODE_SUCCESS) { + alarmContent += "
TriggerMsg=
" + jobLog.getTriggerMsg(); + } + if (jobLog.getHandleCode() > 0 && jobLog.getHandleCode() != XxlJobContext.HANDLE_CODE_SUCCESS) { + alarmContent += "
HandleCode=" + jobLog.getHandleMsg(); + } + + // email info + XxlJobGroup group = XxlJobAdminBootstrap.getInstance().getXxlJobGroupMapper().load(Integer.valueOf(info.getJobGroup())); + String personal = I18nUtil.getString("admin_name_full"); + String title = I18nUtil.getString("jobconf_monitor"); + String content = MessageFormat.format(loadEmailJobAlarmTemplate(), + group != null ? group.getTitle() : "null", + info.getId(), + info.getJobDesc(), + alarmContent); + + Set emailSet = new HashSet(Arrays.asList(info.getAlarmEmail().split(","))); + for (String email : emailSet) { + + // make mail + try { + MimeMessage mimeMessage = XxlJobAdminBootstrap.getInstance().getMailSender().createMimeMessage(); + + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); + helper.setFrom(XxlJobAdminBootstrap.getInstance().getEmailFrom(), personal); + helper.setTo(email); + helper.setSubject(title); + helper.setText(content, true); + + XxlJobAdminBootstrap.getInstance().getMailSender().send(mimeMessage); + } catch (Exception e) { + logger.error(">>>>>>>>>>> xxl-job, job fail alarm email send error, JobLogId:{}", jobLog.getId(), e); + + alarmResult = false; + } + + } + } + + return alarmResult; + } + + /** + * load email job alarm template + * + * @return + */ + private static final String loadEmailJobAlarmTemplate() { + String mailBodyTemplate = "

" + I18nUtil.getString("jobconf_monitor_detail") + ":" + + "\n" + + " " + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
" + I18nUtil.getString("jobinfo_field_jobgroup") + "" + I18nUtil.getString("jobinfo_field_id") + "" + I18nUtil.getString("jobinfo_field_jobdesc") + "" + I18nUtil.getString("jobconf_monitor_alarm_title") + "" + I18nUtil.getString("jobconf_monitor_alarm_content") + "
{0}{1}{2}" + I18nUtil.getString("jobconf_monitor_alarm_type") + "{3}
"; + + return mailBodyTemplate; + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/complete/JobCompleter.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/complete/JobCompleter.java new file mode 100644 index 000000000..720c219f9 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/complete/JobCompleter.java @@ -0,0 +1,122 @@ +package com.xxl.job.admin.scheduler.complete; + +import com.xxl.job.admin.mapper.XxlJobInfoMapper; +import com.xxl.job.admin.mapper.XxlJobLogMapper; +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.model.XxlJobLog; +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.job.core.context.XxlJobContext; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.response.Response; +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.text.MessageFormat; + +/** + * xxl-job job log complete + * + * @author xuxueli 2020-10-30 20:43:10 + */ +@Component +public class JobCompleter { + private static final Logger logger = LoggerFactory.getLogger(JobCompleter.class); + + + @Resource + private XxlJobInfoMapper xxlJobInfoMapper; + @Resource + private XxlJobLogMapper xxlJobLogMapper; + + + /** + * complate job (limit only once) + */ + public int complete(XxlJobLog xxlJobLog) { + + // 1、process child-job + processChildJob(xxlJobLog); + + // text最大64kb 避免长度过长 + if (xxlJobLog.getHandleMsg().length() > 15000) { + xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg().substring(0, 15000)); + } + + // 2、fix_delay trigger next + // on the way + + // 3、update job handle-info + return xxlJobLogMapper.updateHandleInfo(xxlJobLog); + } + + + /** + * do somethind to finish job + */ + private void processChildJob(XxlJobLog xxlJobLog) { + + // 1、handle success, to trigger child job + String triggerChildMsg = null; + if (XxlJobContext.HANDLE_CODE_SUCCESS == xxlJobLog.getHandleCode()) { + XxlJobInfo xxlJobInfo = xxlJobInfoMapper.loadById(xxlJobLog.getJobId()); + + // process child job + if (xxlJobInfo != null && StringTool.isNotBlank(xxlJobInfo.getChildJobId())) { + triggerChildMsg = "

>>>>>>>>>>>" + I18nUtil.getString("jobconf_trigger_child_run") + "<<<<<<<<<<<
"; + String[] childJobIds = xxlJobInfo.getChildJobId().split(","); + for (int i = 0; i < childJobIds.length; i++) { + + // process eath child + int childJobId = (StringTool.isNotBlank(childJobIds[i]) && StringTool.isNumeric(childJobIds[i])) + ? Integer.parseInt(childJobIds[i]) + : -1; + if (childJobId > 0) { + // valid + if (childJobId == xxlJobLog.getJobId()) { + logger.debug(">>>>>>>>>>> xxl-job, XxlJobCompleter-finishJob ignore childJobId, childJobId {} is self.", childJobId); + continue; + } + + // trigger child job + XxlJobAdminBootstrap.getInstance().getJobTriggerPoolHelper().trigger(childJobId, TriggerTypeEnum.PARENT, -1, null, null, null); + Response triggerChildResult = Response.ofSuccess(); + + // add msg + triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"), + (i + 1), + childJobIds.length, + childJobIds[i], + (triggerChildResult.isSuccess() ? I18nUtil.getString("system_success") : I18nUtil.getString("system_fail")), + triggerChildResult.getMsg()); + } else { + triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"), + (i + 1), + childJobIds.length, + childJobIds[i]); + } + } + + } + } + + // 2、append trigger-child message + if (StringTool.isNotBlank(triggerChildMsg)) { + xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg() + triggerChildMsg); + } + + } + + /*private static boolean isNumeric(String str){ + try { + int result = Integer.valueOf(str); + return true; + } catch (NumberFormatException e) { + return false; + } + }*/ + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/config/XxlJobAdminBootstrap.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/config/XxlJobAdminBootstrap.java new file mode 100644 index 000000000..1472e7dcd --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/config/XxlJobAdminBootstrap.java @@ -0,0 +1,316 @@ +package com.xxl.job.admin.scheduler.config; + +import com.xxl.job.admin.mapper.*; +import com.xxl.job.admin.scheduler.alarm.JobAlarmer; +import com.xxl.job.admin.scheduler.complete.JobCompleter; +import com.xxl.job.admin.scheduler.thread.*; +import com.xxl.job.admin.scheduler.trigger.JobTrigger; +import com.xxl.job.core.constant.Const; +import com.xxl.job.core.openapi.ExecutorBiz; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.http.HttpTool; +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.stereotype.Component; +import org.springframework.transaction.PlatformTransactionManager; + +import java.util.Arrays; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * xxl-job config + * + * @author xuxueli 2017-04-28 + */ + +@Component +public class XxlJobAdminBootstrap implements InitializingBean, DisposableBean { + private static final Logger logger = LoggerFactory.getLogger(XxlJobAdminBootstrap.class); + + // ---------------------- instance ---------------------- + + private static XxlJobAdminBootstrap adminConfig = null; + + public static XxlJobAdminBootstrap getInstance() { + return adminConfig; + } + + + // ---------------------- start / stop ---------------------- + + @Override + public void afterPropertiesSet() throws Exception { + // init instance + adminConfig = this; + + // start + doStart(); + } + + @Override + public void destroy() throws Exception { + // stop + doStop(); + } + + // job module + private JobTriggerPoolHelper jobTriggerPoolHelper; + private JobRegistryHelper jobRegistryHelper; + private JobFailAlarmMonitorHelper jobFailAlarmMonitorHelper; + private JobCompleteHelper jobCompleteHelper; + private JobLogReportHelper jobLogReportHelper; + private JobScheduleHelper jobScheduleHelper; + + public JobTriggerPoolHelper getJobTriggerPoolHelper() { + return jobTriggerPoolHelper; + } + + public JobRegistryHelper getJobRegistryHelper() { + return jobRegistryHelper; + } + + public JobCompleteHelper getJobCompleteHelper() { + return jobCompleteHelper; + } + + /** + * do start + */ + private void doStart() throws Exception { + // trigger-pool start + jobTriggerPoolHelper = new JobTriggerPoolHelper(); + jobTriggerPoolHelper.start(); + + // registry monitor start + jobRegistryHelper = new JobRegistryHelper(); + jobRegistryHelper.start(); + + // fail-alarm monitor start + jobFailAlarmMonitorHelper = new JobFailAlarmMonitorHelper(); + jobFailAlarmMonitorHelper.start(); + + // job complate start ( depend on JobTriggerPoolHelper ) for callback and result-lost + jobCompleteHelper = new JobCompleteHelper(); + jobCompleteHelper.start(); + + // log-report start + jobLogReportHelper = new JobLogReportHelper(); + jobLogReportHelper.start(); + + // job-schedule start ( depend on JobTriggerPoolHelper ) + jobScheduleHelper = new JobScheduleHelper(); + jobScheduleHelper.start(); + + logger.info(">>>>>>>>> xxl-job admin start success."); + } + + /** + * do stop + */ + private void doStop() { + // job-schedule stop + jobScheduleHelper.stop(); + + // log-report stop + jobLogReportHelper.stop(); + + // job complate stop + jobCompleteHelper.stop(); + + // fail-alarm monitor stop + jobFailAlarmMonitorHelper.stop(); + + // registry monitor stop + jobRegistryHelper.stop(); + + // trigger-pool stop + jobTriggerPoolHelper.stop(); + + logger.info(">>>>>>>>> xxl-job admin stopped."); + } + + + // ---------------------- executor-client ---------------------- + + private static ConcurrentMap executorBizRepository = new ConcurrentHashMap(); + + public static ExecutorBiz getExecutorBiz(String address) throws Exception { + // valid + if (StringTool.isBlank(address)) { + return null; + } + + // load-cache + address = address.trim(); + ExecutorBiz executorBiz = executorBizRepository.get(address); + if (executorBiz != null) { + return executorBiz; + } + + // set-cache + executorBiz = HttpTool.createClient() + .url(address) + .timeout(XxlJobAdminBootstrap.getInstance().getTimeout() * 1000) + .header(Const.XXL_JOB_ACCESS_TOKEN, XxlJobAdminBootstrap.getInstance().getAccessToken()) + .proxy(ExecutorBiz.class); + executorBizRepository.put(address, executorBiz); + return executorBiz; + } + + + // ---------------------- field ---------------------- + + // conf + @Value("${xxl.job.i18n}") + private String i18n; + + @Value("${xxl.job.accessToken:}") + private String accessToken; + + @Value("${xxl.job.timeout}") + private int timeout; + + @Value("${spring.mail.from}") + private String emailFrom; + + @Value("${xxl.job.triggerpool.fast.max}") + private int triggerPoolFastMax; + + @Value("${xxl.job.triggerpool.slow.max}") + private int triggerPoolSlowMax; + + @Value("${xxl.job.schedule.batchsize}") + private int scheduleBatchSize; + + @Value("${xxl.job.logretentiondays}") + private int logretentiondays; + + // service, mapper + @Resource + private XxlJobLogMapper xxlJobLogMapper; + @Resource + private XxlJobInfoMapper xxlJobInfoMapper; + @Resource + private XxlJobRegistryMapper xxlJobRegistryMapper; + @Resource + private XxlJobGroupMapper xxlJobGroupMapper; + @Resource + private XxlJobLogReportMapper xxlJobLogReportMapper; + @Resource + private XxlJobLockMapper xxlJobLockMapper; + @Resource + private JavaMailSender mailSender; + /*@Resource + private DataSource dataSource;*/ + @Resource + private PlatformTransactionManager transactionManager; + @Resource + private JobAlarmer jobAlarmer; + @Resource + private JobTrigger jobTrigger; + @Resource + private JobCompleter jobCompleter; + + + public String getI18n() { + if (!Arrays.asList("zh_CN", "zh_TC", "en").contains(i18n)) { + return "zh_CN"; + } + return i18n; + } + + public String getAccessToken() { + return accessToken; + } + + public int getTimeout() { + return timeout; + } + + public String getEmailFrom() { + return emailFrom; + } + + public int getTriggerPoolFastMax() { + if (triggerPoolFastMax < 200) { + return 200; + } + return triggerPoolFastMax; + } + + public int getTriggerPoolSlowMax() { + if (triggerPoolSlowMax < 100) { + return 100; + } + return triggerPoolSlowMax; + } + + public int getScheduleBatchSize() { + if (!(scheduleBatchSize >= 50 && scheduleBatchSize <= 500)) { + return 100; + } + return scheduleBatchSize; + } + + public int getLogretentiondays() { + if (logretentiondays < 3) { + return -1; // Limit greater than or equal to 3, otherwise close + } + return logretentiondays; + } + + public XxlJobLogMapper getXxlJobLogMapper() { + return xxlJobLogMapper; + } + + public XxlJobInfoMapper getXxlJobInfoMapper() { + return xxlJobInfoMapper; + } + + public XxlJobRegistryMapper getXxlJobRegistryMapper() { + return xxlJobRegistryMapper; + } + + public XxlJobGroupMapper getXxlJobGroupMapper() { + return xxlJobGroupMapper; + } + + public XxlJobLogReportMapper getXxlJobLogReportMapper() { + return xxlJobLogReportMapper; + } + + public XxlJobLockMapper getXxlJobLockMapper() { + return xxlJobLockMapper; + } + + public JavaMailSender getMailSender() { + return mailSender; + } + + /*public DataSource getDataSource() { + return dataSource; + }*/ + + public PlatformTransactionManager getTransactionManager() { + return transactionManager; + } + + public JobAlarmer getJobAlarmer() { + return jobAlarmer; + } + + public JobTrigger getJobTrigger() { + return jobTrigger; + } + + public JobCompleter getJobCompleter() { + return jobCompleter; + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/cron/CronExpression.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/cron/CronExpression.java new file mode 100644 index 000000000..f112591a7 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/cron/CronExpression.java @@ -0,0 +1,1698 @@ +package com.xxl.job.admin.scheduler.cron; +/* + * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. + * Copyright IBM Corp. 2024, 2025 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Borrowed from quartz v2.5.2 + */ + +import java.io.Serializable; +import java.text.ParseException; +import java.util.*; + +/** + * Provides a parser and evaluator for unix-like cron expressions. Cron + * expressions provide the ability to specify complex time combinations such as + * "At 8:00am every Monday through Friday" or "At 1:30am every + * last Friday of the month". + *

+ * Cron expressions are comprised of 6 required fields and one optional field + * separated by white space. The fields respectively are described as follows: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of cron expressions and their meanings.
Field Name Allowed Values Allowed Special Characters
Seconds 0-59 , - * /
Minutes 0-59 , - * /
Hours 0-23 , - * /
Day-of-month 1-31 , - * ? / L W
Month 1-12 or JAN-DEC , - * /
Day-of-Week 1-7 or SUN-SAT , - * ? / L #
Year (Optional) empty, 1970-2199 , - * /
+ *

+ * The '*' character is used to specify all values. For example, "*" + * in the minute field means "every minute". + *

+ *

+ * The '?' character is allowed for the day-of-month and day-of-week fields. It + * is used to specify 'no specific value'. This is useful when you need to + * specify something in one of the two fields, but not the other. + *

+ * The '-' character is used to specify ranges For example "10-12" in + * the hour field means "the hours 10, 11 and 12". + *

+ * The ',' character is used to specify additional values. For example + * "MON,WED,FRI" in the day-of-week field means "the days Monday, + * Wednesday, and Friday". + *

+ *

+ * The '/' character is used to specify increments. For example "0/15" + * in the seconds field means "the seconds 0, 15, 30, and 45". And + * "5/15" in the seconds field means "the seconds 5, 20, 35, and + * 50". Specifying '*' before the '/' is equivalent to specifying 0 is + * the value to start with. Essentially, for each field in the expression, there + * is a set of numbers that can be turned on or off. For seconds and minutes, + * the numbers range from 0 to 59. For hours 0 to 23, for days of the month 0 to + * 31, and for months 0 to 11 (JAN to DEC). The "/" character simply helps you turn + * on every "nth" value in the given set. Thus "7/6" in the + * month field only turns on month "7", it does NOT mean every 6th + * month, please note that subtlety. + *

+ *

+ * The 'L' character is allowed for the day-of-month and day-of-week fields. + * This character is short-hand for "last", but it has different + * meaning in each of the two fields. For example, the value "L" in + * the day-of-month field means "the last day of the month" - day 31 + * for January, day 28 for February on non-leap years. If used in the + * day-of-week field by itself, it simply means "7" or + * "SAT". But if used in the day-of-week field after another value, it + * means "the last xxx day of the month" - for example "6L" + * means "the last friday of the month". You can also specify an offset + * from the last day of the month, such as "L-3" which would mean the third-to-last + * day of the calendar month. When using the 'L' option, it is important not to + * specify lists, or ranges of values, as you'll get confusing/unexpected results. + *

+ *

+ * The 'W' character is allowed for the day-of-month field. This character + * is used to specify the weekday (Monday-Friday) nearest the given day. As an + * example, if you were to specify "15W" as the value for the + * day-of-month field, the meaning is: "the nearest weekday to the 15th of + * the month". So if the 15th is a Saturday, the trigger will fire on + * Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the + * 16th. If the 15th is a Tuesday, then it will fire on Tuesday the 15th. + * However if you specify "1W" as the value for day-of-month, and the + * 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not + * 'jump' over the boundary of a month's days. The 'W' character can only be + * specified when the day-of-month is a single day, not a range or list of days. + *

+ *

+ * The 'L' and 'W' characters can also be combined for the day-of-month + * expression to yield 'LW', which translates to "last weekday of the + * month". + *

+ *

+ * The '#' character is allowed for the day-of-week field. This character is + * used to specify "the nth" XXX day of the month. For example, the + * value of "6#3" in the day-of-week field means the third Friday of + * the month (day 6 = Friday and "#3" = the 3rd one in the month). + * Other examples: "2#1" = the first Monday of the month and + * "4#5" = the fifth Wednesday of the month. Note that if you specify + * "#5" and there is not 5 of the given day-of-week in the month, then + * no firing will occur that month. If the '#' character is used, there can + * only be one expression in the day-of-week field ("3#1,6#3" is + * not valid, since there are two expressions). + *

+ * + *

+ * The legal characters and the names of months and days of the week are not + * case sensitive. + * + *

+ * NOTES: + *

+ *
    + *
  • Support for specifying both a day-of-week and a day-of-month value is + * not complete (you'll need to use the '?' character in one of these fields). + *
  • + *
  • Overflowing ranges is supported - that is, having a larger number on + * the left hand side than the right. You might do 22-2 to catch 10 o'clock + * at night until 2 o'clock in the morning, or you might have NOV-FEB. It is + * very important to note that overuse of overflowing ranges creates ranges + * that don't make sense and no effort has been made to determine which + * interpretation CronExpression chooses. An example would be + * "0 0 14-6 ? * FRI-MON".
  • + *
+ * + * @author Sharada Jambula, James House + * @author Contributions from Mads Henderson + * @author Refactoring from CronTrigger to CronExpression by Aaron Craven + */ +public final class CronExpression implements Serializable, Cloneable { + + private static final long serialVersionUID = 12423409423L; + + protected static final int SECOND = 0; + protected static final int MINUTE = 1; + protected static final int HOUR = 2; + protected static final int DAY_OF_MONTH = 3; + protected static final int MONTH = 4; + protected static final int DAY_OF_WEEK = 5; + protected static final int YEAR = 6; + protected static final int ALL_SPEC_INT = 99; // '*' + protected static final int NO_SPEC_INT = 98; // '?' + protected static final int MAX_LAST_DAY_OFFSET = 30; + protected static final int LAST_DAY_OFFSET_START = 32; // "L-30" + protected static final int LAST_DAY_OFFSET_END = LAST_DAY_OFFSET_START + MAX_LAST_DAY_OFFSET; // 'L' + protected static final Integer ALL_SPEC = ALL_SPEC_INT; + protected static final Integer NO_SPEC = NO_SPEC_INT; + + protected static final Map monthMap = new HashMap<>(20); + protected static final Map dayMap = new HashMap<>(60); + + static { + monthMap.put("JAN", 0); + monthMap.put("FEB", 1); + monthMap.put("MAR", 2); + monthMap.put("APR", 3); + monthMap.put("MAY", 4); + monthMap.put("JUN", 5); + monthMap.put("JUL", 6); + monthMap.put("AUG", 7); + monthMap.put("SEP", 8); + monthMap.put("OCT", 9); + monthMap.put("NOV", 10); + monthMap.put("DEC", 11); + + dayMap.put("SUN", 1); + dayMap.put("MON", 2); + dayMap.put("TUE", 3); + dayMap.put("WED", 4); + dayMap.put("THU", 5); + dayMap.put("FRI", 6); + dayMap.put("SAT", 7); + } + + private final String cronExpression; + private TimeZone timeZone = null; + protected transient TreeSet seconds; + protected transient TreeSet minutes; + protected transient TreeSet hours; + protected transient TreeSet daysOfMonth; + protected transient TreeSet nearestWeekdays; + protected transient TreeSet months; + protected transient TreeSet daysOfWeek; + protected transient TreeSet years; + + protected transient boolean lastDayOfWeek = false; + protected transient int nthDayOfWeek = 0; + protected transient boolean expressionParsed = false; + + public static final int MAX_YEAR = Calendar.getInstance().get(Calendar.YEAR) + 100; + + /** + * Constructs a new CronExpression based on the specified + * parameter. + * + * @param cronExpression String representation of the cron expression the + * new object should represent + * @throws java.text.ParseException if the string expression cannot be parsed into a valid + * CronExpression + */ + public CronExpression(String cronExpression) throws ParseException { + if (cronExpression == null) { + throw new IllegalArgumentException("cronExpression cannot be null"); + } + + this.cronExpression = cronExpression.toUpperCase(Locale.US); + + buildExpression(this.cronExpression); + } + + /** + * Constructs a new {@code CronExpression} as a copy of an existing + * instance. + * + * @param expression The existing cron expression to be copied + */ + public CronExpression(CronExpression expression) { + /* + * We don't call the other constructor here since we need to swallow the + * ParseException. We also elide some of the sanity checking as it is + * not logically trippable. + */ + this.cronExpression = expression.getCronExpression(); + try { + buildExpression(cronExpression); + } catch (ParseException ex) { + throw new AssertionError("Could not parse expression!", ex); + } + if (expression.getTimeZone() != null) { + setTimeZone((TimeZone) expression.getTimeZone().clone()); + } + } + + /** + * Indicates whether the given date satisfies the cron expression. Note that + * milliseconds are ignored, so two Dates falling on different milliseconds + * of the same second will always have the same result here. + * + * @param date the date to evaluate + * @return a boolean indicating whether the given date satisfies the cron + * expression + */ + public boolean isSatisfiedBy(Date date) { + Calendar testDateCal = Calendar.getInstance(getTimeZone()); + testDateCal.setTime(date); + testDateCal.set(Calendar.MILLISECOND, 0); + Date originalDate = testDateCal.getTime(); + + testDateCal.add(Calendar.SECOND, -1); + + Date timeAfter = getTimeAfter(testDateCal.getTime()); + + return ((timeAfter != null) && (timeAfter.equals(originalDate))); + } + + /** + * Returns the next date/time after the given date/time which + * satisfies the cron expression. + * + * @param date the date/time at which to begin the search for the next valid + * date/time + * @return the next valid date/time + */ + public Date getNextValidTimeAfter(Date date) { + return getTimeAfter(date); + } + + /** + * Returns the next date/time after the given date/time which does + * not satisfy the expression + * + * @param date the date/time at which to begin the search for the next + * invalid date/time + * @return the next valid date/time + */ + public Date getNextInvalidTimeAfter(Date date) { + long difference = 1000; + + //move back to the nearest second so differences will be accurate + Calendar adjustCal = Calendar.getInstance(getTimeZone()); + adjustCal.setTime(date); + adjustCal.set(Calendar.MILLISECOND, 0); + Date lastDate = adjustCal.getTime(); + + Date newDate; + + //FUTURE_TODO: (QUARTZ-481) IMPROVE THIS! The following is a BAD solution to this problem. Performance will be very bad here, depending on the cron expression. It is, however A solution. + + //keep getting the next included time until it's farther than one second + // apart. At that point, lastDate is the last valid fire time. We return + // the second immediately following it. + while (difference == 1000) { + newDate = getTimeAfter(lastDate); + if (newDate == null) + break; + + difference = newDate.getTime() - lastDate.getTime(); + + if (difference == 1000) { + lastDate = newDate; + } + } + + return new Date(lastDate.getTime() + 1000); + } + + /** + * Returns the time zone for which this CronExpression + * will be resolved. + */ + public TimeZone getTimeZone() { + if (timeZone == null) { + timeZone = TimeZone.getDefault(); + } + + return timeZone; + } + + /** + * Sets the time zone for which this CronExpression + * will be resolved. + */ + public void setTimeZone(TimeZone timeZone) { + this.timeZone = timeZone; + } + + /** + * Returns the string representation of the CronExpression + * + * @return a string representation of the CronExpression + */ + @Override + public String toString() { + return cronExpression; + } + + /** + * Indicates whether the specified cron expression can be parsed into a + * valid cron expression + * + * @param cronExpression the expression to evaluate + * @return a boolean indicating whether the given expression is a valid cron + * expression + */ + public static boolean isValidExpression(String cronExpression) { + + try { + new CronExpression(cronExpression); + } catch (ParseException pe) { + return false; + } + + return true; + } + + public static void validateExpression(String cronExpression) throws ParseException { + + new CronExpression(cronExpression); + } + + + //////////////////////////////////////////////////////////////////////////// + // + // Expression Parsing Functions + // + + /// ///////////////////////////////////////////////////////////////////////// + + protected void buildExpression(String expression) throws ParseException { + expressionParsed = true; + + try { + + if (seconds == null) { + seconds = new TreeSet<>(); + } + if (minutes == null) { + minutes = new TreeSet<>(); + } + if (hours == null) { + hours = new TreeSet<>(); + } + if (daysOfMonth == null) { + daysOfMonth = new TreeSet<>(); + } + if (nearestWeekdays == null) { + nearestWeekdays = new TreeSet<>(); + } + if (months == null) { + months = new TreeSet<>(); + } + if (daysOfWeek == null) { + daysOfWeek = new TreeSet<>(); + } + if (years == null) { + years = new TreeSet<>(); + } + + int exprOn = SECOND; + + StringTokenizer exprsTok = new StringTokenizer(expression, " \t", + false); + + if (exprsTok.countTokens() > 7) { + throw new ParseException("Invalid expression has too many terms: " + expression, -1); + } + + while (exprsTok.hasMoreTokens() && exprOn <= YEAR) { + String expr = exprsTok.nextToken().trim(); + + // throw an exception if L is used with other days of the week + if (exprOn == DAY_OF_WEEK && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(",")) { + throw new ParseException("Support for specifying 'L' with other days of the week is not implemented", -1); + } + if (exprOn == DAY_OF_WEEK && expr.indexOf('#') != -1 && expr.indexOf('#', expr.indexOf('#') + 1) != -1) { + throw new ParseException("Support for specifying multiple \"nth\" days is not implemented.", -1); + } + + StringTokenizer vTok = new StringTokenizer(expr, ","); + while (vTok.hasMoreTokens()) { + String v = vTok.nextToken(); + storeExpressionVals(0, v, exprOn); + } + + exprOn++; + } + + if (exprOn <= DAY_OF_WEEK) { + throw new ParseException("Unexpected end of expression.", + expression.length()); + } + + if (exprOn <= YEAR) { + storeExpressionVals(0, "*", YEAR); + } + + TreeSet dow = getSet(DAY_OF_WEEK); + TreeSet dom = getSet(DAY_OF_MONTH); + + // Copying the logic from the UnsupportedOperationException below + boolean dayOfMSpec = !dom.contains(NO_SPEC); + boolean dayOfWSpec = !dow.contains(NO_SPEC); + + if (!dayOfMSpec || dayOfWSpec) { + if (!dayOfWSpec || dayOfMSpec) { + throw new ParseException( + "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.", 0); + } + } + } catch (ParseException pe) { + throw pe; + } catch (Exception e) { + throw new ParseException("Illegal cron expression format (" + + e + ")", 0); + } + } + + protected int storeExpressionVals(int pos, String s, int type) + throws ParseException { + + int incr = 0; + int i = skipWhiteSpace(pos, s); + if (i >= s.length()) { + return i; + } + char c = s.charAt(i); + if ((c >= 'A') && (c <= 'Z') && (!s.equals("L")) && (!s.equals("LW")) && (!s.matches("^L-[0-9]*[W]?"))) { + String sub = s.substring(i, i + 3); + int sval = -1; + int eval = -1; + if (type == MONTH) { + sval = getMonthNumber(sub) + 1; + if (sval <= 0) { + throw new ParseException("Invalid Month value: '" + sub + "'", i); + } + if (s.length() > i + 3) { + c = s.charAt(i + 3); + if (c == '-') { + i += 4; + sub = s.substring(i, i + 3); + eval = getMonthNumber(sub) + 1; + if (eval <= 0) { + throw new ParseException("Invalid Month value: '" + sub + "'", i); + } + } + } + } else if (type == DAY_OF_WEEK) { + sval = getDayOfWeekNumber(sub); + if (sval < 0) { + throw new ParseException("Invalid Day-of-Week value: '" + + sub + "'", i); + } + if (s.length() > i + 3) { + c = s.charAt(i + 3); + if (c == '-') { + i += 4; + sub = s.substring(i, i + 3); + eval = getDayOfWeekNumber(sub); + if (eval < 0) { + throw new ParseException( + "Invalid Day-of-Week value: '" + sub + + "'", i); + } + } else if (c == '#') { + try { + i += 4; + nthDayOfWeek = Integer.parseInt(s.substring(i)); + if (nthDayOfWeek < 1 || nthDayOfWeek > 5) { + throw new Exception(); + } + } catch (Exception e) { + throw new ParseException( + "A numeric value between 1 and 5 must follow the '#' option", + i); + } + } else if (c == 'L') { + lastDayOfWeek = true; + i++; + } + } + + } else { + throw new ParseException( + "Illegal characters for this position: '" + sub + "'", + i); + } + if (eval != -1) { + incr = 1; + } + addToSet(sval, eval, incr, type); + return (i + 3); + } + + if (c == '?') { + i++; + if ((i + 1) < s.length() + && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\t')) { + throw new ParseException("Illegal character after '?': " + + s.charAt(i), i); + } + if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) { + throw new ParseException( + "'?' can only be specified for Day-of-Month or Day-of-Week.", + i); + } + if (type == DAY_OF_WEEK) { + if (!daysOfMonth.isEmpty() && daysOfMonth.last() == NO_SPEC_INT) { + throw new ParseException( + "'?' can only be specified for Day-of-Month -OR- Day-of-Week.", + i); + } + } + + addToSet(NO_SPEC_INT, -1, 0, type); + return i; + } + + if (c == '*' || c == '/') { + if (c == '*' && (i + 1) >= s.length()) { + addToSet(ALL_SPEC_INT, -1, incr, type); + return i + 1; + } else if (c == '/' + && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s + .charAt(i + 1) == '\t')) { + throw new ParseException("'/' must be followed by an integer.", i); + } else if (c == '*') { + i++; + } + c = s.charAt(i); + if (c == '/') { // is an increment specified? + i++; + if (i >= s.length()) { + throw new ParseException("Unexpected end of string.", i); + } + + incr = getNumericValue(s, i); + + i++; + if (incr > 10) { + i++; + } + checkIncrementRange(incr, type, i); + } else { + incr = 1; + } + + addToSet(ALL_SPEC_INT, -1, incr, type); + return i; + } else if (c == 'L') { + + if (type < DAY_OF_MONTH) + throw new ParseException("'L' not expected in seconds, minutes or hours fields.", i); + + i++; + if (type == DAY_OF_WEEK) { + addToSet(7, 7, 0, type); + } + if (type == DAY_OF_MONTH) { + int dom = LAST_DAY_OFFSET_END; + boolean nearestWeekday = false; + if (s.length() > i) { + c = s.charAt(i); + if (c == '-') { + ValueSet vs = getValue(0, s, i + 1); + int offset = vs.value; + if (offset > MAX_LAST_DAY_OFFSET) + throw new ParseException("Offset from last day must be <= " + MAX_LAST_DAY_OFFSET, i + 1); + dom -= offset; + i = vs.pos; + } + if (s.length() > i) { + c = s.charAt(i); + if (c == 'W') { + nearestWeekday = true; + i++; + } + } + } + if (nearestWeekday) { + nearestWeekdays.add(dom); + } else { + daysOfMonth.add(dom); + } + } + return i; + } else if (c >= '0' && c <= '9') { + int val = Integer.parseInt(String.valueOf(c)); + i++; + if (i >= s.length()) { + addToSet(val, -1, -1, type); + } else { + c = s.charAt(i); + if (c >= '0' && c <= '9') { + ValueSet vs = getValue(val, s, i); + val = vs.value; + i = vs.pos; + } + i = checkNext(i, s, val, type); + return i; + } + } else { + throw new ParseException("Unexpected character: " + c, i); + } + + return i; + } + + private void checkIncrementRange(int incr, int type, int idxPos) throws ParseException { + if (incr > 59 && (type == SECOND || type == MINUTE)) { + throw new ParseException("Increment >= 60 : " + incr, idxPos); + } else if (incr > 23 && (type == HOUR)) { + throw new ParseException("Increment >= 24 : " + incr, idxPos); + } else if (incr > 31 && (type == DAY_OF_MONTH)) { + throw new ParseException("Increment >= 31 : " + incr, idxPos); + } else if (incr > 7 && (type == DAY_OF_WEEK)) { + throw new ParseException("Increment >= 7 : " + incr, idxPos); + } else if (incr > 12 && (type == MONTH)) { + throw new ParseException("Increment >= 12 : " + incr, idxPos); + } + } + + protected int checkNext(int pos, String s, int val, int type) + throws ParseException { + + int end = -1; + int i = pos; + + if (i >= s.length()) { + addToSet(val, end, -1, type); + return i; + } + + char c = s.charAt(pos); + + if (c == 'L') { + if (type == DAY_OF_WEEK) { + if (val < 1 || val > 7) + throw new ParseException("Day-of-Week values must be between 1 and 7", -1); + lastDayOfWeek = true; + } else { + throw new ParseException("'L' option is not valid here. (pos=" + i + ")", i); + } + TreeSet set = getSet(type); + set.add(val); + i++; + return i; + } + + if (c == 'W') { + if (type != DAY_OF_MONTH) { + throw new ParseException("'W' option is not valid here. (pos=" + i + ")", i); + } + if (val > 31) + throw new ParseException("The 'W' option does not make sense with values larger than 31 (max number of days in a month)", i); + nearestWeekdays.add(val); + i++; + return i; + } + + if (c == '#') { + if (type != DAY_OF_WEEK) { + throw new ParseException("'#' option is not valid here. (pos=" + i + ")", i); + } + i++; + try { + nthDayOfWeek = Integer.parseInt(s.substring(i)); + if (nthDayOfWeek < 1 || nthDayOfWeek > 5) { + throw new Exception(); + } + } catch (Exception e) { + throw new ParseException( + "A numeric value between 1 and 5 must follow the '#' option", + i); + } + + TreeSet set = getSet(type); + set.add(val); + i++; + return i; + } + + if (c == '-') { + i++; + c = s.charAt(i); + int v = Integer.parseInt(String.valueOf(c)); + end = v; + i++; + if (i >= s.length()) { + addToSet(val, end, 1, type); + return i; + } + c = s.charAt(i); + if (c >= '0' && c <= '9') { + ValueSet vs = getValue(v, s, i); + end = vs.value; + i = vs.pos; + } + if (i < s.length() && ((c = s.charAt(i)) == '/')) { + i++; + c = s.charAt(i); + int v2 = Integer.parseInt(String.valueOf(c)); + i++; + if (i >= s.length()) { + addToSet(val, end, v2, type); + return i; + } + c = s.charAt(i); + if (c >= '0' && c <= '9') { + ValueSet vs = getValue(v2, s, i); + int v3 = vs.value; + addToSet(val, end, v3, type); + i = vs.pos; + return i; + } else { + addToSet(val, end, v2, type); + return i; + } + } else { + addToSet(val, end, 1, type); + return i; + } + } + + if (c == '/') { + if ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s.charAt(i + 1) == '\t') { + throw new ParseException("'/' must be followed by an integer.", i); + } + + i++; + c = s.charAt(i); + int v2 = Integer.parseInt(String.valueOf(c)); + i++; + if (i >= s.length()) { + checkIncrementRange(v2, type, i); + addToSet(val, end, v2, type); + return i; + } + c = s.charAt(i); + if (c >= '0' && c <= '9') { + ValueSet vs = getValue(v2, s, i); + int v3 = vs.value; + checkIncrementRange(v3, type, i); + addToSet(val, end, v3, type); + i = vs.pos; + return i; + } else { + throw new ParseException("Unexpected character '" + c + "' after '/'", i); + } + } + + addToSet(val, end, 0, type); + i++; + return i; + } + + public String getCronExpression() { + return cronExpression; + } + + public String getExpressionSummary() { + StringBuilder buf = new StringBuilder(); + + buf.append("seconds: "); + buf.append(getExpressionSetSummary(seconds)); + buf.append("\n"); + buf.append("minutes: "); + buf.append(getExpressionSetSummary(minutes)); + buf.append("\n"); + buf.append("hours: "); + buf.append(getExpressionSetSummary(hours)); + buf.append("\n"); + buf.append("daysOfMonth: "); + buf.append(getExpressionSetSummary(daysOfMonth)); + buf.append("\n"); + buf.append("nearestWeekdays: "); + buf.append(getExpressionSetSummary(nearestWeekdays)); + buf.append("\n"); + buf.append("months: "); + buf.append(getExpressionSetSummary(months)); + buf.append("\n"); + buf.append("daysOfWeek: "); + buf.append(getExpressionSetSummary(daysOfWeek)); + buf.append("\n"); + buf.append("lastDayOfWeek: "); + buf.append(lastDayOfWeek); + buf.append("\n"); + buf.append("NthDayOfWeek: "); + buf.append(nthDayOfWeek); + buf.append("\n"); + buf.append("years: "); + buf.append(getExpressionSetSummary(years)); + buf.append("\n"); + + return buf.toString(); + } + + protected String getExpressionSetSummary(java.util.Set set) { + + if (set.contains(NO_SPEC)) { + return "?"; + } + if (set.contains(ALL_SPEC)) { + return "*"; + } + + StringBuilder buf = new StringBuilder(); + + Iterator itr = set.iterator(); + boolean first = true; + while (itr.hasNext()) { + Integer iVal = itr.next(); + String val = iVal.toString(); + if (!first) { + buf.append(","); + } + buf.append(val); + first = false; + } + + return buf.toString(); + } + + protected String getExpressionSetSummary(java.util.ArrayList list) { + + if (list.contains(NO_SPEC)) { + return "?"; + } + if (list.contains(ALL_SPEC)) { + return "*"; + } + + StringBuilder buf = new StringBuilder(); + + Iterator itr = list.iterator(); + boolean first = true; + while (itr.hasNext()) { + Integer iVal = itr.next(); + String val = iVal.toString(); + if (!first) { + buf.append(","); + } + buf.append(val); + first = false; + } + + return buf.toString(); + } + + protected int skipWhiteSpace(int i, String s) { + for (; i < s.length() && (s.charAt(i) == ' ' || s.charAt(i) == '\t'); i++) { + } + + return i; + } + + protected int findNextWhiteSpace(int i, String s) { + for (; i < s.length() && (s.charAt(i) != ' ' || s.charAt(i) != '\t'); i++) { + } + + return i; + } + + protected void addToSet(int val, int end, int incr, int type) + throws ParseException { + + TreeSet set = getSet(type); + + if (type == SECOND || type == MINUTE) { + if ((val < 0 || val > 59 || end > 59) && (val != ALL_SPEC_INT)) { + throw new ParseException( + "Minute and Second values must be between 0 and 59", + -1); + } + } else if (type == HOUR) { + if ((val < 0 || val > 23 || end > 23) && (val != ALL_SPEC_INT)) { + throw new ParseException( + "Hour values must be between 0 and 23", -1); + } + } else if (type == DAY_OF_MONTH) { + if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT) + && (val != NO_SPEC_INT)) { + throw new ParseException( + "Day of month values must be between 1 and 31", -1); + } + } else if (type == MONTH) { + if ((val < 1 || val > 12 || end > 12) && (val != ALL_SPEC_INT)) { + throw new ParseException( + "Month values must be between 1 and 12", -1); + } + } else if (type == DAY_OF_WEEK) { + if ((val == 0 || val > 7 || end > 7) && (val != ALL_SPEC_INT) + && (val != NO_SPEC_INT)) { + throw new ParseException( + "Day-of-Week values must be between 1 and 7", -1); + } + } + + if ((incr == 0 || incr == -1) && val != ALL_SPEC_INT) { + if (val != -1) { + set.add(val); + } else { + set.add(NO_SPEC); + } + + return; + } + + int startAt = val; + int stopAt = end; + + if (val == ALL_SPEC_INT && incr <= 0) { + incr = 1; + set.add(ALL_SPEC); // put in a marker, but also fill values + } + + if (type == SECOND || type == MINUTE) { + if (stopAt == -1) { + stopAt = 59; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 0; + } + } else if (type == HOUR) { + if (stopAt == -1) { + stopAt = 23; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 0; + } + } else if (type == DAY_OF_MONTH) { + if (stopAt == -1) { + stopAt = 31; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1; + } + } else if (type == MONTH) { + if (stopAt == -1) { + stopAt = 12; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1; + } + } else if (type == DAY_OF_WEEK) { + if (stopAt == -1) { + stopAt = 7; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1; + } + } else if (type == YEAR) { + if (stopAt == -1) { + stopAt = MAX_YEAR; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1970; + } + } + + // if the end of the range is before the start, then we need to overflow into + // the next day, month etc. This is done by adding the maximum amount for that + // type, and using modulus max to determine the value being added. + int max = -1; + if (stopAt < startAt) { + switch (type) { + case SECOND: + max = 60; + break; + case MINUTE: + max = 60; + break; + case HOUR: + max = 24; + break; + case MONTH: + max = 12; + break; + case DAY_OF_WEEK: + max = 7; + break; + case DAY_OF_MONTH: + max = 31; + break; + case YEAR: + throw new IllegalArgumentException("Start year must be less than stop year"); + default: + throw new IllegalArgumentException("Unexpected type encountered"); + } + stopAt += max; + } + + for (int i = startAt; i <= stopAt; i += incr) { + if (max == -1) { + // ie: there's no max to overflow over + set.add(i); + } else { + // take the modulus to get the real value + int i2 = i % max; + + // 1-indexed ranges should not include 0, and should include their max + if (i2 == 0 && (type == MONTH || type == DAY_OF_WEEK || type == DAY_OF_MONTH)) { + i2 = max; + } + + set.add(i2); + } + } + } + + TreeSet getSet(int type) { + switch (type) { + case SECOND: + return seconds; + case MINUTE: + return minutes; + case HOUR: + return hours; + case DAY_OF_MONTH: + return daysOfMonth; + case MONTH: + return months; + case DAY_OF_WEEK: + return daysOfWeek; + case YEAR: + return years; + default: + return null; + } + } + + protected ValueSet getValue(int v, String s, int i) { + char c = s.charAt(i); + StringBuilder s1 = new StringBuilder(String.valueOf(v)); + while (c >= '0' && c <= '9') { + s1.append(c); + i++; + if (i >= s.length()) { + break; + } + c = s.charAt(i); + } + ValueSet val = new ValueSet(); + + val.pos = (i < s.length()) ? i : i + 1; + val.value = Integer.parseInt(s1.toString()); + return val; + } + + protected int getNumericValue(String s, int i) { + int endOfVal = findNextWhiteSpace(i, s); + String val = s.substring(i, endOfVal); + return Integer.parseInt(val); + } + + protected int getMonthNumber(String s) { + Integer integer = monthMap.get(s); + + if (integer == null) { + return -1; + } + + return integer; + } + + protected int getDayOfWeekNumber(String s) { + Integer integer = dayMap.get(s); + + if (integer == null) { + return -1; + } + + return integer; + } + + //////////////////////////////////////////////////////////////////////////// + // + // Computation Functions + // + + /// ///////////////////////////////////////////////////////////////////////// + + public Date getTimeAfter(Date afterTime) { + + // Computation is based on Gregorian year only. + Calendar cl = new java.util.GregorianCalendar(getTimeZone()); + + // move ahead one second, since we're computing the time *after* the + // given time + afterTime = new Date(afterTime.getTime() + 1000); + // CronTrigger does not deal with milliseconds + cl.setTime(afterTime); + cl.set(Calendar.MILLISECOND, 0); + + boolean gotOne = false; + // loop until we've computed the next time, or we've past the endTime + while (!gotOne) { + + //if (endTime != null && cl.getTime().after(endTime)) return null; + if (cl.get(Calendar.YEAR) > 2999) { // prevent endless loop... + return null; + } + + SortedSet st = null; + int t = 0; + + int sec = cl.get(Calendar.SECOND); + int min = cl.get(Calendar.MINUTE); + + // get second................................................. + st = seconds.tailSet(sec); + if (st != null && !st.isEmpty()) { + sec = st.first(); + } else { + sec = seconds.first(); + min++; + cl.set(Calendar.MINUTE, min); + } + cl.set(Calendar.SECOND, sec); + + min = cl.get(Calendar.MINUTE); + int hr = cl.get(Calendar.HOUR_OF_DAY); + t = -1; + + // get minute................................................. + st = minutes.tailSet(min); + if (st != null && !st.isEmpty()) { + t = min; + min = st.first(); + } else { + min = minutes.first(); + hr++; + } + if (min != t) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, min); + setCalendarHour(cl, hr); + continue; + } + cl.set(Calendar.MINUTE, min); + + hr = cl.get(Calendar.HOUR_OF_DAY); + int day = cl.get(Calendar.DAY_OF_MONTH); + t = -1; + + // get hour................................................... + st = hours.tailSet(hr); + if (st != null && !st.isEmpty()) { + t = hr; + hr = st.first(); + } else { + hr = hours.first(); + day++; + } + if (hr != t) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.DAY_OF_MONTH, day); + setCalendarHour(cl, hr); + continue; + } + cl.set(Calendar.HOUR_OF_DAY, hr); + + day = cl.get(Calendar.DAY_OF_MONTH); + int mon = cl.get(Calendar.MONTH) + 1; + // '+ 1' because calendar is 0-based for this field, and we are + // 1-based + t = -1; + int tmon = mon; + + // get day................................................... + boolean dayOfMSpec = !daysOfMonth.contains(NO_SPEC); + boolean dayOfWSpec = !daysOfWeek.contains(NO_SPEC); + if (dayOfMSpec && !dayOfWSpec) { // get day by day of month rule + Optional smallestDay = findSmallestDay(day, mon, cl.get(Calendar.YEAR), daysOfMonth); + Optional smallestDayForWeekday = findSmallestDay(day, mon, cl.get(Calendar.YEAR), nearestWeekdays); + t = day; + day = -1; + if (smallestDayForWeekday.isPresent()) { + day = smallestDayForWeekday.get(); + + java.util.Calendar tcal = java.util.Calendar.getInstance(getTimeZone()); + tcal.set(Calendar.SECOND, 0); + tcal.set(Calendar.MINUTE, 0); + tcal.set(Calendar.HOUR_OF_DAY, 0); + tcal.set(Calendar.DAY_OF_MONTH, day); + tcal.set(Calendar.MONTH, mon - 1); + tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR)); + + int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + int dow = tcal.get(Calendar.DAY_OF_WEEK); + + if (dow == Calendar.SATURDAY && day == 1) { + day += 2; + } else if (dow == Calendar.SATURDAY) { + day -= 1; + } else if (dow == Calendar.SUNDAY && day == ldom) { + day -= 2; + } else if (dow == Calendar.SUNDAY) { + day += 1; + } + + + tcal.set(Calendar.SECOND, sec); + tcal.set(Calendar.MINUTE, min); + tcal.set(Calendar.HOUR_OF_DAY, hr); + tcal.set(Calendar.DAY_OF_MONTH, day); + tcal.set(Calendar.MONTH, mon - 1); + Date nTime = tcal.getTime(); + if (nTime.before(afterTime)) { + day = -1; + } + } + + boolean needAdvance = false; + if (smallestDay.isPresent()) { + if (day == -1 || smallestDay.get() < day) { + day = smallestDay.get(); + needAdvance = true; + } + } else if (day == -1) { + day = 1; + mon++; + needAdvance = true; + } + + if (needAdvance && (day != t || mon != tmon)) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, day); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' because calendar is 0-based for this field, and we + // are 1-based + continue; + } + + } else if (dayOfWSpec && !dayOfMSpec) { // get day by day of week rule + if (lastDayOfWeek) { // are we looking for the last XXX day of + // the month? + int dow = daysOfWeek.first(); // desired + // d-o-w + int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w + int daysToAdd = 0; + if (cDow < dow) { + daysToAdd = dow - cDow; + } + if (cDow > dow) { + daysToAdd = dow + (7 - cDow); + } + + int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + + if (day + daysToAdd > lDay) { // did we already miss the + // last one? + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, mon); + // no '- 1' here because we are promoting the month + continue; + } + + // find date of last occurrence of this day in this month... + while ((day + daysToAdd + 7) <= lDay) { + daysToAdd += 7; + } + + day += daysToAdd; + + if (daysToAdd > 0) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, day); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' here because we are not promoting the month + continue; + } + + } else if (nthDayOfWeek != 0) { + // are we looking for the Nth XXX day in the month? + int dow = daysOfWeek.first(); // desired + // d-o-w + int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w + int daysToAdd = 0; + if (cDow < dow) { + daysToAdd = dow - cDow; + } else if (cDow > dow) { + daysToAdd = dow + (7 - cDow); + } + + boolean dayShifted = daysToAdd > 0; + + day += daysToAdd; + int weekOfMonth = day / 7; + if (day % 7 > 0) { + weekOfMonth++; + } + + daysToAdd = (nthDayOfWeek - weekOfMonth) * 7; + day += daysToAdd; + if (daysToAdd < 0 + || day > getLastDayOfMonth(mon, cl + .get(Calendar.YEAR))) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, mon); + // no '- 1' here because we are promoting the month + continue; + } else if (daysToAdd > 0 || dayShifted) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, day); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' here because we are NOT promoting the month + continue; + } + } else { + int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w + int dow = daysOfWeek.first(); // desired + // d-o-w + st = daysOfWeek.tailSet(cDow); + if (st != null && !st.isEmpty()) { + dow = st.first(); + } + + int daysToAdd = 0; + if (cDow < dow) { + daysToAdd = dow - cDow; + } + if (cDow > dow) { + daysToAdd = dow + (7 - cDow); + } + + int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + + if (day + daysToAdd > lDay) { // will we pass the end of + // the month? + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, mon); + // no '- 1' here because we are promoting the month + continue; + } else if (daysToAdd > 0) { // are we switching days? + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, day + daysToAdd); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' because calendar is 0-based for this field, + // and we are 1-based + continue; + } + } + } else { // dayOfWSpec && !dayOfMSpec + throw new UnsupportedOperationException( + "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented."); + } + cl.set(Calendar.DAY_OF_MONTH, day); + + mon = cl.get(Calendar.MONTH) + 1; + // '+ 1' because calendar is 0-based for this field, and we are + // 1-based + int year = cl.get(Calendar.YEAR); + t = -1; + + // test for expressions that never generate a valid fire date, + // but keep looping... + if (year > MAX_YEAR) { + return null; + } + + // get month................................................... + st = months.tailSet(mon); + if (st != null && !st.isEmpty()) { + t = mon; + mon = st.first(); + } else { + mon = months.first(); + year++; + } + if (mon != t) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' because calendar is 0-based for this field, and we are + // 1-based + cl.set(Calendar.YEAR, year); + continue; + } + cl.set(Calendar.MONTH, mon - 1); + // '- 1' because calendar is 0-based for this field, and we are + // 1-based + + year = cl.get(Calendar.YEAR); + t = -1; + + // get year................................................... + st = years.tailSet(year); + if (st != null && !st.isEmpty()) { + t = year; + year = st.first(); + } else { + return null; // ran out of years... + } + + if (year != t) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, 0); + // '- 1' because calendar is 0-based for this field, and we are + // 1-based + cl.set(Calendar.YEAR, year); + continue; + } + cl.set(Calendar.YEAR, year); + + gotOne = true; + } // while( !done ) + + return cl.getTime(); + } + + /** + * Advance the calendar to the particular hour paying particular attention + * to daylight saving problems. + * + * @param cal the calendar to operate on + * @param hour the hour to set + */ + protected void setCalendarHour(Calendar cal, int hour) { + cal.set(java.util.Calendar.HOUR_OF_DAY, hour); + if (cal.get(java.util.Calendar.HOUR_OF_DAY) != hour && hour != 24) { + cal.set(java.util.Calendar.HOUR_OF_DAY, hour + 1); + } + } + + /** + * Returns the time before the given time + * that the CronExpression matches. + * + * @param endTime a time for which the previous + * matching time is returned + * @return the previous matching time before the given end time, + * or null if there are no previous matching times + */ + public Date getTimeBefore(Date endTime) { + // the current implementation is not a direct calculation, but rather + // uses getTimeAfter with a binary search to find the previous match time + long end = endTime.getTime(); + long min = 0; // the epoch date is the minimum supported by this class + long max = end; + // check if it's satisfiable at all + Date date = new Date(min); + Date after = getTimeAfter(date); + if (after == null || after.getTime() >= end) + return null; // there are no after-times before end + // from this point forward min's time-after is always less than end, + // and max's time-after is always equal to or greater than end + // so we just need to shrink the interval until they meet. + // optimization - perform inverse binary search to find a tighter lower bound + long interval = 60 * 60 * 1000; // start with a reasonable interval + while (interval < max) { + date.setTime(max - interval); + after = getTimeAfter(date); + if (after != null && after.getTime() < max) { + min = date.getTime(); // found a closer min + break; + } + interval *= 2; + } + // perform a regular binary search to find the earliest moment + // whose time-after is equal to or greater than the end time - + // this moment is the previous match time itself + while (max - min > 1000) { // we can stop at 1 second resolution + long mid = (min + max) >>> 1; + date.setTime(mid); + after = getTimeAfter(date); + if (after != null && after.getTime() < end) + min = mid; + else + max = mid; + } + date.setTime(max - max % 1000); // round to second + return date; + } + + /** + * NOT YET IMPLEMENTED: Returns the final time that the + * CronExpression will match. + */ + public Date getFinalFireTime() { + // FUTURE_TODO: implement QUARTZ-423 + return null; + } + + protected boolean isLeapYear(int year) { + return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)); + } + + protected int getLastDayOfMonth(int monthNum, int year) { + + switch (monthNum) { + case 1: + return 31; + case 2: + return (isLeapYear(year)) ? 29 : 28; + case 3: + return 31; + case 4: + return 30; + case 5: + return 31; + case 6: + return 30; + case 7: + return 31; + case 8: + return 31; + case 9: + return 30; + case 10: + return 31; + case 11: + return 30; + case 12: + return 31; + default: + throw new IllegalArgumentException("Illegal month number: " + + monthNum); + } + } + + + private Optional findSmallestDay(int day, int mon, int year, TreeSet set) { + if (set.isEmpty()) { + return Optional.empty(); + } + + final int lastDay = getLastDayOfMonth(mon, year); + // For "L", "L-1", etc. + final int smallestDay = Optional.ofNullable(set.ceiling(LAST_DAY_OFFSET_END - (lastDay - day))) + .map(d -> d - LAST_DAY_OFFSET_START + 1) + .orElse(Integer.MAX_VALUE); + + // For "1", "2", etc. + SortedSet st = set.subSet(day, LAST_DAY_OFFSET_START); + // make sure we don't over-run a short month, such as february + if (!st.isEmpty() && st.first() < smallestDay && st.first() <= lastDay) { + return Optional.of(st.first()); + } + + if (smallestDay == Integer.MAX_VALUE) { + return Optional.empty(); + } else { + return Optional.of(smallestDay + lastDay - LAST_DAY_OFFSET_START + 1); + } + } + + private void readObject(java.io.ObjectInputStream stream) + throws java.io.IOException, ClassNotFoundException { + + stream.defaultReadObject(); + try { + buildExpression(cronExpression); + } catch (Exception ignore) { + } // never happens + } + + @Override + @Deprecated + public Object clone() { + return new CronExpression(this); + } +} + +class ValueSet { + public int value; + + public int pos; +} \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/exception/XxlJobException.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/exception/XxlJobException.java new file mode 100644 index 000000000..01f9c7077 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/exception/XxlJobException.java @@ -0,0 +1,15 @@ +package com.xxl.job.admin.scheduler.exception; + +/** + * @author xuxueli 2019-05-04 23:19:29 + */ +public class XxlJobException extends RuntimeException { + + public XxlJobException() { + } + + public XxlJobException(String message) { + super(message); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/MisfireHandler.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/MisfireHandler.java new file mode 100644 index 000000000..e3969364d --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/MisfireHandler.java @@ -0,0 +1,17 @@ +package com.xxl.job.admin.scheduler.misfire; + +/** + * Misfire Handler + * + * @author xuxueli 2020-10-29 + */ +public abstract class MisfireHandler { + + /** + * misfire handle + * + * @param jobId jobId + */ + public abstract void handle(final int jobId); + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/MisfireStrategyEnum.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/MisfireStrategyEnum.java new file mode 100644 index 000000000..7814912c3 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/MisfireStrategyEnum.java @@ -0,0 +1,54 @@ +package com.xxl.job.admin.scheduler.misfire; + +import com.xxl.job.admin.scheduler.misfire.strategy.MisfireDoNothing; +import com.xxl.job.admin.scheduler.misfire.strategy.MisfireFireOnceNow; +import com.xxl.job.admin.util.I18nUtil; + +/** + * @author xuxueli 2020-10-29 21:11:23 + */ +public enum MisfireStrategyEnum { + + /** + * do nothing + */ + DO_NOTHING(I18nUtil.getString("misfire_strategy_do_nothing"), new MisfireDoNothing()), + + /** + * fire once now + */ + FIRE_ONCE_NOW(I18nUtil.getString("misfire_strategy_fire_once_now"), new MisfireFireOnceNow()); + + private final String title; + private final MisfireHandler misfireHandler; + + MisfireStrategyEnum(String title, MisfireHandler misfireHandler) { + this.title = title; + this.misfireHandler = misfireHandler; + } + + public String getTitle() { + return title; + } + + public MisfireHandler getMisfireHandler() { + return misfireHandler; + } + + /** + * match misfire strategy + * + * @param name name of misfire strategy + * @param defaultItem default misfire strategy + * @return misfire strategy + */ + public static MisfireStrategyEnum match(String name, MisfireStrategyEnum defaultItem) { + for (MisfireStrategyEnum item : MisfireStrategyEnum.values()) { + if (item.name().equals(name)) { + return item; + } + } + return defaultItem; + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/strategy/MisfireDoNothing.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/strategy/MisfireDoNothing.java new file mode 100644 index 000000000..c423dd5c5 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/strategy/MisfireDoNothing.java @@ -0,0 +1,15 @@ +package com.xxl.job.admin.scheduler.misfire.strategy; + +import com.xxl.job.admin.scheduler.misfire.MisfireHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MisfireDoNothing extends MisfireHandler { + private static final Logger logger = LoggerFactory.getLogger(MisfireDoNothing.class); + + @Override + public void handle(int jobId) { + logger.warn(">>>>>>>>>>> xxl-job, schedule MisfireDoNothing: jobId = " + jobId); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/strategy/MisfireFireOnceNow.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/strategy/MisfireFireOnceNow.java new file mode 100644 index 000000000..7ec5d8505 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/strategy/MisfireFireOnceNow.java @@ -0,0 +1,19 @@ +package com.xxl.job.admin.scheduler.misfire.strategy; + +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.admin.scheduler.misfire.MisfireHandler; +import com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MisfireFireOnceNow extends MisfireHandler { + protected static Logger logger = LoggerFactory.getLogger(MisfireFireOnceNow.class); + + @Override + public void handle(int jobId) { + // FIRE_ONCE_NOW 》 trigger + XxlJobAdminBootstrap.getInstance().getJobTriggerPoolHelper().trigger(jobId, TriggerTypeEnum.MISFIRE, -1, null, null, null); + logger.warn(">>>>>>>>>>> xxl-job, schedule MisfireFireOnceNow: jobId = " + jobId); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/openapi/OpenApiController.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/openapi/OpenApiController.java new file mode 100644 index 000000000..96759c2ba --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/openapi/OpenApiController.java @@ -0,0 +1,80 @@ +package com.xxl.job.admin.scheduler.openapi; + +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.core.constant.Const; +import com.xxl.job.core.openapi.AdminBiz; +import com.xxl.job.core.openapi.model.CallbackRequest; +import com.xxl.job.core.openapi.model.RegistryRequest; +import com.xxl.sso.core.annotation.XxlSso; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.json.GsonTool; +import com.xxl.tool.response.Response; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * Created by xuxueli on 17/5/10. + */ +@Controller +public class OpenApiController { + + @Resource + private AdminBiz adminBiz; + + /** + * api + */ + @RequestMapping("/api/{uri}") + @ResponseBody + @XxlSso(login = false) + public Object api(HttpServletRequest request, + @PathVariable("uri") String uri, + @RequestHeader(value = Const.XXL_JOB_ACCESS_TOKEN, required = false) String accesstoken, + @RequestBody(required = false) String requestBody) { + + // valid + if (!"POST".equalsIgnoreCase(request.getMethod())) { + return Response.ofFail("invalid request, HttpMethod not support."); + } + if (StringTool.isBlank(uri)) { + return Response.ofFail("invalid request, uri-mapping empty."); + } + if (StringTool.isBlank(requestBody)) { + return Response.ofFail("invalid request, requestBody empty."); + } + + // valid token + if (StringTool.isNotBlank(XxlJobAdminBootstrap.getInstance().getAccessToken()) + && !XxlJobAdminBootstrap.getInstance().getAccessToken().equals(accesstoken)) { + return Response.ofFail("The access token is wrong."); + } + + // dispatch request + try { + switch (uri) { + case "callback": { + List callbackParamList = GsonTool.fromJson(requestBody, List.class, CallbackRequest.class); + return adminBiz.callback(callbackParamList); + } + case "registry": { + RegistryRequest registryParam = GsonTool.fromJson(requestBody, RegistryRequest.class); + return adminBiz.registry(registryParam); + } + case "registryRemove": { + RegistryRequest registryParam = GsonTool.fromJson(requestBody, RegistryRequest.class); + return adminBiz.registryRemove(registryParam); + } + default: + return Response.ofFail("invalid request, uri-mapping(" + uri + ") not found."); + } + } catch (Exception e) { + return Response.ofFail("openapi invoke error: " + e.getMessage()); + } + + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/ExecutorRouteStrategyEnum.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/ExecutorRouteStrategyEnum.java new file mode 100644 index 000000000..24623ffac --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/ExecutorRouteStrategyEnum.java @@ -0,0 +1,52 @@ +package com.xxl.job.admin.scheduler.route; + +import com.xxl.job.admin.scheduler.route.strategy.*; +import com.xxl.job.admin.util.I18nUtil; + +/** + * Created by xuxueli on 17/3/10. + */ +public enum ExecutorRouteStrategyEnum { + + FIRST(I18nUtil.getString("jobconf_route_first"), new ExecutorRouteFirst()), + LAST(I18nUtil.getString("jobconf_route_last"), new ExecutorRouteLast()), + ROUND(I18nUtil.getString("jobconf_route_round"), new ExecutorRouteRound()), + RANDOM(I18nUtil.getString("jobconf_route_random"), new ExecutorRouteRandom()), + CONSISTENT_HASH(I18nUtil.getString("jobconf_route_consistenthash"), new ExecutorRouteConsistentHash()), + LEAST_FREQUENTLY_USED(I18nUtil.getString("jobconf_route_lfu"), new ExecutorRouteLFU()), + LEAST_RECENTLY_USED(I18nUtil.getString("jobconf_route_lru"), new ExecutorRouteLRU()), + FAILOVER(I18nUtil.getString("jobconf_route_failover"), new ExecutorRouteFailover()), + BUSYOVER(I18nUtil.getString("jobconf_route_busyover"), new ExecutorRouteBusyover()), + SHARDING_BROADCAST(I18nUtil.getString("jobconf_route_shard"), null); + + ExecutorRouteStrategyEnum(String title, ExecutorRouter router) { + this.title = title; + this.router = router; + } + + private String title; + private ExecutorRouter router; + + public String getTitle() { + return title; + } + + public ExecutorRouter getRouter() { + return router; + } + + /** + * match router + */ + public static ExecutorRouteStrategyEnum match(String name, ExecutorRouteStrategyEnum defaultItem) { + if (name != null) { + for (ExecutorRouteStrategyEnum item : ExecutorRouteStrategyEnum.values()) { + if (item.name().equals(name)) { + return item; + } + } + } + return defaultItem; + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/ExecutorRouter.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/ExecutorRouter.java new file mode 100644 index 000000000..0ce857ac5 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/ExecutorRouter.java @@ -0,0 +1,24 @@ +package com.xxl.job.admin.scheduler.route; + +import com.xxl.job.core.openapi.model.TriggerRequest; +import com.xxl.tool.response.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * Created by xuxueli on 17/3/10. + */ +public abstract class ExecutorRouter { + protected static Logger logger = LoggerFactory.getLogger(ExecutorRouter.class); + + /** + * route address + * + * @param addressList executor address list + * @return ReturnT.content=address + */ + public abstract Response route(TriggerRequest triggerParam, List addressList); + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteBusyover.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteBusyover.java new file mode 100644 index 000000000..c3fd0eed7 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteBusyover.java @@ -0,0 +1,48 @@ +package com.xxl.job.admin.scheduler.route.strategy; + +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.admin.scheduler.route.ExecutorRouter; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.job.core.openapi.ExecutorBiz; +import com.xxl.job.core.openapi.model.IdleBeatRequest; +import com.xxl.job.core.openapi.model.TriggerRequest; +import com.xxl.tool.response.Response; + +import java.util.List; + +/** + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteBusyover extends ExecutorRouter { + + @Override + public Response route(TriggerRequest triggerParam, List addressList) { + StringBuffer idleBeatResultSB = new StringBuffer(); + for (String address : addressList) { + // beat + Response idleBeatResult = null; + try { + ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(address); + idleBeatResult = executorBiz.idleBeat(new IdleBeatRequest(triggerParam.getJobId())); + } catch (Exception e) { + logger.error(e.getMessage(), e); + idleBeatResult = Response.ofFail("" + e); + } + idleBeatResultSB.append((idleBeatResultSB.length() > 0) ? "

" : "") + .append(I18nUtil.getString("jobconf_idleBeat") + ":") + .append("
address:").append(address) + .append("
code:").append(idleBeatResult.getCode()) + .append("
msg:").append(idleBeatResult.getMsg()); + + // beat success + if (idleBeatResult.isSuccess()) { + idleBeatResult.setMsg(idleBeatResultSB.toString()); + idleBeatResult.setData(address); + return idleBeatResult; + } + } + + return Response.ofFail(idleBeatResultSB.toString()); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteConsistentHash.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteConsistentHash.java new file mode 100644 index 000000000..c3569de9f --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteConsistentHash.java @@ -0,0 +1,99 @@ +package com.xxl.job.admin.scheduler.route.strategy; + +import com.xxl.job.admin.scheduler.route.ExecutorRouter; +import com.xxl.job.core.openapi.model.TriggerRequest; +import com.xxl.tool.response.Response; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * 分组下机器地址相同,不同JOB均匀散列在不同机器上,保证分组下机器分配JOB平均;且每个JOB固定调度其中一台机器; + * a、virtual node:解决不均衡问题 + * b、hash method replace hashCode:String的hashCode可能重复,需要进一步扩大hashCode的取值范围 + *

+ * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteConsistentHash extends ExecutorRouter { + + private static final int VIRTUAL_NODE_NUM = 100; + + /** + * get hash code on 2^32 ring (md5散列的方式计算hash值) + * + * @param key key + * @return hash code + */ + private static long hash(String key) { + + // md5 byte + MessageDigest md5; + try { + md5 = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("MD5 not supported", e); + } + md5.reset(); + byte[] keyBytes = null; + keyBytes = key.getBytes(StandardCharsets.UTF_8); + + md5.update(keyBytes); + byte[] digest = md5.digest(); + + // hash code, Truncate to 32-bits + long hashCode = ((long) (digest[3] & 0xFF) << 24) + | ((long) (digest[2] & 0xFF) << 16) + | ((long) (digest[1] & 0xFF) << 8) + | (digest[0] & 0xFF); + + return hashCode & 0xffffffffL; + } + + /** + * get address by jobId + * + * @param jobId job id + * @param addressList address list + * @return address + */ + public String hashJob(int jobId, List addressList) { + + // 1、hash ring + // ------A1------A2-------A3------ + // -----------J1------------------ + TreeMap addressRing = new TreeMap<>(); + for (String address : addressList) { + for (int i = 0; i < VIRTUAL_NODE_NUM; i++) { + long addressHash = hash("SHARD-" + address + "-NODE-" + i); + addressRing.put(addressHash, address); + } + } + + // 2、generate job-hash + long jobHash = hash(String.valueOf(jobId)); + + // 3、route job-node + Map.Entry ceilingEntry = addressRing.ceilingEntry(jobHash); + if (ceilingEntry != null) { + return ceilingEntry.getValue(); + } + /*SortedMap lastRing = addressRing.tailMap(jobHash); + if (!lastRing.isEmpty()) { + return lastRing.get(lastRing.firstKey()); + }*/ + + // 4、default first node + return addressRing.firstEntry().getValue(); + } + + @Override + public Response route(TriggerRequest triggerParam, List addressList) { + String address = hashJob(triggerParam.getJobId(), addressList); + return Response.ofSuccess(address); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteFailover.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteFailover.java new file mode 100644 index 000000000..406b25b5c --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteFailover.java @@ -0,0 +1,48 @@ +package com.xxl.job.admin.scheduler.route.strategy; + +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.admin.scheduler.route.ExecutorRouter; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.job.core.openapi.ExecutorBiz; +import com.xxl.job.core.openapi.model.TriggerRequest; +import com.xxl.tool.response.Response; + +import java.util.List; + +/** + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteFailover extends ExecutorRouter { + + @Override + public Response route(TriggerRequest triggerParam, List addressList) { + + StringBuffer beatResultSB = new StringBuffer(); + for (String address : addressList) { + // beat + Response beatResult = null; + try { + ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(address); + beatResult = executorBiz.beat(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + beatResult = Response.ofFail(e.getMessage()); + } + beatResultSB.append((beatResultSB.length() > 0) ? "

" : "") + .append(I18nUtil.getString("jobconf_beat") + ":") + .append("
address:").append(address) + .append("
code:").append(beatResult.getCode()) + .append("
msg:").append(beatResult.getMsg()); + + // beat success + if (beatResult.isSuccess()) { + + beatResult.setMsg(beatResultSB.toString()); + beatResult.setData(address); + return beatResult; + } + } + return Response.ofFail(beatResultSB.toString()); + + } +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteFirst.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteFirst.java new file mode 100644 index 000000000..6c0f3fffd --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteFirst.java @@ -0,0 +1,19 @@ +package com.xxl.job.admin.scheduler.route.strategy; + +import com.xxl.job.admin.scheduler.route.ExecutorRouter; +import com.xxl.job.core.openapi.model.TriggerRequest; +import com.xxl.tool.response.Response; + +import java.util.List; + +/** + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteFirst extends ExecutorRouter { + + @Override + public Response route(TriggerRequest triggerParam, List addressList) { + return Response.ofSuccess(addressList.get(0)); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteLFU.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteLFU.java new file mode 100644 index 000000000..9df0fb3f6 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteLFU.java @@ -0,0 +1,78 @@ +package com.xxl.job.admin.scheduler.route.strategy; + +import com.xxl.job.admin.scheduler.route.ExecutorRouter; +import com.xxl.job.core.openapi.model.TriggerRequest; +import com.xxl.tool.response.Response; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * 单个JOB对应的每个执行器,使用频率最低的优先被选举 + * a(*)、LFU(Least Frequently Used):最不经常使用,频率/次数 + * b、LRU(Least Recently Used):最近最久未使用,时间 + *

+ * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteLFU extends ExecutorRouter { + + /** + * job lfu map + *

+ * > + */ + private static ConcurrentMap> jobLfuMap = new ConcurrentHashMap>(); + private static long CACHE_VALID_TIME = 0; + + public String route(int jobId, List addressList) { + + // cache clear + if (System.currentTimeMillis() > CACHE_VALID_TIME) { + jobLfuMap.clear(); + CACHE_VALID_TIME = System.currentTimeMillis() + 1000 * 60 * 60 * 24; + } + + // lfu item init + HashMap lfuItemMap = jobLfuMap.get(jobId); // Key排序可以用TreeMap+构造入参Compare;Value排序暂时只能通过ArrayList; + if (lfuItemMap == null) { + lfuItemMap = new HashMap<>(); + jobLfuMap.putIfAbsent(jobId, lfuItemMap); // 避免重复覆盖 + } + + // put new + for (String address : addressList) { + if (!lfuItemMap.containsKey(address) || lfuItemMap.get(address) > 1000000) { + lfuItemMap.put(address, new Random().nextInt(addressList.size())); // 初始化时主动Random一次,缓解首次压力 + } + } + // remove old + List delKeys = new ArrayList<>(); + for (String existKey : lfuItemMap.keySet()) { + if (!addressList.contains(existKey)) { + delKeys.add(existKey); + } + } + if (!delKeys.isEmpty()) { + for (String delKey : delKeys) { + lfuItemMap.remove(delKey); + } + } + + // load least userd count address + List> lfuItemList = new ArrayList<>(lfuItemMap.entrySet()); + lfuItemList.sort(Map.Entry.comparingByValue()); // 默认升序, 获取 Value 最小值 + + Map.Entry addressItem = lfuItemList.get(0); + addressItem.setValue(addressItem.getValue() + 1); + + return addressItem.getKey(); + } + + @Override + public Response route(TriggerRequest triggerParam, List addressList) { + String address = route(triggerParam.getJobId(), addressList); + return Response.ofSuccess(address); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteLRU.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteLRU.java new file mode 100644 index 000000000..49f3093ae --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteLRU.java @@ -0,0 +1,80 @@ +package com.xxl.job.admin.scheduler.route.strategy; + +import com.xxl.job.admin.scheduler.route.ExecutorRouter; +import com.xxl.job.core.openapi.model.TriggerRequest; +import com.xxl.tool.response.Response; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * 单个JOB对应的每个执行器,最久为使用的优先被选举 + * a、LFU(Least Frequently Used):最不经常使用,频率/次数 + * b(*)、LRU(Least Recently Used):最近最久未使用,时间 + *

+ * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteLRU extends ExecutorRouter { + + /** + * job lru map + *

+ * > + */ + private static ConcurrentMap> jobLRUMap = new ConcurrentHashMap>(); + private static long CACHE_VALID_TIME = 0; + + public String route(int jobId, List addressList) { + + // cache clear + if (System.currentTimeMillis() > CACHE_VALID_TIME) { + jobLRUMap.clear(); + CACHE_VALID_TIME = System.currentTimeMillis() + 1000 * 60 * 60 * 24; + } + + // init lru + LinkedHashMap lruItem = jobLRUMap.get(jobId); + if (lruItem == null) { + /** + * LinkedHashMap + * a、accessOrder:true=访问顺序排序(get/put时排序);false=插入顺序排期; + * b、removeEldestEntry:新增元素时将会调用,返回true时会删除最老元素;可封装LinkedHashMap并重写该方法,比如定义最大容量,超出是返回true即可实现固定长度的LRU算法; + */ + lruItem = new LinkedHashMap<>(16, 0.75f, true); + jobLRUMap.putIfAbsent(jobId, lruItem); + } + + // put new + for (String address : addressList) { + if (!lruItem.containsKey(address)) { + lruItem.put(address, address); + } + } + // remove old + List delKeys = new ArrayList<>(); + for (String existKey : lruItem.keySet()) { + if (!addressList.contains(existKey)) { + delKeys.add(existKey); + } + } + if (!delKeys.isEmpty()) { + for (String delKey : delKeys) { + lruItem.remove(delKey); + } + } + + // load first elment, eldest entry + String eldestKey = lruItem.entrySet().iterator().next().getKey(); + return lruItem.get(eldestKey); + } + + @Override + public Response route(TriggerRequest triggerParam, List addressList) { + String address = route(triggerParam.getJobId(), addressList); + return Response.ofSuccess(address); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteLast.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteLast.java new file mode 100644 index 000000000..3e37a6dc9 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteLast.java @@ -0,0 +1,19 @@ +package com.xxl.job.admin.scheduler.route.strategy; + +import com.xxl.job.admin.scheduler.route.ExecutorRouter; +import com.xxl.job.core.openapi.model.TriggerRequest; +import com.xxl.tool.response.Response; + +import java.util.List; + +/** + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteLast extends ExecutorRouter { + + @Override + public Response route(TriggerRequest triggerParam, List addressList) { + return Response.ofSuccess(addressList.get(addressList.size() - 1)); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteRandom.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteRandom.java new file mode 100644 index 000000000..ae760d297 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteRandom.java @@ -0,0 +1,23 @@ +package com.xxl.job.admin.scheduler.route.strategy; + +import com.xxl.job.admin.scheduler.route.ExecutorRouter; +import com.xxl.job.core.openapi.model.TriggerRequest; +import com.xxl.tool.response.Response; + +import java.util.List; +import java.util.Random; + +/** + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteRandom extends ExecutorRouter { + + private static Random localRandom = new Random(); + + @Override + public Response route(TriggerRequest triggerParam, List addressList) { + String address = addressList.get(localRandom.nextInt(addressList.size())); + return Response.ofSuccess(address); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteRound.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteRound.java new file mode 100644 index 000000000..e3d0178d3 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteRound.java @@ -0,0 +1,46 @@ +package com.xxl.job.admin.scheduler.route.strategy; + +import com.xxl.job.admin.scheduler.route.ExecutorRouter; +import com.xxl.job.core.openapi.model.TriggerRequest; +import com.xxl.tool.response.Response; + +import java.util.List; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteRound extends ExecutorRouter { + + private static ConcurrentMap routeCountEachJob = new ConcurrentHashMap<>(); + private static long CACHE_VALID_TIME = 0; + + private static int count(int jobId) { + // cache clear + if (System.currentTimeMillis() > CACHE_VALID_TIME) { + routeCountEachJob.clear(); + CACHE_VALID_TIME = System.currentTimeMillis() + 1000 * 60 * 60 * 24; + } + + AtomicInteger count = routeCountEachJob.get(jobId); + if (count == null || count.get() > 1000000) { + // 初始化时主动Random一次,缓解首次压力 + count = new AtomicInteger(new Random().nextInt(100)); + } else { + // count++ + count.addAndGet(1); + } + routeCountEachJob.put(jobId, count); + return count.get(); + } + + @Override + public Response route(TriggerRequest triggerParam, List addressList) { + String address = addressList.get(count(triggerParam.getJobId()) % addressList.size()); + return Response.ofSuccess(address); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobCompleteHelper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobCompleteHelper.java new file mode 100644 index 000000000..694a37bcb --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobCompleteHelper.java @@ -0,0 +1,185 @@ +package com.xxl.job.admin.scheduler.thread; + +import com.xxl.job.admin.model.XxlJobLog; +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.job.core.context.XxlJobContext; +import com.xxl.job.core.openapi.model.CallbackRequest; +import com.xxl.tool.core.DateTool; +import com.xxl.tool.response.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.List; +import java.util.concurrent.*; + +/** + * job complate, for callback and result-lost + * + * @author xuxueli 2015-9-1 18:05:56 + */ +public class JobCompleteHelper { + private static final Logger logger = LoggerFactory.getLogger(JobCompleteHelper.class); + + // ---------------------- monitor ---------------------- + + private ThreadPoolExecutor callbackThreadPool = null; + private Thread monitorThread; + private volatile boolean toStop = false; + + /** + * start + */ + public void start() { + + // for callback + callbackThreadPool = new ThreadPoolExecutor( + 2, + 20, + 30L, + TimeUnit.SECONDS, + new LinkedBlockingQueue(3000), + new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "xxl-job, admin JobLosedMonitorHelper-callbackThreadPool-" + r.hashCode()); + } + }, + new RejectedExecutionHandler() { + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + r.run(); + logger.warn(">>>>>>>>>>> xxl-job, callback too fast, match threadpool rejected handler(run now)."); + } + }); + + + // for monitor + monitorThread = new Thread(new Runnable() { + + @Override + public void run() { + + // wait for JobTriggerPoolHelper-init + try { + TimeUnit.MILLISECONDS.sleep(50); + } catch (Throwable e) { + if (!toStop) { + logger.error(e.getMessage(), e); + } + } + + // monitor + while (!toStop) { + try { + // 任务结果丢失处理:调度记录停留在 "运行中" 状态超过10min,且对应执行器心跳注册失败不在线,则将本地调度主动标记失败; + Date losedTime = DateTool.addMinutes(new Date(), -10); + List losedJobIds = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().findLostJobIds(losedTime); + + if (losedJobIds != null && losedJobIds.size() > 0) { + for (Long logId : losedJobIds) { + + XxlJobLog jobLog = new XxlJobLog(); + jobLog.setId(logId); + + jobLog.setHandleTime(new Date()); + jobLog.setHandleCode(XxlJobContext.HANDLE_CODE_FAIL); + jobLog.setHandleMsg(I18nUtil.getString("joblog_lost_fail")); + + XxlJobAdminBootstrap.getInstance().getJobCompleter().complete(jobLog); + } + + } + } catch (Throwable e) { + if (!toStop) { + logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e); + } + } + + try { + TimeUnit.SECONDS.sleep(60); + } catch (Throwable e) { + if (!toStop) { + logger.error(e.getMessage(), e); + } + } + + } + + logger.info(">>>>>>>>>>> xxl-job, JobLosedMonitorHelper stop"); + + } + }); + monitorThread.setDaemon(true); + monitorThread.setName("xxl-job, admin JobLosedMonitorHelper"); + monitorThread.start(); + } + + /** + * stop + */ + public void stop() { + toStop = true; + + // stop registryOrRemoveThreadPool + callbackThreadPool.shutdownNow(); + + // stop monitorThread (interrupt and wait) + monitorThread.interrupt(); + try { + monitorThread.join(); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + } + + + // ---------------------- helper ---------------------- + + public Response callback(List callbackParamList) { + + callbackThreadPool.execute(new Runnable() { + @Override + public void run() { + for (CallbackRequest callbackRequest : callbackParamList) { + Response callbackResult = doCallback(callbackRequest); + logger.debug(">>>>>>>>> JobApiController.callback {}, callbackRequest={}, callbackResult={}", + (callbackResult.isSuccess() ? "success" : "fail"), callbackRequest, callbackResult); + } + } + }); + + return Response.ofSuccess(); + } + + private Response doCallback(CallbackRequest handleCallbackParam) { + // valid log item + XxlJobLog log = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().load(handleCallbackParam.getLogId()); + if (log == null) { + return Response.ofFail("log item not found."); + } + if (log.getHandleCode() > 0) { + return Response.ofFail("log repeate callback."); // avoid repeat callback, trigger child job etc + } + + // handle msg + StringBuffer handleMsg = new StringBuffer(); + if (log.getHandleMsg() != null) { + handleMsg.append(log.getHandleMsg()).append("
"); + } + if (handleCallbackParam.getHandleMsg() != null) { + handleMsg.append(handleCallbackParam.getHandleMsg()); + } + + // success, save log + log.setHandleTime(new Date()); + log.setHandleCode(handleCallbackParam.getHandleCode()); + log.setHandleMsg(handleMsg.toString()); + XxlJobAdminBootstrap.getInstance().getJobCompleter().complete(log); + + return Response.ofSuccess(); + } + + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobFailAlarmMonitorHelper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobFailAlarmMonitorHelper.java new file mode 100644 index 000000000..f3315c96c --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobFailAlarmMonitorHelper.java @@ -0,0 +1,113 @@ +package com.xxl.job.admin.scheduler.thread; + +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.model.XxlJobLog; +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum; +import com.xxl.job.admin.util.I18nUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * job fail-monitor helper + * + * @author xuxueli 2015-9-1 18:05:56 + */ +public class JobFailAlarmMonitorHelper { + private static Logger logger = LoggerFactory.getLogger(JobFailAlarmMonitorHelper.class); + + + // ---------------------- monitor ---------------------- + + private Thread monitorThread; + private volatile boolean toStop = false; + + /** + * start + */ + public void start() { + monitorThread = new Thread(new Runnable() { + + @Override + public void run() { + + // monitor + while (!toStop) { + try { + + List failLogIds = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().findFailJobLogIds(1000); + if (failLogIds != null && !failLogIds.isEmpty()) { + for (long failLogId : failLogIds) { + + // lock log + int lockRet = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().updateAlarmStatus(failLogId, 0, -1); + if (lockRet < 1) { + continue; + } + XxlJobLog log = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().load(failLogId); + XxlJobInfo info = XxlJobAdminBootstrap.getInstance().getXxlJobInfoMapper().loadById(log.getJobId()); + + // 1、fail retry monitor + if (log.getExecutorFailRetryCount() > 0) { + XxlJobAdminBootstrap.getInstance().getJobTriggerPoolHelper().trigger(log.getJobId(), TriggerTypeEnum.RETRY, (log.getExecutorFailRetryCount() - 1), log.getExecutorShardingParam(), log.getExecutorParam(), null); + String retryMsg = "

>>>>>>>>>>>" + I18nUtil.getString("jobconf_trigger_type_retry") + "<<<<<<<<<<<
"; + log.setTriggerMsg(log.getTriggerMsg() + retryMsg); + XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().updateTriggerInfo(log); + } + + // 2、fail alarm monitor + int newAlarmStatus = 0; // 告警状态:0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败 + if (info != null) { + boolean alarmResult = XxlJobAdminBootstrap.getInstance().getJobAlarmer().alarm(info, log); + newAlarmStatus = alarmResult ? 2 : 3; + } else { + newAlarmStatus = 1; + } + + XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().updateAlarmStatus(failLogId, -1, newAlarmStatus); + } + } + + } catch (Throwable e) { + if (!toStop) { + logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e.getMessage(), e); + } + } + + try { + TimeUnit.SECONDS.sleep(10); + } catch (Throwable e) { + if (!toStop) { + logger.error(e.getMessage(), e); + } + } + + } + + logger.info(">>>>>>>>>>> xxl-job, job fail monitor thread stop"); + + } + }); + monitorThread.setDaemon(true); + monitorThread.setName("xxl-job, admin JobFailMonitorHelper"); + monitorThread.start(); + } + + /** + * stop + */ + public void stop() { + toStop = true; + // interrupt and wait + monitorThread.interrupt(); + try { + monitorThread.join(); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobLogReportHelper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobLogReportHelper.java new file mode 100644 index 000000000..2c67fceab --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobLogReportHelper.java @@ -0,0 +1,162 @@ +package com.xxl.job.admin.scheduler.thread; + +import com.xxl.job.admin.model.XxlJobLogReport; +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * job log report helper + * + * @author xuxueli 2019-11-22 + */ +public class JobLogReportHelper { + private static final Logger logger = LoggerFactory.getLogger(JobLogReportHelper.class); + + + private Thread logReportThread; + private volatile boolean toStop = false; + + /** + * start + */ + public void start() { + logReportThread = new Thread(new Runnable() { + + @Override + public void run() { + + // last clean log time + long lastCleanLogTime = 0; + + + while (!toStop) { + + // 1、log-report refresh: refresh log report in 3 days + try { + + for (int i = 0; i < 3; i++) { + + // today + Calendar itemDay = Calendar.getInstance(); + itemDay.add(Calendar.DAY_OF_MONTH, -i); + itemDay.set(Calendar.HOUR_OF_DAY, 0); + itemDay.set(Calendar.MINUTE, 0); + itemDay.set(Calendar.SECOND, 0); + itemDay.set(Calendar.MILLISECOND, 0); + + Date todayFrom = itemDay.getTime(); + + itemDay.set(Calendar.HOUR_OF_DAY, 23); + itemDay.set(Calendar.MINUTE, 59); + itemDay.set(Calendar.SECOND, 59); + itemDay.set(Calendar.MILLISECOND, 999); + + Date todayTo = itemDay.getTime(); + + // refresh log-report every minute + XxlJobLogReport xxlJobLogReport = new XxlJobLogReport(); + xxlJobLogReport.setTriggerDay(todayFrom); + xxlJobLogReport.setRunningCount(0); + xxlJobLogReport.setSucCount(0); + xxlJobLogReport.setFailCount(0); + xxlJobLogReport.setUpdateTime(new Date()); + + // fill count-data + Map triggerCountMap = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().findLogReport(todayFrom, todayTo); + if (triggerCountMap != null && !triggerCountMap.isEmpty()) { + int triggerDayCount = triggerCountMap.containsKey("triggerDayCount") ? Integer.parseInt(String.valueOf(triggerCountMap.get("triggerDayCount"))) : 0; + int triggerDayCountRunning = triggerCountMap.containsKey("triggerDayCountRunning") ? Integer.parseInt(String.valueOf(triggerCountMap.get("triggerDayCountRunning"))) : 0; + int triggerDayCountSuc = triggerCountMap.containsKey("triggerDayCountSuc") ? Integer.parseInt(String.valueOf(triggerCountMap.get("triggerDayCountSuc"))) : 0; + int triggerDayCountFail = triggerDayCount - triggerDayCountRunning - triggerDayCountSuc; + + xxlJobLogReport.setRunningCount(triggerDayCountRunning); + xxlJobLogReport.setSucCount(triggerDayCountSuc); + xxlJobLogReport.setFailCount(triggerDayCountFail); + } + + // do refresh: + XxlJobAdminBootstrap.getInstance().getXxlJobLogReportMapper().saveOrUpdate(xxlJobLogReport); // 0-fail; 1-save suc; 2-update suc; + /*if (ret < 1) { + XxlJobAdminBootstrap.getInstance().getXxlJobLogReportMapper().save(xxlJobLogReport); + }*/ + } + + } catch (Throwable e) { + if (!toStop) { + logger.error(">>>>>>>>>>> xxl-job, JobLogReportHelper(log-report refresh) error:{}", e.getMessage(), e); + } + } + + // 2、log-clean: switch open & once each day + try { + if (XxlJobAdminBootstrap.getInstance().getLogretentiondays() > 0 + && System.currentTimeMillis() - lastCleanLogTime > 24 * 60 * 60 * 1000) { + + // expire-time + Calendar expiredDay = Calendar.getInstance(); + expiredDay.add(Calendar.DAY_OF_MONTH, -1 * XxlJobAdminBootstrap.getInstance().getLogretentiondays()); + expiredDay.set(Calendar.HOUR_OF_DAY, 0); + expiredDay.set(Calendar.MINUTE, 0); + expiredDay.set(Calendar.SECOND, 0); + expiredDay.set(Calendar.MILLISECOND, 0); + Date clearBeforeTime = expiredDay.getTime(); + + // clean expired log + List logIds = null; + do { + logIds = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().findClearLogIds(0, 0, clearBeforeTime, 0, 1000); + if (logIds != null && !logIds.isEmpty()) { + XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().clearLog(logIds); + } + } while (logIds != null && !logIds.isEmpty()); + + // update clean time + lastCleanLogTime = System.currentTimeMillis(); + } + } catch (Throwable e) { + if (!toStop) { + logger.error(">>>>>>>>>>> xxl-job, JobLogReportHelper(log-clean) error:{}", e.getMessage(), e); + } + } + + try { + TimeUnit.MINUTES.sleep(1); + } catch (Throwable e) { + if (!toStop) { + logger.error(e.getMessage(), e); + } + } + + } + + logger.info(">>>>>>>>>>> xxl-job, job log report thread stop"); + + } + }); + logReportThread.setDaemon(true); + logReportThread.setName("xxl-job, admin JobLogReportHelper"); + logReportThread.start(); + } + + /** + * stop + */ + public void stop() { + toStop = true; + // interrupt and wait + logReportThread.interrupt(); + try { + logReportThread.join(); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobRegistryHelper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobRegistryHelper.java new file mode 100644 index 000000000..d5657c515 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobRegistryHelper.java @@ -0,0 +1,222 @@ +package com.xxl.job.admin.scheduler.thread; + +import com.xxl.job.admin.model.XxlJobGroup; +import com.xxl.job.admin.model.XxlJobRegistry; +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.core.constant.Const; +import com.xxl.job.core.constant.RegistType; +import com.xxl.job.core.openapi.model.RegistryRequest; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.response.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.*; + +/** + * job registry instance helper + * + * @author xuxueli 2016-10-02 19:10:24 + */ +public class JobRegistryHelper { + private static Logger logger = LoggerFactory.getLogger(JobRegistryHelper.class); + + + private ThreadPoolExecutor registryOrRemoveThreadPool = null; + private Thread registryMonitorThread; + private volatile boolean toStop = false; + + + /** + * start + */ + public void start() { + + // for registry or remove + registryOrRemoveThreadPool = new ThreadPoolExecutor( + 2, + 10, + 30L, + TimeUnit.SECONDS, + new LinkedBlockingQueue(2000), + new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "xxl-job, admin JobRegistryMonitorHelper-registryOrRemoveThreadPool-" + r.hashCode()); + } + }, + new RejectedExecutionHandler() { + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + r.run(); + logger.warn(">>>>>>>>>>> xxl-job, registry or remove too fast, match threadpool rejected handler(run now)."); + } + }); + + // for monitor + registryMonitorThread = new Thread(new Runnable() { + @Override + public void run() { + while (!toStop) { + try { + // auto registry group + List groupList = XxlJobAdminBootstrap.getInstance().getXxlJobGroupMapper().findByAddressType(0); + if (groupList != null && !groupList.isEmpty()) { + + // remove dead address (admin/executor) + List ids = XxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().findDead(Const.DEAD_TIMEOUT, new Date()); + if (ids != null && !ids.isEmpty()) { + XxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().removeDead(ids); + } + + // fresh online address (admin/executor) + HashMap> appAddressMap = new HashMap>(); + List list = XxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().findAll(Const.DEAD_TIMEOUT, new Date()); + if (list != null) { + for (XxlJobRegistry item : list) { + if (RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) { + String appname = item.getRegistryKey(); + List registryList = appAddressMap.get(appname); + if (registryList == null) { + registryList = new ArrayList(); + } + + if (!registryList.contains(item.getRegistryValue())) { + registryList.add(item.getRegistryValue()); + } + appAddressMap.put(appname, registryList); + } + } + } + + // fresh group address + for (XxlJobGroup group : groupList) { + List registryList = appAddressMap.get(group.getAppname()); + String addressListStr = null; + if (registryList != null && !registryList.isEmpty()) { + Collections.sort(registryList); + StringBuilder addressListSB = new StringBuilder(); + for (String item : registryList) { + addressListSB.append(item).append(","); + } + addressListStr = addressListSB.toString(); + addressListStr = addressListStr.substring(0, addressListStr.length() - 1); + } + group.setAddressList(addressListStr); + group.setUpdateTime(new Date()); + + XxlJobAdminBootstrap.getInstance().getXxlJobGroupMapper().update(group); + } + } + } catch (Throwable e) { + if (!toStop) { + logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e); + } + } + try { + TimeUnit.SECONDS.sleep(Const.BEAT_TIMEOUT); + } catch (Throwable e) { + if (!toStop) { + logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e); + } + } + } + logger.info(">>>>>>>>>>> xxl-job, job registry monitor thread stop"); + } + }); + registryMonitorThread.setDaemon(true); + registryMonitorThread.setName("xxl-job, admin JobRegistryMonitorHelper-registryMonitorThread"); + registryMonitorThread.start(); + } + + + /** + * stop + */ + public void stop() { + toStop = true; + + // stop registryOrRemoveThreadPool + registryOrRemoveThreadPool.shutdownNow(); + + // stop monitor (interrupt and wait) + registryMonitorThread.interrupt(); + try { + registryMonitorThread.join(); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + } + + + // ---------------------- tool ---------------------- + + /** + * registry + */ + public Response registry(RegistryRequest registryParam) { + + // valid + if (StringTool.isBlank(registryParam.getRegistryGroup()) + || StringTool.isBlank(registryParam.getRegistryKey()) + || StringTool.isBlank(registryParam.getRegistryValue())) { + return Response.ofFail("Illegal Argument."); + } + + // async execute + registryOrRemoveThreadPool.execute(new Runnable() { + @Override + public void run() { + // 0-fail; 1-save suc; 2-update suc; + int ret = XxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().registrySaveOrUpdate(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date()); + if (ret == 1) { + // fresh (add) + freshGroupRegistryInfo(registryParam); + } + /*int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registryUpdate(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date()); + if (ret < 1) { + XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registrySave(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date()); + + // fresh + freshGroupRegistryInfo(registryParam); + }*/ + } + }); + + return Response.ofSuccess(); + } + + /** + * registry remove + */ + public Response registryRemove(RegistryRequest registryParam) { + + // valid + if (StringTool.isBlank(registryParam.getRegistryGroup()) + || StringTool.isBlank(registryParam.getRegistryKey()) + || StringTool.isBlank(registryParam.getRegistryValue())) { + return Response.ofFail("Illegal Argument."); + } + + // async execute + registryOrRemoveThreadPool.execute(new Runnable() { + @Override + public void run() { + int ret = XxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().registryDelete(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue()); + if (ret > 0) { + // fresh (delete) + freshGroupRegistryInfo(registryParam); + } + } + }); + + return Response.ofSuccess(); + } + + private void freshGroupRegistryInfo(RegistryRequest registryParam) { + // Under consideration, prevent affecting core tables + } + + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobScheduleHelper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobScheduleHelper.java new file mode 100644 index 000000000..8c6d1b0ed --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobScheduleHelper.java @@ -0,0 +1,371 @@ +package com.xxl.job.admin.scheduler.thread; + +import com.xxl.job.admin.constant.TriggerStatus; +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.admin.scheduler.misfire.MisfireStrategyEnum; +import com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum; +import com.xxl.job.admin.scheduler.type.ScheduleTypeEnum; +import com.xxl.tool.core.CollectionTool; +import com.xxl.tool.core.MapTool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.DefaultTransactionDefinition; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +/** + * @author xuxueli 2019-05-21 + */ +public class JobScheduleHelper { + private static final Logger logger = LoggerFactory.getLogger(JobScheduleHelper.class); + + + /** + * pre-read time for scheduler, increase efficiency + */ + public static final long PRE_READ_MS = 5000; + /* + * elegant shutdown wait seconds + */ + private static final long ELEGANT_SHUTDOWN_WAITING_SECONDS = 10; + + private Thread scheduleThread; + private Thread ringThread; + private volatile boolean scheduleThreadToStop = false; + private volatile boolean ringThreadToStop = false; + private final Map> ringData = new ConcurrentHashMap<>(); + + /** + * start + */ + public void start() { + + // schedule thread + scheduleThread = new Thread(new Runnable() { + @Override + public void run() { + + // align time + try { + TimeUnit.MILLISECONDS.sleep(5000 - System.currentTimeMillis() % 1000); + } catch (Throwable e) { + if (!scheduleThreadToStop) { + logger.error(e.getMessage(), e); + } + } + logger.info(">>>>>>>>> init xxl-job admin scheduler success."); + + // pre-read count: treadpool-size * 10 (trigger-qps: 1000ms / 100ms each trigger cost) + int preReadCount = (XxlJobAdminBootstrap.getInstance().getTriggerPoolFastMax() + XxlJobAdminBootstrap.getInstance().getTriggerPoolSlowMax()) * 10; + + // do schedule + while (!scheduleThreadToStop) { + + // param + long start = System.currentTimeMillis(); + boolean preReadSuc = true; + + // transaction start + TransactionStatus transactionStatus = null; + try { + transactionStatus = XxlJobAdminBootstrap.getInstance().getTransactionManager().getTransaction(new DefaultTransactionDefinition()); + // 1、job lock + String lockedRecord = XxlJobAdminBootstrap.getInstance().getXxlJobLockMapper().scheduleLock(); + long nowTime = System.currentTimeMillis(); + + // scan and process job + List scheduleList = XxlJobAdminBootstrap.getInstance().getXxlJobInfoMapper().scheduleJobQuery(nowTime + PRE_READ_MS, preReadCount); + if (CollectionTool.isNotEmpty(scheduleList)) { + + // 2、push time-ring + for (XxlJobInfo jobInfo : scheduleList) { + + // time-ring jump + if (nowTime > jobInfo.getTriggerNextTime() + PRE_READ_MS) { + // 2.1、trigger-expire > 5s:pass && make next-trigger-time + + // 1、misfire handle + MisfireStrategyEnum misfireStrategyEnum = MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), MisfireStrategyEnum.DO_NOTHING); + misfireStrategyEnum.getMisfireHandler().handle(jobInfo.getId()); + + // 2、fresh next + refreshNextTriggerTime(jobInfo, new Date()); + + } else if (nowTime >= jobInfo.getTriggerNextTime()) { + // 2.2、trigger-expire < 5s:direct-trigger && make next-trigger-time + + // 1、trigger direct + XxlJobAdminBootstrap.getInstance().getJobTriggerPoolHelper().trigger(jobInfo.getId(), TriggerTypeEnum.CRON, -1, null, null, null); + logger.debug(">>>>>>>>>>> xxl-job, schedule expire, direct trigger : jobId = " + jobInfo.getId()); + + // 2、fresh next + refreshNextTriggerTime(jobInfo, new Date()); + + // next-trigger-time in 5s, pre-read again + if (jobInfo.getTriggerStatus() == TriggerStatus.RUNNING.getValue() && nowTime + PRE_READ_MS > jobInfo.getTriggerNextTime()) { + + // 1、make ring second + int ringSecond = (int) ((jobInfo.getTriggerNextTime() / 1000) % 60); + + // 2、push time ring (pre read) + pushTimeRing(ringSecond, jobInfo.getId()); + logger.debug(">>>>>>>>>>> xxl-job, schedule pre-read, push trigger : jobId = " + jobInfo.getId()); + + // 3、fresh next + refreshNextTriggerTime(jobInfo, new Date(jobInfo.getTriggerNextTime())); + + } + + } else { + // 2.3、trigger-pre-read:time-ring trigger && make next-trigger-time + + // 1、make ring second + int ringSecond = (int) ((jobInfo.getTriggerNextTime() / 1000) % 60); + + // 2、push time ring + pushTimeRing(ringSecond, jobInfo.getId()); + logger.debug(">>>>>>>>>>> xxl-job, schedule normal, push trigger : jobId = " + jobInfo.getId()); + + // 3、fresh next + refreshNextTriggerTime(jobInfo, new Date(jobInfo.getTriggerNextTime())); + + } + + } + + // 3、update trigger info + /*for (XxlJobInfo jobInfo: scheduleList) { + XxlJobAdminBootstrap.getInstance().getXxlJobInfoMapper().scheduleUpdate(jobInfo); + }*/ + int batchSize = XxlJobAdminBootstrap.getInstance().getScheduleBatchSize(); + List> scheduleListBatches = CollectionTool.split(scheduleList, batchSize); + for (List scheduleListBatch : scheduleListBatches) { + int totalAffected = XxlJobAdminBootstrap.getInstance().getXxlJobInfoMapper().scheduleBatchUpdate(scheduleListBatch); + logger.debug(">>>>>>>>>>> xxl-job, JobScheduleHelper scheduleBatchUpdate records:" + totalAffected); + } + + } else { + preReadSuc = false; + } + + } catch (Throwable e) { + if (!scheduleThreadToStop) { + logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread error:{}", e.getMessage(), e); + } + } finally { + // transaction commit + try { + if (transactionStatus != null) { + XxlJobAdminBootstrap.getInstance().getTransactionManager().commit(transactionStatus); // avlid schedule repeat + } + } catch (Throwable e) { + logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread transaction commit error:{}", e.getMessage(), e); + } + } + // transaction end + long cost = System.currentTimeMillis() - start; + + + // Wait seconds, align second + if (cost < 1000) { // scan-overtime, not wait + try { + // pre-read period: success > scan each second; fail > skip this period; + TimeUnit.MILLISECONDS.sleep((preReadSuc ? 1000 : PRE_READ_MS) - System.currentTimeMillis() % 1000); + } catch (Throwable e) { + if (!scheduleThreadToStop) { + logger.error(e.getMessage(), e); + } + } + } + + } + + logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread stop"); + } + }); + scheduleThread.setDaemon(true); + scheduleThread.setName("xxl-job, admin JobScheduleHelper#scheduleThread"); + scheduleThread.start(); + + + // ring thread + ringThread = new Thread(new Runnable() { + @Override + public void run() { + + while (!ringThreadToStop) { + + // align second + try { + TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis() % 1000); + } catch (Throwable e) { + if (!ringThreadToStop) { + logger.error(e.getMessage(), e); + } + } + + try { + // second data + List ringItemData = new ArrayList<>(); + + // collect rind data, by second + int nowSecond = Calendar.getInstance().get(Calendar.SECOND); + for (int i = 0; i <= 2; i++) { // 避免调度遗漏:处理耗时太长、跨过刻度,除当前刻度外 + 向前校验2个刻度; + List ringItemList = ringData.remove((nowSecond + 60 - i) % 60); + if (CollectionTool.isNotEmpty(ringItemList)) { + // distinct for each second + List ringItemListDistinct = ringItemList.stream().distinct().toList(); // 避免调度重复:重复推送时间轮刻度,去重只保留一个;; + if (ringItemListDistinct.size() < ringItemList.size()) { + logger.warn(">>>>>>>>>>> xxl-job, time-ring found job repeat beat : " + nowSecond + " = " + ringItemData); + } + + // collect ring item + ringItemData.addAll(ringItemListDistinct); + } + } + + // ring trigger + logger.debug(">>>>>>>>>>> xxl-job, time-ring beat : " + nowSecond + " = " + ringItemData); + if (CollectionTool.isNotEmpty(ringItemData)) { + // do trigger + for (int jobId : ringItemData) { + // do trigger + XxlJobAdminBootstrap.getInstance().getJobTriggerPoolHelper().trigger(jobId, TriggerTypeEnum.CRON, -1, null, null, null); + } + // clear + ringItemData.clear(); + } + } catch (Throwable e) { + if (!ringThreadToStop) { + logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread error:{}", e.getMessage(), e); + } + } + } + logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread stop"); + } + }); + ringThread.setDaemon(true); + ringThread.setName("xxl-job, admin JobScheduleHelper#ringThread"); + ringThread.start(); + } + + /** + * refresh next trigger time of job + * + * @param jobInfo job info + * @param fromTime from time + */ + private void refreshNextTriggerTime(XxlJobInfo jobInfo, Date fromTime) { + try { + // generate next trigger time + ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), ScheduleTypeEnum.NONE); + Date nextTriggerTime = scheduleTypeEnum.getScheduleType().generateNextTriggerTime(jobInfo, fromTime); + + // refresh next trigger-time + status + if (nextTriggerTime != null) { + // generate success + jobInfo.setTriggerStatus(-1); // pass, may be Inaccurate + jobInfo.setTriggerLastTime(jobInfo.getTriggerNextTime()); + jobInfo.setTriggerNextTime(nextTriggerTime.getTime()); + } else { + // generate fail, stop job + jobInfo.setTriggerStatus(TriggerStatus.STOPPED.getValue()); + jobInfo.setTriggerLastTime(0); + jobInfo.setTriggerNextTime(0); + logger.error(">>>>>>>>>>> xxl-job, refreshNextValidTime fail for job: jobId={}, scheduleType={}, scheduleConf={}", + jobInfo.getId(), jobInfo.getScheduleType(), jobInfo.getScheduleConf()); + } + } catch (Throwable e) { + // generate error, stop job + jobInfo.setTriggerStatus(TriggerStatus.STOPPED.getValue()); + jobInfo.setTriggerLastTime(0); + jobInfo.setTriggerNextTime(0); + + logger.error(">>>>>>>>>>> xxl-job, refreshNextValidTime error for job: jobId={}, scheduleType={}, scheduleConf={}", + jobInfo.getId(), jobInfo.getScheduleType(), jobInfo.getScheduleConf(), e); + } + } + + /** + * push time ring + * + * @param ringSecond ring second + * @param jobId job id + */ + private void pushTimeRing(int ringSecond, int jobId) { + // get ringItemData, init when not exists + List ringItemList = ringData.computeIfAbsent( + ringSecond, + k -> new ArrayList<>()); + + // push async rind + ringItemList.add(jobId); + logger.debug(">>>>>>>>>>> xxl-job, schedule push time-ring : " + ringSecond + " = " + List.of(ringItemList)); + } + + /** + * stop + */ + public void stop() { + + // 1、stop schedule + scheduleThreadToStop = true; + try { + TimeUnit.SECONDS.sleep(1); // wait + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + if (scheduleThread.getState() != Thread.State.TERMINATED) { + // interrupt and wait + scheduleThread.interrupt(); + try { + scheduleThread.join(); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + } + + // if has ring data, wait for elegent shutdown + boolean hasRingData = false; + if (MapTool.isNotEmpty(ringData)) { + for (int second : ringData.keySet()) { + List ringItemList = ringData.get(second); + if (CollectionTool.isNotEmpty(ringItemList)) { + hasRingData = true; + break; + } + } + } + if (hasRingData) { + try { + TimeUnit.SECONDS.sleep(ELEGANT_SHUTDOWN_WAITING_SECONDS); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + } + + // stop ring (wait job-in-memory stop) + ringThreadToStop = true; + try { + TimeUnit.SECONDS.sleep(1); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + if (ringThread.getState() != Thread.State.TERMINATED) { + // interrupt and wait + ringThread.interrupt(); + try { + ringThread.join(); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + } + + logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper stop"); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobTriggerPoolHelper.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobTriggerPoolHelper.java new file mode 100644 index 000000000..650582742 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobTriggerPoolHelper.java @@ -0,0 +1,153 @@ +package com.xxl.job.admin.scheduler.thread; + +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * job trigger thread pool helper + * + * @author xuxueli 2018-07-03 21:08:07 + */ +public class JobTriggerPoolHelper { + private static final Logger logger = LoggerFactory.getLogger(JobTriggerPoolHelper.class); + + + // ---------------------- trigger pool ---------------------- + + // fast/slow thread pool + private ThreadPoolExecutor fastTriggerPool = null; + private ThreadPoolExecutor slowTriggerPool = null; + + /** + * start + */ + public void start() { + fastTriggerPool = new ThreadPoolExecutor( + 10, + XxlJobAdminBootstrap.getInstance().getTriggerPoolFastMax(), + 60L, + TimeUnit.SECONDS, + new LinkedBlockingQueue(2000), + new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-fastTriggerPool-" + r.hashCode()); + } + }, + new RejectedExecutionHandler() { + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + logger.error(">>>>>>>>>>> xxl-job, admin JobTriggerPoolHelper-fastTriggerPool execute too fast, Runnable=" + r.toString()); + } + }); + + slowTriggerPool = new ThreadPoolExecutor( + 10, + XxlJobAdminBootstrap.getInstance().getTriggerPoolSlowMax(), + 60L, + TimeUnit.SECONDS, + new LinkedBlockingQueue(5000), + new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-slowTriggerPool-" + r.hashCode()); + } + }, + new RejectedExecutionHandler() { + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + logger.error(">>>>>>>>>>> xxl-job, admin JobTriggerPoolHelper-slowTriggerPool execute too fast, Runnable=" + r.toString()); + } + }); + } + + /** + * stop + */ + public void stop() { + //triggerPool.shutdown(); + fastTriggerPool.shutdownNow(); + slowTriggerPool.shutdownNow(); + logger.info(">>>>>>>>> xxl-job trigger thread pool shutdown success."); + } + + + // job timeout count + private volatile long minTim = System.currentTimeMillis() / 60000; // ms > min + private volatile ConcurrentMap jobTimeoutCountMap = new ConcurrentHashMap<>(); + + + // ---------------------- tool ---------------------- + + /** + * trigger job + * + * @param jobId + * @param triggerType + * @param failRetryCount >=0: use this param + * <0: use param from job info config + * @param executorShardingParam + * @param executorParam null: use job param + * not null: cover job param + */ + public void trigger(final int jobId, + final TriggerTypeEnum triggerType, + final int failRetryCount, + final String executorShardingParam, + final String executorParam, + final String addressList) { + + // choose thread pool + ThreadPoolExecutor triggerPool_ = fastTriggerPool; + AtomicInteger jobTimeoutCount = jobTimeoutCountMap.get(jobId); + if (jobTimeoutCount != null && jobTimeoutCount.get() > 10) { // job-timeout 10 times in 1 min + triggerPool_ = slowTriggerPool; + } + + // trigger + triggerPool_.execute(new Runnable() { + @Override + public void run() { + + long start = System.currentTimeMillis(); + + try { + // do trigger + XxlJobAdminBootstrap.getInstance().getJobTrigger().trigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, addressList); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } finally { + + // check timeout-count-map + long minTim_now = System.currentTimeMillis() / 60000; + if (minTim != minTim_now) { + minTim = minTim_now; + jobTimeoutCountMap.clear(); + } + + // incr timeout-count-map + long cost = System.currentTimeMillis() - start; + if (cost > 500) { // ob-timeout threshold 500ms + AtomicInteger timeoutCount = jobTimeoutCountMap.putIfAbsent(jobId, new AtomicInteger(1)); + if (timeoutCount != null) { + timeoutCount.incrementAndGet(); + } + } + + } + + } + + @Override + public String toString() { + return "Job Runnable, jobId:" + jobId; + } + }); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/trigger/JobTrigger.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/trigger/JobTrigger.java new file mode 100644 index 000000000..c9cd363e1 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/trigger/JobTrigger.java @@ -0,0 +1,277 @@ +package com.xxl.job.admin.scheduler.trigger; + +import com.xxl.job.admin.mapper.XxlJobGroupMapper; +import com.xxl.job.admin.mapper.XxlJobInfoMapper; +import com.xxl.job.admin.mapper.XxlJobLogMapper; +import com.xxl.job.admin.model.XxlJobGroup; +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.model.XxlJobLog; +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.admin.scheduler.route.ExecutorRouteStrategyEnum; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.job.core.constant.ExecutorBlockStrategyEnum; +import com.xxl.job.core.context.XxlJobContext; +import com.xxl.job.core.openapi.ExecutorBiz; +import com.xxl.job.core.openapi.model.TriggerRequest; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.error.ThrowableTool; +import com.xxl.tool.http.IPTool; +import com.xxl.tool.response.Response; +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.Date; + +/** + * xxl-job trigger + * + * @author xuxueli 17/7/13. + */ +@Component +public class JobTrigger { + private static final Logger logger = LoggerFactory.getLogger(JobTrigger.class); + + + @Resource + private XxlJobInfoMapper xxlJobInfoMapper; + @Resource + private XxlJobGroupMapper xxlJobGroupMapper; + @Resource + private XxlJobLogMapper xxlJobLogMapper; + + + /** + * trigger job + * + * @param jobId + * @param triggerType + * @param failRetryCount >=0: use this param + * <0: use param from job info config + * @param executorShardingParam null: new sharding, all nodes + * not null: for retry, only one node + * @param executorParam null: use job param + * not null: cover job param + * @param addressList null: use executor addressList + * not null: cover + */ + public void trigger(int jobId, + TriggerTypeEnum triggerType, + int failRetryCount, + String executorShardingParam, + String executorParam, + String addressList) { + + // load data + XxlJobInfo jobInfo = xxlJobInfoMapper.loadById(jobId); + if (jobInfo == null) { + logger.warn(">>>>>>>>>>>> trigger fail, jobId invalid,jobId={}", jobId); + return; + } + if (executorParam != null) { + jobInfo.setExecutorParam(executorParam); + } + int finalFailRetryCount = failRetryCount >= 0 ? failRetryCount : jobInfo.getExecutorFailRetryCount(); + XxlJobGroup group = xxlJobGroupMapper.load(jobInfo.getJobGroup()); + + // cover addressList + if (StringTool.isNotBlank(addressList)) { + group.setAddressType(1); + group.setAddressList(addressList.trim()); + } + + // sharding param + int[] shardingParam = null; + Date triggerTime = new Date(); + if (executorShardingParam != null) { + String[] shardingArr = executorShardingParam.split("/"); + if (shardingArr.length == 2 && StringTool.isNumeric(shardingArr[0]) && StringTool.isNumeric(shardingArr[1])) { + shardingParam = new int[2]; + shardingParam[0] = Integer.parseInt(shardingArr[0]); + shardingParam[1] = Integer.parseInt(shardingArr[1]); + } + } + if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) + && group.getRegistryList() != null && !group.getRegistryList().isEmpty() + && shardingParam == null) { + for (int i = 0; i < group.getRegistryList().size(); i++) { + processTrigger(group, jobInfo, finalFailRetryCount, triggerType, triggerTime, i, group.getRegistryList().size()); + } + } else { + if (shardingParam == null) { + shardingParam = new int[]{0, 1}; + } + processTrigger(group, jobInfo, finalFailRetryCount, triggerType, triggerTime, shardingParam[0], shardingParam[1]); + } + + } + + /*private static boolean isNumeric(String str){ + try { + int result = Integer.valueOf(str); + return true; + } catch (NumberFormatException e) { + return false; + } + }*/ + + /** + * process trigger with log + * + * @param group job group, registry list may be empty + * @param jobInfo job info + * @param finalFailRetryCount the fail-retry count + * @param triggerType trigger type + * @param triggerTime trigger time + * @param index sharding index + * @param total sharding index + */ + private void processTrigger(XxlJobGroup group, + XxlJobInfo jobInfo, + int finalFailRetryCount, + TriggerTypeEnum triggerType, + Date triggerTime, + int index, + int total) { + + // param + ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), ExecutorBlockStrategyEnum.SERIAL_EXECUTION); // block strategy + ExecutorRouteStrategyEnum executorRouteStrategyEnum = ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null); // route strategy + String shardingParam = (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum) ? String.valueOf(index).concat("/").concat(String.valueOf(total)) : null; + + // 1、save log-id + XxlJobLog jobLog = new XxlJobLog(); + jobLog.setJobGroup(jobInfo.getJobGroup()); + jobLog.setJobId(jobInfo.getId()); + jobLog.setTriggerTime(triggerTime); + xxlJobLogMapper.save(jobLog); + logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getJobId()); + + // 2、init trigger-param + TriggerRequest triggerParam = new TriggerRequest(); + triggerParam.setJobId(jobInfo.getId()); + triggerParam.setExecutorHandler(jobInfo.getExecutorHandler()); + triggerParam.setExecutorParams(jobInfo.getExecutorParam()); + triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); + triggerParam.setExecutorTimeout(jobInfo.getExecutorTimeout()); + triggerParam.setLogId(jobLog.getId()); + triggerParam.setLogDateTime(jobLog.getTriggerTime().getTime()); + triggerParam.setGlueType(jobInfo.getGlueType()); + triggerParam.setGlueSource(jobInfo.getGlueSource()); + triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime()); + triggerParam.setBroadcastIndex(index); + triggerParam.setBroadcastTotal(total); + + // 3、init address + String address = null; + Response routeAddressResult = null; + if (group.getRegistryList() != null && !group.getRegistryList().isEmpty()) { + if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum) { + if (index < group.getRegistryList().size()) { + address = group.getRegistryList().get(index); + } else { + address = group.getRegistryList().get(0); + } + } else { + routeAddressResult = executorRouteStrategyEnum.getRouter().route(triggerParam, group.getRegistryList()); + if (routeAddressResult.isSuccess()) { + address = routeAddressResult.getData(); + } + } + } else { + routeAddressResult = Response.of(XxlJobContext.HANDLE_CODE_FAIL, I18nUtil.getString("jobconf_trigger_address_empty")); + } + + // 4、trigger remote executor + Response triggerResult = null; + if (address != null) { + triggerResult = doTrigger(triggerParam, address); + } else { + triggerResult = Response.of(XxlJobContext.HANDLE_CODE_FAIL, "Address Router Fail."); + } + + // 5、collection trigger info + // trigger config + StringBuilder triggerMsgSb = new StringBuilder(); + triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_type")).append(":").append(triggerType.getTitle()); + triggerMsgSb.append("
").append(I18nUtil.getString("jobconf_trigger_admin_adress")).append(":").append(IPTool.getIp()); + triggerMsgSb.append("
").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append(":") + .append((group.getAddressType() == 0) ? I18nUtil.getString("jobgroup_field_addressType_0") : I18nUtil.getString("jobgroup_field_addressType_1")); + triggerMsgSb.append("
").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append(":").append(group.getRegistryList()); + triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append(":").append(executorRouteStrategyEnum.getTitle()); + if (shardingParam != null) { + triggerMsgSb.append("(").append(shardingParam).append(")"); + } + triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append(":").append(blockStrategy.getTitle()); + triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_timeout")).append(":").append(jobInfo.getExecutorTimeout()); + triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_executorFailRetryCount")).append(":").append(finalFailRetryCount); + + // trigger data + triggerMsgSb.append("

>>>>>>>>>>>").append(I18nUtil.getString("jobconf_trigger_run")).append("<<<<<<<<<<<
"); + triggerMsgSb.append("
").append(I18nUtil.getString("joblog_field_executorAddress")).append(":"); + if (StringTool.isNotBlank(address)) { + triggerMsgSb.append(address); + } else if (routeAddressResult != null && !routeAddressResult.isSuccess() && routeAddressResult.getMsg() != null) { + triggerMsgSb.append("address route fail, ").append(routeAddressResult.getMsg()); + } else { + triggerMsgSb.append("address route fail."); + } + if (StringTool.isNotBlank(jobInfo.getExecutorHandler())) { + triggerMsgSb.append("
").append("JobHandler").append(":").append(jobInfo.getExecutorHandler()); + } + triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_executorparam")).append(":").append(jobInfo.getExecutorParam()); + triggerMsgSb.append("
").append(I18nUtil.getString("joblog_field_triggerMsg")).append(":"); + if (triggerResult.isSuccess()) { + triggerMsgSb.append("success"); + } else if (triggerResult.getMsg() != null) { + triggerMsgSb.append("error, ").append(triggerResult.getMsg()); + } else { + triggerMsgSb.append("fail"); + } + + // 6、save log trigger-info + jobLog.setExecutorAddress(address); + jobLog.setExecutorHandler(jobInfo.getExecutorHandler()); + jobLog.setExecutorParam(jobInfo.getExecutorParam()); + jobLog.setExecutorShardingParam(shardingParam); + jobLog.setExecutorFailRetryCount(finalFailRetryCount); + //jobLog.setTriggerTime(); + jobLog.setTriggerCode(triggerResult.getCode()); + jobLog.setTriggerMsg(triggerMsgSb.toString()); + xxlJobLogMapper.updateTriggerInfo(jobLog); + + logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getJobId()); + } + + /** + * do trigger with address + * + * @param triggerParam trigger param + * @param address the address + * @return return + */ + private Response doTrigger(TriggerRequest triggerParam, String address) { + try { + // build client + ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(address); + + // invoke + Response runResult = executorBiz.run(triggerParam); + + // build result + StringBuffer runResultSB = new StringBuffer(I18nUtil.getString("jobconf_trigger_run") + ":"); + runResultSB.append("
address:").append(address); + runResultSB.append("
code:").append(runResult.getCode()); + runResultSB.append("
msg:").append(runResult.getMsg()); + + // return + runResult.setMsg(runResultSB.toString()); + return runResult; + } catch (Exception e) { + logger.error(">>>>>>>>>>> xxl-job trigger error, please check if the executor[{}] is running.", address, e); + return Response.of(XxlJobContext.HANDLE_CODE_FAIL, ThrowableTool.toString(e)); + } + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/trigger/TriggerTypeEnum.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/trigger/TriggerTypeEnum.java new file mode 100644 index 000000000..b962af975 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/trigger/TriggerTypeEnum.java @@ -0,0 +1,29 @@ +package com.xxl.job.admin.scheduler.trigger; + +import com.xxl.job.admin.util.I18nUtil; + +/** + * trigger type enum + * + * @author xuxueli 2018-09-16 04:56:41 + */ +public enum TriggerTypeEnum { + + MANUAL(I18nUtil.getString("jobconf_trigger_type_manual")), + CRON(I18nUtil.getString("jobconf_trigger_type_cron")), + RETRY(I18nUtil.getString("jobconf_trigger_type_retry")), + PARENT(I18nUtil.getString("jobconf_trigger_type_parent")), + API(I18nUtil.getString("jobconf_trigger_type_api")), + MISFIRE(I18nUtil.getString("jobconf_trigger_type_misfire")); + + private TriggerTypeEnum(String title) { + this.title = title; + } + + private String title; + + public String getTitle() { + return title; + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/ScheduleType.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/ScheduleType.java new file mode 100644 index 000000000..9299b042d --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/ScheduleType.java @@ -0,0 +1,22 @@ +package com.xxl.job.admin.scheduler.type; + +import com.xxl.job.admin.model.XxlJobInfo; + +import java.util.Date; + +/** + * Schedule Type + * + * @author xuxueli 2020-10-29 + */ +public abstract class ScheduleType { + + /** + * generate next trigger time + * + * @param jobInfo job info + * @param fromTime from time + */ + public abstract Date generateNextTriggerTime(XxlJobInfo jobInfo, Date fromTime) throws Exception; + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/ScheduleTypeEnum.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/ScheduleTypeEnum.java new file mode 100644 index 000000000..79a5ce91b --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/ScheduleTypeEnum.java @@ -0,0 +1,63 @@ +package com.xxl.job.admin.scheduler.type; + +import com.xxl.job.admin.scheduler.type.strategy.CronScheduleType; +import com.xxl.job.admin.scheduler.type.strategy.FixRateScheduleType; +import com.xxl.job.admin.scheduler.type.strategy.NoneScheduleType; +import com.xxl.job.admin.util.I18nUtil; + +/** + * @author xuxueli 2020-10-29 21:11:23 + */ +public enum ScheduleTypeEnum { + + NONE(I18nUtil.getString("schedule_type_none"), new NoneScheduleType()), + + /** + * schedule by cron + */ + CRON(I18nUtil.getString("schedule_type_cron"), new CronScheduleType()), + + /** + * schedule by fixed rate (in seconds) + */ + FIX_RATE(I18nUtil.getString("schedule_type_fix_rate"), new FixRateScheduleType()), + + /** + * schedule by fix delay (in seconds), after the last time + */ + /*FIX_DELAY(I18nUtil.getString("schedule_type_fix_delay"))*/; + + private final String title; + private final ScheduleType scheduleType; + ; + + ScheduleTypeEnum(String title, ScheduleType scheduleType) { + this.title = title; + this.scheduleType = scheduleType; + } + + public String getTitle() { + return title; + } + + public ScheduleType getScheduleType() { + return scheduleType; + } + + /** + * match by name + * + * @param name name of ScheduleTypeEnum + * @param defaultItem default item + * @return ScheduleTypeEnum + */ + public static ScheduleTypeEnum match(String name, ScheduleTypeEnum defaultItem) { + for (ScheduleTypeEnum item : ScheduleTypeEnum.values()) { + if (item.name().equals(name)) { + return item; + } + } + return defaultItem; + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/strategy/CronScheduleType.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/strategy/CronScheduleType.java new file mode 100644 index 000000000..e7b86611d --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/strategy/CronScheduleType.java @@ -0,0 +1,17 @@ +package com.xxl.job.admin.scheduler.type.strategy; + +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.scheduler.cron.CronExpression; +import com.xxl.job.admin.scheduler.type.ScheduleType; + +import java.util.Date; + +public class CronScheduleType extends ScheduleType { + + @Override + public Date generateNextTriggerTime(XxlJobInfo jobInfo, Date fromTime) throws Exception { + // generate next trigger time, with cron + return new CronExpression(jobInfo.getScheduleConf()).getNextValidTimeAfter(fromTime); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/strategy/FixRateScheduleType.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/strategy/FixRateScheduleType.java new file mode 100644 index 000000000..298ab7d11 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/strategy/FixRateScheduleType.java @@ -0,0 +1,26 @@ +package com.xxl.job.admin.scheduler.type.strategy; + +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.scheduler.type.ScheduleType; +import com.xxl.tool.core.DateTool; + +import java.util.Date; + +public class FixRateScheduleType extends ScheduleType { + + @Override + public Date generateNextTriggerTime(XxlJobInfo jobInfo, Date fromTime) throws Exception { + + // generate next trigger time, fix rate delay + Date nextTriggerTime = new Date(fromTime.getTime() + Long.parseLong(jobInfo.getScheduleConf()) * 1000L); + + // assign second: + if (nextTriggerTime.getTime() % 1000 != 0) { + nextTriggerTime = DateTool.addSeconds(DateTool.setMilliseconds(nextTriggerTime, 0), 1); + } + + return nextTriggerTime; + + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/strategy/NoneScheduleType.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/strategy/NoneScheduleType.java new file mode 100644 index 000000000..d17b1e83b --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/strategy/NoneScheduleType.java @@ -0,0 +1,16 @@ +package com.xxl.job.admin.scheduler.type.strategy; + +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.scheduler.type.ScheduleType; + +import java.util.Date; + +public class NoneScheduleType extends ScheduleType { + + @Override + public Date generateNextTriggerTime(XxlJobInfo jobInfo, Date fromTime) throws Exception { + // generate none trigger-time + return null; + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java index 20a53f1c8..1e5fe1edf 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java @@ -1,8 +1,9 @@ package com.xxl.job.admin.service; -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.core.model.XxlJobUser; -import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.sso.core.model.LoginInfo; +import com.xxl.tool.response.PageModel; +import com.xxl.tool.response.Response; import java.util.Date; import java.util.Map; @@ -16,74 +17,47 @@ public interface XxlJobService { /** * page list - * @param start - * @param length - * @param jobGroup - * @param jobDesc - * @param executorHandler - * @param author - * @return */ - public Map pageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, - String executorHandler, String author); + public Response> pageList(int offset, int pagesize, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author); /** * add job - * @param jobInfo - * @return */ - public ReturnT add(XxlJobInfo jobInfo, XxlJobUser loginUser); + public Response add(XxlJobInfo jobInfo, LoginInfo loginInfo); /** * update job - * @param jobInfo - * @return */ - public ReturnT update(XxlJobInfo jobInfo, XxlJobUser loginUser); + public Response update(XxlJobInfo jobInfo, LoginInfo loginInfo); /** - * remove job * - * @param id - * @return + * remove job */ - public ReturnT remove(int id); + public Response remove(int id, LoginInfo loginInfo); /** * start job - * @param id - * @return */ - public ReturnT start(int id); + public Response start(int id, LoginInfo loginInfo); /** * stop job - * @param id - * @return */ - public ReturnT stop(int id); + public Response stop(int id, LoginInfo loginInfo); /** * trigger - * @param loginUser - * @param jobId - * @param executorParam - * @param addressList - * @return */ - public ReturnT trigger(XxlJobUser loginUser, int jobId, String executorParam, String addressList); + public Response trigger(LoginInfo loginInfo, int jobId, String executorParam, String addressList); /** * dashboard info - * @return */ public Map dashboardInfo(); /** * chart info - * @param startDate - * @param endDate - * @return */ - public ReturnT> chartInfo(Date startDate, Date endDate); + public Response> chartInfo(Date startDate, Date endDate); } diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java index 9247e2a5f..5575edb52 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java @@ -1,11 +1,10 @@ package com.xxl.job.admin.service.impl; -import com.xxl.job.admin.core.thread.JobCompleteHelper; -import com.xxl.job.admin.core.thread.JobRegistryHelper; -import com.xxl.job.core.biz.AdminBiz; -import com.xxl.job.core.biz.model.HandleCallbackParam; -import com.xxl.job.core.biz.model.RegistryParam; -import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.core.openapi.AdminBiz; +import com.xxl.job.core.openapi.model.CallbackRequest; +import com.xxl.job.core.openapi.model.RegistryRequest; +import com.xxl.tool.response.Response; import org.springframework.stereotype.Service; import java.util.List; @@ -16,19 +15,19 @@ import java.util.List; @Service public class AdminBizImpl implements AdminBiz { - @Override - public ReturnT callback(List callbackParamList) { - return JobCompleteHelper.getInstance().callback(callbackParamList); - } + @Override + public Response callback(List callbackRequestList) { + return XxlJobAdminBootstrap.getInstance().getJobCompleteHelper().callback(callbackRequestList); + } - @Override - public ReturnT registry(RegistryParam registryParam) { - return JobRegistryHelper.getInstance().registry(registryParam); - } + @Override + public Response registry(RegistryRequest registryRequest) { + return XxlJobAdminBootstrap.getInstance().getJobRegistryHelper().registry(registryRequest); + } - @Override - public ReturnT registryRemove(RegistryParam registryParam) { - return JobRegistryHelper.getInstance().registryRemove(registryParam); - } + @Override + public Response registryRemove(RegistryRequest registryRequest) { + return XxlJobAdminBootstrap.getInstance().getJobRegistryHelper().registryRemove(registryRequest); + } } diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/LoginService.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/LoginService.java deleted file mode 100644 index 241a32f57..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/LoginService.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.xxl.job.admin.service.impl; - -import com.xxl.job.admin.core.model.XxlJobUser; -import com.xxl.job.admin.core.util.CookieUtil; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.admin.core.util.JacksonUtil; -import com.xxl.job.admin.dao.XxlJobUserDao; -import com.xxl.job.core.biz.model.ReturnT; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.stereotype.Service; -import org.springframework.util.DigestUtils; - -import java.math.BigInteger; - -/** - * @author xuxueli 2019-05-04 22:13:264 - */ -@Service -public class LoginService { - - public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY"; - - @Resource - private XxlJobUserDao xxlJobUserDao; - - // ---------------------- token tool ---------------------- - - private String makeToken(XxlJobUser xxlJobUser) { - String tokenJson = JacksonUtil.writeValueAsString(xxlJobUser); - String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16); - return tokenHex; - } - - private XxlJobUser parseToken(String tokenHex) { - XxlJobUser xxlJobUser = null; - if (tokenHex != null) { - String tokenJson = new String(new BigInteger(tokenHex, 16).toByteArray()); // username_password(md5) - xxlJobUser = JacksonUtil.readValue(tokenJson, XxlJobUser.class); - } - return xxlJobUser; - } - - // ---------------------- login tool, with cookie and db ---------------------- - - public ReturnT login(HttpServletRequest request, HttpServletResponse response, String username, - String password, boolean ifRemember) { - - // param - if (username == null || username.trim().length() == 0 || password == null || password.trim().length() == 0) { - return new ReturnT(500, I18nUtil.getString("login_param_empty")); - } - - // valid passowrd - XxlJobUser xxlJobUser = xxlJobUserDao.loadByUserName(username); - if (xxlJobUser == null) { - return new ReturnT(500, I18nUtil.getString("login_param_unvalid")); - } - String passwordMd5 = DigestUtils.md5DigestAsHex(password.getBytes()); - if (!passwordMd5.equals(xxlJobUser.getPassword())) { - return new ReturnT(500, I18nUtil.getString("login_param_unvalid")); - } - - String loginToken = makeToken(xxlJobUser); - - // do login - CookieUtil.set(response, LOGIN_IDENTITY_KEY, loginToken, ifRemember); - return ReturnT.SUCCESS; - } - - /** - * logout - * @param request - * @param response - */ - public ReturnT logout(HttpServletRequest request, HttpServletResponse response) { - CookieUtil.remove(request, response, LOGIN_IDENTITY_KEY); - return ReturnT.SUCCESS; - } - - /** - * logout - * @param request - * @return - */ - public XxlJobUser ifLogin(HttpServletRequest request, HttpServletResponse response) { - String cookieToken = CookieUtil.getValue(request, LOGIN_IDENTITY_KEY); - if (cookieToken != null) { - XxlJobUser cookieUser = null; - try { - cookieUser = parseToken(cookieToken); - } - catch (Exception e) { - logout(request, response); - } - if (cookieUser != null) { - XxlJobUser dbUser = xxlJobUserDao.loadByUserName(cookieUser.getUsername()); - if (dbUser != null) { - if (cookieUser.getPassword().equals(dbUser.getPassword())) { - return dbUser; - } - } - } - } - return null; - } - -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java index 7ee8e58bc..92509d470 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java @@ -1,23 +1,28 @@ package com.xxl.job.admin.service.impl; -import com.xxl.job.admin.core.cron.CronExpression; -import com.xxl.job.admin.core.model.XxlJobGroup; -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.core.model.XxlJobLogReport; -import com.xxl.job.admin.core.model.XxlJobUser; -import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; -import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum; -import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum; -import com.xxl.job.admin.core.thread.JobScheduleHelper; -import com.xxl.job.admin.core.thread.JobTriggerPoolHelper; -import com.xxl.job.admin.core.trigger.TriggerTypeEnum; -import com.xxl.job.admin.core.util.I18nUtil; -import com.xxl.job.admin.dao.*; +import com.xxl.job.admin.constant.TriggerStatus; +import com.xxl.job.admin.mapper.*; +import com.xxl.job.admin.model.XxlJobGroup; +import com.xxl.job.admin.model.XxlJobInfo; +import com.xxl.job.admin.model.XxlJobLogReport; +import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap; +import com.xxl.job.admin.scheduler.cron.CronExpression; +import com.xxl.job.admin.scheduler.misfire.MisfireStrategyEnum; +import com.xxl.job.admin.scheduler.route.ExecutorRouteStrategyEnum; +import com.xxl.job.admin.scheduler.thread.JobScheduleHelper; +import com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum; +import com.xxl.job.admin.scheduler.type.ScheduleTypeEnum; import com.xxl.job.admin.service.XxlJobService; -import com.xxl.job.core.biz.model.ReturnT; -import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; +import com.xxl.job.admin.util.I18nUtil; +import com.xxl.job.admin.util.JobGroupPermissionUtil; +import com.xxl.job.core.constant.ExecutorBlockStrategyEnum; import com.xxl.job.core.glue.GlueTypeEnum; -import com.xxl.job.core.util.DateUtil; +import com.xxl.sso.core.model.LoginInfo; +import com.xxl.tool.core.DateTool; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.json.GsonTool; +import com.xxl.tool.response.PageModel; +import com.xxl.tool.response.Response; import jakarta.annotation.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,105 +33,82 @@ import java.util.*; /** * core job action for xxl-job - * * @author xuxueli 2016-5-28 15:30:33 */ @Service public class XxlJobServiceImpl implements XxlJobService { - private static Logger logger = LoggerFactory.getLogger(XxlJobServiceImpl.class); @Resource - private XxlJobGroupDao xxlJobGroupDao; - + private XxlJobGroupMapper xxlJobGroupMapper; @Resource - private XxlJobInfoDao xxlJobInfoDao; - + private XxlJobInfoMapper xxlJobInfoMapper; @Resource - public XxlJobLogDao xxlJobLogDao; - + public XxlJobLogMapper xxlJobLogMapper; @Resource - private XxlJobLogGlueDao xxlJobLogGlueDao; - + private XxlJobLogGlueMapper xxlJobLogGlueMapper; @Resource - private XxlJobLogReportDao xxlJobLogReportDao; + private XxlJobLogReportMapper xxlJobLogReportMapper; @Override - public Map pageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, - String executorHandler, String author) { + public Response> pageList(int offset, int pagesize, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) { // page list - List list = xxlJobInfoDao.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, - author); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, - author); + List list = xxlJobInfoMapper.pageList(offset, pagesize, jobGroup, triggerStatus, jobDesc, executorHandler, author); + int list_count = xxlJobInfoMapper.pageListCount(offset, pagesize, jobGroup, triggerStatus, jobDesc, executorHandler, author); // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; + PageModel pageModel = new PageModel<>(); + pageModel.setData(list); + pageModel.setTotal(list_count); + + return Response.ofSuccess(pageModel); } @Override - public ReturnT add(XxlJobInfo jobInfo, XxlJobUser loginUser) { + public Response add(XxlJobInfo jobInfo, LoginInfo loginInfo) { // valid base - XxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup()); + XxlJobGroup group = xxlJobGroupMapper.load(jobInfo.getJobGroup()); if (group == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("system_please_choose") + I18nUtil.getString("jobinfo_field_jobgroup"))); + return Response.ofFail(I18nUtil.getString("system_please_choose") + I18nUtil.getString("jobinfo_field_jobgroup")); } - if (jobInfo.getJobDesc() == null || jobInfo.getJobDesc().trim().length() == 0) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_jobdesc"))); + if (StringTool.isBlank(jobInfo.getJobDesc())) { + return Response.ofFail((I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_jobdesc"))); } - if (jobInfo.getAuthor() == null || jobInfo.getAuthor().trim().length() == 0) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_author"))); + if (StringTool.isBlank(jobInfo.getAuthor())) { + return Response.ofFail((I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_author"))); } // valid trigger ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null); if (scheduleTypeEnum == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("schedule_type") + I18nUtil.getString("system_invalid"))); } if (scheduleTypeEnum == ScheduleTypeEnum.CRON) { if (jobInfo.getScheduleConf() == null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) { - return new ReturnT(ReturnT.FAIL_CODE, "Cron" + I18nUtil.getString("system_unvalid")); + return Response.ofFail("Cron" + I18nUtil.getString("system_invalid")); } - } - else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE/* - * || scheduleTypeEnum == - * ScheduleTypeEnum. - * FIX_DELAY - */) { + } else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE/* || scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) { if (jobInfo.getScheduleConf() == null) { - return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type"))); + return Response.ofFail((I18nUtil.getString("schedule_type"))); } try { - int fixSecond = Integer.valueOf(jobInfo.getScheduleConf()); + int fixSecond = Integer.parseInt(jobInfo.getScheduleConf()); if (fixSecond < 1) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("schedule_type") + I18nUtil.getString("system_invalid"))); } - } - catch (Exception e) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } catch (Exception e) { + return Response.ofFail((I18nUtil.getString("schedule_type") + I18nUtil.getString("system_invalid"))); } } // valid job if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("jobinfo_field_gluetype") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("jobinfo_field_gluetype") + I18nUtil.getString("system_invalid"))); } - if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType()) - && (jobInfo.getExecutorHandler() == null || jobInfo.getExecutorHandler().trim().length() == 0)) { - return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + "JobHandler")); + if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType()) && StringTool.isBlank(jobInfo.getExecutorHandler())) { + return Response.ofFail((I18nUtil.getString("system_please_input") + "JobHandler")); } // 》fix "\r" in shell if (GlueTypeEnum.GLUE_SHELL == GlueTypeEnum.match(jobInfo.getGlueType()) && jobInfo.getGlueSource() != null) { @@ -135,39 +117,33 @@ public class XxlJobServiceImpl implements XxlJobService { // valid advanced if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("jobinfo_field_executorRouteStrategy") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("jobinfo_field_executorRouteStrategy") + I18nUtil.getString("system_invalid"))); } if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("misfire_strategy") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("misfire_strategy") + I18nUtil.getString("system_invalid"))); } if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("jobinfo_field_executorBlockStrategy") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("jobinfo_field_executorBlockStrategy") + I18nUtil.getString("system_invalid"))); } // 》ChildJobId valid - if (jobInfo.getChildJobId() != null && jobInfo.getChildJobId().trim().length() > 0) { + if (StringTool.isNotBlank(jobInfo.getChildJobId())) { String[] childJobIds = jobInfo.getChildJobId().split(","); for (String childJobIdItem : childJobIds) { - if (childJobIdItem != null && childJobIdItem.trim().length() > 0 && isNumeric(childJobIdItem)) { - XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.parseInt(childJobIdItem)); + if (StringTool.isNotBlank(childJobIdItem) && StringTool.isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoMapper.loadById(Integer.parseInt(childJobIdItem)); if (childJobInfo == null) { - return new ReturnT(ReturnT.FAIL_CODE, - MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" - + I18nUtil.getString("system_not_found")), childJobIdItem)); + return Response.ofFail( + MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_not_found")), childJobIdItem)); } - if (!loginUser.validPermission(childJobInfo.getJobGroup())) { - return new ReturnT(ReturnT.FAIL_CODE, - MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" - + I18nUtil.getString("system_permission_limit")), childJobIdItem)); + // valid jobGroup permission + if (!JobGroupPermissionUtil.hasJobGroupPermission(loginInfo, childJobInfo.getJobGroup())) { + return Response.ofFail( + MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_permission_limit")), childJobIdItem)); } - } - else { - return new ReturnT(ReturnT.FAIL_CODE, - MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" - + I18nUtil.getString("system_unvalid")), childJobIdItem)); + } else { + return Response.ofFail( + MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_invalid")), childJobIdItem)); } } @@ -187,114 +163,88 @@ public class XxlJobServiceImpl implements XxlJobService { jobInfo.setGlueUpdatetime(new Date()); // remove the whitespace jobInfo.setExecutorHandler(jobInfo.getExecutorHandler().trim()); - xxlJobInfoDao.save(jobInfo); + xxlJobInfoMapper.save(jobInfo); if (jobInfo.getId() < 1) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("jobinfo_field_add") + I18nUtil.getString("system_fail"))); + return Response.ofFail((I18nUtil.getString("jobinfo_field_add") + I18nUtil.getString("system_fail"))); } - return new ReturnT(String.valueOf(jobInfo.getId())); - } + // write operation log + logger.info(">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}", + loginInfo.getUserName(), "jobinfo-save", GsonTool.toJson(jobInfo)); - private boolean isNumeric(String str) { - try { - int result = Integer.valueOf(str); - return true; - } - catch (NumberFormatException e) { - return false; - } + return Response.ofSuccess(String.valueOf(jobInfo.getId())); } @Override - public ReturnT update(XxlJobInfo jobInfo, XxlJobUser loginUser) { + public Response update(XxlJobInfo jobInfo, LoginInfo loginInfo) { // valid base - if (jobInfo.getJobDesc() == null || jobInfo.getJobDesc().trim().length() == 0) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_jobdesc"))); + if (StringTool.isBlank(jobInfo.getJobDesc())) { + return Response.ofFail((I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_jobdesc"))); } - if (jobInfo.getAuthor() == null || jobInfo.getAuthor().trim().length() == 0) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_author"))); + if (StringTool.isBlank(jobInfo.getAuthor())) { + return Response.ofFail((I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_author"))); } // valid trigger ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null); if (scheduleTypeEnum == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("schedule_type") + I18nUtil.getString("system_invalid"))); } if (scheduleTypeEnum == ScheduleTypeEnum.CRON) { if (jobInfo.getScheduleConf() == null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) { - return new ReturnT(ReturnT.FAIL_CODE, "Cron" + I18nUtil.getString("system_unvalid")); + return Response.ofFail("Cron" + I18nUtil.getString("system_invalid")); } - } - else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE /* - * || scheduleTypeEnum == - * ScheduleTypeEnum. - * FIX_DELAY - */) { + } else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE /*|| scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) { if (jobInfo.getScheduleConf() == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("schedule_type") + I18nUtil.getString("system_invalid"))); } try { - int fixSecond = Integer.valueOf(jobInfo.getScheduleConf()); + int fixSecond = Integer.parseInt(jobInfo.getScheduleConf()); if (fixSecond < 1) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("schedule_type") + I18nUtil.getString("system_invalid"))); } - } - catch (Exception e) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } catch (Exception e) { + return Response.ofFail((I18nUtil.getString("schedule_type") + I18nUtil.getString("system_invalid"))); } } // valid advanced if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("jobinfo_field_executorRouteStrategy") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("jobinfo_field_executorRouteStrategy") + I18nUtil.getString("system_invalid"))); } if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("misfire_strategy") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("misfire_strategy") + I18nUtil.getString("system_invalid"))); } if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("jobinfo_field_executorBlockStrategy") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("jobinfo_field_executorBlockStrategy") + I18nUtil.getString("system_invalid"))); } // 》ChildJobId valid - if (jobInfo.getChildJobId() != null && jobInfo.getChildJobId().trim().length() > 0) { + if (StringTool.isNotBlank(jobInfo.getChildJobId())) { String[] childJobIds = jobInfo.getChildJobId().split(","); for (String childJobIdItem : childJobIds) { - if (childJobIdItem != null && childJobIdItem.trim().length() > 0 && isNumeric(childJobIdItem)) { + if (StringTool.isNotBlank(childJobIdItem) && StringTool.isNumeric(childJobIdItem)) { // parse child int childJobId = Integer.parseInt(childJobIdItem); if (childJobId == jobInfo.getId()) { - return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_childJobId") - + "(" + childJobId + ")" + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("jobinfo_field_childJobId") + "(" + childJobId + ")" + I18nUtil.getString("system_invalid"))); } // valid child - XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(childJobId); + XxlJobInfo childJobInfo = xxlJobInfoMapper.loadById(childJobId); if (childJobInfo == null) { - return new ReturnT(ReturnT.FAIL_CODE, - MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" - + I18nUtil.getString("system_not_found")), childJobIdItem)); + return Response.ofFail( + MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_not_found")), childJobIdItem)); } - if (!loginUser.validPermission(childJobInfo.getJobGroup())) { - return new ReturnT(ReturnT.FAIL_CODE, - MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" - + I18nUtil.getString("system_permission_limit")), childJobIdItem)); + // valid jobGroup permission + if (!JobGroupPermissionUtil.hasJobGroupPermission(loginInfo, childJobInfo.getJobGroup())) { + return Response.ofFail( + MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_permission_limit")), childJobIdItem)); } - } - else { - return new ReturnT(ReturnT.FAIL_CODE, - MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" - + I18nUtil.getString("system_unvalid")), childJobIdItem)); + } else { + return Response.ofFail( + MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_invalid")), childJobIdItem)); } } @@ -309,37 +259,32 @@ public class XxlJobServiceImpl implements XxlJobService { } // group valid - XxlJobGroup jobGroup = xxlJobGroupDao.load(jobInfo.getJobGroup()); + XxlJobGroup jobGroup = xxlJobGroupMapper.load(jobInfo.getJobGroup()); if (jobGroup == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("jobinfo_field_jobgroup") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("jobinfo_field_jobgroup") + I18nUtil.getString("system_invalid"))); } // stage job info - XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(jobInfo.getId()); + XxlJobInfo exists_jobInfo = xxlJobInfoMapper.loadById(jobInfo.getId()); if (exists_jobInfo == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_not_found"))); + return Response.ofFail((I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_not_found"))); } // next trigger time (5s后生效,避开预读周期) long nextTriggerTime = exists_jobInfo.getTriggerNextTime(); boolean scheduleDataNotChanged = jobInfo.getScheduleType().equals(exists_jobInfo.getScheduleType()) - && jobInfo.getScheduleConf().equals(exists_jobInfo.getScheduleConf()); - if (exists_jobInfo.getTriggerStatus() == 1 && !scheduleDataNotChanged) { + && jobInfo.getScheduleConf().equals(exists_jobInfo.getScheduleConf()); // 触发配置如果不变,避免重复计算; + if (exists_jobInfo.getTriggerStatus() == TriggerStatus.RUNNING.getValue() && !scheduleDataNotChanged) { try { - Date nextValidTime = JobScheduleHelper.generateNextValidTime(jobInfo, - new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS)); + // generate next trigger time + Date nextValidTime = scheduleTypeEnum.getScheduleType().generateNextTriggerTime(jobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS)); if (nextValidTime == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("schedule_type") + I18nUtil.getString("system_invalid"))); } nextTriggerTime = nextValidTime.getTime(); - } - catch (Exception e) { + } catch (Exception e) { logger.error(e.getMessage(), e); - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("schedule_type") + I18nUtil.getString("system_invalid"))); } } @@ -361,94 +306,126 @@ public class XxlJobServiceImpl implements XxlJobService { exists_jobInfo.setTriggerNextTime(nextTriggerTime); exists_jobInfo.setUpdateTime(new Date()); - xxlJobInfoDao.update(exists_jobInfo); + xxlJobInfoMapper.update(exists_jobInfo); - return ReturnT.SUCCESS; + // write operation log + logger.info(">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}", + loginInfo.getUserName(), "jobinfo-update", GsonTool.toJson(exists_jobInfo)); + + return Response.ofSuccess(); } @Override - public ReturnT remove(int id) { - XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id); + public Response remove(int id, LoginInfo loginInfo) { + // valid job + XxlJobInfo xxlJobInfo = xxlJobInfoMapper.loadById(id); if (xxlJobInfo == null) { - return ReturnT.SUCCESS; + return Response.ofSuccess(); } - xxlJobInfoDao.delete(id); - xxlJobLogDao.delete(id); - xxlJobLogGlueDao.deleteByJobId(id); - return ReturnT.SUCCESS; + // valid jobGroup permission + if (!JobGroupPermissionUtil.hasJobGroupPermission(loginInfo, xxlJobInfo.getJobGroup())) { + return Response.ofFail(I18nUtil.getString("system_permission_limit")); + } + + xxlJobInfoMapper.delete(id); + xxlJobLogMapper.delete(id); + xxlJobLogGlueMapper.deleteByJobId(id); + + // write operation log + logger.info(">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}", + loginInfo.getUserName(), "jobinfo-remove", id); + + return Response.ofSuccess(); } @Override - public ReturnT start(int id) { + public Response start(int id, LoginInfo loginInfo) { // load and valid - XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id); + XxlJobInfo xxlJobInfo = xxlJobInfoMapper.loadById(id); if (xxlJobInfo == null) { - return new ReturnT(ReturnT.FAIL.getCode(), I18nUtil.getString("jobinfo_glue_jobid_unvalid")); + return Response.ofFail(I18nUtil.getString("jobinfo_glue_jobid_invalid")); } - // valid + // valid jobGroup permission + if (!JobGroupPermissionUtil.hasJobGroupPermission(loginInfo, xxlJobInfo.getJobGroup())) { + return Response.ofFail(I18nUtil.getString("system_permission_limit")); + } + + // valid ScheduleType: can not be none ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(xxlJobInfo.getScheduleType(), ScheduleTypeEnum.NONE); if (ScheduleTypeEnum.NONE == scheduleTypeEnum) { - return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type_none_limit_start"))); + return Response.ofFail(I18nUtil.getString("schedule_type_none_limit_start")); } // next trigger time (5s后生效,避开预读周期) long nextTriggerTime = 0; try { - Date nextValidTime = JobScheduleHelper.generateNextValidTime(xxlJobInfo, - new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS)); + // generate next trigger time + Date nextValidTime = scheduleTypeEnum.getScheduleType().generateNextTriggerTime(xxlJobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS)); + if (nextValidTime == null) { - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("schedule_type") + I18nUtil.getString("system_invalid"))); } nextTriggerTime = nextValidTime.getTime(); - } - catch (Exception e) { + } catch (Exception e) { logger.error(e.getMessage(), e); - return new ReturnT(ReturnT.FAIL_CODE, - (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + return Response.ofFail((I18nUtil.getString("schedule_type") + I18nUtil.getString("system_invalid"))); } - xxlJobInfo.setTriggerStatus(1); + xxlJobInfo.setTriggerStatus(TriggerStatus.RUNNING.getValue()); xxlJobInfo.setTriggerLastTime(0); xxlJobInfo.setTriggerNextTime(nextTriggerTime); xxlJobInfo.setUpdateTime(new Date()); - xxlJobInfoDao.update(xxlJobInfo); - return ReturnT.SUCCESS; + xxlJobInfoMapper.update(xxlJobInfo); + + // write operation log + logger.info(">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}", + loginInfo.getUserName(), "jobinfo-start", id); + + return Response.ofSuccess(); } @Override - public ReturnT stop(int id) { + public Response stop(int id, LoginInfo loginInfo) { // load and valid - XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id); + XxlJobInfo xxlJobInfo = xxlJobInfoMapper.loadById(id); if (xxlJobInfo == null) { - return new ReturnT(ReturnT.FAIL.getCode(), I18nUtil.getString("jobinfo_glue_jobid_unvalid")); + return Response.ofFail(I18nUtil.getString("jobinfo_glue_jobid_invalid")); + } + + // valid jobGroup permission + if (!JobGroupPermissionUtil.hasJobGroupPermission(loginInfo, xxlJobInfo.getJobGroup())) { + return Response.ofFail(I18nUtil.getString("system_permission_limit")); } // stop - xxlJobInfo.setTriggerStatus(0); + xxlJobInfo.setTriggerStatus(TriggerStatus.STOPPED.getValue()); xxlJobInfo.setTriggerLastTime(0); xxlJobInfo.setTriggerNextTime(0); xxlJobInfo.setUpdateTime(new Date()); - xxlJobInfoDao.update(xxlJobInfo); - return ReturnT.SUCCESS; + xxlJobInfoMapper.update(xxlJobInfo); + + // write operation log + logger.info(">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}", + loginInfo.getUserName(), "jobinfo-stop", id); + + return Response.ofSuccess(); } @Override - public ReturnT trigger(XxlJobUser loginUser, int jobId, String executorParam, String addressList) { - // permission - if (loginUser == null) { - return new ReturnT(ReturnT.FAIL.getCode(), I18nUtil.getString("system_permission_limit")); - } - XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(jobId); + public Response trigger(LoginInfo loginInfo, int jobId, String executorParam, String addressList) { + // valid job + XxlJobInfo xxlJobInfo = xxlJobInfoMapper.loadById(jobId); if (xxlJobInfo == null) { - return new ReturnT(ReturnT.FAIL.getCode(), I18nUtil.getString("jobinfo_glue_jobid_unvalid")); + return Response.ofFail(I18nUtil.getString("jobinfo_glue_jobid_invalid")); } - if (!hasPermission(loginUser, xxlJobInfo.getJobGroup())) { - return new ReturnT(ReturnT.FAIL.getCode(), I18nUtil.getString("system_permission_limit")); + + // valid jobGroup permission + if (!JobGroupPermissionUtil.hasJobGroupPermission(loginInfo, xxlJobInfo.getJobGroup())) { + return Response.ofFail(I18nUtil.getString("system_permission_limit")); } // force cover job param @@ -456,37 +433,30 @@ public class XxlJobServiceImpl implements XxlJobService { executorParam = ""; } - JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList); - return ReturnT.SUCCESS; - } + XxlJobAdminBootstrap.getInstance().getJobTriggerPoolHelper().trigger(jobId, TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList); - private boolean hasPermission(XxlJobUser loginUser, int jobGroup) { - if (loginUser.getRole() == 1) { - return true; - } - List groupIdStrs = new ArrayList<>(); - if (loginUser.getPermission() != null && loginUser.getPermission().trim().length() > 0) { - groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(",")); - } - return groupIdStrs.contains(String.valueOf(jobGroup)); + // write operation log + logger.info(">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}", + loginInfo.getUserName(), "jobinfo-trigger", jobId); + + return Response.ofSuccess(); } @Override public Map dashboardInfo() { - int jobInfoCount = xxlJobInfoDao.findAllCount(); + int jobInfoCount = xxlJobInfoMapper.findAllCount(); int jobLogCount = 0; int jobLogSuccessCount = 0; - XxlJobLogReport xxlJobLogReport = xxlJobLogReportDao.queryLogReportTotal(); + XxlJobLogReport xxlJobLogReport = xxlJobLogReportMapper.queryLogReportTotal(); if (xxlJobLogReport != null) { - jobLogCount = xxlJobLogReport.getRunningCount() + xxlJobLogReport.getSucCount() - + xxlJobLogReport.getFailCount(); + jobLogCount = xxlJobLogReport.getRunningCount() + xxlJobLogReport.getSucCount() + xxlJobLogReport.getFailCount(); jobLogSuccessCount = xxlJobLogReport.getSucCount(); } // executor count Set executorAddressSet = new HashSet(); - List groupList = xxlJobGroupDao.findAll(); + List groupList = xxlJobGroupMapper.findAll(); if (groupList != null && !groupList.isEmpty()) { for (XxlJobGroup group : groupList) { @@ -507,7 +477,7 @@ public class XxlJobServiceImpl implements XxlJobService { } @Override - public ReturnT> chartInfo(Date startDate, Date endDate) { + public Response> chartInfo(Date startDate, Date endDate) { // process List triggerDayList = new ArrayList(); @@ -518,11 +488,11 @@ public class XxlJobServiceImpl implements XxlJobService { int triggerCountSucTotal = 0; int triggerCountFailTotal = 0; - List logReportList = xxlJobLogReportDao.queryLogReport(startDate, endDate); + List logReportList = xxlJobLogReportMapper.queryLogReport(startDate, endDate); - if (logReportList != null && logReportList.size() > 0) { + if (logReportList != null && !logReportList.isEmpty()) { for (XxlJobLogReport item : logReportList) { - String day = DateUtil.formatDate(item.getTriggerDay()); + String day = DateTool.formatDate(item.getTriggerDay()); int triggerDayCountRunning = item.getRunningCount(); int triggerDayCountSuc = item.getSucCount(); int triggerDayCountFail = item.getFailCount(); @@ -536,10 +506,9 @@ public class XxlJobServiceImpl implements XxlJobService { triggerCountSucTotal += triggerDayCountSuc; triggerCountFailTotal += triggerDayCountFail; } - } - else { + } else { for (int i = -6; i <= 0; i++) { - triggerDayList.add(DateUtil.formatDate(DateUtil.addDays(new Date(), i))); + triggerDayList.add(DateTool.formatDate(DateTool.addDays(new Date(), i))); triggerDayCountRunningList.add(0); triggerDayCountSucList.add(0); triggerDayCountFailList.add(0); @@ -556,7 +525,7 @@ public class XxlJobServiceImpl implements XxlJobService { result.put("triggerCountSucTotal", triggerCountSucTotal); result.put("triggerCountFailTotal", triggerCountFailTotal); - return new ReturnT>(result); + return Response.ofSuccess(result); } } diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/I18nUtil.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/I18nUtil.java new file mode 100644 index 000000000..3a9891b11 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/I18nUtil.java @@ -0,0 +1,133 @@ +package com.xxl.job.admin.util; + +import com.xxl.job.core.constant.ExecutorBlockStrategyEnum; +import com.xxl.tool.core.PropTool; +import com.xxl.tool.freemarker.FtlTool; +import com.xxl.tool.json.GsonTool; +import freemarker.template.Configuration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * i18n util + * + * @author xuxueli 2018-01-17 20:39:06 + */ +@Component +public class I18nUtil implements InitializingBean { + private static Logger logger = LoggerFactory.getLogger(I18nUtil.class); + + // ---------------------- for i18n config ---------------------- + + /** + * i18n config + */ + @Value("${xxl.job.i18n}") + private String i18n; + + /** + * freemarker config + */ + @Autowired + private Configuration configuration; + + @Override + public void afterPropertiesSet() throws Exception { + // init freemarker shared variable + configuration.setSharedVariable("I18nUtil", FtlTool.generateStaticModel(I18nUtil.class.getName())); + // init single + single = this; + + // init i18n-enum + initI18nEnum(); + } + + /** + * get i18n + */ + public String getI18n() { + if (!Arrays.asList("zh_CN", "zh_TC", "en").contains(i18n)) { + return "zh_CN"; + } + return i18n; + } + + private static I18nUtil single = null; + + private static I18nUtil getSingle() { + return single; + } + + // ---------------------- tool ---------------------- + + private static Properties prop = null; + + public static Properties loadI18nProp() { + if (prop != null) { + return prop; + } + // build i18n filepath + String i18n = getSingle().getI18n(); + String i18nFile = MessageFormat.format("i18n/message_{0}.properties", i18n); + + // load prop + prop = PropTool.loadProp(i18nFile); + return prop; + } + + /** + * get val of i18n key + * + * @param key + * @return + */ + public static String getString(String key) { + return loadI18nProp().getProperty(key); + } + + /** + * get mult val of i18n mult key, as json + * + * @param keys + * @return + */ + public static String getMultString(String... keys) { + Map map = new HashMap<>(); + + Properties prop = loadI18nProp(); + if (keys != null && keys.length > 0) { + for (String key : keys) { + map.put(key, prop.getProperty(key)); + } + } else { + for (String key : prop.stringPropertyNames()) { + map.put(key, prop.getProperty(key)); + } + } + + return GsonTool.toJson(map); + } + + + // ---------------------- init I18n-enum ---------------------- + + /** + * init i18n-enum + */ + private void initI18nEnum() { + for (ExecutorBlockStrategyEnum item : ExecutorBlockStrategyEnum.values()) { + item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name()))); + } + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/JobGroupPermissionUtil.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/JobGroupPermissionUtil.java new file mode 100644 index 000000000..527a36a74 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/JobGroupPermissionUtil.java @@ -0,0 +1,67 @@ +package com.xxl.job.admin.util; + +import com.xxl.job.admin.constant.Consts; +import com.xxl.job.admin.model.XxlJobGroup; +import com.xxl.sso.core.helper.XxlSsoHelper; +import com.xxl.sso.core.model.LoginInfo; +import com.xxl.tool.core.StringTool; +import com.xxl.tool.response.Response; +import jakarta.servlet.http.HttpServletRequest; + +import java.util.ArrayList; +import java.util.List; + +/** + * jobGroup permission util + * + * @author xuxueli 2025-08-24 + */ +public class JobGroupPermissionUtil { + + /** + * check if has jobgroup permission + */ + public static boolean hasJobGroupPermission(LoginInfo loginInfo, int jobGroup) { + if (XxlSsoHelper.hasRole(loginInfo, Consts.ADMIN_ROLE).isSuccess()) { + return true; + } else { + List jobGroups = (loginInfo.getExtraInfo() != null && loginInfo.getExtraInfo().containsKey("jobGroups")) + ? StringTool.split(loginInfo.getExtraInfo().get("jobGroups"), ",") : new ArrayList<>(); + return jobGroups.contains(String.valueOf(jobGroup)); + } + } + + /** + * valid jobGroup permission + */ + public static LoginInfo validJobGroupPermission(HttpServletRequest request, int jobGroup) { + Response loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request); + if (!(loginInfoResponse.isSuccess() && hasJobGroupPermission(loginInfoResponse.getData(), jobGroup))) { + throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username=" + loginInfoResponse.getData().getUserName() + "]"); + } + return loginInfoResponse.getData(); + } + + /** + * filter jobGroupList by permission + */ + public static List filterJobGroupByPermission(HttpServletRequest request, List jobGroupListTotal) { + Response loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request); + + if (XxlSsoHelper.hasRole(loginInfoResponse.getData(), Consts.ADMIN_ROLE).isSuccess()) { + return jobGroupListTotal; + } else { + List jobGroups = (loginInfoResponse.getData().getExtraInfo() != null + && loginInfoResponse.getData().getExtraInfo().get("jobGroups") != null + ) + ? StringTool.split(loginInfoResponse.getData().getExtraInfo().get("jobGroups"), ",") + : new ArrayList<>(); + + return jobGroupListTotal + .stream() + .filter(jobGroup -> jobGroups.contains(String.valueOf(jobGroup.getId()))) + .toList(); + } + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/CommonDataInterceptor.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/CommonDataInterceptor.java new file mode 100644 index 000000000..d2a9a3fe0 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/CommonDataInterceptor.java @@ -0,0 +1,39 @@ +//package com.xxl.job.admin.web.interceptor; +// +//import com.xxl.job.admin.util.I18nUtil; +//import com.xxl.tool.freemarker.FtlTool; +//import jakarta.servlet.http.HttpServletRequest; +//import jakarta.servlet.http.HttpServletResponse; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.web.servlet.AsyncHandlerInterceptor; +//import org.springframework.web.servlet.ModelAndView; +//import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +//import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +// +/// ** +// * push cookies to model as cookieMap +// * +// * @author xuxueli 2015-12-12 18:09:04 +// */ +//@Configuration +//public class CommonDataInterceptor implements WebMvcConfigurer { +// +// @Override +// public void addInterceptors(InterceptorRegistry registry) { +// registry.addInterceptor(new AsyncHandlerInterceptor() { +// @Override +// public void postHandle(HttpServletRequest request, +// HttpServletResponse response, +// Object handler, +// ModelAndView modelAndView) throws Exception { +// +// // static method +// if (modelAndView != null) { +// modelAndView.addObject("I18nUtil", FtlTool.generateStaticModel(I18nUtil.class.getName())); +// } +// +// } +// }).addPathPatterns("/**"); +// } +// +//} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/CookieUtil.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/CookieUtil.java new file mode 100644 index 000000000..cd568ac5c --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/CookieUtil.java @@ -0,0 +1,98 @@ +//package com.xxl.job.admin.util; +// +//import jakarta.servlet.http.Cookie; +//import jakarta.servlet.http.HttpServletRequest; +//import jakarta.servlet.http.HttpServletResponse; +// +/// ** +// * Cookie.Util +// * +// * @author xuxueli 2015-12-12 18:01:06 +// */ +//public class CookieUtil { +// +// // 默认缓存时间,单位/秒, 2H +// private static final int COOKIE_MAX_AGE = Integer.MAX_VALUE; +// // 保存路径,根路径 +// private static final String COOKIE_PATH = "/"; +// +// /** +// * 保存 +// * +// * @param response +// * @param key +// * @param value +// * @param ifRemember +// */ +// public static void set(HttpServletResponse response, String key, String value, boolean ifRemember) { +// int age = ifRemember?COOKIE_MAX_AGE:-1; +// set(response, key, value, null, COOKIE_PATH, age, true); +// } +// +// /** +// * 保存 +// * +// * @param response +// * @param key +// * @param value +// * @param maxAge +// */ +// private static void set(HttpServletResponse response, String key, String value, String domain, String path, int maxAge, boolean isHttpOnly) { +// Cookie cookie = new Cookie(key, value); +// if (domain != null) { +// cookie.setDomain(domain); +// } +// cookie.setPath(path); +// cookie.setMaxAge(maxAge); +// cookie.setHttpOnly(isHttpOnly); +// response.addCookie(cookie); +// } +// +// /** +// * 查询value +// * +// * @param request +// * @param key +// * @return +// */ +// public static String getValue(HttpServletRequest request, String key) { +// Cookie cookie = get(request, key); +// if (cookie != null) { +// return cookie.getValue(); +// } +// return null; +// } +// +// /** +// * 查询Cookie +// * +// * @param request +// * @param key +// */ +// private static Cookie get(HttpServletRequest request, String key) { +// Cookie[] arr_cookie = request.getCookies(); +// if (arr_cookie != null && arr_cookie.length > 0) { +// for (Cookie cookie : arr_cookie) { +// if (cookie.getName().equals(key)) { +// return cookie; +// } +// } +// } +// return null; +// } +// +// /** +// * 删除Cookie +// * +// * @param request +// * @param response +// * @param key +// */ +// public static void remove(HttpServletRequest request, HttpServletResponse response, String key) { +// Cookie cookie = get(request, key); +// if (cookie != null) { +// set(response, key, "", null, COOKIE_PATH, 0, true); +// } +// } +// +//} \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/FtlUtil.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/FtlUtil.java new file mode 100644 index 000000000..4f05871d8 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/FtlUtil.java @@ -0,0 +1,31 @@ +//package com.xxl.job.admin.util; +// +//import freemarker.ext.beans.BeansWrapper; +//import freemarker.ext.beans.BeansWrapperBuilder; +//import freemarker.template.Configuration; +//import freemarker.template.TemplateHashModel; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +/// ** +// * ftl util +// * +// * @author xuxueli 2018-01-17 20:37:48 +// */ +//public class FtlUtil { +// private static Logger logger = LoggerFactory.getLogger(FtlUtil.class); +// +// private static BeansWrapper wrapper = new BeansWrapperBuilder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS).build(); //BeansWrapper.getDefaultInstance(); +// +// public static TemplateHashModel generateStaticModel(String packageName) { +// try { +// TemplateHashModel staticModels = wrapper.getStaticModels(); +// TemplateHashModel fileStatics = (TemplateHashModel) staticModels.get(packageName); +// return fileStatics; +// } catch (Exception e) { +// logger.error(e.getMessage(), e); +// } +// return null; +// } +// +//} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/JacksonUtil.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/JacksonUtil.java new file mode 100644 index 000000000..1918c3a97 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/JacksonUtil.java @@ -0,0 +1,92 @@ +//package com.xxl.job.admin.util.old; +// +//import com.fasterxml.jackson.core.JsonGenerationException; +//import com.fasterxml.jackson.core.JsonParseException; +//import com.fasterxml.jackson.databind.JavaType; +//import com.fasterxml.jackson.databind.JsonMappingException; +//import com.fasterxml.jackson.databind.ObjectMapper; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import java.io.IOException; +// +/// ** +// * Jackson util +// * +// * 1、obj need private and set/get; +// * 2、do not support inner class; +// * +// * @author xuxueli 2015-9-25 18:02:56 +// */ +//public class JacksonUtil { +// private static Logger logger = LoggerFactory.getLogger(JacksonUtil.class); +// +// private final static ObjectMapper objectMapper = new ObjectMapper(); +// public static ObjectMapper getInstance() { +// return objectMapper; +// } +// +// /** +// * bean、array、List、Map --> json +// * +// * @param obj +// * @return json string +// * @throws Exception +// */ +// public static String writeValueAsString(Object obj) { +// try { +// return getInstance().writeValueAsString(obj); +// } catch (JsonGenerationException e) { +// logger.error(e.getMessage(), e); +// } catch (JsonMappingException e) { +// logger.error(e.getMessage(), e); +// } catch (IOException e) { +// logger.error(e.getMessage(), e); +// } +// return null; +// } +// +// /** +// * string --> bean、Map、List(array) +// * +// * @param jsonStr +// * @param clazz +// * @return obj +// * @throws Exception +// */ +// public static T readValue(String jsonStr, Class clazz) { +// try { +// return getInstance().readValue(jsonStr, clazz); +// } catch (JsonParseException e) { +// logger.error(e.getMessage(), e); +// } catch (JsonMappingException e) { +// logger.error(e.getMessage(), e); +// } catch (IOException e) { +// logger.error(e.getMessage(), e); +// } +// return null; +// } +// +// /** +// * string --> List... +// * +// * @param jsonStr +// * @param parametrized +// * @param parameterClasses +// * @param +// * @return +// */ +// public static T readValue(String jsonStr, Class parametrized, Class... parameterClasses) { +// try { +// JavaType javaType = getInstance().getTypeFactory().constructParametricType(parametrized, parameterClasses); +// return getInstance().readValue(jsonStr, javaType); +// } catch (JsonParseException e) { +// logger.error(e.getMessage(), e); +// } catch (JsonMappingException e) { +// logger.error(e.getMessage(), e); +// } catch (IOException e) { +// logger.error(e.getMessage(), e); +// } +// return null; +// } +//} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/LocalCacheUtil.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/LocalCacheUtil.java new file mode 100644 index 000000000..3c25a5092 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/LocalCacheUtil.java @@ -0,0 +1,133 @@ +//package com.xxl.job.admin.util; +// +//import java.util.concurrent.ConcurrentHashMap; +//import java.util.concurrent.ConcurrentMap; +// +/// ** +// * local cache tool +// * +// * @author xuxueli 2018-01-22 21:37:34 +// */ +//public class LocalCacheUtil { +// +// private static ConcurrentMap cacheRepository = new ConcurrentHashMap(); // 类型建议用抽象父类,兼容性更好; +// private static class LocalCacheData{ +// private String key; +// private Object val; +// private long timeoutTime; +// +// public LocalCacheData() { +// } +// +// public LocalCacheData(String key, Object val, long timeoutTime) { +// this.key = key; +// this.val = val; +// this.timeoutTime = timeoutTime; +// } +// +// public String getKey() { +// return key; +// } +// +// public void setKey(String key) { +// this.key = key; +// } +// +// public Object getVal() { +// return val; +// } +// +// public void setVal(Object val) { +// this.val = val; +// } +// +// public long getTimeoutTime() { +// return timeoutTime; +// } +// +// public void setTimeoutTime(long timeoutTime) { +// this.timeoutTime = timeoutTime; +// } +// } +// +// +// /** +// * set cache +// * +// * @param key +// * @param val +// * @param cacheTime +// * @return +// */ +// public static boolean set(String key, Object val, long cacheTime){ +// +// // clean timeout cache, before set new cache (avoid cache too much) +// cleanTimeoutCache(); +// +// // set new cache +// if (key==null || key.trim().length()==0) { +// return false; +// } +// if (val == null) { +// remove(key); +// } +// if (cacheTime <= 0) { +// remove(key); +// } +// long timeoutTime = System.currentTimeMillis() + cacheTime; +// LocalCacheData localCacheData = new LocalCacheData(key, val, timeoutTime); +// cacheRepository.put(localCacheData.getKey(), localCacheData); +// return true; +// } +// +// /** +// * remove cache +// * +// * @param key +// * @return +// */ +// public static boolean remove(String key){ +// if (key==null || key.trim().length()==0) { +// return false; +// } +// cacheRepository.remove(key); +// return true; +// } +// +// /** +// * get cache +// * +// * @param key +// * @return +// */ +// public static Object get(String key){ +// if (key==null || key.trim().length()==0) { +// return null; +// } +// LocalCacheData localCacheData = cacheRepository.get(key); +// if (localCacheData!=null && System.currentTimeMillis()=localCacheData.getTimeoutTime()) { +// cacheRepository.remove(key); +// } +// } +// } +// return true; +// } +// +//} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/RemoteHttpJobBean.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/RemoteHttpJobBean.java new file mode 100644 index 000000000..15d723afd --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/RemoteHttpJobBean.java @@ -0,0 +1,32 @@ +//package com.xxl.job.admin.core.jobbean; +// +//import com.xxl.job.admin.core.thread.JobTriggerPoolHelper; +//import com.xxl.job.admin.core.trigger.TriggerTypeEnum; +//import org.quartz.JobExecutionContext; +//import org.quartz.JobExecutionException; +//import org.quartz.JobKey; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.springframework.scheduling.quartz.QuartzJobBean; +// +/// ** +// * http job bean +// * “@DisallowConcurrentExecution” disable concurrent, thread size can not be only one, better given more +// * @author xuxueli 2015-12-17 18:20:34 +// */ +/// /@DisallowConcurrentExecution +//public class RemoteHttpJobBean extends QuartzJobBean { +// private static Logger logger = LoggerFactory.getLogger(RemoteHttpJobBean.class); +// +// @Override +// protected void executeInternal(JobExecutionContext context) +// throws JobExecutionException { +// +// // load jobId +// JobKey jobKey = context.getTrigger().getJobKey(); +// Integer jobId = Integer.valueOf(jobKey.getName()); +// +// +// } +// +//} \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/XxlJobDynamicScheduler.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/XxlJobDynamicScheduler.java new file mode 100644 index 000000000..a050f21ae --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/XxlJobDynamicScheduler.java @@ -0,0 +1,413 @@ +//package com.xxl.job.admin.core.schedule; +// +//import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +//import com.xxl.job.admin.core.jobbean.RemoteHttpJobBean; +//import com.xxl.job.admin.core.model.XxlJobInfo; +//import com.xxl.job.admin.core.thread.JobFailMonitorHelper; +//import com.xxl.job.admin.core.thread.JobRegistryMonitorHelper; +//import com.xxl.job.admin.core.thread.JobTriggerPoolHelper; +//import com.xxl.job.admin.core.util.I18nUtil; +//import com.xxl.job.core.biz.AdminBiz; +//import com.xxl.job.core.biz.ExecutorBiz; +//import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; +//import com.xxl.rpc.remoting.invoker.XxlRpcInvokerFactory; +//import com.xxl.rpc.remoting.invoker.call.CallType; +//import com.xxl.rpc.remoting.invoker.reference.XxlRpcReferenceBean; +//import com.xxl.rpc.remoting.invoker.route.LoadBalance; +//import com.xxl.rpc.remoting.net.NetEnum; +//import com.xxl.rpc.remoting.net.impl.servlet.server.ServletServerHandler; +//import com.xxl.rpc.remoting.provider.XxlRpcProviderFactory; +//import com.xxl.rpc.serialize.Serializer; +//import org.quartz.*; +//import org.quartz.Trigger.TriggerState; +//import org.quartz.impl.triggers.CronTriggerImpl; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.springframework.util.Assert; +// +//import javax.servlet.ServletException; +//import javax.servlet.http.HttpServletRequest; +//import javax.servlet.http.HttpServletResponse; +//import java.io.IOException; +//import java.util.Date; +//import java.util.concurrent.ConcurrentHashMap; +// +/// ** +// * base quartz scheduler util +// * @author xuxueli 2015-12-19 16:13:53 +// */ +//public final class XxlJobDynamicScheduler { +// private static final Logger logger = LoggerFactory.getLogger(XxlJobDynamicScheduler_old.class); +// +// // ---------------------- param ---------------------- +// +// // scheduler +// private static Scheduler scheduler; +// public void setScheduler(Scheduler scheduler) { +// XxlJobDynamicScheduler_old.scheduler = scheduler; +// } +// +// +// // ---------------------- init + destroy ---------------------- +// public void start() throws Exception { +// // valid +// Assert.notNull(scheduler, "quartz scheduler is null"); +// +// // init i18n +// initI18n(); +// +// // admin registry monitor run +// JobRegistryMonitorHelper.getInstance().start(); +// +// // admin monitor run +// JobFailMonitorHelper.getInstance().start(); +// +// // admin-server +// initRpcProvider(); +// +// logger.info(">>>>>>>>> init xxl-job admin success."); +// } +// +// +// public void destroy() throws Exception { +// // admin trigger pool stop +// JobTriggerPoolHelper.toStop(); +// +// // admin registry stop +// JobRegistryMonitorHelper.getInstance().toStop(); +// +// // admin monitor stop +// JobFailMonitorHelper.getInstance().toStop(); +// +// // admin-server +// stopRpcProvider(); +// } +// +// +// // ---------------------- I18n ---------------------- +// +// private void initI18n(){ +// for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) { +// item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name()))); +// } +// } +// +// +// // ---------------------- admin rpc provider (no server version) ---------------------- +// private static ServletServerHandler servletServerHandler; +// private void initRpcProvider(){ +// // init +// XxlRpcProviderFactory xxlRpcProviderFactory = new XxlRpcProviderFactory(); +// xxlRpcProviderFactory.initConfig( +// NetEnum.NETTY_HTTP, +// Serializer.SerializeEnum.HESSIAN.getSerializer(), +// null, +// 0, +// XxlJobAdminConfig.getAdminConfig().getAccessToken(), +// null, +// null); +// +// // add services +// xxlRpcProviderFactory.addService(AdminBiz.class.getName(), null, XxlJobAdminConfig.getAdminConfig().getAdminBiz()); +// +// // servlet handler +// servletServerHandler = new ServletServerHandler(xxlRpcProviderFactory); +// } +// private void stopRpcProvider() throws Exception { +// XxlRpcInvokerFactory.getInstance().stop(); +// } +// public static void invokeAdminService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { +// servletServerHandler.handle(null, request, response); +// } +// +// +// // ---------------------- executor-client ---------------------- +// private static ConcurrentHashMap executorBizRepository = new ConcurrentHashMap(); +// public static ExecutorBiz getExecutorBiz(String address) throws Exception { +// // valid +// if (address==null || address.trim().length()==0) { +// return null; +// } +// +// // load-cache +// address = address.trim(); +// ExecutorBiz executorBiz = executorBizRepository.get(address); +// if (executorBiz != null) { +// return executorBiz; +// } +// +// // set-cache +// executorBiz = (ExecutorBiz) new XxlRpcReferenceBean( +// NetEnum.NETTY_HTTP, +// Serializer.SerializeEnum.HESSIAN.getSerializer(), +// CallType.SYNC, +// LoadBalance.ROUND, +// ExecutorBiz.class, +// null, +// 5000, +// address, +// XxlJobAdminConfig.getAdminConfig().getAccessToken(), +// null, +// null).getObject(); +// +// executorBizRepository.put(address, executorBiz); +// return executorBiz; +// } +// +// +// // ---------------------- schedule util ---------------------- +// +// /** +// * fill job info +// * +// * @param jobInfo +// */ +// public static void fillJobInfo(XxlJobInfo jobInfo) { +// +// String name = String.valueOf(jobInfo.getId()); +// +// // trigger key +// TriggerKey triggerKey = TriggerKey.triggerKey(name); +// try { +// +// // trigger cron +// Trigger trigger = scheduler.getTrigger(triggerKey); +// if (trigger!=null && trigger instanceof CronTriggerImpl) { +// String cronExpression = ((CronTriggerImpl) trigger).getCronExpression(); +// jobInfo.setJobCron(cronExpression); +// } +// +// // trigger state +// TriggerState triggerState = scheduler.getTriggerState(triggerKey); +// if (triggerState!=null) { +// jobInfo.setJobStatus(triggerState.name()); +// } +// +// //JobKey jobKey = new JobKey(jobInfo.getJobName(), String.valueOf(jobInfo.getJobGroup())); +// //JobDetail jobDetail = scheduler.getJobDetail(jobKey); +// //String jobClass = jobDetail.getJobClass().getName(); +// +// } catch (SchedulerException e) { +// logger.error(e.getMessage(), e); +// } +// } +// +// +// /** +// * add trigger + job +// * +// * @param jobName +// * @param cronExpression +// * @return +// * @throws SchedulerException +// */ +// public static boolean addJob(String jobName, String cronExpression) throws SchedulerException { +// // 1、job key +// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); +// JobKey jobKey = new JobKey(jobName); +// +// // 2、valid +// if (scheduler.checkExists(triggerKey)) { +// return true; // PASS +// } +// +// // 3、corn trigger +// CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing(); // withMisfireHandlingInstructionDoNothing 忽略掉调度终止过程中忽略的调度 +// CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build(); +// +// // 4、job detail +// Class jobClass_ = RemoteHttpJobBean.class; // Class.forName(jobInfo.getJobClass()); +// JobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).build(); +// +// /*if (jobInfo.getJobData()!=null) { +// JobDataMap jobDataMap = jobDetail.getJobDataMap(); +// jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class)); +// // JobExecutionContext context.getMergedJobDataMap().get("mailGuid"); +// }*/ +// +// // 5、schedule job +// Date date = scheduler.scheduleJob(jobDetail, cronTrigger); +// +// logger.info(">>>>>>>>>>> addJob success(quartz), jobDetail:{}, cronTrigger:{}, date:{}", jobDetail, cronTrigger, date); +// return true; +// } +// +// +// /** +// * remove trigger + job +// * +// * @param jobName +// * @return +// * @throws SchedulerException +// */ +// public static boolean removeJob(String jobName) throws SchedulerException { +// +// JobKey jobKey = new JobKey(jobName); +// scheduler.deleteJob(jobKey); +// +// /*TriggerKey triggerKey = TriggerKey.triggerKey(jobName); +// if (scheduler.checkExists(triggerKey)) { +// scheduler.unscheduleJob(triggerKey); // trigger + job +// }*/ +// +// logger.info(">>>>>>>>>>> removeJob success(quartz), jobKey:{}", jobKey); +// return true; +// } +// +// +// /** +// * updateJobCron +// * +// * @param jobName +// * @param cronExpression +// * @return +// * @throws SchedulerException +// */ +// public static boolean updateJobCron(String jobName, String cronExpression) throws SchedulerException { +// +// // 1、job key +// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); +// +// // 2、valid +// if (!scheduler.checkExists(triggerKey)) { +// return true; // PASS +// } +// +// CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); +// +// // 3、avoid repeat cron +// String oldCron = oldTrigger.getCronExpression(); +// if (oldCron.equals(cronExpression)){ +// return true; // PASS +// } +// +// // 4、new cron trigger +// CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing(); +// oldTrigger = oldTrigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build(); +// +// // 5、rescheduleJob +// scheduler.rescheduleJob(triggerKey, oldTrigger); +// +// /* +// JobKey jobKey = new JobKey(jobName); +// +// // old job detail +// JobDetail jobDetail = scheduler.getJobDetail(jobKey); +// +// // new trigger +// HashSet triggerSet = new HashSet(); +// triggerSet.add(cronTrigger); +// // cover trigger of job detail +// scheduler.scheduleJob(jobDetail, triggerSet, true);*/ +// +// logger.info(">>>>>>>>>>> resumeJob success, JobName:{}", jobName); +// return true; +// } +// +// +// /** +// * pause +// * +// * @param jobName +// * @return +// * @throws SchedulerException +// */ +// /*public static boolean pauseJob(String jobName) throws SchedulerException { +// +// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); +// +// boolean result = false; +// if (scheduler.checkExists(triggerKey)) { +// scheduler.pauseTrigger(triggerKey); +// result = true; +// } +// +// logger.info(">>>>>>>>>>> pauseJob {}, triggerKey:{}", (result?"success":"fail"),triggerKey); +// return result; +// }*/ +// +// +// /** +// * resume +// * +// * @param jobName +// * @return +// * @throws SchedulerException +// */ +// /*public static boolean resumeJob(String jobName) throws SchedulerException { +// +// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); +// +// boolean result = false; +// if (scheduler.checkExists(triggerKey)) { +// scheduler.resumeTrigger(triggerKey); +// result = true; +// } +// +// logger.info(">>>>>>>>>>> resumeJob {}, triggerKey:{}", (result?"success":"fail"), triggerKey); +// return result; +// }*/ +// +// +// /** +// * run +// * +// * @param jobName +// * @return +// * @throws SchedulerException +// */ +// /*public static boolean triggerJob(String jobName) throws SchedulerException { +// // TriggerKey : name + group +// JobKey jobKey = new JobKey(jobName); +// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); +// +// boolean result = false; +// if (scheduler.checkExists(triggerKey)) { +// scheduler.triggerJob(jobKey); +// result = true; +// logger.info(">>>>>>>>>>> runJob success, jobKey:{}", jobKey); +// } else { +// logger.info(">>>>>>>>>>> runJob fail, jobKey:{}", jobKey); +// } +// return result; +// }*/ +// +// +// /** +// * finaAllJobList +// * +// * @return +// *//* +// @Deprecated +// public static List> finaAllJobList(){ +// List> jobList = new ArrayList>(); +// +// try { +// if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) { +// return null; +// } +// String groupName = scheduler.getJobGroupNames().get(0); +// Set jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName)); +// if (jobKeys!=null && jobKeys.size()>0) { +// for (JobKey jobKey : jobKeys) { +// TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), Scheduler.DEFAULT_GROUP); +// Trigger trigger = scheduler.getTrigger(triggerKey); +// JobDetail jobDetail = scheduler.getJobDetail(jobKey); +// TriggerState triggerState = scheduler.getTriggerState(triggerKey); +// Map jobMap = new HashMap(); +// jobMap.put("TriggerKey", triggerKey); +// jobMap.put("Trigger", trigger); +// jobMap.put("JobDetail", jobDetail); +// jobMap.put("TriggerState", triggerState); +// jobList.add(jobMap); +// } +// } +// +// } catch (SchedulerException e) { +// logger.error(e.getMessage(), e); +// return null; +// } +// return jobList; +// }*/ +// +//} \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/XxlJobThreadPool.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/XxlJobThreadPool.java new file mode 100644 index 000000000..8420b9983 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/XxlJobThreadPool.java @@ -0,0 +1,58 @@ +//package com.xxl.job.admin.core.quartz; +// +//import org.quartz.SchedulerConfigException; +//import org.quartz.spi.ThreadPool; +// +/// ** +// * single thread pool, for async trigger +// * +// * @author xuxueli 2019-03-06 +// */ +//public class XxlJobThreadPool implements ThreadPool { +// +// @Override +// public boolean runInThread(Runnable runnable) { +// +// // async run +// runnable.run(); +// return true; +// +// //return false; +// } +// +// @Override +// public int blockForAvailableThreads() { +// return 1; +// } +// +// @Override +// public void initialize() throws SchedulerConfigException { +// +// } +// +// @Override +// public void shutdown(boolean waitForJobsToComplete) { +// +// } +// +// @Override +// public int getPoolSize() { +// return 1; +// } +// +// @Override +// public void setInstanceId(String schedInstId) { +// +// } +// +// @Override +// public void setInstanceName(String schedName) { +// +// } +// +// // support +// public void setThreadCount(int count) { +// // +// } +// +//} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/web/error/WebErrorPageRegistrar.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/web/error/WebErrorPageRegistrar.java new file mode 100644 index 000000000..89a42dc61 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/web/error/WebErrorPageRegistrar.java @@ -0,0 +1,19 @@ +package com.xxl.job.admin.web.error; + +import org.springframework.boot.web.error.ErrorPage; +import org.springframework.boot.web.error.ErrorPageRegistrar; +import org.springframework.boot.web.error.ErrorPageRegistry; +import org.springframework.stereotype.Component; + +/** + * error page + */ +@Component +public class WebErrorPageRegistrar implements ErrorPageRegistrar { + + @Override + public void registerErrorPages(ErrorPageRegistry registry) { + ErrorPage errorPage = new ErrorPage("/errorpage"); + registry.addErrorPages(errorPage); + } +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/web/error/WebHandlerExceptionResolver.java similarity index 52% rename from pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java rename to pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/web/error/WebHandlerExceptionResolver.java index ad2588cb0..51e58692f 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/web/error/WebHandlerExceptionResolver.java @@ -1,8 +1,8 @@ -package com.xxl.job.admin.controller.resolver; +package com.xxl.job.admin.web.error; -import com.xxl.job.admin.core.exception.XxlJobException; -import com.xxl.job.admin.core.util.JacksonUtil; -import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.admin.scheduler.exception.XxlJobException; +import com.xxl.tool.json.GsonTool; +import com.xxl.tool.response.Response; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; @@ -21,49 +21,45 @@ import java.io.IOException; * @author xuxueli 2016-1-6 19:22:18 */ @Component -public class WebExceptionResolver implements HandlerExceptionResolver { - - private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); +public class WebHandlerExceptionResolver implements HandlerExceptionResolver { + private static transient Logger logger = LoggerFactory.getLogger(WebHandlerExceptionResolver.class); @Override - public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, - Exception ex) { + public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { if (!(ex instanceof XxlJobException)) { logger.error("WebExceptionResolver:{}", ex); } - // if json + // parse isJson boolean isJson = false; if (handler instanceof HandlerMethod) { HandlerMethod method = (HandlerMethod) handler; - ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); - if (responseBody != null) { - isJson = true; - } + isJson = method.getMethodAnnotation(ResponseBody.class) != null; } - // error result - ReturnT errorResult = new ReturnT(ReturnT.FAIL_CODE, ex.toString().replaceAll("\n", "
")); - - // response + // process error ModelAndView mv = new ModelAndView(); if (isJson) { try { - response.setContentType("application/json;charset=utf-8"); - response.getWriter().print(JacksonUtil.writeValueAsString(errorResult)); - } - catch (IOException e) { + // errorMsg + String errorMsg = GsonTool.toJson(Response.ofFail(ex.toString())); + + // write response + response.setStatus(HttpServletResponse.SC_OK); + response.setContentType("application/json;charset=UTF-8"); + response.getWriter().println(errorMsg); + } catch (IOException e) { logger.error(e.getMessage(), e); } return mv; - } - else { + } else { - mv.addObject("exceptionMsg", errorResult.getMsg()); - mv.setViewName("/common/common.exception"); + mv.addObject("exceptionMsg", ex.toString()); + mv.setViewName("common/common.errorpage"); return mv; } + } } \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/web/xxlsso/SimpleLoginStore.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/web/xxlsso/SimpleLoginStore.java new file mode 100644 index 000000000..d321213bb --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/web/xxlsso/SimpleLoginStore.java @@ -0,0 +1,84 @@ +package com.xxl.job.admin.web.xxlsso; + +import com.xxl.job.admin.constant.Consts; +import com.xxl.job.admin.mapper.XxlJobUserMapper; +import com.xxl.job.admin.model.XxlJobUser; +import com.xxl.sso.core.model.LoginInfo; +import com.xxl.sso.core.store.LoginStore; +import com.xxl.tool.core.MapTool; +import com.xxl.tool.response.Response; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +/** + * Simple LoginStore + *

+ * 1、store by database; + * 2、If you have higher performance requirements, it is recommended to use RedisLoginStore; + * + * @author xuxueli 2025-08-03 + */ +@Component +public class SimpleLoginStore implements LoginStore { + + + @Resource + private XxlJobUserMapper xxlJobUserMapper; + + + @Override + public Response set(LoginInfo loginInfo) { + + // parse token-signature + String token_sign = loginInfo.getSignature(); + + // write token by UserId + int ret = xxlJobUserMapper.updateToken(Integer.parseInt(loginInfo.getUserId()), token_sign); + return ret > 0 ? Response.ofSuccess() : Response.ofFail("token set fail"); + } + + @Override + public Response update(LoginInfo loginInfo) { + return Response.ofFail("not support"); + } + + @Override + public Response remove(String userId) { + // delete token-signature + int ret = xxlJobUserMapper.updateToken(Integer.parseInt(userId), ""); + return ret > 0 ? Response.ofSuccess() : Response.ofFail("token remove fail"); + } + + /** + * check through DB query + */ + @Override + public Response get(String userId) { + + // load login-user + XxlJobUser user = xxlJobUserMapper.loadById(Integer.parseInt(userId)); + if (user == null) { + return Response.ofFail("userId invalid."); + } + + // parse role + List roleList = user.getRole() == 1 ? List.of(Consts.ADMIN_ROLE) : null; + + // parse jobGroup permission + Map extraInfo = MapTool.newMap( + "jobGroups", user.getPermission() + ); + + // build LoginInfo + LoginInfo loginInfo = new LoginInfo(userId, user.getToken()); + loginInfo.setUserName(user.getUsername()); + loginInfo.setRoleList(roleList); + loginInfo.setExtraInfo(extraInfo); + + return Response.ofSuccess(loginInfo); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/web/xxlsso/XxlSsoConfig.java b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/web/xxlsso/XxlSsoConfig.java new file mode 100644 index 000000000..6b10f873d --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/java/com/xxl/job/admin/web/xxlsso/XxlSsoConfig.java @@ -0,0 +1,62 @@ +package com.xxl.job.admin.web.xxlsso; + +import com.xxl.sso.core.auth.interceptor.XxlSsoWebInterceptor; +import com.xxl.sso.core.bootstrap.XxlSsoBootstrap; +import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * @author xuxueli 2018-11-15 + */ +@Configuration +public class XxlSsoConfig implements WebMvcConfigurer { + + + @Value("${xxl-sso.token.key}") + private String tokenKey; + + @Value("${xxl-sso.token.timeout}") + private long tokenTimeout; + + @Value("${xxl-sso.client.excluded.paths}") + private String excludedPaths; + + @Value("${xxl-sso.client.login.path}") + private String loginPath; + + + @Resource + private SimpleLoginStore loginStore; + + + /** + * 1、配置 XxlSsoBootstrap + */ + @Bean(initMethod = "start", destroyMethod = "stop") + public XxlSsoBootstrap xxlSsoBootstrap() { + + XxlSsoBootstrap bootstrap = new XxlSsoBootstrap(); + bootstrap.setLoginStore(loginStore); + bootstrap.setTokenKey(tokenKey); + bootstrap.setTokenTimeout(tokenTimeout); + return bootstrap; + } + + /** + * 2、配置 XxlSso 拦截器 + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + + // 2.1、build xxl-sso interceptor + XxlSsoWebInterceptor webInterceptor = new XxlSsoWebInterceptor(excludedPaths, loginPath); + + // 2.2、add interceptor + registry.addInterceptor(webInterceptor).addPathPatterns("/**"); + } + +} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/application.yml b/pigx-visual/pigx-xxl-job-admin/src/main/resources/application.yml index 8470afba8..af0b7447d 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/application.yml +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/application.yml @@ -20,32 +20,4 @@ spring: config: import: - optional:nacos:application-@profiles.active@.yml - - optional:nacos:${spring.application.name}-@profiles.active@.yml - datasource: - type: com.alibaba.druid.pool.DruidDataSource - druid: - driver-class-name: com.mysql.cj.jdbc.Driver - username: ${MYSQL_USER:root} - password: ${MYSQL_PWD:root} - url: jdbc:mysql://${MYSQL_HOST:pigx-mysql}:${MYSQL_PORT:3306}/${MYSQL_DB:pigxx_job}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true&allowPublicKeyRetrieval=true - mvc: - static-path-pattern: /static/** - freemarker: - suffix: .ftl - request-context-attribute: request - settings: - number_format: 0.########## - template-loader-path: classpath:/templates/ - mail: - host: smtp.mxhichina.com - port: 465 - from: xxxx@gitee.wang - username: xxxx@gitee.wang - password: xxxx - properties: - mail: - smtp: - auth: true - ssl.enable: true - starttls.enable: false - required: false + - optional:nacos:${spring.application.name}-@profiles.active@.yml \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/i18n/message_en.properties b/pigx-visual/pigx-xxl-job-admin/src/main/resources/i18n/message_en.properties index a6e4d1e11..2faf12e5f 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/i18n/message_en.properties +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/i18n/message_en.properties @@ -1,6 +1,6 @@ admin_name=Scheduling Center -admin_name_full=Distributed Task Scheduling Platform XXL-JOB -admin_version=3.1.1 +admin_name_full=Distributed Task Scheduling Platform\uFF5CXXL-JOB +admin_version=3.4.1-SNAPSHOT admin_i18n=en ## system @@ -10,18 +10,16 @@ system_close=Close system_save=Save system_cancel=Cancel system_search=Search +system_reset=Reset system_status=Status system_opt=Operate +system_opt_add=Add system_please_input=please input system_please_choose=please choose system_success=success system_fail=fail -system_add_suc=add success -system_add_fail=add fail -system_update_suc=update success -system_update_fail=update fail +system_error=error system_all=All -system_api_error=net error system_show=Show system_empty=Empty system_opt_suc=operate success @@ -29,16 +27,25 @@ system_opt_fail=operate fail system_opt_edit=Edit system_opt_del=Delete system_opt_copy=Copy -system_unvalid=illegal +system_invalid=illegal system_not_found=not exist system_nav=Navigation system_digits=digits -system_lengh_limit=Length limit +system_length_limit=Length limit system_permission_limit=Permission limit system_welcome=Welcome +system_num_range=Numerical range limit +system_one=One +system_data=Data +system_selected_nothing=No data selected +## tab +tab_opt=Tab Operation +tab_close_current=Close Current Tabs +tab_close_other=Close Other Tabs +tab_close_all=Close All Tabs +tab_refresh=Refresh Tab ## daterangepicker -daterangepicker_ranges_recent_hour=recent one hour daterangepicker_ranges_today=today daterangepicker_ranges_yesterday=yesterday daterangepicker_ranges_this_month=this month @@ -51,23 +58,6 @@ daterangepicker_custom_endtime=end time daterangepicker_custom_daysofweek=Sun,Mon,Tue,Wed,Thu,Fri,Sat daterangepicker_custom_monthnames=Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec -## dataTable -dataTable_sProcessing=processing... -dataTable_sLengthMenu= _MENU_ records per page -dataTable_sZeroRecords=No matching results -dataTable_sInfo=page _PAGE_ ( Total _PAGES_ pages,_TOTAL_ records ) -dataTable_sInfoEmpty=No Record -dataTable_sInfoFiltered=(Filtered by _MAX_ results) -dataTable_sSearch=Search -dataTable_sEmptyTable=Table data is empty -dataTable_sLoadingRecords=Loading... -dataTable_sFirst=FIRST PAGE -dataTable_sPrevious=Previous Page -dataTable_sNext=Next Page -dataTable_sLast=LAST PAGE -dataTable_sSortAscending=: Rank this column in ascending order -dataTable_sSortDescending=: Rank this column in descending order - ## login login_btn=Login login_remember_me=Remember Me @@ -80,7 +70,7 @@ login_password_lt_4=Password length should not be less than 4 login_success=Login success login_fail=Login fail login_param_empty=Username or password is empty -login_param_unvalid=Username or password error +login_param_invalid=Username or password error ## logout logout_btn=Logout @@ -93,6 +83,11 @@ change_pwd=Change password change_pwd_suc_to_logout=Change password successful, about to log out login change_pwd_field_oldpwd=old password change_pwd_field_newpwd=new password +## change skin +change_skin=Change Theme +## help +admin_help=User Guide +admin_help_document=Official Documentation ## dashboard job_dashboard_name=Run report @@ -137,12 +132,13 @@ jobinfo_opt_run=Run Once jobinfo_opt_run_tips=Please input the address for this trigger. Null will be obtained from the executor jobinfo_opt_registryinfo=Registry Info jobinfo_opt_next_time=Next trigger time +jobinfo_glue_source=GLUE Source jobinfo_glue_remark=Resource Remark jobinfo_glue_remark_limit=Resource Remark length is limited to 4~100 jobinfo_glue_rollback=Version Backtrack -jobinfo_glue_jobid_unvalid=Job ID is illegal -jobinfo_glue_gluetype_unvalid=The job is not GLUE Type -jobinfo_field_executorTimeout_placeholder=Job Timeout period,in seconds. effect if greater than zero +jobinfo_glue_jobid_invalid=Job ID is illegal +jobinfo_glue_gluetype_invalid=The job is not GLUE Type +jobinfo_field_executorTimeout_placeholder=Job Timeout period\uFF0Cin seconds. effect if greater than zero schedule_type=Schedule Type schedule_type_none=None schedule_type_cron=Cron @@ -169,7 +165,7 @@ joblog_field_triggerCode=Trigger Result joblog_field_triggerMsg=Trigger Msg joblog_field_handleTime=Handle Time joblog_field_handleCode=Handle Result -joblog_field_handleMsg=Trigger Msg +joblog_field_handleMsg=Handle Msg joblog_field_executorAddress=Executor Address joblog_clean=Clean joblog_clean_log=Clean Log @@ -183,7 +179,7 @@ joblog_clean_type_6=Clean up log data ten thousand record ago joblog_clean_type_7=Clean up log data thirty thousand record ago joblog_clean_type_8=Clean up log data hundred thousand record ago joblog_clean_type_9=Clean up all log data -joblog_clean_type_unvalid=Clean type is illegal +joblog_clean_type_invalid=Clean type is illegal joblog_handleCode_200=Success joblog_handleCode_500=Fail joblog_handleCode_502=Timeout @@ -195,7 +191,7 @@ joblog_rolling_log=Rolling log joblog_rolling_log_refresh=Refresh joblog_rolling_log_triggerfail=The job trigger fail, can not view the rolling log joblog_rolling_log_failoften=The request for the Rolling log is terminated, the number of failed requests exceeds the limit, Reload the log on the refresh page -joblog_logid_unvalid=Log ID is illegal +joblog_logid_invalid=Log ID is illegal ## job group jobgroup_name=Executor Manage @@ -209,9 +205,9 @@ jobgroup_field_addressType_0=Automatic registration jobgroup_field_addressType_1=Manual registration jobgroup_field_addressType_limit=Manually registration type, the machine address must not be empty jobgroup_field_registryList=machine address -jobgroup_field_registryList_unvalid=registry machine address is illegal +jobgroup_field_registryList_invalid=registry machine address is illegal jobgroup_field_registryList_placeholder=Please enter the machine address, if there are more than one comma separated -jobgroup_field_appname_limit=Limit the beginning of a lowercase letter, consists of lowercase letters、number and hyphen. +jobgroup_field_appname_limit=Limit the beginning of a lowercase letter, consists of lowercase letters\u3001number and hyphen. jobgroup_field_appname_length=AppName length is limited to 4~64 jobgroup_field_title_length=Title length is limited to 4~12 jobgroup_field_order_digits=Please enter a positive integer @@ -244,7 +240,7 @@ jobconf_monitor_alarm_content=Alarm Content jobconf_trigger_admin_adress=Trigger machine address jobconf_trigger_exe_regtype=Execotor-Registry Type jobconf_trigger_exe_regaddress=Execotor-Registry Address -jobconf_trigger_address_empty=Trigger Fail:registry address is empty +jobconf_trigger_address_empty=Trigger Fail\uFF1Aregistry address is empty jobconf_trigger_run=Trigger Job jobconf_trigger_child_run=Trigger child job jobconf_callback_child_msg1={0}/{1} [Job ID={2}], Trigger {3}, Trigger msg: {4}
@@ -271,7 +267,3 @@ user_username_repeat=Username Repeat user_username_valid=Restrictions start with a lowercase letter and consist of lowercase letters and Numbers user_password_update_placeholder=Please input password, empty means not update user_update_loginuser_limit=Operation of current login account is not allowed - -## help -job_help=Tutorial -job_help_document=Official Document diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/i18n/message_zh_CN.properties b/pigx-visual/pigx-xxl-job-admin/src/main/resources/i18n/message_zh_CN.properties index 4ae39f675..298fb5e11 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/i18n/message_zh_CN.properties +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/i18n/message_zh_CN.properties @@ -1,277 +1,269 @@ -admin_name=任务调度中心 -admin_name_full=分布式任务调度平台XXL-JOB -admin_version=3.1.1 +admin_name=\u4EFB\u52A1\u8C03\u5EA6\u4E2D\u5FC3 +admin_name_full=\u5206\u5E03\u5F0F\u4EFB\u52A1\u8C03\u5EA6\u5E73\u53F0\uFF5CXXL-JOB +admin_version=3.4.1-SNAPSHOT admin_i18n= ## system -system_tips=系统提示 -system_ok=确定 -system_close=关闭 -system_save=保存 -system_cancel=取消 -system_search=搜索 -system_status=状态 -system_opt=操作 -system_please_input=请输入 -system_please_choose=请选择 -system_success=成功 -system_fail=失败 -system_add_suc=新增成功 -system_add_fail=新增失败 -system_update_suc=更新成功 -system_update_fail=更新失败 -system_all=全部 -system_api_error=接口异常 -system_show=查看 -system_empty=无 -system_opt_suc=操作成功 -system_opt_fail=操作失败 -system_opt_edit=编辑 -system_opt_del=删除 -system_opt_copy=复制 -system_unvalid=非法 -system_not_found=不存在 -system_nav=导航 -system_digits=整数 -system_lengh_limit=长度限制 -system_permission_limit=权限拦截 -system_welcome=欢迎 +system_tips=\u7CFB\u7EDF\u63D0\u793A +system_ok=\u786E\u5B9A +system_close=\u5173\u95ED +system_save=\u4FDD\u5B58 +system_cancel=\u53D6\u6D88 +system_search=\u641C\u7D22 +system_reset=\u91CD\u7F6E +system_status=\u72B6\u6001 +system_opt=\u64CD\u4F5C +system_opt_add=\u65B0\u589E +system_please_input=\u8BF7\u8F93\u5165 +system_please_choose=\u8BF7\u9009\u62E9 +system_success=\u6210\u529F +system_fail=\u5931\u8D25 +system_error=\u9519\u8BEF +system_all=\u5168\u90E8 +system_show=\u67E5\u770B +system_empty=\u65E0 +system_opt_suc=\u64CD\u4F5C\u6210\u529F +system_opt_fail=\u64CD\u4F5C\u5931\u8D25 +system_opt_edit=\u7F16\u8F91 +system_opt_del=\u5220\u9664 +system_opt_copy=\u590D\u5236 +system_invalid=\u975E\u6CD5 +system_not_found=\u4E0D\u5B58\u5728 +system_nav=\u5BFC\u822A +system_digits=\u6574\u6570 +system_length_limit=\u957F\u5EA6\u9650\u5236 +system_permission_limit=\u6743\u9650\u62E6\u622A +system_welcome=\u6B22\u8FCE +system_num_range=\u6570\u503C\u8303\u56F4\u9650\u5236 +system_one=\u4E00\u6761 +system_data=\u6570\u636E +system_selected_nothing=\u672A\u9009\u62E9 +## tab +tab_opt=\u9875\u7B7E\u64CD\u4F5C +tab_close_current=\u5173\u95ED\u5F53\u524D +tab_close_other=\u5173\u95ED\u5176\u4ED6 +tab_close_all=\u5168\u90E8\u5173\u95ED +tab_refresh=\u5237\u65B0 ## daterangepicker -daterangepicker_ranges_recent_hour=最近一小时 -daterangepicker_ranges_today=今日 -daterangepicker_ranges_yesterday=昨日 -daterangepicker_ranges_this_month=本月 -daterangepicker_ranges_last_month=上个月 -daterangepicker_ranges_recent_week=最近一周 -daterangepicker_ranges_recent_month=最近一月 -daterangepicker_custom_name=自定义 -daterangepicker_custom_starttime=起始时间 -daterangepicker_custom_endtime=结束时间 -daterangepicker_custom_daysofweek=日,一,二,三,四,五,六 -daterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月 - -## dataTable -dataTable_sProcessing=处理中... -dataTable_sLengthMenu=每页 _MENU_ 条记录 -dataTable_sZeroRecords=没有匹配结果 -dataTable_sInfo=第 _PAGE_ 页 ( 总共 _PAGES_ 页,_TOTAL_ 条记录 ) -dataTable_sInfoEmpty=无记录 -dataTable_sInfoFiltered=(由 _MAX_ 项结果过滤) -dataTable_sSearch=搜索 -dataTable_sEmptyTable=表中数据为空 -dataTable_sLoadingRecords=载入中... -dataTable_sFirst=首页 -dataTable_sPrevious=上页 -dataTable_sNext=下页 -dataTable_sLast=末页 -dataTable_sSortAscending=: 以升序排列此列 -dataTable_sSortDescending=: 以降序排列此列 +daterangepicker_ranges_today=\u4ECA\u65E5 +daterangepicker_ranges_yesterday=\u6628\u65E5 +daterangepicker_ranges_this_month=\u672C\u6708 +daterangepicker_ranges_last_month=\u4E0A\u4E2A\u6708 +daterangepicker_ranges_recent_week=\u6700\u8FD1\u4E00\u5468 +daterangepicker_ranges_recent_month=\u6700\u8FD1\u4E00\u6708 +daterangepicker_custom_name=\u81EA\u5B9A\u4E49 +daterangepicker_custom_starttime=\u8D77\u59CB\u65F6\u95F4 +daterangepicker_custom_endtime=\u7ED3\u675F\u65F6\u95F4 +daterangepicker_custom_daysofweek=\u65E5,\u4E00,\u4E8C,\u4E09,\u56DB,\u4E94,\u516D +daterangepicker_custom_monthnames=\u4E00\u6708,\u4E8C\u6708,\u4E09\u6708,\u56DB\u6708,\u4E94\u6708,\u516D\u6708,\u4E03\u6708,\u516B\u6708,\u4E5D\u6708,\u5341\u6708,\u5341\u4E00\u6708,\u5341\u4E8C\u6708 ## login -login_btn=登录 -login_remember_me=记住密码 -login_username_placeholder=请输入登录账号 -login_password_placeholder=请输入登录密码 -login_username_empty=请输入登录账号 -login_username_lt_4=登录账号不应低于4位 -login_password_empty=请输入登录密码 -login_password_lt_4=登录密码不应低于4位 -login_success=登录成功 -login_fail=登录失败 -login_param_empty=账号或密码为空 -login_param_unvalid=账号或密码错误 +login_btn=\u767B\u5F55 +login_remember_me=\u8BB0\u4F4F\u5BC6\u7801 +login_username_placeholder=\u8BF7\u8F93\u5165\u767B\u5F55\u8D26\u53F7 +login_password_placeholder=\u8BF7\u8F93\u5165\u767B\u5F55\u5BC6\u7801 +login_username_empty=\u8BF7\u8F93\u5165\u767B\u5F55\u8D26\u53F7 +login_username_lt_4=\u767B\u5F55\u8D26\u53F7\u4E0D\u5E94\u4F4E\u4E8E4\u4F4D +login_password_empty=\u8BF7\u8F93\u5165\u767B\u5F55\u5BC6\u7801 +login_password_lt_4=\u767B\u5F55\u5BC6\u7801\u4E0D\u5E94\u4F4E\u4E8E4\u4F4D +login_success=\u767B\u5F55\u6210\u529F +login_fail=\u767B\u5F55\u5931\u8D25 +login_param_empty=\u8D26\u53F7\u6216\u5BC6\u7801\u4E3A\u7A7A +login_param_invalid=\u8D26\u53F7\u6216\u5BC6\u7801\u9519\u8BEF ## logout -logout_btn=注销 -logout_confirm=确认注销登录? -logout_success=注销成功 -logout_fail=注销失败 +logout_btn=\u6CE8\u9500 +logout_confirm=\u786E\u8BA4\u6CE8\u9500\u767B\u5F55? +logout_success=\u6CE8\u9500\u6210\u529F +logout_fail=\u6CE8\u9500\u5931\u8D25 ## change pwd -change_pwd=修改密码 -change_pwd_suc_to_logout=修改密码成功,即将注销登陆 -change_pwd_field_oldpwd=旧密码 -change_pwd_field_newpwd=新密码 +change_pwd=\u4FEE\u6539\u5BC6\u7801 +change_pwd_suc_to_logout=\u4FEE\u6539\u5BC6\u7801\u6210\u529F\uFF0C\u5373\u5C06\u6CE8\u9500\u767B\u9646 +change_pwd_field_oldpwd=\u65E7\u5BC6\u7801 +change_pwd_field_newpwd=\u65B0\u5BC6\u7801 +## change skin +change_skin=\u5207\u6362\u4E3B\u9898 +## help +admin_help=\u4F7F\u7528\u6559\u7A0B +admin_help_document=\u5B98\u65B9\u6587\u6863 ## dashboard -job_dashboard_name=运行报表 -job_dashboard_job_num=任务数量 -job_dashboard_job_num_tip=调度中心运行的任务数量 -job_dashboard_trigger_num=调度次数 -job_dashboard_trigger_num_tip=调度中心触发的调度次数 -job_dashboard_jobgroup_num=执行器数量 -job_dashboard_jobgroup_num_tip=调度中心在线的执行器机器数量 -job_dashboard_report=调度报表 -job_dashboard_report_loaddata_fail=调度报表数据加载异常 -job_dashboard_date_report=日期分布图 -job_dashboard_rate_report=成功比例图 +job_dashboard_name=\u8FD0\u884C\u62A5\u8868 +job_dashboard_job_num=\u4EFB\u52A1\u6570\u91CF +job_dashboard_job_num_tip=\u8C03\u5EA6\u4E2D\u5FC3\u8FD0\u884C\u7684\u4EFB\u52A1\u6570\u91CF +job_dashboard_trigger_num=\u8C03\u5EA6\u6B21\u6570 +job_dashboard_trigger_num_tip=\u8C03\u5EA6\u4E2D\u5FC3\u89E6\u53D1\u7684\u8C03\u5EA6\u6B21\u6570 +job_dashboard_jobgroup_num=\u6267\u884C\u5668\u6570\u91CF +job_dashboard_jobgroup_num_tip=\u8C03\u5EA6\u4E2D\u5FC3\u5728\u7EBF\u7684\u6267\u884C\u5668\u673A\u5668\u6570\u91CF +job_dashboard_report=\u8C03\u5EA6\u62A5\u8868 +job_dashboard_report_loaddata_fail=\u8C03\u5EA6\u62A5\u8868\u6570\u636E\u52A0\u8F7D\u5F02\u5E38 +job_dashboard_date_report=\u65E5\u671F\u5206\u5E03\u56FE +job_dashboard_rate_report=\u6210\u529F\u6BD4\u4F8B\u56FE ## job info -jobinfo_name=任务管理 -jobinfo_job=任务 -jobinfo_field_add=新增 -jobinfo_field_update=更新任务 -jobinfo_field_id=任务ID -jobinfo_field_jobgroup=执行器 -jobinfo_field_jobdesc=任务描述 -jobinfo_field_gluetype=运行模式 -jobinfo_field_executorparam=任务参数 -jobinfo_field_author=负责人 -jobinfo_field_timeout=任务超时时间 -jobinfo_field_alarmemail=报警邮件 -jobinfo_field_alarmemail_placeholder=请输入报警邮件,多个邮件地址则逗号分隔 -jobinfo_field_executorRouteStrategy=路由策略 -jobinfo_field_childJobId=子任务ID -jobinfo_field_childJobId_placeholder=请输入子任务的任务ID,如存在多个则逗号分隔 -jobinfo_field_executorBlockStrategy=阻塞处理策略 -jobinfo_field_executorFailRetryCount=失败重试次数 -jobinfo_field_executorFailRetryCount_placeholder=失败重试次数,大于零时生效 -jobinfo_script_location=脚本位置 -jobinfo_shard_index=分片序号 -jobinfo_shard_total=分片总数 -jobinfo_opt_stop=停止 -jobinfo_opt_start=启动 -jobinfo_opt_log=查询日志 -jobinfo_opt_run=执行一次 -jobinfo_opt_run_tips=请输入本次执行的机器地址,为空则从执行器获取 -jobinfo_opt_registryinfo=注册节点 -jobinfo_opt_next_time=下次执行时间 -jobinfo_glue_remark=源码备注 -jobinfo_glue_remark_limit=源码备注长度限制为4~100 -jobinfo_glue_rollback=版本回溯 -jobinfo_glue_jobid_unvalid=任务ID非法 -jobinfo_glue_gluetype_unvalid=该任务非GLUE模式 -jobinfo_field_executorTimeout_placeholder=任务超时时间,单位秒,大于零时生效 -schedule_type=调度类型 -schedule_type_none=无 +jobinfo_name=\u4EFB\u52A1\u7BA1\u7406 +jobinfo_job=\u4EFB\u52A1 +jobinfo_field_add=\u65B0\u589E\u4EFB\u52A1 +jobinfo_field_update=\u66F4\u65B0\u4EFB\u52A1 +jobinfo_field_id=\u4EFB\u52A1ID +jobinfo_field_jobgroup=\u6267\u884C\u5668 +jobinfo_field_jobdesc=\u4EFB\u52A1\u63CF\u8FF0 +jobinfo_field_gluetype=\u8FD0\u884C\u6A21\u5F0F +jobinfo_field_executorparam=\u4EFB\u52A1\u53C2\u6570 +jobinfo_field_author=\u8D1F\u8D23\u4EBA +jobinfo_field_timeout=\u4EFB\u52A1\u8D85\u65F6\u65F6\u95F4 +jobinfo_field_alarmemail=\u62A5\u8B66\u90AE\u4EF6 +jobinfo_field_alarmemail_placeholder=\u8BF7\u8F93\u5165\u62A5\u8B66\u90AE\u4EF6\uFF0C\u591A\u4E2A\u90AE\u4EF6\u5730\u5740\u5219\u9017\u53F7\u5206\u9694 +jobinfo_field_executorRouteStrategy=\u8DEF\u7531\u7B56\u7565 +jobinfo_field_childJobId=\u5B50\u4EFB\u52A1ID +jobinfo_field_childJobId_placeholder=\u8BF7\u8F93\u5165\u5B50\u4EFB\u52A1\u7684\u4EFB\u52A1ID,\u5982\u5B58\u5728\u591A\u4E2A\u5219\u9017\u53F7\u5206\u9694 +jobinfo_field_executorBlockStrategy=\u963B\u585E\u5904\u7406\u7B56\u7565 +jobinfo_field_executorFailRetryCount=\u5931\u8D25\u91CD\u8BD5\u6B21\u6570 +jobinfo_field_executorFailRetryCount_placeholder=\u5931\u8D25\u91CD\u8BD5\u6B21\u6570\uFF0C\u5927\u4E8E\u96F6\u65F6\u751F\u6548 +jobinfo_script_location=\u811A\u672C\u4F4D\u7F6E +jobinfo_shard_index=\u5206\u7247\u5E8F\u53F7 +jobinfo_shard_total=\u5206\u7247\u603B\u6570 +jobinfo_opt_stop=\u505C\u6B62 +jobinfo_opt_start=\u542F\u52A8 +jobinfo_opt_log=\u67E5\u8BE2\u65E5\u5FD7 +jobinfo_opt_run=\u6267\u884C\u4E00\u6B21 +jobinfo_opt_run_tips=\u8BF7\u8F93\u5165\u672C\u6B21\u6267\u884C\u7684\u673A\u5668\u5730\u5740\uFF0C\u4E3A\u7A7A\u5219\u4ECE\u6267\u884C\u5668\u83B7\u53D6 +jobinfo_opt_registryinfo=\u6CE8\u518C\u8282\u70B9 +jobinfo_opt_next_time=\u4E0B\u6B21\u6267\u884C\u65F6\u95F4 +jobinfo_glue_source=GLUE\u6E90\u7801 +jobinfo_glue_remark=\u6E90\u7801\u5907\u6CE8 +jobinfo_glue_remark_limit=\u6E90\u7801\u5907\u6CE8\u957F\u5EA6\u9650\u5236\u4E3A4~100 +jobinfo_glue_rollback=\u7248\u672C\u56DE\u6EAF +jobinfo_glue_jobid_invalid=\u4EFB\u52A1ID\u975E\u6CD5 +jobinfo_glue_gluetype_invalid=\u8BE5\u4EFB\u52A1\u975EGLUE\u6A21\u5F0F +jobinfo_field_executorTimeout_placeholder=\u4EFB\u52A1\u8D85\u65F6\u65F6\u95F4\uFF0C\u5355\u4F4D\u79D2\uFF0C\u5927\u4E8E\u96F6\u65F6\u751F\u6548 +schedule_type=\u8C03\u5EA6\u7C7B\u578B +schedule_type_none=\u65E0 schedule_type_cron=CRON -schedule_type_fix_rate=固定速度 -schedule_type_fix_delay=固定延迟 -schedule_type_none_limit_start=当前调度类型禁止启动 -misfire_strategy=调度过期策略 -misfire_strategy_do_nothing=忽略 -misfire_strategy_fire_once_now=立即执行一次 -jobinfo_conf_base=基础配置 -jobinfo_conf_schedule=调度配置 -jobinfo_conf_job=任务配置 -jobinfo_conf_advanced=高级配置 +schedule_type_fix_rate=\u56FA\u5B9A\u901F\u5EA6 +schedule_type_fix_delay=\u56FA\u5B9A\u5EF6\u8FDF +schedule_type_none_limit_start=\u5F53\u524D\u8C03\u5EA6\u7C7B\u578B\u7981\u6B62\u542F\u52A8 +misfire_strategy=\u8C03\u5EA6\u8FC7\u671F\u7B56\u7565 +misfire_strategy_do_nothing=\u5FFD\u7565 +misfire_strategy_fire_once_now=\u7ACB\u5373\u6267\u884C\u4E00\u6B21 +jobinfo_conf_base=\u57FA\u7840\u914D\u7F6E +jobinfo_conf_schedule=\u8C03\u5EA6\u914D\u7F6E +jobinfo_conf_job=\u4EFB\u52A1\u914D\u7F6E +jobinfo_conf_advanced=\u9AD8\u7EA7\u914D\u7F6E ## job log -joblog_name=调度日志 -joblog_status=状态 -joblog_status_all=全部 -joblog_status_suc=成功 -joblog_status_fail=失败 -joblog_status_running=进行中 -joblog_field_triggerTime=调度时间 -joblog_field_triggerCode=调度结果 -joblog_field_triggerMsg=调度备注 -joblog_field_handleTime=执行时间 -joblog_field_handleCode=执行结果 -joblog_field_handleMsg=执行备注 -joblog_field_executorAddress=执行器地址 -joblog_clean=清理 -joblog_clean_log=日志清理 -joblog_clean_type=清理方式 -joblog_clean_type_1=清理一个月之前日志数据 -joblog_clean_type_2=清理三个月之前日志数据 -joblog_clean_type_3=清理六个月之前日志数据 -joblog_clean_type_4=清理一年之前日志数据 -joblog_clean_type_5=清理一千条以前日志数据 -joblog_clean_type_6=清理一万条以前日志数据 -joblog_clean_type_7=清理三万条以前日志数据 -joblog_clean_type_8=清理十万条以前日志数据 -joblog_clean_type_9=清理所有日志数据 -joblog_clean_type_unvalid=清理类型参数异常 -joblog_handleCode_200=成功 -joblog_handleCode_500=失败 -joblog_handleCode_502=失败(超时) -joblog_kill_log=终止任务 -joblog_kill_log_limit=调度失败,无法终止日志 -joblog_kill_log_byman=人为操作,主动终止 -joblog_lost_fail=任务结果丢失,标记失败 -joblog_rolling_log=执行日志 -joblog_rolling_log_refresh=刷新 -joblog_rolling_log_triggerfail=任务发起调度失败,无法查看执行日志 -joblog_rolling_log_failoften=终止请求Rolling日志,请求失败次数超上限,可刷新页面重新加载日志 -joblog_logid_unvalid=日志ID非法 +joblog_name=\u8C03\u5EA6\u65E5\u5FD7 +joblog_status=\u72B6\u6001 +joblog_status_all=\u5168\u90E8 +joblog_status_suc=\u6210\u529F +joblog_status_fail=\u5931\u8D25 +joblog_status_running=\u8FDB\u884C\u4E2D +joblog_field_triggerTime=\u8C03\u5EA6\u65F6\u95F4 +joblog_field_triggerCode=\u8C03\u5EA6\u7ED3\u679C +joblog_field_triggerMsg=\u8C03\u5EA6\u5907\u6CE8 +joblog_field_handleTime=\u6267\u884C\u65F6\u95F4 +joblog_field_handleCode=\u6267\u884C\u7ED3\u679C +joblog_field_handleMsg=\u6267\u884C\u5907\u6CE8 +joblog_field_executorAddress=\u6267\u884C\u5668\u5730\u5740 +joblog_clean=\u6E05\u7406 +joblog_clean_log=\u65E5\u5FD7\u6E05\u7406 +joblog_clean_type=\u6E05\u7406\u65B9\u5F0F +joblog_clean_type_1=\u6E05\u7406\u4E00\u4E2A\u6708\u4E4B\u524D\u65E5\u5FD7\u6570\u636E +joblog_clean_type_2=\u6E05\u7406\u4E09\u4E2A\u6708\u4E4B\u524D\u65E5\u5FD7\u6570\u636E +joblog_clean_type_3=\u6E05\u7406\u516D\u4E2A\u6708\u4E4B\u524D\u65E5\u5FD7\u6570\u636E +joblog_clean_type_4=\u6E05\u7406\u4E00\u5E74\u4E4B\u524D\u65E5\u5FD7\u6570\u636E +joblog_clean_type_5=\u6E05\u7406\u4E00\u5343\u6761\u4EE5\u524D\u65E5\u5FD7\u6570\u636E +joblog_clean_type_6=\u6E05\u7406\u4E00\u4E07\u6761\u4EE5\u524D\u65E5\u5FD7\u6570\u636E +joblog_clean_type_7=\u6E05\u7406\u4E09\u4E07\u6761\u4EE5\u524D\u65E5\u5FD7\u6570\u636E +joblog_clean_type_8=\u6E05\u7406\u5341\u4E07\u6761\u4EE5\u524D\u65E5\u5FD7\u6570\u636E +joblog_clean_type_9=\u6E05\u7406\u6240\u6709\u65E5\u5FD7\u6570\u636E +joblog_clean_type_invalid=\u6E05\u7406\u7C7B\u578B\u53C2\u6570\u5F02\u5E38 +joblog_handleCode_200=\u6210\u529F +joblog_handleCode_500=\u5931\u8D25 +joblog_handleCode_502=\u5931\u8D25(\u8D85\u65F6) +joblog_kill_log=\u7EC8\u6B62\u4EFB\u52A1 +joblog_kill_log_limit=\u8C03\u5EA6\u5931\u8D25\uFF0C\u65E0\u6CD5\u7EC8\u6B62\u65E5\u5FD7 +joblog_kill_log_byman=\u4EBA\u4E3A\u64CD\u4F5C\uFF0C\u4E3B\u52A8\u7EC8\u6B62 +joblog_lost_fail=\u4EFB\u52A1\u7ED3\u679C\u4E22\u5931\uFF0C\u6807\u8BB0\u5931\u8D25 +joblog_rolling_log=\u6267\u884C\u65E5\u5FD7 +joblog_rolling_log_refresh=\u5237\u65B0 +joblog_rolling_log_triggerfail=\u4EFB\u52A1\u53D1\u8D77\u8C03\u5EA6\u5931\u8D25\uFF0C\u65E0\u6CD5\u67E5\u770B\u6267\u884C\u65E5\u5FD7 +joblog_rolling_log_failoften=\u7EC8\u6B62\u8BF7\u6C42Rolling\u65E5\u5FD7,\u8BF7\u6C42\u5931\u8D25\u6B21\u6570\u8D85\u4E0A\u9650,\u53EF\u5237\u65B0\u9875\u9762\u91CD\u65B0\u52A0\u8F7D\u65E5\u5FD7 +joblog_logid_invalid=\u65E5\u5FD7ID\u975E\u6CD5 ## job group -jobgroup_name=执行器管理 -jobgroup_list=执行器列表 -jobgroup_add=新增执行器 -jobgroup_edit=编辑执行器 -jobgroup_del=删除执行器 -jobgroup_field_title=名称 -jobgroup_field_addressType=注册方式 -jobgroup_field_addressType_0=自动注册 -jobgroup_field_addressType_1=手动录入 -jobgroup_field_addressType_limit=手动录入注册方式,机器地址不可为空 -jobgroup_field_registryList=机器地址 -jobgroup_field_registryList_unvalid=机器地址格式非法 -jobgroup_field_registryList_placeholder=请输入执行器地址列表,多地址逗号分隔 -jobgroup_field_appname_limit=限制以小写字母开头,由小写字母、数字和中划线组成 -jobgroup_field_appname_length=AppName长度限制为4~64 -jobgroup_field_title_length=名称长度限制为4~12 -jobgroup_field_order_digits=请输入整数 -jobgroup_field_orderrange=取值范围为1~1000 -jobgroup_del_limit_0=拒绝删除,该执行器使用中 -jobgroup_del_limit_1=拒绝删除, 系统至少保留一个执行器 -jobgroup_empty=不存在有效执行器,请联系管理员 +jobgroup_name=\u6267\u884C\u5668\u7BA1\u7406 +jobgroup_list=\u6267\u884C\u5668\u5217\u8868 +jobgroup_add=\u65B0\u589E\u6267\u884C\u5668 +jobgroup_edit=\u7F16\u8F91\u6267\u884C\u5668 +jobgroup_del=\u5220\u9664\u6267\u884C\u5668 +jobgroup_field_title=\u540D\u79F0 +jobgroup_field_addressType=\u6CE8\u518C\u65B9\u5F0F +jobgroup_field_addressType_0=\u81EA\u52A8\u6CE8\u518C +jobgroup_field_addressType_1=\u624B\u52A8\u5F55\u5165 +jobgroup_field_addressType_limit=\u624B\u52A8\u5F55\u5165\u6CE8\u518C\u65B9\u5F0F\uFF0C\u673A\u5668\u5730\u5740\u4E0D\u53EF\u4E3A\u7A7A +jobgroup_field_registryList=\u673A\u5668\u5730\u5740 +jobgroup_field_registryList_invalid=\u673A\u5668\u5730\u5740\u683C\u5F0F\u975E\u6CD5 +jobgroup_field_registryList_placeholder=\u8BF7\u8F93\u5165\u6267\u884C\u5668\u5730\u5740\u5217\u8868\uFF0C\u591A\u5730\u5740\u9017\u53F7\u5206\u9694 +jobgroup_field_appname_limit=\u9650\u5236\u4EE5\u5C0F\u5199\u5B57\u6BCD\u5F00\u5934\uFF0C\u7531\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u4E2D\u5212\u7EBF\u7EC4\u6210 +jobgroup_field_appname_length=AppName\u957F\u5EA6\u9650\u5236\u4E3A4~64 +jobgroup_field_title_length=\u540D\u79F0\u957F\u5EA6\u9650\u5236\u4E3A4~12 +jobgroup_field_order_digits=\u8BF7\u8F93\u5165\u6574\u6570 +jobgroup_field_orderrange=\u53D6\u503C\u8303\u56F4\u4E3A1~1000 +jobgroup_del_limit_0=\u62D2\u7EDD\u5220\u9664\uFF0C\u8BE5\u6267\u884C\u5668\u4F7F\u7528\u4E2D +jobgroup_del_limit_1=\u62D2\u7EDD\u5220\u9664, \u7CFB\u7EDF\u81F3\u5C11\u4FDD\u7559\u4E00\u4E2A\u6267\u884C\u5668 +jobgroup_empty=\u4E0D\u5B58\u5728\u6709\u6548\u6267\u884C\u5668,\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458 ## job conf -jobconf_block_SERIAL_EXECUTION=单机串行 -jobconf_block_DISCARD_LATER=丢弃后续调度 -jobconf_block_COVER_EARLY=覆盖之前调度 -jobconf_route_first=第一个 -jobconf_route_last=最后一个 -jobconf_route_round=轮询 -jobconf_route_random=随机 -jobconf_route_consistenthash=一致性HASH -jobconf_route_lfu=最不经常使用 -jobconf_route_lru=最近最久未使用 -jobconf_route_failover=故障转移 -jobconf_route_busyover=忙碌转移 -jobconf_route_shard=分片广播 -jobconf_idleBeat=空闲检测 -jobconf_beat=心跳检测 -jobconf_monitor=任务调度中心监控报警 -jobconf_monitor_detail=监控告警明细 -jobconf_monitor_alarm_title=告警类型 -jobconf_monitor_alarm_type=调度失败 -jobconf_monitor_alarm_content=告警内容 -jobconf_trigger_admin_adress=调度机器 -jobconf_trigger_exe_regtype=执行器-注册方式 -jobconf_trigger_exe_regaddress=执行器-地址列表 -jobconf_trigger_address_empty=调度失败:执行器地址为空 -jobconf_trigger_run=触发调度 -jobconf_trigger_child_run=触发子任务 -jobconf_callback_child_msg1={0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4}
-jobconf_callback_child_msg2={0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误
-jobconf_trigger_type=任务触发类型 -jobconf_trigger_type_cron=Cron触发 -jobconf_trigger_type_manual=手动触发 -jobconf_trigger_type_parent=父任务触发 -jobconf_trigger_type_api=API触发 -jobconf_trigger_type_retry=失败重试触发 -jobconf_trigger_type_misfire=调度过期补偿 +jobconf_block_SERIAL_EXECUTION=\u5355\u673A\u4E32\u884C +jobconf_block_DISCARD_LATER=\u4E22\u5F03\u540E\u7EED\u8C03\u5EA6 +jobconf_block_COVER_EARLY=\u8986\u76D6\u4E4B\u524D\u8C03\u5EA6 +jobconf_route_first=\u7B2C\u4E00\u4E2A +jobconf_route_last=\u6700\u540E\u4E00\u4E2A +jobconf_route_round=\u8F6E\u8BE2 +jobconf_route_random=\u968F\u673A +jobconf_route_consistenthash=\u4E00\u81F4\u6027HASH +jobconf_route_lfu=\u6700\u4E0D\u7ECF\u5E38\u4F7F\u7528 +jobconf_route_lru=\u6700\u8FD1\u6700\u4E45\u672A\u4F7F\u7528 +jobconf_route_failover=\u6545\u969C\u8F6C\u79FB +jobconf_route_busyover=\u5FD9\u788C\u8F6C\u79FB +jobconf_route_shard=\u5206\u7247\u5E7F\u64AD +jobconf_idleBeat=\u7A7A\u95F2\u68C0\u6D4B +jobconf_beat=\u5FC3\u8DF3\u68C0\u6D4B +jobconf_monitor=\u4EFB\u52A1\u8C03\u5EA6\u4E2D\u5FC3\u76D1\u63A7\u62A5\u8B66 +jobconf_monitor_detail=\u76D1\u63A7\u544A\u8B66\u660E\u7EC6 +jobconf_monitor_alarm_title=\u544A\u8B66\u7C7B\u578B +jobconf_monitor_alarm_type=\u8C03\u5EA6\u5931\u8D25 +jobconf_monitor_alarm_content=\u544A\u8B66\u5185\u5BB9 +jobconf_trigger_admin_adress=\u8C03\u5EA6\u673A\u5668 +jobconf_trigger_exe_regtype=\u6267\u884C\u5668-\u6CE8\u518C\u65B9\u5F0F +jobconf_trigger_exe_regaddress=\u6267\u884C\u5668-\u5730\u5740\u5217\u8868 +jobconf_trigger_address_empty=\u8C03\u5EA6\u5931\u8D25\uFF1A\u6267\u884C\u5668\u5730\u5740\u4E3A\u7A7A +jobconf_trigger_run=\u89E6\u53D1\u8C03\u5EA6 +jobconf_trigger_child_run=\u89E6\u53D1\u5B50\u4EFB\u52A1 +jobconf_callback_child_msg1={0}/{1} [\u4EFB\u52A1ID={2}], \u89E6\u53D1{3}, \u89E6\u53D1\u5907\u6CE8: {4}
+jobconf_callback_child_msg2={0}/{1} [\u4EFB\u52A1ID={2}], \u89E6\u53D1\u5931\u8D25, \u89E6\u53D1\u5907\u6CE8: \u4EFB\u52A1ID\u683C\u5F0F\u9519\u8BEF
+jobconf_trigger_type=\u4EFB\u52A1\u89E6\u53D1\u7C7B\u578B +jobconf_trigger_type_cron=Cron\u89E6\u53D1 +jobconf_trigger_type_manual=\u624B\u52A8\u89E6\u53D1 +jobconf_trigger_type_parent=\u7236\u4EFB\u52A1\u89E6\u53D1 +jobconf_trigger_type_api=API\u89E6\u53D1 +jobconf_trigger_type_retry=\u5931\u8D25\u91CD\u8BD5\u89E6\u53D1 +jobconf_trigger_type_misfire=\u8C03\u5EA6\u8FC7\u671F\u8865\u507F ## user -user_manage=用户管理 -user_username=账号 -user_password=密码 -user_role=角色 -user_role_admin=管理员 -user_role_normal=普通用户 -user_permission=权限 -user_add=新增用户 -user_update=更新用户 -user_username_repeat=账号重复 -user_username_valid=限制以小写字母开头,由小写字母、数字组成 -user_password_update_placeholder=请输入新密码,为空则不更新密码 -user_update_loginuser_limit=禁止操作当前登录账号 - -## help -job_help=使用教程 -job_help_document=官方文档 \ No newline at end of file +user_manage=\u7528\u6237\u7BA1\u7406 +user_username=\u8D26\u53F7 +user_password=\u5BC6\u7801 +user_role=\u89D2\u8272 +user_role_admin=\u7BA1\u7406\u5458 +user_role_normal=\u666E\u901A\u7528\u6237 +user_permission=\u6743\u9650 +user_add=\u65B0\u589E\u7528\u6237 +user_update=\u66F4\u65B0\u7528\u6237 +user_username_repeat=\u8D26\u53F7\u91CD\u590D +user_username_valid=\u9650\u5236\u4EE5\u5C0F\u5199\u5B57\u6BCD\u5F00\u5934\uFF0C\u7531\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u7EC4\u6210 +user_password_update_placeholder=\u8BF7\u8F93\u5165\u65B0\u5BC6\u7801\uFF0C\u4E3A\u7A7A\u5219\u4E0D\u66F4\u65B0\u5BC6\u7801 +user_update_loginuser_limit=\u7981\u6B62\u64CD\u4F5C\u5F53\u524D\u767B\u5F55\u8D26\u53F7 diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/i18n/message_zh_TC.properties b/pigx-visual/pigx-xxl-job-admin/src/main/resources/i18n/message_zh_TC.properties index 22e144358..b42bdb90c 100755 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/i18n/message_zh_TC.properties +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/i18n/message_zh_TC.properties @@ -1,277 +1,269 @@ -admin_name=任務調度中心 -admin_name_full=分布式任務調度平臺XXL-JOB -admin_version=3.1.1 +admin_name=\u4EFB\u52D9\u8ABF\u5EA6\u4E2D\u5FC3 +admin_name_full=\u5206\u5E03\u5F0F\u4EFB\u52D9\u8ABF\u5EA6\u5E73\u81FA\uFF5CXXL-JOB +admin_version=3.4.1-SNAPSHOT admin_i18n= ## system -system_tips=系統提示 -system_ok=確定 -system_close=關閉 -system_save=儲存 -system_cancel=取消 -system_search=搜尋 -system_status=狀態 -system_opt=操作 -system_please_input=請輸入 -system_please_choose=请選擇 -system_success=成功 -system_fail=失敗 -system_add_suc=新增成功 -system_add_fail=新增失敗 -system_update_suc=更新成功 -system_update_fail=更新失敗 -system_all=全部 -system_api_error=API錯誤 -system_show=查看 -system_empty=無 -system_opt_suc=操作成功 -system_opt_fail=操作失敗 -system_opt_edit=編輯 -system_opt_del=刪除 -system_opt_copy=復制 -system_unvalid=非法 -system_not_found=不存在 -system_nav=導航 -system_digits=整數 -system_lengh_limit=長度限制 -system_permission_limit=權限控管 -system_welcome=歡迎 +system_tips=\u7CFB\u7D71\u63D0\u793A +system_ok=\u78BA\u5B9A +system_close=\u95DC\u9589 +system_save=\u5132\u5B58 +system_cancel=\u53D6\u6D88 +system_search=\u641C\u5C0B +system_reset=\u91CD\u7F6E +system_status=\u72C0\u614B +system_opt=\u64CD\u4F5C +system_opt_add=\u65B0\u589E +system_please_input=\u8ACB\u8F38\u5165 +system_please_choose=\u8BF7\u9078\u64C7 +system_success=\u6210\u529F +system_fail=\u5931\u6557 +system_error=\u932F\u8AA4 +system_all=\u5168\u90E8 +system_show=\u67E5\u770B +system_empty=\u7121 +system_opt_suc=\u64CD\u4F5C\u6210\u529F +system_opt_fail=\u64CD\u4F5C\u5931\u6557 +system_opt_edit=\u7DE8\u8F2F +system_opt_del=\u522A\u9664 +system_opt_copy=\u5FA9\u5236 +system_invalid=\u975E\u6CD5 +system_not_found=\u4E0D\u5B58\u5728 +system_nav=\u5C0E\u822A +system_digits=\u6574\u6578 +system_length_limit=\u9577\u5EA6\u9650\u5236 +system_permission_limit=\u6B0A\u9650\u63A7\u7BA1 +system_welcome=\u6B61\u8FCE +system_num_range=\u6578\u503C\u7BC4\u570D\u9650\u5236 +system_one=\u4E00\u689D +system_data=\u6578\u64DA +system_selected_nothing=\u8BF7\u9078\u64C7 +## tab +tab_opt=\u9801\u7C64\u64CD\u4F5C +tab_close_current=\u95DC\u9589\u7576\u524D +tab_close_other=\u95DC\u9589\u5176\u4ED6 +tab_close_all=\u5168\u90E8\u95DC\u9589 +tab_refresh=\u5237\u65B0 ## daterangepicker -daterangepicker_ranges_recent_hour=最近一小時 -daterangepicker_ranges_today=今日 -daterangepicker_ranges_yesterday=昨日 -daterangepicker_ranges_this_month=本月 -daterangepicker_ranges_last_month=上個月 -daterangepicker_ranges_recent_week=最近一周 -daterangepicker_ranges_recent_month=最近一月 -daterangepicker_custom_name=自定義 -daterangepicker_custom_starttime=起始時間 -daterangepicker_custom_endtime=結束時間 -daterangepicker_custom_daysofweek=日,一,二,三,四,五,六 -daterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月 - -## dataTable -dataTable_sProcessing=處理中... -dataTable_sLengthMenu=每頁 _MENU_ 條記錄 -dataTable_sZeroRecords=沒有相符合記錄 -dataTable_sInfo=第 _PAGE_ 頁 ( 總共 _PAGES_ 頁,_TOTAL_ 條記錄 ) -dataTable_sInfoEmpty=無記錄 -dataTable_sInfoFiltered=(由 _MAX_ 項結果過濾) -dataTable_sSearch=搜尋 -dataTable_sEmptyTable=表中資料為空 -dataTable_sLoadingRecords=載入中... -dataTable_sFirst=首頁 -dataTable_sPrevious=上頁 -dataTable_sNext=下頁 -dataTable_sLast=末頁 -dataTable_sSortAscending=: 以升幂排序此列 -dataTable_sSortDescending=: 以降幂排序此列 +daterangepicker_ranges_today=\u4ECA\u65E5 +daterangepicker_ranges_yesterday=\u6628\u65E5 +daterangepicker_ranges_this_month=\u672C\u6708 +daterangepicker_ranges_last_month=\u4E0A\u500B\u6708 +daterangepicker_ranges_recent_week=\u6700\u8FD1\u4E00\u5468 +daterangepicker_ranges_recent_month=\u6700\u8FD1\u4E00\u6708 +daterangepicker_custom_name=\u81EA\u5B9A\u7FA9 +daterangepicker_custom_starttime=\u8D77\u59CB\u6642\u9593 +daterangepicker_custom_endtime=\u7D50\u675F\u6642\u9593 +daterangepicker_custom_daysofweek=\u65E5,\u4E00,\u4E8C,\u4E09,\u56DB,\u4E94,\u516D +daterangepicker_custom_monthnames=\u4E00\u6708,\u4E8C\u6708,\u4E09\u6708,\u56DB\u6708,\u4E94\u6708,\u516D\u6708,\u4E03\u6708,\u516B\u6708,\u4E5D\u6708,\u5341\u6708,\u5341\u4E00\u6708,\u5341\u4E8C\u6708 ## login -login_btn=登入 -login_remember_me=記住密碼 -login_username_placeholder=請輸入登入帳號 -login_password_placeholder=請輸入登入密碼 -login_username_empty=請輸入登入帳號 -login_username_lt_4=登入帳號不應低於4位數 -login_password_empty=請輸入登入密碼 -login_password_lt_4=登入密碼不應低於4位數 -login_success=登入成功 -login_fail=登入失敗 -login_param_empty=帳號或密碼為空值 -login_param_unvalid=帳號或密碼錯誤 +login_btn=\u767B\u5165 +login_remember_me=\u8A18\u4F4F\u5BC6\u78BC +login_username_placeholder=\u8ACB\u8F38\u5165\u767B\u5165\u5E33\u865F +login_password_placeholder=\u8ACB\u8F38\u5165\u767B\u5165\u5BC6\u78BC +login_username_empty=\u8ACB\u8F38\u5165\u767B\u5165\u5E33\u865F +login_username_lt_4=\u767B\u5165\u5E33\u865F\u4E0D\u61C9\u4F4E\u65BC4\u4F4D\u6578 +login_password_empty=\u8ACB\u8F38\u5165\u767B\u5165\u5BC6\u78BC +login_password_lt_4=\u767B\u5165\u5BC6\u78BC\u4E0D\u61C9\u4F4E\u65BC4\u4F4D\u6578 +login_success=\u767B\u5165\u6210\u529F +login_fail=\u767B\u5165\u5931\u6557 +login_param_empty=\u5E33\u865F\u6216\u5BC6\u78BC\u70BA\u7A7A\u503C +login_param_invalid=\u5E33\u865F\u6216\u5BC6\u78BC\u932F\u8AA4 ## logout -logout_btn=登出 -logout_confirm=確認登出? -logout_success=登出成功 -logout_fail=登出失敗 +logout_btn=\u767B\u51FA +logout_confirm=\u78BA\u8A8D\u767B\u51FA? +logout_success=\u767B\u51FA\u6210\u529F +logout_fail=\u767B\u51FA\u5931\u6557 ## change pwd -change_pwd=修改密碼 -change_pwd_suc_to_logout=修改密碼成功,即將登出 -change_pwd_field_oldpwd=舊密碼 -change_pwd_field_newpwd=新密碼 +change_pwd=\u4FEE\u6539\u5BC6\u78BC +change_pwd_suc_to_logout=\u4FEE\u6539\u5BC6\u78BC\u6210\u529F\uFF0C\u5373\u5C07\u767B\u51FA +change_pwd_field_oldpwd=\u820A\u5BC6\u78BC +change_pwd_field_newpwd=\u65B0\u5BC6\u78BC +## change skin +change_skin=\u5207\u63DB\u4E3B\u984C +## help +admin_help=\u4F7F\u7528\u6559\u7A0B +admin_help_document=\u5B98\u65B9\u6587\u6A94 ## dashboard -job_dashboard_name=運行報表 -job_dashboard_job_num=任務數量 -job_dashboard_job_num_tip=調度中心運行的任務數量 -job_dashboard_trigger_num=調度次數 -job_dashboard_trigger_num_tip=調度中心觸發的調度次數 -job_dashboard_jobgroup_num=執行器數量 -job_dashboard_jobgroup_num_tip=調度中心在線的執行器機器數量 -job_dashboard_report=調度報表 -job_dashboard_report_loaddata_fail=調度報表資料加載異常 -job_dashboard_date_report=日期分布圖 -job_dashboard_rate_report=成功比例圖 +job_dashboard_name=\u904B\u884C\u5831\u8868 +job_dashboard_job_num=\u4EFB\u52D9\u6578\u91CF +job_dashboard_job_num_tip=\u8ABF\u5EA6\u4E2D\u5FC3\u904B\u884C\u7684\u4EFB\u52D9\u6578\u91CF +job_dashboard_trigger_num=\u8ABF\u5EA6\u6B21\u6578 +job_dashboard_trigger_num_tip=\u8ABF\u5EA6\u4E2D\u5FC3\u89F8\u767C\u7684\u8ABF\u5EA6\u6B21\u6578 +job_dashboard_jobgroup_num=\u57F7\u884C\u5668\u6578\u91CF +job_dashboard_jobgroup_num_tip=\u8ABF\u5EA6\u4E2D\u5FC3\u5728\u7DDA\u7684\u57F7\u884C\u5668\u6A5F\u5668\u6578\u91CF +job_dashboard_report=\u8ABF\u5EA6\u5831\u8868 +job_dashboard_report_loaddata_fail=\u8ABF\u5EA6\u5831\u8868\u8CC7\u6599\u52A0\u8F09\u7570\u5E38 +job_dashboard_date_report=\u65E5\u671F\u5206\u5E03\u5716 +job_dashboard_rate_report=\u6210\u529F\u6BD4\u4F8B\u5716 ## job info -jobinfo_name=任務管理 -jobinfo_job=任務 -jobinfo_field_add=新增 -jobinfo_field_update=更新任務 -jobinfo_field_id=任務ID -jobinfo_field_jobgroup=執行器 -jobinfo_field_jobdesc=任務描述 -jobinfo_field_gluetype=運行模式 -jobinfo_field_executorparam=任務參數 -jobinfo_field_author=負責人 -jobinfo_field_timeout=任務超時秒數 -jobinfo_field_alarmemail=告警郵件 -jobinfo_field_alarmemail_placeholder=輸入多個告警郵件地址,請以逗號分隔 -jobinfo_field_executorRouteStrategy=路由策略 -jobinfo_field_childJobId=子任務ID -jobinfo_field_childJobId_placeholder=輸入子任務ID,如有多個請以逗號分隔 -jobinfo_field_executorBlockStrategy=阻塞處理策略 -jobinfo_field_executorFailRetryCount=失敗重試次數 -jobinfo_field_executorFailRetryCount_placeholder=失敗重試次數,大於零時生效 -jobinfo_script_location=腳本位置 -jobinfo_shard_index=分片序號 -jobinfo_shard_total=分片總數 -jobinfo_opt_stop=停止 -jobinfo_opt_start=啟動 -jobinfo_opt_log=查詢日誌 -jobinfo_opt_run=執行一次 -jobinfo_opt_run_tips=請輸入本次執行的機器地址,為空則從執行器獲取 -jobinfo_opt_registryinfo=注冊節點 -jobinfo_opt_next_time=下次執行時間 -jobinfo_glue_remark=源碼備註 -jobinfo_glue_remark_limit=源碼備註長度限制為4~100 -jobinfo_glue_rollback=版本回復 -jobinfo_glue_jobid_unvalid=任務ID非法 -jobinfo_glue_gluetype_unvalid=該任務非GLUE模式 -jobinfo_field_executorTimeout_placeholder=任務超時時間,單位秒,大於零時生效 -schedule_type=調度類型 -schedule_type_none=無 +jobinfo_name=\u4EFB\u52D9\u7BA1\u7406 +jobinfo_job=\u4EFB\u52D9 +jobinfo_field_add=\u65B0\u589E\u4EFB\u52D9 +jobinfo_field_update=\u66F4\u65B0\u4EFB\u52D9 +jobinfo_field_id=\u4EFB\u52D9ID +jobinfo_field_jobgroup=\u57F7\u884C\u5668 +jobinfo_field_jobdesc=\u4EFB\u52D9\u63CF\u8FF0 +jobinfo_field_gluetype=\u904B\u884C\u6A21\u5F0F +jobinfo_field_executorparam=\u4EFB\u52D9\u53C3\u6578 +jobinfo_field_author=\u8CA0\u8CAC\u4EBA +jobinfo_field_timeout=\u4EFB\u52D9\u8D85\u6642\u79D2\u6578 +jobinfo_field_alarmemail=\u544A\u8B66\u90F5\u4EF6 +jobinfo_field_alarmemail_placeholder=\u8F38\u5165\u591A\u500B\u544A\u8B66\u90F5\u4EF6\u5730\u5740\uFF0C\u8ACB\u4EE5\u9017\u865F\u5206\u9694 +jobinfo_field_executorRouteStrategy=\u8DEF\u7531\u7B56\u7565 +jobinfo_field_childJobId=\u5B50\u4EFB\u52D9ID +jobinfo_field_childJobId_placeholder=\u8F38\u5165\u5B50\u4EFB\u52D9ID\uFF0C\u5982\u6709\u591A\u500B\u8ACB\u4EE5\u9017\u865F\u5206\u9694 +jobinfo_field_executorBlockStrategy=\u963B\u585E\u8655\u7406\u7B56\u7565 +jobinfo_field_executorFailRetryCount=\u5931\u6557\u91CD\u8A66\u6B21\u6578 +jobinfo_field_executorFailRetryCount_placeholder=\u5931\u6557\u91CD\u8A66\u6B21\u6578\uFF0C\u5927\u65BC\u96F6\u6642\u751F\u6548 +jobinfo_script_location=\u8173\u672C\u4F4D\u7F6E +jobinfo_shard_index=\u5206\u7247\u5E8F\u865F +jobinfo_shard_total=\u5206\u7247\u7E3D\u6578 +jobinfo_opt_stop=\u505C\u6B62 +jobinfo_opt_start=\u555F\u52D5 +jobinfo_opt_log=\u67E5\u8A62\u65E5\u8A8C +jobinfo_opt_run=\u57F7\u884C\u4E00\u6B21 +jobinfo_opt_run_tips=\u8ACB\u8F38\u5165\u672C\u6B21\u57F7\u884C\u7684\u6A5F\u5668\u5730\u5740\uFF0C\u70BA\u7A7A\u5247\u5F9E\u57F7\u884C\u5668\u7372\u53D6 +jobinfo_opt_registryinfo=\u6CE8\u518A\u7BC0\u9EDE +jobinfo_opt_next_time=\u4E0B\u6B21\u57F7\u884C\u6642\u9593 +jobinfo_glue_source=GLUE\u6E90\u78BC +jobinfo_glue_remark=\u6E90\u78BC\u5099\u8A3B +jobinfo_glue_remark_limit=\u6E90\u78BC\u5099\u8A3B\u9577\u5EA6\u9650\u5236\u70BA4~100 +jobinfo_glue_rollback=\u7248\u672C\u56DE\u5FA9 +jobinfo_glue_jobid_invalid=\u4EFB\u52D9ID\u975E\u6CD5 +jobinfo_glue_gluetype_invalid=\u8A72\u4EFB\u52D9\u975EGLUE\u6A21\u5F0F +jobinfo_field_executorTimeout_placeholder=\u4EFB\u52D9\u8D85\u6642\u6642\u9593\uFF0C\u55AE\u4F4D\u79D2\uFF0C\u5927\u65BC\u96F6\u6642\u751F\u6548 +schedule_type=\u8ABF\u5EA6\u985E\u578B +schedule_type_none=\u7121 schedule_type_cron=CRON -schedule_type_fix_rate=固定速度 -schedule_type_fix_delay=固定延遲 -schedule_type_none_limit_start=當前調度類型禁止啟動 -misfire_strategy=調度過期策略 -misfire_strategy_do_nothing=忽略 -misfire_strategy_fire_once_now=立即執行壹次 -jobinfo_conf_base=基礎配置 -jobinfo_conf_schedule=調度配置 -jobinfo_conf_job=任務配置 -jobinfo_conf_advanced=高級配置 +schedule_type_fix_rate=\u56FA\u5B9A\u901F\u5EA6 +schedule_type_fix_delay=\u56FA\u5B9A\u5EF6\u9072 +schedule_type_none_limit_start=\u7576\u524D\u8ABF\u5EA6\u985E\u578B\u7981\u6B62\u555F\u52D5 +misfire_strategy=\u8ABF\u5EA6\u904E\u671F\u7B56\u7565 +misfire_strategy_do_nothing=\u5FFD\u7565 +misfire_strategy_fire_once_now=\u7ACB\u5373\u57F7\u884C\u58F9\u6B21 +jobinfo_conf_base=\u57FA\u790E\u914D\u7F6E +jobinfo_conf_schedule=\u8ABF\u5EA6\u914D\u7F6E +jobinfo_conf_job=\u4EFB\u52D9\u914D\u7F6E +jobinfo_conf_advanced=\u9AD8\u7D1A\u914D\u7F6E ## job log -joblog_name=調度日誌 -joblog_status=狀態 -joblog_status_all=全部 -joblog_status_suc=成功 -joblog_status_fail=失敗 -joblog_status_running=進行中 -joblog_field_triggerTime=調度時間 -joblog_field_triggerCode=調度結果 -joblog_field_triggerMsg=調度備註 -joblog_field_handleTime=執行時間 -joblog_field_handleCode=執行结果 -joblog_field_handleMsg=執行備註 -joblog_field_executorAddress=執行器地址 -joblog_clean=清理 -joblog_clean_log=日誌清理 -joblog_clean_type=清理方式 -joblog_clean_type_1=清理一個月之前日誌資料 -joblog_clean_type_2=清理三個月之前日誌資料 -joblog_clean_type_3=清理六個月之前日誌資料 -joblog_clean_type_4=清理一年之前日誌資料 -joblog_clean_type_5=清理一千條以前日誌資料 -joblog_clean_type_6=清理一萬條以前日誌資料 -joblog_clean_type_7=清理三萬條以前日誌資料 -joblog_clean_type_8=清理十萬條以前日誌資料 -joblog_clean_type_9=清理所有日誌資料 -joblog_clean_type_unvalid=清理類型參数異常 -joblog_handleCode_200=成功 -joblog_handleCode_500=失敗 -joblog_handleCode_502=失敗(超時) -joblog_kill_log=终止任務 -joblog_kill_log_limit=調度失敗,無法终止日誌 -joblog_kill_log_byman=人為操作,主動終止 -joblog_lost_fail=任務結果丟失,標記失敗 -joblog_rolling_log=執行日誌 -joblog_rolling_log_refresh=更新 -joblog_rolling_log_triggerfail=任務發起調度失敗,無法查看執行日誌 -joblog_rolling_log_failoften=終止請求Rolling日誌,請求失敗次數超上限,可刷新頁面重新加載日誌 -joblog_logid_unvalid=日誌ID非法 +joblog_name=\u8ABF\u5EA6\u65E5\u8A8C +joblog_status=\u72C0\u614B +joblog_status_all=\u5168\u90E8 +joblog_status_suc=\u6210\u529F +joblog_status_fail=\u5931\u6557 +joblog_status_running=\u9032\u884C\u4E2D +joblog_field_triggerTime=\u8ABF\u5EA6\u6642\u9593 +joblog_field_triggerCode=\u8ABF\u5EA6\u7D50\u679C +joblog_field_triggerMsg=\u8ABF\u5EA6\u5099\u8A3B +joblog_field_handleTime=\u57F7\u884C\u6642\u9593 +joblog_field_handleCode=\u57F7\u884C\u7ED3\u679C +joblog_field_handleMsg=\u57F7\u884C\u5099\u8A3B +joblog_field_executorAddress=\u57F7\u884C\u5668\u5730\u5740 +joblog_clean=\u6E05\u7406 +joblog_clean_log=\u65E5\u8A8C\u6E05\u7406 +joblog_clean_type=\u6E05\u7406\u65B9\u5F0F +joblog_clean_type_1=\u6E05\u7406\u4E00\u500B\u6708\u4E4B\u524D\u65E5\u8A8C\u8CC7\u6599 +joblog_clean_type_2=\u6E05\u7406\u4E09\u500B\u6708\u4E4B\u524D\u65E5\u8A8C\u8CC7\u6599 +joblog_clean_type_3=\u6E05\u7406\u516D\u500B\u6708\u4E4B\u524D\u65E5\u8A8C\u8CC7\u6599 +joblog_clean_type_4=\u6E05\u7406\u4E00\u5E74\u4E4B\u524D\u65E5\u8A8C\u8CC7\u6599 +joblog_clean_type_5=\u6E05\u7406\u4E00\u5343\u689D\u4EE5\u524D\u65E5\u8A8C\u8CC7\u6599 +joblog_clean_type_6=\u6E05\u7406\u4E00\u842C\u689D\u4EE5\u524D\u65E5\u8A8C\u8CC7\u6599 +joblog_clean_type_7=\u6E05\u7406\u4E09\u842C\u689D\u4EE5\u524D\u65E5\u8A8C\u8CC7\u6599 +joblog_clean_type_8=\u6E05\u7406\u5341\u842C\u689D\u4EE5\u524D\u65E5\u8A8C\u8CC7\u6599 +joblog_clean_type_9=\u6E05\u7406\u6240\u6709\u65E5\u8A8C\u8CC7\u6599 +joblog_clean_type_invalid=\u6E05\u7406\u985E\u578B\u53C3\u6570\u7570\u5E38 +joblog_handleCode_200=\u6210\u529F +joblog_handleCode_500=\u5931\u6557 +joblog_handleCode_502=\u5931\u6557(\u8D85\u6642) +joblog_kill_log=\u7EC8\u6B62\u4EFB\u52D9 +joblog_kill_log_limit=\u8ABF\u5EA6\u5931\u6557\uFF0C\u7121\u6CD5\u7EC8\u6B62\u65E5\u8A8C +joblog_kill_log_byman=\u4EBA\u70BA\u64CD\u4F5C\uFF0C\u4E3B\u52D5\u7D42\u6B62 +joblog_lost_fail=\u4EFB\u52D9\u7D50\u679C\u4E1F\u5931\uFF0C\u6A19\u8A18\u5931\u6557 +joblog_rolling_log=\u57F7\u884C\u65E5\u8A8C +joblog_rolling_log_refresh=\u66F4\u65B0 +joblog_rolling_log_triggerfail=\u4EFB\u52D9\u767C\u8D77\u8ABF\u5EA6\u5931\u6557\uFF0C\u7121\u6CD5\u67E5\u770B\u57F7\u884C\u65E5\u8A8C +joblog_rolling_log_failoften=\u7D42\u6B62\u8ACB\u6C42Rolling\u65E5\u8A8C\uFF0C\u8ACB\u6C42\u5931\u6557\u6B21\u6578\u8D85\u4E0A\u9650\uFF0C\u53EF\u5237\u65B0\u9801\u9762\u91CD\u65B0\u52A0\u8F09\u65E5\u8A8C +joblog_logid_invalid=\u65E5\u8A8CID\u975E\u6CD5 ## job group -jobgroup_name=執行器管理 -jobgroup_list=執行器列表 -jobgroup_add=新增執行器 -jobgroup_edit=編輯執行器 -jobgroup_del=刪除執行器 -jobgroup_field_title=名稱 -jobgroup_field_addressType=注冊方式 -jobgroup_field_addressType_0=自動注冊 -jobgroup_field_addressType_1=手動登錄 -jobgroup_field_addressType_limit=手動登錄注冊方式,機器地址不可為空 -jobgroup_field_registryList=機器地址 -jobgroup_field_registryList_unvalid=機器地址格式非法 -jobgroup_field_registryList_placeholder=請輸入執行器地址列表,多個地址請以逗號分隔 -jobgroup_field_appname_limit=限制以小寫字母開頭,由小寫字母、數字和中划線組成 -jobgroup_field_appname_length=AppName長度限制為4~64 -jobgroup_field_title_length=名稱長度限制為4~12 -jobgroup_field_order_digits=請輸入整數 -jobgroup_field_orderrange=取值範圍為1~1000 -jobgroup_del_limit_0=拒絕刪除,該執行器使用中 -jobgroup_del_limit_1=拒絕删除,系统至少保留一個執行器 -jobgroup_empty=不存在有效執行器,請聯絡系統管理員 +jobgroup_name=\u57F7\u884C\u5668\u7BA1\u7406 +jobgroup_list=\u57F7\u884C\u5668\u5217\u8868 +jobgroup_add=\u65B0\u589E\u57F7\u884C\u5668 +jobgroup_edit=\u7DE8\u8F2F\u57F7\u884C\u5668 +jobgroup_del=\u522A\u9664\u57F7\u884C\u5668 +jobgroup_field_title=\u540D\u7A31 +jobgroup_field_addressType=\u6CE8\u518A\u65B9\u5F0F +jobgroup_field_addressType_0=\u81EA\u52D5\u6CE8\u518A +jobgroup_field_addressType_1=\u624B\u52D5\u767B\u9304 +jobgroup_field_addressType_limit=\u624B\u52D5\u767B\u9304\u6CE8\u518A\u65B9\u5F0F\uFF0C\u6A5F\u5668\u5730\u5740\u4E0D\u53EF\u70BA\u7A7A +jobgroup_field_registryList=\u6A5F\u5668\u5730\u5740 +jobgroup_field_registryList_invalid=\u6A5F\u5668\u5730\u5740\u683C\u5F0F\u975E\u6CD5 +jobgroup_field_registryList_placeholder=\u8ACB\u8F38\u5165\u57F7\u884C\u5668\u5730\u5740\u5217\u8868\uFF0C\u591A\u500B\u5730\u5740\u8ACB\u4EE5\u9017\u865F\u5206\u9694 +jobgroup_field_appname_limit=\u9650\u5236\u4EE5\u5C0F\u5BEB\u5B57\u6BCD\u958B\u982D\uFF0C\u7531\u5C0F\u5BEB\u5B57\u6BCD\u3001\u6578\u5B57\u548C\u4E2D\u5212\u7DDA\u7D44\u6210 +jobgroup_field_appname_length=AppName\u9577\u5EA6\u9650\u5236\u70BA4~64 +jobgroup_field_title_length=\u540D\u7A31\u9577\u5EA6\u9650\u5236\u70BA4~12 +jobgroup_field_order_digits=\u8ACB\u8F38\u5165\u6574\u6578 +jobgroup_field_orderrange=\u53D6\u503C\u7BC4\u570D\u70BA1~1000 +jobgroup_del_limit_0=\u62D2\u7D55\u522A\u9664\uFF0C\u8A72\u57F7\u884C\u5668\u4F7F\u7528\u4E2D +jobgroup_del_limit_1=\u62D2\u7D55\u5220\u9664\uFF0C\u7CFB\u7EDF\u81F3\u5C11\u4FDD\u7559\u4E00\u500B\u57F7\u884C\u5668 +jobgroup_empty=\u4E0D\u5B58\u5728\u6709\u6548\u57F7\u884C\u5668\uFF0C\u8ACB\u806F\u7D61\u7CFB\u7D71\u7BA1\u7406\u54E1 ## job conf -jobconf_block_SERIAL_EXECUTION=單機串行 -jobconf_block_DISCARD_LATER=丢棄后續調度 -jobconf_block_COVER_EARLY=覆蓋之前調度 -jobconf_route_first=第一個 -jobconf_route_last=最後一個 -jobconf_route_round=輪詢 -jobconf_route_random=隨機 -jobconf_route_consistenthash=一致性HASH -jobconf_route_lfu=最不經常使用 -jobconf_route_lru=最近最久未使用 -jobconf_route_failover=故障轉移 -jobconf_route_busyover=忙碌轉移 -jobconf_route_shard=分片廣播 -jobconf_idleBeat=空閒檢測 -jobconf_beat=心跳檢測 -jobconf_monitor=任務調度中心監控告警 -jobconf_monitor_detail=監控告警明细 -jobconf_monitor_alarm_title=告警類型 -jobconf_monitor_alarm_type=調度失敗 -jobconf_monitor_alarm_content=告警内容 -jobconf_trigger_admin_adress=調度機器 -jobconf_trigger_exe_regtype=執行器-注冊方式 -jobconf_trigger_exe_regaddress=執行器-地址列表 -jobconf_trigger_address_empty=調度失敗:執行器地址為空 -jobconf_trigger_run=觸發調度 -jobconf_trigger_child_run=觸發子任務 -jobconf_callback_child_msg1={0}/{1} [任務ID={2}], 觸發{3}, 觸發備註: {4}
-jobconf_callback_child_msg2={0}/{1} [任務ID={2}], 觸發失败, 觸發備註: 任務ID格式錯誤
-jobconf_trigger_type=任務觸發類型 -jobconf_trigger_type_cron=Cron觸發 -jobconf_trigger_type_manual=手動觸發 -jobconf_trigger_type_parent=父任務觸發 -jobconf_trigger_type_api=API觸發 -jobconf_trigger_type_retry=失敗重試觸發 -jobconf_trigger_type_misfire=調度過期補償 +jobconf_block_SERIAL_EXECUTION=\u55AE\u6A5F\u4E32\u884C +jobconf_block_DISCARD_LATER=\u4E22\u68C4\u540E\u7E8C\u8ABF\u5EA6 +jobconf_block_COVER_EARLY=\u8986\u84CB\u4E4B\u524D\u8ABF\u5EA6 +jobconf_route_first=\u7B2C\u4E00\u500B +jobconf_route_last=\u6700\u5F8C\u4E00\u500B +jobconf_route_round=\u8F2A\u8A62 +jobconf_route_random=\u96A8\u6A5F +jobconf_route_consistenthash=\u4E00\u81F4\u6027HASH +jobconf_route_lfu=\u6700\u4E0D\u7D93\u5E38\u4F7F\u7528 +jobconf_route_lru=\u6700\u8FD1\u6700\u4E45\u672A\u4F7F\u7528 +jobconf_route_failover=\u6545\u969C\u8F49\u79FB +jobconf_route_busyover=\u5FD9\u788C\u8F49\u79FB +jobconf_route_shard=\u5206\u7247\u5EE3\u64AD +jobconf_idleBeat=\u7A7A\u9592\u6AA2\u6E2C +jobconf_beat=\u5FC3\u8DF3\u6AA2\u6E2C +jobconf_monitor=\u4EFB\u52D9\u8ABF\u5EA6\u4E2D\u5FC3\u76E3\u63A7\u544A\u8B66 +jobconf_monitor_detail=\u76E3\u63A7\u544A\u8B66\u660E\u7EC6 +jobconf_monitor_alarm_title=\u544A\u8B66\u985E\u578B +jobconf_monitor_alarm_type=\u8ABF\u5EA6\u5931\u6557 +jobconf_monitor_alarm_content=\u544A\u8B66\u5185\u5BB9 +jobconf_trigger_admin_adress=\u8ABF\u5EA6\u6A5F\u5668 +jobconf_trigger_exe_regtype=\u57F7\u884C\u5668-\u6CE8\u518A\u65B9\u5F0F +jobconf_trigger_exe_regaddress=\u57F7\u884C\u5668-\u5730\u5740\u5217\u8868 +jobconf_trigger_address_empty=\u8ABF\u5EA6\u5931\u6557\uFF1A\u57F7\u884C\u5668\u5730\u5740\u70BA\u7A7A +jobconf_trigger_run=\u89F8\u767C\u8ABF\u5EA6 +jobconf_trigger_child_run=\u89F8\u767C\u5B50\u4EFB\u52D9 +jobconf_callback_child_msg1={0}/{1} [\u4EFB\u52D9ID={2}], \u89F8\u767C{3}, \u89F8\u767C\u5099\u8A3B: {4}
+jobconf_callback_child_msg2={0}/{1} [\u4EFB\u52D9ID={2}], \u89F8\u767C\u5931\u8D25, \u89F8\u767C\u5099\u8A3B: \u4EFB\u52D9ID\u683C\u5F0F\u932F\u8AA4
+jobconf_trigger_type=\u4EFB\u52D9\u89F8\u767C\u985E\u578B +jobconf_trigger_type_cron=Cron\u89F8\u767C +jobconf_trigger_type_manual=\u624B\u52D5\u89F8\u767C +jobconf_trigger_type_parent=\u7236\u4EFB\u52D9\u89F8\u767C +jobconf_trigger_type_api=API\u89F8\u767C +jobconf_trigger_type_retry=\u5931\u6557\u91CD\u8A66\u89F8\u767C +jobconf_trigger_type_misfire=\u8ABF\u5EA6\u904E\u671F\u88DC\u511F ## user -user_manage=用户管理 -user_username=帳號 -user_password=密碼 -user_role=角色 -user_role_admin=管理員 -user_role_normal=普通用戶 -user_permission=權限 -user_add=新增用戶 -user_update=更新用戶 -user_username_repeat=帳號重複 -user_username_valid=限制以小寫字母開頭,由小寫字母、數字組成 -user_password_update_placeholder=請輸入新密碼,為空則不更新密碼 -user_update_loginuser_limit=禁止操作當前登入帳號 - -## help -job_help=使用教程 -job_help_document=官方文件 \ No newline at end of file +user_manage=\u7528\u6237\u7BA1\u7406 +user_username=\u5E33\u865F +user_password=\u5BC6\u78BC +user_role=\u89D2\u8272 +user_role_admin=\u7BA1\u7406\u54E1 +user_role_normal=\u666E\u901A\u7528\u6236 +user_permission=\u6B0A\u9650 +user_add=\u65B0\u589E\u7528\u6236 +user_update=\u66F4\u65B0\u7528\u6236 +user_username_repeat=\u5E33\u865F\u91CD\u8907 +user_username_valid=\u9650\u5236\u4EE5\u5C0F\u5BEB\u5B57\u6BCD\u958B\u982D\uFF0C\u7531\u5C0F\u5BEB\u5B57\u6BCD\u3001\u6578\u5B57\u7D44\u6210 +user_password_update_placeholder=\u8ACB\u8F38\u5165\u65B0\u5BC6\u78BC\uFF0C\u70BA\u7A7A\u5247\u4E0D\u66F4\u65B0\u5BC6\u78BC +user_update_loginuser_limit=\u7981\u6B62\u64CD\u4F5C\u7576\u524D\u767B\u5165\u5E33\u865F diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobGroupMapper.xml b/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobGroupMapper.xml similarity index 89% rename from pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobGroupMapper.xml rename to pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobGroupMapper.xml index 56edb7de5..cc0d53a0f 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobGroupMapper.xml +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobGroupMapper.xml @@ -1,9 +1,9 @@ - + - + @@ -36,12 +36,12 @@ ORDER BY t.app_name, t.title, t.id ASC - + INSERT INTO xxl_job_group ( `app_name`, `title`, `address_type`, `address_list`, `update_time`) values ( #{appname}, #{title}, #{addressType}, #{addressList}, #{updateTime} ); - + UPDATE xxl_job_group SET `app_name` = #{appname}, `title` = #{title}, diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml b/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobInfoMapper.xml similarity index 84% rename from pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml rename to pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobInfoMapper.xml index 2d07b04e1..99d602add 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobInfoMapper.xml @@ -1,9 +1,9 @@ - + - + @@ -112,7 +112,7 @@ - + INSERT INTO xxl_job_info ( job_group, job_desc, @@ -175,7 +175,7 @@ WHERE t.id = #{id} - + UPDATE xxl_job_info SET job_group = #{jobGroup}, @@ -232,7 +232,7 @@ LIMIT #{pagesize} - + UPDATE xxl_job_info SET trigger_last_time = #{triggerLastTime}, @@ -244,4 +244,39 @@ AND trigger_status = 1 + + UPDATE xxl_job_info + SET + trigger_last_time = CASE id + + WHEN #{item.id} THEN #{item.triggerLastTime} + + ELSE trigger_last_time + END, + trigger_next_time = CASE id + + WHEN #{item.id} THEN #{item.triggerNextTime} + + ELSE trigger_next_time + END, + trigger_status = CASE id + + WHEN #{item.id} THEN + + + #{item.triggerStatus} + + trigger_status + + + ELSE trigger_status + END + WHERE id IN + + #{item.id} + + AND trigger_status = 1 + + + diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobLockMapper.xml b/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobLockMapper.xml new file mode 100644 index 000000000..812b5a3d7 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobLockMapper.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogGlueMapper.xml b/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobLogGlueMapper.xml similarity index 87% rename from pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogGlueMapper.xml rename to pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobLogGlueMapper.xml index de39a4cc5..b615b30be 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogGlueMapper.xml +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobLogGlueMapper.xml @@ -1,9 +1,9 @@ - + - + @@ -23,8 +23,7 @@ t.update_time - + INSERT INTO xxl_job_logglue ( `job_id`, `glue_type`, diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml b/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobLogMapper.xml similarity index 92% rename from pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml rename to pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobLogMapper.xml index f40e0fed5..9c32fdb6a 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobLogMapper.xml @@ -1,9 +1,9 @@ - + - + @@ -49,7 +49,7 @@ FROM xxl_job_log AS t - + AND t.job_group = #{jobGroup} @@ -75,7 +75,7 @@ AND t.handle_code = 0 - ORDER BY t.trigger_time DESC + ORDER BY t.id DESC LIMIT #{offset}, #{pagesize} @@ -83,7 +83,7 @@ SELECT count(1) FROM xxl_job_log AS t - + AND t.job_group = #{jobGroup} @@ -119,7 +119,7 @@ - + INSERT INTO xxl_job_log ( `job_group`, `job_id`, @@ -180,9 +180,10 @@ diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogReportMapper.xml b/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobLogReportMapper.xml similarity index 54% rename from pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogReportMapper.xml rename to pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobLogReportMapper.xml index e6840b4ec..756413546 100644 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogReportMapper.xml +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/mapper/XxlJobLogReportMapper.xml @@ -1,14 +1,15 @@ - + - + + @@ -16,34 +17,56 @@ t.trigger_day, t.running_count, t.suc_count, - t.fail_count + t.fail_count, + t.update_time - + INSERT INTO xxl_job_log_report ( + `trigger_day`, + `running_count`, + `suc_count`, + `fail_count` + ) VALUES ( + #{triggerDay}, + #{runningCount}, + #{sucCount}, + #{failCount} + ); + <!– + SELECT LAST_INSERT_ID() + –> + + + + UPDATE xxl_job_log_report + SET `running_count` = #{runningCount}, + `suc_count` = #{sucCount}, + `fail_count` = #{failCount} + WHERE `trigger_day` = #{triggerDay} + --> + + INSERT INTO xxl_job_log_report ( `trigger_day`, `running_count`, `suc_count`, - `fail_count` + `fail_count`, + `update_time` ) VALUES ( #{triggerDay}, #{runningCount}, #{sucCount}, - #{failCount} - ); - - - - - UPDATE xxl_job_log_report - SET `running_count` = #{runningCount}, + #{failCount}, + #{updateTime} + ) + ON DUPLICATE KEY UPDATE + `running_count` = #{runningCount}, `suc_count` = #{sucCount}, - `fail_count` = #{failCount} - WHERE `trigger_day` = #{triggerDay} - + `fail_count` = #{failCount}, + `update_time` = #{updateTime} + - + + + INSERT INTO xxl_job_user ( username, password, @@ -67,7 +76,7 @@ ); - + UPDATE xxl_job_user SET @@ -84,4 +93,10 @@ WHERE id = #{id} + + UPDATE xxl_job_user + SET token = #{token} + WHERE id = #{id} + + \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/adminlte/bower_components/PACE/pace.min.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/adminlte/bower_components/PACE/pace.min.js deleted file mode 100644 index 234f9b3e9..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/adminlte/bower_components/PACE/pace.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! pace 1.0.2 */ -(function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X=[].slice,Y={}.hasOwnProperty,Z=function(a,b){function c(){this.constructor=a}for(var d in b)Y.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},$=[].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1};for(u={catchupTime:100,initialRate:.03,minTime:250,ghostTime:100,maxProgressPerFrame:20,easeFactor:1.25,startOnPageLoad:!0,restartOnPushState:!0,restartOnRequestAfter:500,target:"body",elements:{checkInterval:100,selectors:["body"]},eventLag:{minSamples:10,sampleCount:3,lagThreshold:3},ajax:{trackMethods:["GET"],trackWebSockets:!0,ignoreURLs:[]}},C=function(){var a;return null!=(a="undefined"!=typeof performance&&null!==performance&&"function"==typeof performance.now?performance.now():void 0)?a:+new Date},E=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame,t=window.cancelAnimationFrame||window.mozCancelAnimationFrame,null==E&&(E=function(a){return setTimeout(a,50)},t=function(a){return clearTimeout(a)}),G=function(a){var b,c;return b=C(),(c=function(){var d;return d=C()-b,d>=33?(b=C(),a(d,function(){return E(c)})):setTimeout(c,33-d)})()},F=function(){var a,b,c;return c=arguments[0],b=arguments[1],a=3<=arguments.length?X.call(arguments,2):[],"function"==typeof c[b]?c[b].apply(c,a):c[b]},v=function(){var a,b,c,d,e,f,g;for(b=arguments[0],d=2<=arguments.length?X.call(arguments,1):[],f=0,g=d.length;g>f;f++)if(c=d[f])for(a in c)Y.call(c,a)&&(e=c[a],null!=b[a]&&"object"==typeof b[a]&&null!=e&&"object"==typeof e?v(b[a],e):b[a]=e);return b},q=function(a){var b,c,d,e,f;for(c=b=0,e=0,f=a.length;f>e;e++)d=a[e],c+=Math.abs(d),b++;return c/b},x=function(a,b){var c,d,e;if(null==a&&(a="options"),null==b&&(b=!0),e=document.querySelector("[data-pace-"+a+"]")){if(c=e.getAttribute("data-pace-"+a),!b)return c;try{return JSON.parse(c)}catch(f){return d=f,"undefined"!=typeof console&&null!==console?console.error("Error parsing inline pace options",d):void 0}}},g=function(){function a(){}return a.prototype.on=function(a,b,c,d){var e;return null==d&&(d=!1),null==this.bindings&&(this.bindings={}),null==(e=this.bindings)[a]&&(e[a]=[]),this.bindings[a].push({handler:b,ctx:c,once:d})},a.prototype.once=function(a,b,c){return this.on(a,b,c,!0)},a.prototype.off=function(a,b){var c,d,e;if(null!=(null!=(d=this.bindings)?d[a]:void 0)){if(null==b)return delete this.bindings[a];for(c=0,e=[];cQ;Q++)K=U[Q],D[K]===!0&&(D[K]=u[K]);i=function(a){function b(){return V=b.__super__.constructor.apply(this,arguments)}return Z(b,a),b}(Error),b=function(){function a(){this.progress=0}return a.prototype.getElement=function(){var a;if(null==this.el){if(a=document.querySelector(D.target),!a)throw new i;this.el=document.createElement("div"),this.el.className="pace pace-active",document.body.className=document.body.className.replace(/pace-done/g,""),document.body.className+=" pace-running",this.el.innerHTML='

\n
\n
\n
',null!=a.firstChild?a.insertBefore(this.el,a.firstChild):a.appendChild(this.el)}return this.el},a.prototype.finish=function(){var a;return a=this.getElement(),a.className=a.className.replace("pace-active",""),a.className+=" pace-inactive",document.body.className=document.body.className.replace("pace-running",""),document.body.className+=" pace-done"},a.prototype.update=function(a){return this.progress=a,this.render()},a.prototype.destroy=function(){try{this.getElement().parentNode.removeChild(this.getElement())}catch(a){i=a}return this.el=void 0},a.prototype.render=function(){var a,b,c,d,e,f,g;if(null==document.querySelector(D.target))return!1;for(a=this.getElement(),d="translate3d("+this.progress+"%, 0, 0)",g=["webkitTransform","msTransform","transform"],e=0,f=g.length;f>e;e++)b=g[e],a.children[0].style[b]=d;return(!this.lastRenderedProgress||this.lastRenderedProgress|0!==this.progress|0)&&(a.children[0].setAttribute("data-progress-text",""+(0|this.progress)+"%"),this.progress>=100?c="99":(c=this.progress<10?"0":"",c+=0|this.progress),a.children[0].setAttribute("data-progress",""+c)),this.lastRenderedProgress=this.progress},a.prototype.done=function(){return this.progress>=100},a}(),h=function(){function a(){this.bindings={}}return a.prototype.trigger=function(a,b){var c,d,e,f,g;if(null!=this.bindings[a]){for(f=this.bindings[a],g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push(c.call(this,b));return g}},a.prototype.on=function(a,b){var c;return null==(c=this.bindings)[a]&&(c[a]=[]),this.bindings[a].push(b)},a}(),P=window.XMLHttpRequest,O=window.XDomainRequest,N=window.WebSocket,w=function(a,b){var c,d,e;e=[];for(d in b.prototype)try{e.push(null==a[d]&&"function"!=typeof b[d]?"function"==typeof Object.defineProperty?Object.defineProperty(a,d,{get:function(){return b.prototype[d]},configurable:!0,enumerable:!0}):a[d]=b.prototype[d]:void 0)}catch(f){c=f}return e},A=[],j.ignore=function(){var a,b,c;return b=arguments[0],a=2<=arguments.length?X.call(arguments,1):[],A.unshift("ignore"),c=b.apply(null,a),A.shift(),c},j.track=function(){var a,b,c;return b=arguments[0],a=2<=arguments.length?X.call(arguments,1):[],A.unshift("track"),c=b.apply(null,a),A.shift(),c},J=function(a){var b;if(null==a&&(a="GET"),"track"===A[0])return"force";if(!A.length&&D.ajax){if("socket"===a&&D.ajax.trackWebSockets)return!0;if(b=a.toUpperCase(),$.call(D.ajax.trackMethods,b)>=0)return!0}return!1},k=function(a){function b(){var a,c=this;b.__super__.constructor.apply(this,arguments),a=function(a){var b;return b=a.open,a.open=function(d,e){return J(d)&&c.trigger("request",{type:d,url:e,request:a}),b.apply(a,arguments)}},window.XMLHttpRequest=function(b){var c;return c=new P(b),a(c),c};try{w(window.XMLHttpRequest,P)}catch(d){}if(null!=O){window.XDomainRequest=function(){var b;return b=new O,a(b),b};try{w(window.XDomainRequest,O)}catch(d){}}if(null!=N&&D.ajax.trackWebSockets){window.WebSocket=function(a,b){var d;return d=null!=b?new N(a,b):new N(a),J("socket")&&c.trigger("request",{type:"socket",url:a,protocols:b,request:d}),d};try{w(window.WebSocket,N)}catch(d){}}}return Z(b,a),b}(h),R=null,y=function(){return null==R&&(R=new k),R},I=function(a){var b,c,d,e;for(e=D.ajax.ignoreURLs,c=0,d=e.length;d>c;c++)if(b=e[c],"string"==typeof b){if(-1!==a.indexOf(b))return!0}else if(b.test(a))return!0;return!1},y().on("request",function(b){var c,d,e,f,g;return f=b.type,e=b.request,g=b.url,I(g)?void 0:j.running||D.restartOnRequestAfter===!1&&"force"!==J(f)?void 0:(d=arguments,c=D.restartOnRequestAfter||0,"boolean"==typeof c&&(c=0),setTimeout(function(){var b,c,g,h,i,k;if(b="socket"===f?e.readyState<2:0<(h=e.readyState)&&4>h){for(j.restart(),i=j.sources,k=[],c=0,g=i.length;g>c;c++){if(K=i[c],K instanceof a){K.watch.apply(K,d);break}k.push(void 0)}return k}},c))}),a=function(){function a(){var a=this;this.elements=[],y().on("request",function(){return a.watch.apply(a,arguments)})}return a.prototype.watch=function(a){var b,c,d,e;return d=a.type,b=a.request,e=a.url,I(e)?void 0:(c="socket"===d?new n(b):new o(b),this.elements.push(c))},a}(),o=function(){function a(a){var b,c,d,e,f,g,h=this;if(this.progress=0,null!=window.ProgressEvent)for(c=null,a.addEventListener("progress",function(a){return h.progress=a.lengthComputable?100*a.loaded/a.total:h.progress+(100-h.progress)/2},!1),g=["load","abort","timeout","error"],d=0,e=g.length;e>d;d++)b=g[d],a.addEventListener(b,function(){return h.progress=100},!1);else f=a.onreadystatechange,a.onreadystatechange=function(){var b;return 0===(b=a.readyState)||4===b?h.progress=100:3===a.readyState&&(h.progress=50),"function"==typeof f?f.apply(null,arguments):void 0}}return a}(),n=function(){function a(a){var b,c,d,e,f=this;for(this.progress=0,e=["error","open"],c=0,d=e.length;d>c;c++)b=e[c],a.addEventListener(b,function(){return f.progress=100},!1)}return a}(),d=function(){function a(a){var b,c,d,f;for(null==a&&(a={}),this.elements=[],null==a.selectors&&(a.selectors=[]),f=a.selectors,c=0,d=f.length;d>c;c++)b=f[c],this.elements.push(new e(b))}return a}(),e=function(){function a(a){this.selector=a,this.progress=0,this.check()}return a.prototype.check=function(){var a=this;return document.querySelector(this.selector)?this.done():setTimeout(function(){return a.check()},D.elements.checkInterval)},a.prototype.done=function(){return this.progress=100},a}(),c=function(){function a(){var a,b,c=this;this.progress=null!=(b=this.states[document.readyState])?b:100,a=document.onreadystatechange,document.onreadystatechange=function(){return null!=c.states[document.readyState]&&(c.progress=c.states[document.readyState]),"function"==typeof a?a.apply(null,arguments):void 0}}return a.prototype.states={loading:0,interactive:50,complete:100},a}(),f=function(){function a(){var a,b,c,d,e,f=this;this.progress=0,a=0,e=[],d=0,c=C(),b=setInterval(function(){var g;return g=C()-c-50,c=C(),e.push(g),e.length>D.eventLag.sampleCount&&e.shift(),a=q(e),++d>=D.eventLag.minSamples&&a=100&&(this.done=!0),b===this.last?this.sinceLastUpdate+=a:(this.sinceLastUpdate&&(this.rate=(b-this.last)/this.sinceLastUpdate),this.catchup=(b-this.progress)/D.catchupTime,this.sinceLastUpdate=0,this.last=b),b>this.progress&&(this.progress+=this.catchup*a),c=1-Math.pow(this.progress/100,D.easeFactor),this.progress+=c*this.rate*a,this.progress=Math.min(this.lastProgress+D.maxProgressPerFrame,this.progress),this.progress=Math.max(0,this.progress),this.progress=Math.min(100,this.progress),this.lastProgress=this.progress,this.progress},a}(),L=null,H=null,r=null,M=null,p=null,s=null,j.running=!1,z=function(){return D.restartOnPushState?j.restart():void 0},null!=window.history.pushState&&(T=window.history.pushState,window.history.pushState=function(){return z(),T.apply(window.history,arguments)}),null!=window.history.replaceState&&(W=window.history.replaceState,window.history.replaceState=function(){return z(),W.apply(window.history,arguments)}),l={ajax:a,elements:d,document:c,eventLag:f},(B=function(){var a,c,d,e,f,g,h,i;for(j.sources=L=[],g=["ajax","elements","document","eventLag"],c=0,e=g.length;e>c;c++)a=g[c],D[a]!==!1&&L.push(new l[a](D[a]));for(i=null!=(h=D.extraSources)?h:[],d=0,f=i.length;f>d;d++)K=i[d],L.push(new K(D));return j.bar=r=new b,H=[],M=new m})(),j.stop=function(){return j.trigger("stop"),j.running=!1,r.destroy(),s=!0,null!=p&&("function"==typeof t&&t(p),p=null),B()},j.restart=function(){return j.trigger("restart"),j.stop(),j.start()},j.go=function(){var a;return j.running=!0,r.render(),a=C(),s=!1,p=G(function(b,c){var d,e,f,g,h,i,k,l,n,o,p,q,t,u,v,w;for(l=100-r.progress,e=p=0,f=!0,i=q=0,u=L.length;u>q;i=++q)for(K=L[i],o=null!=H[i]?H[i]:H[i]=[],h=null!=(w=K.elements)?w:[K],k=t=0,v=h.length;v>t;k=++t)g=h[k],n=null!=o[k]?o[k]:o[k]=new m(g),f&=n.done,n.done||(e++,p+=n.tick(b));return d=p/e,r.update(M.tick(b,d)),r.done()||f||s?(r.update(100),j.trigger("done"),setTimeout(function(){return r.finish(),j.running=!1,j.trigger("hide")},Math.max(D.ghostTime,Math.max(D.minTime-(C()-a),0)))):c()})},j.start=function(a){v(D,a),j.running=!0;try{r.render()}catch(b){i=b}return document.querySelector(".pace")?(j.trigger("start"),j.go()):setTimeout(j.start,50)},"function"==typeof define&&define.amd?define(["pace"],function(){return j}):"object"==typeof exports?module.exports=j:D.startOnPageLoad&&j.start()}).call(this); \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/adminlte/bower_components/PACE/themes/blue/pace-theme-flash.css b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/adminlte/bower_components/PACE/themes/blue/pace-theme-flash.css deleted file mode 100644 index d9bca466a..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/adminlte/bower_components/PACE/themes/blue/pace-theme-flash.css +++ /dev/null @@ -1,77 +0,0 @@ -/* This is a compiled file, you should be editing the file in the templates directory */ -.pace { - -webkit-pointer-events: none; - pointer-events: none; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; -} - -.pace-inactive { - display: none; -} - -.pace .pace-progress { - background: #2299dd; - position: fixed; - z-index: 2000; - top: 0; - right: 100%; - width: 100%; - height: 2px; -} - -.pace .pace-progress-inner { - display: block; - position: absolute; - right: 0px; - width: 100px; - height: 100%; - box-shadow: 0 0 10px #2299dd, 0 0 5px #2299dd; - opacity: 1.0; - -webkit-transform: rotate(3deg) translate(0px, -4px); - -moz-transform: rotate(3deg) translate(0px, -4px); - -ms-transform: rotate(3deg) translate(0px, -4px); - -o-transform: rotate(3deg) translate(0px, -4px); - transform: rotate(3deg) translate(0px, -4px); -} - -.pace .pace-activity { - display: block; - position: fixed; - z-index: 2000; - top: 15px; - right: 15px; - width: 14px; - height: 14px; - border: solid 2px transparent; - border-top-color: #2299dd; - border-left-color: #2299dd; - border-radius: 10px; - -webkit-animation: pace-spinner 400ms linear infinite; - -moz-animation: pace-spinner 400ms linear infinite; - -ms-animation: pace-spinner 400ms linear infinite; - -o-animation: pace-spinner 400ms linear infinite; - animation: pace-spinner 400ms linear infinite; -} - -@-webkit-keyframes pace-spinner { - 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } - 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); } -} -@-moz-keyframes pace-spinner { - 0% { -moz-transform: rotate(0deg); transform: rotate(0deg); } - 100% { -moz-transform: rotate(360deg); transform: rotate(360deg); } -} -@-o-keyframes pace-spinner { - 0% { -o-transform: rotate(0deg); transform: rotate(0deg); } - 100% { -o-transform: rotate(360deg); transform: rotate(360deg); } -} -@-ms-keyframes pace-spinner { - 0% { -ms-transform: rotate(0deg); transform: rotate(0deg); } - 100% { -ms-transform: rotate(360deg); transform: rotate(360deg); } -} -@keyframes pace-spinner { - 0% { transform: rotate(0deg); transform: rotate(0deg); } - 100% { transform: rotate(360deg); transform: rotate(360deg); } -} diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/ckeditor.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/ckeditor.js new file mode 100644 index 000000000..4c5f558b9 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/ckeditor.js @@ -0,0 +1,1236 @@ +/* +Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license +*/ +(function(){window.CKEDITOR&&window.CKEDITOR.dom||(window.CKEDITOR||(window.CKEDITOR=function(){var a=/(^|.*[\\\/])ckeditor\.js(?:\?.*|;.*)?$/i,f={timestamp:"J5S9",version:"4.12.1 (Standard)",revision:"64749bb245",rnd:Math.floor(900*Math.random())+100,_:{pending:[],basePathSrcPattern:a},status:"unloaded",basePath:function(){var b=window.CKEDITOR_BASEPATH||"";if(!b)for(var c=document.getElementsByTagName("script"),f=0;fe.getListenerIndex(d)){e=e.listeners;f||(f=this);isNaN(g)&&(g=10);var n=this;h.fn=d;h.priority=g;for(var q=e.length-1;0<=q;q--)if(e[q].priority<=g)return e.splice(q+1,0,h),{removeListener:m};e.unshift(h)}return{removeListener:m}},once:function(){var a=Array.prototype.slice.call(arguments),b=a[1];a[1]=function(a){a.removeListener();return b.apply(this, +arguments)};return this.on.apply(this,a)},capture:function(){CKEDITOR.event.useCapture=1;var a=this.on.apply(this,arguments);CKEDITOR.event.useCapture=0;return a},fire:function(){var a=0,b=function(){a=1},l=0,k=function(){l=1};return function(g,h,m){var e=f(this)[g];g=a;var n=l;a=l=0;if(e){var q=e.listeners;if(q.length)for(var q=q.slice(0),y,u=0;udocument.documentMode),mobile:-1c||b.quirks);b.gecko&&(f=a.match(/rv:([\d\.]+)/))&&(f=f[1].split("."),c=1E4*f[0]+100*(f[1]||0)+1*(f[2]||0));b.air&&(c=parseFloat(a.match(/ adobeair\/(\d+)/)[1]));b.webkit&&(c=parseFloat(a.match(/ applewebkit\/(\d+)/)[1]));b.version=c;b.isCompatible=!(b.ie&&7>c)&&!(b.gecko&&4E4>c)&&!(b.webkit&& +534>c);b.hidpi=2<=window.devicePixelRatio;b.needsBrFiller=b.gecko||b.webkit||b.ie&&10c;b.cssClass="cke_browser_"+(b.ie?"ie":b.gecko?"gecko":b.webkit?"webkit":"unknown");b.quirks&&(b.cssClass+=" cke_browser_quirks");b.ie&&(b.cssClass+=" cke_browser_ie"+(b.quirks?"6 cke_browser_iequirks":b.version));b.air&&(b.cssClass+=" cke_browser_air");b.iOS&&(b.cssClass+=" cke_browser_ios");b.hidpi&&(b.cssClass+=" cke_hidpi");return b}()),"unloaded"==CKEDITOR.status&&function(){CKEDITOR.event.implementOn(CKEDITOR); +CKEDITOR.loadFullCore=function(){if("basic_ready"!=CKEDITOR.status)CKEDITOR.loadFullCore._load=1;else{delete CKEDITOR.loadFullCore;var a=document.createElement("script");a.type="text/javascript";a.src=CKEDITOR.basePath+"ckeditor.js";document.getElementsByTagName("head")[0].appendChild(a)}};CKEDITOR.loadFullCoreTimeout=0;CKEDITOR.add=function(a){(this._.pending||(this._.pending=[])).push(a)};(function(){CKEDITOR.domReady(function(){var a=CKEDITOR.loadFullCore,f=CKEDITOR.loadFullCoreTimeout;a&&(CKEDITOR.status= +"basic_ready",a&&a._load?a():f&&setTimeout(function(){CKEDITOR.loadFullCore&&CKEDITOR.loadFullCore()},1E3*f))})})();CKEDITOR.status="basic_loaded"}(),"use strict",CKEDITOR.VERBOSITY_WARN=1,CKEDITOR.VERBOSITY_ERROR=2,CKEDITOR.verbosity=CKEDITOR.VERBOSITY_WARN|CKEDITOR.VERBOSITY_ERROR,CKEDITOR.warn=function(a,f){CKEDITOR.verbosity&CKEDITOR.VERBOSITY_WARN&&CKEDITOR.fire("log",{type:"warn",errorCode:a,additionalData:f})},CKEDITOR.error=function(a,f){CKEDITOR.verbosity&CKEDITOR.VERBOSITY_ERROR&&CKEDITOR.fire("log", +{type:"error",errorCode:a,additionalData:f})},CKEDITOR.on("log",function(a){if(window.console&&window.console.log){var f=console[a.data.type]?a.data.type:"log",b=a.data.errorCode;if(a=a.data.additionalData)console[f]("[CKEDITOR] Error code: "+b+".",a);else console[f]("[CKEDITOR] Error code: "+b+".");console[f]("[CKEDITOR] For more information about this error go to https://ckeditor.com/docs/ckeditor4/latest/guide/dev_errors.html#"+b)}},null,null,999),CKEDITOR.dom={},function(){function a(a,e,b){this._minInterval= +a;this._context=b;this._lastOutput=this._scheduledTimer=0;this._output=CKEDITOR.tools.bind(e,b||{});var g=this;this.input=function(){function a(){g._lastOutput=(new Date).getTime();g._scheduledTimer=0;g._call()}if(!g._scheduledTimer||!1!==g._reschedule()){var e=(new Date).getTime()-g._lastOutput;e/g,k=/|\s) /g,function(a,e){return e+"\x26nbsp;"}).replace(/ (?=<)/g,"\x26nbsp;")},getNextNumber:function(){var a=0;return function(){return++a}}(),getNextId:function(){return"cke_"+this.getNextNumber()},getUniqueId:function(){for(var a="e",e=0;8>e;e++)a+=Math.floor(65536*(1+Math.random())).toString(16).substring(1);return a},override:function(a,e){var g=e(a);g.prototype=a.prototype;return g},setTimeout:function(a,e,g,b,h){h||(h=window);g||(g= +h);return h.setTimeout(function(){b?a.apply(g,[].concat(b)):a.apply(g)},e||0)},throttle:function(a,e,g){return new this.buffers.throttle(a,e,g)},trim:function(){var a=/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g;return function(e){return e.replace(a,"")}}(),ltrim:function(){var a=/^[ \t\n\r]+/g;return function(e){return e.replace(a,"")}}(),rtrim:function(){var a=/[ \t\n\r]+$/g;return function(e){return e.replace(a,"")}}(),indexOf:function(a,e){if("function"==typeof e)for(var g=0,b=a.length;gparseFloat(e);g&&(e=e.replace("-",""));a.setStyle("width",e);e=a.$.clientWidth;return g?-e:e}return e}}(),repeat:function(a, +e){return Array(e+1).join(a)},tryThese:function(){for(var a,e=0,g=arguments.length;ee;e++)a[e]=("0"+parseInt(a[e],10).toString(16)).slice(-2);return"#"+a.join("")})},normalizeHex:function(a){return a.replace(/#(([0-9a-f]{3}){1,2})($|;|\s+)/gi,function(a,e,g,b){a=e.toLowerCase();3==a.length&&(a=a.split(""),a=[a[0],a[0],a[1],a[1],a[2],a[2]].join(""));return"#"+a+b})},parseCssText:function(a,e,g){var b={};g&&(a=(new CKEDITOR.dom.element("span")).setAttribute("style",a).getAttribute("style")||"");a&&(a=CKEDITOR.tools.normalizeHex(CKEDITOR.tools.convertRgbToHex(a))); +if(!a||";"==a)return b;a.replace(/"/g,'"').replace(/\s*([^:;\s]+)\s*:\s*([^;]+)\s*(?=;|$)/g,function(a,g,h){e&&(g=g.toLowerCase(),"font-family"==g&&(h=h.replace(/\s*,\s*/g,",")),h=CKEDITOR.tools.trim(h));b[g]=h});return b},writeCssText:function(a,e){var g,b=[];for(g in a)b.push(g+":"+a[g]);e&&b.sort();return b.join("; ")},objectCompare:function(a,e,g){var b;if(!a&&!e)return!0;if(!a||!e)return!1;for(b in a)if(a[b]!=e[b])return!1;if(!g)for(b in e)if(a[b]!=e[b])return!1;return!0},objectKeys:function(a){return CKEDITOR.tools.object.keys(a)}, +convertArrayToObject:function(a,e){var g={};1==arguments.length&&(e=!0);for(var b=0,h=a.length;bg;g++)a.push(Math.floor(256*Math.random())); +for(g=0;gCKEDITOR.env.version||CKEDITOR.env.ie6Compat)?4===a.button?CKEDITOR.MOUSE_BUTTON_MIDDLE:1===a.button? +CKEDITOR.MOUSE_BUTTON_LEFT:CKEDITOR.MOUSE_BUTTON_RIGHT:a.button:!1},convertHexStringToBytes:function(a){var e=[],g=a.length/2,b;for(b=0;bc)for(m=c;3>m;m++)h[m]=0;d[0]=(h[0]&252)>>2;d[1]=(h[0]&3)<<4|h[1]>>4;d[2]=(h[1]&15)<<2|(h[2]&192)>>6;d[3]=h[2]&63;for(m=0;4>m;m++)e=m<=c?e+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d[m]): +e+"\x3d"}return e},style:{parse:{_colors:{aliceblue:"#F0F8FF",antiquewhite:"#FAEBD7",aqua:"#00FFFF",aquamarine:"#7FFFD4",azure:"#F0FFFF",beige:"#F5F5DC",bisque:"#FFE4C4",black:"#000000",blanchedalmond:"#FFEBCD",blue:"#0000FF",blueviolet:"#8A2BE2",brown:"#A52A2A",burlywood:"#DEB887",cadetblue:"#5F9EA0",chartreuse:"#7FFF00",chocolate:"#D2691E",coral:"#FF7F50",cornflowerblue:"#6495ED",cornsilk:"#FFF8DC",crimson:"#DC143C",cyan:"#00FFFF",darkblue:"#00008B",darkcyan:"#008B8B",darkgoldenrod:"#B8860B",darkgray:"#A9A9A9", +darkgreen:"#006400",darkgrey:"#A9A9A9",darkkhaki:"#BDB76B",darkmagenta:"#8B008B",darkolivegreen:"#556B2F",darkorange:"#FF8C00",darkorchid:"#9932CC",darkred:"#8B0000",darksalmon:"#E9967A",darkseagreen:"#8FBC8F",darkslateblue:"#483D8B",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",darkturquoise:"#00CED1",darkviolet:"#9400D3",deeppink:"#FF1493",deepskyblue:"#00BFFF",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1E90FF",firebrick:"#B22222",floralwhite:"#FFFAF0",forestgreen:"#228B22",fuchsia:"#FF00FF", +gainsboro:"#DCDCDC",ghostwhite:"#F8F8FF",gold:"#FFD700",goldenrod:"#DAA520",gray:"#808080",green:"#008000",greenyellow:"#ADFF2F",grey:"#808080",honeydew:"#F0FFF0",hotpink:"#FF69B4",indianred:"#CD5C5C",indigo:"#4B0082",ivory:"#FFFFF0",khaki:"#F0E68C",lavender:"#E6E6FA",lavenderblush:"#FFF0F5",lawngreen:"#7CFC00",lemonchiffon:"#FFFACD",lightblue:"#ADD8E6",lightcoral:"#F08080",lightcyan:"#E0FFFF",lightgoldenrodyellow:"#FAFAD2",lightgray:"#D3D3D3",lightgreen:"#90EE90",lightgrey:"#D3D3D3",lightpink:"#FFB6C1", +lightsalmon:"#FFA07A",lightseagreen:"#20B2AA",lightskyblue:"#87CEFA",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#B0C4DE",lightyellow:"#FFFFE0",lime:"#00FF00",limegreen:"#32CD32",linen:"#FAF0E6",magenta:"#FF00FF",maroon:"#800000",mediumaquamarine:"#66CDAA",mediumblue:"#0000CD",mediumorchid:"#BA55D3",mediumpurple:"#9370DB",mediumseagreen:"#3CB371",mediumslateblue:"#7B68EE",mediumspringgreen:"#00FA9A",mediumturquoise:"#48D1CC",mediumvioletred:"#C71585",midnightblue:"#191970",mintcream:"#F5FFFA", +mistyrose:"#FFE4E1",moccasin:"#FFE4B5",navajowhite:"#FFDEAD",navy:"#000080",oldlace:"#FDF5E6",olive:"#808000",olivedrab:"#6B8E23",orange:"#FFA500",orangered:"#FF4500",orchid:"#DA70D6",palegoldenrod:"#EEE8AA",palegreen:"#98FB98",paleturquoise:"#AFEEEE",palevioletred:"#DB7093",papayawhip:"#FFEFD5",peachpuff:"#FFDAB9",peru:"#CD853F",pink:"#FFC0CB",plum:"#DDA0DD",powderblue:"#B0E0E6",purple:"#800080",rebeccapurple:"#663399",red:"#FF0000",rosybrown:"#BC8F8F",royalblue:"#4169E1",saddlebrown:"#8B4513",salmon:"#FA8072", +sandybrown:"#F4A460",seagreen:"#2E8B57",seashell:"#FFF5EE",sienna:"#A0522D",silver:"#C0C0C0",skyblue:"#87CEEB",slateblue:"#6A5ACD",slategray:"#708090",slategrey:"#708090",snow:"#FFFAFA",springgreen:"#00FF7F",steelblue:"#4682B4",tan:"#D2B48C",teal:"#008080",thistle:"#D8BFD8",tomato:"#FF6347",turquoise:"#40E0D0",violet:"#EE82EE",windowtext:"windowtext",wheat:"#F5DEB3",white:"#FFFFFF",whitesmoke:"#F5F5F5",yellow:"#FFFF00",yellowgreen:"#9ACD32"},_borderStyle:"none hidden dotted dashed solid double groove ridge inset outset".split(" "), +_widthRegExp:/^(thin|medium|thick|[\+-]?\d+(\.\d+)?[a-z%]+|[\+-]?0+(\.0+)?|\.\d+[a-z%]+)$/,_rgbaRegExp:/rgba?\(\s*\d+%?\s*,\s*\d+%?\s*,\s*\d+%?\s*(?:,\s*[0-9.]+\s*)?\)/gi,_hslaRegExp:/hsla?\(\s*[0-9.]+\s*,\s*\d+%\s*,\s*\d+%\s*(?:,\s*[0-9.]+\s*)?\)/gi,background:function(a){var e={},g=this._findColor(a);g.length&&(e.color=g[0],CKEDITOR.tools.array.forEach(g,function(e){a=a.replace(e,"")}));if(a=CKEDITOR.tools.trim(a))e.unprocessed=a;return e},margin:function(a){return CKEDITOR.tools.style.parse.sideShorthand(a, +function(a){return a.match(/(?:\-?[\.\d]+(?:%|\w*)|auto|inherit|initial|unset|revert)/g)||["0px"]})},sideShorthand:function(a,e){function g(a){b.top=h[a[0]];b.right=h[a[1]];b.bottom=h[a[2]];b.left=h[a[3]]}var b={},h=e?e(a):a.split(/\s+/);switch(h.length){case 1:g([0,0,0,0]);break;case 2:g([0,1,0,1]);break;case 3:g([0,1,2,1]);break;case 4:g([0,1,2,3])}return b},border:function(a){return CKEDITOR.tools.style.border.fromCssRule(a)},_findColor:function(a){var e=[],g=CKEDITOR.tools.array,e=e.concat(a.match(this._rgbaRegExp)|| +[]),e=e.concat(a.match(this._hslaRegExp)||[]);return e=e.concat(g.filter(a.split(/\s+/),function(a){return a.match(/^\#[a-f0-9]{3}(?:[a-f0-9]{3})?$/gi)?!0:a.toLowerCase()in CKEDITOR.tools.style.parse._colors}))}}},array:{filter:function(a,e,g){var b=[];this.forEach(a,function(h,c){e.call(g,h,c,a)&&b.push(h)});return b},find:function(a,e,g){for(var b=a.length,h=0;hCKEDITOR.env.version)for(h=0;hCKEDITOR.env.version&&(this.type==CKEDITOR.NODE_ELEMENT||this.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT)&&c(d);return d},hasPrevious:function(){return!!this.$.previousSibling},hasNext:function(){return!!this.$.nextSibling},insertAfter:function(a){a.$.parentNode.insertBefore(this.$,a.$.nextSibling);return a},insertBefore:function(a){a.$.parentNode.insertBefore(this.$, +a.$);return a},insertBeforeMe:function(a){this.$.parentNode.insertBefore(a.$,this.$);return a},getAddress:function(a){for(var f=[],b=this.getDocument().$.documentElement,c=this.$;c&&c!=b;){var d=c.parentNode;d&&f.unshift(this.getIndex.call({$:c},a));c=d}return f},getDocument:function(){return new CKEDITOR.dom.document(this.$.ownerDocument||this.$.parentNode.ownerDocument)},getIndex:function(a){function f(a,g){var h=g?a.nextSibling:a.previousSibling;return h&&h.nodeType==CKEDITOR.NODE_TEXT?b(h)?f(h, +g):h:null}function b(a){return!a.nodeValue||a.nodeValue==CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE}var c=this.$,d=-1,l;if(!this.$.parentNode||a&&c.nodeType==CKEDITOR.NODE_TEXT&&b(c)&&!f(c)&&!f(c,!0))return-1;do a&&c!=this.$&&c.nodeType==CKEDITOR.NODE_TEXT&&(l||b(c))||(d++,l=c.nodeType==CKEDITOR.NODE_TEXT);while(c=c.previousSibling);return d},getNextSourceNode:function(a,f,b){if(b&&!b.call){var c=b;b=function(a){return!a.equals(c)}}a=!a&&this.getFirst&&this.getFirst();var d;if(!a){if(this.type== +CKEDITOR.NODE_ELEMENT&&b&&!1===b(this,!0))return null;a=this.getNext()}for(;!a&&(d=(d||this).getParent());){if(b&&!1===b(d,!0))return null;a=d.getNext()}return!a||b&&!1===b(a)?null:f&&f!=a.type?a.getNextSourceNode(!1,f,b):a},getPreviousSourceNode:function(a,f,b){if(b&&!b.call){var c=b;b=function(a){return!a.equals(c)}}a=!a&&this.getLast&&this.getLast();var d;if(!a){if(this.type==CKEDITOR.NODE_ELEMENT&&b&&!1===b(this,!0))return null;a=this.getPrevious()}for(;!a&&(d=(d||this).getParent());){if(b&&!1=== +b(d,!0))return null;a=d.getPrevious()}return!a||b&&!1===b(a)?null:f&&a.type!=f?a.getPreviousSourceNode(!1,f,b):a},getPrevious:function(a){var f=this.$,b;do b=(f=f.previousSibling)&&10!=f.nodeType&&new CKEDITOR.dom.node(f);while(b&&a&&!a(b));return b},getNext:function(a){var f=this.$,b;do b=(f=f.nextSibling)&&new CKEDITOR.dom.node(f);while(b&&a&&!a(b));return b},getParent:function(a){var f=this.$.parentNode;return f&&(f.nodeType==CKEDITOR.NODE_ELEMENT||a&&f.nodeType==CKEDITOR.NODE_DOCUMENT_FRAGMENT)? +new CKEDITOR.dom.node(f):null},getParents:function(a){var f=this,b=[];do b[a?"push":"unshift"](f);while(f=f.getParent());return b},getCommonAncestor:function(a){if(a.equals(this))return this;if(a.contains&&a.contains(this))return a;var f=this.contains?this:this.getParent();do if(f.contains(a))return f;while(f=f.getParent());return null},getPosition:function(a){var f=this.$,b=a.$;if(f.compareDocumentPosition)return f.compareDocumentPosition(b);if(f==b)return CKEDITOR.POSITION_IDENTICAL;if(this.type== +CKEDITOR.NODE_ELEMENT&&a.type==CKEDITOR.NODE_ELEMENT){if(f.contains){if(f.contains(b))return CKEDITOR.POSITION_CONTAINS+CKEDITOR.POSITION_PRECEDING;if(b.contains(f))return CKEDITOR.POSITION_IS_CONTAINED+CKEDITOR.POSITION_FOLLOWING}if("sourceIndex"in f)return 0>f.sourceIndex||0>b.sourceIndex?CKEDITOR.POSITION_DISCONNECTED:f.sourceIndex=document.documentMode||!f||(a=f+":"+a);return new CKEDITOR.dom.nodeList(this.$.getElementsByTagName(a))},getHead:function(){var a=this.$.getElementsByTagName("head")[0];return a=a?new CKEDITOR.dom.element(a):this.getDocumentElement().append(new CKEDITOR.dom.element("head"),!0)},getBody:function(){return new CKEDITOR.dom.element(this.$.body)}, +getDocumentElement:function(){return new CKEDITOR.dom.element(this.$.documentElement)},getWindow:function(){return new CKEDITOR.dom.window(this.$.parentWindow||this.$.defaultView)},write:function(a){this.$.open("text/html","replace");CKEDITOR.env.ie&&(a=a.replace(/(?:^\s*]*?>)|^/i,'$\x26\n\x3cscript data-cke-temp\x3d"1"\x3e('+CKEDITOR.tools.fixDomain+")();\x3c/script\x3e"));this.$.write(a);this.$.close()},find:function(a){return new CKEDITOR.dom.nodeList(this.$.querySelectorAll(a))},findOne:function(a){return(a= +this.$.querySelector(a))?new CKEDITOR.dom.element(a):null},_getHtml5ShivFrag:function(){var a=this.getCustomData("html5ShivFrag");a||(a=this.$.createDocumentFragment(),CKEDITOR.tools.enableHtml5Elements(a,!0),this.setCustomData("html5ShivFrag",a));return a}}),CKEDITOR.dom.nodeList=function(a){this.$=a},CKEDITOR.dom.nodeList.prototype={count:function(){return this.$.length},getItem:function(a){return 0>a||a>=this.$.length?null:(a=this.$[a])?new CKEDITOR.dom.node(a):null},toArray:function(){return CKEDITOR.tools.array.map(this.$, +function(a){return new CKEDITOR.dom.node(a)})}},CKEDITOR.dom.element=function(a,f){"string"==typeof a&&(a=(f?f.$:document).createElement(a));CKEDITOR.dom.domObject.call(this,a)},CKEDITOR.dom.element.get=function(a){return(a="string"==typeof a?document.getElementById(a)||document.getElementsByName(a)[0]:a)&&(a.$?a:new CKEDITOR.dom.element(a))},CKEDITOR.dom.element.prototype=new CKEDITOR.dom.node,CKEDITOR.dom.element.createFromHtml=function(a,f){var b=new CKEDITOR.dom.element("div",f);b.setHtml(a); +return b.getFirst().remove()},CKEDITOR.dom.element.setMarker=function(a,f,b,c){var d=f.getCustomData("list_marker_id")||f.setCustomData("list_marker_id",CKEDITOR.tools.getNextNumber()).getCustomData("list_marker_id"),l=f.getCustomData("list_marker_names")||f.setCustomData("list_marker_names",{}).getCustomData("list_marker_names");a[d]=f;l[b]=1;return f.setCustomData(b,c)},CKEDITOR.dom.element.clearAllMarkers=function(a){for(var f in a)CKEDITOR.dom.element.clearMarkers(a,a[f],1)},CKEDITOR.dom.element.clearMarkers= +function(a,f,b){var c=f.getCustomData("list_marker_names"),d=f.getCustomData("list_marker_id"),l;for(l in c)f.removeCustomData(l);f.removeCustomData("list_marker_names");b&&(f.removeCustomData("list_marker_id"),delete a[d])},function(){function a(a,b){return-1<(" "+a+" ").replace(l," ").indexOf(" "+b+" ")}function f(a){var b=!0;a.$.id||(a.$.id="cke_tmp_"+CKEDITOR.tools.getNextNumber(),b=!1);return function(){b||a.removeAttribute("id")}}function b(a,b){var c=CKEDITOR.tools.escapeCss(a.$.id);return"#"+ +c+" "+b.split(/,\s*/).join(", #"+c+" ")}function c(a){for(var b=0,c=0,e=k[a].length;cCKEDITOR.env.version?this.$.text+=a:this.append(new CKEDITOR.dom.text(a))},appendBogus:function(a){if(a||CKEDITOR.env.needsBrFiller){for(a=this.getLast();a&&a.type==CKEDITOR.NODE_TEXT&&!CKEDITOR.tools.rtrim(a.getText());)a=a.getPrevious();a&& +a.is&&a.is("br")||(a=this.getDocument().createElement("br"),CKEDITOR.env.gecko&&a.setAttribute("type","_moz"),this.append(a))}},breakParent:function(a,b){var c=new CKEDITOR.dom.range(this.getDocument());c.setStartAfter(this);c.setEndAfter(a);var e=c.extractContents(!1,b||!1),d;c.insertNode(this.remove());if(CKEDITOR.env.ie&&!CKEDITOR.env.edge){for(c=new CKEDITOR.dom.element("div");d=e.getFirst();)d.$.style.backgroundColor&&(d.$.style.backgroundColor=d.$.style.backgroundColor),c.append(d);c.insertAfter(this); +c.remove(!0)}else e.insertAfterNode(this)},contains:document.compareDocumentPosition?function(a){return!!(this.$.compareDocumentPosition(a.$)&16)}:function(a){var b=this.$;return a.type!=CKEDITOR.NODE_ELEMENT?b.contains(a.getParent().$):b!=a.$&&b.contains(a.$)},focus:function(){function a(){try{this.$.focus()}catch(b){}}return function(b){b?CKEDITOR.tools.setTimeout(a,100,this):a.call(this)}}(),getHtml:function(){var a=this.$.innerHTML;return CKEDITOR.env.ie?a.replace(/<\?[^>]*>/g,""):a},getOuterHtml:function(){if(this.$.outerHTML)return this.$.outerHTML.replace(/<\?[^>]*>/, +"");var a=this.$.ownerDocument.createElement("div");a.appendChild(this.$.cloneNode(!0));return a.innerHTML},getClientRect:function(a){var b=CKEDITOR.tools.extend({},this.$.getBoundingClientRect());!b.width&&(b.width=b.right-b.left);!b.height&&(b.height=b.bottom-b.top);return a?CKEDITOR.tools.getAbsoluteRectPosition(this.getWindow(),b):b},setHtml:CKEDITOR.env.ie&&9>CKEDITOR.env.version?function(a){try{var b=this.$;if(this.getParent())return b.innerHTML=a;var c=this.getDocument()._getHtml5ShivFrag(); +c.appendChild(b);b.innerHTML=a;c.removeChild(b);return a}catch(e){this.$.innerHTML="";b=new CKEDITOR.dom.element("body",this.getDocument());b.$.innerHTML=a;for(b=b.getChildren();b.count();)this.append(b.getItem(0));return a}}:function(a){return this.$.innerHTML=a},setText:function(){var a=document.createElement("p");a.innerHTML="x";a=a.textContent;return function(b){this.$[a?"textContent":"innerText"]=b}}(),getAttribute:function(){var a=function(a){return this.$.getAttribute(a,2)};return CKEDITOR.env.ie&& +(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)?function(a){switch(a){case "class":a="className";break;case "http-equiv":a="httpEquiv";break;case "name":return this.$.name;case "tabindex":return a=this.$.getAttribute(a,2),0!==a&&0===this.$.tabIndex&&(a=null),a;case "checked":return a=this.$.attributes.getNamedItem(a),(a.specified?a.nodeValue:this.$.checked)?"checked":null;case "hspace":case "value":return this.$[a];case "style":return this.$.style.cssText;case "contenteditable":case "contentEditable":return this.$.attributes.getNamedItem("contentEditable").specified? +this.$.getAttribute("contentEditable"):null}return this.$.getAttribute(a,2)}:a}(),getAttributes:function(a){var b={},c=this.$.attributes,e;a=CKEDITOR.tools.isArray(a)?a:[];for(e=0;e=document.documentMode){var b=this.$.scopeName;"HTML"!=b&&(a=b.toLowerCase()+":"+a)}this.getName=function(){return a};return this.getName()},getValue:function(){return this.$.value},getFirst:function(a){var b=this.$.firstChild;(b=b&&new CKEDITOR.dom.node(b))&&a&&!a(b)&&(b=b.getNext(a));return b},getLast:function(a){var b=this.$.lastChild; +(b=b&&new CKEDITOR.dom.node(b))&&a&&!a(b)&&(b=b.getPrevious(a));return b},getStyle:function(a){return this.$.style[CKEDITOR.tools.cssStyleToDomStyle(a)]},is:function(){var a=this.getName();if("object"==typeof arguments[0])return!!arguments[0][a];for(var b=0;bCKEDITOR.env.version&&this.is("a")){var c=this.getParent();c.type==CKEDITOR.NODE_ELEMENT&&(c=c.clone(),c.setHtml(b),b=c.getHtml(),c.setHtml(a),a=c.getHtml())}return b==a},isVisible:function(){var a=(this.$.offsetHeight||this.$.offsetWidth)&&"hidden"!=this.getComputedStyle("visibility"),b,c;a&&CKEDITOR.env.webkit&&(b=this.getWindow(),!b.equals(CKEDITOR.document.getWindow())&& +(c=b.$.frameElement)&&(a=(new CKEDITOR.dom.element(c)).isVisible()));return!!a},isEmptyInlineRemoveable:function(){if(!CKEDITOR.dtd.$removeEmpty[this.getName()])return!1;for(var a=this.getChildren(),b=0,c=a.count();bCKEDITOR.env.version?function(b){return"name"==b?!!this.$.name:a.call(this,b)}:a:function(a){return!!this.$.attributes.getNamedItem(a)}}(),hide:function(){this.setStyle("display","none")},moveChildren:function(a,b){var c=this.$;a=a.$;if(c!=a){var e;if(b)for(;e=c.lastChild;)a.insertBefore(c.removeChild(e), +a.firstChild);else for(;e=c.firstChild;)a.appendChild(c.removeChild(e))}},mergeSiblings:function(){function a(b,g,e){if(g&&g.type==CKEDITOR.NODE_ELEMENT){for(var c=[];g.data("cke-bookmark")||g.isEmptyInlineRemoveable();)if(c.push(g),g=e?g.getNext():g.getPrevious(),!g||g.type!=CKEDITOR.NODE_ELEMENT)return;if(b.isIdentical(g)){for(var d=e?b.getLast():b.getFirst();c.length;)c.shift().move(b,!e);g.moveChildren(b,!e);g.remove();d&&d.type==CKEDITOR.NODE_ELEMENT&&d.mergeSiblings()}}}return function(b){if(!1=== +b||CKEDITOR.dtd.$removeEmpty[this.getName()]||this.is("a"))a(this,this.getNext(),!0),a(this,this.getPrevious())}}(),show:function(){this.setStyles({display:"",visibility:""})},setAttribute:function(){var a=function(a,b){this.$.setAttribute(a,b);return this};return CKEDITOR.env.ie&&(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)?function(b,c){"class"==b?this.$.className=c:"style"==b?this.$.style.cssText=c:"tabindex"==b?this.$.tabIndex=c:"checked"==b?this.$.checked=c:"contenteditable"==b?a.call(this, +"contentEditable",c):a.apply(this,arguments);return this}:CKEDITOR.env.ie8Compat&&CKEDITOR.env.secure?function(b,c){if("src"==b&&c.match(/^http:\/\//))try{a.apply(this,arguments)}catch(e){}else a.apply(this,arguments);return this}:a}(),setAttributes:function(a){for(var b in a)this.setAttribute(b,a[b]);return this},setValue:function(a){this.$.value=a;return this},removeAttribute:function(){var a=function(a){this.$.removeAttribute(a)};return CKEDITOR.env.ie&&(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)? +function(a){"class"==a?a="className":"tabindex"==a?a="tabIndex":"contenteditable"==a&&(a="contentEditable");this.$.removeAttribute(a)}:a}(),removeAttributes:function(a){if(CKEDITOR.tools.isArray(a))for(var b=0;bCKEDITOR.env.version?(a=Math.round(100*a),this.setStyle("filter",100<=a?"":"progid:DXImageTransform.Microsoft.Alpha(opacity\x3d"+a+")")):this.setStyle("opacity",a)},unselectable:function(){this.setStyles(CKEDITOR.tools.cssVendorPrefix("user-select","none"));if(CKEDITOR.env.ie){this.setAttribute("unselectable","on");for(var a,b=this.getElementsByTag("*"),c=0,e=b.count();cl||0l?l:d);c&&(0>f||0f?f:e,0)},setState:function(a,b,c){b=b||"cke";switch(a){case CKEDITOR.TRISTATE_ON:this.addClass(b+"_on");this.removeClass(b+"_off");this.removeClass(b+"_disabled");c&&this.setAttribute("aria-pressed",!0);c&&this.removeAttribute("aria-disabled");break;case CKEDITOR.TRISTATE_DISABLED:this.addClass(b+"_disabled");this.removeClass(b+"_off");this.removeClass(b+"_on");c&&this.setAttribute("aria-disabled", +!0);c&&this.removeAttribute("aria-pressed");break;default:this.addClass(b+"_off"),this.removeClass(b+"_on"),this.removeClass(b+"_disabled"),c&&this.removeAttribute("aria-pressed"),c&&this.removeAttribute("aria-disabled")}},getFrameDocument:function(){var a=this.$;try{a.contentWindow.document}catch(b){a.src=a.src}return a&&new CKEDITOR.dom.document(a.contentWindow.document)},copyAttributes:function(a,b){var c=this.$.attributes;b=b||{};for(var e=0;e=A.getChildCount()?(A=A.getChild(C-1),F=!0):A=A.getChild(C):J=F=!0;x.type==CKEDITOR.NODE_TEXT?t?E=!0:x.split(B):0ha)for(;Z;)Z=h(Z,K,!0);K=W}t||m()}}function b(){var a=!1,b=CKEDITOR.dom.walker.whitespaces(),c=CKEDITOR.dom.walker.bookmark(!0),d=CKEDITOR.dom.walker.bogus();return function(g){return c(g)||b(g)?!0:d(g)&&!a?a=!0:g.type==CKEDITOR.NODE_TEXT&&(g.hasAscendant("pre")||CKEDITOR.tools.trim(g.getText()).length)||g.type==CKEDITOR.NODE_ELEMENT&&!g.is(l)?!1:!0}}function c(a){var b=CKEDITOR.dom.walker.whitespaces(),c=CKEDITOR.dom.walker.bookmark(1); +return function(d){return c(d)||b(d)?!0:!a&&k(d)||d.type==CKEDITOR.NODE_ELEMENT&&d.is(CKEDITOR.dtd.$removeEmpty)}}function d(a){return function(){var b;return this[a?"getPreviousNode":"getNextNode"](function(a){!b&&m(a)&&(b=a);return h(a)&&!(k(a)&&a.equals(b))})}}var l={abbr:1,acronym:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,"var":1},k=CKEDITOR.dom.walker.bogus(),g=/^[\t\r\n ]*(?: |\xa0)$/, +h=CKEDITOR.dom.walker.editable(),m=CKEDITOR.dom.walker.ignored(!0);CKEDITOR.dom.range.prototype={clone:function(){var a=new CKEDITOR.dom.range(this.root);a._setStartContainer(this.startContainer);a.startOffset=this.startOffset;a._setEndContainer(this.endContainer);a.endOffset=this.endOffset;a.collapsed=this.collapsed;return a},collapse:function(a){a?(this._setEndContainer(this.startContainer),this.endOffset=this.startOffset):(this._setStartContainer(this.endContainer),this.startOffset=this.endOffset); +this.collapsed=!0},cloneContents:function(a){var b=new CKEDITOR.dom.documentFragment(this.document);this.collapsed||f(this,2,b,!1,"undefined"==typeof a?!0:a);return b},deleteContents:function(a){this.collapsed||f(this,0,null,a)},extractContents:function(a,b){var c=new CKEDITOR.dom.documentFragment(this.document);this.collapsed||f(this,1,c,a,"undefined"==typeof b?!0:b);return c},createBookmark:function(a){var b,c,d,g,h=this.collapsed;b=this.document.createElement("span");b.data("cke-bookmark",1);b.setStyle("display", +"none");b.setHtml("\x26nbsp;");a&&(d="cke_bm_"+CKEDITOR.tools.getNextNumber(),b.setAttribute("id",d+(h?"C":"S")));h||(c=b.clone(),c.setHtml("\x26nbsp;"),a&&c.setAttribute("id",d+"E"),g=this.clone(),g.collapse(),g.insertNode(c));g=this.clone();g.collapse(!0);g.insertNode(b);c?(this.setStartAfter(b),this.setEndBefore(c)):this.moveToPosition(b,CKEDITOR.POSITION_AFTER_END);return{startNode:a?d+(h?"C":"S"):b,endNode:a?d+"E":c,serializable:a,collapsed:h}},createBookmark2:function(){function a(b){var e= +b.container,d=b.offset,g;g=e;var h=d;g=g.type!=CKEDITOR.NODE_ELEMENT||0===h||h==g.getChildCount()?0:g.getChild(h-1).type==CKEDITOR.NODE_TEXT&&g.getChild(h).type==CKEDITOR.NODE_TEXT;g&&(e=e.getChild(d-1),d=e.getLength());if(e.type==CKEDITOR.NODE_ELEMENT&&0=a.offset&&(a.offset=d.getIndex(),a.container=d.getParent()))}}var c=CKEDITOR.dom.walker.nodeType(CKEDITOR.NODE_TEXT,!0);return function(c){var d=this.collapsed,g={container:this.startContainer, +offset:this.startOffset},h={container:this.endContainer,offset:this.endOffset};c&&(a(g),b(g,this.root),d||(a(h),b(h,this.root)));return{start:g.container.getAddress(c),end:d?null:h.container.getAddress(c),startOffset:g.offset,endOffset:h.offset,normalized:c,collapsed:d,is2:!0}}}(),moveToBookmark:function(a){if(a.is2){var b=this.document.getByAddress(a.start,a.normalized),c=a.startOffset,d=a.end&&this.document.getByAddress(a.end,a.normalized);a=a.endOffset;this.setStart(b,c);d?this.setEnd(d,a):this.collapse(!0)}else b= +(c=a.serializable)?this.document.getById(a.startNode):a.startNode,a=c?this.document.getById(a.endNode):a.endNode,this.setStartBefore(b),b.remove(),a?(this.setEndBefore(a),a.remove()):this.collapse(!0)},getBoundaryNodes:function(){var a=this.startContainer,b=this.endContainer,c=this.startOffset,d=this.endOffset,g;if(a.type==CKEDITOR.NODE_ELEMENT)if(g=a.getChildCount(),g>c)a=a.getChild(c);else if(1>g)a=a.getPreviousSourceNode();else{for(a=a.$;a.lastChild;)a=a.lastChild;a=new CKEDITOR.dom.node(a);a= +a.getNextSourceNode()||a}if(b.type==CKEDITOR.NODE_ELEMENT)if(g=b.getChildCount(),g>d)b=b.getChild(d).getPreviousSourceNode(!0);else if(1>g)b=b.getPreviousSourceNode();else{for(b=b.$;b.lastChild;)b=b.lastChild;b=new CKEDITOR.dom.node(b)}a.getPosition(b)&CKEDITOR.POSITION_FOLLOWING&&(a=b);return{startNode:a,endNode:b}},getCommonAncestor:function(a,b){var c=this.startContainer,d=this.endContainer,c=c.equals(d)?a&&c.type==CKEDITOR.NODE_ELEMENT&&this.startOffset==this.endOffset-1?c.getChild(this.startOffset): +c:c.getCommonAncestor(d);return b&&!c.is?c.getParent():c},optimize:function(){var a=this.startContainer,b=this.startOffset;a.type!=CKEDITOR.NODE_ELEMENT&&(b?b>=a.getLength()&&this.setStartAfter(a):this.setStartBefore(a));a=this.endContainer;b=this.endOffset;a.type!=CKEDITOR.NODE_ELEMENT&&(b?b>=a.getLength()&&this.setEndAfter(a):this.setEndBefore(a))},optimizeBookmark:function(){var a=this.startContainer,b=this.endContainer;a.is&&a.is("span")&&a.data("cke-bookmark")&&this.setStartAt(a,CKEDITOR.POSITION_BEFORE_START); +b&&b.is&&b.is("span")&&b.data("cke-bookmark")&&this.setEndAt(b,CKEDITOR.POSITION_AFTER_END)},trim:function(a,b){var c=this.startContainer,d=this.startOffset,g=this.collapsed;if((!a||g)&&c&&c.type==CKEDITOR.NODE_TEXT){if(d)if(d>=c.getLength())d=c.getIndex()+1,c=c.getParent();else{var h=c.split(d),d=c.getIndex()+1,c=c.getParent();this.startContainer.equals(this.endContainer)?this.setEnd(h,this.endOffset-this.startOffset):c.equals(this.endContainer)&&(this.endOffset+=1)}else d=c.getIndex(),c=c.getParent(); +this.setStart(c,d);if(g){this.collapse(!0);return}}c=this.endContainer;d=this.endOffset;b||g||!c||c.type!=CKEDITOR.NODE_TEXT||(d?(d>=c.getLength()||c.split(d),d=c.getIndex()+1):d=c.getIndex(),c=c.getParent(),this.setEnd(c,d))},enlarge:function(a,b){function c(a){return a&&a.type==CKEDITOR.NODE_ELEMENT&&a.hasAttribute("contenteditable")?null:a}var d=new RegExp(/[^\s\ufeff]/);switch(a){case CKEDITOR.ENLARGE_INLINE:var g=1;case CKEDITOR.ENLARGE_ELEMENT:var h=function(a,b){var e=new CKEDITOR.dom.range(m); +e.setStart(a,b);e.setEndAt(m,CKEDITOR.POSITION_BEFORE_END);var e=new CKEDITOR.dom.walker(e),c;for(e.guard=function(a){return!(a.type==CKEDITOR.NODE_ELEMENT&&a.isBlockBoundary())};c=e.next();){if(c.type!=CKEDITOR.NODE_TEXT)return!1;H=c!=a?c.getText():c.substring(b);if(d.test(H))return!1}return!0};if(this.collapsed)break;var f=this.getCommonAncestor(),m=this.root,l,k,t,x,A,B=!1,C,H;C=this.startContainer;var F=this.startOffset;C.type==CKEDITOR.NODE_TEXT?(F&&(C=!CKEDITOR.tools.trim(C.substring(0,F)).length&& +C,B=!!C),C&&((x=C.getPrevious())||(t=C.getParent()))):(F&&(x=C.getChild(F-1)||C.getLast()),x||(t=C));for(t=c(t);t||x;){if(t&&!x){!A&&t.equals(f)&&(A=!0);if(g?t.isBlockBoundary():!m.contains(t))break;B&&"inline"==t.getComputedStyle("display")||(B=!1,A?l=t:this.setStartBefore(t));x=t.getPrevious()}for(;x;)if(C=!1,x.type==CKEDITOR.NODE_COMMENT)x=x.getPrevious();else{if(x.type==CKEDITOR.NODE_TEXT)H=x.getText(),d.test(H)&&(x=null),C=/[\s\ufeff]$/.test(H);else if((x.$.offsetWidth>(CKEDITOR.env.webkit?1: +0)||b&&x.is("br"))&&!x.data("cke-bookmark"))if(B&&CKEDITOR.dtd.$removeEmpty[x.getName()]){H=x.getText();if(d.test(H))x=null;else for(var F=x.$.getElementsByTagName("*"),I=0,J;J=F[I++];)if(!CKEDITOR.dtd.$removeEmpty[J.nodeName.toLowerCase()]){x=null;break}x&&(C=!!H.length)}else x=null;C&&(B?A?l=t:t&&this.setStartBefore(t):B=!0);if(x){C=x.getPrevious();if(!t&&!C){t=x;x=null;break}x=C}else t=null}t&&(t=c(t.getParent()))}C=this.endContainer;F=this.endOffset;t=x=null;A=B=!1;C.type==CKEDITOR.NODE_TEXT? +CKEDITOR.tools.trim(C.substring(F)).length?B=!0:(B=!C.getLength(),F==C.getLength()?(x=C.getNext())||(t=C.getParent()):h(C,F)&&(t=C.getParent())):(x=C.getChild(F))||(t=C);for(;t||x;){if(t&&!x){!A&&t.equals(f)&&(A=!0);if(g?t.isBlockBoundary():!m.contains(t))break;B&&"inline"==t.getComputedStyle("display")||(B=!1,A?k=t:t&&this.setEndAfter(t));x=t.getNext()}for(;x;){C=!1;if(x.type==CKEDITOR.NODE_TEXT)H=x.getText(),h(x,0)||(x=null),C=/^[\s\ufeff]/.test(H);else if(x.type==CKEDITOR.NODE_ELEMENT){if((0=f.getLength()?h.setStartAfter(f):(h.setStartBefore(f),c=0):h.setStartBefore(f));m&&m.type==CKEDITOR.NODE_TEXT&&(k?k>=m.getLength()?h.setEndAfter(m):(h.setEndAfter(m),t=0):h.setEndBefore(m));var h=new CKEDITOR.dom.walker(h),x=CKEDITOR.dom.walker.bookmark(),A=CKEDITOR.dom.walker.bogus();h.evaluator=function(b){return b.type==(a==CKEDITOR.SHRINK_ELEMENT?CKEDITOR.NODE_ELEMENT:CKEDITOR.NODE_TEXT)}; +var B;h.guard=function(b,c){if(g&&A(b)||x(b))return!0;if(a==CKEDITOR.SHRINK_ELEMENT&&b.type==CKEDITOR.NODE_TEXT||c&&b.equals(B)||!1===d&&b.type==CKEDITOR.NODE_ELEMENT&&b.isBlockBoundary()||b.type==CKEDITOR.NODE_ELEMENT&&b.hasAttribute("contenteditable"))return!1;c||b.type!=CKEDITOR.NODE_ELEMENT||(B=b);return!0};c&&(f=h[a==CKEDITOR.SHRINK_ELEMENT?"lastForward":"next"]())&&this.setStartAt(f,b?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_START);t&&(h.reset(),(h=h[a==CKEDITOR.SHRINK_ELEMENT? +"lastBackward":"previous"]())&&this.setEndAt(h,b?CKEDITOR.POSITION_BEFORE_END:CKEDITOR.POSITION_AFTER_END));return!(!c&&!t)}},insertNode:function(a){this.optimizeBookmark();this.trim(!1,!0);var b=this.startContainer,c=b.getChild(this.startOffset);c?a.insertBefore(c):b.append(a);a.getParent()&&a.getParent().equals(this.endContainer)&&this.endOffset++;this.setStartBefore(a)},moveToPosition:function(a,b){this.setStartAt(a,b);this.collapse(!0)},moveToRange:function(a){this.setStart(a.startContainer,a.startOffset); +this.setEnd(a.endContainer,a.endOffset)},selectNodeContents:function(a){this.setStart(a,0);this.setEnd(a,a.type==CKEDITOR.NODE_TEXT?a.getLength():a.getChildCount())},setStart:function(b,c){b.type==CKEDITOR.NODE_ELEMENT&&CKEDITOR.dtd.$empty[b.getName()]&&(c=b.getIndex(),b=b.getParent());this._setStartContainer(b);this.startOffset=c;this.endContainer||(this._setEndContainer(b),this.endOffset=c);a(this)},setEnd:function(b,c){b.type==CKEDITOR.NODE_ELEMENT&&CKEDITOR.dtd.$empty[b.getName()]&&(c=b.getIndex()+ +1,b=b.getParent());this._setEndContainer(b);this.endOffset=c;this.startContainer||(this._setStartContainer(b),this.startOffset=c);a(this)},setStartAfter:function(a){this.setStart(a.getParent(),a.getIndex()+1)},setStartBefore:function(a){this.setStart(a.getParent(),a.getIndex())},setEndAfter:function(a){this.setEnd(a.getParent(),a.getIndex()+1)},setEndBefore:function(a){this.setEnd(a.getParent(),a.getIndex())},setStartAt:function(b,c){switch(c){case CKEDITOR.POSITION_AFTER_START:this.setStart(b,0); +break;case CKEDITOR.POSITION_BEFORE_END:b.type==CKEDITOR.NODE_TEXT?this.setStart(b,b.getLength()):this.setStart(b,b.getChildCount());break;case CKEDITOR.POSITION_BEFORE_START:this.setStartBefore(b);break;case CKEDITOR.POSITION_AFTER_END:this.setStartAfter(b)}a(this)},setEndAt:function(b,c){switch(c){case CKEDITOR.POSITION_AFTER_START:this.setEnd(b,0);break;case CKEDITOR.POSITION_BEFORE_END:b.type==CKEDITOR.NODE_TEXT?this.setEnd(b,b.getLength()):this.setEnd(b,b.getChildCount());break;case CKEDITOR.POSITION_BEFORE_START:this.setEndBefore(b); +break;case CKEDITOR.POSITION_AFTER_END:this.setEndAfter(b)}a(this)},fixBlock:function(a,b){var c=this.createBookmark(),d=this.document.createElement(b);this.collapse(a);this.enlarge(CKEDITOR.ENLARGE_BLOCK_CONTENTS);this.extractContents().appendTo(d);d.trim();this.insertNode(d);var g=d.getBogus();g&&g.remove();d.appendBogus();this.moveToBookmark(c);return d},splitBlock:function(a,b){var c=new CKEDITOR.dom.elementPath(this.startContainer,this.root),d=new CKEDITOR.dom.elementPath(this.endContainer,this.root), +g=c.block,h=d.block,f=null;if(!c.blockLimit.equals(d.blockLimit))return null;"br"!=a&&(g||(g=this.fixBlock(!0,a),h=(new CKEDITOR.dom.elementPath(this.endContainer,this.root)).block),h||(h=this.fixBlock(!1,a)));c=g&&this.checkStartOfBlock();d=h&&this.checkEndOfBlock();this.deleteContents();g&&g.equals(h)&&(d?(f=new CKEDITOR.dom.elementPath(this.startContainer,this.root),this.moveToPosition(h,CKEDITOR.POSITION_AFTER_END),h=null):c?(f=new CKEDITOR.dom.elementPath(this.startContainer,this.root),this.moveToPosition(g, +CKEDITOR.POSITION_BEFORE_START),g=null):(h=this.splitElement(g,b||!1),g.is("ul","ol")||g.appendBogus()));return{previousBlock:g,nextBlock:h,wasStartOfBlock:c,wasEndOfBlock:d,elementPath:f}},splitElement:function(a,b){if(!this.collapsed)return null;this.setEndAt(a,CKEDITOR.POSITION_BEFORE_END);var c=this.extractContents(!1,b||!1),d=a.clone(!1,b||!1);c.appendTo(d);d.insertAfter(a);this.moveToPosition(a,CKEDITOR.POSITION_AFTER_END);return d},removeEmptyBlocksAtEnd:function(){function a(e){return function(a){return b(a)|| +c(a)||a.type==CKEDITOR.NODE_ELEMENT&&a.isEmptyInlineRemoveable()||e.is("table")&&a.is("caption")?!1:!0}}var b=CKEDITOR.dom.walker.whitespaces(),c=CKEDITOR.dom.walker.bookmark(!1);return function(b){for(var c=this.createBookmark(),d=this[b?"endPath":"startPath"](),g=d.block||d.blockLimit,h;g&&!g.equals(d.root)&&!g.getFirst(a(g));)h=g.getParent(),this[b?"setEndAt":"setStartAt"](g,CKEDITOR.POSITION_AFTER_END),g.remove(1),g=h;this.moveToBookmark(c)}}(),startPath:function(){return new CKEDITOR.dom.elementPath(this.startContainer, +this.root)},endPath:function(){return new CKEDITOR.dom.elementPath(this.endContainer,this.root)},checkBoundaryOfElement:function(a,b){var d=b==CKEDITOR.START,g=this.clone();g.collapse(d);g[d?"setStartAt":"setEndAt"](a,d?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_END);g=new CKEDITOR.dom.walker(g);g.evaluator=c(d);return g[d?"checkBackward":"checkForward"]()},checkStartOfBlock:function(){var a=this.startContainer,c=this.startOffset;CKEDITOR.env.ie&&c&&a.type==CKEDITOR.NODE_TEXT&&(a=CKEDITOR.tools.ltrim(a.substring(0, +c)),g.test(a)&&this.trim(0,1));this.trim();a=new CKEDITOR.dom.elementPath(this.startContainer,this.root);c=this.clone();c.collapse(!0);c.setStartAt(a.block||a.blockLimit,CKEDITOR.POSITION_AFTER_START);a=new CKEDITOR.dom.walker(c);a.evaluator=b();return a.checkBackward()},checkEndOfBlock:function(){var a=this.endContainer,c=this.endOffset;CKEDITOR.env.ie&&a.type==CKEDITOR.NODE_TEXT&&(a=CKEDITOR.tools.rtrim(a.substring(c)),g.test(a)&&this.trim(1,0));this.trim();a=new CKEDITOR.dom.elementPath(this.endContainer, +this.root);c=this.clone();c.collapse(!1);c.setEndAt(a.block||a.blockLimit,CKEDITOR.POSITION_BEFORE_END);a=new CKEDITOR.dom.walker(c);a.evaluator=b();return a.checkForward()},getPreviousNode:function(a,b,c){var d=this.clone();d.collapse(1);d.setStartAt(c||this.root,CKEDITOR.POSITION_AFTER_START);c=new CKEDITOR.dom.walker(d);c.evaluator=a;c.guard=b;return c.previous()},getNextNode:function(a,b,c){var d=this.clone();d.collapse();d.setEndAt(c||this.root,CKEDITOR.POSITION_BEFORE_END);c=new CKEDITOR.dom.walker(d); +c.evaluator=a;c.guard=b;return c.next()},checkReadOnly:function(){function a(b,c){for(;b;){if(b.type==CKEDITOR.NODE_ELEMENT){if("false"==b.getAttribute("contentEditable")&&!b.data("cke-editable"))return 0;if(b.is("html")||"true"==b.getAttribute("contentEditable")&&(b.contains(c)||b.equals(c)))break}b=b.getParent()}return 1}return function(){var b=this.startContainer,c=this.endContainer;return!(a(b,c)&&a(c,b))}}(),moveToElementEditablePosition:function(a,b){if(a.type==CKEDITOR.NODE_ELEMENT&&!a.isEditable(!1))return this.moveToPosition(a, +b?CKEDITOR.POSITION_AFTER_END:CKEDITOR.POSITION_BEFORE_START),!0;for(var c=0;a;){if(a.type==CKEDITOR.NODE_TEXT){b&&this.endContainer&&this.checkEndOfBlock()&&g.test(a.getText())?this.moveToPosition(a,CKEDITOR.POSITION_BEFORE_START):this.moveToPosition(a,b?CKEDITOR.POSITION_AFTER_END:CKEDITOR.POSITION_BEFORE_START);c=1;break}if(a.type==CKEDITOR.NODE_ELEMENT)if(a.isEditable())this.moveToPosition(a,b?CKEDITOR.POSITION_BEFORE_END:CKEDITOR.POSITION_AFTER_START),c=1;else if(b&&a.is("br")&&this.endContainer&& +this.checkEndOfBlock())this.moveToPosition(a,CKEDITOR.POSITION_BEFORE_START);else if("false"==a.getAttribute("contenteditable")&&a.is(CKEDITOR.dtd.$block))return this.setStartBefore(a),this.setEndAfter(a),!0;var d=a,h=c,f=void 0;d.type==CKEDITOR.NODE_ELEMENT&&d.isEditable(!1)&&(f=d[b?"getLast":"getFirst"](m));h||f||(f=d[b?"getPrevious":"getNext"](m));a=f}return!!c},moveToClosestEditablePosition:function(a,b){var c,d=0,g,h,f=[CKEDITOR.POSITION_AFTER_END,CKEDITOR.POSITION_BEFORE_START];a?(c=new CKEDITOR.dom.range(this.root), +c.moveToPosition(a,f[b?0:1])):c=this.clone();if(a&&!a.is(CKEDITOR.dtd.$block))d=1;else if(g=c[b?"getNextEditableNode":"getPreviousEditableNode"]())d=1,(h=g.type==CKEDITOR.NODE_ELEMENT)&&g.is(CKEDITOR.dtd.$block)&&"false"==g.getAttribute("contenteditable")?(c.setStartAt(g,CKEDITOR.POSITION_BEFORE_START),c.setEndAt(g,CKEDITOR.POSITION_AFTER_END)):!CKEDITOR.env.needsBrFiller&&h&&g.is(CKEDITOR.dom.walker.validEmptyBlockContainers)?(c.setEnd(g,0),c.collapse()):c.moveToPosition(g,f[b?1:0]);d&&this.moveToRange(c); +return!!d},moveToElementEditStart:function(a){return this.moveToElementEditablePosition(a)},moveToElementEditEnd:function(a){return this.moveToElementEditablePosition(a,!0)},getEnclosedNode:function(){var a=this.clone();a.optimize();if(a.startContainer.type!=CKEDITOR.NODE_ELEMENT||a.endContainer.type!=CKEDITOR.NODE_ELEMENT)return null;var a=new CKEDITOR.dom.walker(a),b=CKEDITOR.dom.walker.bookmark(!1,!0),c=CKEDITOR.dom.walker.whitespaces(!0);a.evaluator=function(a){return c(a)&&b(a)};var d=a.next(); +a.reset();return d&&d.equals(a.previous())?d:null},getTouchedStartNode:function(){var a=this.startContainer;return this.collapsed||a.type!=CKEDITOR.NODE_ELEMENT?a:a.getChild(this.startOffset)||a},getTouchedEndNode:function(){var a=this.endContainer;return this.collapsed||a.type!=CKEDITOR.NODE_ELEMENT?a:a.getChild(this.endOffset-1)||a},getNextEditableNode:d(),getPreviousEditableNode:d(1),_getTableElement:function(a){a=a||{td:1,th:1,tr:1,tbody:1,thead:1,tfoot:1,table:1};var b=this.startContainer,c= +this.endContainer,d=b.getAscendant("table",!0),g=c.getAscendant("table",!0);return d&&!this.root.contains(d)?null:CKEDITOR.env.safari&&d&&c.equals(this.root)?b.getAscendant(a,!0):this.getEnclosedNode()?this.getEnclosedNode().getAscendant(a,!0):d&&g&&(d.equals(g)||d.contains(g)||g.contains(d))?b.getAscendant(a,!0):null},scrollIntoView:function(){var a=new CKEDITOR.dom.element.createFromHtml("\x3cspan\x3e\x26nbsp;\x3c/span\x3e",this.document),b,c,d,g=this.clone();g.optimize();(d=g.startContainer.type== +CKEDITOR.NODE_TEXT)?(c=g.startContainer.getText(),b=g.startContainer.split(g.startOffset),a.insertAfter(g.startContainer)):g.insertNode(a);a.scrollIntoView();d&&(g.startContainer.setText(c),b.remove());a.remove()},getClientRects:function(){function a(b,c){var e=CKEDITOR.tools.array.map(b,function(a){return a}),d=new CKEDITOR.dom.range(c.root),g,h,f;c.startContainer instanceof CKEDITOR.dom.element&&(h=0===c.startOffset&&c.startContainer.hasAttribute("data-widget"));c.endContainer instanceof CKEDITOR.dom.element&& +(f=(f=c.endOffset===(c.endContainer.getChildCount?c.endContainer.getChildCount():c.endContainer.length))&&c.endContainer.hasAttribute("data-widget"));h&&d.setStart(c.startContainer.getParent(),c.startContainer.getIndex());f&&d.setEnd(c.endContainer.getParent(),c.endContainer.getIndex()+1);if(h||f)c=d;d=c.cloneContents().find("[data-cke-widget-id]").toArray();if(d=CKEDITOR.tools.array.map(d,function(a){var b=c.root.editor;a=a.getAttribute("data-cke-widget-id");return b.widgets.instances[a].element}))return d= +CKEDITOR.tools.array.map(d,function(a){var b;b=a.getParent().hasClass("cke_widget_wrapper")?a.getParent():a;g=this.root.getDocument().$.createRange();g.setStart(b.getParent().$,b.getIndex());g.setEnd(b.getParent().$,b.getIndex()+1);b=g.getClientRects();b.widgetRect=a.getClientRect();return b},c),CKEDITOR.tools.array.forEach(d,function(a){function b(d){CKEDITOR.tools.array.forEach(e,function(b,g){var h=CKEDITOR.tools.objectCompare(a[d],b);h||(h=CKEDITOR.tools.objectCompare(a.widgetRect,b));h&&(Array.prototype.splice.call(e, +g,a.length-d,a.widgetRect),c=!0)});c||(darguments.length||(this.range=a,this.forceBrBreak=0,this.enlargeBr=1,this.enforceRealBlocks=0,this._||(this._={}))}function f(a){var b=[];a.forEach(function(a){if("true"==a.getAttribute("contenteditable"))return b.push(a),!1},CKEDITOR.NODE_ELEMENT,!0);return b}function b(a,c,d,g){a:{null==g&&(g=f(d));for(var h;h=g.shift();)if(h.getDtd().p){g={element:h,remaining:g};break a}g=null}if(!g)return 0;if((h=CKEDITOR.filter.instances[g.element.data("cke-filter")])&& +!h.check(c))return b(a,c,d,g.remaining);c=new CKEDITOR.dom.range(g.element);c.selectNodeContents(g.element);c=c.createIterator();c.enlargeBr=a.enlargeBr;c.enforceRealBlocks=a.enforceRealBlocks;c.activeFilter=c.filter=h;a._.nestedEditable={element:g.element,container:d,remaining:g.remaining,iterator:c};return 1}function c(a,b,c){if(!b)return!1;a=a.clone();a.collapse(!c);return a.checkBoundaryOfElement(b,c?CKEDITOR.START:CKEDITOR.END)}var d=/^[\r\n\t ]+$/,l=CKEDITOR.dom.walker.bookmark(!1,!0),k=CKEDITOR.dom.walker.whitespaces(!0), +g=function(a){return l(a)&&k(a)},h={dd:1,dt:1,li:1};a.prototype={getNextParagraph:function(a){var e,f,k,y,u;a=a||"p";if(this._.nestedEditable){if(e=this._.nestedEditable.iterator.getNextParagraph(a))return this.activeFilter=this._.nestedEditable.iterator.activeFilter,e;this.activeFilter=this.filter;if(b(this,a,this._.nestedEditable.container,this._.nestedEditable.remaining))return this.activeFilter=this._.nestedEditable.iterator.activeFilter,this._.nestedEditable.iterator.getNextParagraph(a);this._.nestedEditable= +null}if(!this.range.root.getDtd()[a])return null;if(!this._.started){var p=this.range.clone();f=p.startPath();var v=p.endPath(),w=!p.collapsed&&c(p,f.block),r=!p.collapsed&&c(p,v.block,1);p.shrink(CKEDITOR.SHRINK_ELEMENT,!0);w&&p.setStartAt(f.block,CKEDITOR.POSITION_BEFORE_END);r&&p.setEndAt(v.block,CKEDITOR.POSITION_AFTER_START);f=p.endContainer.hasAscendant("pre",!0)||p.startContainer.hasAscendant("pre",!0);p.enlarge(this.forceBrBreak&&!f||!this.enlargeBr?CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS:CKEDITOR.ENLARGE_BLOCK_CONTENTS); +p.collapsed||(f=new CKEDITOR.dom.walker(p.clone()),v=CKEDITOR.dom.walker.bookmark(!0,!0),f.evaluator=v,this._.nextNode=f.next(),f=new CKEDITOR.dom.walker(p.clone()),f.evaluator=v,f=f.previous(),this._.lastNode=f.getNextSourceNode(!0,null,p.root),this._.lastNode&&this._.lastNode.type==CKEDITOR.NODE_TEXT&&!CKEDITOR.tools.trim(this._.lastNode.getText())&&this._.lastNode.getParent().isBlockBoundary()&&(v=this.range.clone(),v.moveToPosition(this._.lastNode,CKEDITOR.POSITION_AFTER_END),v.checkEndOfBlock()&& +(v=new CKEDITOR.dom.elementPath(v.endContainer,v.root),this._.lastNode=(v.block||v.blockLimit).getNextSourceNode(!0))),this._.lastNode&&p.root.contains(this._.lastNode)||(this._.lastNode=this._.docEndMarker=p.document.createText(""),this._.lastNode.insertAfter(f)),p=null);this._.started=1;f=p}v=this._.nextNode;p=this._.lastNode;for(this._.nextNode=null;v;){var w=0,r=v.hasAscendant("pre"),z=v.type!=CKEDITOR.NODE_ELEMENT,t=0;if(z)v.type==CKEDITOR.NODE_TEXT&&d.test(v.getText())&&(z=0);else{var x=v.getName(); +if(CKEDITOR.dtd.$block[x]&&"false"==v.getAttribute("contenteditable")){e=v;b(this,a,e);break}else if(v.isBlockBoundary(this.forceBrBreak&&!r&&{br:1})){if("br"==x)z=1;else if(!f&&!v.getChildCount()&&"hr"!=x){e=v;k=v.equals(p);break}f&&(f.setEndAt(v,CKEDITOR.POSITION_BEFORE_START),"br"!=x&&(this._.nextNode=v));w=1}else{if(v.getFirst()){f||(f=this.range.clone(),f.setStartAt(v,CKEDITOR.POSITION_BEFORE_START));v=v.getFirst();continue}z=1}}z&&!f&&(f=this.range.clone(),f.setStartAt(v,CKEDITOR.POSITION_BEFORE_START)); +k=(!w||z)&&v.equals(p);if(f&&!w)for(;!v.getNext(g)&&!k;){x=v.getParent();if(x.isBlockBoundary(this.forceBrBreak&&!r&&{br:1})){w=1;z=0;k||x.equals(p);f.setEndAt(x,CKEDITOR.POSITION_BEFORE_END);break}v=x;z=1;k=v.equals(p);t=1}z&&f.setEndAt(v,CKEDITOR.POSITION_AFTER_END);v=this._getNextSourceNode(v,t,p);if((k=!v)||w&&f)break}if(!e){if(!f)return this._.docEndMarker&&this._.docEndMarker.remove(),this._.nextNode=null;e=new CKEDITOR.dom.elementPath(f.startContainer,f.root);v=e.blockLimit;w={div:1,th:1,td:1}; +e=e.block;!e&&v&&!this.enforceRealBlocks&&w[v.getName()]&&f.checkStartOfBlock()&&f.checkEndOfBlock()&&!v.equals(f.root)?e=v:!e||this.enforceRealBlocks&&e.is(h)?(e=this.range.document.createElement(a),f.extractContents().appendTo(e),e.trim(),f.insertNode(e),y=u=!0):"li"!=e.getName()?f.checkStartOfBlock()&&f.checkEndOfBlock()||(e=e.clone(!1),f.extractContents().appendTo(e),e.trim(),u=f.splitBlock(),y=!u.wasStartOfBlock,u=!u.wasEndOfBlock,f.insertNode(e)):k||(this._.nextNode=e.equals(p)?null:this._getNextSourceNode(f.getBoundaryNodes().endNode, +1,p))}y&&(y=e.getPrevious())&&y.type==CKEDITOR.NODE_ELEMENT&&("br"==y.getName()?y.remove():y.getLast()&&"br"==y.getLast().$.nodeName.toLowerCase()&&y.getLast().remove());u&&(y=e.getLast())&&y.type==CKEDITOR.NODE_ELEMENT&&"br"==y.getName()&&(!CKEDITOR.env.needsBrFiller||y.getPrevious(l)||y.getNext(l))&&y.remove();this._.nextNode||(this._.nextNode=k||e.equals(p)||!p?null:this._getNextSourceNode(e,1,p));return e},_getNextSourceNode:function(a,b,c){function d(a){return!(a.equals(c)||a.equals(g))}var g= +this.range.root;for(a=a.getNextSourceNode(b,null,d);!l(a);)a=a.getNextSourceNode(b,null,d);return a}};CKEDITOR.dom.range.prototype.createIterator=function(){return new a(this)}}(),CKEDITOR.command=function(a,f){this.uiItems=[];this.exec=function(b){if(this.state==CKEDITOR.TRISTATE_DISABLED||!this.checkAllowed())return!1;this.editorFocus&&a.focus();return!1===this.fire("exec")?!0:!1!==f.exec.call(this,a,b)};this.refresh=function(a,b){if(!this.readOnly&&a.readOnly)return!0;if(this.context&&!b.isContextFor(this.context)|| +!this.checkAllowed(!0))return this.disable(),!0;this.startDisabled||this.enable();this.modes&&!this.modes[a.mode]&&this.disable();return!1===this.fire("refresh",{editor:a,path:b})?!0:f.refresh&&!1!==f.refresh.apply(this,arguments)};var b;this.checkAllowed=function(c){return c||"boolean"!=typeof b?b=a.activeFilter.checkFeature(this):b};CKEDITOR.tools.extend(this,f,{modes:{wysiwyg:1},editorFocus:1,contextSensitive:!!f.context,state:CKEDITOR.TRISTATE_DISABLED});CKEDITOR.event.call(this)},CKEDITOR.command.prototype= +{enable:function(){this.state==CKEDITOR.TRISTATE_DISABLED&&this.checkAllowed()&&this.setState(this.preserveState&&"undefined"!=typeof this.previousState?this.previousState:CKEDITOR.TRISTATE_OFF)},disable:function(){this.setState(CKEDITOR.TRISTATE_DISABLED)},setState:function(a){if(this.state==a||a!=CKEDITOR.TRISTATE_DISABLED&&!this.checkAllowed())return!1;this.previousState=this.state;this.state=a;this.fire("state");return!0},toggleState:function(){this.state==CKEDITOR.TRISTATE_OFF?this.setState(CKEDITOR.TRISTATE_ON): +this.state==CKEDITOR.TRISTATE_ON&&this.setState(CKEDITOR.TRISTATE_OFF)}},CKEDITOR.event.implementOn(CKEDITOR.command.prototype),CKEDITOR.ENTER_P=1,CKEDITOR.ENTER_BR=2,CKEDITOR.ENTER_DIV=3,CKEDITOR.config={customConfig:"config.js",autoUpdateElement:!0,language:"",defaultLanguage:"en",contentsLangDirection:"",enterMode:CKEDITOR.ENTER_P,forceEnterMode:!1,shiftEnterMode:CKEDITOR.ENTER_BR,docType:"\x3c!DOCTYPE html\x3e",bodyId:"",bodyClass:"",fullPage:!1,height:200,contentsCss:CKEDITOR.getUrl("contents.css"), +extraPlugins:"",removePlugins:"",protectedSource:[],tabIndex:0,width:"",baseFloatZIndex:1E4,blockedKeystrokes:[CKEDITOR.CTRL+66,CKEDITOR.CTRL+73,CKEDITOR.CTRL+85]},function(){function a(a,b,c,e,d){var g,h;a=[];for(g in b){h=b[g];h="boolean"==typeof h?{}:"function"==typeof h?{match:h}:I(h);"$"!=g.charAt(0)&&(h.elements=g);c&&(h.featureName=c.toLowerCase());var f=h;f.elements=k(f.elements,/\s+/)||null;f.propertiesOnly=f.propertiesOnly||!0===f.elements;var m=/\s*,\s*/,l=void 0;for(l in L){f[l]=k(f[l], +m)||null;var n=f,v=G[l],D=k(f[G[l]],m),x=f[l],A=[],B=!0,r=void 0;D?B=!1:D={};for(r in x)"!"==r.charAt(0)&&(r=r.slice(1),A.push(r),D[r]=!0,B=!1);for(;r=A.pop();)x[r]=x["!"+r],delete x["!"+r];n[v]=(B?!1:D)||null}f.match=f.match||null;e.push(h);a.push(h)}b=d.elements;d=d.generic;var F;c=0;for(e=a.length;c=--g&&(l&&CKEDITOR.document.getDocumentElement().removeStyle("cursor"),e(b))},q=function(b,c){a[b]=1;var e=f[b];delete f[b];for(var d=0;d=CKEDITOR.env.version||CKEDITOR.env.ie9Compat)?d.$.onreadystatechange=function(){if("loaded"==d.$.readyState||"complete"==d.$.readyState)d.$.onreadystatechange=null,q(b,!0)}:(d.$.onload=function(){setTimeout(function(){d.$.onload=null;d.$.onerror=null;q(b,!0)},0)},d.$.onerror=function(){d.$.onload=null;d.$.onerror=null;q(b,!1)}));d.appendTo(CKEDITOR.document.getHead())}}};l&&CKEDITOR.document.getDocumentElement().setStyle("cursor","wait");for(var u=0;u]+)>)|(?:!--([\S|\s]*?)--\x3e)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/g}},function(){var a=/([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g, +f={checked:1,compact:1,declare:1,defer:1,disabled:1,ismap:1,multiple:1,nohref:1,noresize:1,noshade:1,nowrap:1,readonly:1,selected:1};CKEDITOR.htmlParser.prototype={onTagOpen:function(){},onTagClose:function(){},onText:function(){},onCDATA:function(){},onComment:function(){},parse:function(b){for(var c,d,l=0,k;c=this._.htmlPartsRegex.exec(b);){d=c.index;if(d>l)if(l=b.substring(l,d),k)k.push(l);else this.onText(l);l=this._.htmlPartsRegex.lastIndex;if(d=c[1])if(d=d.toLowerCase(),k&&CKEDITOR.dtd.$cdata[d]&& +(this.onCDATA(k.join("")),k=null),!k){this.onTagClose(d);continue}if(k)k.push(c[0]);else if(d=c[3]){if(d=d.toLowerCase(),!/="/.test(d)){var g={},h,m=c[4];c=!!c[5];if(m)for(;h=a.exec(m);){var e=h[1].toLowerCase();h=h[2]||h[3]||h[4]||"";g[e]=!h&&f[e]?e:CKEDITOR.tools.htmlDecodeAttr(h)}this.onTagOpen(d,g,c);!k&&CKEDITOR.dtd.$cdata[d]&&(k=[])}}else if(d=c[2])this.onComment(d)}if(b.length>l)this.onText(b.substring(l,b.length))}}}(),CKEDITOR.htmlParser.basicWriter=CKEDITOR.tools.createClass({$:function(){this._= +{output:[]}},proto:{openTag:function(a){this._.output.push("\x3c",a)},openTagClose:function(a,f){f?this._.output.push(" /\x3e"):this._.output.push("\x3e")},attribute:function(a,f){"string"==typeof f&&(f=CKEDITOR.tools.htmlEncodeAttr(f));this._.output.push(" ",a,'\x3d"',f,'"')},closeTag:function(a){this._.output.push("\x3c/",a,"\x3e")},text:function(a){this._.output.push(a)},comment:function(a){this._.output.push("\x3c!--",a,"--\x3e")},write:function(a){this._.output.push(a)},reset:function(){this._.output= +[];this._.indent=!1},getHtml:function(a){var f=this._.output.join("");a&&this.reset();return f}}}),"use strict",function(){CKEDITOR.htmlParser.node=function(){};CKEDITOR.htmlParser.node.prototype={remove:function(){var a=this.parent.children,f=CKEDITOR.tools.indexOf(a,this),b=this.previous,c=this.next;b&&(b.next=c);c&&(c.previous=b);a.splice(f,1);this.parent=null},replaceWith:function(a){var f=this.parent.children,b=CKEDITOR.tools.indexOf(f,this),c=a.previous=this.previous,d=a.next=this.next;c&&(c.next= +a);d&&(d.previous=a);f[b]=a;a.parent=this.parent;this.parent=null},insertAfter:function(a){var f=a.parent.children,b=CKEDITOR.tools.indexOf(f,a),c=a.next;f.splice(b+1,0,this);this.next=a.next;this.previous=a;a.next=this;c&&(c.previous=this);this.parent=a.parent},insertBefore:function(a){var f=a.parent.children,b=CKEDITOR.tools.indexOf(f,a);f.splice(b,0,this);this.next=a;(this.previous=a.previous)&&(a.previous.next=this);a.previous=this;this.parent=a.parent},getAscendant:function(a){var f="function"== +typeof a?a:"string"==typeof a?function(b){return b.name==a}:function(b){return b.name in a},b=this.parent;for(;b&&b.type==CKEDITOR.NODE_ELEMENT;){if(f(b))return b;b=b.parent}return null},wrapWith:function(a){this.replaceWith(a);a.add(this);return a},getIndex:function(){return CKEDITOR.tools.indexOf(this.parent.children,this)},getFilterContext:function(a){return a||{}}}}(),"use strict",CKEDITOR.htmlParser.comment=function(a){this.value=a;this._={isBlockLike:!1}},CKEDITOR.htmlParser.comment.prototype= +CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_COMMENT,filter:function(a,f){var b=this.value;if(!(b=a.onComment(f,b,this)))return this.remove(),!1;if("string"!=typeof b)return this.replaceWith(b),!1;this.value=b;return!0},writeHtml:function(a,f){f&&this.filter(f);a.comment(this.value)}}),"use strict",function(){CKEDITOR.htmlParser.text=function(a){this.value=a;this._={isBlockLike:!1}};CKEDITOR.htmlParser.text.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_TEXT, +filter:function(a,f){if(!(this.value=a.onText(f,this.value,this)))return this.remove(),!1},writeHtml:function(a,f){f&&this.filter(f);a.text(this.value)}})}(),"use strict",function(){CKEDITOR.htmlParser.cdata=function(a){this.value=a};CKEDITOR.htmlParser.cdata.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_TEXT,filter:function(){},writeHtml:function(a){a.write(this.value)}})}(),"use strict",CKEDITOR.htmlParser.fragment=function(){this.children=[];this.parent=null; +this._={isBlockLike:!0,hasInlineStarted:!1}},function(){function a(a){return a.attributes["data-cke-survive"]?!1:"a"==a.name&&a.attributes.href||CKEDITOR.dtd.$removeEmpty[a.name]}var f=CKEDITOR.tools.extend({table:1,ul:1,ol:1,dl:1},CKEDITOR.dtd.table,CKEDITOR.dtd.ul,CKEDITOR.dtd.ol,CKEDITOR.dtd.dl),b={ol:1,ul:1},c=CKEDITOR.tools.extend({},{html:1},CKEDITOR.dtd.html,CKEDITOR.dtd.body,CKEDITOR.dtd.head,{style:1,script:1}),d={ul:"li",ol:"li",dl:"dd",table:"tbody",tbody:"tr",thead:"tr",tfoot:"tr",tr:"td"}; +CKEDITOR.htmlParser.fragment.fromHtml=function(l,k,g){function h(a){var b;if(0k;k++)if(f=d[k]){f= +f.exec(a,c,this);if(!1===f)return null;if(f&&f!=c)return this.onNode(a,f);if(c.parent&&!c.name)break}return c},onNode:function(a,c){var d=c.type;return d==CKEDITOR.NODE_ELEMENT?this.onElement(a,c):d==CKEDITOR.NODE_TEXT?new CKEDITOR.htmlParser.text(this.onText(a,c.value)):d==CKEDITOR.NODE_COMMENT?new CKEDITOR.htmlParser.comment(this.onComment(a,c.value)):null},onAttribute:function(a,c,d,f){return(d=this.attributesRules[d])?d.exec(a,f,c,this):f}}});CKEDITOR.htmlParser.filterRulesGroup=a;a.prototype= +{add:function(a,c,d){this.rules.splice(this.findIndex(c),0,{value:a,priority:c,options:d})},addMany:function(a,c,d){for(var f=[this.findIndex(c),0],k=0,g=a.length;k/g,"\x26gt;")+"\x3c/textarea\x3e");return"\x3ccke:encoded\x3e"+encodeURIComponent(a)+"\x3c/cke:encoded\x3e"})}function n(a){return a.replace(D,function(a,b){return decodeURIComponent(b)})}function q(a){return a.replace(/\x3c!--(?!{cke_protected})[\s\S]+?--\x3e/g, +function(a){return"\x3c!--"+z+"{C}"+encodeURIComponent(a).replace(/--/g,"%2D%2D")+"--\x3e"})}function y(a){return CKEDITOR.tools.array.reduce(a.split(""),function(a,b){var c=b.toLowerCase(),e=b.toUpperCase(),d=u(c);c!==e&&(d+="|"+u(e));return a+("("+d+")")},"")}function u(a){var b;b=a.charCodeAt(0);var c=b.toString(16);b={htmlCode:"\x26#"+b+";?",hex:"\x26#x0*"+c+";?",entity:{"\x3c":"\x26lt;","\x3e":"\x26gt;",":":"\x26colon;"}[a]};for(var e in b)b[e]&&(a+="|"+b[e]);return a}function p(a){return a.replace(/\x3c!--\{cke_protected\}\{C\}([\s\S]+?)--\x3e/g, +function(a,b){return decodeURIComponent(b)})}function v(a,b){var c=b._.dataStore;return a.replace(/\x3c!--\{cke_protected\}([\s\S]+?)--\x3e/g,function(a,b){return decodeURIComponent(b)}).replace(/\{cke_protected_(\d+)\}/g,function(a,b){return c&&c[b]||""})}function w(a,b){var c=[],e=b.config.protectedSource,d=b._.dataStore||(b._.dataStore={id:1}),g=/<\!--\{cke_temp(comment)?\}(\d*?)--\x3e/g,e=[/|$)/gi,//gi,//gi].concat(e);a=a.replace(/\x3c!--[\s\S]*?--\x3e/g, +function(a){return"\x3c!--{cke_tempcomment}"+(c.push(a)-1)+"--\x3e"});for(var h=0;h]+\s*=\s*(?:[^'"\s>]+|'[^']*'|"[^"]*"))|[^\s=\/>]+))+\s*\/?>/g,function(a){return a.replace(/\x3c!--\{cke_protected\}([^>]*)--\x3e/g, +function(a,b){d[d.id]=decodeURIComponent(b);return"{cke_protected_"+d.id++ +"}"})});return a=a.replace(/<(title|iframe|textarea)([^>]*)>([\s\S]*?)<\/\1>/g,function(a,c,e,d){return"\x3c"+c+e+"\x3e"+v(p(d),b)+"\x3c/"+c+"\x3e"})}CKEDITOR.htmlDataProcessor=function(b){var c,d,g=this;this.editor=b;this.dataFilter=c=new CKEDITOR.htmlParser.filter;this.htmlFilter=d=new CKEDITOR.htmlParser.filter;this.writer=new CKEDITOR.htmlParser.basicWriter;c.addRules(B);c.addRules(C,{applyToAll:!0});c.addRules(a(b,"data"), +{applyToAll:!0});d.addRules(H);d.addRules(F,{applyToAll:!0});d.addRules(a(b,"html"),{applyToAll:!0});b.on("toHtml",function(a){a=a.data;var c=a.dataValue,d,c=c.replace(N,""),c=w(c,b),c=e(c,G),c=m(c),c=e(c,L),c=c.replace(Q,"$1cke:$2"),c=c.replace(K,"\x3ccke:$1$2\x3e\x3c/cke:$1\x3e"),c=c.replace(/(]*>)(\r\n|\n)/g,"$1$2$2"),c=c.replace(/([^a-z0-9<\-])(on\w{3,})(?!>)/gi,"$1data-cke-"+CKEDITOR.rnd+"-$2");d=a.context||b.editable().getName();var g;CKEDITOR.env.ie&&9>CKEDITOR.env.version&&"pre"== +d&&(d="div",c="\x3cpre\x3e"+c+"\x3c/pre\x3e",g=1);d=b.document.createElement(d);d.setHtml("a"+c);c=d.getHtml().substr(1);c=c.replace(new RegExp("data-cke-"+CKEDITOR.rnd+"-","ig"),"");g&&(c=c.replace(/^
|<\/pre>$/gi,""));c=c.replace(O,"$1$2");c=n(c);c=p(c);d=!1===a.fixForBody?!1:f(a.enterMode,b.config.autoParagraph);c=CKEDITOR.htmlParser.fragment.fromHtml(c,a.context,d);d&&(g=c,!g.children.length&&CKEDITOR.dtd[g.name][d]&&(d=new CKEDITOR.htmlParser.element(d),g.add(d)));a.dataValue=c},null,null,
+5);b.on("toHtml",function(a){a.data.filter.applyTo(a.data.dataValue,!0,a.data.dontFilter,a.data.enterMode)&&b.fire("dataFiltered")},null,null,6);b.on("toHtml",function(a){a.data.dataValue.filterChildren(g.dataFilter,!0)},null,null,10);b.on("toHtml",function(a){a=a.data;var b=a.dataValue,c=new CKEDITOR.htmlParser.basicWriter;b.writeChildrenHtml(c);b=c.getHtml(!0);a.dataValue=q(b)},null,null,15);b.on("toDataFormat",function(a){var c=a.data.dataValue;a.data.enterMode!=CKEDITOR.ENTER_BR&&(c=c.replace(/^
/i, +""));a.data.dataValue=CKEDITOR.htmlParser.fragment.fromHtml(c,a.data.context,f(a.data.enterMode,b.config.autoParagraph))},null,null,5);b.on("toDataFormat",function(a){a.data.dataValue.filterChildren(g.htmlFilter,!0)},null,null,10);b.on("toDataFormat",function(a){a.data.filter.applyTo(a.data.dataValue,!1,!0)},null,null,11);b.on("toDataFormat",function(a){var c=a.data.dataValue,e=g.writer;e.reset();c.writeChildrenHtml(e);c=e.getHtml(!0);c=p(c);c=v(c,b);a.data.dataValue=c},null,null,15)};CKEDITOR.htmlDataProcessor.prototype= +{toHtml:function(a,b,c,e){var d=this.editor,g,h,f,m;b&&"object"==typeof b?(g=b.context,c=b.fixForBody,e=b.dontFilter,h=b.filter,f=b.enterMode,m=b.protectedWhitespaces):g=b;g||null===g||(g=d.editable().getName());return d.fire("toHtml",{dataValue:a,context:g,fixForBody:c,dontFilter:e,filter:h||d.filter,enterMode:f||d.enterMode,protectedWhitespaces:m}).dataValue},toDataFormat:function(a,b){var c,e,d;b&&(c=b.context,e=b.filter,d=b.enterMode);c||null===c||(c=this.editor.editable().getName());return this.editor.fire("toDataFormat", +{dataValue:a,filter:e||this.editor.filter,context:c,enterMode:d||this.editor.enterMode}).dataValue}};var r=/(?: |\xa0)$/,z="{cke_protected}",t=CKEDITOR.dtd,x="caption colgroup col thead tfoot tbody".split(" "),A=CKEDITOR.tools.extend({},t.$blockLimit,t.$block),B={elements:{input:g,textarea:g}},C={attributeNames:[[/^on/,"data-cke-pa-on"],[/^srcdoc/,"data-cke-pa-srcdoc"],[/^data-cke-expando$/,""]],elements:{iframe:function(a){if(a.attributes&&a.attributes.src){var b=a.attributes.src.toLowerCase().replace(/[^a-z]/gi, +"");if(0===b.indexOf("javascript")||0===b.indexOf("data"))a.attributes["data-cke-pa-src"]=a.attributes.src,delete a.attributes.src}}}},H={elements:{embed:function(a){var b=a.parent;if(b&&"object"==b.name){var c=b.attributes.width,b=b.attributes.height;c&&(a.attributes.width=c);b&&(a.attributes.height=b)}},a:function(a){var b=a.attributes;if(!(a.children.length||b.name||b.id||a.attributes["data-cke-saved-name"]))return!1}}},F={elementNames:[[/^cke:/,""],[/^\?xml:namespace$/,""]],attributeNames:[[/^data-cke-(saved|pa)-/, +""],[/^data-cke-.*/,""],["hidefocus",""]],elements:{$:function(a){var b=a.attributes;if(b){if(b["data-cke-temp"])return!1;for(var c=["name","href","src"],e,d=0;de? +1:-1})},param:function(a){a.children=[];a.isEmpty=!0;return a},span:function(a){"Apple-style-span"==a.attributes["class"]&&delete a.name},html:function(a){delete a.attributes.contenteditable;delete a.attributes["class"]},body:function(a){delete a.attributes.spellcheck;delete a.attributes.contenteditable},style:function(a){var b=a.children[0];b&&b.value&&(b.value=CKEDITOR.tools.trim(b.value));a.attributes.type||(a.attributes.type="text/css")},title:function(a){var b=a.children[0];!b&&k(a,b=new CKEDITOR.htmlParser.text); +b.value=a.attributes["data-cke-title"]||""},input:h,textarea:h},attributes:{"class":function(a){return CKEDITOR.tools.ltrim(a.replace(/(?:^|\s+)cke_[^\s]*/g,""))||!1}}};CKEDITOR.env.ie&&(F.attributes.style=function(a){return a.replace(/(^|;)([^\:]+)/g,function(a){return a.toLowerCase()})});var I=/<(a|area|img|input|source)\b([^>]*)>/gi,J=/([\w-:]+)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+))/gi,E=/^(href|src|name)$/i,L=/(?:])[^>]*>[\s\S]*?<\/style>)|(?:<(:?link|meta|base)[^>]*>)/gi, +G=/(])[^>]*>)([\s\S]*?)(?:<\/textarea>)/gi,D=/([^<]*)<\/cke:encoded>/gi,N=new RegExp("("+y("\x3ccke:encoded\x3e")+"(.*?)"+y("\x3c/cke:encoded\x3e")+")|("+y("\x3c")+y("/")+"?"+y("cke:encoded\x3e")+")","gi"),Q=/(<\/?)((?:object|embed|param|html|body|head|title)([\s][^>]*)?>)/gi,O=/(<\/?)cke:((?:html|body|head|title)[^>]*>)/gi,K=/]*?)\/?>(?!\s*<\/cke:\1)/gi}(),"use strict",CKEDITOR.htmlParser.element=function(a,f){this.name=a;this.attributes=f||{};this.children= +[];var b=a||"",c=b.match(/^cke:(.*)/);c&&(b=c[1]);b=!!(CKEDITOR.dtd.$nonBodyContent[b]||CKEDITOR.dtd.$block[b]||CKEDITOR.dtd.$listItem[b]||CKEDITOR.dtd.$tableContent[b]||CKEDITOR.dtd.$nonEditable[b]||"br"==b);this.isEmpty=!!CKEDITOR.dtd.$empty[a];this.isUnknown=!CKEDITOR.dtd[a];this._={isBlockLike:b,hasInlineStarted:this.isEmpty||!b}},CKEDITOR.htmlParser.cssStyle=function(a){var f={};((a instanceof CKEDITOR.htmlParser.element?a.attributes.style:a)||"").replace(/"/g,'"').replace(/\s*([^ :;]+)\s*:\s*([^;]+)\s*(?=;|$)/g, +function(a,c,d){"font-family"==c&&(d=d.replace(/["']/g,""));f[c.toLowerCase()]=d});return{rules:f,populate:function(a){var c=this.toString();c&&(a instanceof CKEDITOR.dom.element?a.setAttribute("style",c):a instanceof CKEDITOR.htmlParser.element?a.attributes.style=c:a.style=c)},toString:function(){var a=[],c;for(c in f)f[c]&&a.push(c,":",f[c],";");return a.join("")}}},function(){function a(a){return function(b){return b.type==CKEDITOR.NODE_ELEMENT&&("string"==typeof a?b.name==a:b.name in a)}}var f= +function(a,b){a=a[0];b=b[0];return ab?1:0},b=CKEDITOR.htmlParser.fragment.prototype;CKEDITOR.htmlParser.element.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_ELEMENT,add:b.add,clone:function(){return new CKEDITOR.htmlParser.element(this.name,this.attributes)},filter:function(a,b){var f=this,k,g;b=f.getFilterContext(b);if(!f.parent)a.onRoot(b,f);for(;;){k=f.name;if(!(g=a.onElementName(b,k)))return this.remove(),!1;f.name=g;if(!(f=a.onElement(b,f)))return this.remove(), +!1;if(f!==this)return this.replaceWith(f),!1;if(f.name==k)break;if(f.type!=CKEDITOR.NODE_ELEMENT)return this.replaceWith(f),!1;if(!f.name)return this.replaceWithChildren(),!1}k=f.attributes;var h,m;for(h in k){for(g=k[h];;)if(m=a.onAttributeName(b,h))if(m!=h)delete k[h],h=m;else break;else{delete k[h];break}m&&(!1===(g=a.onAttribute(b,f,m,g))?delete k[m]:k[m]=g)}f.isEmpty||this.filterChildren(a,!1,b);return!0},filterChildren:b.filterChildren,writeHtml:function(a,b){b&&this.filter(b);var l=this.name, +k=[],g=this.attributes,h,m;a.openTag(l,g);for(h in g)k.push([h,g[h]]);a.sortAttributes&&k.sort(f);h=0;for(m=k.length;hCKEDITOR.env.version||CKEDITOR.env.quirks))this.hasFocus&&(this.focus(),b());else if(this.hasFocus)this.focus(), +a();else this.once("focus",function(){a()},null,null,-999)},getHtmlFromRange:function(a){if(a.collapsed)return new CKEDITOR.dom.documentFragment(a.document);a={doc:this.getDocument(),range:a.clone()};z.eol.detect(a,this);z.bogus.exclude(a);z.cell.shrink(a);a.fragment=a.range.cloneContents();z.tree.rebuild(a,this);z.eol.fix(a,this);return new CKEDITOR.dom.documentFragment(a.fragment.$)},extractHtmlFromRange:function(a,b){var c=t,e={range:a,doc:a.document},d=this.getHtmlFromRange(a);if(a.collapsed)return a.optimize(), +d;a.enlarge(CKEDITOR.ENLARGE_INLINE,1);c.table.detectPurge(e);e.bookmark=a.createBookmark();delete e.range;var g=this.editor.createRange();g.moveToPosition(e.bookmark.startNode,CKEDITOR.POSITION_BEFORE_START);e.targetBookmark=g.createBookmark();c.list.detectMerge(e,this);c.table.detectRanges(e,this);c.block.detectMerge(e,this);e.tableContentsRanges?(c.table.deleteRanges(e),a.moveToBookmark(e.bookmark),e.range=a):(a.moveToBookmark(e.bookmark),e.range=a,a.extractContents(c.detectExtractMerge(e)));a.moveToBookmark(e.targetBookmark); +a.optimize();c.fixUneditableRangePosition(a);c.list.merge(e,this);c.table.purge(e,this);c.block.merge(e,this);if(b){c=a.startPath();if(e=a.checkStartOfBlock()&&a.checkEndOfBlock()&&c.block&&!a.root.equals(c.block)){a:{var e=c.block.getElementsByTag("span"),g=0,f;if(e)for(;f=e.getItem(g++);)if(!q(f)){e=!0;break a}e=!1}e=!e}e&&(a.moveToPosition(c.block,CKEDITOR.POSITION_BEFORE_START),c.block.remove())}else c.autoParagraph(this.editor,a),y(a.startContainer)&&a.startContainer.appendBogus();a.startContainer.mergeSiblings(); +return d},setup:function(){var a=this.editor;this.attachListener(a,"beforeGetData",function(){var b=this.getData();this.is("textarea")||!1!==a.config.ignoreEmptyParagraph&&(b=b.replace(p,function(a,b){return b}));a.setData(b,null,1)},this);this.attachListener(a,"getSnapshot",function(a){a.data=this.getData(1)},this);this.attachListener(a,"afterSetData",function(){this.setData(a.getData(1))},this);this.attachListener(a,"loadSnapshot",function(a){this.setData(a.data,1)},this);this.attachListener(a, +"beforeFocus",function(){var b=a.getSelection();(b=b&&b.getNative())&&"Control"==b.type||this.focus()},this);this.attachListener(a,"insertHtml",function(a){this.insertHtml(a.data.dataValue,a.data.mode,a.data.range)},this);this.attachListener(a,"insertElement",function(a){this.insertElement(a.data)},this);this.attachListener(a,"insertText",function(a){this.insertText(a.data)},this);this.setReadOnly(a.readOnly);this.attachClass("cke_editable");a.elementMode==CKEDITOR.ELEMENT_MODE_INLINE?this.attachClass("cke_editable_inline"): +a.elementMode!=CKEDITOR.ELEMENT_MODE_REPLACE&&a.elementMode!=CKEDITOR.ELEMENT_MODE_APPENDTO||this.attachClass("cke_editable_themed");this.attachClass("cke_contents_"+a.config.contentsLangDirection);a.keystrokeHandler.blockedKeystrokes[8]=+a.readOnly;a.keystrokeHandler.attach(this);this.on("blur",function(){this.hasFocus=!1},null,null,-1);this.on("focus",function(){this.hasFocus=!0},null,null,-1);if(CKEDITOR.env.webkit)this.on("scroll",function(){a._.previousScrollTop=a.editable().$.scrollTop},null, +null,-1);if(CKEDITOR.env.edge&&14CKEDITOR.env.version?m.$.styleSheet.cssText=h:m.setText(h)):(h=g.appendStyleText(h),h=new CKEDITOR.dom.element(h.ownerNode||h.owningElement),f.setCustomData("stylesheet", +h),h.data("cke-temp",1))}f=g.getCustomData("stylesheet_ref")||0;g.setCustomData("stylesheet_ref",f+1);this.setCustomData("cke_includeReadonly",!a.config.disableReadonlyStyling);this.attachListener(this,"click",function(a){a=a.data;var b=(new CKEDITOR.dom.elementPath(a.getTarget(),this)).contains("a");b&&2!=a.$.button&&b.isReadOnly()&&a.preventDefault()});var k={8:1,46:1};this.attachListener(a,"key",function(b){if(a.readOnly)return!0;var c=b.data.domEvent.getKey(),e;b=a.getSelection();if(0!==b.getRanges().length){if(c in +k){var d,g=b.getRanges()[0],f=g.startPath(),h,m,q,c=8==c;CKEDITOR.env.ie&&11>CKEDITOR.env.version&&(d=b.getSelectedElement())||(d=l(b))?(a.fire("saveSnapshot"),g.moveToPosition(d,CKEDITOR.POSITION_BEFORE_START),d.remove(),g.select(),a.fire("saveSnapshot"),e=1):g.collapsed&&((h=f.block)&&(q=h[c?"getPrevious":"getNext"](n))&&q.type==CKEDITOR.NODE_ELEMENT&&q.is("table")&&g[c?"checkStartOfBlock":"checkEndOfBlock"]()?(a.fire("saveSnapshot"),g[c?"checkEndOfBlock":"checkStartOfBlock"]()&&h.remove(),g["moveToElementEdit"+ +(c?"End":"Start")](q),g.select(),a.fire("saveSnapshot"),e=1):f.blockLimit&&f.blockLimit.is("td")&&(m=f.blockLimit.getAscendant("table"))&&g.checkBoundaryOfElement(m,c?CKEDITOR.START:CKEDITOR.END)&&(q=m[c?"getPrevious":"getNext"](n))?(a.fire("saveSnapshot"),g["moveToElementEdit"+(c?"End":"Start")](q),g.checkStartOfBlock()&&g.checkEndOfBlock()?q.remove():g.select(),a.fire("saveSnapshot"),e=1):(m=f.contains(["td","th","caption"]))&&g.checkBoundaryOfElement(m,c?CKEDITOR.START:CKEDITOR.END)&&(e=1))}return!e}}); +a.blockless&&CKEDITOR.env.ie&&CKEDITOR.env.needsBrFiller&&this.attachListener(this,"keyup",function(b){b.data.getKeystroke()in k&&!this.getFirst(c)&&(this.appendBogus(),b=a.createRange(),b.moveToPosition(this,CKEDITOR.POSITION_AFTER_START),b.select())});this.attachListener(this,"dblclick",function(b){if(a.readOnly)return!1;b={element:b.data.getTarget()};a.fire("doubleclick",b)});CKEDITOR.env.ie&&this.attachListener(this,"click",b);CKEDITOR.env.ie&&!CKEDITOR.env.edge||this.attachListener(this,"mousedown", +function(b){var c=b.data.getTarget();c.is("img","hr","input","textarea","select")&&!c.isReadOnly()&&(a.getSelection().selectElement(c),c.is("input","textarea","select")&&b.data.preventDefault())});CKEDITOR.env.edge&&this.attachListener(this,"mouseup",function(b){(b=b.data.getTarget())&&b.is("img")&&!b.isReadOnly()&&a.getSelection().selectElement(b)});CKEDITOR.env.gecko&&this.attachListener(this,"mouseup",function(b){if(2==b.data.$.button&&(b=b.data.getTarget(),!b.getAscendant("table")&&!b.getOuterHtml().replace(p, +""))){var c=a.createRange();c.moveToElementEditStart(b);c.select(!0)}});CKEDITOR.env.webkit&&(this.attachListener(this,"click",function(a){a.data.getTarget().is("input","select")&&a.data.preventDefault()}),this.attachListener(this,"mouseup",function(a){a.data.getTarget().is("input","textarea")&&a.data.preventDefault()}));CKEDITOR.env.webkit&&this.attachListener(a,"key",function(b){if(a.readOnly)return!0;var c=b.data.domEvent.getKey();if(c in k&&(b=a.getSelection(),0!==b.getRanges().length)){var c= +8==c,d=b.getRanges()[0];b=d.startPath();if(d.collapsed)a:{var g=b.block;if(g&&d[c?"checkStartOfBlock":"checkEndOfBlock"]()&&d.moveToClosestEditablePosition(g,!c)&&d.collapsed){if(d.startContainer.type==CKEDITOR.NODE_ELEMENT){var f=d.startContainer.getChild(d.startOffset-(c?1:0));if(f&&f.type==CKEDITOR.NODE_ELEMENT&&f.is("hr")){a.fire("saveSnapshot");f.remove();b=!0;break a}}d=d.startPath().block;if(!d||d&&d.contains(g))b=void 0;else{a.fire("saveSnapshot");var h;(h=(c?d:g).getBogus())&&h.remove(); +h=a.getSelection();f=h.createBookmarks();(c?g:d).moveChildren(c?d:g,!1);b.lastElement.mergeSiblings();e(g,d,!c);h.selectBookmarks(f);b=!0}}else b=!1}else c=d,h=b.block,d=c.endPath().block,h&&d&&!h.equals(d)?(a.fire("saveSnapshot"),(g=h.getBogus())&&g.remove(),c.enlarge(CKEDITOR.ENLARGE_INLINE),c.deleteContents(),d.getParent()&&(d.moveChildren(h,!1),b.lastElement.mergeSiblings(),e(h,d,!0)),c=a.getSelection().getRanges()[0],c.collapse(1),c.optimize(),""===c.startContainer.getHtml()&&c.startContainer.appendBogus(), +c.select(),b=!0):b=!1;if(!b)return;a.getSelection().scrollIntoView();a.fire("saveSnapshot");return!1}},this,null,100)}}},_:{detach:function(){this.editor.setData(this.editor.getData(),0,1);this.clearListeners();this.restoreAttrs();var a;if(a=this.removeCustomData("classes"))for(;a.length;)this.removeClass(a.pop());if(!this.is("textarea")){a=this.getDocument();var b=a.getHead();if(b.getCustomData("stylesheet")){var c=a.getCustomData("stylesheet_ref");--c?a.setCustomData("stylesheet_ref",c):(a.removeCustomData("stylesheet_ref"), +b.removeCustomData("stylesheet").remove())}}this.editor.fire("contentDomUnload");delete this.editor}}});CKEDITOR.editor.prototype.editable=function(a){var b=this._.editable;if(b&&a)return 0;arguments.length&&(b=this._.editable=a?a instanceof CKEDITOR.editable?a:new CKEDITOR.editable(this,a):(b&&b.detach(),null));return b};CKEDITOR.on("instanceLoaded",function(b){var c=b.editor;c.on("insertElement",function(a){a=a.data;a.type==CKEDITOR.NODE_ELEMENT&&(a.is("input")||a.is("textarea"))&&("false"!=a.getAttribute("contentEditable")&& +a.data("cke-editable",a.hasAttribute("contenteditable")?"true":"1"),a.setAttribute("contentEditable",!1))});c.on("selectionChange",function(b){if(!c.readOnly){var e=c.getSelection();e&&!e.isLocked&&(e=c.checkDirty(),c.fire("lockSnapshot"),a(b),c.fire("unlockSnapshot"),!e&&c.resetDirty())}})});CKEDITOR.on("instanceCreated",function(a){var b=a.editor;b.on("mode",function(){var a=b.editable();if(a&&a.isInline()){var c=b.title;a.changeAttr("role","textbox");a.changeAttr("aria-multiline","true");a.changeAttr("aria-label", +c);c&&a.changeAttr("title",c);var e=b.fire("ariaEditorHelpLabel",{}).label;if(e&&(c=this.ui.space(this.elementMode==CKEDITOR.ELEMENT_MODE_INLINE?"top":"contents"))){var d=CKEDITOR.tools.getNextId(),e=CKEDITOR.dom.element.createFromHtml('\x3cspan id\x3d"'+d+'" class\x3d"cke_voice_label"\x3e'+e+"\x3c/span\x3e");c.append(e);a.changeAttr("aria-describedby",d)}}})});CKEDITOR.addCss(".cke_editable{cursor:text}.cke_editable img,.cke_editable input,.cke_editable textarea{cursor:default}");n=CKEDITOR.dom.walker.whitespaces(!0); +q=CKEDITOR.dom.walker.bookmark(!1,!0);y=CKEDITOR.dom.walker.empty();u=CKEDITOR.dom.walker.bogus();p=/(^|]*>)\s*<(p|div|address|h\d|center|pre)[^>]*>\s*(?:]*>| |\u00A0| )?\s*(:?<\/\2>)?\s*(?=$|<\/body>)/gi;v=function(){function a(b){return b.type==CKEDITOR.NODE_ELEMENT}function b(c,e){var d,g,f,h,m=[],k=e.range.startContainer;d=e.range.startPath();for(var k=n[k.getName()],l=0,q=c.getChildren(),G=q.count(),v=-1,r=-1,F=0,t=d.contains(n.$list);lCKEDITOR.env.version&&e.getChildCount()&&e.getFirst().remove())}return function(e){var d=e.startContainer,g=d.getAscendant("table",1),f=!1;c(g.getElementsByTag("td"));c(g.getElementsByTag("th"));g=e.clone();g.setStart(d,0);g= +a(g).lastBackward();g||(g=e.clone(),g.setEndAt(d,CKEDITOR.POSITION_BEFORE_END),g=a(g).lastForward(),f=!0);g||(g=d);g.is("table")?(e.setStartAt(g,CKEDITOR.POSITION_BEFORE_START),e.collapse(!0),g.remove()):(g.is({tbody:1,thead:1,tfoot:1})&&(g=b(g,"tr",f)),g.is("tr")&&(g=b(g,g.getParent().is("thead")?"th":"td",f)),(d=g.getBogus())&&d.remove(),e.moveToPosition(g,f?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_END))}}();r=function(){function a(b){b=new CKEDITOR.dom.walker(b);b.guard=function(a, +b){if(b)return!1;if(a.type==CKEDITOR.NODE_ELEMENT)return a.is(CKEDITOR.dtd.$list)||a.is(CKEDITOR.dtd.$listItem)};b.evaluator=function(a){return a.type==CKEDITOR.NODE_ELEMENT&&a.is(CKEDITOR.dtd.$listItem)};return b}return function(b){var c=b.startContainer,e=!1,d;d=b.clone();d.setStart(c,0);d=a(d).lastBackward();d||(d=b.clone(),d.setEndAt(c,CKEDITOR.POSITION_BEFORE_END),d=a(d).lastForward(),e=!0);d||(d=c);d.is(CKEDITOR.dtd.$list)?(b.setStartAt(d,CKEDITOR.POSITION_BEFORE_START),b.collapse(!0),d.remove()): +((c=d.getBogus())&&c.remove(),b.moveToPosition(d,e?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_END),b.select())}}();z={eol:{detect:function(a,b){var c=a.range,e=c.clone(),d=c.clone(),g=new CKEDITOR.dom.elementPath(c.startContainer,b),f=new CKEDITOR.dom.elementPath(c.endContainer,b);e.collapse(1);d.collapse();g.block&&e.checkBoundaryOfElement(g.block,CKEDITOR.END)&&(c.setStartAfter(g.block),a.prependEolBr=1);f.block&&d.checkBoundaryOfElement(f.block,CKEDITOR.START)&&(c.setEndBefore(f.block), +a.appendEolBr=1)},fix:function(a,b){var c=b.getDocument(),e;a.appendEolBr&&(e=this.createEolBr(c),a.fragment.append(e));!a.prependEolBr||e&&!e.getPrevious()||a.fragment.append(this.createEolBr(c),1)},createEolBr:function(a){return a.createElement("br",{attributes:{"data-cke-eol":1}})}},bogus:{exclude:function(a){var b=a.range.getBoundaryNodes(),c=b.startNode,b=b.endNode;!b||!u(b)||c&&c.equals(b)||a.range.setEndBefore(b)}},tree:{rebuild:function(a,b){var c=a.range,e=c.getCommonAncestor(),d=new CKEDITOR.dom.elementPath(e, +b),g=new CKEDITOR.dom.elementPath(c.startContainer,b),c=new CKEDITOR.dom.elementPath(c.endContainer,b),f;e.type==CKEDITOR.NODE_TEXT&&(e=e.getParent());if(d.blockLimit.is({tr:1,table:1})){var h=d.contains("table").getParent();f=function(a){return!a.equals(h)}}else if(d.block&&d.block.is(CKEDITOR.dtd.$listItem)&&(g=g.contains(CKEDITOR.dtd.$list),c=c.contains(CKEDITOR.dtd.$list),!g.equals(c))){var m=d.contains(CKEDITOR.dtd.$list).getParent();f=function(a){return!a.equals(m)}}f||(f=function(a){return!a.equals(d.block)&& +!a.equals(d.blockLimit)});this.rebuildFragment(a,b,e,f)},rebuildFragment:function(a,b,c,e){for(var d;c&&!c.equals(b)&&e(c);)d=c.clone(0,1),a.fragment.appendTo(d),a.fragment=d,c=c.getParent()}},cell:{shrink:function(a){a=a.range;var b=a.startContainer,c=a.endContainer,e=a.startOffset,d=a.endOffset;b.type==CKEDITOR.NODE_ELEMENT&&b.equals(c)&&b.is("tr")&&++e==d&&a.shrink(CKEDITOR.SHRINK_TEXT)}}};t=function(){function a(b,c){var e=b.getParent();if(e.is(CKEDITOR.dtd.$inline))b[c?"insertBefore":"insertAfter"](e)} +function b(c,e,d){a(e);a(d,1);for(var g;g=d.getNext();)g.insertAfter(e),e=g;y(c)&&c.remove()}function c(a,b){var e=new CKEDITOR.dom.range(a);e.setStartAfter(b.startNode);e.setEndBefore(b.endNode);return e}return{list:{detectMerge:function(a,b){var e=c(b,a.bookmark),d=e.startPath(),g=e.endPath(),f=d.contains(CKEDITOR.dtd.$list),h=g.contains(CKEDITOR.dtd.$list);a.mergeList=f&&h&&f.getParent().equals(h.getParent())&&!f.equals(h);a.mergeListItems=d.block&&g.block&&d.block.is(CKEDITOR.dtd.$listItem)&& +g.block.is(CKEDITOR.dtd.$listItem);if(a.mergeList||a.mergeListItems)e=e.clone(),e.setStartBefore(a.bookmark.startNode),e.setEndAfter(a.bookmark.endNode),a.mergeListBookmark=e.createBookmark()},merge:function(a,c){if(a.mergeListBookmark){var e=a.mergeListBookmark.startNode,d=a.mergeListBookmark.endNode,g=new CKEDITOR.dom.elementPath(e,c),f=new CKEDITOR.dom.elementPath(d,c);if(a.mergeList){var h=g.contains(CKEDITOR.dtd.$list),m=f.contains(CKEDITOR.dtd.$list);h.equals(m)||(m.moveChildren(h),m.remove())}a.mergeListItems&& +(g=g.contains(CKEDITOR.dtd.$listItem),f=f.contains(CKEDITOR.dtd.$listItem),g.equals(f)||b(f,e,d));e.remove();d.remove()}}},block:{detectMerge:function(a,b){if(!a.tableContentsRanges&&!a.mergeListBookmark){var c=new CKEDITOR.dom.range(b);c.setStartBefore(a.bookmark.startNode);c.setEndAfter(a.bookmark.endNode);a.mergeBlockBookmark=c.createBookmark()}},merge:function(a,c){if(a.mergeBlockBookmark&&!a.purgeTableBookmark){var e=a.mergeBlockBookmark.startNode,d=a.mergeBlockBookmark.endNode,g=new CKEDITOR.dom.elementPath(e, +c),f=new CKEDITOR.dom.elementPath(d,c),g=g.block,f=f.block;g&&f&&!g.equals(f)&&b(f,e,d);e.remove();d.remove()}}},table:function(){function a(c){var d=[],g,f=new CKEDITOR.dom.walker(c),h=c.startPath().contains(e),m=c.endPath().contains(e),k={};f.guard=function(a,f){if(a.type==CKEDITOR.NODE_ELEMENT){var l="visited_"+(f?"out":"in");if(a.getCustomData(l))return;CKEDITOR.dom.element.setMarker(k,a,l,1)}if(f&&h&&a.equals(h))g=c.clone(),g.setEndAt(h,CKEDITOR.POSITION_BEFORE_END),d.push(g);else if(!f&&m&& +a.equals(m))g=c.clone(),g.setStartAt(m,CKEDITOR.POSITION_AFTER_START),d.push(g);else{if(l=!f)l=a.type==CKEDITOR.NODE_ELEMENT&&a.is(e)&&(!h||b(a,h))&&(!m||b(a,m));if(!l&&(l=f))if(a.is(e))var l=h&&h.getAscendant("table",!0),n=m&&m.getAscendant("table",!0),q=a.getAscendant("table",!0),l=l&&l.contains(q)||n&&n.contains(q);else l=void 0;l&&(g=c.clone(),g.selectNodeContents(a),d.push(g))}};f.lastForward();CKEDITOR.dom.element.clearAllMarkers(k);return d}function b(a,c){var e=CKEDITOR.POSITION_CONTAINS+ +CKEDITOR.POSITION_IS_CONTAINED,d=a.getPosition(c);return d===CKEDITOR.POSITION_IDENTICAL?!1:0===(d&e)}var e={td:1,th:1,caption:1};return{detectPurge:function(a){var b=a.range,c=b.clone();c.enlarge(CKEDITOR.ENLARGE_ELEMENT);var c=new CKEDITOR.dom.walker(c),d=0;c.evaluator=function(a){a.type==CKEDITOR.NODE_ELEMENT&&a.is(e)&&++d};c.checkForward();if(1g&&d&&d.intersectsNode(c.$)){var f=[{node:e.anchorNode,offset:e.anchorOffset},{node:e.focusNode,offset:e.focusOffset}];e.anchorNode==c.$&&e.anchorOffset>g&&(f[0].offset-=g);e.focusNode==c.$&&e.focusOffset>g&&(f[1].offset-=g)}}c.setText(q(c.getText(),1));f&&(c=a.getDocument().$, +e=c.getSelection(),c=c.createRange(),c.setStart(f[0].node,f[0].offset),c.collapse(!0),e.removeAllRanges(),e.addRange(c),e.extend(f[1].node,f[1].offset))}}function q(a,b){return b?a.replace(z,function(a,b){return b?" ":""}):a.replace(r,"")}function y(a,b){var c=b&&CKEDITOR.tools.htmlEncode(b)||"\x26nbsp;",c=CKEDITOR.dom.element.createFromHtml('\x3cdiv data-cke-hidden-sel\x3d"1" data-cke-temp\x3d"1" style\x3d"'+(CKEDITOR.env.ie&&14>CKEDITOR.env.version?"display:none":"position:fixed;top:0;left:-1000px;width:0;height:0;overflow:hidden;")+ +'"\x3e'+c+"\x3c/div\x3e",a.document);a.fire("lockSnapshot");a.editable().append(c);var e=a.getSelection(1),d=a.createRange(),g=e.root.on("selectionchange",function(a){a.cancel()},null,null,0);d.setStartAt(c,CKEDITOR.POSITION_AFTER_START);d.setEndAt(c,CKEDITOR.POSITION_BEFORE_END);e.selectRanges([d]);g.removeListener();a.fire("unlockSnapshot");a._.hiddenSelectionContainer=c}function u(a){var b={37:1,39:1,8:1,46:1};return function(c){var e=c.data.getKeystroke();if(b[e]){var d=a.getSelection().getRanges(), +g=d[0];1==d.length&&g.collapsed&&(e=g[38>e?"getPreviousEditableNode":"getNextEditableNode"]())&&e.type==CKEDITOR.NODE_ELEMENT&&"false"==e.getAttribute("contenteditable")&&(a.getSelection().fake(e),c.data.preventDefault(),c.cancel())}}}function p(a){for(var b=0;b=e.getLength()?h.setStartAfter(e):h.setStartBefore(e));d&&d.type==CKEDITOR.NODE_TEXT&&(f?h.setEndAfter(d):h.setEndBefore(d));e=new CKEDITOR.dom.walker(h);e.evaluator=function(e){if(e.type==CKEDITOR.NODE_ELEMENT&&e.isReadOnly()){var d=c.clone();c.setEndBefore(e);c.collapsed&&a.splice(b--,1);e.getPosition(h.endContainer)& +CKEDITOR.POSITION_CONTAINS||(d.setStartAfter(e),d.collapsed||a.splice(b+1,0,d));return!0}return!1};e.next()}}return a}var v="function"!=typeof window.getSelection,w=1,r=CKEDITOR.tools.repeat("​",7),z=new RegExp(r+"( )?","g"),t,x,A,B=CKEDITOR.dom.walker.invisible(1),C=function(){function a(b){return function(a){var c=a.editor.createRange();c.moveToClosestEditablePosition(a.selected,b)&&a.editor.getSelection().selectRanges([c]);return!1}}function b(a){return function(b){var c=b.editor,e=c.createRange(), +d;if(!c.readOnly)return(d=e.moveToClosestEditablePosition(b.selected,a))||(d=e.moveToClosestEditablePosition(b.selected,!a)),d&&c.getSelection().selectRanges([e]),c.fire("saveSnapshot"),b.selected.remove(),d||(e.moveToElementEditablePosition(c.editable()),c.getSelection().selectRanges([e])),c.fire("saveSnapshot"),!1}}var c=a(),e=a(1);return{37:c,38:c,39:e,40:e,8:b(),46:b(1)}}();CKEDITOR.on("instanceCreated",function(a){function b(){var a=c.getSelection();a&&a.removeAllRanges()}var c=a.editor;c.on("contentDom", +function(){function a(){t=new CKEDITOR.dom.selection(c.getSelection());t.lock()}function b(){g.removeListener("mouseup",b);m.removeListener("mouseup",b);var a=CKEDITOR.document.$.selection,c=a.createRange();"None"!=a.type&&c.parentElement()&&c.parentElement().ownerDocument==d.$&&c.select()}function e(a){a=a.getRanges()[0];return a?(a=a.startContainer.getAscendant(function(a){return a.type==CKEDITOR.NODE_ELEMENT&&a.hasAttribute("contenteditable")},!0))&&"false"===a.getAttribute("contenteditable")? +a:null:null}var d=c.document,g=CKEDITOR.document,f=c.editable(),h=d.getBody(),m=d.getDocumentElement(),q=f.isInline(),r,t;CKEDITOR.env.gecko&&f.attachListener(f,"focus",function(a){a.removeListener();0!==r&&(a=c.getSelection().getNative())&&a.isCollapsed&&a.anchorNode==f.$&&(a=c.createRange(),a.moveToElementEditStart(f),a.select())},null,null,-2);f.attachListener(f,CKEDITOR.env.webkit||CKEDITOR.env.gecko?"focusin":"focus",function(){if(r&&(CKEDITOR.env.webkit||CKEDITOR.env.gecko)){r=c._.previousActive&& +c._.previousActive.equals(d.getActive());var a=null!=c._.previousScrollTop&&c._.previousScrollTop!=f.$.scrollTop;CKEDITOR.env.webkit&&r&&a&&(f.$.scrollTop=c._.previousScrollTop)}c.unlockSelection(r);r=0},null,null,-1);f.attachListener(f,"mousedown",function(){r=0});if(CKEDITOR.env.ie||q)v?f.attachListener(f,"beforedeactivate",a,null,null,-1):f.attachListener(c,"selectionCheck",a,null,null,-1),f.attachListener(f,CKEDITOR.env.webkit||CKEDITOR.env.gecko?"focusout":"blur",function(){c.lockSelection(t); +r=1},null,null,-1),f.attachListener(f,"mousedown",function(){r=0});if(CKEDITOR.env.ie&&!q){var w;f.attachListener(f,"mousedown",function(a){2==a.data.$.button&&((a=c.document.getSelection())&&a.getType()!=CKEDITOR.SELECTION_NONE||(w=c.window.getScrollPosition()))});f.attachListener(f,"mouseup",function(a){2==a.data.$.button&&w&&(c.document.$.documentElement.scrollLeft=w.x,c.document.$.documentElement.scrollTop=w.y);w=null});if("BackCompat"!=d.$.compatMode){if(CKEDITOR.env.ie7Compat||CKEDITOR.env.ie6Compat){var z, +y;m.on("mousedown",function(a){function b(a){a=a.data.$;if(z){var c=h.$.createTextRange();try{c.moveToPoint(a.clientX,a.clientY)}catch(e){}z.setEndPoint(0>y.compareEndPoints("StartToStart",c)?"EndToEnd":"StartToStart",c);z.select()}}function c(){m.removeListener("mousemove",b);g.removeListener("mouseup",c);m.removeListener("mouseup",c);z.select()}a=a.data;if(a.getTarget().is("html")&&a.$.yCKEDITOR.env.version)m.on("mousedown",function(a){a.data.getTarget().is("html")&&(g.on("mouseup",b),m.on("mouseup",b))})}}f.attachListener(f,"selectionchange",l,c);f.attachListener(f,"keyup",k,c);f.attachListener(f,"touchstart",k,c);f.attachListener(f,"touchend",k,c);CKEDITOR.env.ie&&f.attachListener(f,"keydown",function(a){var b=this.getSelection(1),c=e(b);c&&!c.equals(f)&&(b.selectElement(c),a.data.preventDefault())}, +c);f.attachListener(f,CKEDITOR.env.webkit||CKEDITOR.env.gecko?"focusin":"focus",function(){c.forceNextSelectionCheck();c.selectionChange(1)});if(q&&(CKEDITOR.env.webkit||CKEDITOR.env.gecko)){var p;f.attachListener(f,"mousedown",function(){p=1});f.attachListener(d.getDocumentElement(),"mouseup",function(){p&&k.call(c);p=0})}else f.attachListener(CKEDITOR.env.ie?f:d.getDocumentElement(),"mouseup",k,c);CKEDITOR.env.webkit&&f.attachListener(d,"keydown",function(a){switch(a.data.getKey()){case 13:case 33:case 34:case 35:case 36:case 37:case 39:case 8:case 45:case 46:f.hasFocus&& +n(f)}},null,null,-1);f.attachListener(f,"keydown",u(c),null,null,-1)});c.on("setData",function(){c.unlockSelection();CKEDITOR.env.webkit&&b()});c.on("contentDomUnload",function(){c.unlockSelection()});if(CKEDITOR.env.ie9Compat)c.on("beforeDestroy",b,null,null,9);c.on("dataReady",function(){delete c._.fakeSelection;delete c._.hiddenSelectionContainer;c.selectionChange(1)});c.on("loadSnapshot",function(){var a=CKEDITOR.dom.walker.nodeType(CKEDITOR.NODE_ELEMENT),b=c.editable().getLast(a);b&&b.hasAttribute("data-cke-hidden-sel")&& +(b.remove(),CKEDITOR.env.gecko&&(a=c.editable().getFirst(a))&&a.is("br")&&a.getAttribute("_moz_editor_bogus_node")&&a.remove())},null,null,100);c.on("key",function(a){if("wysiwyg"==c.mode){var b=c.getSelection();if(b.isFake){var e=C[a.data.keyCode];if(e)return e({editor:c,selected:b.getSelectedElement(),selection:b,keyEvent:a})}}})});if(CKEDITOR.env.webkit)CKEDITOR.on("instanceReady",function(a){var b=a.editor;b.on("selectionChange",function(){var a=b.editable(),c=a.getCustomData("cke-fillingChar"); +c&&(c.getCustomData("ready")?(n(a),a.editor.fire("selectionCheck")):c.setCustomData("ready",1))},null,null,-1);b.on("beforeSetMode",function(){n(b.editable())},null,null,-1);b.on("getSnapshot",function(a){a.data&&(a.data=q(a.data))},b,null,20);b.on("toDataFormat",function(a){a.data.dataValue=q(a.data.dataValue)},null,null,0)});CKEDITOR.editor.prototype.selectionChange=function(a){(a?l:k).call(this)};CKEDITOR.editor.prototype.getSelection=function(a){return!this._.savedSelection&&!this._.fakeSelection|| +a?(a=this.editable())&&"wysiwyg"==this.mode?new CKEDITOR.dom.selection(a):null:this._.savedSelection||this._.fakeSelection};CKEDITOR.editor.prototype.lockSelection=function(a){a=a||this.getSelection(1);return a.getType()!=CKEDITOR.SELECTION_NONE?(!a.isLocked&&a.lock(),this._.savedSelection=a,!0):!1};CKEDITOR.editor.prototype.unlockSelection=function(a){var b=this._.savedSelection;return b?(b.unlock(a),delete this._.savedSelection,!0):!1};CKEDITOR.editor.prototype.forceNextSelectionCheck=function(){delete this._.selectionPreviousPath}; +CKEDITOR.dom.document.prototype.getSelection=function(){return new CKEDITOR.dom.selection(this)};CKEDITOR.dom.range.prototype.select=function(){var a=this.root instanceof CKEDITOR.editable?this.root.editor.getSelection():new CKEDITOR.dom.selection(this.root);a.selectRanges([this]);return a};CKEDITOR.SELECTION_NONE=1;CKEDITOR.SELECTION_TEXT=2;CKEDITOR.SELECTION_ELEMENT=3;CKEDITOR.dom.selection=function(a){if(a instanceof CKEDITOR.dom.selection){var b=a;a=a.root}var c=a instanceof CKEDITOR.dom.element; +this.rev=b?b.rev:w++;this.document=a instanceof CKEDITOR.dom.document?a:a.getDocument();this.root=c?a:this.document.getBody();this.isLocked=0;this._={cache:{}};if(b)return CKEDITOR.tools.extend(this._.cache,b._.cache),this.isFake=b.isFake,this.isLocked=b.isLocked,this;a=this.getNative();var e,d;if(a)if(a.getRangeAt)e=(d=a.rangeCount&&a.getRangeAt(0))&&new CKEDITOR.dom.node(d.commonAncestorContainer);else{try{d=a.createRange()}catch(g){}e=d&&CKEDITOR.dom.element.get(d.item&&d.item(0)||d.parentElement())}if(!e|| +e.type!=CKEDITOR.NODE_ELEMENT&&e.type!=CKEDITOR.NODE_TEXT||!this.root.equals(e)&&!this.root.contains(e))this._.cache.type=CKEDITOR.SELECTION_NONE,this._.cache.startElement=null,this._.cache.selectedElement=null,this._.cache.selectedText="",this._.cache.ranges=new CKEDITOR.dom.rangeList;return this};var H={img:1,hr:1,li:1,table:1,tr:1,td:1,th:1,embed:1,object:1,ol:1,ul:1,a:1,input:1,form:1,select:1,textarea:1,button:1,fieldset:1,thead:1,tfoot:1};CKEDITOR.tools.extend(CKEDITOR.dom.selection,{_removeFillingCharSequenceString:q, +_createFillingCharSequenceNode:e,FILLING_CHAR_SEQUENCE:r});CKEDITOR.dom.selection.prototype={getNative:function(){return void 0!==this._.cache.nativeSel?this._.cache.nativeSel:this._.cache.nativeSel=v?this.document.$.selection:this.document.getWindow().$.getSelection()},getType:v?function(){var a=this._.cache;if(a.type)return a.type;var b=CKEDITOR.SELECTION_NONE;try{var c=this.getNative(),e=c.type;"Text"==e&&(b=CKEDITOR.SELECTION_TEXT);"Control"==e&&(b=CKEDITOR.SELECTION_ELEMENT);c.createRange().parentElement()&& +(b=CKEDITOR.SELECTION_TEXT)}catch(d){}return a.type=b}:function(){var a=this._.cache;if(a.type)return a.type;var b=CKEDITOR.SELECTION_TEXT,c=this.getNative();if(!c||!c.rangeCount)b=CKEDITOR.SELECTION_NONE;else if(1==c.rangeCount){var c=c.getRangeAt(0),e=c.startContainer;e==c.endContainer&&1==e.nodeType&&1==c.endOffset-c.startOffset&&H[e.childNodes[c.startOffset].nodeName.toLowerCase()]&&(b=CKEDITOR.SELECTION_ELEMENT)}return a.type=b},getRanges:function(){var a=v?function(){function a(b){return(new CKEDITOR.dom.node(b)).getIndex()} +var b=function(b,c){b=b.duplicate();b.collapse(c);var e=b.parentElement();if(!e.hasChildNodes())return{container:e,offset:0};for(var d=e.children,g,f,h=b.duplicate(),m=0,k=d.length-1,l=-1,n,q;m<=k;)if(l=Math.floor((m+k)/2),g=d[l],h.moveToElementText(g),n=h.compareEndPoints("StartToStart",b),0n)m=l+1;else return{container:e,offset:a(g)};if(-1==l||l==d.length-1&&0>n){h.moveToElementText(e);h.setEndPoint("StartToStart",b);h=h.text.replace(/(\r\n|\r)/g,"\n").length;d=e.childNodes;if(!h)return g= +d[d.length-1],g.nodeType!=CKEDITOR.NODE_TEXT?{container:e,offset:d.length}:{container:g,offset:g.nodeValue.length};for(e=d.length;0]*>)[ \t\r\n]*/gi,"$1");f=f.replace(/([ \t\n\r]+| )/g, +" ");f=f.replace(/]*>/gi,"\n");if(CKEDITOR.env.ie){var h=a.getDocument().createElement("div");h.append(g);g.$.outerHTML="\x3cpre\x3e"+f+"\x3c/pre\x3e";g.copyAttributes(h.getFirst());g=h.getFirst().remove()}else g.setHtml(f);b=g}else f?b=q(c?[a.getHtml()]:e(a),b):a.moveChildren(b);b.replace(a);if(d){var c=b,m;(m=c.getPrevious(E))&&m.type==CKEDITOR.NODE_ELEMENT&&m.is("pre")&&(d=n(m.getHtml(),/\n$/,"")+"\n\n"+n(c.getHtml(),/^\n/,""),CKEDITOR.env.ie?c.$.outerHTML="\x3cpre\x3e"+d+"\x3c/pre\x3e": +c.setHtml(d),m.remove())}else c&&v(b)}function e(a){var b=[];n(a.getOuterHtml(),/(\S\s*)\n(?:\s|(]+data-cke-bookmark.*?\/span>))*\n(?!$)/gi,function(a,b,c){return b+"\x3c/pre\x3e"+c+"\x3cpre\x3e"}).replace(/([\s\S]*?)<\/pre>/gi,function(a,c){b.push(c)});return b}function n(a,b,c){var e="",d="";a=a.replace(/(^]+data-cke-bookmark.*?\/span>)|(]+data-cke-bookmark.*?\/span>$)/gi,function(a,b,c){b&&(e=b);c&&(d=c);return""});return e+a.replace(b,c)+d}function q(a,b){var c; +1=c?(l=d.createText(""),l.insertAfter(this)):(a=d.createText(""),a.insertAfter(l),a.remove()));return l},substring:function(a,f){return"number"!=typeof f?this.$.nodeValue.substr(a):this.$.nodeValue.substring(a,f)}}),function(){function a(a,c,d){var f=a.serializable,k=c[d?"endContainer":"startContainer"],g=d?"endOffset":"startOffset",h=f?c.document.getById(a.startNode):a.startNode;a=f?c.document.getById(a.endNode):a.endNode;k.equals(h.getPrevious())? +(c.startOffset=c.startOffset-k.getLength()-a.getPrevious().getLength(),k=a.getNext()):k.equals(a.getPrevious())&&(c.startOffset-=k.getLength(),k=a.getNext());k.equals(h.getParent())&&c[g]++;k.equals(a.getParent())&&c[g]++;c[d?"endContainer":"startContainer"]=k;return c}CKEDITOR.dom.rangeList=function(a){if(a instanceof CKEDITOR.dom.rangeList)return a;a?a instanceof CKEDITOR.dom.range&&(a=[a]):a=[];return CKEDITOR.tools.extend(a,f)};var f={createIterator:function(){var a=this,c=CKEDITOR.dom.walker.bookmark(), +d=[],f;return{getNextRange:function(k){f=void 0===f?0:f+1;var g=a[f];if(g&&1b?-1:1}),g=0,f;gCKEDITOR.env.version?a[h].$.styleSheet.cssText+=f:a[h].$.innerHTML+=f}}var l={};CKEDITOR.skin={path:a,loadPart:function(c, +e){CKEDITOR.skin.name!=CKEDITOR.skinName.split(",")[0]?CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(a()+"skin.js"),function(){b(c,e)}):b(c,e)},getPath:function(a){return CKEDITOR.getUrl(f(a))},icons:{},addIcon:function(a,b,c,d){a=a.toLowerCase();this.icons[a]||(this.icons[a]={path:b,offset:c||0,bgsize:d||"16px"})},getIconStyle:function(a,b,c,d,g){var f;a&&(a=a.toLowerCase(),b&&(f=this.icons[a+"-rtl"]),f||(f=this.icons[a]));a=c||f&&f.path||"";d=d||f&&f.offset;g=g||f&&f.bgsize||"16px";a&&(a=a.replace(/'/g, +"\\'"));return a&&"background-image:url('"+CKEDITOR.getUrl(a)+"');background-position:0 "+d+"px;background-size:"+g+";"}};CKEDITOR.tools.extend(CKEDITOR.editor.prototype,{getUiColor:function(){return this.uiColor},setUiColor:function(a){var b=c(CKEDITOR.document);return(this.setUiColor=function(a){this.uiColor=a;var c=CKEDITOR.skin.chameleon,f="",m="";"function"==typeof c&&(f=c(this,"editor"),m=c(this,"panel"));a=[[h,a]];d([b],f,a);d(g,m,a)}).call(this,a)}});var k="cke_ui_color",g=[],h=/\$color/g; +CKEDITOR.on("instanceLoaded",function(a){if(!CKEDITOR.env.ie||!CKEDITOR.env.quirks){var b=a.editor;a=function(a){a=(a.data[0]||a.data).element.getElementsByTag("iframe").getItem(0).getFrameDocument();if(!a.getById("cke_ui_color")){var f=c(a);g.push(f);b.on("destroy",function(){g=CKEDITOR.tools.array.filter(g,function(a){return f!==a})});(a=b.getUiColor())&&d([f],CKEDITOR.skin.chameleon(b,"panel"),[[h,a]])}};b.on("panelShow",a);b.on("menuShow",a);b.config.uiColor&&b.setUiColor(b.config.uiColor)}})}(), +function(){if(CKEDITOR.env.webkit)CKEDITOR.env.hc=!1;else{var a=CKEDITOR.dom.element.createFromHtml('\x3cdiv style\x3d"width:0;height:0;position:absolute;left:-10000px;border:1px solid;border-color:red blue"\x3e\x3c/div\x3e',CKEDITOR.document);a.appendTo(CKEDITOR.document.getHead());try{var f=a.getComputedStyle("border-top-color"),b=a.getComputedStyle("border-right-color");CKEDITOR.env.hc=!(!f||f!=b)}catch(c){CKEDITOR.env.hc=!1}a.remove()}CKEDITOR.env.hc&&(CKEDITOR.env.cssClass+=" cke_hc");CKEDITOR.document.appendStyleText(".cke{visibility:hidden;}"); +CKEDITOR.status="loaded";CKEDITOR.fireOnce("loaded");if(a=CKEDITOR._.pending)for(delete CKEDITOR._.pending,f=0;ff;f++){var k=f,g;g=parseInt(d[f],16);g=("0"+(0>c?0|g*(1+c):0| +g+(255-g)*c).toString(16)).slice(-2);d[k]=g}return"#"+d.join("")}}(),f={editor:new CKEDITOR.template("{id}.cke_chrome [border-color:{defaultBorder};] {id} .cke_top [ background-color:{defaultBackground};border-bottom-color:{defaultBorder};] {id} .cke_bottom [background-color:{defaultBackground};border-top-color:{defaultBorder};] {id} .cke_resizer [border-right-color:{ckeResizer}] {id} .cke_dialog_title [background-color:{defaultBackground};border-bottom-color:{defaultBorder};] {id} .cke_dialog_footer [background-color:{defaultBackground};outline-color:{defaultBorder};] {id} .cke_dialog_tab [background-color:{dialogTab};border-color:{defaultBorder};] {id} .cke_dialog_tab:hover [background-color:{lightBackground};] {id} .cke_dialog_contents [border-top-color:{defaultBorder};] {id} .cke_dialog_tab_selected, {id} .cke_dialog_tab_selected:hover [background:{dialogTabSelected};border-bottom-color:{dialogTabSelectedBorder};] {id} .cke_dialog_body [background:{dialogBody};border-color:{defaultBorder};] {id} a.cke_button_off:hover,{id} a.cke_button_off:focus,{id} a.cke_button_off:active [background-color:{darkBackground};border-color:{toolbarElementsBorder};] {id} .cke_button_on [background-color:{ckeButtonOn};border-color:{toolbarElementsBorder};] {id} .cke_toolbar_separator,{id} .cke_toolgroup a.cke_button:last-child:after,{id} .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after [background-color: {toolbarElementsBorder};border-color: {toolbarElementsBorder};] {id} a.cke_combo_button:hover,{id} a.cke_combo_button:focus,{id} .cke_combo_on a.cke_combo_button [border-color:{toolbarElementsBorder};background-color:{darkBackground};] {id} .cke_combo:after [border-color:{toolbarElementsBorder};] {id} .cke_path_item [color:{elementsPathColor};] {id} a.cke_path_item:hover,{id} a.cke_path_item:focus,{id} a.cke_path_item:active [background-color:{darkBackground};] {id}.cke_panel [border-color:{defaultBorder};] "), +panel:new CKEDITOR.template(".cke_panel_grouptitle [background-color:{lightBackground};border-color:{defaultBorder};] .cke_menubutton_icon [background-color:{menubuttonIcon};] .cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active [background-color:{menubuttonHover};] .cke_menubutton:hover .cke_menubutton_icon, .cke_menubutton:focus .cke_menubutton_icon, .cke_menubutton:active .cke_menubutton_icon [background-color:{menubuttonIconHover};] .cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon [background-color:{menubuttonIcon};] .cke_menuseparator [background-color:{menubuttonIcon};] a:hover.cke_colorbox, a:active.cke_colorbox [border-color:{defaultBorder};] a:hover.cke_colorauto, a:hover.cke_colormore, a:active.cke_colorauto, a:active.cke_colormore [background-color:{ckeColorauto};border-color:{defaultBorder};] ")}; +return function(b,c){var d=a(b.uiColor,.4),d={id:"."+b.id,defaultBorder:a(d,-.2),toolbarElementsBorder:a(d,-.25),defaultBackground:d,lightBackground:a(d,.8),darkBackground:a(d,-.15),ckeButtonOn:a(d,.4),ckeResizer:a(d,-.4),ckeColorauto:a(d,.8),dialogBody:a(d,.7),dialogTab:a(d,.65),dialogTabSelected:"#FFF",dialogTabSelectedBorder:"#FFF",elementsPathColor:a(d,-.6),menubuttonHover:a(d,.1),menubuttonIcon:a(d,.5),menubuttonIconHover:a(d,.3)};return f[c].output(d).replace(/\[/g,"{").replace(/\]/g,"}")}}(), +CKEDITOR.plugins.add("dialogui",{onLoad:function(){var a=function(a){this._||(this._={});this._["default"]=this._.initValue=a["default"]||"";this._.required=a.required||!1;for(var b=[this._],c=1;carguments.length)){var g=a.call(this,c);g.labelId=CKEDITOR.tools.getNextId()+ +"_label";this._.children=[];var f={role:c.role||"presentation"};c.includeLabel&&(f["aria-labelledby"]=g.labelId);CKEDITOR.ui.dialog.uiElement.call(this,b,c,e,"div",null,f,function(){var a=[],e=c.required?" cke_required":"";"horizontal"!=c.labelLayout?a.push('\x3clabel class\x3d"cke_dialog_ui_labeled_label'+e+'" ',' id\x3d"'+g.labelId+'"',g.inputId?' for\x3d"'+g.inputId+'"':"",(c.labelStyle?' style\x3d"'+c.labelStyle+'"':"")+"\x3e",c.label,"\x3c/label\x3e",'\x3cdiv class\x3d"cke_dialog_ui_labeled_content"', +c.controlStyle?' style\x3d"'+c.controlStyle+'"':"",' role\x3d"presentation"\x3e',d.call(this,b,c),"\x3c/div\x3e"):(e={type:"hbox",widths:c.widths,padding:0,children:[{type:"html",html:'\x3clabel class\x3d"cke_dialog_ui_labeled_label'+e+'" id\x3d"'+g.labelId+'" for\x3d"'+g.inputId+'"'+(c.labelStyle?' style\x3d"'+c.labelStyle+'"':"")+"\x3e"+CKEDITOR.tools.htmlEncode(c.label)+"\x3c/label\x3e"},{type:"html",html:'\x3cspan class\x3d"cke_dialog_ui_labeled_content"'+(c.controlStyle?' style\x3d"'+c.controlStyle+ +'"':"")+"\x3e"+d.call(this,b,c)+"\x3c/span\x3e"}]},CKEDITOR.dialog._.uiElementBuilders.hbox.build(b,e,a));return a.join("")})}},textInput:function(b,c,e){if(!(3>arguments.length)){a.call(this,c);var d=this._.inputId=CKEDITOR.tools.getNextId()+"_textInput",f={"class":"cke_dialog_ui_input_"+c.type,id:d,type:c.type};c.validate&&(this.validate=c.validate);c.maxLength&&(f.maxlength=c.maxLength);c.size&&(f.size=c.size);c.inputStyle&&(f.style=c.inputStyle);var k=this,l=!1;b.on("load",function(){k.getInputElement().on("keydown", +function(a){13==a.data.getKeystroke()&&(l=!0)});k.getInputElement().on("keyup",function(a){13==a.data.getKeystroke()&&l&&(b.getButton("ok")&&setTimeout(function(){b.getButton("ok").click()},0),l=!1);k.bidi&&g.call(k,a)},null,null,1E3)});CKEDITOR.ui.dialog.labeledElement.call(this,b,c,e,function(){var a=['\x3cdiv class\x3d"cke_dialog_ui_input_',c.type,'" role\x3d"presentation"'];c.width&&a.push('style\x3d"width:'+c.width+'" ');a.push("\x3e\x3cinput ");f["aria-labelledby"]=this._.labelId;this._.required&& +(f["aria-required"]=this._.required);for(var b in f)a.push(b+'\x3d"'+f[b]+'" ');a.push(" /\x3e\x3c/div\x3e");return a.join("")})}},textarea:function(b,c,e){if(!(3>arguments.length)){a.call(this,c);var d=this,f=this._.inputId=CKEDITOR.tools.getNextId()+"_textarea",k={};c.validate&&(this.validate=c.validate);k.rows=c.rows||5;k.cols=c.cols||20;k["class"]="cke_dialog_ui_input_textarea "+(c["class"]||"");"undefined"!=typeof c.inputStyle&&(k.style=c.inputStyle);c.dir&&(k.dir=c.dir);if(d.bidi)b.on("load", +function(){d.getInputElement().on("keyup",g)},d);CKEDITOR.ui.dialog.labeledElement.call(this,b,c,e,function(){k["aria-labelledby"]=this._.labelId;this._.required&&(k["aria-required"]=this._.required);var a=['\x3cdiv class\x3d"cke_dialog_ui_input_textarea" role\x3d"presentation"\x3e\x3ctextarea id\x3d"',f,'" '],b;for(b in k)a.push(b+'\x3d"'+CKEDITOR.tools.htmlEncode(k[b])+'" ');a.push("\x3e",CKEDITOR.tools.htmlEncode(d._["default"]),"\x3c/textarea\x3e\x3c/div\x3e");return a.join("")})}},checkbox:function(b, +c,e){if(!(3>arguments.length)){var d=a.call(this,c,{"default":!!c["default"]});c.validate&&(this.validate=c.validate);CKEDITOR.ui.dialog.uiElement.call(this,b,c,e,"span",null,null,function(){var a=CKEDITOR.tools.extend({},c,{id:c.id?c.id+"_checkbox":CKEDITOR.tools.getNextId()+"_checkbox"},!0),e=[],g=CKEDITOR.tools.getNextId()+"_label",f={"class":"cke_dialog_ui_checkbox_input",type:"checkbox","aria-labelledby":g};k(a);c["default"]&&(f.checked="checked");"undefined"!=typeof a.inputStyle&&(a.style=a.inputStyle); +d.checkbox=new CKEDITOR.ui.dialog.uiElement(b,a,e,"input",null,f);e.push(' \x3clabel id\x3d"',g,'" for\x3d"',f.id,'"'+(c.labelStyle?' style\x3d"'+c.labelStyle+'"':"")+"\x3e",CKEDITOR.tools.htmlEncode(c.label),"\x3c/label\x3e");return e.join("")})}},radio:function(b,c,e){if(!(3>arguments.length)){a.call(this,c);this._["default"]||(this._["default"]=this._.initValue=c.items[0][1]);c.validate&&(this.validate=c.validate);var d=[],g=this;c.role="radiogroup";c.includeLabel=!0;CKEDITOR.ui.dialog.labeledElement.call(this, +b,c,e,function(){for(var a=[],e=[],f=(c.id?c.id:CKEDITOR.tools.getNextId())+"_radio",l=0;larguments.length)){var d=a.call(this,c);c.validate&&(this.validate=c.validate);d.inputId=CKEDITOR.tools.getNextId()+"_select";CKEDITOR.ui.dialog.labeledElement.call(this,b,c,e,function(){var a=CKEDITOR.tools.extend({},c,{id:c.id?c.id+"_select":CKEDITOR.tools.getNextId()+"_select"},!0),e=[],g=[],f={id:d.inputId,"class":"cke_dialog_ui_input_select","aria-labelledby":this._.labelId};e.push('\x3cdiv class\x3d"cke_dialog_ui_input_', +c.type,'" role\x3d"presentation"');c.width&&e.push('style\x3d"width:'+c.width+'" ');e.push("\x3e");void 0!==c.size&&(f.size=c.size);void 0!==c.multiple&&(f.multiple=c.multiple);k(a);for(var l=0,w;larguments.length)){void 0===c["default"]&&(c["default"]="");var d=CKEDITOR.tools.extend(a.call(this,c),{definition:c,buttons:[]});c.validate&&(this.validate=c.validate);b.on("load",function(){CKEDITOR.document.getById(d.frameId).getParent().addClass("cke_dialog_ui_input_file")});CKEDITOR.ui.dialog.labeledElement.call(this,b,c,e,function(){d.frameId=CKEDITOR.tools.getNextId()+"_fileInput";var a=['\x3ciframe frameborder\x3d"0" allowtransparency\x3d"0" class\x3d"cke_dialog_ui_input_file" role\x3d"presentation" id\x3d"', +d.frameId,'" title\x3d"',c.label,'" src\x3d"javascript:void('];a.push(CKEDITOR.env.ie?"(function(){"+encodeURIComponent("document.open();("+CKEDITOR.tools.fixDomain+")();document.close();")+"})()":"0");a.push(')"\x3e\x3c/iframe\x3e');return a.join("")})}},fileButton:function(b,c,e){var d=this;if(!(3>arguments.length)){a.call(this,c);c.validate&&(this.validate=c.validate);var g=CKEDITOR.tools.extend({},c),f=g.onClick;g.className=(g.className?g.className+" ":"")+"cke_dialog_ui_button";g.onClick=function(a){var e= +c["for"];a=f?f.call(this,a):!1;!1!==a&&("xhr"!==a&&b.getContentElement(e[0],e[1]).submit(),this.disable())};b.on("load",function(){b.getContentElement(c["for"][0],c["for"][1])._.buttons.push(d)});CKEDITOR.ui.dialog.button.call(this,b,g,e)}},html:function(){var a=/^\s*<[\w:]+\s+([^>]*)?>/,b=/^(\s*<[\w:]+(?:\s+[^>]*)?)((?:.|\r|\n)+)$/,c=/\/$/;return function(d,g,f){if(!(3>arguments.length)){var k=[],l=g.html;"\x3c"!=l.charAt(0)&&(l="\x3cspan\x3e"+l+"\x3c/span\x3e");var v=g.focus;if(v){var w=this.focus; +this.focus=function(){("function"==typeof v?v:w).call(this);this.fire("focus")};g.isFocusable&&(this.isFocusable=this.isFocusable);this.keyboardFocusable=!0}CKEDITOR.ui.dialog.uiElement.call(this,d,g,k,"span",null,null,"");k=k.join("").match(a);l=l.match(b)||["","",""];c.test(l[1])&&(l[1]=l[1].slice(0,-1),l[2]="/"+l[2]);f.push([l[1]," ",k[1]||"",l[2]].join(""))}}}(),fieldset:function(a,b,c,d,g){var f=g.label;this._={children:b};CKEDITOR.ui.dialog.uiElement.call(this,a,g,d,"fieldset",null,null,function(){var a= +[];f&&a.push("\x3clegend"+(g.labelStyle?' style\x3d"'+g.labelStyle+'"':"")+"\x3e"+f+"\x3c/legend\x3e");for(var b=0;bb.getChildCount()?(new CKEDITOR.dom.text(a,CKEDITOR.document)).appendTo(b):b.getChild(0).$.nodeValue= +a;return this},getLabel:function(){var a=CKEDITOR.document.getById(this._.labelId);return!a||1>a.getChildCount()?"":a.getChild(0).getText()},eventProcessors:d},!0);CKEDITOR.ui.dialog.button.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.uiElement,{click:function(){return this._.disabled?!1:this.fire("click",{dialog:this._.dialog})},enable:function(){this._.disabled=!1;var a=this.getElement();a&&a.removeClass("cke_disabled")},disable:function(){this._.disabled=!0;this.getElement().addClass("cke_disabled")}, +isVisible:function(){return this.getElement().getFirst().isVisible()},isEnabled:function(){return!this._.disabled},eventProcessors:CKEDITOR.tools.extend({},CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors,{onClick:function(a,b){this.on("click",function(){b.apply(this,arguments)})}},!0),accessKeyUp:function(){this.click()},accessKeyDown:function(){this.focus()},keyboardFocusable:!0},!0);CKEDITOR.ui.dialog.textInput.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.labeledElement,{getInputElement:function(){return CKEDITOR.document.getById(this._.inputId)}, +focus:function(){var a=this.selectParentTab();setTimeout(function(){var b=a.getInputElement();b&&b.$.focus()},0)},select:function(){var a=this.selectParentTab();setTimeout(function(){var b=a.getInputElement();b&&(b.$.focus(),b.$.select())},0)},accessKeyUp:function(){this.select()},setValue:function(a){if(this.bidi){var b=a&&a.charAt(0);(b="‪"==b?"ltr":"‫"==b?"rtl":null)&&(a=a.slice(1));this.setDirectionMarker(b)}a||(a="");return CKEDITOR.ui.dialog.uiElement.prototype.setValue.apply(this,arguments)}, +getValue:function(){var a=CKEDITOR.ui.dialog.uiElement.prototype.getValue.call(this);if(this.bidi&&a){var b=this.getDirectionMarker();b&&(a=("ltr"==b?"‪":"‫")+a)}return a},setDirectionMarker:function(a){var b=this.getInputElement();a?b.setAttributes({dir:a,"data-cke-dir-marker":a}):this.getDirectionMarker()&&b.removeAttributes(["dir","data-cke-dir-marker"])},getDirectionMarker:function(){return this.getInputElement().data("cke-dir-marker")},keyboardFocusable:!0},c,!0);CKEDITOR.ui.dialog.textarea.prototype= +new CKEDITOR.ui.dialog.textInput;CKEDITOR.ui.dialog.select.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.labeledElement,{getInputElement:function(){return this._.select.getElement()},add:function(a,b,c){var d=new CKEDITOR.dom.element("option",this.getDialog().getParentEditor().document),g=this.getInputElement().$;d.$.text=a;d.$.value=void 0===b||null===b?a:b;void 0===c||null===c?CKEDITOR.env.ie?g.add(d.$):g.add(d.$,null):g.add(d.$,c);return this},remove:function(a){this.getInputElement().$.remove(a); +return this},clear:function(){for(var a=this.getInputElement().$;0b-a;c--)if(this._.tabs[this._.tabIdList[c%a]][0].$.offsetHeight)return this._.tabIdList[c%a];return null}function f(){for(var a=this._.tabIdList.length,b=CKEDITOR.tools.indexOf(this._.tabIdList,this._.currentTabId),c=b+1;cl.width-k.width-f?l.width-k.width+("rtl"==g.lang.dir?0:h[1]):d.x,d.y+h[0]l.height-k.height-f?l.height-k.height+h[2]:d.y,1);c.data.preventDefault()} +function c(){CKEDITOR.document.removeListener("mousemove",b);CKEDITOR.document.removeListener("mouseup",c);if(CKEDITOR.env.ie6Compat){var a=B.getChild(0).getFrameDocument();a.removeListener("mousemove",b);a.removeListener("mouseup",c)}}var e=null,d=null,g=a.getParentEditor(),f=g.config.dialog_magnetDistance,h=CKEDITOR.skin.margins||[0,0,0,0];"undefined"==typeof f&&(f=20);a.parts.title.on("mousedown",function(g){e={x:g.data.$.screenX,y:g.data.$.screenY};CKEDITOR.document.on("mousemove",b);CKEDITOR.document.on("mouseup", +c);d=a.getPosition();if(CKEDITOR.env.ie6Compat){var f=B.getChild(0).getFrameDocument();f.on("mousemove",b);f.on("mouseup",c)}g.data.preventDefault()},a)}function e(a){function b(c){var n="rtl"==g.lang.dir,r=m.width,t=m.height,v=r+(c.data.$.screenX-l.x)*(n?-1:1)*(a._.moved?1:2),q=t+(c.data.$.screenY-l.y)*(a._.moved?1:2),w=a._.element.getFirst(),w=n&&w.getComputedStyle("right"),z=a.getPosition();z.y+q>k.height&&(q=k.height-z.y);(n?w:z.x)+v>k.width&&(v=k.width-(n?w:z.x));if(d==CKEDITOR.DIALOG_RESIZE_WIDTH|| +d==CKEDITOR.DIALOG_RESIZE_BOTH)r=Math.max(e.minWidth||0,v-f);if(d==CKEDITOR.DIALOG_RESIZE_HEIGHT||d==CKEDITOR.DIALOG_RESIZE_BOTH)t=Math.max(e.minHeight||0,q-h);a.resize(r,t);a._.moved||a.layout();c.data.preventDefault()}function c(){CKEDITOR.document.removeListener("mouseup",c);CKEDITOR.document.removeListener("mousemove",b);n&&(n.remove(),n=null);if(CKEDITOR.env.ie6Compat){var a=B.getChild(0).getFrameDocument();a.removeListener("mouseup",c);a.removeListener("mousemove",b)}}var e=a.definition,d=e.resizable; +if(d!=CKEDITOR.DIALOG_RESIZE_NONE){var g=a.getParentEditor(),f,h,k,l,m,n,r=CKEDITOR.tools.addFunction(function(e){m=a.getSize();var d=a.parts.contents;d.$.getElementsByTagName("iframe").length&&(n=CKEDITOR.dom.element.createFromHtml('\x3cdiv class\x3d"cke_dialog_resize_cover" style\x3d"height: 100%; position: absolute; width: 100%;"\x3e\x3c/div\x3e'),d.append(n));h=m.height-a.parts.contents.getSize("height",!(CKEDITOR.env.gecko||CKEDITOR.env.ie&&CKEDITOR.env.quirks));f=m.width-a.parts.contents.getSize("width", +1);l={x:e.screenX,y:e.screenY};k=CKEDITOR.document.getWindow().getViewPaneSize();CKEDITOR.document.on("mousemove",b);CKEDITOR.document.on("mouseup",c);CKEDITOR.env.ie6Compat&&(d=B.getChild(0).getFrameDocument(),d.on("mousemove",b),d.on("mouseup",c));e.preventDefault&&e.preventDefault()});a.on("load",function(){var b="";d==CKEDITOR.DIALOG_RESIZE_WIDTH?b=" cke_resizer_horizontal":d==CKEDITOR.DIALOG_RESIZE_HEIGHT&&(b=" cke_resizer_vertical");b=CKEDITOR.dom.element.createFromHtml('\x3cdiv class\x3d"cke_resizer'+ +b+" cke_resizer_"+g.lang.dir+'" title\x3d"'+CKEDITOR.tools.htmlEncode(g.lang.common.resize)+'" onmousedown\x3d"CKEDITOR.tools.callFunction('+r+', event )"\x3e'+("ltr"==g.lang.dir?"◢":"◣")+"\x3c/div\x3e");a.parts.footer.append(b,1)});g.on("destroy",function(){CKEDITOR.tools.removeFunction(r)})}}function n(a){a.data.preventDefault(1)}function q(a){var b=CKEDITOR.document.getWindow(),c=a.config,e=CKEDITOR.skinName||a.config.skin,d=c.dialog_backgroundCoverColor||("moono-lisa"==e?"black":"white"),e=c.dialog_backgroundCoverOpacity, +g=c.baseFloatZIndex,c=CKEDITOR.tools.genKey(d,e,g),f=A[c];f?f.show():(g=['\x3cdiv tabIndex\x3d"-1" style\x3d"position: ',CKEDITOR.env.ie6Compat?"absolute":"fixed","; z-index: ",g,"; top: 0px; left: 0px; ",CKEDITOR.env.ie6Compat?"":"background-color: "+d,'" class\x3d"cke_dialog_background_cover"\x3e'],CKEDITOR.env.ie6Compat&&(d="\x3chtml\x3e\x3cbody style\x3d\\'background-color:"+d+";\\'\x3e\x3c/body\x3e\x3c/html\x3e",g.push('\x3ciframe hidefocus\x3d"true" frameborder\x3d"0" id\x3d"cke_dialog_background_iframe" src\x3d"javascript:'), +g.push("void((function(){"+encodeURIComponent("document.open();("+CKEDITOR.tools.fixDomain+")();document.write( '"+d+"' );document.close();")+"})())"),g.push('" style\x3d"position:absolute;left:0;top:0;width:100%;height: 100%;filter: progid:DXImageTransform.Microsoft.Alpha(opacity\x3d0)"\x3e\x3c/iframe\x3e')),g.push("\x3c/div\x3e"),f=CKEDITOR.dom.element.createFromHtml(g.join("")),f.setOpacity(void 0!==e?e:.5),f.on("keydown",n),f.on("keypress",n),f.on("keyup",n),f.appendTo(CKEDITOR.document.getBody()), +A[c]=f);a.focusManager.add(f);B=f;a=function(){var a=b.getViewPaneSize();f.setStyles({width:a.width+"px",height:a.height+"px"})};var h=function(){var a=b.getScrollPosition(),c=CKEDITOR.dialog._.currentTop;f.setStyles({left:a.x+"px",top:a.y+"px"});if(c){do a=c.getPosition(),c.move(a.x,a.y);while(c=c._.parentDialog)}};x=a;b.on("resize",a);a();CKEDITOR.env.mac&&CKEDITOR.env.webkit||f.focus();if(CKEDITOR.env.ie6Compat){var k=function(){h();k.prevScrollHandler.apply(this,arguments)};b.$.setTimeout(function(){k.prevScrollHandler= +window.onscroll||function(){};window.onscroll=k},0);h()}}function y(a){B&&(a.focusManager.remove(B),a=CKEDITOR.document.getWindow(),B.hide(),B=null,a.removeListener("resize",x),CKEDITOR.env.ie6Compat&&a.$.setTimeout(function(){window.onscroll=window.onscroll&&window.onscroll.prevScrollHandler||null},0),x=null)}var u=CKEDITOR.tools.cssLength,p='\x3cdiv class\x3d"cke_reset_all {editorId} {editorDialogClass} {hidpi}" dir\x3d"{langDir}" lang\x3d"{langCode}" role\x3d"dialog" aria-labelledby\x3d"cke_dialog_title_{id}"\x3e\x3ctable class\x3d"cke_dialog '+ +CKEDITOR.env.cssClass+' cke_{langDir}" style\x3d"position:absolute" role\x3d"presentation"\x3e\x3ctr\x3e\x3ctd role\x3d"presentation"\x3e\x3cdiv class\x3d"cke_dialog_body" role\x3d"presentation"\x3e\x3cdiv id\x3d"cke_dialog_title_{id}" class\x3d"cke_dialog_title" role\x3d"presentation"\x3e\x3c/div\x3e\x3ca id\x3d"cke_dialog_close_button_{id}" class\x3d"cke_dialog_close_button" href\x3d"javascript:void(0)" title\x3d"{closeTitle}" role\x3d"button"\x3e\x3cspan class\x3d"cke_label"\x3eX\x3c/span\x3e\x3c/a\x3e\x3cdiv id\x3d"cke_dialog_tabs_{id}" class\x3d"cke_dialog_tabs" role\x3d"tablist"\x3e\x3c/div\x3e\x3ctable class\x3d"cke_dialog_contents" role\x3d"presentation"\x3e\x3ctr\x3e\x3ctd id\x3d"cke_dialog_contents_{id}" class\x3d"cke_dialog_contents_body" role\x3d"presentation"\x3e\x3c/td\x3e\x3c/tr\x3e\x3ctr\x3e\x3ctd id\x3d"cke_dialog_footer_{id}" class\x3d"cke_dialog_footer" role\x3d"presentation"\x3e\x3c/td\x3e\x3c/tr\x3e\x3c/table\x3e\x3c/div\x3e\x3c/td\x3e\x3c/tr\x3e\x3c/table\x3e\x3c/div\x3e'; +CKEDITOR.dialog=function(b,g){function h(){var a=x._.focusList;a.sort(function(a,b){return a.tabIndex!=b.tabIndex?b.tabIndex-a.tabIndex:a.focusIndex-b.focusIndex});for(var b=a.length,c=0;cb.length)){var c=x._.currentFocusIndex;x._.tabBarMode&&0>a&&(c=0);try{b[c].getInputElement().$.blur()}catch(e){}var d=c,g=1c.height||b.width+(0c.width?a.setStyle("position","absolute"):a.setStyle("position","fixed"));this.move(this._.moved?this._.position.x:e,this._.moved?this._.position.y:d)},foreach:function(a){for(var b in this._.contents)for(var c in this._.contents[b])a.call(this,this._.contents[b][c]);return this},reset:function(){var a=function(a){a.reset&&a.reset(1)};return function(){this.foreach(a);return this}}(), +setupContent:function(){var a=arguments;this.foreach(function(b){b.setup&&b.setup.apply(b,a)})},commitContent:function(){var a=arguments;this.foreach(function(b){CKEDITOR.env.ie&&this._.currentFocusIndex==b.focusIndex&&b.getInputElement().$.blur();b.commit&&b.commit.apply(b,a)})},hide:function(){if(this.parts.dialog.isVisible()){this.fire("hide",{});this._.editor.fire("dialogHide",this);this.selectPage(this._.tabIdList[0]);var a=this._.element;a.setStyle("display","none");this.parts.dialog.setStyle("visibility", +"hidden");for(J(this);CKEDITOR.dialog._.currentTop!=this;)CKEDITOR.dialog._.currentTop.hide();if(this._.parentDialog){var b=this._.parentDialog.getElement().getFirst();b.setStyle("z-index",parseInt(b.$.style.zIndex,10)+Math.floor(this._.editor.config.baseFloatZIndex/2))}else y(this._.editor);if(CKEDITOR.dialog._.currentTop=this._.parentDialog)CKEDITOR.dialog._.currentZIndex-=10;else{CKEDITOR.dialog._.currentZIndex=null;a.removeListener("keydown",H);a.removeListener("keyup",F);var c=this._.editor; +c.focus();setTimeout(function(){c.focusManager.unlock();CKEDITOR.env.iOS&&c.window.focus()},0)}delete this._.parentDialog;this.foreach(function(a){a.resetInitValue&&a.resetInitValue()});this.setState(CKEDITOR.DIALOG_STATE_IDLE)}},addPage:function(a){if(!a.requiredContent||this._.editor.filter.check(a.requiredContent)){for(var b=[],c=a.label?' title\x3d"'+CKEDITOR.tools.htmlEncode(a.label)+'"':"",e=CKEDITOR.dialog._.uiElementBuilders.vbox.build(this,{type:"vbox",className:"cke_dialog_page_contents", +children:a.elements,expand:!!a.expand,padding:a.padding,style:a.style||"width: 100%;"},b),d=this._.contents[a.id]={},g=e.getChild(),f=0;e=g.shift();)e.notAllowed||"hbox"==e.type||"vbox"==e.type||f++,d[e.id]=e,"function"==typeof e.getChild&&g.push.apply(g,e.getChild());f||(a.hidden=!0);b=CKEDITOR.dom.element.createFromHtml(b.join(""));b.setAttribute("role","tabpanel");e=CKEDITOR.env;d="cke_"+a.id+"_"+CKEDITOR.tools.getNextNumber();c=CKEDITOR.dom.element.createFromHtml(['\x3ca class\x3d"cke_dialog_tab"', +0arguments.length)){var h=(e.call?e(b):e)||"div",k=["\x3c",h," "],l=(d&&d.call?d(b):d)||{},m=(g&&g.call?g(b):g)||{},n=(f&&f.call?f.call(this,a,b):f)||"",r=this.domId=m.id||CKEDITOR.tools.getNextId()+"_uiElement";b.requiredContent&&!a.getParentEditor().filter.check(b.requiredContent)&&(l.display="none",this.notAllowed=!0);m.id=r;var q={};b.type&&(q["cke_dialog_ui_"+ +b.type]=1);b.className&&(q[b.className]=1);b.disabled&&(q.cke_disabled=1);for(var t=m["class"]&&m["class"].split?m["class"].split(" "):[],r=0;rCKEDITOR.env.version?"cke_dialog_ui_focused":"";b.on("focus",function(){a._.tabBarMode=!1;a._.hasFocus=!0;v.fire("focus"); +c&&this.addClass(c)});b.on("blur",function(){v.fire("blur");c&&this.removeClass(c)})}});CKEDITOR.tools.extend(this,b);this.keyboardFocusable&&(this.tabIndex=b.tabIndex||0,this.focusIndex=a._.focusList.push(this)-1,this.on("focus",function(){a._.currentFocusIndex=v.focusIndex}))}},hbox:function(a,b,c,e,d){if(!(4>arguments.length)){this._||(this._={});var g=this._.children=b,f=d&&d.widths||null,h=d&&d.height||null,k,l={role:"presentation"};d&&d.align&&(l.align=d.align);CKEDITOR.ui.dialog.uiElement.call(this, +a,d||{type:"hbox"},e,"table",{},l,function(){var a=['\x3ctbody\x3e\x3ctr class\x3d"cke_dialog_ui_hbox"\x3e'];for(k=0;karguments.length)){this._||(this._={});var g=this._.children=b,f=d&&d.width||null,h=d&&d.heights||null;CKEDITOR.ui.dialog.uiElement.call(this,a,d||{type:"vbox"},e,"div",null,{role:"presentation"},function(){var b=['\x3ctable role\x3d"presentation" cellspacing\x3d"0" border\x3d"0" ']; +b.push('style\x3d"');d&&d.expand&&b.push("height:100%;");b.push("width:"+u(f||"100%"),";");CKEDITOR.env.webkit&&b.push("float:none;");b.push('"');b.push('align\x3d"',CKEDITOR.tools.htmlEncode(d&&d.align||("ltr"==a.getParentEditor().lang.dir?"left":"right")),'" ');b.push("\x3e\x3ctbody\x3e");for(var e=0;earguments.length)return this._.children.concat();a.splice||(a=[a]);return 2>a.length?this._.children[a[0]]:this._.children[a[0]]&&this._.children[a[0]].getChild?this._.children[a[0]].getChild(a.slice(1,a.length)):null}},!0);CKEDITOR.ui.dialog.vbox.prototype=new CKEDITOR.ui.dialog.hbox;(function(){var a={build:function(a,b,c){for(var e=b.children,d,g=[],f=[],h=0;hk.length&&(b=a.document.createElement(a.config.enterMode==CKEDITOR.ENTER_P?"p":"div"),g=l.shift(),d.insertNode(b),b.append(new CKEDITOR.dom.text("",a.document)),d.moveToBookmark(g),d.selectNodeContents(b),d.collapse(!0),g=d.createBookmark(),k.push(b),l.unshift(g)); +h=k[0].getParent();d=[];for(g=0;gc||(this.notifications.splice(c,1),a.element.remove(), +this.element.getChildCount()||(this._removeListeners(),this.element.remove()))},_createElement:function(){var a=this.editor,c=a.config,d=new CKEDITOR.dom.element("div");d.addClass("cke_notifications_area");d.setAttribute("id","cke_notifications_area_"+a.name);d.setStyle("z-index",c.baseFloatZIndex-2);return d},_attachListeners:function(){var a=CKEDITOR.document.getWindow(),c=this.editor;a.on("scroll",this._uiBuffer.input);a.on("resize",this._uiBuffer.input);c.on("change",this._changeBuffer.input); +c.on("floatingSpaceLayout",this._layout,this,null,20);c.on("blur",this._layout,this,null,20)},_removeListeners:function(){var a=CKEDITOR.document.getWindow(),c=this.editor;a.removeListener("scroll",this._uiBuffer.input);a.removeListener("resize",this._uiBuffer.input);c.removeListener("change",this._changeBuffer.input);c.removeListener("floatingSpaceLayout",this._layout);c.removeListener("blur",this._layout)},_layout:function(){function a(){c.setStyle("left",w(r+f.width-n-q))}var c=this.element,d= +this.editor,f=d.ui.contentsElement.getClientRect(),k=d.ui.contentsElement.getDocumentPosition(),g,h,m=c.getClientRect(),e,n=this._notificationWidth,q=this._notificationMargin;e=CKEDITOR.document.getWindow();var y=e.getScrollPosition(),u=e.getViewPaneSize(),p=CKEDITOR.document.getBody(),v=p.getDocumentPosition(),w=CKEDITOR.tools.cssLength;n&&q||(e=this.element.getChild(0),n=this._notificationWidth=e.getClientRect().width,q=this._notificationMargin=parseInt(e.getComputedStyle("margin-left"),10)+parseInt(e.getComputedStyle("margin-right"), +10));d.toolbar&&(g=d.ui.space("top"),h=g.getClientRect());g&&g.isVisible()&&h.bottom>f.top&&h.bottomy.y?c.setStyles({position:"fixed",top:0}):c.setStyles({position:"absolute",top:w(k.y+f.height-m.height)});var r="fixed"==c.getStyle("position")?f.left:"static"!=p.getComputedStyle("position")?k.x-v.x:k.x;f.widthy.x+u.width?a():c.setStyle("left", +w(r)):k.x+n+q>y.x+u.width?c.setStyle("left",w(r)):k.x+f.width/2+n/2+q>y.x+u.width?c.setStyle("left",w(r-k.x+y.x+u.width-n-q)):0>f.left+f.width-n-q?a():0>f.left+f.width/2-n/2?c.setStyle("left",w(r-k.x+y.x)):c.setStyle("left",w(r+f.width/2-n/2-q/2))}};CKEDITOR.plugins.notification=a}(),function(){var a='\x3ca id\x3d"{id}" class\x3d"cke_button cke_button__{name} cke_button_{state} {cls}"'+(CKEDITOR.env.gecko&&!CKEDITOR.env.hc?"":" href\x3d\"javascript:void('{titleJs}')\"")+' title\x3d"{title}" tabindex\x3d"-1" hidefocus\x3d"true" role\x3d"button" aria-labelledby\x3d"{id}_label" aria-describedby\x3d"{id}_description" aria-haspopup\x3d"{hasArrow}" aria-disabled\x3d"{ariaDisabled}"'; +CKEDITOR.env.gecko&&CKEDITOR.env.mac&&(a+=' onkeypress\x3d"return false;"');CKEDITOR.env.gecko&&(a+=' onblur\x3d"this.style.cssText \x3d this.style.cssText;"');var f="";CKEDITOR.env.ie&&(f='return false;" onmouseup\x3d"CKEDITOR.tools.getMouseButton(event)\x3d\x3dCKEDITOR.MOUSE_BUTTON_LEFT\x26\x26');var a=a+(' onkeydown\x3d"return CKEDITOR.tools.callFunction({keydownFn},event);" onfocus\x3d"return CKEDITOR.tools.callFunction({focusFn},event);" onclick\x3d"'+f+'CKEDITOR.tools.callFunction({clickFn},this);return false;"\x3e\x3cspan class\x3d"cke_button_icon cke_button__{iconName}_icon" style\x3d"{style}"')+ +'\x3e\x26nbsp;\x3c/span\x3e\x3cspan id\x3d"{id}_label" class\x3d"cke_button_label cke_button__{name}_label" aria-hidden\x3d"false"\x3e{label}\x3c/span\x3e\x3cspan id\x3d"{id}_description" class\x3d"cke_button_label" aria-hidden\x3d"false"\x3e{ariaShortcut}\x3c/span\x3e{arrowHtml}\x3c/a\x3e',b=CKEDITOR.addTemplate("buttonArrow",'\x3cspan class\x3d"cke_button_arrow"\x3e'+(CKEDITOR.env.hc?"\x26#9660;":"")+"\x3c/span\x3e"),c=CKEDITOR.addTemplate("button",a);CKEDITOR.plugins.add("button",{beforeInit:function(a){a.ui.addHandler(CKEDITOR.UI_BUTTON, +CKEDITOR.ui.button.handler)}});CKEDITOR.UI_BUTTON="button";CKEDITOR.ui.button=function(a){CKEDITOR.tools.extend(this,a,{title:a.label,click:a.click||function(b){b.execCommand(a.command)}});this._={}};CKEDITOR.ui.button.handler={create:function(a){return new CKEDITOR.ui.button(a)}};CKEDITOR.ui.button.prototype={render:function(a,f){function k(){var b=a.mode;b&&(b=this.modes[b]?void 0!==g[b]?g[b]:CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,b=a.readOnly&&!this.readOnly?CKEDITOR.TRISTATE_DISABLED: +b,this.setState(b),this.refresh&&this.refresh())}var g=null,h=CKEDITOR.env,m=this._.id=CKEDITOR.tools.getNextId(),e="",n=this.command,q,y,u;this._.editor=a;var p={id:m,button:this,editor:a,focus:function(){CKEDITOR.document.getById(m).focus()},execute:function(){this.button.click(a)},attach:function(a){this.button.attach(a)}},v=CKEDITOR.tools.addFunction(function(a){if(p.onkey)return a=new CKEDITOR.dom.event(a),!1!==p.onkey(p,a.getKeystroke())}),w=CKEDITOR.tools.addFunction(function(a){var b;p.onfocus&& +(b=!1!==p.onfocus(p,new CKEDITOR.dom.event(a)));return b}),r=0;p.clickFn=q=CKEDITOR.tools.addFunction(function(){r&&(a.unlockSelection(1),r=0);p.execute();h.iOS&&a.focus()});this.modes?(g={},a.on("beforeModeUnload",function(){a.mode&&this._.state!=CKEDITOR.TRISTATE_DISABLED&&(g[a.mode]=this._.state)},this),a.on("activeFilterChange",k,this),a.on("mode",k,this),!this.readOnly&&a.on("readOnly",k,this)):n&&(n=a.getCommand(n))&&(n.on("state",function(){this.setState(n.state)},this),e+=n.state==CKEDITOR.TRISTATE_ON? +"on":n.state==CKEDITOR.TRISTATE_DISABLED?"disabled":"off");var z;if(this.directional)a.on("contentDirChanged",function(b){var c=CKEDITOR.document.getById(this._.id),e=c.getFirst();b=b.data;b!=a.lang.dir?c.addClass("cke_"+b):c.removeClass("cke_ltr").removeClass("cke_rtl");e.setAttribute("style",CKEDITOR.skin.getIconStyle(z,"rtl"==b,this.icon,this.iconOffset))},this);n?(y=a.getCommandKeystroke(n))&&(u=CKEDITOR.tools.keystrokeToString(a.lang.common.keyboard,y)):e+="off";y=this.name||this.command;var t= +null,x=this.icon;z=y;this.icon&&!/\./.test(this.icon)?(z=this.icon,x=null):(this.icon&&(t=this.icon),CKEDITOR.env.hidpi&&this.iconHiDpi&&(t=this.iconHiDpi));t?(CKEDITOR.skin.addIcon(t,t),x=null):t=z;e={id:m,name:y,iconName:z,label:this.label,cls:(this.hasArrow?"cke_button_expandable ":"")+(this.className||""),state:e,ariaDisabled:"disabled"==e?"true":"false",title:this.title+(u?" ("+u.display+")":""),ariaShortcut:u?a.lang.common.keyboardShortcut+" "+u.aria:"",titleJs:h.gecko&&!h.hc?"":(this.title|| +"").replace("'",""),hasArrow:"string"===typeof this.hasArrow&&this.hasArrow||(this.hasArrow?"true":"false"),keydownFn:v,focusFn:w,clickFn:q,style:CKEDITOR.skin.getIconStyle(t,"rtl"==a.lang.dir,x,this.iconOffset),arrowHtml:this.hasArrow?b.output():""};c.output(e,f);if(this.onRender)this.onRender();return p},setState:function(a){if(this._.state==a)return!1;this._.state=a;var b=CKEDITOR.document.getById(this._.id);return b?(b.setState(a,"cke_button"),b.setAttribute("aria-disabled",a==CKEDITOR.TRISTATE_DISABLED), +this.hasArrow?b.setAttribute("aria-expanded",a==CKEDITOR.TRISTATE_ON):a===CKEDITOR.TRISTATE_ON?b.setAttribute("aria-pressed",!0):b.removeAttribute("aria-pressed"),!0):!1},getState:function(){return this._.state},toFeature:function(a){if(this._.feature)return this._.feature;var b=this;this.allowedContent||this.requiredContent||!this.command||(b=a.getCommand(this.command)||b);return this._.feature=b}};CKEDITOR.ui.prototype.addButton=function(a,b){this.add(a,CKEDITOR.UI_BUTTON,b)}}(),function(){function a(a){function b(){for(var e= +c(),h=CKEDITOR.tools.clone(a.config.toolbarGroups)||f(a),m=0;mb.order?-1:0>a.order? +1:a.order]+data-cke-bookmark[^<]*?<\/span>/ig,"");g&&a(b,d)})}function A(){if("wysiwyg"==b.mode){var a=B("paste");b.getCommand("cut").setState(B("cut"));b.getCommand("copy").setState(B("copy"));b.getCommand("paste").setState(a);b.fire("pasteState",a)}}function B(a){var c= +b.getSelection(),c=c&&c.getRanges()[0];if((b.readOnly||c&&c.checkReadOnly())&&a in{paste:1,cut:1})return CKEDITOR.TRISTATE_DISABLED;if("paste"==a)return CKEDITOR.TRISTATE_OFF;a=b.getSelection();c=a.getRanges();return a.getType()==CKEDITOR.SELECTION_NONE||1==c.length&&c[0].collapsed?CKEDITOR.TRISTATE_DISABLED:CKEDITOR.TRISTATE_OFF}var C=CKEDITOR.plugins.clipboard,H=0,F=0;(function(){b.on("key",t);b.on("contentDom",c);b.on("selectionChange",A);if(b.contextMenu){b.contextMenu.addListener(function(){return{cut:B("cut"), +copy:B("copy"),paste:B("paste")}});var a=null;b.on("menuShow",function(){a&&(a.removeListener(),a=null);var c=b.contextMenu.findItemByCommandName("paste");c&&c.element&&(a=c.element.on("touchend",function(){b._.forcePasteDialog=!0}))})}if(b.ui.addButton)b.once("instanceReady",function(){b._.pasteButtons&&CKEDITOR.tools.array.forEach(b._.pasteButtons,function(a){if(a=b.ui.get(a))if(a=CKEDITOR.document.getById(a._.id))a.on("touchend",function(){b._.forcePasteDialog=!0})})})})();(function(){function a(c, +d,g,f,h){var k=b.lang.clipboard[d];b.addCommand(d,g);b.ui.addButton&&b.ui.addButton(c,{label:k,command:d,toolbar:"clipboard,"+f});b.addMenuItems&&b.addMenuItem(d,{label:k,command:d,group:"clipboard",order:h})}a("Cut","cut",d("cut"),10,1);a("Copy","copy",d("copy"),20,4);a("Paste","paste",g(),30,8);b._.pasteButtons||(b._.pasteButtons=[]);b._.pasteButtons.push("Paste")})();b.getClipboardData=function(a,c){function d(a){a.removeListener();a.cancel();c(a.data)}function g(a){a.removeListener();a.cancel(); +c({type:h,dataValue:a.data.dataValue,dataTransfer:a.data.dataTransfer,method:"paste"})}var f=!1,h="auto";c||(c=a,a=null);b.on("beforePaste",function(a){a.removeListener();f=!0;h=a.data.type},null,null,1E3);b.on("paste",d,null,null,0);!1===z()&&(b.removeListener("paste",d),b._.forcePasteDialog&&f&&b.fire("pasteDialog")?(b.on("pasteDialogCommit",g),b.on("dialogHide",function(a){a.removeListener();a.data.removeListener("pasteDialogCommit",g);a.data._.committed||c(null)})):c(null))}}function b(a){if(CKEDITOR.env.webkit){if(!a.match(/^[^<]*$/g)&& +!a.match(/^(
<\/div>|
[^<]*<\/div>)*$/gi))return"html"}else if(CKEDITOR.env.ie){if(!a.match(/^([^<]|)*$/gi)&&!a.match(/^(

([^<]|)*<\/p>|(\r\n))*$/gi))return"html"}else if(CKEDITOR.env.gecko){if(!a.match(/^([^<]|)*$/gi))return"html"}else return"html";return"htmlifiedtext"}function c(a,b){function c(a){return CKEDITOR.tools.repeat("\x3c/p\x3e\x3cp\x3e",~~(a/2))+(1==a%2?"\x3cbr\x3e":"")}b=b.replace(/(?!\u3000)\s+/g," ").replace(/> +/gi, +"\x3cbr\x3e");b=b.replace(/<\/?[A-Z]+>/g,function(a){return a.toLowerCase()});if(b.match(/^[^<]$/))return b;CKEDITOR.env.webkit&&-1(
|)<\/div>)(?!$|(

(
|)<\/div>))/g,"\x3cbr\x3e").replace(/^(
(
|)<\/div>){2}(?!$)/g,"\x3cdiv\x3e\x3c/div\x3e"),b.match(/
(
|)<\/div>/)&&(b="\x3cp\x3e"+b.replace(/(
(
|)<\/div>)+/g,function(a){return c(a.split("\x3c/div\x3e\x3cdiv\x3e").length+1)})+"\x3c/p\x3e"),b=b.replace(/<\/div>
/g,"\x3cbr\x3e"), +b=b.replace(/<\/?div>/g,""));CKEDITOR.env.gecko&&a.enterMode!=CKEDITOR.ENTER_BR&&(CKEDITOR.env.gecko&&(b=b.replace(/^

$/,"\x3cbr\x3e")),-1){2,}/g,function(a){return c(a.length/4)})+"\x3c/p\x3e"));return k(a,b)}function d(a){function b(){var a={},c;for(c in CKEDITOR.dtd)"$"!=c.charAt(0)&&"div"!=c&&"span"!=c&&(a[c]=1);return a}var c={};return{get:function(d){return"plain-text"==d?c.plainText||(c.plainText=new CKEDITOR.filter(a, +"br")):"semantic-content"==d?((d=c.semanticContent)||(d=new CKEDITOR.filter(a,{}),d.allow({$1:{elements:b(),attributes:!0,styles:!1,classes:!1}}),d=c.semanticContent=d),d):d?new CKEDITOR.filter(a,d):null}}}function l(a,b,c){b=CKEDITOR.htmlParser.fragment.fromHtml(b);var d=new CKEDITOR.htmlParser.basicWriter;c.applyTo(b,!0,!1,a.activeEnterMode);b.writeHtml(d);return d.getHtml()}function k(a,b){a.enterMode==CKEDITOR.ENTER_BR?b=b.replace(/(<\/p>

)+/g,function(a){return CKEDITOR.tools.repeat("\x3cbr\x3e", +a.length/7*2)}).replace(/<\/?p>/g,""):a.enterMode==CKEDITOR.ENTER_DIV&&(b=b.replace(/<(\/)?p>/g,"\x3c$1div\x3e"));return b}function g(a){a.data.preventDefault();a.data.$.dataTransfer.dropEffect="none"}function h(b){var c=CKEDITOR.plugins.clipboard;b.on("contentDom",function(){function d(c,g,f){g.select();a(b,{dataTransfer:f,method:"drop"},1);f.sourceEditor.fire("saveSnapshot");f.sourceEditor.editable().extractHtmlFromRange(c);f.sourceEditor.getSelection().selectRanges([c]);f.sourceEditor.fire("saveSnapshot")} +function g(d,f){d.select();a(b,{dataTransfer:f,method:"drop"},1);c.resetDragDataTransfer()}function f(a,c,d){var g={$:a.data.$,target:a.data.getTarget()};c&&(g.dragRange=c);d&&(g.dropRange=d);!1===b.fire(a.name,g)&&a.data.preventDefault()}function h(a){a.type!=CKEDITOR.NODE_ELEMENT&&(a=a.getParent());return a.getChildCount()}var k=b.editable(),l=CKEDITOR.plugins.clipboard.getDropTarget(b),m=b.ui.space("top"),z=b.ui.space("bottom");c.preventDefaultDropOnElement(m);c.preventDefaultDropOnElement(z); +k.attachListener(l,"dragstart",f);k.attachListener(b,"dragstart",c.resetDragDataTransfer,c,null,1);k.attachListener(b,"dragstart",function(a){c.initDragDataTransfer(a,b)},null,null,2);k.attachListener(b,"dragstart",function(){var a=c.dragRange=b.getSelection().getRanges()[0];CKEDITOR.env.ie&&10>CKEDITOR.env.version&&(c.dragStartContainerChildCount=a?h(a.startContainer):null,c.dragEndContainerChildCount=a?h(a.endContainer):null)},null,null,100);k.attachListener(l,"dragend",f);k.attachListener(b,"dragend", +c.initDragDataTransfer,c,null,1);k.attachListener(b,"dragend",c.resetDragDataTransfer,c,null,100);k.attachListener(l,"dragover",function(a){if(CKEDITOR.env.edge)a.data.preventDefault();else{var b=a.data.getTarget();b&&b.is&&b.is("html")?a.data.preventDefault():CKEDITOR.env.ie&&CKEDITOR.plugins.clipboard.isFileApiSupported&&a.data.$.dataTransfer.types.contains("Files")&&a.data.preventDefault()}});k.attachListener(l,"drop",function(a){if(!a.data.$.defaultPrevented){a.data.preventDefault();var d=a.data.getTarget(); +if(!d.isReadOnly()||d.type==CKEDITOR.NODE_ELEMENT&&d.is("html")){var d=c.getRangeAtDropPosition(a,b),g=c.dragRange;d&&f(a,g,d)}}},null,null,9999);k.attachListener(b,"drop",c.initDragDataTransfer,c,null,1);k.attachListener(b,"drop",function(a){if(a=a.data){var f=a.dropRange,h=a.dragRange,k=a.dataTransfer;k.getTransferType(b)==CKEDITOR.DATA_TRANSFER_INTERNAL?setTimeout(function(){c.internalDrop(h,f,k,b)},0):k.getTransferType(b)==CKEDITOR.DATA_TRANSFER_CROSS_EDITORS?d(h,f,k):g(f,k)}},null,null,9999)})} +var m;CKEDITOR.plugins.add("clipboard",{requires:"dialog,notification,toolbar",init:function(a){var g,k=d(a);a.config.forcePasteAsPlainText?g="plain-text":a.config.pasteFilter?g=a.config.pasteFilter:!CKEDITOR.env.webkit||"pasteFilter"in a.config||(g="semantic-content");a.pasteFilter=k.get(g);f(a);h(a);CKEDITOR.dialog.add("paste",CKEDITOR.getUrl(this.path+"dialogs/paste.js"));if(CKEDITOR.env.gecko){var m=["image/png","image/jpeg","image/gif"],u;a.on("paste",function(b){var c=b.data,d=c.dataTransfer; +if(!c.dataValue&&"paste"==c.method&&d&&1==d.getFilesCount()&&u!=d.id&&(d=d.getFile(0),-1!=CKEDITOR.tools.indexOf(m,d.type))){var g=new FileReader;g.addEventListener("load",function(){b.data.dataValue='\x3cimg src\x3d"'+g.result+'" /\x3e';a.fire("paste",b.data)},!1);g.addEventListener("abort",function(){a.fire("paste",b.data)},!1);g.addEventListener("error",function(){a.fire("paste",b.data)},!1);g.readAsDataURL(d);u=c.dataTransfer.id;b.stop()}},null,null,1)}a.on("paste",function(b){b.data.dataTransfer|| +(b.data.dataTransfer=new CKEDITOR.plugins.clipboard.dataTransfer);if(!b.data.dataValue){var c=b.data.dataTransfer,d=c.getData("text/html");if(d)b.data.dataValue=d,b.data.type="html";else if(d=c.getData("text/plain"))b.data.dataValue=a.editable().transformPlainTextToHtml(d),b.data.type="text"}},null,null,1);a.on("paste",function(a){var b=a.data.dataValue,c=CKEDITOR.dtd.$block;-1 <\/span>/gi," "),"html"!=a.data.type&&(b=b.replace(/]*>([^<]*)<\/span>/gi, +function(a,b){return b.replace(/\t/g,"\x26nbsp;\x26nbsp; \x26nbsp;")})),-1/,"")),b=b.replace(/(<[^>]+) class="Apple-[^"]*"/gi,"$1"));if(b.match(/^<[^<]+cke_(editable|contents)/i)){var d,e,g=new CKEDITOR.dom.element("div");for(g.setHtml(b);1==g.getChildCount()&&(d=g.getFirst())&&d.type==CKEDITOR.NODE_ELEMENT&&(d.hasClass("cke_editable")|| +d.hasClass("cke_contents"));)g=e=d;e&&(b=e.getHtml().replace(/
$/i,""))}CKEDITOR.env.ie?b=b.replace(/^ (?: |\r\n)?<(\w+)/g,function(b,d){return d.toLowerCase()in c?(a.data.preSniffing="html","\x3c"+d):b}):CKEDITOR.env.webkit?b=b.replace(/<\/(\w+)>


<\/div>$/,function(b,d){return d in c?(a.data.endsWithEOL=1,"\x3c/"+d+"\x3e"):b}):CKEDITOR.env.gecko&&(b=b.replace(/(\s)
$/,"$1"));a.data.dataValue=b},null,null,3);a.on("paste",function(d){d=d.data;var g=a._.nextPasteType||d.type,f=d.dataValue, +h,m=a.config.clipboard_defaultContentType||"html",n=d.dataTransfer.getTransferType(a)==CKEDITOR.DATA_TRANSFER_EXTERNAL,u=!0===a.config.forcePasteAsPlainText;h="html"==g||"html"==d.preSniffing?"html":b(f);delete a._.nextPasteType;"htmlifiedtext"==h&&(f=c(a.config,f));if("text"==g&&"html"==h)f=l(a,f,k.get("plain-text"));else if(n&&a.pasteFilter&&!d.dontFilter||u)f=l(a,f,a.pasteFilter);d.startsWithEOL&&(f='\x3cbr data-cke-eol\x3d"1"\x3e'+f);d.endsWithEOL&&(f+='\x3cbr data-cke-eol\x3d"1"\x3e');"auto"== +g&&(g="html"==h||"html"==m?"html":"text");d.type=g;d.dataValue=f;delete d.preSniffing;delete d.startsWithEOL;delete d.endsWithEOL},null,null,6);a.on("paste",function(b){b=b.data;b.dataValue&&(a.insertHtml(b.dataValue,b.type,b.range),setTimeout(function(){a.fire("afterPaste")},0))},null,null,1E3);a.on("pasteDialog",function(b){setTimeout(function(){a.openDialog("paste",b.data)},0)})}});CKEDITOR.plugins.clipboard={isCustomCopyCutSupported:(!CKEDITOR.env.ie||16<=CKEDITOR.env.version)&&!CKEDITOR.env.iOS, +isCustomDataTypesSupported:!CKEDITOR.env.ie||16<=CKEDITOR.env.version,isFileApiSupported:!CKEDITOR.env.ie||9CKEDITOR.env.version||b.isInline()?b:a.document},fixSplitNodesAfterDrop:function(a,b,c,d){function g(a,c,d){var e=a;e.type==CKEDITOR.NODE_TEXT&&(e=a.getParent());if(e.equals(c)&&d!=c.getChildCount())return a=b.startContainer.getChild(b.startOffset-1),c=b.startContainer.getChild(b.startOffset), +a&&a.type==CKEDITOR.NODE_TEXT&&c&&c.type==CKEDITOR.NODE_TEXT&&(d=a.getLength(),a.setText(a.getText()+c.getText()),c.remove(),b.setStart(a,d),b.collapse(!0)),!0}var f=b.startContainer;"number"==typeof d&&"number"==typeof c&&f.type==CKEDITOR.NODE_ELEMENT&&(g(a.startContainer,f,c)||g(a.endContainer,f,d))},isDropRangeAffectedByDragRange:function(a,b){var c=b.startContainer,d=b.endOffset;return a.endContainer.equals(c)&&a.endOffset<=d||a.startContainer.getParent().equals(c)&&a.startContainer.getIndex()< +d||a.endContainer.getParent().equals(c)&&a.endContainer.getIndex()CKEDITOR.env.version&&this.fixSplitNodesAfterDrop(b,c,f.dragStartContainerChildCount,f.dragEndContainerChildCount);(l=this.isDropRangeAffectedByDragRange(b,c))||(k=b.createBookmark(!1));f=c.clone().createBookmark(!1);l&&(k=b.createBookmark(!1));b=k.startNode;c= +k.endNode;l=f.startNode;c&&b.getPosition(l)&CKEDITOR.POSITION_PRECEDING&&c.getPosition(l)&CKEDITOR.POSITION_FOLLOWING&&l.insertBefore(b);b=g.createRange();b.moveToBookmark(k);h.extractHtmlFromRange(b,1);c=g.createRange();f.startNode.getCommonAncestor(h)||(f=g.getSelection().createBookmarks()[0]);c.moveToBookmark(f);a(g,{dataTransfer:d,method:"drop",range:c},1);g.fire("unlockSnapshot")},getRangeAtDropPosition:function(a,b){var c=a.data.$,d=c.clientX,g=c.clientY,f=b.getSelection(!0).getRanges()[0], +h=b.createRange();if(a.data.testRange)return a.data.testRange;if(document.caretRangeFromPoint&&b.document.$.caretRangeFromPoint(d,g))c=b.document.$.caretRangeFromPoint(d,g),h.setStart(CKEDITOR.dom.node(c.startContainer),c.startOffset),h.collapse(!0);else if(c.rangeParent)h.setStart(CKEDITOR.dom.node(c.rangeParent),c.rangeOffset),h.collapse(!0);else{if(CKEDITOR.env.ie&&8l&&!k;l++){if(!k)try{c.moveToPoint(d,g-l),k=!0}catch(m){}if(!k)try{c.moveToPoint(d,g+l),k=!0}catch(t){}}if(k){var x="cke-temp-"+(new Date).getTime();c.pasteHTML('\x3cspan id\x3d"'+x+'"\x3e​\x3c/span\x3e');var A=b.document.getById(x);h.moveToPosition(A,CKEDITOR.POSITION_BEFORE_START);A.remove()}else{var B=b.document.$.elementFromPoint(d,g),C=new CKEDITOR.dom.element(B),H;if(C.equals(b.editable())||"html"==C.getName())return f&&f.startContainer&&!f.startContainer.equals(b.editable())? +f:null;H=C.getClientRect();d/i,bodyRegExp:/([\s\S]*)<\/body>/i,fragmentRegExp:/\x3c!--(?:Start|End)Fragment--\x3e/g,data:{},files:[],nativeHtmlCache:"",normalizeType:function(a){a=a.toLowerCase();return"text"==a||"text/plain"==a?"Text":"url"==a?"URL":a}};this._.fallbackDataTransfer=new CKEDITOR.plugins.clipboard.fallbackDataTransfer(this);this.id=this.getData(m);this.id||(this.id="Text"==m?"":"cke-"+ +CKEDITOR.tools.getUniqueId());b&&(this.sourceEditor=b,this.setData("text/html",b.getSelectedHtml(1)),"Text"==m||this.getData("text/plain")||this.setData("text/plain",b.getSelection().getSelectedText()))};CKEDITOR.DATA_TRANSFER_INTERNAL=1;CKEDITOR.DATA_TRANSFER_CROSS_EDITORS=2;CKEDITOR.DATA_TRANSFER_EXTERNAL=3;CKEDITOR.plugins.clipboard.dataTransfer.prototype={getData:function(a,b){a=this._.normalizeType(a);var c="text/html"==a&&b?this._.nativeHtmlCache:this._.data[a];if(void 0===c||null===c||""=== +c){if(this._.fallbackDataTransfer.isRequired())c=this._.fallbackDataTransfer.getData(a,b);else try{c=this.$.getData(a)||""}catch(d){c=""}"text/html"!=a||b||(c=this._stripHtml(c))}"Text"==a&&CKEDITOR.env.gecko&&this.getFilesCount()&&"file://"==c.substring(0,7)&&(c="");if("string"===typeof c)var g=c.indexOf("\x3c/html\x3e"),c=-1!==g?c.substring(0,g+7):c;return c},setData:function(a,b){a=this._.normalizeType(a);"text/html"==a?(this._.data[a]=this._stripHtml(b),this._.nativeHtmlCache=b):this._.data[a]= +b;if(CKEDITOR.plugins.clipboard.isCustomDataTypesSupported||"URL"==a||"Text"==a)if("Text"==m&&"Text"==a&&(this.id=b),this._.fallbackDataTransfer.isRequired())this._.fallbackDataTransfer.setData(a,b);else try{this.$.setData(a,b)}catch(c){}},storeId:function(){"Text"!==m&&this.setData(m,this.id)},getTransferType:function(a){return this.sourceEditor?this.sourceEditor==a?CKEDITOR.DATA_TRANSFER_INTERNAL:CKEDITOR.DATA_TRANSFER_CROSS_EDITORS:CKEDITOR.DATA_TRANSFER_EXTERNAL},cacheData:function(){function a(c){c= +b._.normalizeType(c);var d=b.getData(c);"text/html"==c&&(b._.nativeHtmlCache=b.getData(c,!0),d=b._stripHtml(d));d&&(b._.data[c]=d)}if(this.$){var b=this,c,d;if(CKEDITOR.plugins.clipboard.isCustomDataTypesSupported){if(this.$.types)for(c=0;cc?v+c:b.width>c?v-a.left:v-a.right+b.width):ec?v-c:b.width>c?v-a.right+b.width:v-a.left);c=a.top;b.height-a.topd?w-d:b.height>d?w-a.bottom+b.height:w-a.top);CKEDITOR.env.ie&&!CKEDITOR.env.edge&&(b=a=new CKEDITOR.dom.element(n.$.offsetParent),"html"==b.getName()&&(b=b.getDocument().getBody()),"rtl"==b.getComputedStyle("direction")&&(v=CKEDITOR.env.ie8Compat?v-2*n.getDocument().getDocumentElement().$.scrollLeft:v-(a.$.scrollWidth- +a.$.clientWidth)));var a=n.getFirst(),k;(k=a.getCustomData("activePanel"))&&k.onHide&&k.onHide.call(this,1);a.setCustomData("activePanel",this);n.setStyles({top:w+"px",left:v+"px"});n.setOpacity(1);g&&g()},this);h.isLoaded?a():h.onLoad=a;CKEDITOR.tools.setTimeout(function(){var a=CKEDITOR.env.webkit&&CKEDITOR.document.getWindow().getScrollPosition().y;this.focus();m.element.focus();CKEDITOR.env.webkit&&(CKEDITOR.document.getBody().$.scrollTop=a);this.allowBlur(!0);this._.markFirst&&(CKEDITOR.env.ie? +CKEDITOR.tools.setTimeout(function(){m.markFirstDisplayed?m.markFirstDisplayed():m._.markFirstDisplayed()},0):m.markFirstDisplayed?m.markFirstDisplayed():m._.markFirstDisplayed());this._.editor.fire("panelShow",this)},0,this)},CKEDITOR.env.air?200:0,this);this.visible=1;this.onShow&&this.onShow.call(this)},reposition:function(){var a=this._.showBlockParams;this.visible&&this._.showBlockParams&&(this.hide(),this.showBlock.apply(this,a))},focus:function(){if(CKEDITOR.env.webkit){var a=CKEDITOR.document.getActive(); +a&&!a.equals(this._.iframe)&&a.$.blur()}(this._.lastFocused||this._.iframe.getFrameDocument().getWindow()).focus()},blur:function(){var a=this._.iframe.getFrameDocument().getActive();a&&a.is("a")&&(this._.lastFocused=a)},hide:function(a){if(this.visible&&(!this.onHide||!0!==this.onHide.call(this))){this.hideChild();CKEDITOR.env.gecko&&this._.iframe.getFrameDocument().$.activeElement.blur();this.element.setStyle("display","none");this.visible=0;this.element.getFirst().removeCustomData("activePanel"); +if(a=a&&this._.returnFocus)CKEDITOR.env.webkit&&a.type&&a.getWindow().$.focus(),a.focus();delete this._.lastFocused;this._.showBlockParams=null;this._.editor.fire("panelHide",this)}},allowBlur:function(a){var c=this._.panel;void 0!==a&&(c.allowBlur=a);return c.allowBlur},showAsChild:function(a,c,d,f,k,g){if(this._.activeChild!=a||a._.panel._.offsetParentId!=d.getId())this.hideChild(),a.onHide=CKEDITOR.tools.bind(function(){CKEDITOR.tools.setTimeout(function(){this._.focused||this.hide()},0,this)}, +this),this._.activeChild=a,this._.focused=!1,a.showBlock(c,d,f,k,g),this.blur(),(CKEDITOR.env.ie7Compat||CKEDITOR.env.ie6Compat)&&setTimeout(function(){a.element.getChild(0).$.style.cssText+=""},100)},hideChild:function(a){var c=this._.activeChild;c&&(delete c.onHide,delete this._.activeChild,c.hide(),a&&this.focus())}}});CKEDITOR.on("instanceDestroyed",function(){var a=CKEDITOR.tools.isEmpty(CKEDITOR.instances),c;for(c in f){var d=f[c];a?d.destroy():d.element.hide()}a&&(f={})})}(),CKEDITOR.plugins.add("menu", +{requires:"floatpanel",beforeInit:function(a){for(var f=a.config.menu_groups.split(","),b=a._.menuGroups={},c=a._.menuItems={},d=0;db.group?1:a.orderb.order?1:0})}var f='\x3cspan class\x3d"cke_menuitem"\x3e\x3ca id\x3d"{id}" class\x3d"cke_menubutton cke_menubutton__{name} cke_menubutton_{state} {cls}" href\x3d"{href}" title\x3d"{title}" tabindex\x3d"-1" _cke_focus\x3d1 hidefocus\x3d"true" role\x3d"{role}" aria-label\x3d"{label}" aria-describedby\x3d"{id}_description" aria-haspopup\x3d"{hasPopup}" aria-disabled\x3d"{disabled}" {ariaChecked} draggable\x3d"false"';CKEDITOR.env.gecko&&CKEDITOR.env.mac&& +(f+=' onkeypress\x3d"return false;"');CKEDITOR.env.gecko&&(f+=' onblur\x3d"this.style.cssText \x3d this.style.cssText;" ondragstart\x3d"return false;"');var f=f+(' onmouseover\x3d"CKEDITOR.tools.callFunction({hoverFn},{index});" onmouseout\x3d"CKEDITOR.tools.callFunction({moveOutFn},{index});" '+(CKEDITOR.env.ie?'onclick\x3d"return false;" onmouseup':"onclick")+'\x3d"CKEDITOR.tools.callFunction({clickFn},{index}); return false;"\x3e'),b=CKEDITOR.addTemplate("menuItem",f+'\x3cspan class\x3d"cke_menubutton_inner"\x3e\x3cspan class\x3d"cke_menubutton_icon"\x3e\x3cspan class\x3d"cke_button_icon cke_button__{iconName}_icon" style\x3d"{iconStyle}"\x3e\x3c/span\x3e\x3c/span\x3e\x3cspan class\x3d"cke_menubutton_label"\x3e{label}\x3c/span\x3e{shortcutHtml}{arrowHtml}\x3c/span\x3e\x3c/a\x3e\x3cspan id\x3d"{id}_description" class\x3d"cke_voice_label" aria-hidden\x3d"false"\x3e{ariaShortcut}\x3c/span\x3e\x3c/span\x3e'), +c=CKEDITOR.addTemplate("menuArrow",'\x3cspan class\x3d"cke_menuarrow"\x3e\x3cspan\x3e{label}\x3c/span\x3e\x3c/span\x3e'),d=CKEDITOR.addTemplate("menuShortcut",'\x3cspan class\x3d"cke_menubutton_label cke_menubutton_shortcut"\x3e{shortcut}\x3c/span\x3e');CKEDITOR.menu=CKEDITOR.tools.createClass({$:function(a,b){b=this._.definition=b||{};this.id=CKEDITOR.tools.getNextId();this.editor=a;this.items=[];this._.listeners=[];this._.level=b.level||1;var c=CKEDITOR.tools.extend({},b.panel,{css:[CKEDITOR.skin.getPath("editor")], +level:this._.level-1,block:{}}),d=c.block.attributes=c.attributes||{};!d.role&&(d.role="menu");this._.panelDefinition=c},_:{onShow:function(){var a=this.editor.getSelection(),b=a&&a.getStartElement(),c=this.editor.elementPath(),d=this._.listeners;this.removeAll();for(var f=0;fz.length)return!1;h=f.getParents(!0);for(r=0;rx;r++)t[r].indent+=h;h=CKEDITOR.plugins.list.arrayToList(t,e,null,a.config.enterMode,f.getDirection());if(!d.isIndent){var C;if((C=f.getParent())&&C.is("li"))for(var z=h.listNode.getChildren(),u=[],p,r=z.count()-1;0<=r;r--)(p=z.getItem(r))&&p.is&&p.is("li")&&u.push(p)}h&&h.listNode.replace(f);if(u&&u.length)for(r=0;rg.length)){d=g[g.length-1].getNext();f=e.createElement(this.type);for(c.push(f);g.length;)c=g.shift(),a=e.createElement("li"),l=c,l.is("pre")||u.test(l.getName())||"false"==l.getAttribute("contenteditable")?c.appendTo(a):(c.copyAttributes(a),h&&c.getDirection()&&(a.removeStyle("direction"),a.removeAttribute("dir")),c.moveChildren(a),c.remove()),a.appendTo(f);h&&k&&f.setAttribute("dir",h);d?f.insertBefore(d):f.appendTo(b)}}function b(a,b,c){function d(c){if(!(!(l= +k[c?"getFirst":"getLast"]())||l.is&&l.isBlockBoundary()||!(m=b.root[c?"getPrevious":"getNext"](CKEDITOR.dom.walker.invisible(!0)))||m.is&&m.isBlockBoundary({br:1})))a.document.createElement("br")[c?"insertBefore":"insertAfter"](l)}for(var e=CKEDITOR.plugins.list.listToArray(b.root,c),g=[],f=0;fe[f-1].indent+1){g=e[f-1].indent+1-e[f].indent;for(h=e[f].indent;e[f]&&e[f].indent>=h;)e[f].indent+=g,f++;f--}var k=CKEDITOR.plugins.list.arrayToList(e,c,null,a.config.enterMode,b.root.getAttribute("dir")).listNode,l,m;d(!0);d();k.replace(b.root);a.fire("contentDomInvalidated")}function c(a,b){this.name=a;this.context=this.type=b;this.allowedContent=b+" li";this.requiredContent=b}function d(a,b,c,d){for(var e, +g;e=a[d?"getLast":"getFirst"](p);)(g=e.getDirection(1))!==b.getDirection(1)&&e.setAttribute("dir",g),e.remove(),c?e[d?"insertBefore":"insertAfter"](c):b.append(e,d),c=e}function l(a){function b(c){var e=a[c?"getPrevious":"getNext"](q);e&&e.type==CKEDITOR.NODE_ELEMENT&&e.is(a.getName())&&(d(a,e,null,!c),a.remove(),a=e)}b();b(1)}function k(a){return a.type==CKEDITOR.NODE_ELEMENT&&(a.getName()in CKEDITOR.dtd.$block||a.getName()in CKEDITOR.dtd.$listItem)&&CKEDITOR.dtd[a.getName()]["#"]}function g(a,b, +c){a.fire("saveSnapshot");c.enlarge(CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS);var e=c.extractContents();b.trim(!1,!0);var g=b.createBookmark(),f=new CKEDITOR.dom.elementPath(b.startContainer),k=f.block,f=f.lastElement.getAscendant("li",1)||k,m=new CKEDITOR.dom.elementPath(c.startContainer),n=m.contains(CKEDITOR.dtd.$listItem),m=m.contains(CKEDITOR.dtd.$list);k?(k=k.getBogus())&&k.remove():m&&(k=m.getPrevious(q))&&y(k)&&k.remove();(k=e.getLast())&&k.type==CKEDITOR.NODE_ELEMENT&&k.is("br")&&k.remove();(k= +b.startContainer.getChild(b.startOffset))?e.insertBefore(k):b.startContainer.append(e);n&&(e=h(n))&&(f.contains(n)?(d(e,n.getParent(),n),e.remove()):f.append(e));for(;c.checkStartOfBlock()&&c.checkEndOfBlock();){m=c.startPath();e=m.block;if(!e)break;e.is("li")&&(f=e.getParent(),e.equals(f.getLast(q))&&e.equals(f.getFirst(q))&&(e=f));c.moveToPosition(e,CKEDITOR.POSITION_BEFORE_START);e.remove()}c=c.clone();e=a.editable();c.setEndAt(e,CKEDITOR.POSITION_BEFORE_END);c=new CKEDITOR.dom.walker(c);c.evaluator= +function(a){return q(a)&&!y(a)};(c=c.next())&&c.type==CKEDITOR.NODE_ELEMENT&&c.getName()in CKEDITOR.dtd.$list&&l(c);b.moveToBookmark(g);b.select();a.fire("saveSnapshot")}function h(a){return(a=a.getLast(q))&&a.type==CKEDITOR.NODE_ELEMENT&&a.getName()in m?a:null}var m={ol:1,ul:1},e=CKEDITOR.dom.walker.whitespaces(),n=CKEDITOR.dom.walker.bookmark(),q=function(a){return!(e(a)||n(a))},y=CKEDITOR.dom.walker.bogus();CKEDITOR.plugins.list={listToArray:function(a,b,c,d,e){if(!m[a.getName()])return[];d||(d= +0);c||(c=[]);for(var g=0,f=a.getChildCount();g=f.$.documentMode&&p.append(f.createText(" ")),p.append(l.listNode),l=l.nextIndex;else if(-1== +G.indent&&!c&&g){m[g.getName()]?(p=G.element.clone(!1,!0),y!=g.getDirection(1)&&p.setAttribute("dir",y)):p=new CKEDITOR.dom.documentFragment(f);var k=g.getDirection(1)!=y,D=G.element,N=D.getAttribute("class"),Q=D.getAttribute("style"),O=p.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT&&(d!=CKEDITOR.ENTER_BR||k||Q||N),K,W=G.contents.length,R;for(g=0;gCKEDITOR.env.version? +k.createText("\r"):k.createElement("br"),c.deleteContents(),c.insertNode(a),CKEDITOR.env.needsBrFiller?(k.createText("").insertAfter(a),l&&(v||p.blockLimit).appendBogus(),a.getNext().$.nodeValue="",c.setStartAt(a.getNext(),CKEDITOR.POSITION_AFTER_START)):c.setStartAt(a,CKEDITOR.POSITION_AFTER_END)),c.collapse(!0),c.select(),c.scrollIntoView()):g(a,b,c,d)}}};l=CKEDITOR.plugins.enterkey;k=l.enterBr;g=l.enterBlock;h=/^h[1-6]$/}(),function(){function a(a,b){var c={},d=[],l={nbsp:" ",shy:"­",gt:"\x3e", +lt:"\x3c",amp:"\x26",apos:"'",quot:'"'};a=a.replace(/\b(nbsp|shy|gt|lt|amp|apos|quot)(?:,|$)/g,function(a,e){var g=b?"\x26"+e+";":l[e];c[g]=b?l[e]:"\x26"+e+";";d.push(g);return""});a=a.replace(/,$/,"");if(!b&&a){a=a.split(",");var k=document.createElement("div"),g;k.innerHTML="\x26"+a.join(";\x26")+";";g=k.innerHTML;k=null;for(k=0;kf&&(f=640);420>b&&(b=420);var d=parseInt((window.screen.height-b)/2,10),l=parseInt((window.screen.width- +f)/2,10);c=(c||"location\x3dno,menubar\x3dno,toolbar\x3dno,dependent\x3dyes,minimizable\x3dno,modal\x3dyes,alwaysRaised\x3dyes,resizable\x3dyes,scrollbars\x3dyes")+",width\x3d"+f+",height\x3d"+b+",top\x3d"+d+",left\x3d"+l;var k=window.open("",null,c,!0);if(!k)return!1;try{-1==navigator.userAgent.toLowerCase().indexOf(" chrome/")&&(k.moveTo(l,d),k.resizeTo(f,b)),k.focus(),k.location.href=a}catch(g){window.open(a,null,c,!0)}return!0}}),"use strict",function(){function a(a){this.editor=a;this.loaders= +[]}function f(a,c,f){var g=a.config.fileTools_defaultFileName;this.editor=a;this.lang=a.lang;"string"===typeof c?(this.data=c,this.file=b(this.data),this.loaded=this.total=this.file.size):(this.data=null,this.file=c,this.total=this.file.size,this.loaded=0);f?this.fileName=f:this.file.name?this.fileName=this.file.name:(a=this.file.type.split("/"),g&&(a[0]=g),this.fileName=a.join("."));this.uploaded=0;this.responseData=this.uploadTotal=null;this.status="created";this.abort=function(){this.changeStatus("abort")}} +function b(a){var b=a.match(c)[1];a=a.replace(c,"");a=atob(a);var f=[],g,h,m,e;for(g=0;gg.status||299w.height-v.bottom?g("pin"):g("bottom"),e=w.width/2,e=d.floatSpacePreferRight?"right":0p.width?"rtl"==d.contentsLangDirection?"right":"left":e-v.left>v.right-e?"left":"right",p.width>w.width?(e="left",n=0):(n="left"==e?0w.width&&(e="left"==e?"right":"left",n=0)),h.setStyle(e,b(("pin"==l?A:t)+n+("pin"==l?0:"left"==e?z:-z)))):(l="pin",g("pin"),k(e))}}}();if(l){var g=new CKEDITOR.template('\x3cdiv id\x3d"cke_{name}" class\x3d"cke {id} cke_reset_all cke_chrome cke_editor_{name} cke_float cke_{langDir} '+ +CKEDITOR.env.cssClass+'" dir\x3d"{langDir}" title\x3d"'+(CKEDITOR.env.gecko?" ":"")+'" lang\x3d"{langCode}" role\x3d"application" style\x3d"{style}"'+(a.title?' aria-labelledby\x3d"cke_{name}_arialbl"':" ")+"\x3e"+(a.title?'\x3cspan id\x3d"cke_{name}_arialbl" class\x3d"cke_voice_label"\x3e{voiceLabel}\x3c/span\x3e':" ")+'\x3cdiv class\x3d"cke_inner"\x3e\x3cdiv id\x3d"{topId}" class\x3d"cke_top" role\x3d"presentation"\x3e{content}\x3c/div\x3e\x3c/div\x3e\x3c/div\x3e'),h=CKEDITOR.document.getBody().append(CKEDITOR.dom.element.createFromHtml(g.output({content:l, +id:a.id,langDir:a.lang.dir,langCode:a.langCode,name:a.name,style:"display:none;z-index:"+(d.baseFloatZIndex-1),topId:a.ui.spaceId("top"),voiceLabel:a.title}))),m=CKEDITOR.tools.eventsBuffer(500,k),e=CKEDITOR.tools.eventsBuffer(100,k);h.unselectable();h.on("mousedown",function(a){a=a.data;a.getTarget().hasAscendant("a",1)||a.preventDefault()});a.on("focus",function(b){k(b);a.on("change",m.input);f.on("scroll",e.input);f.on("resize",e.input)});a.on("blur",function(){h.hide();a.removeListener("change", +m.input);f.removeListener("scroll",e.input);f.removeListener("resize",e.input)});a.on("destroy",function(){f.removeListener("scroll",e.input);f.removeListener("resize",e.input);h.clearCustomData();h.remove()});a.focusManager.hasFocus&&h.show();a.focusManager.add(h,1)}}var f=CKEDITOR.document.getWindow(),b=CKEDITOR.tools.cssLength;CKEDITOR.plugins.add("floatingspace",{init:function(b){b.on("loaded",function(){a(this)},null,null,20)}})}(),CKEDITOR.plugins.add("listblock",{requires:"panel",onLoad:function(){var a= +CKEDITOR.addTemplate("panel-list",'\x3cul role\x3d"presentation" class\x3d"cke_panel_list"\x3e{items}\x3c/ul\x3e'),f=CKEDITOR.addTemplate("panel-list-item",'\x3cli id\x3d"{id}" class\x3d"cke_panel_listItem" role\x3dpresentation\x3e\x3ca id\x3d"{id}_option" _cke_focus\x3d1 hidefocus\x3dtrue title\x3d"{title}" draggable\x3d"false" ondragstart\x3d"return false;" href\x3d"javascript:void(\'{val}\')" {onclick}\x3d"CKEDITOR.tools.callFunction({clickFn},\'{val}\'); return false;" role\x3d"option"\x3e{text}\x3c/a\x3e\x3c/li\x3e'), +b=CKEDITOR.addTemplate("panel-list-group",'\x3ch1 id\x3d"{id}" draggable\x3d"false" ondragstart\x3d"return false;" class\x3d"cke_panel_grouptitle" role\x3d"presentation" \x3e{label}\x3c/h1\x3e'),c=/\'/g;CKEDITOR.ui.panel.prototype.addListBlock=function(a,b){return this.addBlock(a,new CKEDITOR.ui.listBlock(this.getHolderElement(),b))};CKEDITOR.ui.listBlock=CKEDITOR.tools.createClass({base:CKEDITOR.ui.panel.block,$:function(a,b){b=b||{};var c=b.attributes||(b.attributes={});(this.multiSelect=!!b.multiSelect)&& +(c["aria-multiselectable"]=!0);!c.role&&(c.role="listbox");this.base.apply(this,arguments);this.element.setAttribute("role",c.role);c=this.keys;c[40]="next";c[9]="next";c[38]="prev";c[CKEDITOR.SHIFT+9]="prev";c[32]=CKEDITOR.env.ie?"mouseup":"click";CKEDITOR.env.ie&&(c[13]="mouseup");this._.pendingHtml=[];this._.pendingList=[];this._.items={};this._.groups={}},_:{close:function(){if(this._.started){var b=a.output({items:this._.pendingList.join("")});this._.pendingList=[];this._.pendingHtml.push(b); +delete this._.started}},getClick:function(){this._.click||(this._.click=CKEDITOR.tools.addFunction(function(a){var b=this.toggle(a);if(this.onClick)this.onClick(a,b)},this));return this._.click}},proto:{add:function(a,b,k){var g=CKEDITOR.tools.getNextId();this._.started||(this._.started=1,this._.size=this._.size||0);this._.items[a]=g;var h;h=CKEDITOR.tools.htmlEncodeAttr(a).replace(c,"\\'");a={id:g,val:h,onclick:CKEDITOR.env.ie?'onclick\x3d"return false;" onmouseup':"onclick",clickFn:this._.getClick(), +title:CKEDITOR.tools.htmlEncodeAttr(k||a),text:b||a};this._.pendingList.push(f.output(a))},startGroup:function(a){this._.close();var c=CKEDITOR.tools.getNextId();this._.groups[a]=c;this._.pendingHtml.push(b.output({id:c,label:a}))},commit:function(){this._.close();this.element.appendHtml(this._.pendingHtml.join(""));delete this._.size;this._.pendingHtml=[]},toggle:function(a){var b=this.isMarked(a);b?this.unmark(a):this.mark(a);return!b},hideGroup:function(a){var b=(a=this.element.getDocument().getById(this._.groups[a]))&& +a.getNext();a&&(a.setStyle("display","none"),b&&"ul"==b.getName()&&b.setStyle("display","none"))},hideItem:function(a){this.element.getDocument().getById(this._.items[a]).setStyle("display","none")},showAll:function(){var a=this._.items,b=this._.groups,c=this.element.getDocument(),g;for(g in a)c.getById(a[g]).setStyle("display","");for(var f in b)a=c.getById(b[f]),g=a.getNext(),a.setStyle("display",""),g&&"ul"==g.getName()&&g.setStyle("display","")},mark:function(a){this.multiSelect||this.unmarkAll(); +a=this._.items[a];var b=this.element.getDocument().getById(a);b.addClass("cke_selected");this.element.getDocument().getById(a+"_option").setAttribute("aria-selected",!0);this.onMark&&this.onMark(b)},markFirstDisplayed:function(){var a=this;this._.markFirstDisplayed(function(){a.multiSelect||a.unmarkAll()})},unmark:function(a){var b=this.element.getDocument();a=this._.items[a];var c=b.getById(a);c.removeClass("cke_selected");b.getById(a+"_option").removeAttribute("aria-selected");this.onUnmark&&this.onUnmark(c)}, +unmarkAll:function(){var a=this._.items,b=this.element.getDocument(),c;for(c in a){var g=a[c];b.getById(g).removeClass("cke_selected");b.getById(g+"_option").removeAttribute("aria-selected")}this.onUnmark&&this.onUnmark()},isMarked:function(a){return this.element.getDocument().getById(this._.items[a]).hasClass("cke_selected")},focus:function(a){this._.focusIndex=-1;var b=this.element.getElementsByTag("a"),c,g=-1;if(a)for(c=this.element.getDocument().getById(this._.items[a]).getFirst();a=b.getItem(++g);){if(a.equals(c)){this._.focusIndex= +g;break}}else this.element.focus();c&&setTimeout(function(){c.focus()},0)}}})}}),CKEDITOR.plugins.add("richcombo",{requires:"floatpanel,listblock,button",beforeInit:function(a){a.ui.addHandler(CKEDITOR.UI_RICHCOMBO,CKEDITOR.ui.richCombo.handler)}}),function(){var a='\x3cspan id\x3d"{id}" class\x3d"cke_combo cke_combo__{name} {cls}" role\x3d"presentation"\x3e\x3cspan id\x3d"{id}_label" class\x3d"cke_combo_label"\x3e{label}\x3c/span\x3e\x3ca class\x3d"cke_combo_button" title\x3d"{title}" tabindex\x3d"-1"'+ +(CKEDITOR.env.gecko&&!CKEDITOR.env.hc?"":" href\x3d\"javascript:void('{titleJs}')\"")+' hidefocus\x3d"true" role\x3d"button" aria-labelledby\x3d"{id}_label" aria-haspopup\x3d"listbox"';CKEDITOR.env.gecko&&CKEDITOR.env.mac&&(a+=' onkeypress\x3d"return false;"');CKEDITOR.env.gecko&&(a+=' onblur\x3d"this.style.cssText \x3d this.style.cssText;"');var a=a+(' onkeydown\x3d"return CKEDITOR.tools.callFunction({keydownFn},event,this);" onfocus\x3d"return CKEDITOR.tools.callFunction({focusFn},event);" '+(CKEDITOR.env.ie? +'onclick\x3d"return false;" onmouseup':"onclick")+'\x3d"CKEDITOR.tools.callFunction({clickFn},this);return false;"\x3e\x3cspan id\x3d"{id}_text" class\x3d"cke_combo_text cke_combo_inlinelabel"\x3e{label}\x3c/span\x3e\x3cspan class\x3d"cke_combo_open"\x3e\x3cspan class\x3d"cke_combo_arrow"\x3e'+(CKEDITOR.env.hc?"\x26#9660;":CKEDITOR.env.air?"\x26nbsp;":"")+"\x3c/span\x3e\x3c/span\x3e\x3c/a\x3e\x3c/span\x3e"),f=CKEDITOR.addTemplate("combo",a);CKEDITOR.UI_RICHCOMBO="richcombo";CKEDITOR.ui.richCombo= +CKEDITOR.tools.createClass({$:function(a){CKEDITOR.tools.extend(this,a,{canGroup:!1,title:a.label,modes:{wysiwyg:1},editorFocus:1});a=this.panel||{};delete this.panel;this.id=CKEDITOR.tools.getNextNumber();this.document=a.parent&&a.parent.getDocument()||CKEDITOR.document;a.className="cke_combopanel";a.block={multiSelect:a.multiSelect,attributes:a.attributes};a.toolbarRelated=!0;this._={panelDefinition:a,items:{},listeners:[]}},proto:{renderHtml:function(a){var c=[];this.render(a,c);return c.join("")}, +render:function(a,c){function d(){if(this.getState()!=CKEDITOR.TRISTATE_ON){var c=this.modes[a.mode]?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED;a.readOnly&&!this.readOnly&&(c=CKEDITOR.TRISTATE_DISABLED);this.setState(c);this.setValue("");c!=CKEDITOR.TRISTATE_DISABLED&&this.refresh&&this.refresh()}}var l=CKEDITOR.env,k="cke_"+this.id,g=CKEDITOR.tools.addFunction(function(c){q&&(a.unlockSelection(1),q=0);m.execute(c)},this),h=this,m={id:k,combo:this,focus:function(){CKEDITOR.document.getById(k).getChild(1).focus()}, +execute:function(c){var d=h._;if(d.state!=CKEDITOR.TRISTATE_DISABLED)if(h.createPanel(a),d.on)d.panel.hide();else{h.commit();var e=h.getValue();e?d.list.mark(e):d.list.unmarkAll();d.panel.showBlock(h.id,new CKEDITOR.dom.element(c),4)}},clickFn:g};this._.listeners.push(a.on("activeFilterChange",d,this));this._.listeners.push(a.on("mode",d,this));this._.listeners.push(a.on("selectionChange",d,this));!this.readOnly&&this._.listeners.push(a.on("readOnly",d,this));var e=CKEDITOR.tools.addFunction(function(a, +b){a=new CKEDITOR.dom.event(a);var c=a.getKeystroke();switch(c){case 13:case 32:case 40:CKEDITOR.tools.callFunction(g,b);break;default:m.onkey(m,c)}a.preventDefault()}),n=CKEDITOR.tools.addFunction(function(){m.onfocus&&m.onfocus()}),q=0;m.keyDownFn=e;l={id:k,name:this.name||this.command,label:this.label,title:this.title,cls:this.className||"",titleJs:l.gecko&&!l.hc?"":(this.title||"").replace("'",""),keydownFn:e,focusFn:n,clickFn:g};f.output(l,c);if(this.onRender)this.onRender();return m},createPanel:function(a){if(!this._.panel){var c= +this._.panelDefinition,d=this._.panelDefinition.block,f=c.parent||CKEDITOR.document.getBody(),k="cke_combopanel__"+this.name,g=new CKEDITOR.ui.floatPanel(a,f,c),c=g.addListBlock(this.id,d),h=this;g.onShow=function(){this.element.addClass(k);h.setState(CKEDITOR.TRISTATE_ON);h._.on=1;h.editorFocus&&!a.focusManager.hasFocus&&a.focus();if(h.onOpen)h.onOpen()};g.onHide=function(c){this.element.removeClass(k);h.setState(h.modes&&h.modes[a.mode]?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED);h._.on=0; +if(!c&&h.onClose)h.onClose()};g.onEscape=function(){g.hide(1)};c.onClick=function(a,b){h.onClick&&h.onClick.call(h,a,b);g.hide()};this._.panel=g;this._.list=c;g.getBlock(this.id).onHide=function(){h._.on=0;h.setState(CKEDITOR.TRISTATE_OFF)};this.init&&this.init()}},setValue:function(a,c){this._.value=a;var d=this.document.getById("cke_"+this.id+"_text");d&&(a||c?d.removeClass("cke_combo_inlinelabel"):(c=this.label,d.addClass("cke_combo_inlinelabel")),d.setText("undefined"!=typeof c?c:a))},getValue:function(){return this._.value|| +""},unmarkAll:function(){this._.list.unmarkAll()},mark:function(a){this._.list.mark(a)},hideItem:function(a){this._.list.hideItem(a)},hideGroup:function(a){this._.list.hideGroup(a)},showAll:function(){this._.list.showAll()},add:function(a,c,d){this._.items[a]=d||a;this._.list.add(a,c,d)},startGroup:function(a){this._.list.startGroup(a)},commit:function(){this._.committed||(this._.list.commit(),this._.committed=1,CKEDITOR.ui.fire("ready",this));this._.committed=1},setState:function(a){if(this._.state!= +a){var c=this.document.getById("cke_"+this.id);c.setState(a,"cke_combo");a==CKEDITOR.TRISTATE_DISABLED?c.setAttribute("aria-disabled",!0):c.removeAttribute("aria-disabled");this._.state=a}},getState:function(){return this._.state},enable:function(){this._.state==CKEDITOR.TRISTATE_DISABLED&&this.setState(this._.lastState)},disable:function(){this._.state!=CKEDITOR.TRISTATE_DISABLED&&(this._.lastState=this._.state,this.setState(CKEDITOR.TRISTATE_DISABLED))},destroy:function(){CKEDITOR.tools.array.forEach(this._.listeners, +function(a){a.removeListener()});this._.listeners=[]}},statics:{handler:{create:function(a){return new CKEDITOR.ui.richCombo(a)}}}});CKEDITOR.ui.prototype.addRichCombo=function(a,c){this.add(a,CKEDITOR.UI_RICHCOMBO,c)}}(),CKEDITOR.plugins.add("format",{requires:"richcombo",init:function(a){if(!a.blockless){for(var f=a.config,b=a.lang.format,c=f.format_tags.split(";"),d={},l=0,k=[],g=0;gb&&aI.version?" ":R,g=a.hotNode&&a.hotNode.getText()==d&&a.element.equals(a.hotNode)&&a.lastCmdDirection===!!c;h(a,function(d){g&&a.hotNode&&a.hotNode.remove();d[c?"insertAfter":"insertBefore"](b);d.setAttributes({"data-cke-magicline-hot":1, +"data-cke-magicline-dir":!!c});a.lastCmdDirection=!!c});I.ie||a.enterMode==CKEDITOR.ENTER_BR||a.hotNode.scrollIntoView();a.line.detach()}return function(g){g=g.getSelection().getStartElement();var f;g=g.getAscendant(U,1);if(!p(a,g)&&g&&!g.equals(a.editable)&&!g.contains(a.editable)){(f=k(g))&&"false"==f.getAttribute("contenteditable")&&(g=f);a.element=g;f=d(a,g,!c);var h;n(f)&&f.is(a.triggers)&&f.is(X)&&(!d(a,f,!c)||(h=d(a,f,!c))&&n(h)&&h.is(a.triggers))?e(f):(h=b(a,g),n(h)&&(d(a,h,!c)?(g=d(a,h,!c))&& +n(g)&&g.is(a.triggers)&&e(h):e(h)))}}}()}}function e(a,b){if(!b||b.type!=CKEDITOR.NODE_ELEMENT||!b.$)return!1;var c=a.line;return c.wrap.equals(b)||c.wrap.contains(b)}function n(a){return a&&a.type==CKEDITOR.NODE_ELEMENT&&a.$}function q(a){if(!n(a))return!1;var b;(b=y(a))||(n(a)?(b={left:1,right:1,center:1},b=!(!b[a.getComputedStyle("float")]&&!b[a.getAttribute("align")])):b=!1);return b}function y(a){return!!{absolute:1,fixed:1}[a.getComputedStyle("position")]}function u(a,b){return n(b)?b.is(a.triggers): +null}function p(a,b){if(!b)return!1;for(var c=b.getParents(1),d=c.length;d--;)for(var e=a.tabuList.length;e--;)if(c[d].hasAttribute(a.tabuList[e]))return!0;return!1}function v(a,b,c){b=b[c?"getLast":"getFirst"](function(b){return a.isRelevant(b)&&!b.is(ha)});if(!b)return!1;t(a,b);return c?b.size.top>a.mouse.y:b.size.bottom(a.inInlineMode?d.editable.top+d.editable.height/2:Math.min(d.editable.height,d.pane.height)/ +2),b=b[h?"getLast":"getFirst"](function(a){return!(P(a)||S(a))});if(!b)return null;e(a,b)&&(b=a.line.wrap[h?"getPrevious":"getNext"](function(a){return!(P(a)||S(a))}));if(!n(b)||q(b)||!u(a,b))return null;t(a,b);return!h&&0<=b.size.top&&l(c.y,0,b.size.top+g)?(a=a.inInlineMode||0===d.scroll.y?O:W,new f([null,b,G,Q,a])):h&&b.size.bottom<=d.pane.height&&l(c.y,b.size.bottom-g,d.pane.height)?(a=a.inInlineMode||l(b.size.bottom,d.pane.height-g,d.pane.height)?K:W,new f([b,null,D,Q,a])):null}function r(a){var c= +a.mouse,e=a.view,g=a.triggerOffset,h=b(a);if(!h)return null;t(a,h);var g=Math.min(g,0|h.size.outerHeight/2),k=[],m,r;if(l(c.y,h.size.top-1,h.size.top+g))r=!1;else if(l(c.y,h.size.bottom-g,h.size.bottom+1))r=!0;else return null;if(q(h)||v(a,h,r)||h.getParent().is(Z))return null;var M=d(a,h,!r);if(M){if(M&&M.type==CKEDITOR.NODE_TEXT)return null;if(n(M)){if(q(M)||!u(a,M)||M.getParent().is(Z))return null;k=[M,h][r?"reverse":"concat"]().concat([N,Q])}}else h.equals(a.editable[r?"getLast":"getFirst"](a.isRelevant))? +(x(a),r&&l(c.y,h.size.bottom-g,e.pane.height)&&l(h.size.bottom,e.pane.height-g,e.pane.height)?m=K:l(c.y,0,h.size.top+g)&&(m=O)):m=W,k=[null,h][r?"reverse":"concat"]().concat([r?D:G,Q,m,h.equals(a.editable[r?"getLast":"getFirst"](a.isRelevant))?r?K:O:W]);return 0 in k?new f(k):null}function z(a,b,c,d){for(var e=b.getDocumentPosition(),g={},f={},h={},k={},l=Y.length;l--;)g[Y[l]]=parseInt(b.getComputedStyle.call(b,"border-"+Y[l]+"-width"),10)||0,h[Y[l]]=parseInt(b.getComputedStyle.call(b,"padding-"+ +Y[l]),10)||0,f[Y[l]]=parseInt(b.getComputedStyle.call(b,"margin-"+Y[l]),10)||0;c&&!d||A(a,d);k.top=e.y-(c?0:a.view.scroll.y);k.left=e.x-(c?0:a.view.scroll.x);k.outerWidth=b.$.offsetWidth;k.outerHeight=b.$.offsetHeight;k.height=k.outerHeight-(h.top+h.bottom+g.top+g.bottom);k.width=k.outerWidth-(h.left+h.right+g.left+g.right);k.bottom=k.top+k.outerHeight;k.right=k.left+k.outerWidth;a.inInlineMode&&(k.scroll={top:b.$.scrollTop,left:b.$.scrollLeft});return C({border:g,padding:h,margin:f,ignoreScroll:c}, +k,!0)}function t(a,b,c){if(!n(b))return b.size=null;if(!b.size)b.size={};else if(b.size.ignoreScroll==c&&b.size.date>new Date-ba)return null;return C(b.size,z(a,b,c),{date:+new Date},!0)}function x(a,b){a.view.editable=z(a,a.editable,b,!0)}function A(a,b){a.view||(a.view={});var c=a.view;if(!(!b&&c&&c.date>new Date-ba)){var d=a.win,c=d.getScrollPosition(),d=d.getViewPaneSize();C(a.view,{scroll:{x:c.x,y:c.y,width:a.doc.$.documentElement.scrollWidth-d.width,height:a.doc.$.documentElement.scrollHeight- +d.height},pane:{width:d.width,height:d.height,bottom:d.height+c.y},date:+new Date},!0)}}function B(a,b,c,d){for(var e=d,g=d,h=0,k=!1,l=!1,m=a.view.pane.height,n=a.mouse;n.y+hd.left-e.x&&cd.top-e.y&&bCKEDITOR.env.version,E=CKEDITOR.dtd,L={},G=128,D=64,N=32,Q=16, +O=4,K=2,W=1,R=" ",Z=E.$listItem,ha=E.$tableContent,X=C({},E.$nonEditable,E.$empty),U=E.$block,ba=100,ca="width:0px;height:0px;padding:0px;margin:0px;display:block;z-index:9999;color:#fff;position:absolute;font-size: 0px;line-height:0px;",V=ca+"border-color:transparent;display:block;border-style:solid;",M="\x3cspan\x3e"+R+"\x3c/span\x3e";L[CKEDITOR.ENTER_BR]="br";L[CKEDITOR.ENTER_P]="p";L[CKEDITOR.ENTER_DIV]="div";f.prototype={set:function(a,b,c){this.properties=a+b+(c||W);return this},is:function(a){return(this.properties& +a)==a}};var aa=function(){function a(b,c){var d=b.$.elementFromPoint(c.x,c.y);return d&&d.nodeType?new CKEDITOR.dom.element(d):null}return function(b,c,d){if(!b.mouse)return null;var g=b.doc,f=b.line.wrap;d=d||b.mouse;var h=a(g,d);c&&e(b,h)&&(f.hide(),h=a(g,d),f.show());return!h||h.type!=CKEDITOR.NODE_ELEMENT||!h.$||I.ie&&9>I.version&&!b.boundary.equals(h)&&!b.boundary.contains(h)?null:h}}(),P=CKEDITOR.dom.walker.whitespaces(),S=CKEDITOR.dom.walker.nodeType(CKEDITOR.NODE_COMMENT),T=function(){function b(e){var g= +e.element,f,h,k;if(!n(g)||g.contains(e.editable)||g.isReadOnly())return null;k=B(e,function(a,b){return!b.equals(a)},function(a,b){return aa(a,!0,b)},g);f=k.upper;h=k.lower;if(a(e,f,h))return k.set(N,8);if(f&&g.contains(f))for(;!f.getParent().equals(g);)f=f.getParent();else f=g.getFirst(function(a){return d(e,a)});if(h&&g.contains(h))for(;!h.getParent().equals(g);)h=h.getParent();else h=g.getLast(function(a){return d(e,a)});if(!f||!h)return null;t(e,f);t(e,h);if(!l(e.mouse.y,f.size.top,h.size.bottom))return null; +for(var g=Number.MAX_VALUE,m,r,M,q;h&&!h.equals(f)&&(r=f.getNext(e.isRelevant));)m=Math.abs(c(e,f,r)-e.mouse.y),m|<\/font>)/,l=/h.width&&(c.resize_minWidth=h.width);c.resize_minHeight> +h.height&&(c.resize_minHeight=h.height);CKEDITOR.document.on("mousemove",f);CKEDITOR.document.on("mouseup",b);a.document&&(a.document.on("mousemove",f),a.document.on("mouseup",b));d.preventDefault&&d.preventDefault()});a.on("destroy",function(){CKEDITOR.tools.removeFunction(n)});a.on("uiSpace",function(b){if("bottom"==b.data.space){var c="";m&&!e&&(c=" cke_resizer_horizontal");!m&&e&&(c=" cke_resizer_vertical");var g='\x3cspan id\x3d"'+d+'" class\x3d"cke_resizer'+c+" cke_resizer_"+l+'" title\x3d"'+ +CKEDITOR.tools.htmlEncode(a.lang.common.resize)+'" onmousedown\x3d"CKEDITOR.tools.callFunction('+n+', event)"\x3e'+("ltr"==l?"◢":"◣")+"\x3c/span\x3e";"ltr"==l&&"ltr"==c?b.data.html+=g:b.data.html=g+b.data.html}},a,null,100);a.on("maximize",function(b){a.ui.space("resizer")[b.data==CKEDITOR.TRISTATE_ON?"hide":"show"]()})}}}),CKEDITOR.plugins.add("menubutton",{requires:"button,menu",onLoad:function(){var a=function(a){var b=this._,c=b.menu;b.state!==CKEDITOR.TRISTATE_DISABLED&&(b.on&&c?c.hide():(b.previousState= +b.state,c||(c=b.menu=new CKEDITOR.menu(a,{panel:{className:"cke_menu_panel",attributes:{"aria-label":a.lang.common.options}}}),c.onHide=CKEDITOR.tools.bind(function(){var c=this.command?a.getCommand(this.command).modes:this.modes;this.setState(!c||c[a.mode]?b.previousState:CKEDITOR.TRISTATE_DISABLED);b.on=0},this),this.onMenu&&c.addListener(this.onMenu)),this.setState(CKEDITOR.TRISTATE_ON),b.on=1,setTimeout(function(){c.show(CKEDITOR.document.getById(b.id),4)},0)))};CKEDITOR.ui.menuButton=CKEDITOR.tools.createClass({base:CKEDITOR.ui.button, +$:function(f){delete f.panel;this.base(f);this.hasArrow="menu";this.click=a},statics:{handler:{create:function(a){return new CKEDITOR.ui.menuButton(a)}}}})},beforeInit:function(a){a.ui.addHandler(CKEDITOR.UI_MENUBUTTON,CKEDITOR.ui.menuButton.handler)}}),CKEDITOR.UI_MENUBUTTON="menubutton","use strict",CKEDITOR.plugins.add("scayt",{requires:"menubutton,dialog",tabToOpen:null,dialogName:"scaytDialog",onLoad:function(a){"moono-lisa"==(CKEDITOR.skinName||a.config.skin)&&CKEDITOR.document.appendStyleSheet(CKEDITOR.getUrl(this.path+ +"skins/"+CKEDITOR.skin.name+"/scayt.css"));CKEDITOR.document.appendStyleSheet(CKEDITOR.getUrl(this.path+"dialogs/dialog.css"))},init:function(a){var f=this,b=CKEDITOR.plugins.scayt;this.bindEvents(a);this.parseConfig(a);this.addRule(a);CKEDITOR.dialog.add(this.dialogName,CKEDITOR.getUrl(this.path+"dialogs/options.js"));this.addMenuItems(a);var c=a.lang.scayt,d=CKEDITOR.env;a.ui.add("Scayt",CKEDITOR.UI_MENUBUTTON,{label:c.text_title,title:a.plugins.wsc?a.lang.wsc.title:c.text_title,modes:{wysiwyg:!(d.ie&& +(8>d.version||d.quirks))},toolbar:"spellchecker,20",refresh:function(){var c=a.ui.instances.Scayt.getState();a.scayt&&(c=b.state.scayt[a.name]?CKEDITOR.TRISTATE_ON:CKEDITOR.TRISTATE_OFF);a.fire("scaytButtonState",c)},onRender:function(){var b=this;a.on("scaytButtonState",function(a){void 0!==typeof a.data&&b.setState(a.data)})},onMenu:function(){var c=a.scayt;a.getMenuItem("scaytToggle").label=a.lang.scayt[c&&b.state.scayt[a.name]?"btn_disable":"btn_enable"];var d={scaytToggle:CKEDITOR.TRISTATE_OFF, +scaytOptions:c?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,scaytLangs:c?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,scaytDict:c?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,scaytAbout:c?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,WSC:a.plugins.wsc?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED};a.config.scayt_uiTabs[0]||delete d.scaytOptions;a.config.scayt_uiTabs[1]||delete d.scaytLangs;a.config.scayt_uiTabs[2]||delete d.scaytDict;c&&!CKEDITOR.plugins.scayt.isNewUdSupported(c)&& +(delete d.scaytDict,a.config.scayt_uiTabs[2]=0,CKEDITOR.plugins.scayt.alarmCompatibilityMessage());return d}});a.contextMenu&&a.addMenuItems&&(a.contextMenu.addListener(function(b,c){var d=a.scayt,h,m;d&&(m=d.getSelectionNode())&&(h=f.menuGenerator(a,m),d.showBanner("."+a.contextMenu._.definition.panel.className.split(" ").join(" .")));return h}),a.contextMenu._.onHide=CKEDITOR.tools.override(a.contextMenu._.onHide,function(b){return function(){var c=a.scayt;c&&c.hideBanner();return b.apply(this)}}))}, +addMenuItems:function(a){var f=this,b=CKEDITOR.plugins.scayt;a.addMenuGroup("scaytButton");for(var c=a.config.scayt_contextMenuItemsOrder.split("|"),d=0;da.config.scayt_maxSuggestions)a.config.scayt_maxSuggestions=3;if(void 0===a.config.scayt_minWordLength||"number"!=typeof a.config.scayt_minWordLength||1>a.config.scayt_minWordLength)a.config.scayt_minWordLength=3;if(void 0===a.config.scayt_customDictionaryIds||"string"!==typeof a.config.scayt_customDictionaryIds)a.config.scayt_customDictionaryIds="";if(void 0=== +a.config.scayt_userDictionaryName||"string"!==typeof a.config.scayt_userDictionaryName)a.config.scayt_userDictionaryName=null;if("string"===typeof a.config.scayt_uiTabs&&3===a.config.scayt_uiTabs.split(",").length){var b=[],c=[];a.config.scayt_uiTabs=a.config.scayt_uiTabs.split(",");CKEDITOR.tools.search(a.config.scayt_uiTabs,function(a){1===Number(a)||0===Number(a)?(c.push(!0),b.push(Number(a))):c.push(!1)});null===CKEDITOR.tools.search(c,!1)?a.config.scayt_uiTabs=b:a.config.scayt_uiTabs=[1,1,1]}else a.config.scayt_uiTabs= +[1,1,1];"string"!=typeof a.config.scayt_serviceProtocol&&(a.config.scayt_serviceProtocol=null);"string"!=typeof a.config.scayt_serviceHost&&(a.config.scayt_serviceHost=null);"string"!=typeof a.config.scayt_servicePort&&(a.config.scayt_servicePort=null);"string"!=typeof a.config.scayt_servicePath&&(a.config.scayt_servicePath=null);a.config.scayt_moreSuggestions||(a.config.scayt_moreSuggestions="on");"string"!==typeof a.config.scayt_customerId&&(a.config.scayt_customerId="1:WvF0D4-UtPqN1-43nkD4-NKvUm2-daQqk3-LmNiI-z7Ysb4-mwry24-T8YrS3-Q2tpq2"); +"string"!==typeof a.config.scayt_customPunctuation&&(a.config.scayt_customPunctuation="-");"string"!==typeof a.config.scayt_srcUrl&&(f=document.location.protocol,f=-1!=f.search(/https?:/)?f:"http:",a.config.scayt_srcUrl=f+"//svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js");"boolean"!==typeof CKEDITOR.config.scayt_handleCheckDirty&&(CKEDITOR.config.scayt_handleCheckDirty=!0);"boolean"!==typeof CKEDITOR.config.scayt_handleUndoRedo&&(CKEDITOR.config.scayt_handleUndoRedo=!0);CKEDITOR.config.scayt_handleUndoRedo= +CKEDITOR.plugins.undo?CKEDITOR.config.scayt_handleUndoRedo:!1;"boolean"!==typeof a.config.scayt_multiLanguageMode&&(a.config.scayt_multiLanguageMode=!1);"object"!==typeof a.config.scayt_multiLanguageStyles&&(a.config.scayt_multiLanguageStyles={});a.config.scayt_ignoreAllCapsWords&&"boolean"!==typeof a.config.scayt_ignoreAllCapsWords&&(a.config.scayt_ignoreAllCapsWords=!1);a.config.scayt_ignoreDomainNames&&"boolean"!==typeof a.config.scayt_ignoreDomainNames&&(a.config.scayt_ignoreDomainNames=!1);a.config.scayt_ignoreWordsWithMixedCases&& +"boolean"!==typeof a.config.scayt_ignoreWordsWithMixedCases&&(a.config.scayt_ignoreWordsWithMixedCases=!1);a.config.scayt_ignoreWordsWithNumbers&&"boolean"!==typeof a.config.scayt_ignoreWordsWithNumbers&&(a.config.scayt_ignoreWordsWithNumbers=!1);if(a.config.scayt_disableOptionsStorage){var f=CKEDITOR.tools.isArray(a.config.scayt_disableOptionsStorage)?a.config.scayt_disableOptionsStorage:"string"===typeof a.config.scayt_disableOptionsStorage?[a.config.scayt_disableOptionsStorage]:void 0,d="all options lang ignore-all-caps-words ignore-domain-names ignore-words-with-mixed-cases ignore-words-with-numbers".split(" "), +l=["lang","ignore-all-caps-words","ignore-domain-names","ignore-words-with-mixed-cases","ignore-words-with-numbers"],k=CKEDITOR.tools.search,g=CKEDITOR.tools.indexOf;a.config.scayt_disableOptionsStorage=function(a){for(var b=[],c=0;ca.config.scayt_cacheSize)a.config.scayt_cacheSize=4E3},addRule:function(a){var f=CKEDITOR.plugins.scayt,b=a.dataProcessor,c=b&&b.htmlFilter,d=a._.elementsPath&&a._.elementsPath.filters,b=b&&b.dataFilter,l=a.addRemoveFormatFilter,k=function(b){if(a.scayt&&(b.hasAttribute(f.options.data_attribute_name)||b.hasAttribute(f.options.problem_grammar_data_attribute)))return!1},g=function(b){var c= +!0;a.scayt&&(b.hasAttribute(f.options.data_attribute_name)||b.hasAttribute(f.options.problem_grammar_data_attribute))&&(c=!1);return c};d&&d.push(k);b&&b.addRules({elements:{span:function(a){var b=a.hasClass(f.options.misspelled_word_class)&&a.attributes[f.options.data_attribute_name],c=a.hasClass(f.options.problem_grammar_class)&&a.attributes[f.options.problem_grammar_data_attribute];f&&(b||c)&&delete a.name;return a}}});c&&c.addRules({elements:{span:function(a){var b=a.hasClass(f.options.misspelled_word_class)&& +a.attributes[f.options.data_attribute_name],c=a.hasClass(f.options.problem_grammar_class)&&a.attributes[f.options.problem_grammar_data_attribute];f&&(b||c)&&delete a.name;return a}}});l&&l.call(a,g)},scaytMenuDefinition:function(a){var f=this,b=CKEDITOR.plugins.scayt;a=a.scayt;return{scayt:{scayt_ignore:{label:a.getLocal("btn_ignore"),group:"scayt_control",order:1,exec:function(a){a.scayt.ignoreWord()}},scayt_ignoreall:{label:a.getLocal("btn_ignoreAll"),group:"scayt_control",order:2,exec:function(a){a.scayt.ignoreAllWords()}}, +scayt_add:{label:a.getLocal("btn_addWord"),group:"scayt_control",order:3,exec:function(a){var b=a.scayt;setTimeout(function(){b.addWordToUserDictionary()},10)}},scayt_option:{label:a.getLocal("btn_options"),group:"scayt_control",order:4,exec:function(a){a.scayt.tabToOpen="options";b.openDialog(f.dialogName,a)},verification:function(a){return 1==a.config.scayt_uiTabs[0]?!0:!1}},scayt_language:{label:a.getLocal("btn_langs"),group:"scayt_control",order:5,exec:function(a){a.scayt.tabToOpen="langs";b.openDialog(f.dialogName, +a)},verification:function(a){return 1==a.config.scayt_uiTabs[1]?!0:!1}},scayt_dictionary:{label:a.getLocal("btn_dictionaries"),group:"scayt_control",order:6,exec:function(a){a.scayt.tabToOpen="dictionaries";b.openDialog(f.dialogName,a)},verification:function(a){return 1==a.config.scayt_uiTabs[2]?!0:!1}},scayt_about:{label:a.getLocal("btn_about"),group:"scayt_control",order:7,exec:function(a){a.scayt.tabToOpen="about";b.openDialog(f.dialogName,a)}}},grayt:{grayt_problemdescription:{label:"Grammar problem description", +group:"grayt_description",order:1,state:CKEDITOR.TRISTATE_DISABLED,exec:function(a){}},grayt_ignore:{label:a.getLocal("btn_ignore"),group:"grayt_control",order:2,exec:function(a){a.scayt.ignorePhrase()}},grayt_ignoreall:{label:a.getLocal("btn_ignoreAll"),group:"grayt_control",order:3,exec:function(a){a.scayt.ignoreAllPhrases()}}}}},buildSuggestionMenuItems:function(a,f,b){var c={},d={},l=b?"word":"phrase",k=b?"startGrammarCheck":"startSpellCheck",g=a.scayt;if(0=parseInt(f)*Math.pow(10,b)}return f?Array(7).join(String.fromCharCode(8203)):String.fromCharCode(8203)}()}],state:{scayt:{},grayt:{}},warningCounter:0,suggestions:[],options:{disablingCommandExec:{source:!0,newpage:!0,templates:!0},data_attribute_name:"data-scayt-word",misspelled_word_class:"scayt-misspell-word",problem_grammar_data_attribute:"data-grayt-phrase",problem_grammar_class:"gramm-problem"},backCompatibilityMap:{scayt_service_protocol:"scayt_serviceProtocol",scayt_service_host:"scayt_serviceHost", +scayt_service_port:"scayt_servicePort",scayt_service_path:"scayt_servicePath",scayt_customerid:"scayt_customerId"},openDialog:function(a,f){var b=f.scayt;b.isAllModulesReady&&!1===b.isAllModulesReady()||(f.lockSelection(),f.openDialog(a))},alarmCompatibilityMessage:function(){5>this.warningCounter&&(console.warn("You are using the latest version of SCAYT plugin for CKEditor with the old application version. In order to have access to the newest features, it is recommended to upgrade the application version to latest one as well. Contact us for more details at support@webspellchecker.net."), +this.warningCounter+=1)},isNewUdSupported:function(a){return a.getUserDictionary?!0:!1},reloadMarkup:function(a){var f;a&&(f=a.getScaytLangList(),a.reloadMarkup?a.reloadMarkup():(this.alarmCompatibilityMessage(),f&&f.ltr&&f.rtl&&a.fire("startSpellCheck, startGrammarCheck")))},replaceOldOptionsNames:function(a){for(var f in a)f in this.backCompatibilityMap&&(a[this.backCompatibilityMap[f]]=a[f],delete a[f])},createScayt:function(a){var f=this,b=CKEDITOR.plugins.scayt;this.loadScaytLibrary(a,function(a){function d(a){return new SCAYT.CKSCAYT(a, +function(){},function(){})}var l;a.window&&(l="BODY"==a.editable().$.nodeName?a.window.getFrame():a.editable());if(l){l={lang:a.config.scayt_sLang,container:l.$,customDictionary:a.config.scayt_customDictionaryIds,userDictionaryName:a.config.scayt_userDictionaryName,localization:a.langCode,customer_id:a.config.scayt_customerId,customPunctuation:a.config.scayt_customPunctuation,debug:a.config.scayt_debug,data_attribute_name:f.options.data_attribute_name,misspelled_word_class:f.options.misspelled_word_class, +problem_grammar_data_attribute:f.options.problem_grammar_data_attribute,problem_grammar_class:f.options.problem_grammar_class,"options-to-restore":a.config.scayt_disableOptionsStorage,focused:a.editable().hasFocus,ignoreElementsRegex:a.config.scayt_elementsToIgnore,ignoreGraytElementsRegex:a.config.grayt_elementsToIgnore,minWordLength:a.config.scayt_minWordLength,multiLanguageMode:a.config.scayt_multiLanguageMode,multiLanguageStyles:a.config.scayt_multiLanguageStyles,graytAutoStartup:a.config.grayt_autoStartup, +disableCache:a.config.scayt_disableCache,cacheSize:a.config.scayt_cacheSize,charsToObserve:b.charsToObserve};a.config.scayt_serviceProtocol&&(l.service_protocol=a.config.scayt_serviceProtocol);a.config.scayt_serviceHost&&(l.service_host=a.config.scayt_serviceHost);a.config.scayt_servicePort&&(l.service_port=a.config.scayt_servicePort);a.config.scayt_servicePath&&(l.service_path=a.config.scayt_servicePath);"boolean"===typeof a.config.scayt_ignoreAllCapsWords&&(l["ignore-all-caps-words"]=a.config.scayt_ignoreAllCapsWords); +"boolean"===typeof a.config.scayt_ignoreDomainNames&&(l["ignore-domain-names"]=a.config.scayt_ignoreDomainNames);"boolean"===typeof a.config.scayt_ignoreWordsWithMixedCases&&(l["ignore-words-with-mixed-cases"]=a.config.scayt_ignoreWordsWithMixedCases);"boolean"===typeof a.config.scayt_ignoreWordsWithNumbers&&(l["ignore-words-with-numbers"]=a.config.scayt_ignoreWordsWithNumbers);var k;try{k=d(l)}catch(g){f.alarmCompatibilityMessage(),delete l.charsToObserve,k=d(l)}k.subscribe("suggestionListSend", +function(a){for(var b={},c=[],d=0;d=parseInt(a.getAttribute("border"),10))&&a.addClass("cke_show_border")})},afterInit:function(a){var b=a.dataProcessor;a=b&&b.dataFilter;b=b&&b.htmlFilter;a&&a.addRules({elements:{table:function(a){a=a.attributes;var b=a["class"],f=parseInt(a.border,10);f&&!(0>=f)||b&&-1!=b.indexOf("cke_show_border")||(a["class"]=(b||"")+" cke_show_border")}}});b&&b.addRules({elements:{table:function(a){a=a.attributes;var b=a["class"];b&&(a["class"]=b.replace("cke_show_border","").replace(/\s{2}/," ").replace(/^\s+|\s+$/, +""))}}})}});CKEDITOR.on("dialogDefinition",function(a){var b=a.data.name;if("table"==b||"tableProperties"==b)if(a=a.data.definition,b=a.getContents("info").get("txtBorder"),b.commit=CKEDITOR.tools.override(b.commit,function(a){return function(b,f){a.apply(this,arguments);var k=parseInt(this.getValue(),10);f[!k||0>=k?"addClass":"removeClass"]("cke_show_border")}}),a=(a=a.getContents("advanced"))&&a.get("advCSSClasses"))a.setup=CKEDITOR.tools.override(a.setup,function(a){return function(){a.apply(this, +arguments);this.setValue(this.getValue().replace(/cke_show_border/,""))}}),a.commit=CKEDITOR.tools.override(a.commit,function(a){return function(b,f){a.apply(this,arguments);parseInt(f.getAttribute("border"),10)||f.addClass("cke_show_border")}})})}(),function(){CKEDITOR.plugins.add("sourcearea",{init:function(f){function b(){var a=d&&this.equals(CKEDITOR.document.getActive());this.hide();this.setStyle("height",this.getParent().$.clientHeight+"px");this.setStyle("width",this.getParent().$.clientWidth+ +"px");this.show();a&&this.focus()}if(f.elementMode!=CKEDITOR.ELEMENT_MODE_INLINE){var c=CKEDITOR.plugins.sourcearea;f.addMode("source",function(c){var d=f.ui.space("contents").getDocument().createElement("textarea");d.setStyles(CKEDITOR.tools.extend({width:CKEDITOR.env.ie7Compat?"99%":"100%",height:"100%",resize:"none",outline:"none","text-align":"left"},CKEDITOR.tools.cssVendorPrefix("tab-size",f.config.sourceAreaTabSize||4)));d.setAttribute("dir","ltr");d.addClass("cke_source").addClass("cke_reset").addClass("cke_enable_context_menu"); +f.ui.space("contents").append(d);d=f.editable(new a(f,d));d.setData(f.getData(1));CKEDITOR.env.ie&&(d.attachListener(f,"resize",b,d),d.attachListener(CKEDITOR.document.getWindow(),"resize",b,d),CKEDITOR.tools.setTimeout(b,0,d));f.fire("ariaWidget",this);c()});f.addCommand("source",c.commands.source);f.ui.addButton&&f.ui.addButton("Source",{label:f.lang.sourcearea.toolbar,command:"source",toolbar:"mode,10"});f.on("mode",function(){f.getCommand("source").setState("source"==f.mode?CKEDITOR.TRISTATE_ON: +CKEDITOR.TRISTATE_OFF)});var d=CKEDITOR.env.ie&&9==CKEDITOR.env.version}}});var a=CKEDITOR.tools.createClass({base:CKEDITOR.editable,proto:{setData:function(a){this.setValue(a);this.status="ready";this.editor.fire("dataReady")},getData:function(){return this.getValue()},insertHtml:function(){},insertElement:function(){},insertText:function(){},setReadOnly:function(a){this[(a?"set":"remove")+"Attribute"]("readOnly","readonly")},detach:function(){a.baseProto.detach.call(this);this.clearCustomData(); +this.remove()}}})}(),CKEDITOR.plugins.sourcearea={commands:{source:{modes:{wysiwyg:1,source:1},editorFocus:!1,readOnly:1,exec:function(a){"wysiwyg"==a.mode&&a.fire("saveSnapshot");a.getCommand("source").setState(CKEDITOR.TRISTATE_DISABLED);a.setMode("source"==a.mode?"wysiwyg":"source")},canUndo:!1}}},CKEDITOR.plugins.add("specialchar",{availableLangs:{af:1,ar:1,az:1,bg:1,ca:1,cs:1,cy:1,da:1,de:1,"de-ch":1,el:1,en:1,"en-au":1,"en-ca":1,"en-gb":1,eo:1,es:1,"es-mx":1,et:1,eu:1,fa:1,fi:1,fr:1,"fr-ca":1, +gl:1,he:1,hr:1,hu:1,id:1,it:1,ja:1,km:1,ko:1,ku:1,lt:1,lv:1,nb:1,nl:1,no:1,oc:1,pl:1,pt:1,"pt-br":1,ro:1,ru:1,si:1,sk:1,sl:1,sq:1,sr:1,"sr-latn":1,sv:1,th:1,tr:1,tt:1,ug:1,uk:1,vi:1,zh:1,"zh-cn":1},requires:"dialog",init:function(a){var f=this;CKEDITOR.dialog.add("specialchar",this.path+"dialogs/specialchar.js");a.addCommand("specialchar",{exec:function(){var b=a.langCode,b=f.availableLangs[b]?b:f.availableLangs[b.replace(/-.*/,"")]?b.replace(/-.*/,""):"en";CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(f.path+ +"dialogs/lang/"+b+".js"),function(){CKEDITOR.tools.extend(a.lang.specialchar,f.langEntries[b]);a.openDialog("specialchar")})},modes:{wysiwyg:1},canUndo:!1});a.ui.addButton&&a.ui.addButton("SpecialChar",{label:a.lang.specialchar.toolbar,command:"specialchar",toolbar:"insert,50"})}}),CKEDITOR.config.specialChars="! \x26quot; # $ % \x26amp; ' ( ) * + - . / 0 1 2 3 4 5 6 7 8 9 : ; \x26lt; \x3d \x26gt; ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ \x26euro; \x26lsquo; \x26rsquo; \x26ldquo; \x26rdquo; \x26ndash; \x26mdash; \x26iexcl; \x26cent; \x26pound; \x26curren; \x26yen; \x26brvbar; \x26sect; \x26uml; \x26copy; \x26ordf; \x26laquo; \x26not; \x26reg; \x26macr; \x26deg; \x26sup2; \x26sup3; \x26acute; \x26micro; \x26para; \x26middot; \x26cedil; \x26sup1; \x26ordm; \x26raquo; \x26frac14; \x26frac12; \x26frac34; \x26iquest; \x26Agrave; \x26Aacute; \x26Acirc; \x26Atilde; \x26Auml; \x26Aring; \x26AElig; \x26Ccedil; \x26Egrave; \x26Eacute; \x26Ecirc; \x26Euml; \x26Igrave; \x26Iacute; \x26Icirc; \x26Iuml; \x26ETH; \x26Ntilde; \x26Ograve; \x26Oacute; \x26Ocirc; \x26Otilde; \x26Ouml; \x26times; \x26Oslash; \x26Ugrave; \x26Uacute; \x26Ucirc; \x26Uuml; \x26Yacute; \x26THORN; \x26szlig; \x26agrave; \x26aacute; \x26acirc; \x26atilde; \x26auml; \x26aring; \x26aelig; \x26ccedil; \x26egrave; \x26eacute; \x26ecirc; \x26euml; \x26igrave; \x26iacute; \x26icirc; \x26iuml; \x26eth; \x26ntilde; \x26ograve; \x26oacute; \x26ocirc; \x26otilde; \x26ouml; \x26divide; \x26oslash; \x26ugrave; \x26uacute; \x26ucirc; \x26uuml; \x26yacute; \x26thorn; \x26yuml; \x26OElig; \x26oelig; \x26#372; \x26#374 \x26#373 \x26#375; \x26sbquo; \x26#8219; \x26bdquo; \x26hellip; \x26trade; \x26#9658; \x26bull; \x26rarr; \x26rArr; \x26hArr; \x26diams; \x26asymp;".split(" "), +function(){CKEDITOR.plugins.add("stylescombo",{requires:"richcombo",init:function(a){var f=a.config,b=a.lang.stylescombo,c={},d=[],l=[];a.on("stylesSet",function(b){if(b=b.data.styles){for(var g,h,m,e=0,n=b.length;e=b)for(g=this.getNextSourceNode(a,CKEDITOR.NODE_ELEMENT);g;){if(g.isVisible()&&0===g.getTabIndex()){l=g;break}g=g.getNextSourceNode(!1,CKEDITOR.NODE_ELEMENT)}else for(g=this.getDocument().getBody().getFirst();g=g.getNextSourceNode(!1,CKEDITOR.NODE_ELEMENT);){if(!c)if(!d&&g.equals(this)){if(d=!0,a){if(!(g=g.getNextSourceNode(!0,CKEDITOR.NODE_ELEMENT)))break;c=1}}else d&&!this.contains(g)&&(c=1);if(g.isVisible()&&!(0>(h=g.getTabIndex()))){if(c&&h==b){l= +g;break}h>b&&(!l||!k||h(g=h.getTabIndex())))if(0>=b){if(c&&0===g){l=h;break}g>k&& +(l=h,k=g)}else{if(c&&g==b){l=h;break}gk)&&(l=h,k=g)}}l&&l.focus()},CKEDITOR.plugins.add("table",{requires:"dialog",init:function(a){function f(a){return CKEDITOR.tools.extend(a||{},{contextSensitive:1,refresh:function(a,b){this.setState(b.contains("table",1)?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED)}})}if(!a.blockless){var b=a.lang.table;a.addCommand("table",new CKEDITOR.dialogCommand("table",{context:"table",allowedContent:"table{width,height,border-collapse}[align,border,cellpadding,cellspacing,summary];caption tbody thead tfoot;th td tr[scope];td{border*,background-color,vertical-align,width,height}[colspan,rowspan];"+ +(a.plugins.dialogadvtab?"table"+a.plugins.dialogadvtab.allowedContent():""),requiredContent:"table",contentTransformations:[["table{width}: sizeToStyle","table[width]: sizeToAttribute"],["td: splitBorderShorthand"],[{element:"table",right:function(a){if(a.styles){var b;if(a.styles.border)b=CKEDITOR.tools.style.parse.border(a.styles.border);else if(CKEDITOR.env.ie&&8===CKEDITOR.env.version){var f=a.styles;f["border-left"]&&f["border-left"]===f["border-right"]&&f["border-right"]===f["border-top"]&& +f["border-top"]===f["border-bottom"]&&(b=CKEDITOR.tools.style.parse.border(f["border-top"]))}b&&b.style&&"solid"===b.style&&b.width&&0!==parseFloat(b.width)&&(a.attributes.border=1);"collapse"==a.styles["border-collapse"]&&(a.attributes.cellspacing=0)}}}]]}));a.addCommand("tableProperties",new CKEDITOR.dialogCommand("tableProperties",f()));a.addCommand("tableDelete",f({exec:function(a){var b=a.elementPath().contains("table",1);if(b){var f=b.getParent(),k=a.editable();1!=f.getChildCount()||f.is("td", +"th")||f.equals(k)||(b=f);a=a.createRange();a.moveToPosition(b,CKEDITOR.POSITION_BEFORE_START);b.remove();a.select()}}}));a.ui.addButton&&a.ui.addButton("Table",{label:b.toolbar,command:"table",toolbar:"insert,30"});CKEDITOR.dialog.add("table",this.path+"dialogs/table.js");CKEDITOR.dialog.add("tableProperties",this.path+"dialogs/table.js");a.addMenuItems&&a.addMenuItems({table:{label:b.menu,command:"tableProperties",group:"table",order:5},tabledelete:{label:b.deleteTable,command:"tableDelete",group:"table", +order:1}});a.on("doubleclick",function(a){a.data.element.is("table")&&(a.data.dialog="tableProperties")});a.contextMenu&&a.contextMenu.addListener(function(){return{tabledelete:CKEDITOR.TRISTATE_OFF,table:CKEDITOR.TRISTATE_OFF}})}}}),function(){function a(a,b){function c(a){return b?b.contains(a)&&a.getAscendant("table",!0).equals(b):!0}function d(a){0d)d=g}return d}function l(b,c){for(var e=p(b)?b:a(b),g=e[0].getAscendant("table"),f=d(e,1),e=d(e),h=c?f:e,k=CKEDITOR.tools.buildTableMap(g),g=[],f=[],e=[],l=k.length,m=0;ml?new CKEDITOR.dom.element(h[0][l+1]):k&&-1!==h[0][k-1].cellIndex?new CKEDITOR.dom.element(h[0][k-1]):new CKEDITOR.dom.element(e.$.parentNode);m.length==b&&(d[0].moveToPosition(e,CKEDITOR.POSITION_AFTER_END),d[0].select(),e.remove());return k}function g(a,b){var c=a.getStartElement().getAscendant({td:1,th:1},!0);if(c){var d=c.clone();d.appendBogus();b?d.insertBefore(c):d.insertAfter(c)}}function h(b){if(b instanceof CKEDITOR.dom.selection){var c= +b.getRanges(),d=a(b),e=d[0]&&d[0].getAscendant("table"),g;a:{var f=0;g=d.length-1;for(var k={},l,n;l=d[f++];)CKEDITOR.dom.element.setMarker(k,l,"delete_cell",!0);for(f=0;l=d[f++];)if((n=l.getPrevious())&&!n.getCustomData("delete_cell")||(n=l.getNext())&&!n.getCustomData("delete_cell")){CKEDITOR.dom.element.clearAllMarkers(k);g=n;break a}CKEDITOR.dom.element.clearAllMarkers(k);f=d[0].getParent();(f=f.getPrevious())?g=f.getLast():(f=d[g].getParent(),g=(f=f.getNext())?f.getChild(0):null)}b.reset();for(b= +d.length-1;0<=b;b--)h(d[b]);g?m(g,!0):e&&(c[0].moveToPosition(e,CKEDITOR.POSITION_BEFORE_START),c[0].select(),e.remove())}else b instanceof CKEDITOR.dom.element&&(c=b.getParent(),1==c.getChildCount()?c.remove():b.remove())}function m(a,b){var c=a.getDocument(),d=CKEDITOR.document;CKEDITOR.env.ie&&10==CKEDITOR.env.version&&(d.focus(),c.focus());c=new CKEDITOR.dom.range(c);c["moveToElementEdit"+(b?"End":"Start")](a)||(c.selectNodeContents(a),c.collapse(b?!1:!0));c.select(!0)}function e(a,b,c){a=a[b]; +if("undefined"==typeof c)return a;for(b=0;a&&bg.length)||(f=b.getCommonAncestor())&&f.type==CKEDITOR.NODE_ELEMENT&&f.is("table"))return!1;var h;b=g[0];f=b.getAscendant("table");var k=CKEDITOR.tools.buildTableMap(f),l=k.length,m=k[0].length,n=b.getParent().$.rowIndex,q=e(k,n,b);if(c){var p;try{var u=parseInt(b.getAttribute("rowspan"),10)||1; +h=parseInt(b.getAttribute("colspan"),10)||1;p=k["up"==c?n-u:"down"==c?n+u:n]["left"==c?q-h:"right"==c?q+h:q]}catch(y){return!1}if(!p||b.$==p)return!1;g["up"==c||"left"==c?"unshift":"push"](new CKEDITOR.dom.element(p))}c=b.getDocument();var L=n,u=p=0,G=!d&&new CKEDITOR.dom.documentFragment(c),D=0;for(c=0;c=m?b.removeAttribute("rowSpan"):b.$.rowSpan=p;p>=l?b.removeAttribute("colSpan"):b.$.colSpan=u;d=new CKEDITOR.dom.nodeList(f.$.rows);g=d.count();for(c=g-1;0<=c;c--)f=d.getItem(c),f.$.cells.length||(f.remove(),g++);return b} +function q(b,c){var d=a(b);if(1l){g.insertBefore(new CKEDITOR.dom.element(q));break}else q=null;q||f.append(g)}else for(m=n=1,f=g.clone(),f.insertAfter(g),f.append(g=d.clone()), +q=e(h,k),l=0;lc);n++){k[l+n]||(k[l+n]=[]);for(var q=0;q=d)break}}return k},function(){function a(a){return CKEDITOR.plugins.widget&&CKEDITOR.plugins.widget.isDomWidget(a)}function f(a, +b){var c=a.getAscendant("table"),d=b.getAscendant("table"),e=CKEDITOR.tools.buildTableMap(c),g=m(a),f=m(b),h=[],k={},l,n;c.contains(d)&&(b=b.getAscendant({td:1,th:1}),f=m(b));g>f&&(c=g,g=f,f=c,c=a,a=b,b=c);for(c=0;cn&&(c=l,l=n,n=c);for(c=g;c<=f;c++)for(g=l;g<=n;g++)d=new CKEDITOR.dom.element(e[c][g]),d.$&&!d.getCustomData("selected_cell")&&(h.push(d),CKEDITOR.dom.element.setMarker(k,d,"selected_cell", +!0));CKEDITOR.dom.element.clearAllMarkers(k);return h}function b(a){if(a)return a=a.clone(),a.enlarge(CKEDITOR.ENLARGE_ELEMENT),(a=a.getEnclosedNode())&&a.is&&a.is(CKEDITOR.dtd.$tableContent)}function c(a){return(a=a.editable().findOne(".cke_table-faked-selection"))&&a.getAscendant("table")}function d(a,b){var c=a.editable().find(".cke_table-faked-selection"),d=a.editable().findOne("[data-cke-table-faked-selection-table]"),e;a.fire("lockSnapshot");a.editable().removeClass("cke_table-faked-selection-editor"); +for(e=0;eb.count()||(b=f(b.getItem(0),b.getItem(b.count()-1)), +l(a,b))}function g(b,c,e){var g=r(b.getSelection(!0));c=c.is("table")?null:c;var h;(h=v.active&&!v.first)&&!(h=c)&&(h=b.getSelection().getRanges(),h=1CKEDITOR.env.version,l=a.blockless||CKEDITOR.env.ie?"span":"div",m,n,p,q;g.getById("cke_table_copybin")||(m=g.createElement(l),n=g.createElement(l),n.setAttributes({id:"cke_table_copybin","data-cke-temp":"1"}),m.setStyles({position:"absolute",width:"1px", +height:"1px",overflow:"hidden"}),m.setStyle("ltr"==a.config.contentsLangDirection?"left":"right","-5000px"),m.setHtml(a.getSelectedHtml(!0)),a.fire("lockSnapshot"),n.append(m),a.editable().append(n),q=a.on("selectionChange",c,null,null,0),k&&(p=h.scrollTop),f.selectNodeContents(m),f.select(),k&&(h.scrollTop=p),setTimeout(function(){n.remove();d.selectBookmarks(e);q.removeListener();a.fire("unlockSnapshot");b&&(a.extractSelectedHtml(),a.fire("saveSnapshot"))},100))}function y(a){var b=a.editor||a.sender.editor, +c=b.getSelection();c.isInTable()&&(c.getRanges()[0]._getTableElement({table:1}).hasAttribute("data-cke-tableselection-ignored")||q(b,"cut"===a.name))}function u(a){this._reset();a&&this.setSelectedCells(a)}function p(a,b,c){a.on("beforeCommandExec",function(c){-1!==CKEDITOR.tools.array.indexOf(b,c.data.name)&&(c.data.selectedCells=r(a.getSelection()))});a.on("afterCommandExec",function(d){-1!==CKEDITOR.tools.array.indexOf(b,d.data.name)&&c(a,d.data)})}var v={active:!1},w,r,z,t,x;u.prototype={};u.prototype._reset= +function(){this.cells={first:null,last:null,all:[]};this.rows={first:null,last:null}};u.prototype.setSelectedCells=function(a){this._reset();a=a.slice(0);this._arraySortByDOMOrder(a);this.cells.all=a;this.cells.first=a[0];this.cells.last=a[a.length-1];this.rows.first=a[0].getAscendant("tr");this.rows.last=this.cells.last.getAscendant("tr")};u.prototype.getTableMap=function(){var a=z(this.cells.first),b;a:{b=this.cells.last;var c=b.getAscendant("table"),d=m(b),c=CKEDITOR.tools.buildTableMap(c),e;for(e= +0;e=a)return;for(var d=this.cells.first.$.cellIndex,e=this.cells.last.$.cellIndex,g=c?[]:this.cells.all,f,h=0;h=d&&a.$.cellIndex<=e}),g=b?f.concat(g):g.concat(f);this.setSelectedCells(g)};u.prototype.insertColumn=function(a){function b(a){a=m(a);return a>=e&&a<=g}if("undefined"===typeof a)a=1;else if(0>=a)return;for(var c=this.cells,d=c.all,e=m(c.first),g=m(c.last),c=0;cg)l[0].moveToElementEditablePosition(k?m:n,!k),h.selectRanges([l[0]]); +else if(13!==g||13===f||f===CKEDITOR.SHIFT+13){for(e=0;eCKEDITOR.env.version)},onLoad:function(){w=CKEDITOR.plugins.tabletools;r=w.getSelectedCells;z=w.getCellColIndex;t=w.insertRow;x=w.insertColumn; +CKEDITOR.document.appendStyleSheet(this.path+"styles/tableselection.css")},init:function(a){this.isSupportedEnvironment()&&(a.addContentsCss&&a.addContentsCss(this.path+"styles/tableselection.css"),a.on("contentDom",function(){var b=a.editable(),c=b.isInline()?b:a.document,d={editor:a};b.attachListener(c,"mousedown",e,null,d);b.attachListener(c,"mousemove",e,null,d);b.attachListener(c,"mouseup",e,null,d);b.attachListener(b,"dragstart",n);b.attachListener(a,"selectionCheck",h);CKEDITOR.plugins.tableselection.keyboardIntegration(a); +CKEDITOR.plugins.clipboard&&!CKEDITOR.plugins.clipboard.isCustomCopyCutSupported&&(b.attachListener(b,"cut",y),b.attachListener(b,"copy",y))}),a.on("paste",A.onPaste,A),p(a,"rowInsertBefore rowInsertAfter columnInsertBefore columnInsertAfter cellInsertBefore cellInsertAfter".split(" "),function(a,b){l(a,b.selectedCells)}),p(a,["cellMerge","cellMergeRight","cellMergeDown"],function(a,b){l(a,[b.commandData.cell])}),p(a,["cellDelete"],function(a){d(a,!0)}))}})}(),"use strict",function(){var a=[CKEDITOR.CTRL+ +90,CKEDITOR.CTRL+89,CKEDITOR.CTRL+CKEDITOR.SHIFT+90],f={8:1,46:1};CKEDITOR.plugins.add("undo",{init:function(c){function d(a){e.enabled&&!1!==a.data.command.canUndo&&e.save()}function f(){e.enabled=c.readOnly?!1:"wysiwyg"==c.mode;e.onChange()}var e=c.undoManager=new b(c),k=e.editingHandler=new l(e),q=c.addCommand("undo",{exec:function(){e.undo()&&(c.selectionChange(),this.fire("afterUndo"))},startDisabled:!0,canUndo:!1}),y=c.addCommand("redo",{exec:function(){e.redo()&&(c.selectionChange(),this.fire("afterRedo"))}, +startDisabled:!0,canUndo:!1});c.setKeystroke([[a[0],"undo"],[a[1],"redo"],[a[2],"redo"]]);e.onChange=function(){q.setState(e.undoable()?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED);y.setState(e.redoable()?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED)};c.on("beforeCommandExec",d);c.on("afterCommandExec",d);c.on("saveSnapshot",function(a){e.save(a.data&&a.data.contentOnly)});c.on("contentDom",k.attachListeners,k);c.on("instanceReady",function(){c.fire("saveSnapshot")});c.on("beforeModeUnload", +function(){"wysiwyg"==c.mode&&e.save(!0)});c.on("mode",f);c.on("readOnly",f);c.ui.addButton&&(c.ui.addButton("Undo",{label:c.lang.undo.undo,command:"undo",toolbar:"undo,10"}),c.ui.addButton("Redo",{label:c.lang.undo.redo,command:"redo",toolbar:"undo,20"}));c.resetUndo=function(){e.reset();c.fire("saveSnapshot")};c.on("updateSnapshot",function(){e.currentImage&&e.update()});c.on("lockSnapshot",function(a){a=a.data;e.lock(a&&a.dontUpdate,a&&a.forceUpdate)});c.on("unlockSnapshot",e.unlock,e)}});CKEDITOR.plugins.undo= +{};var b=CKEDITOR.plugins.undo.UndoManager=function(a){this.strokesRecorded=[0,0];this.locked=null;this.previousKeyGroup=-1;this.limit=a.config.undoStackSize||20;this.strokesLimit=25;this.editor=a;this.reset()};b.prototype={type:function(a,c){var d=b.getKeyGroup(a),e=this.strokesRecorded[d]+1;c=c||e>=this.strokesLimit;this.typing||(this.hasUndo=this.typing=!0,this.hasRedo=!1,this.onChange());c?(e=0,this.editor.fire("saveSnapshot")):this.editor.fire("change");this.strokesRecorded[d]=e;this.previousKeyGroup= +d},keyGroupChanged:function(a){return b.getKeyGroup(a)!=this.previousKeyGroup},reset:function(){this.snapshots=[];this.index=-1;this.currentImage=null;this.hasRedo=this.hasUndo=!1;this.locked=null;this.resetType()},resetType:function(){this.strokesRecorded=[0,0];this.typing=!1;this.previousKeyGroup=-1},refreshState:function(){this.hasUndo=!!this.getNextImage(!0);this.hasRedo=!!this.getNextImage(!1);this.resetType();this.onChange()},save:function(a,b,d){var e=this.editor;if(this.locked||"ready"!=e.status|| +"wysiwyg"!=e.mode)return!1;var f=e.editable();if(!f||"ready"!=f.status)return!1;f=this.snapshots;b||(b=new c(e));if(!1===b.contents)return!1;if(this.currentImage)if(b.equalsContent(this.currentImage)){if(a||b.equalsSelection(this.currentImage))return!1}else!1!==d&&e.fire("change");f.splice(this.index+1,f.length-this.index-1);f.length==this.limit&&f.shift();this.index=f.push(b)-1;this.currentImage=b;!1!==d&&this.refreshState();return!0},restoreImage:function(a){var b=this.editor,c;a.bookmarks&&(b.focus(), +c=b.getSelection());this.locked={level:999};this.editor.loadSnapshot(a.contents);a.bookmarks?c.selectBookmarks(a.bookmarks):CKEDITOR.env.ie&&(c=this.editor.document.getBody().$.createTextRange(),c.collapse(!0),c.select());this.locked=null;this.index=a.index;this.currentImage=this.snapshots[this.index];this.update();this.refreshState();b.fire("change")},getNextImage:function(a){var b=this.snapshots,c=this.currentImage,d;if(c)if(a)for(d=this.index-1;0<=d;d--){if(a=b[d],!c.equalsContent(a))return a.index= +d,a}else for(d=this.index+1;d=this.undoManager.strokesLimit&&(this.undoManager.type(a.keyCode,!0),this.keyEventsStack.resetInputs())}},onKeyup:function(a){var d=this.undoManager; +a=a.data.getKey();var f=this.keyEventsStack.getTotalInputs();this.keyEventsStack.remove(a);if(!(b.ieFunctionalKeysBug(a)&&this.lastKeydownImage&&this.lastKeydownImage.equalsContent(new c(d.editor,!0))))if(0=this.rect.right||a<=this.rect.top||a>=this.rect.bottom)&&this.hideVisible();(0>=b||b>=this.winTopPane.width||0>=a||a>=this.winTopPane.height)&&this.hideVisible()},this);c.attachListener(a,"resize",f);c.attachListener(a,"mode",k);a.on("destroy",k);this.lineTpl=(new CKEDITOR.template('\x3cdiv data-cke-lineutils-line\x3d"1" class\x3d"cke_reset_all" style\x3d"{lineStyle}"\x3e\x3cspan style\x3d"{tipLeftStyle}"\x3e\x26nbsp;\x3c/span\x3e\x3cspan style\x3d"{tipRightStyle}"\x3e\x26nbsp;\x3c/span\x3e\x3c/div\x3e')).output({lineStyle:CKEDITOR.tools.writeCssText(CKEDITOR.tools.extend({}, +l,this.lineStyle,!0)),tipLeftStyle:CKEDITOR.tools.writeCssText(CKEDITOR.tools.extend({},d,{left:"0px","border-left-color":"red","border-width":"6px 0 6px 6px"},this.tipCss,this.tipLeftStyle,!0)),tipRightStyle:CKEDITOR.tools.writeCssText(CKEDITOR.tools.extend({},d,{right:"0px","border-right-color":"red","border-width":"6px 6px 6px 0"},this.tipCss,this.tipRightStyle,!0))})}function c(a){var b;if(b=a&&a.type==CKEDITOR.NODE_ELEMENT)b=!(k[a.getComputedStyle("float")]||k[a.getAttribute("align")]);return b&& +!g[a.getComputedStyle("position")]}CKEDITOR.plugins.add("lineutils");CKEDITOR.LINEUTILS_BEFORE=1;CKEDITOR.LINEUTILS_AFTER=2;CKEDITOR.LINEUTILS_INSIDE=4;a.prototype={start:function(a){var b=this,c=this.editor,d=this.doc,f,g,k,l,v=CKEDITOR.tools.eventsBuffer(50,function(){c.readOnly||"wysiwyg"!=c.mode||(b.relations={},(g=d.$.elementFromPoint(k,l))&&g.nodeType&&(f=new CKEDITOR.dom.element(g),b.traverseSearch(f),isNaN(k+l)||b.pixelSearch(f,k,l),a&&a(b.relations,k,l)))});this.listener=this.editable.attachListener(this.target, +"mousemove",function(a){k=a.data.$.clientX;l=a.data.$.clientY;v.input()});this.editable.attachListener(this.inline?this.editable:this.frame,"mouseout",function(){v.reset()})},stop:function(){this.listener&&this.listener.removeListener()},getRange:function(){var a={};a[CKEDITOR.LINEUTILS_BEFORE]=CKEDITOR.POSITION_BEFORE_START;a[CKEDITOR.LINEUTILS_AFTER]=CKEDITOR.POSITION_AFTER_END;a[CKEDITOR.LINEUTILS_INSIDE]=CKEDITOR.POSITION_AFTER_START;return function(b){var c=this.editor.createRange();c.moveToPosition(this.relations[b.uid].element, +a[b.type]);return c}}(),store:function(){function a(b,c,d){var f=b.getUniqueId();f in d?d[f].type|=c:d[f]={element:b,type:c}}return function(b,d){var f;d&CKEDITOR.LINEUTILS_AFTER&&c(f=b.getNext())&&f.isVisible()&&(a(f,CKEDITOR.LINEUTILS_BEFORE,this.relations),d^=CKEDITOR.LINEUTILS_AFTER);d&CKEDITOR.LINEUTILS_INSIDE&&c(f=b.getFirst())&&f.isVisible()&&(a(f,CKEDITOR.LINEUTILS_BEFORE,this.relations),d^=CKEDITOR.LINEUTILS_INSIDE);a(b,d,this.relations)}}(),traverseSearch:function(a){var b,d,f;do if(f=a.$["data-cke-expando"], +!(f&&f in this.relations)){if(a.equals(this.editable))break;if(c(a))for(b in this.lookups)(d=this.lookups[b](a))&&this.store(a,d)}while((!a||a.type!=CKEDITOR.NODE_ELEMENT||"true"!=a.getAttribute("contenteditable"))&&(a=a.getParent()))},pixelSearch:function(){function a(d,f,g,h,k){for(var l=0,v;k(g);){g+=h;if(25==++l)break;if(v=this.doc.$.elementFromPoint(f,g))if(v==d)l=0;else if(b(d,v)&&(l=0,c(v=new CKEDITOR.dom.element(v))))return v}}var b=CKEDITOR.env.ie||CKEDITOR.env.webkit?function(a,b){return a.contains(b)}: +function(a,b){return!!(a.compareDocumentPosition(b)&16)};return function(b,d,f){var g=this.win.getViewPaneSize().height,k=a.call(this,b.$,d,f,-1,function(a){return 0this.rect.bottom)return!1;this.inline? +f.left=c.elementRect.left-this.rect.relativeX:(0[^<]*e});0>f&&(f=a._.upcasts.length);a._.upcasts.splice(f,0,[CKEDITOR.tools.bind(b,c),c.name,e])}var e=b.upcast,f=b.upcastPriority||10;e&&("string"==typeof e?d(c, +b,f):d(e,b,f))}function l(a,b){a.focused=null;if(b.isInited()){var c=b.editor.checkDirty();a.fire("widgetBlurred",{widget:b});b.setFocused(!1);!c&&b.editor.resetDirty()}}function k(a){a=a.data;if("wysiwyg"==this.editor.mode){var b=this.editor.editable(),c=this.instances,d,e,g,h;if(b){for(d in c)c[d].isReady()&&!b.contains(c[d].wrapper)&&this.destroy(c[d],!0);if(a&&a.initOnlyNew)c=this.initOnAll();else{var k=b.find(".cke_widget_wrapper"),c=[];d=0;for(e=k.count();dCKEDITOR.tools.indexOf(b,a)&&c.push(a);a=CKEDITOR.tools.indexOf(d,a);0<=a&&d.splice(a,1);return this},focus:function(a){e=a;return this}, +commit:function(){var f=a.focused!==e,g,h;a.editor.fire("lockSnapshot");for(f&&(g=a.focused)&&l(a,g);g=d.pop();)b.splice(CKEDITOR.tools.indexOf(b,g),1),g.isInited()&&(h=g.editor.checkDirty(),g.setSelected(!1),!h&&g.editor.resetDirty());f&&e&&(h=a.editor.checkDirty(),a.focused=e,a.fire("widgetFocused",{widget:e}),e.setFocused(!0),!h&&a.editor.resetDirty());for(;g=c.pop();)b.push(g),g.setSelected(!0);a.editor.fire("unlockSnapshot")}}}function I(a,b,c){var d=0;b=L(b);var e=a.data.classes||{},f;if(b){for(e= +CKEDITOR.tools.clone(e);f=b.pop();)c?e[f]||(d=e[f]=1):e[f]&&(delete e[f],d=1);d&&a.setData("classes",e)}}function J(a){a.cancel()}function E(a,b){var c=a.editor,d=c.document,e=CKEDITOR.env.edge&&16<=CKEDITOR.env.version;if(!d.getById("cke_copybin")){var f=!c.blockless&&!CKEDITOR.env.ie||e?"div":"span",e=d.createElement(f),g=d.createElement(f),f=CKEDITOR.env.ie&&9>CKEDITOR.env.version;g.setAttributes({id:"cke_copybin","data-cke-temp":"1"});e.setStyles({position:"absolute",width:"1px",height:"1px", +overflow:"hidden"});e.setStyle("ltr"==c.config.contentsLangDirection?"left":"right","-5000px");var h=c.createRange();h.setStartBefore(a.wrapper);h.setEndAfter(a.wrapper);e.setHtml('\x3cspan data-cke-copybin-start\x3d"1"\x3e​\x3c/span\x3e'+c.editable().getHtmlFromRange(h).getHtml()+'\x3cspan data-cke-copybin-end\x3d"1"\x3e​\x3c/span\x3e');c.fire("saveSnapshot");c.fire("lockSnapshot");g.append(e);c.editable().append(g);var k=c.on("selectionChange",J,null,null,0),l=a.repository.on("checkSelection",J, +null,null,0);if(f)var m=d.getDocumentElement().$,n=m.scrollTop;h=c.createRange();h.selectNodeContents(e);h.select();f&&(m.scrollTop=n);setTimeout(function(){b||a.focus();g.remove();k.removeListener();l.removeListener();c.fire("unlockSnapshot");b&&!c.readOnly&&(a.repository.del(a),c.fire("saveSnapshot"))},100)}}function L(a){return(a=(a=a.getDefinition().attributes)&&a["class"])?a.split(/\s+/):null}function G(){var a=CKEDITOR.document.getActive(),b=this.editor,c=b.editable();(c.isInline()?c:b.document.getWindow().getFrame()).equals(a)&& +b.focusManager.focus(c)}function D(){CKEDITOR.env.gecko&&this.editor.unlockSelection();CKEDITOR.env.webkit||(this.editor.forceNextSelectionCheck(),this.editor.selectionChange(1))}function N(a){var b=null;a.on("data",function(){var a=this.data.classes,c;if(b!=a){for(c in b)a&&a[c]||this.removeClass(c);for(c in a)this.addClass(c);b=a}})}function Q(a){a.on("data",function(){if(a.wrapper){var b=this.getLabel?this.getLabel():this.editor.lang.widget.label.replace(/%1/,this.pathName||this.element.getName()); +a.wrapper.setAttribute("role","region");a.wrapper.setAttribute("aria-label",b)}},null,null,9999)}function O(a){if(a.draggable){var b=a.editor,c=a.wrapper.getLast(f.isDomDragHandlerContainer),d;c?d=c.findOne("img"):(c=new CKEDITOR.dom.element("span",b.document),c.setAttributes({"class":"cke_reset cke_widget_drag_handler_container",style:"background:rgba(220,220,220,0.5);background-image:url("+b.plugins.widget.path+"images/handle.png)"}),d=new CKEDITOR.dom.element("img",b.document),d.setAttributes({"class":"cke_reset cke_widget_drag_handler", +"data-cke-widget-drag-handler":"1",src:CKEDITOR.tools.transparentImageData,width:15,title:b.lang.widget.move,height:15,role:"presentation"}),a.inline&&d.setAttribute("draggable","true"),c.append(d),a.wrapper.append(c));a.wrapper.on("dragover",function(a){a.data.preventDefault()});a.wrapper.on("mouseenter",a.updateDragHandlerPosition,a);setTimeout(function(){a.on("data",a.updateDragHandlerPosition,a)},50);if(!a.inline&&(d.on("mousedown",K,a),CKEDITOR.env.ie&&9>CKEDITOR.env.version))d.on("dragstart", +function(a){a.data.preventDefault(!0)});a.dragHandlerContainer=c}}function K(a){function b(){var c;for(p.reset();c=h.pop();)c.removeListener();var d=k;c=a.sender;var e=this.repository.finder,f=this.repository.liner,g=this.editor,l=this.editor.editable();CKEDITOR.tools.isEmpty(f.visible)||(d=e.getRange(d[0]),this.focus(),g.fire("drop",{dropRange:d,target:d.startContainer}));l.removeClass("cke_widget_dragging");f.hideVisible();g.fire("dragend",{target:c})}if(CKEDITOR.tools.getMouseButton(a)===CKEDITOR.MOUSE_BUTTON_LEFT){var c= +this.repository.finder,d=this.repository.locator,e=this.repository.liner,f=this.editor,g=f.editable(),h=[],k=[],l,m;this.repository._.draggedWidget=this;var n=c.greedySearch(),p=CKEDITOR.tools.eventsBuffer(50,function(){l=d.locate(n);k=d.sort(m,1);k.length&&(e.prepare(n,l),e.placeLine(k[0]),e.cleanup())});g.addClass("cke_widget_dragging");h.push(g.on("mousemove",function(a){m=a.data.$.clientY;p.input()}));f.fire("dragstart",{target:a.sender});h.push(f.document.once("mouseup",b,this));g.isInline()|| +h.push(CKEDITOR.document.once("mouseup",b,this))}}function W(a){var b,c,d=a.editables;a.editables={};if(a.editables)for(b in d)c=d[b],a.initEditable(b,"string"==typeof c?{selector:c}:c)}function R(a){if(a.mask){var b=a.wrapper.findOne(".cke_widget_mask");b||(b=new CKEDITOR.dom.element("img",a.editor.document),b.setAttributes({src:CKEDITOR.tools.transparentImageData,"class":"cke_reset cke_widget_mask"}),a.wrapper.append(b));a.mask=b}}function Z(a){if(a.parts){var b={},c,d;for(d in a.parts)c=a.wrapper.findOne(a.parts[d]), +b[d]=c;a.parts=b}}function ha(a,b){X(a);Z(a);W(a);R(a);O(a);N(a);Q(a);if(CKEDITOR.env.ie&&9>CKEDITOR.env.version)a.wrapper.on("dragstart",function(b){var c=b.data.getTarget();f.getNestedEditable(a,c)||a.inline&&f.isDomDragHandler(c)||b.data.preventDefault()});a.wrapper.removeClass("cke_widget_new");a.element.addClass("cke_widget_element");a.on("key",function(b){b=b.data.keyCode;if(13==b)a.edit();else{if(b==CKEDITOR.CTRL+67||b==CKEDITOR.CTRL+88){E(a,b==CKEDITOR.CTRL+88);return}if(b in V||CKEDITOR.CTRL& +b||CKEDITOR.ALT&b)return}return!1},null,null,999);a.on("doubleclick",function(b){a.edit()&&b.cancel()});if(b.data)a.on("data",b.data);if(b.edit)a.on("edit",b.edit)}function X(a){(a.wrapper=a.element.getParent()).setAttribute("data-cke-widget-id",a.id)}function U(a){a.element.data("cke-widget-data",encodeURIComponent(JSON.stringify(a.data)))}function ba(){function a(){}function b(a,c,d){return d&&this.checkElement(a)?(a=d.widgets.getByElement(a,!0))&&a.checkStyleActive(this):!1}function c(a){function b(a, +c,d){for(var e=a.length,f=0;f)?(?:<(?:div|span)(?: style="[^"]+")?>)?]*data-cke-copybin-start="1"[^>]*>.?<\/span>([\s\S]+)]*data-cke-copybin-end="1"[^>]*>.?<\/span>(?:<\/(?:div|span)>)?(?:<\/(?:div|span)>)?$/i,V={37:1,38:1,39:1,40:1,8:1,46:1};V[CKEDITOR.SHIFT+121]=1;CKEDITOR.plugins.widget=f;f.repository=a;f.nestedEditable=b}(),function(){function a(a,c,d){this.editor= +a;this.notification=null;this._message=new CKEDITOR.template(c);this._singularMessage=d?new CKEDITOR.template(d):null;this._tasks=[];this._doneTasks=this._doneWeights=this._totalWeights=0}function f(a){this._weight=a||1;this._doneWeight=0;this._isCanceled=!1}CKEDITOR.plugins.add("notificationaggregator",{requires:"notification"});a.prototype={createTask:function(a){a=a||{};var c=!this.notification,d;c&&(this.notification=this._createNotification());d=this._addTask(a);d.on("updated",this._onTaskUpdate, +this);d.on("done",this._onTaskDone,this);d.on("canceled",function(){this._removeTask(d)},this);this.update();c&&this.notification.show();return d},update:function(){this._updateNotification();this.isFinished()&&this.fire("finished")},getPercentage:function(){return 0===this.getTaskCount()?1:this._doneWeights/this._totalWeights},isFinished:function(){return this.getDoneTaskCount()===this.getTaskCount()},getTaskCount:function(){return this._tasks.length},getDoneTaskCount:function(){return this._doneTasks}, +_updateNotification:function(){this.notification.update({message:this._getNotificationMessage(),progress:this.getPercentage()})},_getNotificationMessage:function(){var a=this.getTaskCount(),c={current:this.getDoneTaskCount(),max:a,percentage:Math.round(100*this.getPercentage())};return(1==a&&this._singularMessage?this._singularMessage:this._message).output(c)},_createNotification:function(){return new CKEDITOR.plugins.notification(this.editor,{type:"progress"})},_addTask:function(a){a=new f(a.weight); +this._tasks.push(a);this._totalWeights+=a._weight;return a},_removeTask:function(a){var c=CKEDITOR.tools.indexOf(this._tasks,a);-1!==c&&(a._doneWeight&&(this._doneWeights-=a._doneWeight),this._totalWeights-=a._weight,this._tasks.splice(c,1),this.update())},_onTaskUpdate:function(a){this._doneWeights+=a.data;this.update()},_onTaskDone:function(){this._doneTasks+=1;this.update()}};CKEDITOR.event.implementOn(a.prototype);f.prototype={done:function(){this.update(this._weight)},update:function(a){if(!this.isDone()&& +!this.isCanceled()){a=Math.min(this._weight,a);var c=a-this._doneWeight;this._doneWeight=a;this.fire("updated",c);this.isDone()&&this.fire("done")}},cancel:function(){this.isDone()||this.isCanceled()||(this._isCanceled=!0,this.fire("canceled"))},isDone:function(){return this._weight===this._doneWeight},isCanceled:function(){return this._isCanceled}};CKEDITOR.event.implementOn(f.prototype);CKEDITOR.plugins.notificationAggregator=a;CKEDITOR.plugins.notificationAggregator.task=f}(),"use strict",function(){CKEDITOR.plugins.add("uploadwidget", +{requires:"widget,clipboard,filetools,notificationaggregator",init:function(a){a.filter.allow("*[!data-widget,!data-cke-upload-id]")},isSupportedEnvironment:function(){return CKEDITOR.plugins.clipboard.isFileApiSupported}});CKEDITOR.fileTools||(CKEDITOR.fileTools={});CKEDITOR.tools.extend(CKEDITOR.fileTools,{addUploadWidget:function(a,f,b){var c=CKEDITOR.fileTools,d=a.uploadRepository,l=b.supportedTypes?10:20;if(b.fileToElement)a.on("paste",function(b){b=b.data;var g=a.widgets.registered[f],h=b.dataTransfer, +l=h.getFilesCount(),e=g.loadMethod||"loadAndUpload",n,q;if(!b.dataValue&&l)for(q=0;q=a&&(a="0"+a);return String(a)}function f(c){var d=new Date,d=[d.getFullYear(),d.getMonth()+1,d.getDate(),d.getHours(),d.getMinutes(),d.getSeconds()];b+=1;return"image-"+CKEDITOR.tools.array.map(d,a).join("")+"-"+b+"."+c}var b=0;CKEDITOR.plugins.add("uploadimage", +{requires:"uploadwidget",onLoad:function(){CKEDITOR.addCss(".cke_upload_uploading img{opacity: 0.3}")},isSupportedEnvironment:function(){return CKEDITOR.plugins.clipboard.isFileApiSupported},init:function(a){if(this.isSupportedEnvironment()){var b=CKEDITOR.fileTools,l=b.getUploadUrl(a.config,"image");l&&(b.addUploadWidget(a,"uploadimage",{supportedTypes:/image\/(jpeg|png|gif|bmp)/,uploadUrl:l,fileToElement:function(){var a=new CKEDITOR.dom.element("img");a.setAttribute("src","data:image/gif;base64,R0lGODlhDgAOAIAAAAAAAP///yH5BAAAAAAALAAAAAAOAA4AAAIMhI+py+0Po5y02qsKADs\x3d"); +return a},parts:{img:"img"},onUploading:function(a){this.parts.img.setAttribute("src",a.data)},onUploaded:function(a){var b=this.parts.img.$;this.replaceWith('\x3cimg src\x3d"'+a.url+'" width\x3d"'+(a.responseData.width||b.naturalWidth)+'" height\x3d"'+(a.responseData.height||b.naturalHeight)+'"\x3e')}}),a.on("paste",function(k){if(k.data.dataValue.match(/f.version||f.quirks))};"undefined"==typeof a.plugins.scayt&&a.ui.addButton&&a.ui.addButton("SpellChecker",{label:a.lang.wsc.toolbar,click:function(a){var c=a.elementMode==CKEDITOR.ELEMENT_MODE_INLINE?a.container.getText(): +a.document.getBody().getText();(c=c.replace(/\s/g,""))?a.execCommand("checkspell"):alert("Nothing to check!")},toolbar:"spellchecker,10"});CKEDITOR.dialog.add("checkspell",this.path+(CKEDITOR.env.ie&&7>=CKEDITOR.env.version?"dialogs/wsc_ie.js":window.postMessage?"dialogs/wsc.js":"dialogs/wsc_ie.js"))}}),function(){function a(a){function b(a){var c=!1;e.attachListener(e,"keydown",function(){var b=g.getBody().getElementsByTag(a);if(!c){for(var d=0;dCKEDITOR.env.version&&c.enterMode!=CKEDITOR.ENTER_DIV&&b("div");if(CKEDITOR.env.webkit||CKEDITOR.env.ie&&10this.$.offsetHeight){var d=c.createRange();d[33==b?"moveToElementEditStart": +"moveToElementEditEnd"](this);d.select();a.data.preventDefault()}});CKEDITOR.env.ie&&this.attachListener(g,"blur",function(){try{g.$.selection.empty()}catch(a){}});CKEDITOR.env.iOS&&this.attachListener(g,"touchend",function(){a.focus()});h=c.document.getElementsByTag("title").getItem(0);h.data("cke-title",h.getText());CKEDITOR.env.ie&&(c.document.$.title=this._.docTitle);CKEDITOR.tools.setTimeout(function(){"unloaded"==this.status&&(this.status="ready");c.fire("contentDom");this._.isPendingFocus&& +(c.focus(),this._.isPendingFocus=!1);setTimeout(function(){c.fire("dataReady")},0)},0,this)}function f(a){function b(){var f;a.editable().attachListener(a,"selectionChange",function(){var b=a.getSelection().getSelectedElement();b&&(f&&(f.detachEvent("onresizestart",c),f=null),b.$.attachEvent("onresizestart",c),f=b.$)})}function c(a){a.returnValue=!1}if(CKEDITOR.env.gecko)try{var f=a.document.$;f.execCommand("enableObjectResizing",!1,!a.config.disableObjectResizing);f.execCommand("enableInlineTableEditing", +!1,!a.config.disableNativeTableHandles)}catch(h){}else CKEDITOR.env.ie&&11>CKEDITOR.env.version&&a.config.disableObjectResizing&&b(a)}function b(){var a=[];if(8<=CKEDITOR.document.$.documentMode){a.push("html.CSS1Compat [contenteditable\x3dfalse]{min-height:0 !important}");var b=[],c;for(c in CKEDITOR.dtd.$removeEmpty)b.push("html.CSS1Compat "+c+"[contenteditable\x3dfalse]");a.push(b.join(",")+"{display:inline-block}")}else CKEDITOR.env.gecko&&(a.push("html{height:100% !important}"),a.push("img:-moz-broken{-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}")); +a.push("html{cursor:text;*cursor:auto}");a.push("img,input,textarea{cursor:default}");return a.join("\n")}var c;CKEDITOR.plugins.add("wysiwygarea",{init:function(a){a.config.fullPage&&a.addFeature({allowedContent:"html head title; style [media,type]; body (*)[id]; meta link [*]",requiredContent:"body"});a.addMode("wysiwyg",function(b){function f(e){e&&e.removeListener();a.editable(new c(a,h.$.contentWindow.document.body));a.setData(a.getData(1),b)}var g="document.open();"+(CKEDITOR.env.ie?"("+CKEDITOR.tools.fixDomain+ +")();":"")+"document.close();",g=CKEDITOR.env.air?"javascript:void(0)":CKEDITOR.env.ie&&!CKEDITOR.env.edge?"javascript:void(function(){"+encodeURIComponent(g)+"}())":"",h=CKEDITOR.dom.element.createFromHtml('\x3ciframe src\x3d"'+g+'" frameBorder\x3d"0"\x3e\x3c/iframe\x3e');h.setStyles({width:"100%",height:"100%"});h.addClass("cke_wysiwyg_frame").addClass("cke_reset");g=a.ui.space("contents");g.append(h);var m=CKEDITOR.env.ie&&!CKEDITOR.env.edge||CKEDITOR.env.gecko;if(m)h.on("load",f);var e=a.title, +n=a.fire("ariaEditorHelpLabel",{}).label;e&&(CKEDITOR.env.ie&&n&&(e+=", "+n),h.setAttribute("title",e));if(n){var e=CKEDITOR.tools.getNextId(),q=CKEDITOR.dom.element.createFromHtml('\x3cspan id\x3d"'+e+'" class\x3d"cke_voice_label"\x3e'+n+"\x3c/span\x3e");g.append(q,1);h.setAttribute("aria-describedby",e)}a.on("beforeModeUnload",function(a){a.removeListener();q&&q.remove()});h.setAttributes({tabIndex:a.tabIndex,allowTransparency:"true"});!m&&f();a.fire("ariaWidget",h)})}});CKEDITOR.editor.prototype.addContentsCss= +function(a){var b=this.config,c=b.contentsCss;CKEDITOR.tools.isArray(c)||(b.contentsCss=c?[c]:[]);b.contentsCss.push(a)};c=CKEDITOR.tools.createClass({$:function(){this.base.apply(this,arguments);this._.frameLoadedHandler=CKEDITOR.tools.addFunction(function(b){CKEDITOR.tools.setTimeout(a,0,this,b)},this);this._.docTitle=this.getWindow().getFrame().getAttribute("title")},base:CKEDITOR.editable,proto:{setData:function(a,c){var f=this.editor;if(c)this.setHtml(a),this.fixInitialSelection(),f.fire("dataReady"); +else{this._.isLoadingData=!0;f._.dataStore={id:1};var g=f.config,h=g.fullPage,m=g.docType,e=CKEDITOR.tools.buildStyleHtml(b()).replace(/ + +
+
+
+
+ `); + $('.wrapper').append(skinModal); + + /** + * skin opt + */ + $('#changeSkin').on('click', function () { + $('#skinModal').modal({backdrop: true, keyboard: false}).modal('show'); + }); + + /** + * skin list + */ + var skins = [ + "skin-blue", + "skin-black", + "skin-purple", + "skin-green", + "skin-red", + "skin-yellow", + "skin-blue-light", + "skin-black-light", + "skin-purple-light", + "skin-green-light", + "skin-red-light", + "skin-yellow-light" + ]; + + /** + * skin change + */ + $("[data-skin]").on('click', function (e) { + var skin = $(this).data('skin'); + $.each(skins, function (i) { + $("body").removeClass(skins[i]); + }); + $("body").addClass(skin); + store('admin_skin', skin); + return false; + }); + + /** + * skin init + */ + let skin = loadStore('admin_skin'); + if (skin) { + $.each(skins, function (i) { + $("body").removeClass(skins[i]); + }); + $("body").addClass(skin); + } + + // ---------------------- localStorage ---------------------- + + /** + * store + */ + function store(name, val) { + if (typeof (Storage) !== "undefined") { + localStorage.setItem(name, val); + } else { + window.alert('Please use a modern browser to properly view this template!'); + } + } + + /** + * get + */ + function loadStore(name) { + if (typeof (Storage) !== "undefined") { + return localStorage.getItem(name); + } else { + window.alert('Please use a modern browser to properly view this template!'); + } + } + + // ---------------------- menu, sidebar-toggle ---------------------- + + // init menu speed + $('.sidebar-menu').attr('data-animation-speed', 1); + + // init menu status + let sidebar = loadStore('admin_sidebar_status'); + if ('close' === sidebar) { + $('body').addClass('sidebar-collapse'); + } else { + $('body').removeClass('sidebar-collapse'); + } + + // change menu status + $('.sidebar-toggle').click(function () { + if ('close' === loadStore('admin_sidebar_status')) { + store('admin_sidebar_status', 'open') + } else { + store('admin_sidebar_status', 'close') + } + }); + +}); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/biz/common/admin.tab.css b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/biz/common/admin.tab.css new file mode 100644 index 000000000..41365770c --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/biz/common/admin.tab.css @@ -0,0 +1,230 @@ +/* admin tab start */ +html, +body { + height: 100% !important; + min-height: 0px !important; +} + +body .wrapper { + height: 100% !important; + min-height: 0px !important; +} + +body .content-wrapper { + /*for footer*/ + height: calc(100% - 36px); +} + +body .sidebar { + overflow: hidden; +} + +.content-tabs { + position: relative; + height: 35px; + background: #fafafa; + line-height: 35px; +} + +.content-tabs .roll-nav, +.page-tabs-list { + position: absolute; + width: 40px; + height: 35px; + text-align: center; + color: #999; + z-index: 2; + top: 0; +} + +.content-tabs .roll-left { + left: 0; + border-right: solid 1px #eee; +} + +.content-tabs .roll-right { + right: 0; + border-left: solid 1px #eee; +} + +.content-tabs button { + background: #fff; + border: 0; + height: 35px; + width: 40px; + outline: none; +} + +.content-tabs button:hover { + background: #fafafa; +} + +nav.page-tabs { + margin-left: 40px; + width: 100000px; + height: 35px; + overflow: hidden; +} + +nav.page-tabs .page-tabs-content { + float: left; +} + +.page-tabs a { + display: block; + float: left; + border-right: solid 1px #eee; + padding: 0 15px; +} + +.page-tabs a i:hover { + color: #c00; +} + +.page-tabs a:hover, +.content-tabs .roll-nav:hover { + color: #777; + background: #f2f2f2; + cursor: pointer; +} + +.roll-right.J_tabRight { + right: 200px; +} + +.roll-right.btn-group { + right: 120px; + width: 80px; + padding: 0; +} + +.roll-right.btn-group button { + width: 80px; +} + +.roll-right.J_tabExit, .roll-right.tabReload { + right: 60px; + background: #fff; + height: 35px; + width: 60px; + outline: none; +} + +.roll-right.J_tabExit, .roll-right.fullscreen { + background: #fff; + height: 35px; + width: 60px; + outline: none; +} + +.dropdown-menu-right { + left: auto; +} + +#content-main { + height: calc(100% - 50px); + overflow: hidden; +} + +.fixed-nav #content-main { + height: calc(100% - 80px); + overflow: hidden; +} + +.content-tabs { + height: 37px; + border-bottom: solid 2px #d2d6de; +} + +.page-tabs a { + color: #999; +} + +.page-tabs a i { + color: #ccc; +} + +.page-tabs a.active { + background: #2f4050; + color: #ccc; +} + +.page-tabs a.active:hover, +.page-tabs a.active i:hover { + background: #2f4050; + color: #fff; +} + +/** 遮罩层 **/ +.loaderbox { + display: inline-block; + min-width: 125px; + padding: 10px; + margin: 0 auto; + color: #000 !important; + font-size: 13px; + font-weight: 400; + text-align: center; + vertical-align: middle; + border: 1px solid #ddd; + background-color: #eee; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + -ms-border-radius: 2px; + -o-border-radius: 2px; + border-radius: 2px; + -webkit-box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1); +} + +.loaderbox .loading-activity { + float: left; + width: 18px; + height: 18px; + border: solid 2px transparent; + border-top-color: #000; + border-left-color: #000; + border-radius: 10px; + -webkit-animation: pace-spinner 400ms linear infinite; + -moz-animation: pace-spinner 400ms linear infinite; + -ms-animation: pace-spinner 400ms linear infinite; + -o-animation: pace-spinner 400ms linear infinite; + animation: pace-spinner 400ms linear infinite; +} + +.dropdown-menu { + min-width: 100px; +} + +.main-footer { + height: 37px; + border-top: solid 2px #d2d6de; + padding: 8px 20px 12px 20px; +} + +/* admin tab end */ + +/* nprogress start */ +#nprogress .bar { + background: #FFFFFF !important; +} + +#nprogress .peg { + box-shadow: 0 0 10px #FFFFFF, 0 0 5px #FFFFFF !important; +} + +#nprogress .spinner-icon { + border-top-color: #FFFFFF !important; + border-left-color: #FFFFFF !important; +} + +/* nprogress end */ + +/* menu start */ +.treeview-menu > li > a { + padding-top: 8px; + padding-bottom: 8px; +} + +/* menu end */ diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/biz/common/admin.tab.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/biz/common/admin.tab.js new file mode 100644 index 000000000..5b2e96bed --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/biz/common/admin.tab.js @@ -0,0 +1,588 @@ +/*! +* Admin Tab for XXL-BOOT +* ================ +* +* 1、menu: +* - J_menuItem: 菜单 +* 2、tab: +* - J_tabLeft: 左移按扭 +* - J_menuTabs: +* - J_menuTab : 菜单Tab +* - J_tabRight: 右移按扭 +* - J_tabCloseOther: 关闭其他Tab +* - J_tabCloseAll : 关闭所有Tab +* 3、contont +* - J_mainContent +* - J_iframe : 页面iframe +* +* @author xuxueli +* @repository https://github.com/xuxueli/xxl-boot +*/ +(function ($) { + + $.extend({ + adminTab: { + initTab: function (options) { + + /** + * 点击菜单:打开Tab,展示Menu页面 + */ + $('.J_menuItem').on('click', function () { + // 获取Tab属性 + let tabSrc = $(this).attr('href'); + let tabName = $.trim($(this).text()); + + // open tab + return openTab(tabSrc, tabName); + }); + + /** + * Tab关闭(x按钮):关闭菜单页面 + */ + $('.J_menuTabs').on('click', '.J_menuTab i', closeTab); + + /** + * Tab单击(切换/激活):展示Tab页面 + 左侧菜单active更新 + */ + $('.J_menuTabs').on('click', '.J_menuTab', activeTab); + + /** + * 选项卡-左移按扭:查看左侧隐藏的选项卡 + */ + $('.J_tabLeft').on('click', scrollTabLeft); + + /** + * 选项卡-右移按扭:查看右侧隐藏的选项卡 + */ + $('.J_tabRight').on('click', scrollTabRight); + + /** + * Tab-刷新按钮:刷新active的 Tab 页面 + */ + $('.tabReload').on('click', refreshTab); + + /** + * 关闭其他选项卡 + */ + $('.J_tabCloseOther').on('click', closeOtherTabs); + + /** + * 关闭当前选项卡 + */ + $('.tabCloseCurrent').on('click', tabCloseCurrent); + + /** + * 关闭全部选项卡 + */ + $('.J_tabCloseAll').on('click', tabCloseAll); + + /** + * 全屏显示 + */ + $('#fullScreen').on('click', function () { + let currentHash = window.location.hash; + $(document).toggleFullScreen(); + + // reset + if (currentHash) { + setTimeout(function () { + window.location.hash = currentHash; + }, 50) + } + }); + + /** + * 默认打开菜单Tab:优先尝试打开url路径TAB,兜底打开首个菜单 + */ + openDefaultTab(); + }, + openTab: function (options, isCloseCurrent) { + // 当前页面是否关闭 + if (isCloseCurrent) { + tabCloseCurrent(); + } + // 打开Tab页面 + return openTab(options.tabSrc, options.tabName); + } + } + }); + + // -------------------- tab:open default -------------------- + + /** + * 默认打开菜单Tab:初始化首页菜单,然后 尝试打开url路径TAB + */ + function openDefaultTab() { + // load url + let tabSrc = window.location.hash.slice(1); + + // 1、首页菜单:初始化 + let $firstMenuItem = $(".J_menuItem:first"); + if ($firstMenuItem.length > 0) { + $firstMenuItem.click(); + // 首页菜单特殊逻辑,不允许关闭 + $('.J_menuTab[data-id="' + $firstMenuItem.attr('href') + '"] i').remove(); + } + + // 2、URL匹配到菜单,初始化 + if (tabSrc === '' || tabSrc === undefined || tabSrc === null) { + // URL菜单路径不存在则pass + return; + } + setTimeout(function () { + var $menuItem = $('.J_menuItem').filter('a[href$="' + decodeURI(tabSrc) + '"]'); + if ($menuItem.length > 0) { + // URL匹配到菜单,初始化 + $menuItem.click(); + return; + } else { + // 匹配失败,兜底直接打开 + openTab(tabSrc, tabSrc); + } + }, 100) + + } + + // -------------------- tab:open、close -------------------- + + /** + * 打开Tab:根据 url + 名称 + * + * @param tabSrc + * @param tabName + * @returns {boolean} + */ + function openTab(tabSrc, tabName) { + // 0、valid dateurl + if (tabSrc === undefined || $.trim(tabSrc).length === 0) { + return false; + } + if (tabName === undefined || $.trim(tabName).length === 0) { + tabName = tabSrc; + } + let tabNameShow = tabName.length > 15 ? tabName.substring(0, 15) + '...' : tabName; + + // 1、菜单Menu联动 + 页面锚点(hash参数)更新 + activeMenuAndPath(tabSrc); + + // 2、匹配已存在Tab,切换/active展示 + let tabExist = false; + $('.J_menuTab').each(function () { + // 匹配成功 + if ($(this).data('id') === tabSrc) { + // Tab是否展示,若否则切换展示 + if (!$(this).hasClass('active')) { + $(this).addClass('active').siblings('.J_menuTab').removeClass('active'); + scrollToTab(this); + // 显示Tab对应的内容区 + $('.J_mainContent .J_iframe').each(function () { + if ($(this).data('id') === tabSrc) { + $(this).show().siblings('.J_iframe').hide(); + return false; + } + }); + } + tabExist = true; + return false; + } + }); + if (tabExist) { + return false; + } + + // 3、Tab不存在,初始化新Tab + IFrame + // build Tab (other tab no-active) + $('.J_menuTab').removeClass('active'); + var tabStr = '' + tabNameShow + ' '; + + // build IFrame (other ifame hide) + var iframeStr = ''; + + // 4、添加Tab + IFrame + // append iframe + $('.J_mainContent').find('iframe.J_iframe').hide(); + $('.J_mainContent').append(iframeStr); + // append tab + $('.J_menuTabs .page-tabs-content').append(tabStr); + + // 添加遮罩层 + NProgress.inc(0.2); + NProgress.configure({ + easing: 'ease', // 动画缓动函数 (默认: 'ease') + speed: 500, // 动画速度(毫秒)(默认: 200) + showSpinner: true // 是否显示旋转图标 (默认: true) + }); + NProgress.start(); + + // load iframe + let $iframe = $('.J_mainContent iframe:visible'); + $iframe.on('load', function () { + NProgress.done(); + }).on('error', function () { + NProgress.done(); + // 处理加载失败情况,防止跳转 + console.error('iframe load error, src = ' + $(this).attr('src')); + }); + + // 5、滚动到已激活的Tab + scrollToTab($('.J_menuTab.active')); + return false; + } + + /** + * 关闭Tab:根据点击 Tab元素 + * + * @returns {boolean} + */ + function closeTab() { + // param + var closeTabId = $(this).parents('.J_menuTab').data('id'); + var currentWidth = $(this).parents('.J_menuTab').width(); + + // process + if ($(this).parents('.J_menuTab').hasClass('active')) { + // 1、当前元素处于活动状态 + + // 当前元素后面有同辈元素,使后面的一个元素处于活动状态 + if ($(this).parents('.J_menuTab').next('.J_menuTab').length > 0) { + // 后一个Tab,激活 Tab + var activeId = $(this).parents('.J_menuTab').next('.J_menuTab:eq(0)').data('id'); + $(this).parents('.J_menuTab').next('.J_menuTab:eq(0)').addClass('active'); + + // 后一个Tab,激活 iframe + $('.J_mainContent .J_iframe').each(function () { + if ($(this).data('id') === activeId) { + $(this).show().siblings('.J_iframe').hide(); + return false; + } + }); + + var marginLeftVal = parseInt($('.page-tabs-content').css('margin-left')); + if (marginLeftVal < 0) { + $('.page-tabs-content').animate({ + marginLeft: (marginLeftVal + currentWidth) + 'px' + }, "fast"); + } + + // 移除 当前 Tab + $(this).parents('.J_menuTab').remove(); + + // 移除 当前 iframe + $('.J_mainContent .J_iframe').each(function () { + if ($(this).data('id') === closeTabId) { + $(this).remove(); + return false; + } + }); + } + + // 当前元素后面没有同辈元素,使当前元素的上一个元素处于活动状态 + if ($(this).parents('.J_menuTab').prev('.J_menuTab').length > 0) { + // 前一个Tab,激活 Tab + var activeId = $(this).parents('.J_menuTab').prev('.J_menuTab:last').data('id'); + $(this).parents('.J_menuTab').prev('.J_menuTab:last').addClass('active'); + + // 前一个Tab,激活 iframe + $('.J_mainContent .J_iframe').each(function () { + if ($(this).data('id') == activeId) { + $(this).show().siblings('.J_iframe').hide(); + return false; + } + }); + + // 移除 当前 Tab + $(this).parents('.J_menuTab').remove(); + + // 移除 当前 iframe + $('.J_mainContent .J_iframe').each(function () { + if ($(this).data('id') === closeTabId) { + $(this).remove(); + return false; + } + }); + } + } else { + // 2、当前元素不处于活动状态 + + // 移除 当前 Tab + $(this).parents('.J_menuTab').remove(); + + // 移除 当前 iframe + $('.J_mainContent .J_iframe').each(function () { + if ($(this).data('id') == closeTabId) { + $(this).remove(); + return false; + } + }); + + // 滚动到active状态 Tab + scrollToTab($('.J_menuTab.active')); + } + + // 3、菜单Menu联动 + 页面锚点(hash参数)更新 + activeMenuAndPath($('.page-tabs-content').find('.active').attr('data-id')); + return false; + } + + /** + * 菜单Menu联动 + 页面锚点(hash参数)更新 + */ + function activeMenuAndPath(tabSrc) { + + // 页面锚点(hash参数)更新 + window.location.hash = tabSrc; + + // 菜单Menu切换/active + $(".sidebar-menu ul li, .sidebar-menu li").removeClass("active"); + $('.J_menuItem').each(function () { + if ($(this).attr('href') === tabSrc) { + + // 菜单Menu切换/active + $(this).parents("li").addClass("active"); + + + return true; + } + }) + return false; + } + + /** + * Tab单击(切换/激活):展示Tab页面 + 左侧菜单active更新 + */ + function activeTab() { + // 是否已激活 active,避免重复处理 + if (!$(this).hasClass('active')) { + // 待激活Tab信息 + let tabSrc = $(this).data('id'); + + // Ifame 切换展示 + $('.J_mainContent .J_iframe').each(function () { + if ($(this).data('id') === tabSrc) { + $(this).show().siblings('.J_iframe').hide(); + return false; + } + }); + + // Tab 激活 + $(this).addClass('active').siblings('.J_menuTab').removeClass('active'); + scrollToTab(this); + + // 菜单Menu联动 + activeMenuAndPath(tabSrc); + } + } + + // -------------------- tab: scroll -------------------- + + /** + * 滚动到指定选项卡 + */ + function scrollToTab(element) { + + // 当前元素左侧宽度 + var marginLeftVal = calSumWidth($(element).prevAll()), marginRightVal = calSumWidth($(element).nextAll()); + // Tab外部区域宽度 + var tabOuterWidth = calSumWidth($(".content-tabs").children().not(".J_menuTabs")); + // 可视区域Tab宽度 + var visibleWidth = $(".content-tabs").outerWidth(true) - tabOuterWidth; + // 实际滚动宽度 + var scrollVal = 0; + if ($(".page-tabs-content").outerWidth() < visibleWidth) { + scrollVal = 0; + } else if (marginRightVal <= (visibleWidth - $(element).outerWidth(true) - $(element).next().outerWidth(true))) { + if ((visibleWidth - $(element).next().outerWidth(true)) > marginRightVal) { + scrollVal = marginLeftVal; + var tabElement = element; + while ((scrollVal - $(tabElement).outerWidth()) > ($(".page-tabs-content").outerWidth() - visibleWidth)) { + scrollVal -= $(tabElement).prev().outerWidth(); + tabElement = $(tabElement).prev(); + } + } + } else if (marginLeftVal > (visibleWidth - $(element).outerWidth(true) - $(element).prev().outerWidth(true))) { + scrollVal = marginLeftVal - $(element).prev().outerWidth(true); + } + + // 滚动处理 + $('.page-tabs-content').animate({ + marginLeft: 0 - scrollVal + 'px' + }, "fast"); + } + + /** + * 计算元素集合的总宽度 + */ + function calSumWidth(elements) { + var width = 0; + $(elements).each(function () { + width += $(this).outerWidth(true); + }); + return width; + } + + // -------------------- tab: scroll-left、scroll-right、 -------------------- + + /** + * 选项卡-左移按扭:查看左侧隐藏的选项卡 + */ + function scrollTabLeft() { + + // 当前元素左侧宽度 + var marginLeftVal = Math.abs(parseInt($('.page-tabs-content').css('margin-left'))); + // Tab外部区域宽度 + var tabOuterWidth = calSumWidth($(".content-tabs").children().not(".J_menuTabs")); + // 可视区域tab宽度 + var visibleWidth = $(".content-tabs").outerWidth(true) - tabOuterWidth; + // 实际滚动宽度 + var scrollVal = 0; + if ($(".page-tabs-content").width() < visibleWidth) { + return false; + } else { + var tabElement = $(".J_menuTab:first"); + var offsetVal = 0; + while ((offsetVal + $(tabElement).outerWidth(true)) <= marginLeftVal) {//找到离当前tab最近的元素 + offsetVal += $(tabElement).outerWidth(true); + tabElement = $(tabElement).next(); + } + offsetVal = 0; + if (calSumWidth($(tabElement).prevAll()) > visibleWidth) { + while ((offsetVal + $(tabElement).outerWidth(true)) < (visibleWidth) && tabElement.length > 0) { + offsetVal += $(tabElement).outerWidth(true); + tabElement = $(tabElement).prev(); + } + scrollVal = calSumWidth($(tabElement).prevAll()); + } + } + + // 滚动处理 + $('.page-tabs-content').animate({ + marginLeft: 0 - scrollVal + 'px' + }, "fast"); + } + + /** + * 选项卡-右移按扭:查看右侧隐藏的选项卡 + */ + function scrollTabRight() { + + // 当前元素左侧宽度 + var marginLeftVal = Math.abs(parseInt($('.page-tabs-content').css('margin-left'))); + // 可视区域非tab宽度 + var tabOuterWidth = calSumWidth($(".content-tabs").children().not(".J_menuTabs")); + // 可视区域tab宽度 + var visibleWidth = $(".content-tabs").outerWidth(true) - tabOuterWidth; + // 实际滚动宽度 + var scrollVal = 0; + if ($(".page-tabs-content").width() < visibleWidth) { + return false; + } else { + var tabElement = $(".J_menuTab:first"); + var offsetVal = 0; + while ((offsetVal + $(tabElement).outerWidth(true)) <= marginLeftVal) {//找到离当前tab最近的元素 + offsetVal += $(tabElement).outerWidth(true); + tabElement = $(tabElement).next(); + } + offsetVal = 0; + while ((offsetVal + $(tabElement).outerWidth(true)) < (visibleWidth) && tabElement.length > 0) { + offsetVal += $(tabElement).outerWidth(true); + tabElement = $(tabElement).next(); + } + scrollVal = calSumWidth($(tabElement).prevAll()); + if (scrollVal > 0) { + $('.page-tabs-content').animate({ + marginLeft: 0 - scrollVal + 'px' + }, "fast"); + } + } + } + + // -------------------- tab: refresh、close-other、close-current、close-all -------------------- + + /** + * Tab-刷新按钮:刷新active的 Tab 页面 + */ + function refreshTab() { + + // 显示进度条 + NProgress.inc(0.2); + NProgress.configure({ + easing: 'ease', // 动画缓动函数 (默认: 'ease') + speed: 500, // 动画速度(毫秒)(默认: 200) + showSpinner: true // 是否显示旋转图标 (默认: true) + }); + NProgress.start(); + + // 1、获取当前激活的 Tab + var tabSrc = $('.page-tabs-content').find('.active').attr('data-id'); + var target = $('.J_iframe[data-id="' + tabSrc + '"]'); + var url = target.attr('src'); + + // 2、重新加载页面 + // target.attr('src', url).ready(); + target.attr('src', url).on('load', function () { + NProgress.done(); + + // 3、菜单Menu联动 + 页面锚点(hash参数)更新 + activeMenuAndPath($('.page-tabs-content').find('.active').attr('data-id')); + + }).on('error', function () { + NProgress.done(); + // 处理加载失败情况,防止跳转 + console.error('iframe load error, src = ' + $(this).attr('src')); + }); + } + + /** + * 选项卡-Tab双击:刷新菜单页面 + */ + /*$('.J_menuTabs').on('dblclick', '.J_menuTab', refreshTab);*/ + + /** + * 滚动到已激活的选项卡 + */ + + /*$('.J_tabShowActive').on('click', showActiveTab); + function showActiveTab(){ + scrollToTab($('.J_menuTab.active')); + }*/ + + /** + * 关闭其他选项卡 + */ + function closeOtherTabs() { + $('.page-tabs-content').children("[data-id]").not(":first").not(".active").each(function () { + $('.J_iframe[data-id="' + $(this).data('id') + '"]').remove(); + $(this).remove(); + }); + $('.page-tabs-content').css("margin-left", "0"); + } + + /** + * 关闭当前选项卡 + */ + function tabCloseCurrent() { + $('.page-tabs-content').find('.active i').trigger("click"); + } + + /** + * 关闭全部选项卡 + */ + function tabCloseAll() { + // 保留 第一个 Tab,其他删除(Tab+iframe) + $('.page-tabs-content').children("[data-id]").not(":first").each(function () { + $('.J_iframe[data-id="' + $(this).data('id') + '"]').remove(); + $(this).remove(); + }); + // 第一个 Tab 激活/展示(Tab+iframe) + $('.page-tabs-content').children("[data-id]:first").each(function () { + $('.J_iframe[data-id="' + $(this).data('id') + '"]').show(); + $(this).addClass("active"); + }); + $('.page-tabs-content').css("margin-left", "0"); + + // 菜单Menu联动 + 页面锚点(hash参数)更新 + activeMenuAndPath($('.page-tabs-content').find('.active').attr('data-id')); + } + + +})(jQuery); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/biz/common/admin.table.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/biz/common/admin.table.js new file mode 100644 index 000000000..58f996084 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/biz/common/admin.table.js @@ -0,0 +1,484 @@ +/*! +* Admin Table for XXL-BOOT +* ================ +* +* 1、data_filter: +* searchBtn: 搜索 +* resetBtn: 重置 +* 2、data_operation: +* action: +* - add: 新增 +* - update: 更新 +* - delete: 删除 +* style: +* - selectOnlyOne: 单选 +* - selectAny: 多选 +* 3、data_list +* mainDataTable: 表格 +* +* @author xuxueli +* @repository https://github.com/xuxueli/xxl-boot +*/ +(function ($) { + + $.extend({ + adminTable: { + table: null, + options: {}, + selectIds: function () { + // get select rows + let rows = this.table.bootstrapTable('getSelections'); + // find select ids + return (rows && rows.length > 0) ? rows.map(row => row.id) : []; + }, + selectRows: function () { + // get select rows + return this.table.bootstrapTable('getSelections'); + }, + initTable: function (options) { + // parse param + this.table = $(options.table); + this.options = options; + + // init filter + initSearch(this.table, options); + initReset(options); + + // init table + initAdminTable(this.table, options); + }, + initTreeTable: function (options) { + // parse param + this.table = $(options.table); + + // init filter + initSearch(this.table, options); + initReset(options); + + // init tree table + initAdminTreeTable(this.table, options); + }, + initDelete: function (options) { + initDeleteFun(this.table, options); + }, + initAdd: function (options) { + initAddFun(options); + }, + initUpdate: function (options) { + initUpdateFun(this.table, options); + } + } + }); + + /** + * init search + */ + function initSearch(table, options) { + // search + $('#data_filter .searchBtn').on('click', function () { + + // searchHandler + let searchHandler = options.searchHandler; + if (typeof searchHandler === 'function') { + searchHandler(); + return; + } + + // do search + $(table).bootstrapTable('refresh'); + + }); + } + + /** + * init reset + */ + function initReset(options) { + + // reset + $('#data_filter .resetBtn').on('click', function () { + + // reset + let resetHandler = options.resetHandler; + if (typeof resetHandler === 'function') { + // resetHandler + resetHandler(); + } else { + // do reset + + // input + $('#data_filter input[type="text"]').val(''); + // select + $('#data_filter select').each(function () { + $(this).prop('selectedIndex', 0); + }); + // checkbox + $('#data_filter input[type="checkbox"]').prop('checked', false); + // radio + $('#data_filter input[type="radio"]').prop('checked', false); + } + + // do search + $('#data_filter .searchBtn').click(); + }); + } + + /** + * init admin table + * + * @param table + * @param url + * @param queryParams + * @param columns + */ + function initAdminTable(table, options) { + + // parse param + let url = options.url; + let queryParams = options.queryParams; + let columns = options.columns; + + // init table + $(table).bootstrapTable({ + url: url, + method: "post", + contentType: "application/x-www-form-urlencoded", + queryParamsType: "limit", + queryParams: queryParams, // bootstrapTable -> queryParams + sidePagination: "server", // server side page + responseHandler: function (result) { + // custome + if (options.responseHandler) { + return options.responseHandler(result); + } + + // valid + if (result.code !== 200) { + layer.msg(result.msg || (I18n.system_opt + I18n.system_fail)); + return { + total: 0, + rows: [] + } + } + + // default + return { + "total": result.data.total, + "rows": result.data.data + }; + }, + columns: columns, + clickToSelect: true, // 是否启用点击选中行 + multipleSelectRow: true, // 启动多选行:点击 选择单行,Shift+点击 选择连续行, Commond+点击 非连续选择多行 + sortable: false, // 是否启用排序 + pagination: true, // 是否显示分页 + pageNumber: 1, // 默认第一页 + pageList: [10, 25, 50, 100], // 可供选择的每页的行数(*) + smartDisplay: false, // 当总记录数小于分页数,是否显示可选项 + paginationParts: ['pageInfoShort', 'pageSize', 'pageList'], + paginationPreText: '<<', // 跳转页面的 上一页按钮 + paginationNextText: '>>', // 跳转页面的 下一页按钮 + paginationLoop: false, // 是否循环翻页 + showRefresh: true, // 显示刷新按钮 + showColumns: true, // 显示/隐藏列 + minimumCountColumns: 2, // 最少允许的列数 + // onLoadSuccess: function(data) {} + onAll: function (name, args) { + // filter + if (!(['check.bs.table', "uncheck.bs.table", "check-all.bs.table", "uncheck-all.bs.table", 'post-body.bs.table'].indexOf(name) > -1)) { + return false; + } + var rows = $(table).bootstrapTable('getSelections'); + var selectLen = rows.length; + + if (selectLen > 0) { + $("#data_operation .selectAny").removeClass('disabled'); + } else { + $("#data_operation .selectAny").addClass('disabled'); + } + if (selectLen === 1) { + $("#data_operation .selectOnlyOne").removeClass('disabled'); + } else { + $("#data_operation .selectOnlyOne").addClass('disabled'); + } + } + }); + + // toolbar 样式调整; + var toolbarElement = document.querySelector('.fixed-table-toolbar'); + if (toolbarElement) { + toolbarElement.classList.remove('fixed-table-toolbar'); + } + } + + function initAdminTreeTable(table, options) { + + // parse param + let url = options.url; + let queryParams = options.queryParams; + let columns = options.columns; + + // table + var mainDataTable = $("#data_list").bootstrapTable({ + url: url, + method: "post", + contentType: "application/x-www-form-urlencoded", + queryParams: queryParams, + responseHandler: function (result) { + if (result.code !== 200) { + layer.open({ + icon: '2', + content: result.msg + }); + return; + } + return result.data; + }, + treeEnable: true, + idField: 'id', // 树形id + parentIdField: 'parentId', // 父级字段 + treeShowField: 'name', // 树形字段 + onPostBody: function (data) { + $("#data_list").treegrid({ + treeColumn: 1, // 选择第几列作为树形字段 + initialState: 'expanded', // 默认展开;expanded、collapsed + expanderExpandedClass: 'fa fa-fw fa-minus-square-o', // 树形展开图标 + expanderCollapsedClass: 'fa fa-fw fa-plus-square-o', // 树形折叠图标 + onChange() { + $("#data_list").bootstrapTable('resetView') // 树形表格重绘 + } + }) + }, + columns: columns, + clickToSelect: true, // 是否启用点击选中行 + multipleSelectRow: true, // 启动多选行:点击 选择单行,Shift+点击 选择连续行, Commond+点击 非连续选择多行 + sortable: false, // 是否启用排序 + showRefresh: true, // 显示刷新按钮 + showColumns: true, // 显示/隐藏列 + minimumCountColumns: 2, // 最少允许的列数 + onAll: function (name, args) { + // filter + if (!(['check.bs.table', "uncheck.bs.table", "check-all.bs.table", "uncheck-all.bs.table"].indexOf(name) > -1)) { + return false; + } + var rows = mainDataTable.bootstrapTable('getSelections'); + var selectLen = rows.length; + + if (selectLen > 0) { + $("#data_operation .selectAny").removeClass('disabled'); + } else { + $("#data_operation .selectAny").addClass('disabled'); + } + if (selectLen === 1) { + $("#data_operation .selectOnlyOne").removeClass('disabled'); + } else { + $("#data_operation .selectOnlyOne").addClass('disabled'); + } + } + }); + + // toolbar 样式调整; + var toolbarElement = document.querySelector('.fixed-table-toolbar'); + if (toolbarElement) { + toolbarElement.classList.remove('fixed-table-toolbar'); + } + } + + /** + * init delete + */ + function initDeleteFun(table, options) { + // parse param + let url = options.url; + + // delete + $("#data_operation").on('click', '.delete', function () { + // get select rows + var rows = $(table).bootstrapTable('getSelections'); + + // find select ids + const selectIds = (rows && rows.length > 0) ? rows.map(row => row.id) : []; + if (selectIds.length <= 0) { + layer.msg(I18n.system_please_choose + I18n.system_data); + return; + } + + // do delete + layer.confirm(I18n.system_ok + I18n.system_opt_del + '?', { + icon: 3, + title: I18n.system_tips, + btn: [I18n.system_ok, I18n.system_cancel] + }, function (index) { + layer.close(index); + + $.ajax({ + type: 'POST', + url: url, + data: { + "ids": selectIds + }, + dataType: "json", + success: function (data) { + if (data.code === 200) { + layer.msg(I18n.system_opt_del + I18n.system_success); + // refresh table + $('#data_filter .searchBtn').click(); + } else { + layer.msg(data.msg || I18n.system_opt_del + I18n.system_fail); + } + }, + error: function (xhr, status, error) { + // Handle error + console.log("Error: " + error); + layer.open({ + icon: '2', + content: (I18n.system_opt_del + I18n.system_fail) + }); + } + }); + }); + }); + } + + /** + * init add + */ + function initAddFun(options) { + + // parse param + let url = options.url; + let rules = options.rules; + let messages = options.messages; + let writeFormData = options.writeFormData; + let readFormData = options.readFormData; + + // add + $("#data_operation .add").click(function () { + // reset + addModalValidate.resetForm(); + $("#addModal .form")[0].reset(); + $("#addModal .form .form-group").removeClass("has-error"); + + // write FormData + if (typeof writeFormData === 'function') { + writeFormData(); + } + + // show + $('#addModal').modal({backdrop: false, keyboard: false}).modal('show'); + }); + var addModalValidate = $("#addModal .form").validate({ + errorElement: 'span', + errorClass: 'help-block', + focusInvalid: true, + rules: rules, // jquery.validate -> rules + messages: messages, // jquery.validate -> messages + highlight: function (element) { + $(element).closest('.form-group').addClass('has-error'); + }, + success: function (label) { + label.closest('.form-group').removeClass('has-error'); + label.remove(); + }, + errorPlacement: function (error, element) { + element.parent('div').append(error); + }, + submitHandler: function (form) { + // post + $.post(url, readFormData(), function (data, status) { + if (data.code === 200) { + $('#addModal').modal('hide'); + layer.msg(I18n.system_opt_add + I18n.system_success); + + // refresh table + $('#data_filter .searchBtn').click(); + } else { + layer.open({ + title: I18n.system_tips, + btn: [I18n.system_ok], + content: (data.msg || I18n.system_opt_add + I18n.system_fail), + icon: '2' + }); + } + }); + } + }); + } + + /** + * init update + */ + function initUpdateFun(table, options) { + + // parse param + let url = options.url; + let rules = options.rules; + let messages = options.messages; + let writeFormData = options.writeFormData; + let readFormData = options.readFormData; + + // update + $("#data_operation .update").click(function () { + // get select rows + var rows = $(table).bootstrapTable('getSelections'); + + // find select row + if (rows.length !== 1) { + layer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data); + return; + } + var row = rows[0]; + + // reset + $("#updateModal .form")[0].reset(); + $("#updateModal .form .form-group").removeClass("has-error"); + updateModalValidate.resetForm(); + + // write FormData + writeFormData(row); + + // show + $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show'); + }); + var updateModalValidate = $("#updateModal .form").validate({ + errorElement: 'span', + errorClass: 'help-block', + focusInvalid: true, + highlight: function (element) { + $(element).closest('.form-group').addClass('has-error'); + }, + success: function (label) { + label.closest('.form-group').removeClass('has-error'); + label.remove(); + }, + errorPlacement: function (error, element) { + element.parent('div').append(error); + }, + rules: rules, // jquery.validate -> rules + messages: messages, // jquery.validate -> messages + submitHandler: function (form) { + + // request + var paramData = readFormData(); + + $.post(url, paramData, function (data, status) { + if (data.code === 200) { + $('#updateModal').modal('hide'); + layer.msg(I18n.system_opt_edit + I18n.system_success); + + // refresh table + $('#data_filter .searchBtn').click(); + } else { + layer.open({ + title: I18n.system_tips, + btn: [I18n.system_ok], + content: (data.msg || I18n.system_opt_edit + I18n.system_fail), + icon: '2' + }); + } + }); + } + }); + } + +})(jQuery); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/biz/common/admin.util.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/biz/common/admin.util.js new file mode 100644 index 000000000..5006bbfaf --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/biz/common/admin.util.js @@ -0,0 +1,47 @@ +/*! +* Admin Util for XXL-BOOT +* ================ +* +* 1、openTab: 打开新页面,兼容iframe和window.open +* +* @author xuxueli +* @repository https://github.com/xuxueli/xxl-boot +*/ +$(function () { + + + // ---------------------- openTab ---------------------- + + /** + * 打开新页面,兼容iframe和window.open + * + * @param tabSrc tab访问地址 + * @param tabName tab展示名称 + * @param isCloseCurrent 是否关闭当前页 + */ + window.openTab = function (tabSrc, tabName, isCloseCurrent) { + // open tab + if (window.parent.$.adminTab) { + window.parent.$.adminTab.openTab({ + tabSrc: tabSrc, + tabName: tabName + }, isCloseCurrent) + } else { + if (isCloseCurrent) { + window.open(tabSrc, '_self'); + } else { + window.open(tabSrc, '_blank'); + } + } + } + + // ---------------------- isOpenWithTab ---------------------- + + /** + * 是否在Tab中打开 + */ + window.isOpenWithTab = function () { + return !!window.parent.$.adminTab; + } + +}); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/common.1.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/common.1.js deleted file mode 100644 index 7b736fbc2..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/common.1.js +++ /dev/null @@ -1,164 +0,0 @@ -$(function(){ - - // logout - $("#logoutBtn").click(function(){ - layer.confirm( I18n.logout_confirm , { - icon: 3, - title: I18n.system_tips , - btn: [ I18n.system_ok, I18n.system_cancel ] - }, function(index){ - layer.close(index); - - $.post(base_url + "/logout", function(data, status) { - if (data.code == "200") { - layer.msg( I18n.logout_success ); - setTimeout(function(){ - window.location.href = base_url + "/"; - }, 500); - } else { - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: (data.msg || I18n.logout_fail), - icon: '2' - }); - } - }); - }); - - }); - - // slideToTop - var slideToTop = $("
"); - slideToTop.html(''); - slideToTop.css({ - position: 'fixed', - bottom: '20px', - right: '25px', - width: '40px', - height: '40px', - color: '#eee', - 'font-size': '', - 'line-height': '40px', - 'text-align': 'center', - 'background-color': '#222d32', - cursor: 'pointer', - 'border-radius': '5px', - 'z-index': '99999', - opacity: '.7', - 'display': 'none' - }); - slideToTop.on('mouseenter', function () { - $(this).css('opacity', '1'); - }); - slideToTop.on('mouseout', function () { - $(this).css('opacity', '.7'); - }); - $('.wrapper').append(slideToTop); - $(window).scroll(function () { - if ($(window).scrollTop() >= 150) { - if (!$(slideToTop).is(':visible')) { - $(slideToTop).fadeIn(500); - } - } else { - $(slideToTop).fadeOut(500); - } - }); - $(slideToTop).click(function () { - $("html,body").animate({ // firefox ie not support body, chrome support body. but found that new version chrome not support body too. - scrollTop: 0 - }, 100); - }); - - // left menu status v: js + server + cookie - $('.sidebar-toggle').click(function(){ - var xxljob_adminlte_settings = $.cookie('xxljob_adminlte_settings'); // on=open,off=close - if ('off' == xxljob_adminlte_settings) { - xxljob_adminlte_settings = 'on'; - } else { - xxljob_adminlte_settings = 'off'; - } - $.cookie('xxljob_adminlte_settings', xxljob_adminlte_settings, { expires: 7 }); //$.cookie('the_cookie', '', { expires: -1 }); - }); - - // left menu status v1: js + cookie - /* - var xxljob_adminlte_settings = $.cookie('xxljob_adminlte_settings'); - if (xxljob_adminlte_settings == 'off') { - $('body').addClass('sidebar-collapse'); - } - */ - - - // update pwd - $('#updatePwd').on('click', function(){ - $('#updatePwdModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var updatePwdModalValidate = $("#updatePwdModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - rules : { - oldPassword : { - required : true , - rangelength:[4,20] - }, - password : { - required : true , - rangelength:[4,20] - } - }, - messages : { - oldPassword : { - required : I18n.system_please_input +I18n.change_pwd_field_oldpwd, - rangelength : "密码长度限制为4~20" - }, - password : { - required : I18n.system_please_input +I18n.change_pwd_field_newpwd, - rangelength : "密码长度限制为4~20" - } - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - $.post(base_url + "/user/updatePwd", $("#updatePwdModal .form").serialize(), function(data, status) { - if (data.code == 200) { - $('#updatePwdModal').modal('hide'); - - layer.msg( I18n.change_pwd_suc_to_logout ); - setTimeout(function(){ - $.post(base_url + "/logout", function(data, status) { - if (data.code == 200) { - window.location.href = base_url + "/"; - } else { - layer.open({ - icon: '2', - content: (data.msg|| I18n.logout_fail) - }); - } - }); - }, 500); - } else { - layer.open({ - icon: '2', - content: (data.msg|| I18n.change_pwd + I18n.system_fail ) - }); - } - }); - } - }); - $("#updatePwdModal").on('hide.bs.modal', function () { - $("#updatePwdModal .form")[0].reset(); - updatePwdModalValidate.resetForm(); - $("#updatePwdModal .form .form-group").removeClass("has-error"); - }); - -}); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/index.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/index.js deleted file mode 100644 index 09111c584..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/index.js +++ /dev/null @@ -1,207 +0,0 @@ -/** - * Created by xuxueli on 17/4/24. - */ -$(function () { - - // filter Time - var rangesConf = {}; - rangesConf[I18n.daterangepicker_ranges_today] = [moment().startOf('day'), moment().endOf('day')]; - rangesConf[I18n.daterangepicker_ranges_yesterday] = [moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').endOf('day')]; - rangesConf[I18n.daterangepicker_ranges_this_month] = [moment().startOf('month'), moment().endOf('month')]; - rangesConf[I18n.daterangepicker_ranges_last_month] = [moment().subtract(1, 'months').startOf('month'), moment().subtract(1, 'months').endOf('month')]; - rangesConf[I18n.daterangepicker_ranges_recent_week] = [moment().subtract(1, 'weeks').startOf('day'), moment().endOf('day')]; - rangesConf[I18n.daterangepicker_ranges_recent_month] = [moment().subtract(1, 'months').startOf('day'), moment().endOf('day')]; - - $('#filterTime').daterangepicker({ - autoApply:false, - singleDatePicker:false, - showDropdowns:false, // 是否显示年月选择条件 - timePicker: true, // 是否显示小时和分钟选择条件 - timePickerIncrement: 10, // 时间的增量,单位为分钟 - timePicker24Hour : true, - opens : 'left', //日期选择框的弹出位置 - ranges: rangesConf, - locale : { - format: 'YYYY-MM-DD HH:mm:ss', - separator : ' - ', - customRangeLabel : I18n.daterangepicker_custom_name , - applyLabel : I18n.system_ok , - cancelLabel : I18n.system_cancel , - fromLabel : I18n.daterangepicker_custom_starttime , - toLabel : I18n.daterangepicker_custom_endtime , - daysOfWeek : I18n.daterangepicker_custom_daysofweek.split(',') , // '日', '一', '二', '三', '四', '五', '六' - monthNames : I18n.daterangepicker_custom_monthnames.split(',') , // '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月' - firstDay : 1 - }, - startDate: rangesConf[I18n.daterangepicker_ranges_recent_week][0] , - endDate: rangesConf[I18n.daterangepicker_ranges_recent_week][1] - }, function (start, end, label) { - freshChartDate(start, end); - }); - freshChartDate(rangesConf[I18n.daterangepicker_ranges_recent_week][0], rangesConf[I18n.daterangepicker_ranges_recent_week][1]); - - /** - * fresh Chart Date - * - * @param startDate - * @param endDate - */ - function freshChartDate(startDate, endDate) { - $.ajax({ - type : 'POST', - url : base_url + '/chartInfo', - data : { - 'startDate':startDate.format('YYYY-MM-DD HH:mm:ss'), - 'endDate':endDate.format('YYYY-MM-DD HH:mm:ss') - }, - dataType : "json", - success : function(data){ - if (data.code == 200) { - lineChartInit(data) - pieChartInit(data); - } else { - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: (data.msg || I18n.job_dashboard_report_loaddata_fail ), - icon: '2' - }); - } - } - }); - } - - /** - * line Chart Init - */ - function lineChartInit(data) { - var option = { - title: { - text: I18n.job_dashboard_date_report - }, - tooltip : { - trigger: 'axis', - axisPointer: { - type: 'cross', - label: { - backgroundColor: '#6a7985' - } - } - }, - legend: { - data:[I18n.joblog_status_suc, I18n.joblog_status_fail, I18n.joblog_status_running] - }, - toolbox: { - feature: { - /*saveAsImage: {}*/ - } - }, - grid: { - left: '3%', - right: '4%', - bottom: '3%', - containLabel: true - }, - xAxis : [ - { - type : 'category', - boundaryGap : false, - data : data.content.triggerDayList - } - ], - yAxis : [ - { - type : 'value' - } - ], - series : [ - { - name:I18n.joblog_status_suc, - type:'line', - stack: 'Total', - areaStyle: {normal: {}}, - data: data.content.triggerDayCountSucList - }, - { - name:I18n.joblog_status_fail, - type:'line', - stack: 'Total', - label: { - normal: { - show: true, - position: 'top' - } - }, - areaStyle: {normal: {}}, - data: data.content.triggerDayCountFailList - }, - { - name:I18n.joblog_status_running, - type:'line', - stack: 'Total', - areaStyle: {normal: {}}, - data: data.content.triggerDayCountRunningList - } - ], - color:['#00A65A', '#c23632', '#F39C12'] - }; - - var lineChart = echarts.init(document.getElementById('lineChart')); - lineChart.setOption(option); - } - - /** - * pie Chart Init - */ - function pieChartInit(data) { - var option = { - title : { - text: I18n.job_dashboard_rate_report , - /*subtext: 'subtext',*/ - x:'center' - }, - tooltip : { - trigger: 'item', - formatter: "{b} : {c} ({d}%)" - }, - legend: { - orient: 'vertical', - left: 'left', - data: [I18n.joblog_status_suc, I18n.joblog_status_fail, I18n.joblog_status_running ] - }, - series : [ - { - //name: '分布比例', - type: 'pie', - radius : '55%', - center: ['50%', '60%'], - data:[ - { - name:I18n.joblog_status_suc, - value:data.content.triggerCountSucTotal - }, - { - name:I18n.joblog_status_fail, - value:data.content.triggerCountFailTotal - }, - { - name:I18n.joblog_status_running, - value:data.content.triggerCountRunningTotal - } - ], - itemStyle: { - emphasis: { - shadowBlur: 10, - shadowOffsetX: 0, - shadowColor: 'rgba(0, 0, 0, 0.5)' - } - } - } - ], - color:['#00A65A', '#c23632', '#F39C12'] - }; - var pieChart = echarts.init(document.getElementById('pieChart')); - pieChart.setOption(option); - } - -}); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/jobcode.index.1.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/jobcode.index.1.js deleted file mode 100644 index 668d63470..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/jobcode.index.1.js +++ /dev/null @@ -1,97 +0,0 @@ -$(function() { - - // init code editor - var codeEditor; - function initIde(glueSource) { - if (codeEditor == null) { - codeEditor = CodeMirror(document.getElementById("ideWindow"), { - mode : ideMode, - lineNumbers : true, - matchBrackets : true, - value: glueSource - }); - } else { - codeEditor.setValue(glueSource); - } - } - - initIde($("#version_now").val()); - - // code change - $(".source_version").click(function(){ - var sourceId = $(this).attr('version'); - var temp = $( "#" + sourceId ).val(); - - //codeEditor.setValue(''); - initIde(temp); - }); - - // code source save - $("#save").click(function() { - $('#saveModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - - $("#saveModal .ok").click(function() { - - var glueSource = codeEditor.getValue(); - var glueRemark = $("#glueRemark").val(); - - if (!glueRemark) { - layer.open({ - title: I18n.system_tips, - btn: [ I18n.system_ok], - content: I18n.system_please_input + I18n.jobinfo_glue_remark , - icon: '2' - }); - return; - } - if (glueRemark.length <4 || glueRemark.length > 100) { - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: I18n.jobinfo_glue_remark_limit , - icon: '2' - }); - return; - } - - $.ajax({ - type : 'POST', - url : base_url + '/jobcode/save', - data : { - 'id' : id, - 'glueSource' : glueSource, - 'glueRemark' : glueRemark - }, - dataType : "json", - success : function(data){ - if (data.code == 200) { - layer.open({ - title: I18n.system_tips, - btn: [ I18n.system_ok ], - content: (I18n.system_save + I18n.system_success) , - icon: '1', - end: function(layero, index){ - //$(window).unbind('beforeunload'); - window.location.reload(); - } - }); - } else { - layer.open({ - title: I18n.system_tips, - btn: [ I18n.system_ok ], - content: (data.msg || (I18n.system_save + I18n.system_fail) ), - icon: '2' - }); - } - } - }); - - }); - - // before upload - /*$(window).bind('beforeunload',function(){ - return 'Glue尚未保存,确定离开Glue编辑器?'; - });*/ - -}); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/jobgroup.index.1.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/jobgroup.index.1.js deleted file mode 100644 index 0e5b23565..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/jobgroup.index.1.js +++ /dev/null @@ -1,370 +0,0 @@ -$(function() { - - // init date tables - var jobGroupTable = $("#jobgroup_list").dataTable({ - "deferRender": true, - "processing" : true, - "serverSide": true, - "ajax": { - url: base_url + "/jobgroup/pageList", - type:"post", - data : function ( d ) { - var obj = {}; - obj.appname = $('#appname').val(); - obj.title = $('#title').val(); - obj.start = d.start; - obj.length = d.length; - return obj; - } - }, - "searching": false, - "ordering": false, - //"scrollX": true, // scroll x,close self-adaption - "columns": [ - { - "data": 'id', - "visible" : false - }, - { - "data": 'appname', - "visible" : true, - "width":'30%' - }, - { - "data": 'title', - "visible" : true, - "width":'30%' - }, - { - "data": 'addressType', - "width":'10%', - "visible" : true, - "render": function ( data, type, row ) { - if (row.addressType == 0) { - return I18n.jobgroup_field_addressType_0; - } else { - return I18n.jobgroup_field_addressType_1; - } - } - }, - { - "data": 'registryList', - "width":'15%', - "visible" : true, - "render": function ( data, type, row ) { - return row.registryList - ?'' - + I18n.system_show +' ( ' + row.registryList.length+ ' )' - :I18n.system_empty; - } - }, - { - "data": I18n.system_opt , - "width":'15%', - "render": function ( data, type, row ) { - return function(){ - // data - tableData['key'+row.id] = row; - - // opt - var html = '
\n' + - ' \n' + - ' \n' + - ' \n' + - '
'; - - return html; - }; - } - } - ], - "language" : { - "sProcessing" : I18n.dataTable_sProcessing , - "sLengthMenu" : I18n.dataTable_sLengthMenu , - "sZeroRecords" : I18n.dataTable_sZeroRecords , - "sInfo" : I18n.dataTable_sInfo , - "sInfoEmpty" : I18n.dataTable_sInfoEmpty , - "sInfoFiltered" : I18n.dataTable_sInfoFiltered , - "sInfoPostFix" : "", - "sSearch" : I18n.dataTable_sSearch , - "sUrl" : "", - "sEmptyTable" : I18n.dataTable_sEmptyTable , - "sLoadingRecords" : I18n.dataTable_sLoadingRecords , - "sInfoThousands" : ",", - "oPaginate" : { - "sFirst" : I18n.dataTable_sFirst , - "sPrevious" : I18n.dataTable_sPrevious , - "sNext" : I18n.dataTable_sNext , - "sLast" : I18n.dataTable_sLast - }, - "oAria" : { - "sSortAscending" : I18n.dataTable_sSortAscending , - "sSortDescending" : I18n.dataTable_sSortDescending - } - } - }); - - // table data - var tableData = {}; - - // search btn - $('#searchBtn').on('click', function(){ - jobGroupTable.fnDraw(); - }); - - // job registryinfo - $("#jobgroup_list").on('click', '.show_registryList',function() { - var id = $(this).attr("_id"); - var row = tableData['key'+id]; - - /*var html = '
'; - if (row.registryList) { - for (var index in row.registryList) { - html += (parseInt(index)+1) + '. ' + row.registryList[index] + '
'; - } - } - html += '
'; - - layer.open({ - title: I18n.jobinfo_opt_registryinfo , - btn: [ I18n.system_ok ], - content: html - });*/ - - var html = ''; - if (row.registryList) { - for (var index in row.registryList) { - html += ''; - html += ''; - } - } - html += '
' + (parseInt(index)+1) + '' + row.registryList[index] + '
'; - - $('#showRegistryListModal .data').html(html); - $('#showRegistryListModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - - - // opt_del - $("#jobgroup_list").on('click', '.opt_del',function() { - var id = $(this).parents('ul').attr("_id"); - - layer.confirm( (I18n.system_ok + I18n.jobgroup_del + '?') , { - icon: 3, - title: I18n.system_tips , - btn: [ I18n.system_ok, I18n.system_cancel ] - }, function(index){ - layer.close(index); - - $.ajax({ - type : 'POST', - url : base_url + '/jobgroup/remove', - data : {"id":id}, - dataType : "json", - success : function(data){ - if (data.code == 200) { - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: (I18n.jobgroup_del + I18n.system_success), - icon: '1', - end: function(layero, index){ - jobGroupTable.fnDraw(); - } - }); - } else { - layer.open({ - title: I18n.system_tips, - btn: [ I18n.system_ok ], - content: (data.msg || (I18n.jobgroup_del + I18n.system_fail)), - icon: '2' - }); - } - }, - }); - }); - }); - - - // jquery.validate “low letters start, limit contants、 letters、numbers and line-through.” - jQuery.validator.addMethod("myValid01", function(value, element) { - var length = value.length; - var valid = /^[a-z][a-zA-Z0-9-]*$/; - return this.optional(element) || valid.test(value); - }, I18n.jobgroup_field_appname_limit ); - - $('.add').on('click', function(){ - $('#addModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var addModalValidate = $("#addModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - rules : { - appname : { - required : true, - rangelength:[4,64], - myValid01 : true - }, - title : { - required : true, - rangelength:[4, 12] - } - }, - messages : { - appname : { - required : I18n.system_please_input+"AppName", - rangelength: I18n.jobgroup_field_appname_length , - myValid01: I18n.jobgroup_field_appname_limit - }, - title : { - required : I18n.system_please_input + I18n.jobgroup_field_title , - rangelength: I18n.jobgroup_field_title_length - } - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - $.post(base_url + "/jobgroup/save", $("#addModal .form").serialize(), function(data, status) { - if (data.code == "200") { - $('#addModal').modal('hide'); - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: I18n.system_add_suc , - icon: '1', - end: function(layero, index){ - jobGroupTable.fnDraw(); - } - }); - } else { - layer.open({ - title: I18n.system_tips, - btn: [ I18n.system_ok ], - content: (data.msg || I18n.system_add_fail ), - icon: '2' - }); - } - }); - } - }); - $("#addModal").on('hide.bs.modal', function () { - $("#addModal .form")[0].reset(); - addModalValidate.resetForm(); - $("#addModal .form .form-group").removeClass("has-error"); - }); - - // addressType change - $("#addModal input[name=addressType], #updateModal input[name=addressType]").click(function(){ - var addressType = $(this).val(); - var $addressList = $(this).parents("form").find("textarea[name=addressList]"); - if (addressType == 0) { - $addressList.css("background-color", "#eee"); // 自动注册 - $addressList.attr("readonly","readonly"); - $addressList.val(""); - } else { - $addressList.css("background-color", "white"); - $addressList.removeAttr("readonly"); - } - }); - - // opt_edit - $("#jobgroup_list").on('click', '.opt_edit',function() { - var id = $(this).parents('ul').attr("_id"); - var row = tableData['key'+id]; - - $("#updateModal .form input[name='id']").val( row.id ); - $("#updateModal .form input[name='appname']").val( row.appname ); - $("#updateModal .form input[name='title']").val( row.title ); - - // 注册方式 - $("#updateModal .form input[name='addressType']").removeAttr('checked'); - $("#updateModal .form input[name='addressType'][value='"+ row.addressType +"']").click(); - // 机器地址 - $("#updateModal .form textarea[name='addressList']").val( row.addressList ); - - $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var updateModalValidate = $("#updateModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - rules : { - appname : { - required : true, - rangelength:[4,64], - myValid01 : true - }, - title : { - required : true, - rangelength:[4, 12] - } - }, - messages : { - appname : { - required : I18n.system_please_input+"AppName", - rangelength: I18n.jobgroup_field_appname_length , - myValid01: I18n.jobgroup_field_appname_limit - }, - title : { - required : I18n.system_please_input + I18n.jobgroup_field_title , - rangelength: I18n.jobgroup_field_title_length - } - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - $.post(base_url + "/jobgroup/update", $("#updateModal .form").serialize(), function(data, status) { - if (data.code == "200") { - $('#updateModal').modal('hide'); - - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: I18n.system_update_suc , - icon: '1', - end: function(layero, index){ - jobGroupTable.fnDraw(); - } - }); - } else { - layer.open({ - title: I18n.system_tips, - btn: [ I18n.system_ok ], - content: (data.msg || I18n.system_update_fail ), - icon: '2' - }); - } - }); - } - }); - $("#updateModal").on('hide.bs.modal', function () { - $("#updateModal .form")[0].reset(); - addModalValidate.resetForm(); - $("#updateModal .form .form-group").removeClass("has-error"); - }); - - -}); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/jobinfo.index.1.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/jobinfo.index.1.js deleted file mode 100644 index b479e9724..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/jobinfo.index.1.js +++ /dev/null @@ -1,739 +0,0 @@ -$(function() { - - // init date tables - var jobTable = $("#job_list").dataTable({ - "deferRender": true, - "processing" : true, - "serverSide": true, - "ajax": { - url: base_url + "/jobinfo/pageList", - type:"post", - data : function ( d ) { - var obj = {}; - obj.jobGroup = $('#jobGroup').val(); - obj.triggerStatus = $('#triggerStatus').val(); - obj.jobDesc = $('#jobDesc').val(); - obj.executorHandler = $('#executorHandler').val(); - obj.author = $('#author').val(); - obj.start = d.start; - obj.length = d.length; - return obj; - } - }, - "searching": false, - "ordering": false, - //"scrollX": true, // scroll x,close self-adaption - "columns": [ - { - "data": 'id', - "bSortable": false, - "visible" : true, - "width":'7%' - }, - { - "data": 'jobGroup', - "visible" : false, - "render": function ( data, type, row ) { - var groupMenu = $("#jobGroup").find("option"); - for ( var index in $("#jobGroup").find("option")) { - if ($(groupMenu[index]).attr('value') == data) { - return $(groupMenu[index]).html(); - } - } - return data; - } - }, - { - "data": 'jobDesc', - "visible" : true, - "width":'25%' - }, - { - "data": 'scheduleType', - "visible" : true, - "width":'13%', - "render": function ( data, type, row ) { - if (row.scheduleConf) { - return row.scheduleType + ':'+ row.scheduleConf; - } else { - return row.scheduleType; - } - } - }, - { - "data": 'glueType', - "width":'25%', - "visible" : true, - "render": function ( data, type, row ) { - var glueTypeTitle = findGlueTypeTitle(row.glueType); - if (row.executorHandler) { - return glueTypeTitle +":" + row.executorHandler; - } else { - return glueTypeTitle; - } - } - }, - { "data": 'executorParam', "visible" : false}, - { - "data": 'addTime', - "visible" : false, - "render": function ( data, type, row ) { - return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; - } - }, - { - "data": 'updateTime', - "visible" : false, - "render": function ( data, type, row ) { - return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; - } - }, - { "data": 'author', "visible" : true, "width":'10%'}, - { "data": 'alarmEmail', "visible" : false}, - { - "data": 'triggerStatus', - "width":'10%', - "visible" : true, - "render": function ( data, type, row ) { - // status - if (1 == data) { - return 'RUNNING'; - } else { - return 'STOP'; - } - return data; - } - }, - { - "data": I18n.system_opt , - "width":'10%', - "render": function ( data, type, row ) { - return function(){ - - // status - var start_stop_div = ""; - if (1 == row.triggerStatus ) { - start_stop_div = '
  • '+ I18n.jobinfo_opt_stop +'
  • \n'; - } else { - start_stop_div = '
  • '+ I18n.jobinfo_opt_start +'
  • \n'; - } - - // job_next_time_html - var job_next_time_html = ''; - if (row.scheduleType == 'CRON' || row.scheduleType == 'FIX_RATE') { - job_next_time_html = '
  • ' + I18n.jobinfo_opt_next_time + '
  • \n'; - } - - // log url - var logHref = base_url +'/joblog?jobId='+ row.id; - - // code url - var codeBtn = ""; - if ('BEAN' != row.glueType) { - var codeUrl = base_url +'/jobcode?jobId='+ row.id; - codeBtn = '
  • GLUE IDE
  • \n'; - codeBtn += '
  • \n'; - } - - // data - tableData['key'+row.id] = row; - - // opt - var html = '
    \n' + - ' \n' + - ' \n' + - ' \n' + - '
    '; - - return html; - }; - } - } - ], - "language" : { - "sProcessing" : I18n.dataTable_sProcessing , - "sLengthMenu" : I18n.dataTable_sLengthMenu , - "sZeroRecords" : I18n.dataTable_sZeroRecords , - "sInfo" : I18n.dataTable_sInfo , - "sInfoEmpty" : I18n.dataTable_sInfoEmpty , - "sInfoFiltered" : I18n.dataTable_sInfoFiltered , - "sInfoPostFix" : "", - "sSearch" : I18n.dataTable_sSearch , - "sUrl" : "", - "sEmptyTable" : I18n.dataTable_sEmptyTable , - "sLoadingRecords" : I18n.dataTable_sLoadingRecords , - "sInfoThousands" : ",", - "oPaginate" : { - "sFirst" : I18n.dataTable_sFirst , - "sPrevious" : I18n.dataTable_sPrevious , - "sNext" : I18n.dataTable_sNext , - "sLast" : I18n.dataTable_sLast - }, - "oAria" : { - "sSortAscending" : I18n.dataTable_sSortAscending , - "sSortDescending" : I18n.dataTable_sSortDescending - } - } - }); - - // table data - var tableData = {}; - - // search btn - $('#searchBtn').on('click', function(){ - jobTable.fnDraw(); - }); - - // jobGroup change - $('#jobGroup').on('change', function(){ - //reload - var jobGroup = $('#jobGroup').val(); - window.location.href = base_url + "/jobinfo?jobGroup=" + jobGroup; - }); - - // job operate - $("#job_list").on('click', '.job_operate',function() { - var typeName; - var url; - var needFresh = false; - - var type = $(this).attr("_type"); - if ("job_pause" == type) { - typeName = I18n.jobinfo_opt_stop ; - url = base_url + "/jobinfo/stop"; - needFresh = true; - } else if ("job_resume" == type) { - typeName = I18n.jobinfo_opt_start ; - url = base_url + "/jobinfo/start"; - needFresh = true; - } else if ("job_del" == type) { - typeName = I18n.system_opt_del ; - url = base_url + "/jobinfo/remove"; - needFresh = true; - } else { - return; - } - - var id = $(this).parents('ul').attr("_id"); - - layer.confirm( I18n.system_ok + typeName + '?', { - icon: 3, - title: I18n.system_tips , - btn: [ I18n.system_ok, I18n.system_cancel ] - }, function(index){ - layer.close(index); - - $.ajax({ - type : 'POST', - url : url, - data : { - "id" : id - }, - dataType : "json", - success : function(data){ - if (data.code == 200) { - layer.msg( typeName + I18n.system_success ); - if (needFresh) { - //window.location.reload(); - jobTable.fnDraw(false); - } - } else { - layer.msg( data.msg || typeName + I18n.system_fail ); - } - } - }); - }); - }); - - // job trigger - $("#job_list").on('click', '.job_trigger',function() { - var id = $(this).parents('ul').attr("_id"); - var row = tableData['key'+id]; - - $("#jobTriggerModal .form input[name='id']").val( row.id ); - $("#jobTriggerModal .form textarea[name='executorParam']").val( row.executorParam ); - - $('#jobTriggerModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - $("#jobTriggerModal .ok").on('click',function() { - $.ajax({ - type : 'POST', - url : base_url + "/jobinfo/trigger", - data : { - "id" : $("#jobTriggerModal .form input[name='id']").val(), - "executorParam" : $("#jobTriggerModal .textarea[name='executorParam']").val(), - "addressList" : $("#jobTriggerModal .textarea[name='addressList']").val() - }, - dataType : "json", - success : function(data){ - if (data.code == 200) { - $('#jobTriggerModal').modal('hide'); - - layer.msg( I18n.jobinfo_opt_run + I18n.system_success ); - } else { - layer.msg( data.msg || I18n.jobinfo_opt_run + I18n.system_fail ); - } - } - }); - }); - $("#jobTriggerModal").on('hide.bs.modal', function () { - $("#jobTriggerModal .form")[0].reset(); - }); - - - // job registryinfo - $("#job_list").on('click', '.job_registryinfo',function() { - var id = $(this).parents('ul').attr("_id"); - var row = tableData['key'+id]; - - var jobGroup = row.jobGroup; - - $.ajax({ - type : 'POST', - url : base_url + "/jobgroup/loadById", - data : { - "id" : jobGroup - }, - dataType : "json", - success : function(data){ - - var html = '
    '; - if (data.code == 200 && data.content.registryList) { - for (var index in data.content.registryList) { - html += (parseInt(index)+1) + '. ' + data.content.registryList[index] + '
    '; - } - } - html += '
    '; - - layer.open({ - title: I18n.jobinfo_opt_registryinfo , - btn: [ I18n.system_ok ], - content: html - }); - - } - }); - - }); - - // job_next_time - $("#job_list").on('click', '.job_next_time',function() { - var id = $(this).parents('ul').attr("_id"); - var row = tableData['key'+id]; - - $.ajax({ - type : 'POST', - url : base_url + "/jobinfo/nextTriggerTime", - data : { - "scheduleType" : row.scheduleType, - "scheduleConf" : row.scheduleConf - }, - dataType : "json", - success : function(data){ - - if (data.code != 200) { - layer.open({ - title: I18n.jobinfo_opt_next_time , - btn: [ I18n.system_ok ], - content: data.msg - }); - } else { - var html = '
    '; - if (data.code == 200 && data.content) { - for (var index in data.content) { - html += '' + data.content[index] + '
    '; - } - } - html += '
    '; - - layer.open({ - title: I18n.jobinfo_opt_next_time , - btn: [ I18n.system_ok ], - content: html - }); - } - - } - }); - - }); - - // add - $(".add").click(function(){ - - // init-cronGen - $("#addModal .form input[name='schedule_conf_CRON']").show().siblings().remove(); - $("#addModal .form input[name='schedule_conf_CRON']").cronGen({}); - - // 》init scheduleType - $("#updateModal .form select[name=scheduleType]").change(); - - // 》init glueType - $("#updateModal .form select[name=glueType]").change(); - - $('#addModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var addModalValidate = $("#addModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - rules : { - jobDesc : { - required : true, - maxlength: 50 - }, - author : { - required : true - }/*, - executorTimeout : { - digits:true - }, - executorFailRetryCount : { - digits:true - }*/ - }, - messages : { - jobDesc : { - required : I18n.system_please_input + I18n.jobinfo_field_jobdesc - }, - author : { - required : I18n.system_please_input + I18n.jobinfo_field_author - }/*, - executorTimeout : { - digits: I18n.system_please_input + I18n.system_digits - }, - executorFailRetryCount : { - digits: I18n.system_please_input + I18n.system_digits - }*/ - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - - // process executorTimeout+executorFailRetryCount - var executorTimeout = $("#addModal .form input[name='executorTimeout']").val(); - if(!/^\d+$/.test(executorTimeout)) { - executorTimeout = 0; - } - $("#addModal .form input[name='executorTimeout']").val(executorTimeout); - var executorFailRetryCount = $("#addModal .form input[name='executorFailRetryCount']").val(); - if(!/^\d+$/.test(executorFailRetryCount)) { - executorFailRetryCount = 0; - } - $("#addModal .form input[name='executorFailRetryCount']").val(executorFailRetryCount); - - // process schedule_conf - var scheduleType = $("#addModal .form select[name='scheduleType']").val(); - var scheduleConf; - if (scheduleType == 'CRON') { - scheduleConf = $("#addModal .form input[name='cronGen_display']").val(); - } else if (scheduleType == 'FIX_RATE') { - scheduleConf = $("#addModal .form input[name='schedule_conf_FIX_RATE']").val(); - } else if (scheduleType == 'FIX_DELAY') { - scheduleConf = $("#addModal .form input[name='schedule_conf_FIX_DELAY']").val(); - } - $("#addModal .form input[name='scheduleConf']").val( scheduleConf ); - - $.post(base_url + "/jobinfo/add", $("#addModal .form").serialize(), function(data, status) { - if (data.code == "200") { - $('#addModal').modal('hide'); - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: I18n.system_add_suc , - icon: '1', - end: function(layero, index){ - jobTable.fnDraw(); - //window.location.reload(); - } - }); - } else { - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: (data.msg || I18n.system_add_fail), - icon: '2' - }); - } - }); - } - }); - $("#addModal").on('hide.bs.modal', function () { - addModalValidate.resetForm(); - $("#addModal .form")[0].reset(); - $("#addModal .form .form-group").removeClass("has-error"); - $(".remote_panel").show(); // remote - - $("#addModal .form input[name='executorHandler']").removeAttr("readonly"); - }); - - // scheduleType change - $(".scheduleType").change(function(){ - var scheduleType = $(this).val(); - $(this).parents("form").find(".schedule_conf").hide(); - $(this).parents("form").find(".schedule_conf_" + scheduleType).show(); - - }); - - // glueType change - $(".glueType").change(function(){ - // executorHandler - var $executorHandler = $(this).parents("form").find("input[name='executorHandler']"); - var glueType = $(this).val(); - if ('BEAN' != glueType) { - $executorHandler.val(""); - $executorHandler.attr("readonly","readonly"); - } else { - $executorHandler.removeAttr("readonly"); - } - }); - - $("#addModal .glueType").change(function(){ - // glueSource - var glueType = $(this).val(); - if ('GLUE_GROOVY'==glueType){ - $("#addModal .form textarea[name='glueSource']").val( $("#addModal .form .glueSource_java").val() ); - } else if ('GLUE_SHELL'==glueType){ - $("#addModal .form textarea[name='glueSource']").val( $("#addModal .form .glueSource_shell").val() ); - } else if ('GLUE_PYTHON'==glueType){ - $("#addModal .form textarea[name='glueSource']").val( $("#addModal .form .glueSource_python").val() ); - } else if ('GLUE_PHP'==glueType){ - $("#addModal .form textarea[name='glueSource']").val( $("#addModal .form .glueSource_php").val() ); - } else if ('GLUE_NODEJS'==glueType){ - $("#addModal .form textarea[name='glueSource']").val( $("#addModal .form .glueSource_nodejs").val() ); - } else if ('GLUE_POWERSHELL'==glueType){ - $("#addModal .form textarea[name='glueSource']").val( $("#addModal .form .glueSource_powershell").val() ); - } else { - $("#addModal .form textarea[name='glueSource']").val(""); - } - }); - - // update - $("#job_list").on('click', '.update',function() { - - var id = $(this).parents('ul').attr("_id"); - var row = tableData['key'+id]; - - // fill base - $("#updateModal .form input[name='id']").val( row.id ); - $('#updateModal .form select[name=jobGroup] option[value='+ row.jobGroup +']').prop('selected', true); - $("#updateModal .form input[name='jobDesc']").val( row.jobDesc ); - $("#updateModal .form input[name='author']").val( row.author ); - $("#updateModal .form input[name='alarmEmail']").val( row.alarmEmail ); - - // fill trigger - $('#updateModal .form select[name=scheduleType] option[value='+ row.scheduleType +']').prop('selected', true); - $("#updateModal .form input[name='scheduleConf']").val( row.scheduleConf ); - if (row.scheduleType == 'CRON') { - $("#updateModal .form input[name='schedule_conf_CRON']").val( row.scheduleConf ); - } else if (row.scheduleType == 'FIX_RATE') { - $("#updateModal .form input[name='schedule_conf_FIX_RATE']").val( row.scheduleConf ); - } else if (row.scheduleType == 'FIX_DELAY') { - $("#updateModal .form input[name='schedule_conf_FIX_DELAY']").val( row.scheduleConf ); - } - - // 》init scheduleType - $("#updateModal .form select[name=scheduleType]").change(); - - // fill job - $('#updateModal .form select[name=glueType] option[value='+ row.glueType +']').prop('selected', true); - $("#updateModal .form input[name='executorHandler']").val( row.executorHandler ); - $("#updateModal .form textarea[name='executorParam']").val( row.executorParam ); - - // 》init glueType - $("#updateModal .form select[name=glueType]").change(); - - // 》init-cronGen - $("#updateModal .form input[name='schedule_conf_CRON']").show().siblings().remove(); - $("#updateModal .form input[name='schedule_conf_CRON']").cronGen({}); - - // fill advanced - $('#updateModal .form select[name=executorRouteStrategy] option[value='+ row.executorRouteStrategy +']').prop('selected', true); - $("#updateModal .form input[name='childJobId']").val( row.childJobId ); - $('#updateModal .form select[name=misfireStrategy] option[value='+ row.misfireStrategy +']').prop('selected', true); - $('#updateModal .form select[name=executorBlockStrategy] option[value='+ row.executorBlockStrategy +']').prop('selected', true); - $("#updateModal .form input[name='executorTimeout']").val( row.executorTimeout ); - $("#updateModal .form input[name='executorFailRetryCount']").val( row.executorFailRetryCount ); - - // show - $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var updateModalValidate = $("#updateModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - - rules : { - jobDesc : { - required : true, - maxlength: 50 - }, - author : { - required : true - } - }, - messages : { - jobDesc : { - required : I18n.system_please_input + I18n.jobinfo_field_jobdesc - }, - author : { - required : I18n.system_please_input + I18n.jobinfo_field_author - } - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - - // process executorTimeout + executorFailRetryCount - var executorTimeout = $("#updateModal .form input[name='executorTimeout']").val(); - if(!/^\d+$/.test(executorTimeout)) { - executorTimeout = 0; - } - $("#updateModal .form input[name='executorTimeout']").val(executorTimeout); - var executorFailRetryCount = $("#updateModal .form input[name='executorFailRetryCount']").val(); - if(!/^\d+$/.test(executorFailRetryCount)) { - executorFailRetryCount = 0; - } - $("#updateModal .form input[name='executorFailRetryCount']").val(executorFailRetryCount); - - - // process schedule_conf - var scheduleType = $("#updateModal .form select[name='scheduleType']").val(); - var scheduleConf; - if (scheduleType == 'CRON') { - scheduleConf = $("#updateModal .form input[name='cronGen_display']").val(); - } else if (scheduleType == 'FIX_RATE') { - scheduleConf = $("#updateModal .form input[name='schedule_conf_FIX_RATE']").val(); - } else if (scheduleType == 'FIX_DELAY') { - scheduleConf = $("#updateModal .form input[name='schedule_conf_FIX_DELAY']").val(); - } - $("#updateModal .form input[name='scheduleConf']").val( scheduleConf ); - - // post - $.post(base_url + "/jobinfo/update", $("#updateModal .form").serialize(), function(data, status) { - if (data.code == "200") { - $('#updateModal').modal('hide'); - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: I18n.system_update_suc , - icon: '1', - end: function(layero, index){ - //window.location.reload(); - jobTable.fnDraw(); - } - }); - } else { - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: (data.msg || I18n.system_update_fail ), - icon: '2' - }); - } - }); - } - }); - $("#updateModal").on('hide.bs.modal', function () { - updateModalValidate.resetForm(); - $("#updateModal .form")[0].reset(); - $("#updateModal .form .form-group").removeClass("has-error"); - }); - - /** - * find title by name, GlueType - */ - function findGlueTypeTitle(glueType) { - var glueTypeTitle; - $("#addModal .form select[name=glueType] option").each(function () { - var name = $(this).val(); - var title = $(this).text(); - if (glueType == name) { - glueTypeTitle = title; - return false - } - }); - return glueTypeTitle; - } - - // job_copy - $("#job_list").on('click', '.job_copy',function() { - - var id = $(this).parents('ul').attr("_id"); - var row = tableData['key'+id]; - - // fill base - $('#addModal .form select[name=jobGroup] option[value='+ row.jobGroup +']').prop('selected', true); - $("#addModal .form input[name='jobDesc']").val( row.jobDesc ); - $("#addModal .form input[name='author']").val( row.author ); - $("#addModal .form input[name='alarmEmail']").val( row.alarmEmail ); - - // fill trigger - $('#addModal .form select[name=scheduleType] option[value='+ row.scheduleType +']').prop('selected', true); - $("#addModal .form input[name='scheduleConf']").val( row.scheduleConf ); - if (row.scheduleType == 'CRON') { - $("#addModal .form input[name='schedule_conf_CRON']").val( row.scheduleConf ); - } else if (row.scheduleType == 'FIX_RATE') { - $("#addModal .form input[name='schedule_conf_FIX_RATE']").val( row.scheduleConf ); - } else if (row.scheduleType == 'FIX_DELAY') { - $("#addModal .form input[name='schedule_conf_FIX_DELAY']").val( row.scheduleConf ); - } - - // 》init scheduleType - $("#addModal .form select[name=scheduleType]").change(); - - // fill job - $('#addModal .form select[name=glueType] option[value='+ row.glueType +']').prop('selected', true); - $("#addModal .form input[name='executorHandler']").val( row.executorHandler ); - $("#addModal .form textarea[name='executorParam']").val( row.executorParam ); - - // 》init glueType - $("#addModal .form select[name=glueType]").change(); - - // 》init-cronGen - $("#addModal .form input[name='schedule_conf_CRON']").show().siblings().remove(); - $("#addModal .form input[name='schedule_conf_CRON']").cronGen({}); - - // fill advanced - $('#addModal .form select[name=executorRouteStrategy] option[value='+ row.executorRouteStrategy +']').prop('selected', true); - $("#addModal .form input[name='childJobId']").val( row.childJobId ); - $('#addModal .form select[name=misfireStrategy] option[value='+ row.misfireStrategy +']').prop('selected', true); - $('#addModal .form select[name=executorBlockStrategy] option[value='+ row.executorBlockStrategy +']').prop('selected', true); - $("#addModal .form input[name='executorTimeout']").val( row.executorTimeout ); - $("#addModal .form input[name='executorFailRetryCount']").val( row.executorFailRetryCount ); - - // show - $('#addModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - -}); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/joblog.detail.1.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/joblog.detail.1.js deleted file mode 100644 index 0638eee27..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/joblog.detail.1.js +++ /dev/null @@ -1,89 +0,0 @@ -$(function() { - - // trigger fail, end - if ( !(triggerCode == 200 || handleCode != 0) ) { - $('#logConsoleRunning').hide(); - $('#logConsole').append(''+ I18n.joblog_rolling_log_triggerfail +''); - return; - } - - // pull log - var fromLineNum = 1; // [from, to], start as 1 - var pullFailCount = 0; - function pullLog() { - // pullFailCount, max=20 - if (pullFailCount++ > 20) { - logRunStop(''+ I18n.joblog_rolling_log_failoften +''); - return; - } - - // load - console.log("pullLog, fromLineNum:" + fromLineNum); - - $.ajax({ - type : 'POST', - async: false, // sync, make log ordered - url : base_url + '/joblog/logDetailCat', - data : { - "logId":logId, - "fromLineNum":fromLineNum - }, - dataType : "json", - success : function(data){ - - if (data.code == 200) { - if (!data.content) { - console.log('pullLog fail'); - return; - } - if (fromLineNum != data.content.fromLineNum) { - console.log('pullLog fromLineNum not match'); - return; - } - if (fromLineNum > data.content.toLineNum ) { - console.log('pullLog already line-end'); - - // valid end - if (data.content.end) { - logRunStop('
    [Rolling Log Finish]'); - return; - } - - return; - } - - // append content - fromLineNum = data.content.toLineNum + 1; - $('#logConsole').append(data.content.logContent); - pullFailCount = 0; - - // scroll to bottom - scrollTo(0, document.body.scrollHeight); // $('#logConsolePre').scrollTop( document.body.scrollHeight + 300 ); - - } else { - console.log('pullLog fail:'+data.msg); - } - } - }); - } - - // pull first page - pullLog(); - - // handler already callback, end - if (handleCode > 0) { - logRunStop('
    [Load Log Finish]'); - return; - } - - // round until end - var logRun = setInterval(function () { - pullLog() - }, 3000); - function logRunStop(content){ - $('#logConsoleRunning').hide(); - logRun = window.clearInterval(logRun); - $('#logConsole').append(content); - } - -}); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/joblog.index.1.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/joblog.index.1.js deleted file mode 100644 index e0fc3f20b..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/joblog.index.1.js +++ /dev/null @@ -1,396 +0,0 @@ -$(function() { - - // jobGroup change, job list init and select - $("#jobGroup").on("change", function () { - var jobGroup = $(this).children('option:selected').val(); - $.ajax({ - type : 'POST', - async: false, // async, avoid js invoke pagelist before jobId data init - url : base_url + '/joblog/getJobsByGroup', - data : {"jobGroup":jobGroup}, - dataType : "json", - success : function(data){ - if (data.code == 200) { - $("#jobId").html( '' ); - $.each(data.content, function (n, value) { - $("#jobId").append(''); - }); - if ($("#jobId").attr("paramVal")){ - $("#jobId").find("option[value='" + $("#jobId").attr("paramVal") + "']").attr("selected",true); - } - } else { - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: (data.msg || I18n.system_api_error ), - icon: '2' - }); - } - }, - }); - }); - if ($("#jobGroup").attr("paramVal")){ - $("#jobGroup").find("option[value='" + $("#jobGroup").attr("paramVal") + "']").attr("selected",true); - $("#jobGroup").change(); - } - - // filter Time - var rangesConf = {}; - rangesConf[I18n.daterangepicker_ranges_recent_hour] = [moment().subtract(1, 'hours'), moment()]; - rangesConf[I18n.daterangepicker_ranges_today] = [moment().startOf('day'), moment().endOf('day')]; - rangesConf[I18n.daterangepicker_ranges_yesterday] = [moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').endOf('day')]; - rangesConf[I18n.daterangepicker_ranges_this_month] = [moment().startOf('month'), moment().endOf('month')]; - rangesConf[I18n.daterangepicker_ranges_last_month] = [moment().subtract(1, 'months').startOf('month'), moment().subtract(1, 'months').endOf('month')]; - rangesConf[I18n.daterangepicker_ranges_recent_week] = [moment().subtract(1, 'weeks').startOf('day'), moment().endOf('day')]; - rangesConf[I18n.daterangepicker_ranges_recent_month] = [moment().subtract(1, 'months').startOf('day'), moment().endOf('day')]; - - $('#filterTime').daterangepicker({ - autoApply:false, - singleDatePicker:false, - showDropdowns:false, // 是否显示年月选择条件 - timePicker: true, // 是否显示小时和分钟选择条件 - timePickerIncrement: 10, // 时间的增量,单位为分钟 - timePicker24Hour : true, - opens : 'left', //日期选择框的弹出位置 - ranges: rangesConf, - locale : { - format: 'YYYY-MM-DD HH:mm:ss', - separator : ' - ', - customRangeLabel : I18n.daterangepicker_custom_name , - applyLabel : I18n.system_ok , - cancelLabel : I18n.system_cancel , - fromLabel : I18n.daterangepicker_custom_starttime , - toLabel : I18n.daterangepicker_custom_endtime , - daysOfWeek : I18n.daterangepicker_custom_daysofweek.split(',') , // '日', '一', '二', '三', '四', '五', '六' - monthNames : I18n.daterangepicker_custom_monthnames.split(',') , // '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月' - firstDay : 1 - }, - startDate: rangesConf[I18n.daterangepicker_ranges_today][0], - endDate: rangesConf[I18n.daterangepicker_ranges_today][1] - }); - - // init date tables - var logTable = $("#joblog_list").dataTable({ - "deferRender": true, - "processing" : true, - "serverSide": true, - "ajax": { - url: base_url + "/joblog/pageList" , - type:"post", - data : function ( d ) { - var obj = {}; - obj.jobGroup = $('#jobGroup').val(); - obj.jobId = $('#jobId').val(); - obj.logStatus = $('#logStatus').val(); - obj.filterTime = $('#filterTime').val(); - obj.start = d.start; - obj.length = d.length; - return obj; - } - }, - "searching": false, - "ordering": false, - //"scrollX": false, - "columns": [ - { - "data": 'jobId', - "visible" : true, - "width":'10%', - "render": function ( data, type, row ) { - - var jobhandler = ''; - if (row.executorHandler) { - jobhandler = "
    JobHandler:" + row.executorHandler; - } - - var temp = ''; - temp += I18n.joblog_field_executorAddress + ':' + (row.executorAddress?row.executorAddress:''); - temp += jobhandler; - temp += '
    '+ I18n.jobinfo_field_executorparam +':' + row.executorParam; - - return ''+ row.jobId +''+ temp +''; - } - }, - { "data": 'jobGroup', "visible" : false}, - { - "data": 'triggerTime', - "width":'20%', - "render": function ( data, type, row ) { - return data?moment(data).format("YYYY-MM-DD HH:mm:ss"):""; - } - }, - { - "data": 'triggerCode', - "width":'10%', - "render": function ( data, type, row ) { - var html = data; - if (data == 200) { - html = ''+ I18n.system_success +''; - } else if (data == 500) { - html = ''+ I18n.system_fail +''; - } else if (data == 0) { - html = ''; - } - return html; - } - }, - { - "data": 'triggerMsg', - "width":'10%', - "render": function ( data, type, row ) { - return data?''+ I18n.system_show +''+ data +'':I18n.system_empty; - } - }, - { - "data": 'handleTime', - "width":'20%', - "render": function ( data, type, row ) { - return data?moment(data).format("YYYY-MM-DD HH:mm:ss"):""; - } - }, - { - "data": 'handleCode', - "width":'10%', - "render": function ( data, type, row ) { - var html = data; - if (data == 200) { - html = ''+ I18n.joblog_handleCode_200 +''; - } else if (data == 500) { - html = ''+ I18n.joblog_handleCode_500 +''; - } else if (data == 502) { - html = ''+ I18n.joblog_handleCode_502 +''; - } else if (data == 0) { - html = ''; - } - return html; - } - }, - { - "data": 'handleMsg', - "width":'10%', - "render": function ( data, type, row ) { - return data?''+ I18n.system_show +''+ data +'':I18n.system_empty; - } - }, - { - "data": 'handleMsg' , - "bSortable": false, - "width":'10%', - "render": function ( data, type, row ) { - // better support expression or string, not function - return function () { - if (row.triggerCode == 200 || row.handleCode != 0){ - - /*var temp = ''+ I18n.joblog_rolling_log +''; - if(row.handleCode == 0){ - temp += '
    '+ I18n.joblog_kill_log +''; - }*/ - //return temp; - - var logKillDiv = ''; - if(row.handleCode == 0){ - logKillDiv = '
  • \n' + - '
  • '+ I18n.joblog_kill_log +'
  • \n'; - } - - var html = '
    \n' + - ' \n' + - ' \n' + - ' \n' + - '
    '; - - return html; - } - return null; - } - } - } - ], - "language" : { - "sProcessing" : I18n.dataTable_sProcessing , - "sLengthMenu" : I18n.dataTable_sLengthMenu , - "sZeroRecords" : I18n.dataTable_sZeroRecords , - "sInfo" : I18n.dataTable_sInfo , - "sInfoEmpty" : I18n.dataTable_sInfoEmpty , - "sInfoFiltered" : I18n.dataTable_sInfoFiltered , - "sInfoPostFix" : "", - "sSearch" : I18n.dataTable_sSearch , - "sUrl" : "", - "sEmptyTable" : I18n.dataTable_sEmptyTable , - "sLoadingRecords" : I18n.dataTable_sLoadingRecords , - "sInfoThousands" : ",", - "oPaginate" : { - "sFirst" : I18n.dataTable_sFirst , - "sPrevious" : I18n.dataTable_sPrevious , - "sNext" : I18n.dataTable_sNext , - "sLast" : I18n.dataTable_sLast - }, - "oAria" : { - "sSortAscending" : I18n.dataTable_sSortAscending , - "sSortDescending" : I18n.dataTable_sSortDescending - } - } - }); - logTable.on('xhr.dt',function(e, settings, json, xhr) { - if (json.code && json.code != 200) { - layer.msg( json.msg || I18n.system_api_error ); - } - }); - - // logTips alert - $('#joblog_list').on('click', '.logTips', function(){ - var msg = $(this).find('span').html(); - ComAlertTec.show(msg); - }); - - // search Btn - $('#searchBtn').on('click', function(){ - logTable.fnDraw(); - }); - - // logDetail look - $('#joblog_list').on('click', '.logDetail', function(){ - var _id = $(this).attr('_id'); - - window.open(base_url + '/joblog/logDetailPage?id=' + _id); - return; - }); - - /** - * log Kill - */ - $('#joblog_list').on('click', '.logKill', function(){ - var _id = $(this).attr('_id'); - - layer.confirm( (I18n.system_ok + I18n.joblog_kill_log + '?'), { - icon: 3, - title: I18n.system_tips , - btn: [ I18n.system_ok, I18n.system_cancel ] - }, function(index){ - layer.close(index); - - $.ajax({ - type : 'POST', - url : base_url + '/joblog/logKill', - data : {"id":_id}, - dataType : "json", - success : function(data){ - if (data.code == 200) { - layer.open({ - title: I18n.system_tips, - btn: [ I18n.system_ok ], - content: I18n.system_opt_suc , - icon: '1', - end: function(layero, index){ - logTable.fnDraw(); - } - }); - } else { - layer.open({ - title: I18n.system_tips, - btn: [ I18n.system_ok ], - content: (data.msg || I18n.system_opt_fail ), - icon: '2' - }); - } - }, - }); - }); - - }); - - /** - * clear Log - */ - $('#clearLog').on('click', function(){ - - var jobGroup = $('#jobGroup').val(); - var jobId = $('#jobId').val(); - - var jobGroupText = $("#jobGroup").find("option:selected").text(); - var jobIdText = $("#jobId").find("option:selected").text(); - - $('#clearLogModal input[name=jobGroup]').val(jobGroup); - $('#clearLogModal input[name=jobId]').val(jobId); - - $('#clearLogModal .jobGroupText').val(jobGroupText); - $('#clearLogModal .jobIdText').val(jobIdText); - - $('#clearLogModal').modal('show'); - - }); - $("#clearLogModal .ok").on('click', function(){ - $.post(base_url + "/joblog/clearLog", $("#clearLogModal .form").serialize(), function(data, status) { - if (data.code == "200") { - $('#clearLogModal').modal('hide'); - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: (I18n.joblog_clean_log + I18n.system_success) , - icon: '1', - end: function(layero, index){ - logTable.fnDraw(); - } - }); - } else { - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: (data.msg || (I18n.joblog_clean_log + I18n.system_fail) ), - icon: '2' - }); - } - }); - }); - $("#clearLogModal").on('hide.bs.modal', function () { - $("#clearLogModal .form")[0].reset(); - }); - -}); - - -// Com Alert by Tec theme -var ComAlertTec = { - html:function(){ - var html = - ''; - return html; - }, - show:function(msg, callback){ - // dom init - if ($('#ComAlertTec').length == 0){ - $('body').append(ComAlertTec.html()); - } - - // init com alert - $('#ComAlertTec .alert').html(msg); - $('#ComAlertTec').modal('show'); - - $('#ComAlertTec .ok').click(function(){ - $('#ComAlertTec').modal('hide'); - if(typeof callback == 'function') { - callback(); - } - }); - } -}; diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/login.1.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/login.1.js deleted file mode 100644 index ef4096157..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/login.1.js +++ /dev/null @@ -1,66 +0,0 @@ -$(function(){ - - // input iCheck - $('input').iCheck({ - checkboxClass: 'icheckbox_square-blue', - radioClass: 'iradio_square-blue', - increaseArea: '20%' // optional - }); - - // login Form Valid - var loginFormValid = $("#loginForm").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - rules : { - userName : { - required : true , - minlength: 4, - maxlength: 20 - }, - password : { - required : true , - minlength: 4, - maxlength: 20 - } - }, - messages : { - userName : { - required : I18n.login_username_empty, - minlength : I18n.login_username_lt_4 - }, - password : { - required : I18n.login_password_empty , - minlength : I18n.login_password_lt_4 - /*,maxlength:"登录密码不应超过20位"*/ - } - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - $.post(base_url + "/login", $("#loginForm").serialize(), function(data, status) { - if (data.code == "200") { - layer.msg( I18n.login_success ); - setTimeout(function(){ - window.location.href = base_url + "/"; - }, 500); - } else { - layer.open({ - title: I18n.system_tips, - btn: [ I18n.system_ok ], - content: (data.msg || I18n.login_fail ), - icon: '2' - }); - } - }); - } - }); -}); \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/user.index.1.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/user.index.1.js deleted file mode 100644 index 48d3f3020..000000000 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/js/user.index.1.js +++ /dev/null @@ -1,328 +0,0 @@ -$(function() { - - // init date tables - var userListTable = $("#user_list").dataTable({ - "deferRender": true, - "processing" : true, - "serverSide": true, - "ajax": { - url: base_url + "/user/pageList", - type:"post", - data : function ( d ) { - var obj = {}; - obj.username = $('#username').val(); - obj.role = $('#role').val(); - obj.start = d.start; - obj.length = d.length; - return obj; - } - }, - "searching": false, - "ordering": false, - //"scrollX": true, // scroll x,close self-adaption - "columns": [ - { - "data": 'id', - "visible" : false, - "width":'10%' - }, - { - "data": 'username', - "visible" : true, - "width":'20%' - }, - { - "data": 'password', - "visible" : false, - "width":'20%', - "render": function ( data, type, row ) { - return '*********'; - } - }, - { - "data": 'role', - "visible" : true, - "width":'10%', - "render": function ( data, type, row ) { - if (data == 1) { - return I18n.user_role_admin - } else { - return I18n.user_role_normal - } - } - }, - { - "data": 'permission', - "width":'10%', - "visible" : false - }, - { - "data": I18n.system_opt , - "width":'15%', - "render": function ( data, type, row ) { - return function(){ - // html - tableData['key'+row.id] = row; - var html = '

    '+ - ' '+ - ' '+ - '

    '; - - return html; - }; - } - } - ], - "language" : { - "sProcessing" : I18n.dataTable_sProcessing , - "sLengthMenu" : I18n.dataTable_sLengthMenu , - "sZeroRecords" : I18n.dataTable_sZeroRecords , - "sInfo" : I18n.dataTable_sInfo , - "sInfoEmpty" : I18n.dataTable_sInfoEmpty , - "sInfoFiltered" : I18n.dataTable_sInfoFiltered , - "sInfoPostFix" : "", - "sSearch" : I18n.dataTable_sSearch , - "sUrl" : "", - "sEmptyTable" : I18n.dataTable_sEmptyTable , - "sLoadingRecords" : I18n.dataTable_sLoadingRecords , - "sInfoThousands" : ",", - "oPaginate" : { - "sFirst" : I18n.dataTable_sFirst , - "sPrevious" : I18n.dataTable_sPrevious , - "sNext" : I18n.dataTable_sNext , - "sLast" : I18n.dataTable_sLast - }, - "oAria" : { - "sSortAscending" : I18n.dataTable_sSortAscending , - "sSortDescending" : I18n.dataTable_sSortDescending - } - } - }); - - // table data - var tableData = {}; - - // search btn - $('#searchBtn').on('click', function(){ - userListTable.fnDraw(); - }); - - // job operate - $("#user_list").on('click', '.delete',function() { - var id = $(this).parent('p').attr("id"); - - layer.confirm( I18n.system_ok + I18n.system_opt_del + '?', { - icon: 3, - title: I18n.system_tips , - btn: [ I18n.system_ok, I18n.system_cancel ] - }, function(index){ - layer.close(index); - - $.ajax({ - type : 'POST', - url : base_url + "/user/remove", - data : { - "id" : id - }, - dataType : "json", - success : function(data){ - if (data.code == 200) { - layer.msg( I18n.system_success ); - userListTable.fnDraw(false); - } else { - layer.msg( data.msg || I18n.system_opt_del + I18n.system_fail ); - } - } - }); - }); - }); - - // add role - $("#addModal .form input[name=role]").change(function () { - var role = $(this).val(); - if (role == 1) { - $("#addModal .form input[name=permission]").parents('.form-group').hide(); - } else { - $("#addModal .form input[name=permission]").parents('.form-group').show(); - } - $("#addModal .form input[name='permission']").prop("checked",false); - }); - - jQuery.validator.addMethod("myValid01", function(value, element) { - var length = value.length; - var valid = /^[a-z][a-z0-9]*$/; - return this.optional(element) || valid.test(value); - }, I18n.user_username_valid ); - - // add - $(".add").click(function(){ - $('#addModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var addModalValidate = $("#addModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - rules : { - username : { - required : true, - rangelength:[4, 20], - myValid01: true - }, - password : { - required : true, - rangelength:[4, 20] - } - }, - messages : { - username : { - required : I18n.system_please_input + I18n.user_username, - rangelength: I18n.system_lengh_limit + "[4-20]" - }, - password : { - required : I18n.system_please_input + I18n.user_password, - rangelength: I18n.system_lengh_limit + "[4-20]" - } - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - - var permissionArr = []; - $("#addModal .form input[name=permission]:checked").each(function(){ - permissionArr.push($(this).val()); - }); - - var paramData = { - "username": $("#addModal .form input[name=username]").val(), - "password": $("#addModal .form input[name=password]").val(), - "role": $("#addModal .form input[name=role]:checked").val(), - "permission": permissionArr.join(',') - }; - - $.post(base_url + "/user/add", paramData, function(data, status) { - if (data.code == "200") { - $('#addModal').modal('hide'); - - layer.msg( I18n.system_add_suc ); - userListTable.fnDraw(); - } else { - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: (data.msg || I18n.system_add_fail), - icon: '2' - }); - } - }); - } - }); - $("#addModal").on('hide.bs.modal', function () { - $("#addModal .form")[0].reset(); - addModalValidate.resetForm(); - $("#addModal .form .form-group").removeClass("has-error"); - $(".remote_panel").show(); // remote - - $("#addModal .form input[name=permission]").parents('.form-group').show(); - }); - - // update role - $("#updateModal .form input[name=role]").change(function () { - var role = $(this).val(); - if (role == 1) { - $("#updateModal .form input[name=permission]").parents('.form-group').hide(); - } else { - $("#updateModal .form input[name=permission]").parents('.form-group').show(); - } - $("#updateModal .form input[name='permission']").prop("checked",false); - }); - - // update - $("#user_list").on('click', '.update',function() { - - var id = $(this).parent('p').attr("id"); - var row = tableData['key'+id]; - - // base data - $("#updateModal .form input[name='id']").val( row.id ); - $("#updateModal .form input[name='username']").val( row.username ); - $("#updateModal .form input[name='password']").val( '' ); - $("#updateModal .form input[name='role'][value='"+ row.role +"']").click(); - var permissionArr = []; - if (row.permission) { - permissionArr = row.permission.split(","); - } - $("#updateModal .form input[name='permission']").each(function () { - if($.inArray($(this).val(), permissionArr) > -1) { - $(this).prop("checked",true); - } else { - $(this).prop("checked",false); - } - }); - - // show - $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var updateModalValidate = $("#updateModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - - var permissionArr =[]; - $("#updateModal .form input[name=permission]:checked").each(function(){ - permissionArr.push($(this).val()); - }); - - var paramData = { - "id": $("#updateModal .form input[name=id]").val(), - "username": $("#updateModal .form input[name=username]").val(), - "password": $("#updateModal .form input[name=password]").val(), - "role": $("#updateModal .form input[name=role]:checked").val(), - "permission": permissionArr.join(',') - }; - - $.post(base_url + "/user/update", paramData, function(data, status) { - if (data.code == "200") { - $('#updateModal').modal('hide'); - - layer.msg( I18n.system_update_suc ); - userListTable.fnDraw(); - } else { - layer.open({ - title: I18n.system_tips , - btn: [ I18n.system_ok ], - content: (data.msg || I18n.system_update_fail), - icon: '2' - }); - } - }); - } - }); - $("#updateModal").on('hide.bs.modal', function () { - $("#updateModal .form")[0].reset(); - updateModalValidate.resetForm(); - $("#updateModal .form .form-group").removeClass("has-error"); - $(".remote_panel").show(); // remote - - $("#updateModal .form input[name=permission]").parents('.form-group').show(); - }); - -}); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/bootstrap-table/bootstrap-table.min.css b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/bootstrap-table/bootstrap-table.min.css new file mode 100644 index 000000000..775661119 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/bootstrap-table/bootstrap-table.min.css @@ -0,0 +1,10 @@ +/** + * bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation) + * + * @version v1.24.1 + * @homepage https://bootstrap-table.com + * @author wenzhixin (http://wenzhixin.net.cn/) + * @license MIT + */ + +@charset "UTF-8";.bootstrap-table .fixed-table-toolbar::after{content:"";display:block;clear:both}.bootstrap-table .fixed-table-toolbar .bs-bars,.bootstrap-table .fixed-table-toolbar .columns,.bootstrap-table .fixed-table-toolbar .search{position:relative;margin-top:10px;margin-bottom:10px}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group{display:inline-block;margin-left:-1px!important}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group>.btn{border-radius:0}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group:first-child>.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group:last-child>.btn{border-top-right-radius:4px;border-bottom-right-radius:4px}.bootstrap-table .fixed-table-toolbar .columns .dropdown-menu{text-align:left;max-height:300px;overflow:auto;-ms-overflow-style:scrollbar;z-index:1001}.bootstrap-table .fixed-table-toolbar .columns label{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.4286}.bootstrap-table .fixed-table-toolbar .columns-left{margin-right:5px}.bootstrap-table .fixed-table-toolbar .columns-right{margin-left:5px}.bootstrap-table .fixed-table-toolbar .pull-right .dropdown-menu{right:0;left:auto}.bootstrap-table .fixed-table-container{position:relative;clear:both}.bootstrap-table .fixed-table-container .table{width:100%;margin-bottom:0!important}.bootstrap-table .fixed-table-container .table td,.bootstrap-table .fixed-table-container .table th{vertical-align:middle;box-sizing:border-box}.bootstrap-table .fixed-table-container .table tfoot th,.bootstrap-table .fixed-table-container .table thead th{vertical-align:bottom;padding:0;margin:0}.bootstrap-table .fixed-table-container .table tfoot th:focus,.bootstrap-table .fixed-table-container .table thead th:focus{outline:0 solid transparent}.bootstrap-table .fixed-table-container .table tfoot th.detail,.bootstrap-table .fixed-table-container .table thead th.detail{width:30px}.bootstrap-table .fixed-table-container .table tfoot th .th-inner,.bootstrap-table .fixed-table-container .table thead th .th-inner{padding:.75rem;vertical-align:bottom;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bootstrap-table .fixed-table-container .table tfoot th .sortable,.bootstrap-table .fixed-table-container .table thead th .sortable{cursor:pointer;background-position:right;background-repeat:no-repeat;padding-right:30px!important}.bootstrap-table .fixed-table-container .table tfoot th .sortable.sortable-center,.bootstrap-table .fixed-table-container .table thead th .sortable.sortable-center{padding-left:20px!important;padding-right:20px!important}.bootstrap-table .fixed-table-container .table tfoot th .both,.bootstrap-table .fixed-table-container .table thead th .both{background-image:url('data:image/svg+xml;utf8,');background-size:16px 16px;background-position:center right 2px}.bootstrap-table .fixed-table-container .table tfoot th .asc,.bootstrap-table .fixed-table-container .table thead th .asc{background-image:url('data:image/svg+xml;utf8,')}.bootstrap-table .fixed-table-container .table tfoot th .desc,.bootstrap-table .fixed-table-container .table thead th .desc{background-image:url('data:image/svg+xml;utf8,')}.bootstrap-table .fixed-table-container .table tbody tr.selected td{background-color:rgba(0,0,0,.075)}.bootstrap-table .fixed-table-container .table tbody tr.no-records-found td{text-align:center}.bootstrap-table .fixed-table-container .table tbody tr .card-view{display:flex}.bootstrap-table .fixed-table-container .table tbody tr .card-view .card-view-title{font-weight:700;display:inline-block;min-width:30%;width:auto!important;text-align:left!important}.bootstrap-table .fixed-table-container .table tbody tr .card-view .card-view-value{width:100%!important;text-align:left!important}.bootstrap-table .fixed-table-container .table .bs-checkbox{text-align:center}.bootstrap-table .fixed-table-container .table .bs-checkbox label{margin-bottom:0}.bootstrap-table .fixed-table-container .table .bs-checkbox label input[type=checkbox],.bootstrap-table .fixed-table-container .table .bs-checkbox label input[type=radio]{margin:0 auto!important}.bootstrap-table .fixed-table-container .table.table-sm .th-inner{padding:.25rem}.bootstrap-table .fixed-table-container.fixed-height:not(.has-footer){border-bottom:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height.has-card-view{border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height .fixed-table-border{border-left:1px solid #dee2e6;border-right:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height .table thead th{border-bottom:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height .table-dark thead th{border-bottom:1px solid #32383e}.bootstrap-table .fixed-table-container .fixed-table-header{overflow:hidden}.bootstrap-table .fixed-table-container .fixed-table-body{overflow:auto;height:100%}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading{align-items:center;background:#fff;display:flex;justify-content:center;position:absolute;bottom:0;width:100%;max-width:100%;z-index:1000;transition:visibility 0s,opacity .15s ease-in-out;opacity:0;visibility:hidden}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.open{visibility:visible;opacity:1}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap{align-items:baseline;display:flex;justify-content:center}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .loading-text{margin-right:6px}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap{align-items:center;display:flex;justify-content:center}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-dot,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::after,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::before{content:"";animation-duration:1.5s;animation-iteration-count:infinite;animation-name:loading;background:#212529;border-radius:50%;display:block;height:5px;margin:0 4px;opacity:0;width:5px}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-dot{animation-delay:.3s}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::after{animation-delay:.6s}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark{background:#212529}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-dot,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-wrap::after,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-wrap::before{background:#fff}.bootstrap-table .fixed-table-container .fixed-table-footer{overflow:hidden}.bootstrap-table .fixed-table-pagination::after{content:"";display:block;clear:both}.bootstrap-table .fixed-table-pagination>.pagination,.bootstrap-table .fixed-table-pagination>.pagination-detail{margin-top:10px;margin-bottom:10px}.bootstrap-table .fixed-table-pagination>.pagination-detail .pagination-info{line-height:34px;margin-right:5px}.bootstrap-table .fixed-table-pagination>.pagination-detail .page-list{display:inline-block}.bootstrap-table .fixed-table-pagination>.pagination-detail .page-list .btn-group{position:relative;display:inline-block;vertical-align:middle}.bootstrap-table .fixed-table-pagination>.pagination-detail .page-list .btn-group .dropdown-menu{margin-bottom:0}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination{margin:0}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.page-intermediate a{color:#c8c8c8}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.page-intermediate a::before{content:"⬅"}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.page-intermediate a::after{content:"➡"}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.disabled a{pointer-events:none;cursor:default}.bootstrap-table.fullscreen{position:fixed;top:0;left:0;z-index:1050;width:100%!important;background:#fff;height:100vh;overflow-y:scroll}.bootstrap-table.bootstrap4 .pagination-lg .page-link,.bootstrap-table.bootstrap5 .pagination-lg .page-link{padding:.5rem 1rem}.bootstrap-table.bootstrap5 .float-left{float:left}.bootstrap-table.bootstrap5 .float-right{float:right}div.fixed-table-scroll-inner{width:100%;height:200px}div.fixed-table-scroll-outer{top:0;left:0;visibility:hidden;width:200px;height:150px;overflow:hidden}@keyframes loading{0%{opacity:0}50%{opacity:1}100%{opacity:0}} \ No newline at end of file diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/bootstrap-table/bootstrap-table.min.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/bootstrap-table/bootstrap-table.min.js new file mode 100644 index 000000000..0e4d37b75 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/bootstrap-table/bootstrap-table.min.js @@ -0,0 +1,10 @@ +/** + * bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation) + * + * @version v1.24.1 + * @homepage https://bootstrap-table.com + * @author wenzhixin (http://wenzhixin.net.cn/) + * @license MIT + */ + +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).BootstrapTable=e(t.jQuery)}(this,(function(t){"use strict";function e(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=Array(e);n=t.length?{done:!0}:{done:!1,value:t[i++]}},e:function(t){throw t},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,a=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){s=!0,o=t},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw o}}}}function o(t,e,n){return(e=u(e))in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function a(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,i)}return n}function s(t){for(var e=1;e0&&t[0]<4?1:+(t[0]+t[1])),!e&&i&&(!(t=i.match(/Edge\/(\d+)/))||t[1]>=74)&&(t=i.match(/Chrome\/(\d+)/))&&(e=+t[1]),nt=e}function jt(){if(ot)return rt;ot=1;var t=Et(),e=P(),n=b().String;return rt=!!Object.getOwnPropertySymbols&&!e((function(){var e=Symbol("symbol detection");return!n(e)||!(Object(e)instanceof Symbol)||!Symbol.sham&&t&&t<41}))}function Nt(){if(st)return at;st=1;var t=jt();return at=t&&!Symbol.sham&&"symbol"==typeof Symbol.iterator}function Ft(){if(ct)return lt;ct=1;var t=At(),e=Pt(),n=$t(),i=Nt(),r=Object;return lt=i?function(t){return"symbol"==typeof t}:function(i){var o=t("Symbol");return e(o)&&n(o.prototype,r(i))}}function Dt(){if(ht)return ut;ht=1;var t=String;return ut=function(e){try{return t(e)}catch(t){return"Object"}}}function Lt(){if(dt)return ft;dt=1;var t=Pt(),e=Dt(),n=TypeError;return ft=function(i){if(t(i))return i;throw new n(e(i)+" is not a function")}}function _t(){if(gt)return pt;gt=1;var t=Lt(),e=kt();return pt=function(n,i){var r=n[i];return e(r)?void 0:t(r)}}function Vt(){if(bt)return vt;bt=1;var t=$(),e=Pt(),n=It(),i=TypeError;return vt=function(r,o){var a,s;if("string"===o&&e(a=r.toString)&&!n(s=t(a,r)))return s;if(e(a=r.valueOf)&&!n(s=t(a,r)))return s;if("string"!==o&&e(a=r.toString)&&!n(s=t(a,r)))return s;throw new i("Can't convert object to primitive value")}}var Bt,Ht,Mt,Ut,zt,qt,Wt,Gt,Kt,Jt,Yt,Qt,Xt,Zt,te,ee,ne,ie,re,oe,ae,se,le,ce,ue={exports:{}};function he(){return Ht?Bt:(Ht=1,Bt=!1)}function fe(){if(Ut)return Mt;Ut=1;var t=b(),e=Object.defineProperty;return Mt=function(n,i){try{e(t,n,{value:i,configurable:!0,writable:!0})}catch(e){t[n]=i}return i}}function de(){if(zt)return ue.exports;zt=1;var t=he(),e=b(),n=fe(),i="__core-js_shared__",r=ue.exports=e[i]||n(i,{});return(r.versions||(r.versions=[])).push({version:"3.39.0",mode:t?"pure":"global",copyright:"© 2014-2024 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.39.0/LICENSE",source:"https://github.com/zloirock/core-js"}),ue.exports}function pe(){if(Wt)return qt;Wt=1;var t=de();return qt=function(e,n){return t[e]||(t[e]=n||{})}}function ge(){if(Kt)return Gt;Kt=1;var t=Tt(),e=Object;return Gt=function(n){return e(t(n))}}function ve(){if(Yt)return Jt;Yt=1;var t=St(),e=ge(),n=t({}.hasOwnProperty);return Jt=Object.hasOwn||function(t,i){return n(e(t),i)}}function be(){if(Xt)return Qt;Xt=1;var t=St(),e=0,n=Math.random(),i=t(1..toString);return Qt=function(t){return"Symbol("+(void 0===t?"":t)+")_"+i(++e+n,36)}}function me(){if(te)return Zt;te=1;var t=b(),e=pe(),n=ve(),i=be(),r=jt(),o=Nt(),a=t.Symbol,s=e("wks"),l=o?a.for||a:a&&a.withoutSetter||i;return Zt=function(t){return n(s,t)||(s[t]=r&&n(a,t)?a[t]:l("Symbol."+t)),s[t]}}function ye(){if(ne)return ee;ne=1;var t=$(),e=It(),n=Ft(),i=_t(),r=Vt(),o=me(),a=TypeError,s=o("toPrimitive");return ee=function(o,l){if(!e(o)||n(o))return o;var c,u=i(o,s);if(u){if(void 0===l&&(l="default"),c=t(u,o,l),!e(c)||n(c))return c;throw new a("Can't convert object to primitive value")}return void 0===l&&(l="number"),r(o,l)}}function we(){if(re)return ie;re=1;var t=ye(),e=Ft();return ie=function(n){var i=t(n,"string");return e(i)?i:i+""}}function Se(){if(ae)return oe;ae=1;var t=b(),e=It(),n=t.document,i=e(n)&&e(n.createElement);return oe=function(t){return i?n.createElement(t):{}}}function xe(){if(le)return se;le=1;var t=I(),e=P(),n=Se();return se=!t&&!e((function(){return 7!==Object.defineProperty(n("div"),"a",{get:function(){return 7}}).a}))}function Oe(){if(ce)return C;ce=1;var t=I(),e=$(),n=yt(),i=wt(),r=Ct(),o=we(),a=ve(),s=xe(),l=Object.getOwnPropertyDescriptor;return C.f=t?l:function(t,c){if(t=r(t),c=o(c),s)try{return l(t,c)}catch(t){}if(a(t,c))return i(!e(n.f,t,c),t[c])},C}var ke,Te,Ce,Pe,Ie,Ae,$e,Re={};function Ee(){if(Te)return ke;Te=1;var t=I(),e=P();return ke=t&&e((function(){return 42!==Object.defineProperty((function(){}),"prototype",{value:42,writable:!1}).prototype}))}function je(){if(Pe)return Ce;Pe=1;var t=It(),e=String,n=TypeError;return Ce=function(i){if(t(i))return i;throw new n(e(i)+" is not an object")}}function Ne(){if(Ie)return Re;Ie=1;var t=I(),e=xe(),n=Ee(),i=je(),r=we(),o=TypeError,a=Object.defineProperty,s=Object.getOwnPropertyDescriptor,l="enumerable",c="configurable",u="writable";return Re.f=t?n?function(t,e,n){if(i(t),e=r(e),i(n),"function"==typeof t&&"prototype"===e&&"value"in n&&u in n&&!n[u]){var o=s(t,e);o&&o[u]&&(t[e]=n.value,n={configurable:c in n?n[c]:o[c],enumerable:l in n?n[l]:o[l],writable:!1})}return a(t,e,n)}:a:function(t,n,s){if(i(t),n=r(n),i(s),e)try{return a(t,n,s)}catch(t){}if("get"in s||"set"in s)throw new o("Accessors not supported");return"value"in s&&(t[n]=s.value),t},Re}function Fe(){if($e)return Ae;$e=1;var t=I(),e=Ne(),n=wt();return Ae=t?function(t,i,r){return e.f(t,i,n(1,r))}:function(t,e,n){return t[e]=n,t}}var De,Le,_e,Ve,Be,He,Me,Ue,ze,qe,We,Ge,Ke,Je,Ye,Qe={exports:{}};function Xe(){if(Le)return De;Le=1;var t=I(),e=ve(),n=Function.prototype,i=t&&Object.getOwnPropertyDescriptor,r=e(n,"name"),o=r&&"something"===function(){}.name,a=r&&(!t||t&&i(n,"name").configurable);return De={EXISTS:r,PROPER:o,CONFIGURABLE:a}}function Ze(){if(Ve)return _e;Ve=1;var t=St(),e=Pt(),n=de(),i=t(Function.toString);return e(n.inspectSource)||(n.inspectSource=function(t){return i(t)}),_e=n.inspectSource}function tn(){if(Ue)return Me;Ue=1;var t=pe(),e=be(),n=t("keys");return Me=function(t){return n[t]||(n[t]=e(t))}}function en(){return qe?ze:(qe=1,ze={})}function nn(){if(Ge)return We;Ge=1;var t,e,n,i=function(){if(He)return Be;He=1;var t=b(),e=Pt(),n=t.WeakMap;return Be=e(n)&&/native code/.test(String(n))}(),r=b(),o=It(),a=Fe(),s=ve(),l=de(),c=tn(),u=en(),h="Object already initialized",f=r.TypeError,d=r.WeakMap;if(i||l.state){var p=l.state||(l.state=new d);p.get=p.get,p.has=p.has,p.set=p.set,t=function(t,e){if(p.has(t))throw new f(h);return e.facade=t,p.set(t,e),e},e=function(t){return p.get(t)||{}},n=function(t){return p.has(t)}}else{var g=c("state");u[g]=!0,t=function(t,e){if(s(t,g))throw new f(h);return e.facade=t,a(t,g,e),e},e=function(t){return s(t,g)?t[g]:{}},n=function(t){return s(t,g)}}return We={set:t,get:e,has:n,enforce:function(i){return n(i)?e(i):t(i,{})},getterFor:function(t){return function(n){var i;if(!o(n)||(i=e(n)).type!==t)throw new f("Incompatible receiver, "+t+" required");return i}}}}function rn(){if(Ke)return Qe.exports;Ke=1;var t=St(),e=P(),n=Pt(),i=ve(),r=I(),o=Xe().CONFIGURABLE,a=Ze(),s=nn(),l=s.enforce,c=s.get,u=String,h=Object.defineProperty,f=t("".slice),d=t("".replace),p=t([].join),g=r&&!e((function(){return 8!==h((function(){}),"length",{value:8}).length})),v=String(String).split("String"),b=Qe.exports=function(t,e,n){"Symbol("===f(u(e),0,7)&&(e="["+d(u(e),/^Symbol\(([^)]*)\).*$/,"$1")+"]"),n&&n.getter&&(e="get "+e),n&&n.setter&&(e="set "+e),(!i(t,"name")||o&&t.name!==e)&&(r?h(t,"name",{value:e,configurable:!0}):t.name=e),g&&n&&i(n,"arity")&&t.length!==n.arity&&h(t,"length",{value:n.arity});try{n&&i(n,"constructor")&&n.constructor?r&&h(t,"prototype",{writable:!1}):t.prototype&&(t.prototype=void 0)}catch(t){}var a=l(t);return i(a,"source")||(a.source=p(v,"string"==typeof e?e:"")),t};return Function.prototype.toString=b((function(){return n(this)&&c(this).source||a(this)}),"toString"),Qe.exports}function on(){if(Ye)return Je;Ye=1;var t=Pt(),e=Ne(),n=rn(),i=fe();return Je=function(r,o,a,s){s||(s={});var l=s.enumerable,c=void 0!==s.name?s.name:o;if(t(a)&&n(a,c,s),s.global)l?r[o]=a:i(o,a);else{try{s.unsafe?r[o]&&(l=!0):delete r[o]}catch(t){}l?r[o]=a:e.f(r,o,{value:a,enumerable:!1,configurable:!s.nonConfigurable,writable:!s.nonWritable})}return r}}var an,sn,ln,cn,un,hn,fn,dn,pn,gn,vn,bn,mn,yn,wn,Sn,xn,On={};function kn(){if(cn)return ln;cn=1;var t=function(){if(sn)return an;sn=1;var t=Math.ceil,e=Math.floor;return an=Math.trunc||function(n){var i=+n;return(i>0?e:t)(i)}}();return ln=function(e){var n=+e;return n!=n||0===n?0:t(n)}}function Tn(){if(hn)return un;hn=1;var t=kn(),e=Math.max,n=Math.min;return un=function(i,r){var o=t(i);return o<0?e(o+r,0):n(o,r)}}function Cn(){if(dn)return fn;dn=1;var t=kn(),e=Math.min;return fn=function(n){var i=t(n);return i>0?e(i,9007199254740991):0}}function Pn(){if(gn)return pn;gn=1;var t=Cn();return pn=function(e){return t(e.length)}}function In(){if(bn)return vn;bn=1;var t=Ct(),e=Tn(),n=Pn(),i=function(i){return function(r,o,a){var s=t(r),l=n(s);if(0===l)return!i&&-1;var c,u=e(a,l);if(i&&o!=o){for(;l>u;)if((c=s[u++])!=c)return!0}else for(;l>u;u++)if((i||u in s)&&s[u]===o)return i||u||0;return!i&&-1}};return vn={includes:i(!0),indexOf:i(!1)}}function An(){if(yn)return mn;yn=1;var t=St(),e=ve(),n=Ct(),i=In().indexOf,r=en(),o=t([].push);return mn=function(t,a){var s,l=n(t),c=0,u=[];for(s in l)!e(r,s)&&e(l,s)&&o(u,s);for(;a.length>c;)e(l,s=a[c++])&&(~i(u,s)||o(u,s));return u}}function $n(){return Sn?wn:(Sn=1,wn=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"])}function Rn(){if(xn)return On;xn=1;var t=An(),e=$n().concat("length","prototype");return On.f=Object.getOwnPropertyNames||function(n){return t(n,e)},On}var En,jn,Nn,Fn,Dn,Ln,_n,Vn,Bn,Hn,Mn,Un,zn,qn,Wn,Gn,Kn,Jn,Yn,Qn,Xn,Zn,ti,ei,ni,ii,ri,oi,ai={};function si(){return En||(En=1,ai.f=Object.getOwnPropertySymbols),ai}function li(){if(Nn)return jn;Nn=1;var t=At(),e=St(),n=Rn(),i=si(),r=je(),o=e([].concat);return jn=t("Reflect","ownKeys")||function(t){var e=n.f(r(t)),a=i.f;return a?o(e,a(t)):e}}function ci(){if(Dn)return Fn;Dn=1;var t=ve(),e=li(),n=Oe(),i=Ne();return Fn=function(r,o,a){for(var s=e(o),l=i.f,c=n.f,u=0;u9007199254740991)throw t("Maximum allowed index exceeded");return e}}function pi(){if(Wn)return qn;Wn=1;var t=I(),e=Ne(),n=wt();return qn=function(i,r,o){t?e.f(i,r,n(0,o)):i[r]=o}}function gi(){if(Kn)return Gn;Kn=1;var t={};return t[me()("toStringTag")]="z",Gn="[object z]"===String(t)}function vi(){if(Yn)return Jn;Yn=1;var t=gi(),e=Pt(),n=xt(),i=me()("toStringTag"),r=Object,o="Arguments"===n(function(){return arguments}());return Jn=t?n:function(t){var a,s,l;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(s=function(t,e){try{return t[e]}catch(t){}}(a=r(t),i))?s:o?n(a):"Object"===(l=n(a))&&e(a.callee)?"Arguments":l}}function bi(){if(Xn)return Qn;Xn=1;var t=St(),e=P(),n=Pt(),i=vi(),r=At(),o=Ze(),a=function(){},s=r("Reflect","construct"),l=/^\s*(?:class|function)\b/,c=t(l.exec),u=!l.test(a),h=function(t){if(!n(t))return!1;try{return s(a,[],t),!0}catch(t){return!1}},f=function(t){if(!n(t))return!1;switch(i(t)){case"AsyncFunction":case"GeneratorFunction":case"AsyncGeneratorFunction":return!1}try{return u||!!c(l,o(t))}catch(t){return!0}};return f.sham=!0,Qn=!s||e((function(){var t;return h(h.call)||!h(Object)||!h((function(){t=!0}))||t}))?f:h}function mi(){if(ti)return Zn;ti=1;var t=fi(),e=bi(),n=It(),i=me()("species"),r=Array;return Zn=function(o){var a;return t(o)&&(a=o.constructor,(e(a)&&(a===r||t(a.prototype))||n(a)&&null===(a=a[i]))&&(a=void 0)),void 0===a?r:a}}function yi(){if(ni)return ei;ni=1;var t=mi();return ei=function(e,n){return new(t(e))(0===n?0:n)}}function wi(){if(ri)return ii;ri=1;var t=P(),e=me(),n=Et(),i=e("species");return ii=function(e){return n>=51||!t((function(){var t=[];return(t.constructor={})[i]=function(){return{foo:1}},1!==t[e](Boolean).foo}))}}!function(){if(oi)return v;oi=1;var t=hi(),e=P(),n=fi(),i=It(),r=ge(),o=Pn(),a=di(),s=pi(),l=yi(),c=wi(),u=me(),h=Et(),f=u("isConcatSpreadable"),d=h>=51||!e((function(){var t=[];return t[f]=!1,t.concat()[0]!==t})),p=function(t){if(!i(t))return!1;var e=t[f];return void 0!==e?!!e:n(t)};t({target:"Array",proto:!0,arity:1,forced:!d||!c("concat")},{concat:function(t){var e,n,i,c,u,h=r(this),f=l(h,0),d=0;for(e=-1,i=arguments.length;ek;k++)if((d||k in S)&&(y=O(m=S[k],k,w),e))if(s)C[k]=y;else if(y)switch(e){case 3:return!0;case 5:return m;case 6:return k;case 2:a(C,m)}else switch(e){case 4:return!1;case 7:a(C,m)}return h?-1:c||u?u:C}};return Ti={forEach:s(0),map:s(1),filter:s(2),some:s(3),every:s(4),find:s(5),findIndex:s(6),filterReject:s(7)}}!function(){if(Pi)return Ii;Pi=1;var t=hi(),e=Ri().filter;t({target:"Array",proto:!0,forced:!wi()("filter")},{filter:function(t){return e(this,t,arguments.length>1?arguments[1]:void 0)}})}();var Ei,ji,Ni,Fi,Di,Li,_i,Vi,Bi,Hi,Mi={},Ui={};function zi(){if(ji)return Ei;ji=1;var t=An(),e=$n();return Ei=Object.keys||function(n){return t(n,e)}}function qi(){if(Di)return Fi;Di=1;var t=At();return Fi=t("document","documentElement")}function Wi(){if(_i)return Li;_i=1;var t,e=je(),n=function(){if(Ni)return Ui;Ni=1;var t=I(),e=Ee(),n=Ne(),i=je(),r=Ct(),o=zi();return Ui.f=t&&!e?Object.defineProperties:function(t,e){i(t);for(var a,s=r(e),l=o(e),c=l.length,u=0;c>u;)n.f(t,a=l[u++],s[a]);return t},Ui}(),i=$n(),r=en(),o=qi(),a=Se(),s=tn(),l="prototype",c="script",u=s("IE_PROTO"),h=function(){},f=function(t){return"<"+c+">"+t+""},d=function(t){t.write(f("")),t.close();var e=t.parentWindow.Object;return t=null,e},p=function(){try{t=new ActiveXObject("htmlfile")}catch(t){}var e,n,r;p="undefined"!=typeof document?document.domain&&t?d(t):(n=a("iframe"),r="java"+c+":",n.style.display="none",o.appendChild(n),n.src=String(r),(e=n.contentWindow.document).open(),e.write(f("document.F=Object")),e.close(),e.F):d(t);for(var s=i.length;s--;)delete p[l][i[s]];return p()};return r[u]=!0,Li=Object.create||function(t,i){var r;return null!==t?(h[l]=e(t),r=new h,h[l]=null,r[u]=t):r=p(),void 0===i?r:n.f(r,i)}}function Gi(){if(Bi)return Vi;Bi=1;var t=me(),e=Wi(),n=Ne().f,i=t("unscopables"),r=Array.prototype;return void 0===r[i]&&n(r,i,{configurable:!0,value:e(null)}),Vi=function(t){r[i][t]=!0}}!function(){if(Hi)return Mi;Hi=1;var t=hi(),e=Ri().find,n=Gi(),i="find",r=!0;i in[]&&Array(1)[i]((function(){r=!1})),t({target:"Array",proto:!0,forced:r},{find:function(t){return e(this,t,arguments.length>1?arguments[1]:void 0)}}),n(i)}();var Ki,Ji={};!function(){if(Ki)return Ji;Ki=1;var t=hi(),e=Ri().findIndex,n=Gi(),i="findIndex",r=!0;i in[]&&Array(1)[i]((function(){r=!1})),t({target:"Array",proto:!0,forced:r},{findIndex:function(t){return e(this,t,arguments.length>1?arguments[1]:void 0)}}),n(i)}();var Yi,Qi={};!function(){if(Yi)return Qi;Yi=1;var t=hi(),e=In().includes,n=P(),i=Gi();t({target:"Array",proto:!0,forced:n((function(){return!Array(1).includes()}))},{includes:function(t){return e(this,t,arguments.length>1?arguments[1]:void 0)}}),i("includes")}();var Xi,Zi,tr,er,nr,ir,rr,or,ar,sr,lr,cr,ur,hr,fr,dr,pr,gr,vr,br,mr,yr,wr,Sr,xr,Or,kr,Tr,Cr,Pr={};function Ir(){if(Zi)return Xi;Zi=1;var t=P();return Xi=function(e,n){var i=[][e];return!!i&&t((function(){i.call(null,n||function(){return 1},1)}))}}function Ar(){return nr?er:(nr=1,er={})}function $r(){if(rr)return ir;rr=1;var t=P();return ir=!t((function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype}))}function Rr(){if(ar)return or;ar=1;var t=ve(),e=Pt(),n=ge(),i=tn(),r=$r(),o=i("IE_PROTO"),a=Object,s=a.prototype;return or=r?a.getPrototypeOf:function(i){var r=n(i);if(t(r,o))return r[o];var l=r.constructor;return e(l)&&r instanceof l?l.prototype:r instanceof a?s:null}}function Er(){if(lr)return sr;lr=1;var t,e,n,i=P(),r=Pt(),o=It(),a=Wi(),s=Rr(),l=on(),c=me(),u=he(),h=c("iterator"),f=!1;return[].keys&&("next"in(n=[].keys())?(e=s(s(n)))!==Object.prototype&&(t=e):f=!0),!o(t)||i((function(){var e={};return t[h].call(e)!==e}))?t={}:u&&(t=a(t)),r(t[h])||l(t,h,(function(){return this})),sr={IteratorPrototype:t,BUGGY_SAFARI_ITERATORS:f}}function jr(){if(ur)return cr;ur=1;var t=Ne().f,e=ve(),n=me()("toStringTag");return cr=function(i,r,o){i&&!o&&(i=i.prototype),i&&!e(i,n)&&t(i,n,{configurable:!0,value:r})}}function Nr(){if(fr)return hr;fr=1;var t=Er().IteratorPrototype,e=Wi(),n=wt(),i=jr(),r=Ar(),o=function(){return this};return hr=function(a,s,l,c){var u=s+" Iterator";return a.prototype=e(t,{next:n(+!c,l)}),i(a,u,!1,!0),r[u]=o,a}}function Fr(){if(vr)return gr;vr=1;var t=It();return gr=function(e){return t(e)||null===e}}function Dr(){if(mr)return br;mr=1;var t=Fr(),e=String,n=TypeError;return br=function(i){if(t(i))return i;throw new n("Can't set "+e(i)+" as a prototype")}}function Lr(){if(wr)return yr;wr=1;var t=function(){if(pr)return dr;pr=1;var t=St(),e=Lt();return dr=function(n,i,r){try{return t(e(Object.getOwnPropertyDescriptor(n,i)[r]))}catch(t){}}}(),e=It(),n=Tt(),i=Dr();return yr=Object.setPrototypeOf||("__proto__"in{}?function(){var r,o=!1,a={};try{(r=t(Object.prototype,"__proto__","set"))(a,[]),o=a instanceof Array}catch(t){}return function(t,a){return n(t),i(a),e(t)?(o?r(t,a):t.__proto__=a,t):t}}():void 0)}function _r(){if(xr)return Sr;xr=1;var t=hi(),e=$(),n=he(),i=Xe(),r=Pt(),o=Nr(),a=Rr(),s=Lr(),l=jr(),c=Fe(),u=on(),h=me(),f=Ar(),d=Er(),p=i.PROPER,g=i.CONFIGURABLE,v=d.IteratorPrototype,b=d.BUGGY_SAFARI_ITERATORS,m=h("iterator"),y="keys",w="values",S="entries",x=function(){return this};return Sr=function(i,h,d,O,k,T,C){o(d,h,O);var P,I,A,$=function(t){if(t===k&&F)return F;if(!b&&t&&t in j)return j[t];switch(t){case y:case w:case S:return function(){return new d(this,t)}}return function(){return new d(this)}},R=h+" Iterator",E=!1,j=i.prototype,N=j[m]||j["@@iterator"]||k&&j[k],F=!b&&N||$(k),D="Array"===h&&j.entries||N;if(D&&(P=a(D.call(new i)))!==Object.prototype&&P.next&&(n||a(P)===v||(s?s(P,v):r(P[m])||u(P,m,x)),l(P,R,!0,!0),n&&(f[R]=x)),p&&k===w&&N&&N.name!==w&&(!n&&g?c(j,"name",w):(E=!0,F=function(){return e(N,this)})),k)if(I={values:$(w),keys:T?F:$(y),entries:$(S)},C)for(A in I)(b||E||!(A in j))&&u(j,A,I[A]);else t({target:h,proto:!0,forced:b||E},I);return n&&!C||j[m]===F||u(j,m,F,{name:k}),f[h]=F,I}}function Vr(){return kr?Or:(kr=1,Or=function(t,e){return{value:t,done:e}})}function Br(){if(Cr)return Tr;Cr=1;var t=Ct(),e=Gi(),n=Ar(),i=nn(),r=Ne().f,o=_r(),a=Vr(),s=he(),l=I(),c="Array Iterator",u=i.set,h=i.getterFor(c);Tr=o(Array,"Array",(function(e,n){u(this,{type:c,target:t(e),index:0,kind:n})}),(function(){var t=h(this),e=t.target,n=t.index++;if(!e||n>=e.length)return t.target=null,a(void 0,!0);switch(t.kind){case"keys":return a(n,!1);case"values":return a(e[n],!1)}return a([n,e[n]],!1)}),"values");var f=n.Arguments=n.Array;if(e("keys"),e("values"),e("entries"),!s&&l&&"values"!==f.name)try{r(f,"name",{value:"values"})}catch(t){}return Tr}!function(){if(tr)return Pr;tr=1;var t=hi(),e=Ai(),n=In().indexOf,i=Ir(),r=e([].indexOf),o=!!r&&1/r([1],1,-0)<0;t({target:"Array",proto:!0,forced:o||!i("indexOf")},{indexOf:function(t){var e=arguments.length>1?arguments[1]:void 0;return o?r(this,t,e)||0:n(this,t,e)}})}(),Br();var Hr,Mr={};!function(){if(Hr)return Mr;Hr=1;var t=hi(),e=St(),n=Ot(),i=Ct(),r=Ir(),o=e([].join);t({target:"Array",proto:!0,forced:n!==Object||!r("join",",")},{join:function(t){return o(i(this),void 0===t?",":t)}})}();var Ur,zr={};!function(){if(Ur)return zr;Ur=1;var t=hi(),e=Ri().map;t({target:"Array",proto:!0,forced:!wi()("map")},{map:function(t){return e(this,t,arguments.length>1?arguments[1]:void 0)}})}();var qr,Wr={};!function(){if(qr)return Wr;qr=1;var t=hi(),e=St(),n=fi(),i=e([].reverse),r=[1,2];t({target:"Array",proto:!0,forced:String(r)===String(r.reverse())},{reverse:function(){return n(this)&&(this.length=this.length),i(this)}})}();var Gr,Kr,Jr,Yr={};function Qr(){if(Kr)return Gr;Kr=1;var t=St();return Gr=t([].slice)}!function(){if(Jr)return Yr;Jr=1;var t=hi(),e=fi(),n=bi(),i=It(),r=Tn(),o=Pn(),a=Ct(),s=pi(),l=me(),c=wi(),u=Qr(),h=c("slice"),f=l("species"),d=Array,p=Math.max;t({target:"Array",proto:!0,forced:!h},{slice:function(t,l){var c,h,g,v=a(this),b=o(v),m=r(t,b),y=r(void 0===l?b:l,b);if(e(v)&&(c=v.constructor,(n(c)&&(c===d||e(c.prototype))||i(c)&&null===(c=c[f]))&&(c=void 0),c===d||void 0===c))return u(v,m,y);for(h=new(void 0===c?d:c)(p(y-m,0)),g=0;m0;)i[s]=i[--s];s!==l++&&(i[s]=a)}else for(var c=e(o/2),u=n(t(i,0,c),r),h=n(t(i,c),r),f=u.length,d=h.length,p=0,g=0;p3)){if(h)return!0;if(d)return d<603;var t,e,n,i,r="";for(t=65;t<76;t++){switch(e=String.fromCharCode(t),t){case 66:case 69:case 70:case 72:n=3;break;case 68:case 71:n=4;break;default:n=2}for(i=0;i<47;i++)p.push({k:e+i,v:n})}for(p.sort((function(t,e){return e.v-t.v})),i=0;ia(n)?1:-1}}(t)),s=r(u),c=0;cw-p+d;v--)c(y,v-1)}else if(d>p)for(v=w-p;v>S;v--)m=v+d-1,(b=v+p-1)in y?y[m]=y[b]:c(y,m);for(v=0;v2)if(c=m(c),43===(e=T(c,0))||45===e){if(88===(n=T(c,2))||120===n)return NaN}else if(48===e){switch(T(c,1)){case 66:case 98:i=2,r=49;break;case 79:case 111:i=8,r=55;break;default:return+c}for(a=(o=k(c,2)).length,s=0;sr)return NaN;return parseInt(o,i)}return+c},A=a(y,!w(" 0o1")||!w("0b1")||w("+0x1")),$=function(t){var e,n=arguments.length<1?0:w(function(t){var e=h(t,"number");return"bigint"==typeof e?e:C(e)}(t));return c(x,e=this)&&f((function(){v(e)}))?l(Object(n),this,$):n};$.prototype=x,A&&!e&&(x.constructor=$),t({global:!0,constructor:!0,wrap:!0,forced:A},{Number:$});var R=function(t,e){for(var i,r=n?d(e):"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,isFinite,isInteger,isNaN,isSafeInteger,parseFloat,parseInt,fromString,range".split(","),o=0;r.length>o;o++)s(e,i=r[o])&&!s(t,i)&&g(t,i,p(e,i))};e&&S&&R(r[y],S),(A||e)&&R(r[y],w)}();var Vo,Bo,Ho,Mo={};!function(){if(Ho)return Mo;Ho=1;var t=hi(),e=function(){if(Bo)return Vo;Bo=1;var t=I(),e=St(),n=$(),i=P(),r=zi(),o=si(),a=yt(),s=ge(),l=Ot(),c=Object.assign,u=Object.defineProperty,h=e([].concat);return Vo=!c||i((function(){if(t&&1!==c({b:1},c(u({},"a",{enumerable:!0,get:function(){u(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var e={},n={},i=Symbol("assign detection"),o="abcdefghijklmnopqrst";return e[i]=7,o.split("").forEach((function(t){n[t]=t})),7!==c({},e)[i]||r(c({},n)).join("")!==o}))?function(e,i){for(var c=s(e),u=arguments.length,f=1,d=o.f,p=a.f;u>f;)for(var g,v=l(arguments[f++]),b=d?h(r(v),d(v)):r(v),m=b.length,y=0;m>y;)g=b[y++],t&&!n(p,v,g)||(c[g]=v[g]);return c}:c,Vo}();t({target:"Object",stat:!0,arity:2,forced:Object.assign!==e},{assign:e})}();var Uo,zo,qo,Wo={};!function(){if(qo)return Wo;qo=1;var t=hi(),e=function(){if(zo)return Uo;zo=1;var t=I(),e=P(),n=St(),i=Rr(),r=zi(),o=Ct(),a=n(yt().f),s=n([].push),l=t&&e((function(){var t=Object.create(null);return t[2]=2,!a(t,2)})),c=function(e){return function(n){for(var c,u=o(n),h=r(u),f=l&&null===i(u),d=h.length,p=0,g=[];d>p;)c=h[p++],t&&!(f?c in u:a(u,c))||s(g,e?[c,u[c]]:u[c]);return g}};return Uo={entries:c(!0),values:c(!1)}}().entries;t({target:"Object",stat:!0},{entries:function(t){return e(t)}})}();var Go,Ko={};!function(){if(Go)return Ko;Go=1;var t=hi(),e=ge(),n=zi();t({target:"Object",stat:!0,forced:P()((function(){n(1)}))},{keys:function(t){return n(e(t))}})}();var Jo,Yo,Qo,Xo={};!function(){if(Qo)return Xo;Qo=1;var t=gi(),e=on(),n=function(){if(Yo)return Jo;Yo=1;var t=gi(),e=vi();return Jo=t?{}.toString:function(){return"[object "+e(this)+"]"}}();t||e(Object.prototype,"toString",n,{unsafe:!0})}();var Zo,ta,ea,na={};!function(){if(ea)return na;ea=1;var t=hi(),e=function(){if(ta)return Zo;ta=1;var t=b(),e=P(),n=St(),i=po(),r=_o().trim,o=Lo(),a=n("".charAt),s=t.parseFloat,l=t.Symbol,c=l&&l.iterator,u=1/s(o+"-0")!=-1/0||c&&!e((function(){s(Object(c))}));return Zo=u?function(t){var e=r(i(t)),n=s(e);return 0===n&&"-"===a(e,0)?-0:n}:s}();t({global:!0,forced:parseFloat!==e},{parseFloat:e})}();var ia,ra,oa,aa={};!function(){if(oa)return aa;oa=1;var t=hi(),e=function(){if(ra)return ia;ra=1;var t=b(),e=P(),n=St(),i=po(),r=_o().trim,o=Lo(),a=t.parseInt,s=t.Symbol,l=s&&s.iterator,c=/^[+-]?0x/i,u=n(c.exec),h=8!==a(o+"08")||22!==a(o+"0x16")||l&&!e((function(){a(Object(l))}));return ia=h?function(t,e){var n=r(i(t));return a(n,e>>>0||(u(c,n)?16:10))}:a}();t({global:!0,forced:parseInt!==e},{parseInt:e})}();var sa,la,ca,ua,ha,fa,da,pa,ga,va,ba,ma,ya,wa,Sa,xa,Oa,ka,Ta,Ca={};function Pa(){if(la)return sa;la=1;var t=It(),e=xt(),n=me()("match");return sa=function(i){var r;return t(i)&&(void 0!==(r=i[n])?!!r:"RegExp"===e(i))}}function Ia(){if(ua)return ca;ua=1;var t=je();return ca=function(){var e=t(this),n="";return e.hasIndices&&(n+="d"),e.global&&(n+="g"),e.ignoreCase&&(n+="i"),e.multiline&&(n+="m"),e.dotAll&&(n+="s"),e.unicode&&(n+="u"),e.unicodeSets&&(n+="v"),e.sticky&&(n+="y"),n}}function Aa(){if(fa)return ha;fa=1;var t=$(),e=ve(),n=$t(),i=Ia(),r=RegExp.prototype;return ha=function(o){var a=o.flags;return void 0!==a||"flags"in r||e(o,"flags")||!n(r,o)?a:t(i,o)}}function $a(){if(pa)return da;pa=1;var t=P(),e=b().RegExp,n=t((function(){var t=e("a","y");return t.lastIndex=2,null!==t.exec("abcd")})),i=n||t((function(){return!e("a","y").sticky})),r=n||t((function(){var t=e("^r","gy");return t.lastIndex=2,null!==t.exec("str")}));return da={BROKEN_CARET:r,MISSED_STICKY:i,UNSUPPORTED_Y:n}}function Ra(){if(va)return ga;va=1;var t=Ne().f;return ga=function(e,n,i){i in e||t(e,i,{configurable:!0,get:function(){return n[i]},set:function(t){n[i]=t}})}}function Ea(){if(ma)return ba;ma=1;var t=rn(),e=Ne();return ba=function(n,i,r){return r.get&&t(r.get,i,{getter:!0}),r.set&&t(r.set,i,{setter:!0}),e.f(n,i,r)}}function ja(){if(wa)return ya;wa=1;var t=At(),e=Ea(),n=me(),i=I(),r=n("species");return ya=function(n){var o=t(n);i&&o&&!o[r]&&e(o,r,{configurable:!0,get:function(){return this}})}}function Na(){if(xa)return Sa;xa=1;var t=P(),e=b().RegExp;return Sa=t((function(){var t=e(".","s");return!(t.dotAll&&t.test("\n")&&"s"===t.flags)}))}function Fa(){if(ka)return Oa;ka=1;var t=P(),e=b().RegExp;return Oa=t((function(){var t=e("(?b)","g");return"b"!==t.exec("b").groups.a||"bc"!=="b".replace(t,"$c")}))}!function(){if(Ta)return Ca;Ta=1;var t=I(),e=b(),n=St(),i=ui(),r=Fo(),o=Fe(),a=Wi(),s=Rn().f,l=$t(),c=Pa(),u=po(),h=Aa(),f=$a(),d=Ra(),p=on(),g=P(),v=ve(),m=nn().enforce,y=ja(),w=me(),S=Na(),x=Fa(),O=w("match"),k=e.RegExp,T=k.prototype,C=e.SyntaxError,A=n(T.exec),$=n("".charAt),R=n("".replace),E=n("".indexOf),j=n("".slice),N=/^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/,F=/a/g,D=/a/g,L=new k(F)!==F,_=f.MISSED_STICKY,V=f.UNSUPPORTED_Y,B=t&&(!L||_||S||x||g((function(){return D[O]=!1,k(F)!==F||k(D)===D||"/a/i"!==String(k(F,"i"))})));if(i("RegExp",B)){for(var H=function(t,e){var n,i,s,f,d,p,g=l(T,this),b=c(t),y=void 0===e,w=[],O=t;if(!g&&b&&y&&t.constructor===H)return t;if((b||l(T,t))&&(t=t.source,y&&(e=h(O))),t=void 0===t?"":u(t),e=void 0===e?"":u(e),O=t,S&&"dotAll"in F&&(i=!!e&&E(e,"s")>-1)&&(e=R(e,/s/g,"")),n=e,_&&"sticky"in F&&(s=!!e&&E(e,"y")>-1)&&V&&(e=R(e,/y/g,"")),x&&(f=function(t){for(var e,n=t.length,i=0,r="",o=[],s=a(null),l=!1,c=!1,u=0,h="";i<=n;i++){if("\\"===(e=$(t,i)))e+=$(t,++i);else if("]"===e)l=!1;else if(!l)switch(!0){case"["===e:l=!0;break;case"("===e:if(r+=e,"?:"===j(t,i+1,i+3))continue;A(N,j(t,i+1))&&(i+=2,c=!0),u++;continue;case">"===e&&c:if(""===h||v(s,h))throw new C("Invalid capture group name");s[h]=!0,o[o.length]=[h,u],c=!1,h="";continue}c?h+=e:r+=e}return[r,o]}(t),t=f[0],w=f[1]),d=r(k(t,e),g?this:T,H),(i||s||w.length)&&(p=m(d),i&&(p.dotAll=!0,p.raw=H(function(t){for(var e,n=t.length,i=0,r="",o=!1;i<=n;i++)"\\"!==(e=$(t,i))?o||"."!==e?("["===e?o=!0:"]"===e&&(o=!1),r+=e):r+="[\\s\\S]":r+=e+$(t,++i);return r}(t),n)),s&&(p.sticky=!0),w.length&&(p.groups=w)),t!==O)try{o(d,"source",""===O?"(?:)":O)}catch(t){}return d},M=s(k),U=0;M.length>U;)d(H,k,M[U++]);T.constructor=H,H.prototype=T,p(e,"RegExp",H,{constructor:!0})}y("RegExp")}();var Da,La,_a,Va={};function Ba(){if(La)return Da;La=1;var t,e,n=$(),i=St(),r=po(),o=Ia(),a=$a(),s=pe(),l=Wi(),c=nn().get,u=Na(),h=Fa(),f=s("native-string-replace",String.prototype.replace),d=RegExp.prototype.exec,p=d,g=i("".charAt),v=i("".indexOf),b=i("".replace),m=i("".slice),y=(e=/b*/g,n(d,t=/a/,"a"),n(d,e,"a"),0!==t.lastIndex||0!==e.lastIndex),w=a.BROKEN_CARET,S=void 0!==/()??/.exec("")[1];return(y||S||w||u||h)&&(p=function(t){var e,i,a,s,u,h,x,O=this,k=c(O),T=r(t),C=k.raw;if(C)return C.lastIndex=O.lastIndex,e=n(p,C,T),O.lastIndex=C.lastIndex,e;var P=k.groups,I=w&&O.sticky,A=n(o,O),$=O.source,R=0,E=T;if(I&&(A=b(A,"y",""),-1===v(A,"g")&&(A+="g"),E=m(T,O.lastIndex),O.lastIndex>0&&(!O.multiline||O.multiline&&"\n"!==g(T,O.lastIndex-1))&&($="(?: "+$+")",E=" "+E,R++),i=new RegExp("^(?:"+$+")",A)),S&&(i=new RegExp("^"+$+"$(?!\\s)",A)),y&&(a=O.lastIndex),s=n(d,I?i:O,E),I?s?(s.input=m(s.input,R),s[0]=m(s[0],R),s.index=O.lastIndex,O.lastIndex+=s[0].length):O.lastIndex=0:y&&s&&(O.lastIndex=O.global?s.index+s[0].length:a),S&&s&&s.length>1&&n(f,s[0],i,(function(){for(u=1;u1?arguments[1]:void 0)}})}();var Xa,Za,ts,es,ns,is,rs,os,as,ss,ls,cs,us,hs={};function fs(){if(es)return ts;es=1,Ha();var t=$(),e=on(),n=Ba(),i=P(),r=me(),o=Fe(),a=r("species"),s=RegExp.prototype;return ts=function(l,c,u,h){var f=r(l),d=!i((function(){var t={};return t[f]=function(){return 7},7!==""[l](t)})),p=d&&!i((function(){var t=!1,e=/a/;return"split"===l&&((e={}).constructor={},e.constructor[a]=function(){return e},e.flags="",e[f]=/./[f]),e.exec=function(){return t=!0,null},e[f](""),!t}));if(!d||!p||u){var g=/./[f],v=c(f,""[l],(function(e,i,r,o,a){var l=i.exec;return l===n||l===s.exec?d&&!a?{done:!0,value:t(g,i,r,o)}:{done:!0,value:t(e,r,i,o)}:{done:!1}}));e(String.prototype,l,v[0]),e(s,f,v[1])}h&&o(s[f],"sham",!0)}}function ds(){if(is)return ns;is=1;var t=St(),e=kn(),n=po(),i=Tt(),r=t("".charAt),o=t("".charCodeAt),a=t("".slice),s=function(t){return function(s,l){var c,u,h=n(i(s)),f=e(l),d=h.length;return f<0||f>=d?t?"":void 0:(c=o(h,f))<55296||c>56319||f+1===d||(u=o(h,f+1))<56320||u>57343?t?r(h,f):c:t?a(h,f,f+2):u-56320+(c-55296<<10)+65536}};return ns={codeAt:s(!1),charAt:s(!0)}}function ps(){if(os)return rs;os=1;var t=ds().charAt;return rs=function(e,n,i){return n+(i?t(e,n).length:1)}}function gs(){if(ss)return as;ss=1;var t=St(),e=ge(),n=Math.floor,i=t("".charAt),r=t("".replace),o=t("".slice),a=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,s=/\$([$&'`]|\d{1,2})/g;return as=function(t,l,c,u,h,f){var d=c+t.length,p=u.length,g=s;return void 0!==h&&(h=e(h),g=a),r(f,g,(function(e,r){var a;switch(i(r,0)){case"$":return"$";case"&":return t;case"`":return o(l,0,c);case"'":return o(l,d);case"<":a=h[o(r,1,-1)];break;default:var s=+r;if(0===s)return e;if(s>p){var f=n(s/10);return 0===f?e:f<=p?void 0===u[f-1]?i(r,1):u[f-1]+i(r,1):e}a=u[s-1]}return void 0===a?"":a}))}}function vs(){if(cs)return ls;cs=1;var t=$(),e=je(),n=Pt(),i=xt(),r=Ba(),o=TypeError;return ls=function(a,s){var l=a.exec;if(n(l)){var c=t(l,a,s);return null!==c&&e(c),c}if("RegExp"===i(a))return t(r,a,s);throw new o("RegExp#exec called on incompatible receiver")}}!function(){if(us)return hs;us=1;var t=function(){if(Za)return Xa;Za=1;var t=A(),e=Function.prototype,n=e.apply,i=e.call;return Xa="object"==typeof Reflect&&Reflect.apply||(t?i.bind(n):function(){return i.apply(n,arguments)}),Xa}(),e=$(),n=St(),i=fs(),r=P(),o=je(),a=Pt(),s=kt(),l=kn(),c=Cn(),u=po(),h=Tt(),f=ps(),d=_t(),p=gs(),g=vs(),v=me()("replace"),b=Math.max,m=Math.min,y=n([].concat),w=n([].push),S=n("".indexOf),x=n("".slice),O="$0"==="a".replace(/./,"$0"),k=!!/./[v]&&""===/./[v]("a","$0");i("replace",(function(n,i,r){var O=k?"$":"$0";return[function(t,n){var r=h(this),o=s(t)?void 0:d(t,v);return o?e(o,t,r,n):e(i,u(r),t,n)},function(e,n){var s=o(this),h=u(e);if("string"==typeof n&&-1===S(n,O)&&-1===S(n,"$<")){var d=r(i,s,h,n);if(d.done)return d.value}var v=a(n);v||(n=u(n));var k,T=s.global;T&&(k=s.unicode,s.lastIndex=0);for(var C,P=[];null!==(C=g(s,h))&&(w(P,C),T);){""===u(C[0])&&(s.lastIndex=f(h,c(s.lastIndex),k))}for(var I,A="",$=0,R=0;R=$&&(A+=x(h,$,N)+E,$=N+j.length)}return A+x(h,$)}]}),!!r((function(){var t=/./;return t.exec=function(){var t=[];return t.groups={a:"7"},t},"7"!=="".replace(t,"$")}))||!O||k)}();var bs,ms,ys,ws={};function Ss(){return ms?bs:(ms=1,bs=Object.is||function(t,e){return t===e?0!==t||1/t==1/e:t!=t&&e!=e})}!function(){if(ys)return ws;ys=1;var t=$(),e=fs(),n=je(),i=kt(),r=Tt(),o=Ss(),a=po(),s=_t(),l=vs();e("search",(function(e,c,u){return[function(n){var o=r(this),l=i(n)?void 0:s(n,e);return l?t(l,n,o):new RegExp(n)[e](a(o))},function(t){var e=n(this),i=a(t),r=u(c,e,i);if(r.done)return r.value;var s=e.lastIndex;o(s,0)||(e.lastIndex=0);var h=l(e,i);return o(e.lastIndex,s)||(e.lastIndex=s),null===h?-1:h.index}]}))}();var xs,Os,ks,Ts,Cs,Ps={};function Is(){if(Os)return xs;Os=1;var t=bi(),e=Dt(),n=TypeError;return xs=function(i){if(t(i))return i;throw new n(e(i)+" is not a constructor")}}function As(){if(Ts)return ks;Ts=1;var t=je(),e=Is(),n=kt(),i=me()("species");return ks=function(r,o){var a,s=t(r).constructor;return void 0===s||n(a=t(s)[i])?o:e(a)}}!function(){if(Cs)return Ps;Cs=1;var t=$(),e=St(),n=fs(),i=je(),r=kt(),o=Tt(),a=As(),s=ps(),l=Cn(),c=po(),u=_t(),h=vs(),f=$a(),d=P(),p=f.UNSUPPORTED_Y,g=Math.min,v=e([].push),b=e("".slice),m=!d((function(){var t=/(?:)/,e=t.exec;t.exec=function(){return e.apply(this,arguments)};var n="ab".split(t);return 2!==n.length||"a"!==n[0]||"b"!==n[1]})),y="c"==="abbc".split(/(b)*/)[1]||4!=="test".split(/(?:)/,-1).length||2!=="ab".split(/(?:ab)*/).length||4!==".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length;n("split",(function(e,n,f){var d="0".split(void 0,0).length?function(e,i){return void 0===e&&0===i?[]:t(n,this,e,i)}:n;return[function(n,i){var a=o(this),s=r(n)?void 0:u(n,e);return s?t(s,n,a,i):t(d,c(a),n,i)},function(t,e){var r=i(this),o=c(t);if(!y){var u=f(d,r,o,e,d!==n);if(u.done)return u.value}var m=a(r,RegExp),w=r.unicode,S=(r.ignoreCase?"i":"")+(r.multiline?"m":"")+(r.unicode?"u":"")+(p?"g":"y"),x=new m(p?"^(?:"+r.source+")":r,S),O=void 0===e?4294967295:e>>>0;if(0===O)return[];if(0===o.length)return null===h(x,o)?[o]:[];for(var k=0,T=0,C=[];T1?arguments[1]:void 0)},_s}(),r=Fe(),o=function(t){if(t&&t.forEach!==i)try{r(t,"forEach",i)}catch(e){t.forEach=i}};for(var a in e)e[a]&&o(t[a]&&t[a].prototype);o(n)}();var zs,qs={};!function(){if(zs)return qs;zs=1;var t=b(),e=Ms(),n=Us(),i=Br(),r=Fe(),o=jr(),a=me()("iterator"),s=i.values,l=function(t,n){if(t){if(t[a]!==s)try{r(t,a,s)}catch(e){t[a]=s}if(o(t,n,!0),e[n])for(var l in i)if(t[l]!==i[l])try{r(t,l,i[l])}catch(e){t[l]=i[l]}}};for(var c in e)l(t[c]&&t[c].prototype,c);l(n,"DOMTokenList")}();var Ws,Gs={};!function(){if(Ws)return Gs;Ws=1;var t=hi(),e=P(),n=ge(),i=Rr(),r=$r();t({target:"Object",stat:!0,forced:e((function(){i(1)})),sham:!r},{getPrototypeOf:function(t){return i(n(t))}})}();var Ks,Js={};!function(){if(Ks)return Js;Ks=1;var t,e=hi(),n=Ai(),i=Oe().f,r=Cn(),o=po(),a=Ya(),s=Tt(),l=Qa(),c=he(),u=n("".slice),h=Math.min,f=l("endsWith");e({target:"String",proto:!0,forced:!!(c||f||(t=i(String.prototype,"endsWith"),!t||t.writable))&&!f},{endsWith:function(t){var e=o(s(this));a(t);var n=arguments.length>1?arguments[1]:void 0,i=e.length,l=void 0===n?i:h(r(n),i),c=o(t);return u(e,l-c.length,l)===c}})}();var Ys,Qs={};!function(){if(Ys)return Qs;Ys=1;var t=ds().charAt,e=po(),n=nn(),i=_r(),r=Vr(),o="String Iterator",a=n.set,s=n.getterFor(o);i(String,"String",(function(t){a(this,{type:o,string:e(t),index:0})}),(function(){var e,n=s(this),i=n.string,o=n.index;return o>=i.length?r(void 0,!0):(e=t(i,o),n.index+=e.length,r(e,!1))}))}();var Xs,Zs={};!function(){if(Xs)return Zs;Xs=1;var t=$(),e=fs(),n=je(),i=kt(),r=Cn(),o=po(),a=Tt(),s=_t(),l=ps(),c=vs();e("match",(function(e,u,h){return[function(n){var r=a(this),l=i(n)?void 0:s(n,e);return l?t(l,n,r):new RegExp(n)[e](o(r))},function(t){var e=n(this),i=o(t),a=h(u,e,i);if(a.done)return a.value;if(!e.global)return c(e,i);var s=e.unicode;e.lastIndex=0;for(var f,d=[],p=0;null!==(f=c(e,i));){var g=o(f[0]);d[p]=g,""===g&&(e.lastIndex=l(i,r(e.lastIndex),s)),p++}return 0===p?null:d}]}))}();var tl,el={};!function(){if(tl)return el;tl=1;var t,e=hi(),n=Ai(),i=Oe().f,r=Cn(),o=po(),a=Ya(),s=Tt(),l=Qa(),c=he(),u=n("".slice),h=Math.min,f=l("startsWith");e({target:"String",proto:!0,forced:!!(c||f||(t=i(String.prototype,"startsWith"),!t||t.writable))&&!f},{startsWith:function(t){var e=o(s(this));a(t);var n=r(h(arguments.length>1?arguments[1]:void 0,e.length)),i=o(t);return u(e,n,n+i.length)===i}})}();var nl,il,rl,ol,al,sl,ll,cl,ul,hl,fl,dl,pl,gl,vl,bl,ml,yl,wl={};function Sl(){if(rl)return il;rl=1;var t=b(),e=I(),n=Object.getOwnPropertyDescriptor;return il=function(i){if(!e)return t[i];var r=n(t,i);return r&&r.value}}function xl(){if(ll)return sl;ll=1;var t=on();return sl=function(e,n,i){for(var r in n)t(e,r,n[r],i);return e}}function Ol(){if(ul)return cl;ul=1;var t=$t(),e=TypeError;return cl=function(n,i){if(t(i,n))return n;throw new e("Incorrect invocation")}}function kl(){if(fl)return hl;fl=1;var t=vi(),e=_t(),n=kt(),i=Ar(),r=me()("iterator");return hl=function(o){if(!n(o))return e(o,r)||e(o,"@@iterator")||i[t(o)]}}function Tl(){if(pl)return dl;pl=1;var t=$(),e=Lt(),n=je(),i=Dt(),r=kl(),o=TypeError;return dl=function(a,s){var l=arguments.length<2?r(a):s;if(e(l))return n(t(l,a));throw new o(i(a)+" is not iterable")},dl}function Cl(){if(vl)return gl;vl=1;var t=TypeError;return gl=function(e,n){if(el;){if(e=+arguments[l++],n(e,1114111)!==e)throw new i(e+" is not a valid code point");o[l]=e<65536?r(e):r(55296+((e-=65536)>>10),e%1024+56320)}return a(o,"")}})}();var t=hi(),e=b(),n=Sl(),i=At(),r=$(),o=St(),a=I(),s=function(){if(al)return ol;al=1;var t=P(),e=me(),n=I(),i=he(),r=e("iterator");return ol=!t((function(){var t=new URL("b?a=1&b=2&c=3","https://a"),e=t.searchParams,o=new URLSearchParams("a=1&a=2&b=3"),a="";return t.pathname="c%20d",e.forEach((function(t,n){e.delete("b"),a+=n+t})),o.delete("a",2),o.delete("b",void 0),i&&(!t.toJSON||!o.has("a",1)||o.has("a",2)||!o.has("a",void 0)||o.has("b"))||!e.size&&(i||!n)||!e.sort||"https://a/c%20d?a=1&c=3"!==t.href||"3"!==e.get("c")||"a=1"!==String(new URLSearchParams("?a=1"))||!e[r]||"a"!==new URL("https://a@b").username||"b"!==new URLSearchParams(new URLSearchParams("a=b")).get("a")||"xn--e1aybc"!==new URL("https://тест").host||"#%D0%B1"!==new URL("https://a#б").hash||"a1c3"!==a||"x"!==new URL("https://x",void 0).host}))}(),l=on(),c=Ea(),u=xl(),h=jr(),f=Nr(),d=nn(),p=Ol(),g=Pt(),v=ve(),m=$i(),y=vi(),w=je(),S=It(),x=po(),O=Wi(),k=wt(),T=Tl(),C=kl(),A=Vr(),R=Cl(),E=me(),j=go(),N=E("iterator"),F="URLSearchParams",D=F+"Iterator",L=d.set,_=d.getterFor(F),V=d.getterFor(D),B=n("fetch"),H=n("Request"),M=n("Headers"),U=H&&H.prototype,z=M&&M.prototype,q=e.TypeError,W=e.encodeURIComponent,G=String.fromCharCode,K=i("String","fromCodePoint"),J=parseInt,Y=o("".charAt),Q=o([].join),X=o([].push),Z=o("".replace),tt=o([].shift),et=o([].splice),nt=o("".split),it=o("".slice),rt=o(/./.exec),ot=/\+/g,at=/^[0-9a-f]+$/i,st=function(t,e){var n=it(t,e,e+2);return rt(at,n)?J(n,16):NaN},lt=function(t){for(var e=0,n=128;n>0&&t&n;n>>=1)e++;return e},ct=function(t){var e=null;switch(t.length){case 1:e=t[0];break;case 2:e=(31&t[0])<<6|63&t[1];break;case 3:e=(15&t[0])<<12|(63&t[1])<<6|63&t[2];break;case 4:e=(7&t[0])<<18|(63&t[1])<<12|(63&t[2])<<6|63&t[3]}return e>1114111?null:e},ut=function(t){for(var e=(t=Z(t,ot," ")).length,n="",i=0;ie){n+="%",i++;continue}var o=st(t,i+1);if(o!=o){n+=r,i++;continue}i+=2;var a=lt(o);if(0===a)r=G(o);else{if(1===a||a>4){n+="�",i++;continue}for(var s=[o],l=1;le||"%"!==Y(t,i));){var c=st(t,i+1);if(c!=c){i+=3;break}if(c>191||c<128)break;X(s,c),i+=2,l++}if(s.length!==a){n+="�";continue}var u=ct(s);null===u?n+="�":r=K(u)}}n+=r,i++}return n},ht=/[!'()~]|%20/g,ft={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+"},dt=function(t){return ft[t]},pt=function(t){return Z(W(t),ht,dt)},gt=f((function(t,e){L(this,{type:D,target:_(t).entries,index:0,kind:e})}),F,(function(){var t=V(this),e=t.target,n=t.index++;if(!e||n>=e.length)return t.target=null,A(void 0,!0);var i=e[n];switch(t.kind){case"keys":return A(i.key,!1);case"values":return A(i.value,!1)}return A([i.key,i.value],!1)}),!0),vt=function(t){this.entries=[],this.url=null,void 0!==t&&(S(t)?this.parseObject(t):this.parseQuery("string"==typeof t?"?"===Y(t,0)?it(t,1):t:x(t)))};vt.prototype={type:F,bindURL:function(t){this.url=t,this.update()},parseObject:function(t){var e,n,i,o,a,s,l,c=this.entries,u=C(t);if(u)for(n=(e=T(t,u)).next;!(i=r(n,e)).done;){if(a=(o=T(w(i.value))).next,(s=r(a,o)).done||(l=r(a,o)).done||!r(a,o).done)throw new q("Expected sequence with length 2");X(c,{key:x(s.value),value:x(l.value)})}else for(var h in t)v(t,h)&&X(c,{key:h,value:x(t[h])})},parseQuery:function(t){if(t)for(var e,n,i=this.entries,r=nt(t,"&"),o=0;o0?arguments[0]:void 0));a||(this.size=t.entries.length)},mt=bt.prototype;if(u(mt,{append:function(t,e){var n=_(this);R(arguments.length,2),X(n.entries,{key:x(t),value:x(e)}),a||this.length++,n.updateURL()},delete:function(t){for(var e=_(this),n=R(arguments.length,1),i=e.entries,r=x(t),o=n<2?void 0:arguments[1],s=void 0===o?o:x(o),l=0;le.key?1:-1})),t.updateURL()},forEach:function(t){for(var e,n=_(this).entries,i=m(t,arguments.length>1?arguments[1]:void 0),r=0;r1?Ot(arguments[1]):{})}}),g(H)){var kt=function(t){return p(this,U),new H(t,arguments.length>1?Ot(arguments[1]):{})};U.constructor=kt,kt.prototype=U,t({global:!0,constructor:!0,dontCallGetSet:!0,forced:!0},{Request:kt})}}return bl={URLSearchParams:bt,getState:_}}yl||(yl=1,Pl());var Il={getBootstrapVersion:function(){var e,n,i=5;if("undefined"!=typeof window&&null!==(e=window.bootstrap)&&void 0!==e&&null!==(e=e.Tooltip)&&void 0!==e&&e.VERSION){var r=window.bootstrap.Tooltip.VERSION;void 0!==r&&(i=parseInt(r,10))}else if(void 0!==t&&null!==(n=t.fn)&&void 0!==n&&null!==(n=n.dropdown)&&void 0!==n&&null!==(n=n.Constructor)&&void 0!==n&&n.VERSION){var o=t.fn.dropdown.Constructor.VERSION;void 0!==o&&(i=parseInt(o,10))}return i},getIconsPrefix:function(t){return{bootstrap3:"glyphicon",bootstrap4:"fa",bootstrap5:"bi","bootstrap-table":"icon",bulma:"fa",foundation:"fa",materialize:"material-icons",semantic:"fa"}[t]||"fa"},getIcons:function(t,e){return t[e]||{}},assignIcons:function(t,e,n){for(var i=0,r=Object.keys(t);i1?e-1:0),i=1;i0&&void 0!==arguments[0]?arguments[0]:{};return 0===Object.entries(t).length&&t.constructor===Object},isNumeric:function(t){return!isNaN(parseFloat(t))&&isFinite(t)},getFieldTitle:function(t,e){var n,i=r(t);try{for(i.s();!(n=i.n()).done;){var o=n.value;if(o.field===e)return o.title}}catch(t){i.e(t)}finally{i.f()}return""},setFieldIndex:function(t){var e,n=0,i=[],o=r(t[0]);try{for(o.s();!(e=o.n()).done;){n+=+e.value.colspan||1}}catch(t){o.e(t)}finally{o.f()}for(var a=0;a1){for(var h=0,f=function(t){var e=o.filter((function(e){return e.fieldIndex===t})),n=e[e.length-1];if(e.length>1)for(var i=0;i0}}}catch(t){l.e(t)}finally{l.f()}}}catch(t){a.e(t)}finally{a.f()}if(!(t.length<2)){var p,g=r(e);try{var v=function(){var t=p.value,e=o.filter((function(e){return e.fieldIndex===t.fieldIndex}));if(e.length>1){var n,i=r(e);try{for(i.s();!(n=i.n()).done;){n.value.visible=t.visible}}catch(t){i.e(t)}finally{i.f()}}};for(g.s();!(p=g.n()).done;)v()}catch(t){g.e(t)}finally{g.f()}}},getScrollBarWidth:function(){if(void 0===this.cachedWidth){var e=t("
    ").addClass("fixed-table-scroll-inner"),n=t("
    ").addClass("fixed-table-scroll-outer");n.append(e),t("body").append(n);var i=e[0].offsetWidth;n.css("overflow","scroll");var r=e[0].offsetWidth;i===r&&(r=n[0].clientWidth),n.remove(),this.cachedWidth=i-r}return this.cachedWidth},calculateObjectValue:function(t,e,n,i){var o=e;if("string"==typeof e){var a=e.split(".");if(a.length>1){o=window;var s,l=r(a);try{for(l.s();!(s=l.n()).done;){o=o[s.value]}}catch(t){l.e(t)}finally{l.f()}}else o=window[e]}return null!==o&&"object"===h(o)?o:"function"==typeof o?o.apply(t,n||[]):!o&&"string"==typeof e&&n&&this.sprintf.apply(this,[e].concat(c(n)))?this.sprintf.apply(this,[e].concat(c(n))):i},compareObjects:function(t,e,n){var i=Object.keys(t),r=Object.keys(e);if(n&&i.length!==r.length)return!1;for(var o=0,a=i;o/g,">").replace(/"/g,""").replace(/'/g,"'"):t},unescapeHTML:function(t){return"string"==typeof t&&t?t.toString().replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'"):t},removeHTML:function(t){return t?t.toString().replace(/(<([^>]+)>)/gi,"").replace(/&[#A-Za-z0-9]+;/gi,"").trim():t},getRealDataAttr:function(t){for(var e=0,n=Object.entries(t);e3&&void 0!==arguments[3]?arguments[3]:void 0,o=t;if(void 0!==i&&(n=i),"string"!=typeof e||t.hasOwnProperty(e))return n?this.escapeHTML(t[e]):t[e];var a,s=r(e.split("."));try{for(s.s();!(a=s.n()).done;){var l=a.value;o=o&&o[l]}}catch(t){s.e(t)}finally{s.f()}return n?this.escapeHTML(o):o},isIEBrowser:function(){return navigator.userAgent.includes("MSIE ")||/Trident.*rv:11\./.test(navigator.userAgent)},findIndex:function(t,e){var n,i=r(t);try{for(i.s();!(n=i.n()).done;){var o=n.value;if(JSON.stringify(o)===JSON.stringify(e))return t.indexOf(o)}}catch(t){i.e(t)}finally{i.f()}return-1},trToData:function(e,n){var i=this,r=[],o=[];return n.each((function(n,a){var s=t(a),l={};l._id=s.attr("id"),l._class=s.attr("class"),l._data=i.getRealDataAttr(s.data()),l._style=s.attr("style"),s.find(">td,>th").each((function(r,a){for(var s=t(a),c=+s.attr("colspan")||1,u=+s.attr("rowspan")||1,h=r;o[n]&&o[n][h];h++);for(var f=h;fe?n:0;if(i.sortEmptyLast){if(""===t)return 1;if(""===e)return-1}return t===e?0:("string"!=typeof t&&(t=t.toString()),-1===t.localeCompare(e)?-1*n:n)},getEventName:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=e||"".concat(+new Date).concat(~~(1e6*Math.random())),"".concat(t,"-").concat(e)},hasDetailViewIcon:function(t){return t.detailView&&t.detailViewIcon&&!t.cardView},getDetailViewIndexOffset:function(t){return this.hasDetailViewIcon(t)&&"right"!==t.detailViewAlign?1:0},checkAutoMergeCells:function(t){var e,n=r(t);try{for(n.s();!(e=n.n()).done;)for(var i=e.value,o=0,a=Object.keys(i);o0){var i=e.substring(0,n).trim(),r=e.substring(n+1).trim();t.style.setProperty(i,r)}}));else if(Array.isArray(e)){var n,i=r(e);try{for(i.s();!(n=i.n()).done;){var o=n.value;this.parseStyle(t,o)}}catch(t){i.e(t)}finally{i.f()}}else if("object"===h(e))for(var a=0,s=Object.entries(e);a',icon:'',inputGroup:'
    %s%s
    ',pageDropdown:['"],pageDropdownItem:'
    ',pagination:['
      ',"
    "],paginationItem:'
  • %s
  • ',searchButton:'',searchClearButton:'',searchInput:'',toolbarDropdown:['"],toolbarDropdownItem:'',toolbarDropdownSeparator:'
  • '}},4:{classes:{buttonActive:"active",buttons:"secondary",buttonsDropdown:"btn-group",buttonsGroup:"btn-group",buttonsPrefix:"btn",dropdownActive:"active",dropup:"dropup",input:"form-control",inputGroup:"btn-group",inputPrefix:"form-control-",paginationActive:"active",paginationDropdown:"btn-group dropdown",pull:"float",select:"form-control"},html:{dropdownCaret:'',icon:'',inputGroup:'
    %s
    %s
    ',pageDropdown:['"],pageDropdownItem:'%s',pagination:['
      ',"
    "],paginationItem:'
  • %s
  • ',searchButton:'',searchClearButton:'',searchInput:'',toolbarDropdown:['"],toolbarDropdownItem:'',toolbarDropdownSeparator:''}},5:{classes:{buttonActive:"active",buttons:"secondary",buttonsDropdown:"btn-group",buttonsGroup:"btn-group",buttonsPrefix:"btn",dropdownActive:"active",dropup:"dropup",input:"form-control",inputGroup:"btn-group",inputPrefix:"form-control-",paginationActive:"active",paginationDropdown:"btn-group dropdown",pull:"float",select:"form-select"},html:{dataToggle:"data-bs-toggle",dropdownCaret:'',icon:'',inputGroup:'
    %s%s
    ',pageDropdown:['"],pageDropdownItem:'%s',pagination:['
      ',"
    "],paginationItem:'
  • %s
  • ',searchButton:'',searchClearButton:'',searchInput:'',toolbarDropdown:['"],toolbarDropdownItem:'',toolbarDropdownSeparator:''}}}[Al],Rl={ajax:void 0,ajaxOptions:{},buttons:{},buttonsAlign:"right",buttonsAttributeTitle:"title",buttonsClass:$l.classes.buttons,buttonsOrder:["paginationSwitch","refresh","toggle","fullscreen","columns"],buttonsPrefix:$l.classes.buttonsPrefix,buttonsToolbar:void 0,cache:!0,cardView:!1,checkboxHeader:!0,classes:"table table-bordered table-hover",clickToSelect:!1,columns:[[]],contentType:"application/json",customSearch:void 0,customSort:void 0,data:[],dataField:"rows",dataType:"json",detailFilter:function(t,e){return!0},detailFormatter:function(t,e){return""},detailView:!1,detailViewAlign:"left",detailViewByClick:!1,detailViewIcon:!0,escape:!1,escapeTitle:!0,filterOptions:{filterAlgorithm:"and"},fixedScroll:!1,footerField:"footer",footerStyle:function(t){return{}},headerStyle:function(t){return{}},height:void 0,icons:{},iconSize:void 0,iconsPrefix:void 0,idField:void 0,ignoreClickToSelectOn:function(t){var e=t.tagName;return["A","BUTTON"].includes(e)},loadingFontSize:"auto",loadingTemplate:function(t){return'\n '.concat(t,'\n \n \n ')},locale:void 0,maintainMetaData:!1,method:"get",minimumCountColumns:1,multipleSelectRow:!1,pageList:[10,25,50,100],pageNumber:1,pageSize:10,pagination:!1,paginationDetailHAlign:"left",paginationHAlign:"right",paginationLoadMore:!1,paginationLoop:!0,paginationNextText:"›",paginationPagesBySide:1,paginationParts:["pageInfo","pageSize","pageList"],paginationPreText:"‹",paginationSuccessivelySize:5,paginationUseIntermediate:!1,paginationVAlign:"bottom",queryParams:function(t){return t},queryParamsType:"limit",regexSearch:!1,rememberOrder:!1,responseHandler:function(t){return t},rowAttributes:function(t,e){return{}},rowStyle:function(t,e){return{}},search:!1,searchable:!1,searchAccentNeutralise:!1,searchAlign:"right",searchHighlight:!1,searchOnEnterKey:!1,searchSelector:!1,searchText:"",searchTimeOut:500,selectItemName:"btSelectItem",serverSort:!0,showButtonIcons:!0,showButtonText:!1,showColumns:!1,showColumnsSearch:!1,showColumnsToggleAll:!1,showExtendedPagination:!1,showFooter:!1,showFullscreen:!1,showHeader:!0,showPaginationSwitch:!1,showRefresh:!1,showSearchButton:!1,showSearchClearButton:!1,showToggle:!1,sidePagination:"client",silentSort:!0,singleSelect:!1,smartDisplay:!0,sortable:!0,sortClass:void 0,sortEmptyLast:!1,sortName:void 0,sortOrder:void 0,sortReset:!1,sortResetPage:!1,sortStable:!1,strictSearch:!1,theadClasses:"",toolbar:void 0,toolbarAlign:"left",totalField:"total",totalNotFiltered:0,totalNotFilteredField:"totalNotFiltered",totalRows:0,trimOnSearch:!0,undefinedText:"-",uniqueId:void 0,url:void 0,virtualScroll:!1,virtualScrollItemHeight:void 0,visibleSearch:!1,onAll:function(t,e){return!1},onCheck:function(t){return!1},onCheckAll:function(t){return!1},onCheckSome:function(t){return!1},onClickCell:function(t,e,n,i){return!1},onClickRow:function(t,e){return!1},onCollapseRow:function(t,e){return!1},onColumnSwitch:function(t,e){return!1},onColumnSwitchAll:function(t){return!1},onDblClickCell:function(t,e,n,i){return!1},onDblClickRow:function(t,e){return!1},onExpandRow:function(t,e,n){return!1},onLoadError:function(t){return!1},onLoadSuccess:function(t){return!1},onPageChange:function(t,e){return!1},onPostBody:function(){return!1},onPostFooter:function(){return!1},onPostHeader:function(){return!1},onPreBody:function(t){return!1},onRefresh:function(t){return!1},onRefreshOptions:function(t){return!1},onResetView:function(){return!1},onScrollBody:function(){return!1},onSearch:function(t){return!1},onSort:function(t,e){return!1},onToggle:function(t){return!1},onTogglePagination:function(t){return!1},onUncheck:function(t){return!1},onUncheckAll:function(t){return!1},onUncheckSome:function(t){return!1},onVirtualScroll:function(t,e){return!1}},El={formatLoadingMessage:function(){return"Loading, please wait"},formatRecordsPerPage:function(t){return"".concat(t," rows per page")},formatShowingRows:function(t,e,n,i){return void 0!==i&&i>0&&i>n?"Showing ".concat(t," to ").concat(e," of ").concat(n," rows (filtered from ").concat(i," total rows)"):"Showing ".concat(t," to ").concat(e," of ").concat(n," rows")},formatSRPaginationPreText:function(){return"previous page"},formatSRPaginationPageText:function(t){return"to page ".concat(t)},formatSRPaginationNextText:function(){return"next page"},formatDetailPagination:function(t){return"Showing ".concat(t," rows")},formatSearch:function(){return"Search"},formatClearSearch:function(){return"Clear Search"},formatNoMatches:function(){return"No matching records found"},formatPaginationSwitch:function(){return"Hide/Show pagination"},formatPaginationSwitchDown:function(){return"Show pagination"},formatPaginationSwitchUp:function(){return"Hide pagination"},formatRefresh:function(){return"Refresh"},formatToggleOn:function(){return"Show card view"},formatToggleOff:function(){return"Hide card view"},formatColumns:function(){return"Columns"},formatColumnsToggleAll:function(){return"Toggle all"},formatFullscreen:function(){return"Fullscreen"},formatAllRows:function(){return"All"}},jl={align:void 0,cardVisible:!0,cellStyle:void 0,checkbox:!1,checkboxEnabled:!0,class:void 0,clickToSelect:!0,colspan:void 0,detailFormatter:void 0,escape:void 0,events:void 0,falign:void 0,field:void 0,footerFormatter:void 0,footerStyle:void 0,formatter:void 0,halign:void 0,order:"asc",radio:!1,rowspan:void 0,searchable:!0,searchFormatter:!0,searchHighlightFormatter:!1,showSelectTitle:!1,sortable:!1,sorter:void 0,sortName:void 0,switchable:!0,switchableLabel:void 0,title:void 0,titleTooltip:void 0,valign:void 0,visible:!0,width:void 0,widthUnit:"px"};Object.assign(Rl,El);var Nl={COLUMN_DEFAULTS:jl,CONSTANTS:$l,DEFAULTS:Rl,EVENTS:{"all.bs.table":"onAll","check-all.bs.table":"onCheckAll","check-some.bs.table":"onCheckSome","check.bs.table":"onCheck","click-cell.bs.table":"onClickCell","click-row.bs.table":"onClickRow","collapse-row.bs.table":"onCollapseRow","column-switch-all.bs.table":"onColumnSwitchAll","column-switch.bs.table":"onColumnSwitch","dbl-click-cell.bs.table":"onDblClickCell","dbl-click-row.bs.table":"onDblClickRow","expand-row.bs.table":"onExpandRow","load-error.bs.table":"onLoadError","load-success.bs.table":"onLoadSuccess","page-change.bs.table":"onPageChange","post-body.bs.table":"onPostBody","post-footer.bs.table":"onPostFooter","post-header.bs.table":"onPostHeader","pre-body.bs.table":"onPreBody","refresh-options.bs.table":"onRefreshOptions","refresh.bs.table":"onRefresh","reset-view.bs.table":"onResetView","scroll-body.bs.table":"onScrollBody","search.bs.table":"onSearch","sort.bs.table":"onSort","toggle-pagination.bs.table":"onTogglePagination","toggle.bs.table":"onToggle","uncheck-all.bs.table":"onUncheckAll","uncheck-some.bs.table":"onUncheckSome","uncheck.bs.table":"onUncheck","virtual-scroll.bs.table":"onVirtualScroll"},ICONS:{glyphicon:{clearSearch:"glyphicon-trash",columns:"glyphicon-th icon-th",detailClose:"glyphicon-minus icon-minus",detailOpen:"glyphicon-plus icon-plus",fullscreen:"glyphicon-fullscreen",paginationSwitchDown:"glyphicon-collapse-down icon-chevron-down",paginationSwitchUp:"glyphicon-collapse-up icon-chevron-up",refresh:"glyphicon-refresh icon-refresh",search:"glyphicon-search",toggleOff:"glyphicon-list-alt icon-list-alt",toggleOn:"glyphicon-list-alt icon-list-alt"},fa:{clearSearch:"fa-trash",columns:"fa-th-list",detailClose:"fa-minus",detailOpen:"fa-plus",fullscreen:"fa-arrows-alt",paginationSwitchDown:"fa-caret-square-down",paginationSwitchUp:"fa-caret-square-up",refresh:"fa-sync",search:"fa-search",toggleOff:"fa-toggle-off",toggleOn:"fa-toggle-on"},bi:{clearSearch:"bi-trash",columns:"bi-list-ul",detailClose:"bi-dash",detailOpen:"bi-plus",fullscreen:"bi-arrows-move",paginationSwitchDown:"bi-caret-down-square",paginationSwitchUp:"bi-caret-up-square",refresh:"bi-arrow-clockwise",search:"bi-search",toggleOff:"bi-toggle-off",toggleOn:"bi-toggle-on"},icon:{clearSearch:"icon-trash-2",columns:"icon-list",detailClose:"icon-minus",detailOpen:"icon-plus",fullscreen:"icon-maximize",paginationSwitchDown:"icon-arrow-up-circle",paginationSwitchUp:"icon-arrow-down-circle",refresh:"icon-refresh-cw",search:"icon-search",toggleOff:"icon-toggle-right",toggleOn:"icon-toggle-right"},"material-icons":{clearSearch:"delete",columns:"view_list",detailClose:"remove",detailOpen:"add",fullscreen:"fullscreen",paginationSwitchDown:"grid_on",paginationSwitchUp:"grid_off",refresh:"refresh",search:"search",sort:"sort",toggleOff:"tablet",toggleOn:"tablet_android"}},LOCALES:{en:El,"en-US":El},METHODS:["getOptions","refreshOptions","getData","getFooterData","getSelections","load","append","prepend","remove","removeAll","insertRow","updateRow","getRowByUniqueId","updateByUniqueId","removeByUniqueId","updateCell","updateCellByUniqueId","showRow","hideRow","getHiddenRows","showColumn","hideColumn","getVisibleColumns","getHiddenColumns","showAllColumns","hideAllColumns","mergeCells","checkAll","uncheckAll","checkInvert","check","uncheck","checkBy","uncheckBy","refresh","destroy","resetView","showLoading","hideLoading","togglePagination","toggleFullscreen","toggleView","resetSearch","filterBy","sortBy","sortReset","scrollTo","getScrollPosition","selectPage","prevPage","nextPage","toggleDetailView","expandRow","collapseRow","expandRowByUniqueId","collapseRowByUniqueId","expandAllRows","collapseAllRows","updateColumnTitle","updateFormatText"],THEME:"bootstrap".concat(Al),VERSION:"1.24.1"},Fl=function(){return i((function t(e){var i=this;n(this,t),this.rows=e.rows,this.scrollEl=e.scrollEl,this.contentEl=e.contentEl,this.callback=e.callback,this.itemHeight=e.itemHeight,this.cache={},this.scrollTop=this.scrollEl.scrollTop,this.initDOM(this.rows,e.fixedScroll),this.scrollEl.scrollTop=this.scrollTop,this.lastCluster=0;var r=function(){i.lastCluster!==(i.lastCluster=i.getNum())&&(i.initDOM(i.rows),i.callback(i.startIndex,i.endIndex))};this.scrollEl.addEventListener("scroll",r,!1),this.destroy=function(){i.contentEl.innerHtml="",i.scrollEl.removeEventListener("scroll",r,!1)}}),[{key:"initDOM",value:function(t,e){void 0===this.clusterHeight?(this.cache.scrollTop=this.scrollEl.scrollTop,this.cache.data=this.contentEl.innerHTML=t[0]+t[0]+t[0],this.getRowsHeight(t)):0===this.blockHeight&&this.getRowsHeight(t);var n=this.initData(t,this.getNum(e)),i=n.rows.join(""),r=this.checkChanges("data",i),o=this.checkChanges("top",n.topOffset),a=this.checkChanges("bottom",n.bottomOffset),s=[];r&&o?(n.topOffset&&s.push(this.getExtra("top",n.topOffset)),s.push(i),n.bottomOffset&&s.push(this.getExtra("bottom",n.bottomOffset)),this.startIndex=n.start,this.endIndex=n.end,this.contentEl.innerHTML=s.join(""),e&&(this.contentEl.scrollTop=this.cache.scrollTop)):a&&(this.contentEl.lastChild.style.height="".concat(n.bottomOffset,"px"))}},{key:"getRowsHeight",value:function(){if(void 0===this.itemHeight||0===this.itemHeight){var t=this.contentEl.children,e=t[Math.floor(t.length/2)];this.itemHeight=e.offsetHeight}this.blockHeight=50*this.itemHeight,this.clusterRows=200,this.clusterHeight=4*this.blockHeight}},{key:"getNum",value:function(t){return this.scrollTop=t?this.cache.scrollTop:this.scrollEl.scrollTop,Math.floor(this.scrollTop/(this.clusterHeight-this.blockHeight))||0}},{key:"initData",value:function(t,e){if(t.length<50)return{topOffset:0,bottomOffset:0,rowsAbove:0,rows:t};var n=Math.max((this.clusterRows-50)*e,0),i=n+this.clusterRows,r=Math.max(n*this.itemHeight,0),o=Math.max((t.length-i)*this.itemHeight,0),a=[],s=n;r<1&&s++;for(var l=n;l
    ':"",n=["bottom","both"].includes(this.options.paginationVAlign)?'
    ':"",i=Il.calculateObjectValue(this.options,this.options.loadingTemplate,[this.options.formatLoadingMessage()]);this.$container=t('\n
    \n
    \n ').concat(e,'\n
    \n
    \n
    \n
    \n ').concat(i,'\n
    \n
    \n \n
    \n ').concat(n,"\n
    \n ")),this.$container.insertAfter(this.$el),this.$tableContainer=this.$container.find(".fixed-table-container"),this.$tableHeader=this.$container.find(".fixed-table-header"),this.$tableBody=this.$container.find(".fixed-table-body"),this.$tableLoading=this.$container.find(".fixed-table-loading"),this.$tableFooter=this.$el.find("tfoot"),this.options.buttonsToolbar?this.$toolbar=t("body").find(this.options.buttonsToolbar):this.$toolbar=this.$container.find(".fixed-table-toolbar"),this.$pagination=this.$container.find(".fixed-table-pagination"),this.$tableBody.append(this.$el),this.$container.after('
    '),this.$el.addClass(this.options.classes),this.$tableLoading.addClass(this.options.classes),this.options.height&&(this.$tableContainer.addClass("fixed-height"),this.options.showFooter&&this.$tableContainer.addClass("has-footer"),this.options.classes.split(" ").includes("table-bordered")&&(this.$tableBody.append('
    '),this.$tableBorder=this.$tableBody.find(".fixed-table-border"),this.$tableLoading.addClass("fixed-table-border")),this.$tableFooter=this.$container.find(".fixed-table-footer"))}},{key:"initTable",value:function(){var n=this,i=[];if(this.$header=this.$el.find(">thead"),this.$header.length?this.options.theadClasses&&this.$header.addClass(this.options.theadClasses):this.$header=t('')).appendTo(this.$el),this._headerTrClasses=[],this._headerTrStyles=[],this.$header.find("tr").each((function(e,r){var o=t(r),a=[];o.find("th").each((function(e,n){var i=t(n);void 0!==i.data("field")&&i.data("field","".concat(i.data("field")));var r=Object.assign({},i.data());for(var o in r)t.fn.bootstrapTable.columnDefaults.hasOwnProperty(o)&&delete r[o];a.push(Il.extend({},{_data:Il.getRealDataAttr(r),title:i.html(),class:i.attr("class"),titleTooltip:i.attr("title"),rowspan:i.attr("rowspan")?+i.attr("rowspan"):void 0,colspan:i.attr("colspan")?+i.attr("colspan"):void 0},i.data()))})),i.push(a),o.attr("class")&&n._headerTrClasses.push(o.attr("class")),o.attr("style")&&n._headerTrStyles.push(o.attr("style"))})),Array.isArray(this.options.columns[0])||(this.options.columns=[this.options.columns]),this.options.columns=Il.extend(!0,[],i,this.options.columns),this.columns=[],this.fieldsColumnsIndex=[],!1!==this.optionsColumnsChanged&&Il.setFieldIndex(this.options.columns),this.options.columns.forEach((function(t,i){t.forEach((function(t,r){var o=Il.extend({},e.COLUMN_DEFAULTS,t,{passed:t});void 0!==o.fieldIndex&&(n.columns[o.fieldIndex]=o,n.fieldsColumnsIndex[o.field]=o.fieldIndex),n.options.columns[i][r]=o}))})),!this.options.data.length){var r=Il.trToData(this.columns,this.$el.find(">tbody>tr"));r.length&&(this.options.data=r,this.fromHtml=!0)}this.options.pagination&&"server"!==this.options.sidePagination||(this.footerData=Il.trToData(this.columns,this.$el.find(">tfoot>tr"))),this.footerData&&this.$el.find("tfoot").html(""),!this.options.showFooter||this.options.cardView?this.$tableFooter.hide():this.$tableFooter.show()}},{key:"initHeader",value:function(){var e=this,n={},i=[];this.header={fields:[],styles:[],classes:[],formatters:[],detailFormatters:[],events:[],sorters:[],sortNames:[],cellStyles:[],searchables:[]},Il.updateFieldGroup(this.options.columns,this.columns),this.options.columns.forEach((function(t,r){var o=[];o.push(""));var a="";if(0===r&&Il.hasDetailViewIcon(e.options)){var s=e.options.columns.length>1?' rowspan="'.concat(e.options.columns.length,'"'):"";a='\n
    \n ')}a&&"right"!==e.options.detailViewAlign&&o.push(a),t.forEach((function(t,i){var a=Il.sprintf(' class="%s"',t.class),s=t.widthUnit,c=parseFloat(t.width),u=t.halign?t.halign:t.align,f=Il.sprintf("text-align: %s; ",u),d=Il.sprintf("text-align: %s; ",t.align),p=Il.sprintf("vertical-align: %s; ",t.valign);if(p+=Il.sprintf("width: %s; ",!t.checkbox&&!t.radio||c?c?c+s:void 0:t.showSelectTitle?void 0:"36px"),void 0!==t.fieldIndex||t.visible){var g=Il.calculateObjectValue(null,e.options.headerStyle,[t]),v=[],b=[],m="";if(g&&g.css)for(var y=0,w=Object.entries(g.css);y0)for(var k=0,T=Object.entries(t._data);k0?" data-not-first-th":"",b.length>0?b.join(" "):"",">"),o.push(Il.sprintf('
    ',e.options.sortable&&t.sortable?"sortable".concat("center"===u?" sortable-center":""," both"):""));var A=e.options.escape&&e.options.escapeTitle?Il.escapeHTML(t.title):t.title,$=A;t.checkbox&&(A="",!e.options.singleSelect&&e.options.checkboxHeader&&(A=''),e.header.stateField=t.field),t.radio&&(A="",e.header.stateField=t.field),!A&&t.showSelectTitle&&(A+=$),o.push(A),o.push("
    "),o.push('
    '),o.push("
    "),o.push("")}})),a&&"right"===e.options.detailViewAlign&&o.push(a),o.push(""),o.length>3&&i.push(o.join(""))})),this.$header.html(i.join("")),this.$header.find("th[data-field]").each((function(e,i){t(i).data(n[t(i).data("field")])})),this.$container.off("click",".th-inner").on("click",".th-inner",(function(n){var i=t(n.currentTarget);if(e.options.detailView&&!i.parent().hasClass("bs-checkbox")&&i.closest(".bootstrap-table")[0]!==e.$container[0])return!1;e.options.sortable&&i.parent().data().sortable&&e.onSort(n)}));var r=Il.getEventName("resize.bootstrap-table",this.$el.attr("id"));t(window).off(r),!this.options.showHeader||this.options.cardView?(this.$header.hide(),this.$tableHeader.hide(),this.$tableLoading.css("top",0)):(this.$header.show(),this.$tableHeader.show(),this.$tableLoading.css("top",this.$header.outerHeight()+1),this.getCaret(),t(window).on(r,(function(){return e.resetView()}))),this.$selectAll=this.$header.find('[name="btSelectAll"]'),this.$selectAll.off("click").on("click",(function(n){n.stopPropagation();var i=t(n.currentTarget).prop("checked");e[i?"checkAll":"uncheckAll"](),e.updateSelected()}))}},{key:"initData",value:function(t,e){"append"===e?this.options.data=this.options.data.concat(t):"prepend"===e?this.options.data=[].concat(t).concat(this.options.data):(t=t||Il.deepCopy(this.options.data),this.options.data=Array.isArray(t)?t:t[this.options.dataField]),this.data=c(this.options.data),this.options.sortReset&&(this.unsortedData=c(this.data)),"server"!==this.options.sidePagination&&this.initSort()}},{key:"initSort",value:function(){var t=this,e=this.options.sortName,n="desc"===this.options.sortOrder?-1:1,i=this.header.fields.indexOf(this.options.sortName),r=0;-1!==i?(this.options.sortStable&&this.data.forEach((function(t,e){t.hasOwnProperty("_position")||(t._position=e)})),this.options.customSort?Il.calculateObjectValue(this.options,this.options.customSort,[this.options.sortName,this.options.sortOrder,this.data]):this.data.sort((function(r,o){t.header.sortNames[i]&&(e=t.header.sortNames[i]);var a=Il.getItemField(r,e,t.options.escape),s=Il.getItemField(o,e,t.options.escape),l=Il.calculateObjectValue(t.header,t.header.sorters[i],[a,s,r,o]);return void 0!==l?t.options.sortStable&&0===l?n*(r._position-o._position):n*l:Il.sort(a,s,n,t.options,r._position,o._position)})),void 0!==this.options.sortClass&&(clearTimeout(r),r=setTimeout((function(){t.$el.removeClass(t.options.sortClass);var e=t.$header.find('[data-field="'.concat(t.options.sortName,'"]')).index();t.$el.find("tr td:nth-child(".concat(e+1,")")).addClass(t.options.sortClass)}),250))):this.options.sortReset&&(this.data=c(this.unsortedData))}},{key:"sortReset",value:function(){this.options.sortName=void 0,this.options.sortOrder=void 0,this._sort()}},{key:"sortBy",value:function(t){this.options.sortName=t.field,this.options.sortOrder=t.hasOwnProperty("sortOrder")?t.sortOrder:"asc",this._sort()}},{key:"onSort",value:function(e){var n=e.type,i=e.currentTarget,r="keypress"===n?t(i):t(i).parent(),o=this.$header.find("th").eq(r.index());if(this.$header.add(this.$header_).find("span.order").remove(),this.options.sortName===r.data("field")){var a=this.options.sortOrder,s=this.columns[this.fieldsColumnsIndex[r.data("field")]].sortOrder||this.columns[this.fieldsColumnsIndex[r.data("field")]].order;void 0===a?this.options.sortOrder="asc":"asc"===a?this.options.sortOrder=this.options.sortReset?"asc"===s?"desc":void 0:"desc":"desc"===this.options.sortOrder&&(this.options.sortOrder=this.options.sortReset?"desc"===s?"asc":void 0:"asc"),void 0===this.options.sortOrder&&(this.options.sortName=void 0)}else this.options.sortName=r.data("field"),this.options.rememberOrder?this.options.sortOrder="asc"===r.data("order")?"desc":"asc":this.options.sortOrder=this.columns[this.fieldsColumnsIndex[r.data("field")]].sortOrder||this.columns[this.fieldsColumnsIndex[r.data("field")]].order;r.add(o).data("order",this.options.sortOrder),this.getCaret(),this._sort()}},{key:"_sort",value:function(){if("server"===this.options.sidePagination&&this.options.serverSort)return this.options.pageNumber=1,this.trigger("sort",this.options.sortName,this.options.sortOrder),void this.initServer(this.options.silentSort);this.options.pagination&&this.options.sortResetPage&&(this.options.pageNumber=1,this.initPagination()),this.trigger("sort",this.options.sortName,this.options.sortOrder),this.initSort(),this.initBody()}},{key:"initToolbar",value:function(){var e,n=this,i=this.options,o=[],a=0,s=0;this.$toolbar.find(".bs-bars").children().length&&t("body").append(t(i.toolbar)),this.$toolbar.html(""),"string"!=typeof i.toolbar&&"object"!==h(i.toolbar)||t(Il.sprintf('
    ',this.constants.classes.pull,i.toolbarAlign)).appendTo(this.$toolbar).append(t(i.toolbar)),o=['
    ')],"string"==typeof i.buttonsOrder&&(i.buttonsOrder=i.buttonsOrder.replace(/\[|\]| |'/g,"").split(",")),this.buttons=Object.assign(this.buttons,{paginationSwitch:{text:i.pagination?i.formatPaginationSwitchUp():i.formatPaginationSwitchDown(),icon:i.pagination?i.icons.paginationSwitchDown:i.icons.paginationSwitchUp,render:!1,event:this.togglePagination,attributes:{"aria-label":i.formatPaginationSwitch(),title:i.formatPaginationSwitch()}},refresh:{text:i.formatRefresh(),icon:i.icons.refresh,render:!1,event:this.refresh,attributes:{"aria-label":i.formatRefresh(),title:i.formatRefresh()}},toggle:{text:i.formatToggleOn(),icon:i.icons.toggleOff,render:!1,event:this.toggleView,attributes:{"aria-label":i.formatToggleOn(),title:i.formatToggleOn()}},fullscreen:{text:i.formatFullscreen(),icon:i.icons.fullscreen,render:!1,event:this.toggleFullscreen,attributes:{"aria-label":i.formatFullscreen(),title:i.formatFullscreen()}},columns:{render:!1,html:function(){var t=[];if(t.push('
    \n \n ").concat(n.constants.html.toolbarDropdown[0])),i.showColumnsSearch&&(t.push(Il.sprintf(n.constants.html.toolbarDropdownItem,Il.sprintf('',n.constants.classes.input,i.formatSearch()))),t.push(n.constants.html.toolbarDropdownSeparator)),i.showColumnsToggleAll){var e=n.getVisibleColumns().length===n.columns.filter((function(t){return!n.isSelectionColumn(t)})).length;t.push(Il.sprintf(n.constants.html.toolbarDropdownItem,Il.sprintf(' %s',e?'checked="checked"':"",i.formatColumnsToggleAll()))),t.push(n.constants.html.toolbarDropdownSeparator)}var r=0;return n.columns.forEach((function(t){t.visible&&r++})),n.columns.forEach((function(e,o){if(!n.isSelectionColumn(e)&&(!i.cardView||e.cardVisible)){var a=e.visible?' checked="checked"':"",l=r<=i.minimumCountColumns&&a?' disabled="disabled"':"";e.switchable&&(t.push(Il.sprintf(n.constants.html.toolbarDropdownItem,Il.sprintf(' %s',e.field,o,a,l,e.switchableLabel||e.title))),s++)}})),t.push(n.constants.html.toolbarDropdown[1],"
    "),t.join("")}}});for(var c={},u=0,f=Object.entries(this.buttons);u"}c[p]=v;var k="show".concat(p.charAt(0).toUpperCase()).concat(p.substring(1)),T=i[k];!(!g.hasOwnProperty("render")||g.hasOwnProperty("render")&&g.render)||void 0!==T&&!0!==T||(i[k]=!0),i.buttonsOrder.includes(p)||i.buttonsOrder.push(p)}var C,P=r(i.buttonsOrder);try{for(P.s();!(C=P.n()).done;){var I=C.value;i["show".concat(I.charAt(0).toUpperCase()).concat(I.substring(1))]&&o.push(c[I])}}catch(t){P.e(t)}finally{P.f()}o.push("
    "),(this.showToolbar||o.length>2)&&this.$toolbar.append(o.join(""));for(var A=function(){var t=l(R[$],2),e=t[0],i=t[1];if(i.hasOwnProperty("event")){if("function"==typeof i.event||"string"==typeof i.event){var r="string"==typeof i.event?window[i.event]:i.event;return n.$toolbar.find('button[name="'.concat(e,'"]')).off("click").on("click",(function(){return r.call(n)})),1}for(var o=function(){var t=l(s[a],2),i=t[0],r=t[1],o="string"==typeof r?window[r]:r;n.$toolbar.find('button[name="'.concat(e,'"]')).off(i).on(i,(function(){return o.call(n)}))},a=0,s=Object.entries(i.event);a'),B=V;if(i.showSearchButton||i.showSearchClearButton){var H=(i.showSearchButton?L:"")+(i.showSearchClearButton?_:"");B=i.search?Il.sprintf(this.constants.html.inputGroup,V,H):H}o.push(Il.sprintf('\n
    \n %s\n
    \n '),B)),this.$toolbar.append(o.join(""));var M=Il.getSearchInput(this);i.showSearchButton?(this.$toolbar.find(".search button[name=search]").off("click").on("click",(function(){clearTimeout(a),a=setTimeout((function(){n.onSearch({currentTarget:M})}),i.searchTimeOut)})),i.searchOnEnterKey&&D(M)):D(M),i.showSearchClearButton&&this.$toolbar.find(".search button[name=clearSearch]").click((function(){n.resetSearch()}))}else"string"==typeof i.searchSelector&&D(Il.getSearchInput(this))}},{key:"onSearch",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.currentTarget,i=e.firedByInitSearchText,r=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];if(void 0!==n&&t(n).length&&r){var o=t(n).val().trim();if(this.options.trimOnSearch&&t(n).val()!==o&&t(n).val(o),this.searchText===o)return;var a=Il.getSearchInput(this),s=n instanceof jQuery?n:t(n);(s.is(a)||s.hasClass("search-input"))&&(this.searchText=o,this.options.searchText=o)}i||(this.options.pageNumber=1),this.initSearch(),i?"client"===this.options.sidePagination&&this.updatePagination():this.updatePagination(),this.trigger("search",this.searchText)}},{key:"initSearch",value:function(){var e=this;if(this.filterOptions=this.filterOptions||this.options.filterOptions,"server"!==this.options.sidePagination){if(this.options.customSearch)return this.data=Il.calculateObjectValue(this.options,this.options.customSearch,[this.options.data,this.searchText,this.filterColumns]),this.options.sortReset&&(this.unsortedData=c(this.data)),void this.initSort();var n=this.searchText&&(this.fromHtml?Il.escapeHTML(this.searchText):this.searchText),i=n?n.toLowerCase():"",r=Il.isEmptyObject(this.filterColumns)?null:this.filterColumns;this.options.searchAccentNeutralise&&(i=Il.normalizeAccent(i)),"function"==typeof this.filterOptions.filterAlgorithm?this.data=this.options.data.filter((function(t){return e.filterOptions.filterAlgorithm.apply(null,[t,r])})):"string"==typeof this.filterOptions.filterAlgorithm&&(this.data=r?this.options.data.filter((function(t){var n=e.filterOptions.filterAlgorithm;if("and"===n){for(var i in r)if(Array.isArray(r[i])&&!r[i].includes(t[i])||!Array.isArray(r[i])&&t[i]!==r[i])return!1}else if("or"===n){var o=!1;for(var a in r)(Array.isArray(r[a])&&r[a].includes(t[a])||!Array.isArray(r[a])&&t[a]===r[a])&&(o=!0);return o}return!0})):c(this.options.data));var o=this.getVisibleFields();this.data=i?this.data.filter((function(r,a){for(var s=0;s").html(u).text())),"string"==typeof u||"number"==typeof u)if(e.options.strictSearch){if("".concat(u).toLowerCase()===i)return!0}else if(e.options.regexSearch){if(Il.regexCompare(u,n))return!0}else{var d=/(?:(<=|=>|=<|>=|>|<)(?:\s+)?(-?\d+)?|(-?\d+)?(\s+)?(<=|=>|=<|>=|>|<))/gm.exec(e.searchText),p=!1;if(d){var g=d[1]||"".concat(d[5],"l"),v=d[2]||d[3],b=parseInt(u,10),m=parseInt(v,10);switch(g){case">":case"m;break;case"<":case">l":p=b=l":case"=>l":p=b<=m;break;case">=":case"=>":case"<=l":case"==m}}if(p||"".concat(u).toLowerCase().includes(i))return!0}}return!1})):this.data,this.options.sortReset&&(this.unsortedData=c(this.data)),this.initSort()}}},{key:"initPagination",value:function(){var t=this,e=this.options;if(e.pagination){this.$pagination.show();var n,i,r,o,a,s,l,c=[],u=!1,h=this.getData({includeHiddenRows:!1}),f=e.pageList;if("string"==typeof f&&(f=f.replace(/\[|\]| /g,"").toLowerCase().split(",")),f=f.map((function(t){return"string"==typeof t?t.toLowerCase()===e.formatAllRows().toLowerCase()||["all","unlimited"].includes(t.toLowerCase())?e.formatAllRows():+t:t})),this.paginationParts=e.paginationParts,"string"==typeof this.paginationParts&&(this.paginationParts=this.paginationParts.replace(/\[|\]| |'/g,"").split(",")),"server"!==e.sidePagination&&(e.totalRows=h.length),this.totalPages=0,e.totalRows&&(e.pageSize===e.formatAllRows()&&(e.pageSize=e.totalRows,u=!0),this.totalPages=1+~~((e.totalRows-1)/e.pageSize),e.totalPages=this.totalPages),this.totalPages>0&&e.pageNumber>this.totalPages&&(e.pageNumber=this.totalPages),this.pageFrom=(e.pageNumber-1)*e.pageSize+1,this.pageTo=e.pageNumber*e.pageSize,this.pageTo>e.totalRows&&(this.pageTo=e.totalRows),this.options.pagination&&"server"!==this.options.sidePagination&&(this.options.totalNotFiltered=this.options.data.length),this.options.showExtendedPagination||(this.options.totalNotFiltered=void 0),(this.paginationParts.includes("pageInfo")||this.paginationParts.includes("pageInfoShort")||this.paginationParts.includes("pageSize"))&&c.push('
    ')),this.paginationParts.includes("pageInfo")||this.paginationParts.includes("pageInfoShort")){var d=this.options.totalRows;"client"===this.options.sidePagination&&this.options.paginationLoadMore&&!this._paginationLoaded&&this.totalPages>1&&(d+=" +");var p=this.paginationParts.includes("pageInfoShort")?e.formatDetailPagination(d):e.formatShowingRows(this.pageFrom,this.pageTo,d,e.totalNotFiltered);c.push('\n '.concat(p,"\n "))}if(this.paginationParts.includes("pageSize")){c.push('
    ');var g=['
    \n \n ").concat(this.constants.html.pageDropdown[0])];f.forEach((function(n,i){var r;(!e.smartDisplay||0===i||f[i-1]")),c.push(e.formatRecordsPerPage(g.join("")))}if((this.paginationParts.includes("pageInfo")||this.paginationParts.includes("pageInfoShort")||this.paginationParts.includes("pageSize"))&&c.push("
    "),this.paginationParts.includes("pageList")){c.push('
    '),Il.sprintf(this.constants.html.pagination[0],Il.sprintf(" pagination-%s",e.iconSize)),Il.sprintf(this.constants.html.paginationItem," page-pre",e.formatSRPaginationPreText(),e.paginationPreText)),this.totalPagesthis.totalPages-i&&(i=i-(e.paginationSuccessivelySize-(this.totalPages-i))+1),i<1&&(i=1),r>this.totalPages&&(r=this.totalPages);var v=Math.round(e.paginationPagesBySide/2),b=function(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return Il.sprintf(t.constants.html.paginationItem,i+(n===e.pageNumber?" ".concat(t.constants.classes.paginationActive):""),e.formatSRPaginationPageText(n),n)};if(i>1){var m=e.paginationPagesBySide;for(m>=i&&(m=i-1),n=1;n<=m;n++)c.push(b(n));i-1===m+1?(n=i-1,c.push(b(n))):i-1>m&&(i-2*e.paginationPagesBySide>e.paginationPagesBySide&&e.paginationUseIntermediate?(n=Math.round((i-v)/2+v),c.push(b(n," page-intermediate"))):c.push(Il.sprintf(this.constants.html.paginationItem," page-first-separator disabled","","...")))}for(n=i;n<=r;n++)c.push(b(n));if(this.totalPages>r){var y=this.totalPages-(e.paginationPagesBySide-1);for(r>=y&&(y=r+1),r+1===y-1?(n=r+1,c.push(b(n))):y>r+1&&(this.totalPages-r>2*e.paginationPagesBySide&&e.paginationUseIntermediate?(n=Math.round((this.totalPages-v-r)/2+r),c.push(b(n," page-intermediate"))):c.push(Il.sprintf(this.constants.html.paginationItem," page-last-separator disabled","","..."))),n=y;n<=this.totalPages;n++)c.push(b(n))}c.push(Il.sprintf(this.constants.html.paginationItem," page-next",e.formatSRPaginationNextText(),e.paginationNextText)),c.push(this.constants.html.pagination[1],"
    ")}this.$pagination.html(c.join(""));var w=["bottom","both"].includes(e.paginationVAlign)?" ".concat(this.constants.classes.dropup):"";this.$pagination.last().find(".page-list > div").addClass(w),e.onlyInfoPagination||(o=this.$pagination.find(".page-list a"),a=this.$pagination.find(".page-pre"),s=this.$pagination.find(".page-next"),l=this.$pagination.find(".page-item").not(".page-next, .page-pre, .page-last-separator, .page-first-separator"),this.totalPages<=1&&this.$pagination.find("div.pagination").hide(),e.smartDisplay&&(f.length<2||e.totalRows<=f[0])&&this.$pagination.find("div.page-list").hide(),this.$pagination[this.getData().length?"show":"hide"](),e.paginationLoop||(1===e.pageNumber&&a.addClass("disabled"),e.pageNumber===this.totalPages&&s.addClass("disabled")),u&&(e.pageSize=e.formatAllRows()),o.off("click").on("click",(function(e){return t.onPageListChange(e)})),a.off("click").on("click",(function(e){return t.onPagePre(e)})),s.off("click").on("click",(function(e){return t.onPageNext(e)})),l.off("click").on("click",(function(e){return t.onPageNumber(e)})))}else this.$pagination.hide()}},{key:"updatePagination",value:function(e){e&&t(e.currentTarget).hasClass("disabled")||(this.options.maintainMetaData||this.resetRows(),this.initPagination(),this.trigger("page-change",this.options.pageNumber,this.options.pageSize),"server"===this.options.sidePagination||"client"===this.options.sidePagination&&this.options.paginationLoadMore&&!this._paginationLoaded&&this.options.pageNumber===this.totalPages?this.initServer():this.initBody())}},{key:"onPageListChange",value:function(e){e.preventDefault();var n=t(e.currentTarget);return n.parent().addClass(this.constants.classes.dropdownActive).siblings().removeClass(this.constants.classes.dropdownActive),this.options.pageSize=n.text().toUpperCase()===this.options.formatAllRows().toUpperCase()?this.options.formatAllRows():+n.text(),this.$toolbar.find(".page-size").text(this.options.pageSize),this.updatePagination(e),!1}},{key:"onPagePre",value:function(e){if(!t(e.target).hasClass("disabled"))return e.preventDefault(),this.options.pageNumber-1==0?this.options.pageNumber=this.options.totalPages:this.options.pageNumber--,this.updatePagination(e),!1}},{key:"onPageNext",value:function(e){if(!t(e.target).hasClass("disabled"))return e.preventDefault(),this.options.pageNumber+1>this.options.totalPages?this.options.pageNumber=1:this.options.pageNumber++,this.updatePagination(e),!1}},{key:"onPageNumber",value:function(e){if(e.preventDefault(),this.options.pageNumber!==+t(e.currentTarget).text())return this.options.pageNumber=+t(e.currentTarget).text(),this.updatePagination(e),!1}},{key:"initRow",value:function(e,n,i,r){var o=this;if(!(Il.findIndex(this.hiddenRows,e)>-1)){var a=Il.calculateObjectValue(this.options,this.options.rowStyle,[e,n],{}),u=Il.calculateObjectValue(this.options,this.options.rowAttributes,[e,n],{}),f={};if(e._data&&!Il.isEmptyObject(e._data))for(var d=0,p=Object.entries(e._data);dtbody"),this.$body.length||(this.$body=t("").appendTo(this.$el)),this.options.pagination&&"server"!==this.options.sidePagination||(this.pageFrom=1,this.pageTo=r.length);var o=[],a=t(document.createDocumentFragment()),s=!1,l=[];this.autoMergeCells=Il.checkAutoMergeCells(r.slice(this.pageFrom-1,this.pageTo));for(var c=this.pageFrom-1;c tr[data-uniqueid="%s"][data-has-detail-view]',p)).next();g.is("tr.detail-view")&&(l.push(c),n&&p===n||d.push(g[0]))}this.options.virtualScroll?o.push(t("
    ").html(d).html()):a.append(d)}}this.$el.removeAttr("role"),s?this.options.virtualScroll?(this.virtualScroll&&this.virtualScroll.destroy(),this.virtualScroll=new Fl({rows:o,fixedScroll:e,scrollEl:this.$tableBody[0],contentEl:this.$body[0],itemHeight:this.options.virtualScrollItemHeight,callback:function(t,e){i.fitHeader(),i.initBodyEvent(),i.trigger("virtual-scroll",t,e)}})):this.$body.html(a):(this.$body.html(''.concat(Il.sprintf('%s',this.getVisibleFields().length+Il.getDetailViewIndexOffset(this.options),this.options.formatNoMatches()),"")),this.$el.attr("role","presentation")),l.forEach((function(t){i.expandRow(t)})),e||this.scrollTo(0),this.initBodyEvent(),this.initFooter(),this.resetView(),this.updateSelected(),"server"!==this.options.sidePagination&&(this.options.totalRows=r.length),this.trigger("post-body",r)}},{key:"initBodyEvent",value:function(){var e=this;this.$body.find("> tr[data-index] > td").off("click dblclick").on("click dblclick",(function(n){var i=t(n.currentTarget);if(!(i.find(".detail-icon").length||i.index()-Il.getDetailViewIndexOffset(e.options)<0)){var r=i.parent(),o=t(n.target).parents(".card-views").children(),a=t(n.target).parents(".card-view"),s=r.data("index"),l=e.data[s],c=e.options.cardView?o.index(a):i[0].cellIndex,u=e.getVisibleFields()[c-Il.getDetailViewIndexOffset(e.options)],h=e.columns[e.fieldsColumnsIndex[u]],f=Il.getItemField(l,u,e.options.escape,h.escape);if(e.trigger("click"===n.type?"click-cell":"dbl-click-cell",u,f,l,i),e.trigger("click"===n.type?"click-row":"dbl-click-row",l,r,u),"click"===n.type&&e.options.clickToSelect&&h.clickToSelect&&!Il.calculateObjectValue(e.options,e.options.ignoreClickToSelectOn,[n.target])){var d=r.find(Il.sprintf('[name="%s"]',e.options.selectItemName));d.length&&d[0].click()}"click"===n.type&&e.options.detailViewByClick&&e.toggleDetailView(s,e.header.detailFormatters[e.fieldsColumnsIndex[u]])}})).off("mousedown").on("mousedown",(function(t){e.multipleSelectRowCtrlKey=t.ctrlKey||t.metaKey,e.multipleSelectRowShiftKey=t.shiftKey})),this.$body.find("> tr[data-index] > td > .detail-icon").off("click").on("click",(function(n){return n.preventDefault(),e.toggleDetailView(t(n.currentTarget).parent().parent().data("index")),!1})),this.$selectItem=this.$body.find(Il.sprintf('[name="%s"]',this.options.selectItemName)),this.$selectItem.off("click").on("click",(function(n){n.stopImmediatePropagation();var i=t(n.currentTarget);e._toggleCheck(i.prop("checked"),i.data("index"))})),this.header.events.forEach((function(n,i){var r=n;if(r){if("string"==typeof r&&(r=Il.calculateObjectValue(null,r)),!r)throw new Error("Unknown event in the scope: ".concat(n));var o=e.header.fields[i],a=e.getVisibleFields().indexOf(o);if(-1!==a){a+=Il.getDetailViewIndexOffset(e.options);var s=function(n){if(!r.hasOwnProperty(n))return 1;var i=r[n];e.$body.find(">tr:not(.no-records-found)").each((function(r,s){var l=t(s),c=l.find(e.options.cardView?".card-views>.card-view":">td").eq(a),u=n.indexOf(" "),h=n.substring(0,u),f=n.substring(u+1);c.find(f).off(h).on(h,(function(t){var n=l.data("index"),r=e.data[n],a=r[o];i.apply(e,[t,a,r,n])}))}))};for(var l in r)s(l)}}}))}},{key:"initServer",value:function(e,n){var i=this,o={},a=this.header.fields.indexOf(this.options.sortName),s={searchText:this.searchText,sortName:this.options.sortName,sortOrder:this.options.sortOrder};if(this.header.sortNames[a]&&(s.sortName=this.header.sortNames[a]),this.options.pagination&&"server"===this.options.sidePagination&&(s.pageSize=this.options.pageSize===this.options.formatAllRows()?this.options.totalRows:this.options.pageSize,s.pageNumber=this.options.pageNumber),this.options.url||this.options.ajax){if("limit"===this.options.queryParamsType&&(s={search:s.searchText,sort:s.sortName,order:s.sortOrder},this.options.pagination&&"server"===this.options.sidePagination&&(s.offset=this.options.pageSize===this.options.formatAllRows()?0:this.options.pageSize*(this.options.pageNumber-1),s.limit=this.options.pageSize,0!==s.limit&&this.options.pageSize!==this.options.formatAllRows()||delete s.limit)),this.options.search&&"server"===this.options.sidePagination&&this.options.searchable&&this.columns.filter((function(t){return t.searchable})).length){s.searchable=[];var l,c=r(this.columns);try{for(c.s();!(l=c.n()).done;){var u=l.value;!u.checkbox&&u.searchable&&(this.options.visibleSearch&&u.visible||!this.options.visibleSearch)&&s.searchable.push(u.field)}}catch(t){c.e(t)}finally{c.f()}}if(Il.isEmptyObject(this.filterColumnsPartial)||(s.filter=JSON.stringify(this.filterColumnsPartial,null)),Il.extend(s,n||{}),!1!==(o=Il.calculateObjectValue(this.options,this.options.queryParams,[s],o))){e||this.showLoading();var h=Il.extend({},Il.calculateObjectValue(null,this.options.ajaxOptions),{type:this.options.method,url:this.options.url,data:"application/json"===this.options.contentType&&"post"===this.options.method?JSON.stringify(o):o,cache:this.options.cache,contentType:this.options.contentType,dataType:this.options.dataType,success:function(t,n,r){var o=Il.calculateObjectValue(i.options,i.options.responseHandler,[t,r],t);"client"===i.options.sidePagination&&i.options.paginationLoadMore&&(i._paginationLoaded=i.data.length===o.length),i.load(o),i.trigger("load-success",o,r&&r.status,r),e||i.hideLoading(),"server"===i.options.sidePagination&&i.options.pageNumber>1&&o[i.options.totalField]>0&&!o[i.options.dataField].length&&i.updatePagination()},error:function(t){if(t&&0===t.status&&i._xhrAbort)i._xhrAbort=!1;else{var n=[];"server"===i.options.sidePagination&&((n={})[i.options.totalField]=0,n[i.options.dataField]=[]),i.load(n),i.trigger("load-error",t&&t.status,t),e||i.hideLoading()}}});return this.options.ajax?Il.calculateObjectValue(this,this.options.ajax,[h],null):(this._xhr&&4!==this._xhr.readyState&&(this._xhrAbort=!0,this._xhr.abort()),this._xhr=t.ajax(h)),o}}}},{key:"initSearchText",value:function(){if(this.options.search&&(this.searchText="",""!==this.options.searchText)){var t=Il.getSearchInput(this);t.val(this.options.searchText),this.onSearch({currentTarget:t,firedByInitSearchText:!0})}}},{key:"getCaret",value:function(){var e=this;this.$header.find("th").each((function(n,i){t(i).find(".sortable").removeClass("desc asc").addClass(t(i).data("field")===e.options.sortName?e.options.sortOrder:"both")}))}},{key:"updateSelected",value:function(){var e=this.$selectItem.filter(":enabled").length&&this.$selectItem.filter(":enabled").length===this.$selectItem.filter(":enabled").filter(":checked").length;this.$selectAll.add(this.$selectAll_).prop("checked",e),this.$selectItem.each((function(e,n){t(n).closest("tr")[t(n).prop("checked")?"addClass":"removeClass"]("selected")}))}},{key:"updateRows",value:function(){var e=this;this.$selectItem.each((function(n,i){e.data[t(i).data("index")][e.header.stateField]=t(i).prop("checked")}))}},{key:"resetRows",value:function(){var t,e=r(this.data);try{for(e.s();!(t=e.n()).done;){var n=t.value;this.$selectAll.prop("checked",!1),this.$selectItem.prop("checked",!1),this.header.stateField&&(n[this.header.stateField]=!1)}}catch(t){e.e(t)}finally{e.f()}this.initHiddenRows()}},{key:"trigger",value:function(n){for(var i,r,o="".concat(n,".bs.table"),a=arguments.length,s=new Array(a>1?a-1:0),l=1;ln.clientHeight+this.$header.outerHeight()?Il.getScrollBarWidth():0;this.$el.css("margin-top",-this.$header.outerHeight());var r=this.$tableHeader.find(":focus");if(r.length>0){var o=r.parents("th");if(o.length>0){var a=o.attr("data-field");if(void 0!==a){var s=this.$header.find("[data-field='".concat(a,"']"));s.length>0&&s.find(":input").addClass("focus-temp")}}}this.$header_=this.$header.clone(!0,!0),this.$selectAll_=this.$header_.find('[name="btSelectAll"]'),this.$tableHeader.css("margin-right",i).find("table").css("width",this.$el.outerWidth()).html("").attr("class",this.$el.attr("class")).append(this.$header_),this.$tableLoading.css("width",this.$el.outerWidth());var l=t(".focus-temp:visible:eq(0)");l.length>0&&(l.focus(),this.$header.find(".focus-temp").removeClass("focus-temp")),this.$header.find("th[data-field]").each((function(n,i){e.$header_.find(Il.sprintf('th[data-field="%s"]',t(i).data("field"))).data(t(i).data())}));for(var c=this.getVisibleFields(),u=this.$header_.find("th"),h=this.$body.find(">tr:not(.no-records-found,.virtual-scroll-top)").eq(0);h.length&&h.find('>td[colspan]:not([colspan="1"])').length;)h=h.next();var f=h.find("> *").length;h.find("> *").each((function(n,i){var r=t(i);if(Il.hasDetailViewIcon(e.options)&&(0===n&&"right"!==e.options.detailViewAlign||n===f-1&&"right"===e.options.detailViewAlign)){var o=u.filter(".detail"),a=o.innerWidth()-o.find(".fht-cell").width();o.find(".fht-cell").width(r.innerWidth()-a)}else{var s=n-Il.getDetailViewIndexOffset(e.options),l=e.$header_.find(Il.sprintf('th[data-field="%s"]',c[s]));l.length>1&&(l=t(u[r[0].cellIndex]));var h=l.innerWidth()-l.find(".fht-cell").width();l.find(".fht-cell").width(r.innerWidth()-h)}})),this.horizontalScroll(),this.trigger("post-header")}}},{key:"initFooter",value:function(){if(this.options.showFooter&&!this.options.cardView){var t=this.getData(),e=[],n="";Il.hasDetailViewIcon(this.options)&&(n=Il.h("th",{class:"detail"},[Il.h("div",{class:"th-inner"}),Il.h("div",{class:"fht-cell"})])),n&&"right"!==this.options.detailViewAlign&&e.push(n);var i,o=r(this.columns);try{for(o.s();!(i=o.n()).done;){var a=i.value,l=this.footerData&&this.footerData.length>0;if(a.visible&&(!l||a.field in this.footerData[0])){if(this.options.cardView&&!a.cardVisible)return;var u=Il.calculateObjectValue(null,a.footerStyle||this.options.footerStyle,[a]),h=u&&u.css||{},f=l&&this.footerData[0]["_".concat(a.field,"_colspan")]||0,d=l&&this.footerData[0][a.field]||"";d=Il.calculateObjectValue(a,a.footerFormatter,[t,d],d),e.push(Il.h("th",{class:[a.class,u&&u.classes],style:s({"text-align":a.falign?a.falign:a.align,"vertical-align":a.valign},h),colspan:f||void 0},[Il.h("div",{class:"th-inner"},c(Il.htmlToNodes(d))),Il.h("div",{class:"fht-cell"})]))}}}catch(t){o.e(t)}finally{o.f()}n&&"right"===this.options.detailViewAlign&&e.push(n),this.options.height||this.$tableFooter.length||(this.$el.append(""),this.$tableFooter=this.$el.find("tfoot")),this.$tableFooter.find("tr").length||this.$tableFooter.html("
    "),this.$tableFooter.find("tr").html(e),this.trigger("post-footer",this.$tableFooter)}}},{key:"fitFooter",value:function(){var e=this;if(this.$el.is(":hidden"))setTimeout((function(){return e.fitFooter()}),100);else{var n=this.$tableBody.get(0),i=this.hasScrollBar&&n.scrollHeight>n.clientHeight+this.$header.outerHeight()?Il.getScrollBarWidth():0;this.$tableFooter.css("margin-right",i).find("table").css("width",this.$el.outerWidth()).attr("class",this.$el.attr("class"));var r=this.$tableFooter.find("th"),o=this.$body.find(">tr:first-child:not(.no-records-found)");for(r.find(".fht-cell").width("auto");o.length&&o.find('>td[colspan]:not([colspan="1"])').length;)o=o.next();var a=o.find("> *").length;o.find("> *").each((function(n,i){var o=t(i);if(Il.hasDetailViewIcon(e.options)&&(0===n&&"left"===e.options.detailViewAlign||n===a-1&&"right"===e.options.detailViewAlign)){var s=r.filter(".detail"),l=s.innerWidth()-s.find(".fht-cell").width();s.find(".fht-cell").width(o.innerWidth()-l)}else{var c=r.eq(n),u=c.innerWidth()-c.find(".fht-cell").width();c.find(".fht-cell").width(o.innerWidth()-u)}})),this.horizontalScroll()}}},{key:"horizontalScroll",value:function(){var t=this;this.$tableBody.off("scroll").on("scroll",(function(){var e=t.$tableBody.scrollLeft();t.options.showHeader&&t.options.height&&t.$tableHeader.scrollLeft(e),t.options.showFooter&&!t.options.cardView&&t.$tableFooter.scrollLeft(e),t.trigger("scroll-body",t.$tableBody)}))}},{key:"getVisibleFields",value:function(){var t,e=[],n=r(this.header.fields);try{for(n.s();!(t=n.n()).done;){var i=t.value,o=this.columns[this.fieldsColumnsIndex[i]];o&&o.visible&&(!this.options.cardView||o.cardVisible)&&e.push(i)}}catch(t){n.e(t)}finally{n.f()}return e}},{key:"initHiddenRows",value:function(){this.hiddenRows=[]}},{key:"getOptions",value:function(){var t=Il.extend({},this.options);return delete t.data,Il.extend(!0,{},t)}},{key:"refreshOptions",value:function(t){Il.compareObjects(this.options,t,!0)||(this.optionsColumnsChanged=!!t.columns,this.options=Il.extend(this.options,t),this.trigger("refresh-options",this.options),this.destroy(),this.init())}},{key:"getData",value:function(t){var e=this,n=this.options.data;if(!(this.searchText||this.options.customSearch||void 0!==this.options.sortName||this.enableCustomSort)&&Il.isEmptyObject(this.filterColumns)&&"function"!=typeof this.options.filterOptions.filterAlgorithm&&Il.isEmptyObject(this.filterColumnsPartial)||t&&t.unfiltered||(n=this.data),t&&!t.includeHiddenRows){var i=this.getHiddenRows();n=n.filter((function(t){return-1===Il.findIndex(i,t)}))}return t&&t.useCurrentPage&&(n=n.slice(this.pageFrom-1,this.pageTo)),t&&t.formatted?n.map((function(t){for(var n={},i=0,r=Object.entries(t);i=0;n--){var i=this.options.data[n],r=Il.getItemField(i,t.field,this.options.escape,i.escape);void 0===r&&"$index"!==t.field||(!i.hasOwnProperty(t.field)&&"$index"===t.field&&t.values.includes(n)||t.values.includes(r))&&(e++,this.options.data.splice(n,1))}e&&("server"===this.options.sidePagination&&(this.options.totalRows-=e,this.data=c(this.options.data)),this.initSearch(),this.initPagination(),this.initSort(),this.initBody(!0))}},{key:"removeAll",value:function(){this.options.data.length>0&&(this.data.splice(0,this.data.length),this.options.data.splice(0,this.options.data.length),this.initSearch(),this.initPagination(),this.initBody(!0))}},{key:"insertRow",value:function(t){if(t.hasOwnProperty("index")&&t.hasOwnProperty("row")){var e=this.data[t.index],n=this.options.data.indexOf(e);-1!==n?(this.data.splice(t.index,0,t.row),this.options.data.splice(n,0,t.row),this.initSearch(),this.initPagination(),this.initSort(),this.initBody(!0)):this.append([t.row])}}},{key:"updateRow",value:function(t){var e,n=r(Array.isArray(t)?t:[t]);try{for(n.s();!(e=n.n()).done;){var i=e.value;if(i.hasOwnProperty("index")&&i.hasOwnProperty("row")){var o=this.data[i.index],a=this.options.data.indexOf(o);i.hasOwnProperty("replace")&&i.replace?(this.data[i.index]=i.row,this.options.data[a]=i.row):(Il.extend(this.data[i.index],i.row),Il.extend(this.options.data[a],i.row))}}}catch(t){n.e(t)}finally{n.f()}this.initSearch(),this.initPagination(),this.initSort(),this.initBody(!0)}},{key:"getRowByUniqueId",value:function(t){var e,n,i=this.options.uniqueId,r=t,o=null;for(e=this.options.data.length-1;e>=0;e--){n=this.options.data[e];var a=Il.getItemField(n,i,this.options.escape,n.escape);if(void 0!==a&&("string"==typeof a?r=t.toString():"number"==typeof a&&(Number(a)===a&&a%1==0?r=parseInt(t,10):a===Number(a)&&0!==a&&(r=parseFloat(t))),a===r)){o=n;break}}return o}},{key:"updateByUniqueId",value:function(t){var e,n=null,i=r(Array.isArray(t)?t:[t]);try{for(i.s();!(e=i.n()).done;){var o=e.value;if(o.hasOwnProperty("id")&&o.hasOwnProperty("row")){var a=this.options.data.indexOf(this.getRowByUniqueId(o.id));-1!==a&&(o.hasOwnProperty("replace")&&o.replace?this.options.data[a]=o.row:Il.extend(this.options.data[a],o.row),n=o.id)}}}catch(t){i.e(t)}finally{i.f()}this.initSearch(),this.initPagination(),this.initSort(),this.initBody(!0,n)}},{key:"removeByUniqueId",value:function(t){var e=this.options.data.length,n=this.getRowByUniqueId(t);n&&this.options.data.splice(this.options.data.indexOf(n),1),e!==this.options.data.length&&("server"===this.options.sidePagination&&(this.options.totalRows-=1,this.data=c(this.options.data)),this.initSearch(),this.initPagination(),this.initBody(!0))}},{key:"_updateCellOnly",value:function(e,n){var i=this.initRow(this.data[n],n),r=this.getVisibleFields().indexOf(e);-1!==r&&(r+=Il.getDetailViewIndexOffset(this.options),this.$body.find(">tr[data-index=".concat(n,"]")).find(">td:eq(".concat(r,")")).replaceWith(t(i).find(">td:eq(".concat(r,")"))),this.initBodyEvent(),this.initFooter(),this.resetView(),this.updateSelected())}},{key:"updateCell",value:function(t){if(t.hasOwnProperty("index")&&t.hasOwnProperty("field")&&t.hasOwnProperty("value")){var e=this.data[t.index],n=this.options.data.indexOf(e);this.data[t.index][t.field]=t.value,this.options.data[n][t.field]=t.value,!1!==t.reinit?(this.initSort(),this.initBody(!0)):this._updateCellOnly(t.field,t.index)}}},{key:"updateCellByUniqueId",value:function(t){var e=this;(Array.isArray(t)?t:[t]).forEach((function(t){var n=t.id,i=t.field,r=t.value,o=e.options.data.indexOf(e.getRowByUniqueId(n));-1!==o&&(e.options.data[o][i]=r)})),!1!==t.reinit?(this.initSort(),this.initBody(!0)):this._updateCellOnly(t.field,this.options.data.indexOf(this.getRowByUniqueId(t.id)))}},{key:"showRow",value:function(t){this._toggleRow(t,!0)}},{key:"hideRow",value:function(t){this._toggleRow(t,!1)}},{key:"_toggleRow",value:function(t,e){var n;if(t.hasOwnProperty("index")?n=this.getData()[t.index]:t.hasOwnProperty("uniqueId")&&(n=this.getRowByUniqueId(t.uniqueId)),n){var i=Il.findIndex(this.hiddenRows,n);e||-1!==i?e&&i>-1&&this.hiddenRows.splice(i,1):this.hiddenRows.push(n),this.initBody(!0),this.initPagination()}}},{key:"getHiddenRows",value:function(t){if(t)return this.initHiddenRows(),this.initBody(!0),void this.initPagination();var e,n=[],i=r(this.getData());try{for(i.s();!(e=i.n()).done;){var o=e.value;this.hiddenRows.includes(o)&&n.push(o)}}catch(t){i.e(t)}finally{i.f()}return this.hiddenRows=n,n}},{key:"showColumn",value:function(t){var e=this;(Array.isArray(t)?t:[t]).forEach((function(t){e._toggleColumn(e.fieldsColumnsIndex[t],!0,!0)}))}},{key:"hideColumn",value:function(t){var e=this;(Array.isArray(t)?t:[t]).forEach((function(t){e._toggleColumn(e.fieldsColumnsIndex[t],!1,!0)}))}},{key:"_toggleColumn",value:function(t,e,n){if(void 0!==t&&this.columns[t].visible!==e&&(this.columns[t].visible=e,this.initHeader(),this.initSearch(),this.initPagination(),this.initBody(),this.options.showColumns)){var i=this.$toolbar.find('.keep-open input:not(".toggle-all")').prop("disabled",!1);n&&i.filter(Il.sprintf('[value="%s"]',t)).prop("checked",e),i.filter(":checked").length<=this.options.minimumCountColumns&&i.filter(":checked").prop("disabled",!0)}}},{key:"getVisibleColumns",value:function(){var t=this;return this.columns.filter((function(e){return e.visible&&!t.isSelectionColumn(e)}))}},{key:"getHiddenColumns",value:function(){return this.columns.filter((function(t){return!t.visible}))}},{key:"isSelectionColumn",value:function(t){return t.radio||t.checkbox}},{key:"showAllColumns",value:function(){this._toggleAllColumns(!0)}},{key:"hideAllColumns",value:function(){this._toggleAllColumns(!1)}},{key:"_toggleAllColumns",value:function(e){var n,i=this,o=r(this.columns.slice().reverse());try{for(o.s();!(n=o.n()).done;){var a=n.value;if(a.switchable){if(!e&&this.options.showColumns&&this.getVisibleColumns().filter((function(t){return t.switchable})).length===this.options.minimumCountColumns)continue;a.visible=e}}}catch(t){o.e(t)}finally{o.f()}if(this.initHeader(),this.initSearch(),this.initPagination(),this.initBody(),this.options.showColumns){var s=this.$toolbar.find('.keep-open input[type="checkbox"]:not(".toggle-all")').prop("disabled",!1);e?s.prop("checked",e):s.get().reverse().forEach((function(n){s.filter(":checked").length>i.options.minimumCountColumns&&t(n).prop("checked",e)})),s.filter(":checked").length<=this.options.minimumCountColumns&&s.filter(":checked").prop("disabled",!0)}}},{key:"mergeCells",value:function(t){var e,n,i=t.index,r=this.getVisibleFields().indexOf(t.field),o=+t.rowspan||1,a=+t.colspan||1,s=this.$body.find(">tr[data-index]");r+=Il.getDetailViewIndexOffset(this.options);var l=s.eq(i).find(">td").eq(r);if(!(i<0||r<0||i>=this.data.length)){for(e=i;etd").eq(n).hide();l.attr("rowspan",o).attr("colspan",a).show()}}},{key:"checkAll",value:function(){this._toggleCheckAll(!0)}},{key:"uncheckAll",value:function(){this._toggleCheckAll(!1)}},{key:"_toggleCheckAll",value:function(t){var e=this.getSelections();this.$selectAll.add(this.$selectAll_).prop("checked",t),this.$selectItem.filter(":enabled").prop("checked",t),this.updateRows(),this.updateSelected();var n=this.getSelections();t?this.trigger("check-all",n,e):this.trigger("uncheck-all",n,e)}},{key:"checkInvert",value:function(){var e=this.$selectItem.filter(":enabled"),n=e.filter(":checked");e.each((function(e,n){t(n).prop("checked",!t(n).prop("checked"))})),this.updateRows(),this.updateSelected(),this.trigger("uncheck-some",n),n=this.getSelections(),this.trigger("check-some",n)}},{key:"check",value:function(t){this._toggleCheck(!0,t)}},{key:"uncheck",value:function(t){this._toggleCheck(!1,t)}},{key:"_toggleCheck",value:function(t,e){var n=this.$selectItem.filter('[data-index="'.concat(e,'"]')),i=this.data[e];if(n.is(":radio")||this.options.singleSelect||this.options.multipleSelectRow&&!this.multipleSelectRowCtrlKey&&!this.multipleSelectRowShiftKey){var o,a=r(this.options.data);try{for(a.s();!(o=a.n()).done;){o.value[this.header.stateField]=!1}}catch(t){a.e(t)}finally{a.f()}this.$selectItem.filter(":checked").not(n).prop("checked",!1)}if(i[this.header.stateField]=t,this.options.multipleSelectRow){if(this.multipleSelectRowShiftKey&&this.multipleSelectRowLastSelectedIndex>=0)for(var s=l(this.multipleSelectRowLastSelectedIndexn.clientWidth}if(!this.options.cardView&&this.options.showHeader&&this.options.height?(this.$tableHeader.show(),this.resetHeader(),e+=this.$header.outerHeight(!0)+1):(this.$tableHeader.hide(),this.trigger("post-header")),!this.options.cardView&&this.options.showFooter&&(this.$tableFooter.show(),this.fitFooter(),this.options.height&&(e+=this.$tableFooter.outerHeight(!0))),this.$container.hasClass("fullscreen"))this.$tableContainer.css("height",""),this.$tableContainer.css("width","");else if(this.options.height){this.$tableBorder&&(this.$tableBorder.css("width",""),this.$tableBorder.css("height",""));var i=this.$toolbar.outerHeight(!0),r=this.$pagination.outerHeight(!0),o=this.options.height-i-r,a=this.$tableBody.find(">table"),s=a.outerHeight();if(this.$tableContainer.css("height","".concat(o,"px")),this.$tableBorder&&a.is(":visible")){var l=o-s-2;this.hasScrollBar&&(l-=Il.getScrollBarWidth()),this.$tableBorder.css("width","".concat(a.outerWidth(),"px")),this.$tableBorder.css("height","".concat(l,"px"))}}this.options.cardView?(this.$el.css("margin-top","0"),this.$tableContainer.css("padding-bottom","0"),this.$tableFooter.hide()):(this.getCaret(),this.$tableContainer.css("padding-bottom","".concat(e,"px"))),this.trigger("reset-view")}},{key:"showLoading",value:function(){this.$tableLoading.toggleClass("open",!0);var t=this.options.loadingFontSize;"auto"===this.options.loadingFontSize&&(t=.04*this.$tableLoading.width(),t=Math.max(12,t),t=Math.min(32,t),t="".concat(t,"px")),this.$tableLoading.find(".loading-text").css("font-size",t)}},{key:"hideLoading",value:function(){this.$tableLoading.toggleClass("open",!1)}},{key:"togglePagination",value:function(){this.options.pagination=!this.options.pagination;var t=this.options.showButtonIcons?this.options.pagination?this.options.icons.paginationSwitchDown:this.options.icons.paginationSwitchUp:"",e=this.options.showButtonText?this.options.pagination?this.options.formatPaginationSwitchUp():this.options.formatPaginationSwitchDown():"";this.$toolbar.find('button[name="paginationSwitch"]').html("".concat(Il.sprintf(this.constants.html.icon,this.options.iconsPrefix,t)," ").concat(e)),this.updatePagination(),this.trigger("toggle-pagination",this.options.pagination)}},{key:"toggleFullscreen",value:function(){this.$el.closest(".bootstrap-table").toggleClass("fullscreen"),this.resetView()}},{key:"toggleView",value:function(){this.options.cardView=!this.options.cardView,this.initHeader();var t=this.options.showButtonIcons?this.options.cardView?this.options.icons.toggleOn:this.options.icons.toggleOff:"",e=this.options.cardView?this.options.formatToggleOff():this.options.formatToggleOn();this.$toolbar.find('button[name="toggle"]').html("".concat(Il.sprintf(this.constants.html.icon,this.options.iconsPrefix,t)," ").concat(this.options.showButtonText?e:"")).attr("aria-label",e).attr(this.options.buttonsAttributeTitle,e),this.initBody(),this.trigger("toggle",this.options.cardView)}},{key:"resetSearch",value:function(t){var e=Il.getSearchInput(this),n=t||"";e.val(n),this.searchText=n,this.onSearch({currentTarget:e},!1)}},{key:"filterBy",value:function(t,e){this.filterOptions=Il.isEmptyObject(e)?this.options.filterOptions:Il.extend({},this.options.filterOptions,e),this.filterColumns=Il.isEmptyObject(t)?{}:t,this.options.pageNumber=1,this.initSearch(),this.updatePagination()}},{key:"scrollTo",value:function(e){var n={unit:"px",value:0};"object"===h(e)?n=Object.assign(n,e):"string"==typeof e&&"bottom"===e?n.value=this.$tableBody[0].scrollHeight:"string"!=typeof e&&"number"!=typeof e||(n.value=e);var i=n.value;"rows"===n.unit&&(i=0,this.$body.find("> tr:lt(".concat(n.value,")")).each((function(e,n){i+=t(n).outerHeight(!0)}))),this.$tableBody.scrollTop(i)}},{key:"getScrollPosition",value:function(){return this.$tableBody.scrollTop()}},{key:"selectPage",value:function(t){t>0&&t<=this.options.totalPages&&(this.options.pageNumber=t,this.updatePagination())}},{key:"prevPage",value:function(){this.options.pageNumber>1&&(this.options.pageNumber--,this.updatePagination())}},{key:"nextPage",value:function(){this.options.pageNumber tr[data-index="%s"]',t)).next().is("tr.detail-view")?this.collapseRow(t):this.expandRow(t,e),this.resetView()}},{key:"expandRow",value:function(t,e){var n=this.data[t],i=this.$body.find(Il.sprintf('> tr[data-index="%s"][data-has-detail-view]',t));if(this.options.detailViewIcon&&i.find("a.detail-icon").html(Il.sprintf(this.constants.html.icon,this.options.iconsPrefix,this.options.icons.detailClose)),!i.next().is("tr.detail-view")){i.after(Il.sprintf('',i.children("td").length));var r=i.next().find("td"),o=e||this.options.detailFormatter,a=Il.calculateObjectValue(this.options,o,[t,n,r],"");1===r.length&&r.append(a),this.trigger("expand-row",t,n,r)}}},{key:"expandRowByUniqueId",value:function(t){var e=this.getRowByUniqueId(t);e&&this.expandRow(this.data.indexOf(e))}},{key:"collapseRow",value:function(t){var e=this.data[t],n=this.$body.find(Il.sprintf('> tr[data-index="%s"][data-has-detail-view]',t));n.next().is("tr.detail-view")&&(this.options.detailViewIcon&&n.find("a.detail-icon").html(Il.sprintf(this.constants.html.icon,this.options.iconsPrefix,this.options.icons.detailOpen)),this.trigger("collapse-row",t,e,n.next()),n.next().remove())}},{key:"collapseRowByUniqueId",value:function(t){var e=this.getRowByUniqueId(t);e&&this.collapseRow(this.data.indexOf(e))}},{key:"expandAllRows",value:function(){for(var e=this.$body.find("> tr[data-index][data-has-detail-view]"),n=0;n tr[data-index][data-has-detail-view]"),n=0;n1?n-1:0),r=1;r (http://wenzhixin.net.cn/) + * @license MIT + */ + +!function(r,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],t):t((r="undefined"!=typeof globalThis?globalThis:r||self).jQuery)}(this,(function(r){"use strict";function t(r,t){(null==t||t>r.length)&&(t=r.length);for(var n=0,e=Array(t);n=r.length?{done:!0}:{done:!1,value:r[o++]}},e:function(r){throw r},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var u,f=!0,c=!1;return{s:function(){e=e.call(r)},n:function(){var r=e.next();return f=r.done,r},e:function(r){c=!0,u=r},f:function(){try{f||null==e.return||e.return()}finally{if(c)throw u}}}}function i(){return i="undefined"!=typeof Reflect&&Reflect.get?Reflect.get.bind():function(r,t,n){var e=function(r,t){for(;!{}.hasOwnProperty.call(r,t)&&null!==(r=u(r)););return r}(r,t);if(e){var o=Object.getOwnPropertyDescriptor(e,t);return o.get?o.get.call(arguments.length<3?r:n):o.value}},i.apply(null,arguments)}function u(r){return u=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(r){return r.__proto__||Object.getPrototypeOf(r)},u(r)}function f(){try{var r=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(r){}return(f=function(){return!!r})()}function c(r,t){return c=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(r,t){return r.__proto__=t,r},c(r,t)}function a(r,t,n,e){var o=i(u(1&e?r.prototype:r),t,n);return 2&e&&"function"==typeof o?function(r){return o.apply(n,r)}:o}function l(r){var t=function(r,t){if("object"!=typeof r||!r)return r;var n=r[Symbol.toPrimitive];if(void 0!==n){var e=n.call(r,t);if("object"!=typeof e)return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(r)}(r,"string");return"symbol"==typeof t?t:t+""}var s,v,p="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},y={};function b(){if(v)return s;v=1;var r=function(r){return r&&r.Math===Math&&r};return s=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof p&&p)||r("object"==typeof s&&s)||function(){return this}()||Function("return this")()}var d,h,g,m,w,j,O,S,P={};function E(){return h?d:(h=1,d=function(r){try{return!!r()}catch(r){return!0}})}function T(){if(m)return g;m=1;var r=E();return g=!r((function(){return 7!==Object.defineProperty({},1,{get:function(){return 7}})[1]}))}function F(){if(j)return w;j=1;var r=E();return w=!r((function(){var r=function(){}.bind();return"function"!=typeof r||r.hasOwnProperty("prototype")}))}function A(){if(S)return O;S=1;var r=F(),t=Function.prototype.call;return O=r?t.bind(t):function(){return t.apply(t,arguments)},O}var _,I,k,x,R,C,M,B,z,D,L,N,q,G,U,W,$,H,K,Q,V,X,Y,J,Z,rr,tr,nr,er,or,ir,ur,fr,cr,ar,lr,sr,vr,pr,yr,br,dr={};function hr(){if(_)return dr;_=1;var r={}.propertyIsEnumerable,t=Object.getOwnPropertyDescriptor,n=t&&!r.call({1:2},1);return dr.f=n?function(r){var n=t(this,r);return!!n&&n.enumerable}:r,dr}function gr(){return k?I:(k=1,I=function(r,t){return{enumerable:!(1&r),configurable:!(2&r),writable:!(4&r),value:t}})}function mr(){if(R)return x;R=1;var r=F(),t=Function.prototype,n=t.call,e=r&&t.bind.bind(n,n);return x=r?e:function(r){return function(){return n.apply(r,arguments)}},x}function wr(){if(M)return C;M=1;var r=mr(),t=r({}.toString),n=r("".slice);return C=function(r){return n(t(r),8,-1)}}function jr(){if(z)return B;z=1;var r=mr(),t=E(),n=wr(),e=Object,o=r("".split);return B=t((function(){return!e("z").propertyIsEnumerable(0)}))?function(r){return"String"===n(r)?o(r,""):e(r)}:e}function Or(){return L?D:(L=1,D=function(r){return null==r})}function Sr(){if(q)return N;q=1;var r=Or(),t=TypeError;return N=function(n){if(r(n))throw new t("Can't call method on "+n);return n}}function Pr(){if(U)return G;U=1;var r=jr(),t=Sr();return G=function(n){return r(t(n))}}function Er(){if($)return W;$=1;var r="object"==typeof document&&document.all;return W=void 0===r&&void 0!==r?function(t){return"function"==typeof t||t===r}:function(r){return"function"==typeof r}}function Tr(){if(K)return H;K=1;var r=Er();return H=function(t){return"object"==typeof t?null!==t:r(t)}}function Fr(){if(V)return Q;V=1;var r=b(),t=Er();return Q=function(n,e){return arguments.length<2?(o=r[n],t(o)?o:void 0):r[n]&&r[n][e];var o},Q}function Ar(){if(tr)return rr;tr=1;var r,t,n=b(),e=function(){if(Z)return J;Z=1;var r=b().navigator,t=r&&r.userAgent;return J=t?String(t):""}(),o=n.process,i=n.Deno,u=o&&o.versions||i&&i.version,f=u&&u.v8;return f&&(t=(r=f.split("."))[0]>0&&r[0]<4?1:+(r[0]+r[1])),!t&&e&&(!(r=e.match(/Edge\/(\d+)/))||r[1]>=74)&&(r=e.match(/Chrome\/(\d+)/))&&(t=+r[1]),rr=t}function _r(){if(er)return nr;er=1;var r=Ar(),t=E(),n=b().String;return nr=!!Object.getOwnPropertySymbols&&!t((function(){var t=Symbol("symbol detection");return!n(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&r&&r<41}))}function Ir(){if(ir)return or;ir=1;var r=_r();return or=r&&!Symbol.sham&&"symbol"==typeof Symbol.iterator}function kr(){if(fr)return ur;fr=1;var r=Fr(),t=Er(),n=function(){if(Y)return X;Y=1;var r=mr();return X=r({}.isPrototypeOf)}(),e=Ir(),o=Object;return ur=e?function(r){return"symbol"==typeof r}:function(e){var i=r("Symbol");return t(i)&&n(i.prototype,o(e))}}function xr(){if(ar)return cr;ar=1;var r=String;return cr=function(t){try{return r(t)}catch(r){return"Object"}}}function Rr(){if(sr)return lr;sr=1;var r=Er(),t=xr(),n=TypeError;return lr=function(e){if(r(e))return e;throw new n(t(e)+" is not a function")}}function Cr(){if(pr)return vr;pr=1;var r=Rr(),t=Or();return vr=function(n,e){var o=n[e];return t(o)?void 0:r(o)}}function Mr(){if(br)return yr;br=1;var r=A(),t=Er(),n=Tr(),e=TypeError;return yr=function(o,i){var u,f;if("string"===i&&t(u=o.toString)&&!n(f=r(u,o)))return f;if(t(u=o.valueOf)&&!n(f=r(u,o)))return f;if("string"!==i&&t(u=o.toString)&&!n(f=r(u,o)))return f;throw new e("Can't convert object to primitive value")}}var Br,zr,Dr,Lr,Nr,qr,Gr,Ur,Wr,$r,Hr,Kr,Qr,Vr,Xr,Yr,Jr,Zr,rt,tt,nt,et,ot,it,ut={exports:{}};function ft(){if(Lr)return Dr;Lr=1;var r=b(),t=Object.defineProperty;return Dr=function(n,e){try{t(r,n,{value:e,configurable:!0,writable:!0})}catch(t){r[n]=e}return e}}function ct(){if(Nr)return ut.exports;Nr=1;var r=zr?Br:(zr=1,Br=!1),t=b(),n=ft(),e="__core-js_shared__",o=ut.exports=t[e]||n(e,{});return(o.versions||(o.versions=[])).push({version:"3.39.0",mode:r?"pure":"global",copyright:"© 2014-2024 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.39.0/LICENSE",source:"https://github.com/zloirock/core-js"}),ut.exports}function at(){if(Gr)return qr;Gr=1;var r=ct();return qr=function(t,n){return r[t]||(r[t]=n||{})}}function lt(){if(Wr)return Ur;Wr=1;var r=Sr(),t=Object;return Ur=function(n){return t(r(n))}}function st(){if(Hr)return $r;Hr=1;var r=mr(),t=lt(),n=r({}.hasOwnProperty);return $r=Object.hasOwn||function(r,e){return n(t(r),e)}}function vt(){if(Qr)return Kr;Qr=1;var r=mr(),t=0,n=Math.random(),e=r(1..toString);return Kr=function(r){return"Symbol("+(void 0===r?"":r)+")_"+e(++t+n,36)}}function pt(){if(Xr)return Vr;Xr=1;var r=b(),t=at(),n=st(),e=vt(),o=_r(),i=Ir(),u=r.Symbol,f=t("wks"),c=i?u.for||u:u&&u.withoutSetter||e;return Vr=function(r){return n(f,r)||(f[r]=o&&n(u,r)?u[r]:c("Symbol."+r)),f[r]}}function yt(){if(Jr)return Yr;Jr=1;var r=A(),t=Tr(),n=kr(),e=Cr(),o=Mr(),i=pt(),u=TypeError,f=i("toPrimitive");return Yr=function(i,c){if(!t(i)||n(i))return i;var a,l=e(i,f);if(l){if(void 0===c&&(c="default"),a=r(l,i,c),!t(a)||n(a))return a;throw new u("Can't convert object to primitive value")}return void 0===c&&(c="number"),o(i,c)}}function bt(){if(rt)return Zr;rt=1;var r=yt(),t=kr();return Zr=function(n){var e=r(n,"string");return t(e)?e:e+""}}function dt(){if(ot)return et;ot=1;var r=T(),t=E(),n=function(){if(nt)return tt;nt=1;var r=b(),t=Tr(),n=r.document,e=t(n)&&t(n.createElement);return tt=function(r){return e?n.createElement(r):{}}}();return et=!r&&!t((function(){return 7!==Object.defineProperty(n("div"),"a",{get:function(){return 7}}).a}))}function ht(){if(it)return P;it=1;var r=T(),t=A(),n=hr(),e=gr(),o=Pr(),i=bt(),u=st(),f=dt(),c=Object.getOwnPropertyDescriptor;return P.f=r?c:function(r,a){if(r=o(r),a=i(a),f)try{return c(r,a)}catch(r){}if(u(r,a))return e(!t(n.f,r,a),r[a])},P}var gt,mt,wt,jt,Ot,St,Pt,Et={};function Tt(){if(jt)return wt;jt=1;var r=Tr(),t=String,n=TypeError;return wt=function(e){if(r(e))return e;throw new n(t(e)+" is not an object")}}function Ft(){if(Ot)return Et;Ot=1;var r=T(),t=dt(),n=function(){if(mt)return gt;mt=1;var r=T(),t=E();return gt=r&&t((function(){return 42!==Object.defineProperty((function(){}),"prototype",{value:42,writable:!1}).prototype}))}(),e=Tt(),o=bt(),i=TypeError,u=Object.defineProperty,f=Object.getOwnPropertyDescriptor,c="enumerable",a="configurable",l="writable";return Et.f=r?n?function(r,t,n){if(e(r),t=o(t),e(n),"function"==typeof r&&"prototype"===t&&"value"in n&&l in n&&!n[l]){var i=f(r,t);i&&i[l]&&(r[t]=n.value,n={configurable:a in n?n[a]:i[a],enumerable:c in n?n[c]:i[c],writable:!1})}return u(r,t,n)}:u:function(r,n,f){if(e(r),n=o(n),e(f),t)try{return u(r,n,f)}catch(r){}if("get"in f||"set"in f)throw new i("Accessors not supported");return"value"in f&&(r[n]=f.value),r},Et}function At(){if(Pt)return St;Pt=1;var r=T(),t=Ft(),n=gr();return St=r?function(r,e,o){return t.f(r,e,n(1,o))}:function(r,t,n){return r[t]=n,r}}var _t,It,kt,xt,Rt,Ct,Mt,Bt,zt,Dt,Lt,Nt,qt,Gt,Ut,Wt={exports:{}};function $t(){if(xt)return kt;xt=1;var r=mr(),t=Er(),n=ct(),e=r(Function.toString);return t(n.inspectSource)||(n.inspectSource=function(r){return e(r)}),kt=n.inspectSource}function Ht(){if(Bt)return Mt;Bt=1;var r=at(),t=vt(),n=r("keys");return Mt=function(r){return n[r]||(n[r]=t(r))}}function Kt(){return Dt?zt:(Dt=1,zt={})}function Qt(){if(Nt)return Lt;Nt=1;var r,t,n,e=function(){if(Ct)return Rt;Ct=1;var r=b(),t=Er(),n=r.WeakMap;return Rt=t(n)&&/native code/.test(String(n))}(),o=b(),i=Tr(),u=At(),f=st(),c=ct(),a=Ht(),l=Kt(),s="Object already initialized",v=o.TypeError,p=o.WeakMap;if(e||c.state){var y=c.state||(c.state=new p);y.get=y.get,y.has=y.has,y.set=y.set,r=function(r,t){if(y.has(r))throw new v(s);return t.facade=r,y.set(r,t),t},t=function(r){return y.get(r)||{}},n=function(r){return y.has(r)}}else{var d=a("state");l[d]=!0,r=function(r,t){if(f(r,d))throw new v(s);return t.facade=r,u(r,d,t),t},t=function(r){return f(r,d)?r[d]:{}},n=function(r){return f(r,d)}}return Lt={set:r,get:t,has:n,enforce:function(e){return n(e)?t(e):r(e,{})},getterFor:function(r){return function(n){var e;if(!i(n)||(e=t(n)).type!==r)throw new v("Incompatible receiver, "+r+" required");return e}}}}function Vt(){if(qt)return Wt.exports;qt=1;var r=mr(),t=E(),n=Er(),e=st(),o=T(),i=function(){if(It)return _t;It=1;var r=T(),t=st(),n=Function.prototype,e=r&&Object.getOwnPropertyDescriptor,o=t(n,"name"),i=o&&"something"===function(){}.name,u=o&&(!r||r&&e(n,"name").configurable);return _t={EXISTS:o,PROPER:i,CONFIGURABLE:u}}().CONFIGURABLE,u=$t(),f=Qt(),c=f.enforce,a=f.get,l=String,s=Object.defineProperty,v=r("".slice),p=r("".replace),y=r([].join),b=o&&!t((function(){return 8!==s((function(){}),"length",{value:8}).length})),d=String(String).split("String"),h=Wt.exports=function(r,t,n){"Symbol("===v(l(t),0,7)&&(t="["+p(l(t),/^Symbol\(([^)]*)\).*$/,"$1")+"]"),n&&n.getter&&(t="get "+t),n&&n.setter&&(t="set "+t),(!e(r,"name")||i&&r.name!==t)&&(o?s(r,"name",{value:t,configurable:!0}):r.name=t),b&&n&&e(n,"arity")&&r.length!==n.arity&&s(r,"length",{value:n.arity});try{n&&e(n,"constructor")&&n.constructor?o&&s(r,"prototype",{writable:!1}):r.prototype&&(r.prototype=void 0)}catch(r){}var u=c(r);return e(u,"source")||(u.source=y(d,"string"==typeof t?t:"")),r};return Function.prototype.toString=h((function(){return n(this)&&a(this).source||u(this)}),"toString"),Wt.exports}function Xt(){if(Ut)return Gt;Ut=1;var r=Er(),t=Ft(),n=Vt(),e=ft();return Gt=function(o,i,u,f){f||(f={});var c=f.enumerable,a=void 0!==f.name?f.name:i;if(r(u)&&n(u,a,f),f.global)c?o[i]=u:e(i,u);else{try{f.unsafe?o[i]&&(c=!0):delete o[i]}catch(r){}c?o[i]=u:t.f(o,i,{value:u,enumerable:!1,configurable:!f.nonConfigurable,writable:!f.nonWritable})}return o}}var Yt,Jt,Zt,rn,tn,nn,en,on,un,fn,cn,an,ln,sn,vn,pn,yn,bn={};function dn(){if(rn)return Zt;rn=1;var r=function(){if(Jt)return Yt;Jt=1;var r=Math.ceil,t=Math.floor;return Yt=Math.trunc||function(n){var e=+n;return(e>0?t:r)(e)}}();return Zt=function(t){var n=+t;return n!=n||0===n?0:r(n)}}function hn(){if(nn)return tn;nn=1;var r=dn(),t=Math.max,n=Math.min;return tn=function(e,o){var i=r(e);return i<0?t(i+o,0):n(i,o)}}function gn(){if(on)return en;on=1;var r=dn(),t=Math.min;return en=function(n){var e=r(n);return e>0?t(e,9007199254740991):0}}function mn(){if(fn)return un;fn=1;var r=gn();return un=function(t){return r(t.length)}}function wn(){if(sn)return ln;sn=1;var r=mr(),t=st(),n=Pr(),e=function(){if(an)return cn;an=1;var r=Pr(),t=hn(),n=mn(),e=function(e){return function(o,i,u){var f=r(o),c=n(f);if(0===c)return!e&&-1;var a,l=t(u,c);if(e&&i!=i){for(;c>l;)if((a=f[l++])!=a)return!0}else for(;c>l;l++)if((e||l in f)&&f[l]===i)return e||l||0;return!e&&-1}};return cn={includes:e(!0),indexOf:e(!1)}}().indexOf,o=Kt(),i=r([].push);return ln=function(r,u){var f,c=n(r),a=0,l=[];for(f in c)!t(o,f)&&t(c,f)&&i(l,f);for(;u.length>a;)t(c,f=u[a++])&&(~e(l,f)||i(l,f));return l}}function jn(){return pn?vn:(pn=1,vn=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"])}var On,Sn,Pn,En,Tn,Fn,An,_n,In,kn,xn,Rn,Cn,Mn,Bn,zn,Dn,Ln,Nn,qn,Gn,Un,Wn,$n,Hn,Kn,Qn,Vn,Xn,Yn,Jn={};function Zn(){return On||(On=1,Jn.f=Object.getOwnPropertySymbols),Jn}function re(){if(Pn)return Sn;Pn=1;var r=Fr(),t=mr(),n=function(){if(yn)return bn;yn=1;var r=wn(),t=jn().concat("length","prototype");return bn.f=Object.getOwnPropertyNames||function(n){return r(n,t)},bn}(),e=Zn(),o=Tt(),i=t([].concat);return Sn=r("Reflect","ownKeys")||function(r){var t=n.f(o(r)),u=e.f;return u?i(t,u(r)):t}}function te(){if(Tn)return En;Tn=1;var r=st(),t=re(),n=ht(),e=Ft();return En=function(o,i,u){for(var f=t(i),c=e.f,a=n.f,l=0;l=51||!r((function(){var r=[];return(r.constructor={})[e]=function(){return{foo:1}},1!==r[t](Boolean).foo}))}}!function(){if(Yn)return y;Yn=1;var r=ne(),t=function(){if(Qn)return Kn;Qn=1;var r=ee(),t=mr(),n=jr(),e=lt(),o=mn(),i=ae(),u=t([].push),f=function(t){var f=1===t,c=2===t,a=3===t,l=4===t,s=6===t,v=7===t,p=5===t||s;return function(y,b,d,h){for(var g,m,w=e(y),j=n(w),O=o(j),S=r(b,d),P=0,E=h||i,T=f?E(y,O):c||v?E(y,0):void 0;O>P;P++)if((p||P in j)&&(m=S(g=j[P],P,w),t))if(f)T[P]=m;else if(m)switch(t){case 3:return!0;case 5:return g;case 6:return P;case 2:u(T,g)}else switch(t){case 4:return!1;case 7:u(T,g)}return s?-1:a||l?l:T}};return Kn={forEach:f(0),map:f(1),filter:f(2),some:f(3),every:f(4),find:f(5),findIndex:f(6),filterReject:f(7)}}().filter;r({target:"Array",proto:!0,forced:!le()("filter")},{filter:function(r){return t(this,r,arguments.length>1?arguments[1]:void 0)}})}();var se,ve,pe,ye={};function be(){if(ve)return se;ve=1;var r=E();return se=function(t,n){var e=[][t];return!!e&&r((function(){e.call(null,n||function(){return 1},1)}))}}!function(){if(pe)return ye;pe=1;var r=ne(),t=mr(),n=jr(),e=Pr(),o=be(),i=t([].join);r({target:"Array",proto:!0,forced:n!==Object||!o("join",",")},{join:function(r){return i(e(this),void 0===r?",":r)}})}();var de,he,ge,me,we,je={};function Oe(){if(he)return de;he=1;var r=wn(),t=jn();return de=Object.keys||function(n){return r(n,t)}}!function(){if(we)return je;we=1;var r=ne(),t=function(){if(me)return ge;me=1;var r=T(),t=mr(),n=A(),e=E(),o=Oe(),i=Zn(),u=hr(),f=lt(),c=jr(),a=Object.assign,l=Object.defineProperty,s=t([].concat);return ge=!a||e((function(){if(r&&1!==a({b:1},a(l({},"a",{enumerable:!0,get:function(){l(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var t={},n={},e=Symbol("assign detection"),i="abcdefghijklmnopqrst";return t[e]=7,i.split("").forEach((function(r){n[r]=r})),7!==a({},t)[e]||o(a({},n)).join("")!==i}))?function(t,e){for(var a=f(t),l=arguments.length,v=1,p=i.f,y=u.f;l>v;)for(var b,d=c(arguments[v++]),h=p?s(o(d),p(d)):o(d),g=h.length,m=0;g>m;)b=h[m++],r&&!n(y,d,b)||(a[b]=d[b]);return a}:a,ge}();r({target:"Object",stat:!0,arity:2,forced:Object.assign!==t},{assign:t})}();var Se,Pe,Ee,Te={};!function(){if(Ee)return Te;Ee=1;var r=ie(),t=Xt(),n=function(){if(Pe)return Se;Pe=1;var r=ie(),t=ue();return Se=r?{}.toString:function(){return"[object "+t(this)+"]"}}();r||t(Object.prototype,"toString",n,{unsafe:!0})}();var Fe=r.fn.bootstrapTable.utils;Object.assign(r.fn.bootstrapTable.defaults,{treeEnable:!1,treeShowField:null,idField:"id",parentIdField:"pid",rootParentId:null}),r.BootstrapTable=function(t){function i(){return function(r,t){if(!(r instanceof t))throw new TypeError("Cannot call a class as a function")}(this,i),n(this,i,arguments)}return function(r,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(t&&t.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),t&&c(r,t)}(i,t),e(i,[{key:"init",value:function(){this._rowStyle=this.options.rowStyle;for(var r=arguments.length,t=new Array(r),n=0;n (http://wenzhixin.net.cn/) + * @license MIT + */ + +!function(r,n){"object"==typeof exports&&"undefined"!=typeof module?n(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],n):n((r="undefined"!=typeof globalThis?globalThis:r||self).jQuery)}(this,(function(r){"use strict";var n,t,e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},o={};function u(){if(t)return n;t=1;var r=function(r){return r&&r.Math===Math&&r};return n=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof e&&e)||r("object"==typeof n&&n)||function(){return this}()||Function("return this")()}var i,f,c,a,l,s,v,p,g={};function y(){return f?i:(f=1,i=function(r){try{return!!r()}catch(r){return!0}})}function b(){if(a)return c;a=1;var r=y();return c=!r((function(){return 7!==Object.defineProperty({},1,{get:function(){return 7}})[1]}))}function h(){if(s)return l;s=1;var r=y();return l=!r((function(){var r=function(){}.bind();return"function"!=typeof r||r.hasOwnProperty("prototype")}))}function m(){if(p)return v;p=1;var r=h(),n=Function.prototype.call;return v=r?n.bind(n):function(){return n.apply(n,arguments)},v}var d,w,S,O,j,P,T,E,x,C,A,F,R,M,k,I,L,N,z,D,G,H,U,_,q,B,W,$,J,K,Q,V,X,Y,Z,rr,nr,tr,er,or,ur,ir={};function fr(){if(d)return ir;d=1;var r={}.propertyIsEnumerable,n=Object.getOwnPropertyDescriptor,t=n&&!r.call({1:2},1);return ir.f=t?function(r){var t=n(this,r);return!!t&&t.enumerable}:r,ir}function cr(){return S?w:(S=1,w=function(r,n){return{enumerable:!(1&r),configurable:!(2&r),writable:!(4&r),value:n}})}function ar(){if(j)return O;j=1;var r=h(),n=Function.prototype,t=n.call,e=r&&n.bind.bind(t,t);return O=r?e:function(r){return function(){return t.apply(r,arguments)}},O}function lr(){if(T)return P;T=1;var r=ar(),n=r({}.toString),t=r("".slice);return P=function(r){return t(n(r),8,-1)}}function sr(){if(x)return E;x=1;var r=ar(),n=y(),t=lr(),e=Object,o=r("".split);return E=n((function(){return!e("z").propertyIsEnumerable(0)}))?function(r){return"String"===t(r)?o(r,""):e(r)}:e}function vr(){return A?C:(A=1,C=function(r){return null==r})}function pr(){if(R)return F;R=1;var r=vr(),n=TypeError;return F=function(t){if(r(t))throw new n("Can't call method on "+t);return t}}function gr(){if(k)return M;k=1;var r=sr(),n=pr();return M=function(t){return r(n(t))}}function yr(){if(L)return I;L=1;var r="object"==typeof document&&document.all;return I=void 0===r&&void 0!==r?function(n){return"function"==typeof n||n===r}:function(r){return"function"==typeof r}}function br(){if(z)return N;z=1;var r=yr();return N=function(n){return"object"==typeof n?null!==n:r(n)}}function hr(){if(G)return D;G=1;var r=u(),n=yr();return D=function(t,e){return arguments.length<2?(o=r[t],n(o)?o:void 0):r[t]&&r[t][e];var o},D}function mr(){if(W)return B;W=1;var r,n,t=u(),e=function(){if(q)return _;q=1;var r=u().navigator,n=r&&r.userAgent;return _=n?String(n):""}(),o=t.process,i=t.Deno,f=o&&o.versions||i&&i.version,c=f&&f.v8;return c&&(n=(r=c.split("."))[0]>0&&r[0]<4?1:+(r[0]+r[1])),!n&&e&&(!(r=e.match(/Edge\/(\d+)/))||r[1]>=74)&&(r=e.match(/Chrome\/(\d+)/))&&(n=+r[1]),B=n}function dr(){if(J)return $;J=1;var r=mr(),n=y(),t=u().String;return $=!!Object.getOwnPropertySymbols&&!n((function(){var n=Symbol("symbol detection");return!t(n)||!(Object(n)instanceof Symbol)||!Symbol.sham&&r&&r<41}))}function wr(){if(Q)return K;Q=1;var r=dr();return K=r&&!Symbol.sham&&"symbol"==typeof Symbol.iterator}function Sr(){if(X)return V;X=1;var r=hr(),n=yr(),t=function(){if(U)return H;U=1;var r=ar();return H=r({}.isPrototypeOf)}(),e=wr(),o=Object;return V=e?function(r){return"symbol"==typeof r}:function(e){var u=r("Symbol");return n(u)&&t(u.prototype,o(e))}}function Or(){if(Z)return Y;Z=1;var r=String;return Y=function(n){try{return r(n)}catch(r){return"Object"}}}function jr(){if(nr)return rr;nr=1;var r=yr(),n=Or(),t=TypeError;return rr=function(e){if(r(e))return e;throw new t(n(e)+" is not a function")}}function Pr(){if(er)return tr;er=1;var r=jr(),n=vr();return tr=function(t,e){var o=t[e];return n(o)?void 0:r(o)}}function Tr(){if(ur)return or;ur=1;var r=m(),n=yr(),t=br(),e=TypeError;return or=function(o,u){var i,f;if("string"===u&&n(i=o.toString)&&!t(f=r(i,o)))return f;if(n(i=o.valueOf)&&!t(f=r(i,o)))return f;if("string"!==u&&n(i=o.toString)&&!t(f=r(i,o)))return f;throw new e("Can't convert object to primitive value")}}var Er,xr,Cr,Ar,Fr,Rr,Mr,kr,Ir,Lr,Nr,zr,Dr,Gr,Hr,Ur,_r,qr,Br,Wr,$r,Jr,Kr,Qr,Vr={exports:{}};function Xr(){if(Ar)return Cr;Ar=1;var r=u(),n=Object.defineProperty;return Cr=function(t,e){try{n(r,t,{value:e,configurable:!0,writable:!0})}catch(n){r[t]=e}return e}}function Yr(){if(Fr)return Vr.exports;Fr=1;var r=xr?Er:(xr=1,Er=!1),n=u(),t=Xr(),e="__core-js_shared__",o=Vr.exports=n[e]||t(e,{});return(o.versions||(o.versions=[])).push({version:"3.39.0",mode:r?"pure":"global",copyright:"© 2014-2024 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.39.0/LICENSE",source:"https://github.com/zloirock/core-js"}),Vr.exports}function Zr(){if(Mr)return Rr;Mr=1;var r=Yr();return Rr=function(n,t){return r[n]||(r[n]=t||{})}}function rn(){if(Ir)return kr;Ir=1;var r=pr(),n=Object;return kr=function(t){return n(r(t))}}function nn(){if(Nr)return Lr;Nr=1;var r=ar(),n=rn(),t=r({}.hasOwnProperty);return Lr=Object.hasOwn||function(r,e){return t(n(r),e)}}function tn(){if(Dr)return zr;Dr=1;var r=ar(),n=0,t=Math.random(),e=r(1..toString);return zr=function(r){return"Symbol("+(void 0===r?"":r)+")_"+e(++n+t,36)}}function en(){if(Hr)return Gr;Hr=1;var r=u(),n=Zr(),t=nn(),e=tn(),o=dr(),i=wr(),f=r.Symbol,c=n("wks"),a=i?f.for||f:f&&f.withoutSetter||e;return Gr=function(r){return t(c,r)||(c[r]=o&&t(f,r)?f[r]:a("Symbol."+r)),c[r]}}function on(){if(_r)return Ur;_r=1;var r=m(),n=br(),t=Sr(),e=Pr(),o=Tr(),u=en(),i=TypeError,f=u("toPrimitive");return Ur=function(u,c){if(!n(u)||t(u))return u;var a,l=e(u,f);if(l){if(void 0===c&&(c="default"),a=r(l,u,c),!n(a)||t(a))return a;throw new i("Can't convert object to primitive value")}return void 0===c&&(c="number"),o(u,c)}}function un(){if(Br)return qr;Br=1;var r=on(),n=Sr();return qr=function(t){var e=r(t,"string");return n(e)?e:e+""}}function fn(){if(Kr)return Jr;Kr=1;var r=b(),n=y(),t=function(){if($r)return Wr;$r=1;var r=u(),n=br(),t=r.document,e=n(t)&&n(t.createElement);return Wr=function(r){return e?t.createElement(r):{}}}();return Jr=!r&&!n((function(){return 7!==Object.defineProperty(t("div"),"a",{get:function(){return 7}}).a}))}function cn(){if(Qr)return g;Qr=1;var r=b(),n=m(),t=fr(),e=cr(),o=gr(),u=un(),i=nn(),f=fn(),c=Object.getOwnPropertyDescriptor;return g.f=r?c:function(r,a){if(r=o(r),a=u(a),f)try{return c(r,a)}catch(r){}if(i(r,a))return e(!n(t.f,r,a),r[a])},g}var an,ln,sn,vn,pn,gn,yn,bn={};function hn(){if(vn)return sn;vn=1;var r=br(),n=String,t=TypeError;return sn=function(e){if(r(e))return e;throw new t(n(e)+" is not an object")}}function mn(){if(pn)return bn;pn=1;var r=b(),n=fn(),t=function(){if(ln)return an;ln=1;var r=b(),n=y();return an=r&&n((function(){return 42!==Object.defineProperty((function(){}),"prototype",{value:42,writable:!1}).prototype}))}(),e=hn(),o=un(),u=TypeError,i=Object.defineProperty,f=Object.getOwnPropertyDescriptor,c="enumerable",a="configurable",l="writable";return bn.f=r?t?function(r,n,t){if(e(r),n=o(n),e(t),"function"==typeof r&&"prototype"===n&&"value"in t&&l in t&&!t[l]){var u=f(r,n);u&&u[l]&&(r[n]=t.value,t={configurable:a in t?t[a]:u[a],enumerable:c in t?t[c]:u[c],writable:!1})}return i(r,n,t)}:i:function(r,t,f){if(e(r),t=o(t),e(f),n)try{return i(r,t,f)}catch(r){}if("get"in f||"set"in f)throw new u("Accessors not supported");return"value"in f&&(r[t]=f.value),r},bn}function dn(){if(yn)return gn;yn=1;var r=b(),n=mn(),t=cr();return gn=r?function(r,e,o){return n.f(r,e,t(1,o))}:function(r,n,t){return r[n]=t,r}}var wn,Sn,On,jn,Pn,Tn,En,xn,Cn,An,Fn,Rn,Mn,kn,In,Ln={exports:{}};function Nn(){if(jn)return On;jn=1;var r=ar(),n=yr(),t=Yr(),e=r(Function.toString);return n(t.inspectSource)||(t.inspectSource=function(r){return e(r)}),On=t.inspectSource}function zn(){if(xn)return En;xn=1;var r=Zr(),n=tn(),t=r("keys");return En=function(r){return t[r]||(t[r]=n(r))}}function Dn(){return An?Cn:(An=1,Cn={})}function Gn(){if(Rn)return Fn;Rn=1;var r,n,t,e=function(){if(Tn)return Pn;Tn=1;var r=u(),n=yr(),t=r.WeakMap;return Pn=n(t)&&/native code/.test(String(t))}(),o=u(),i=br(),f=dn(),c=nn(),a=Yr(),l=zn(),s=Dn(),v="Object already initialized",p=o.TypeError,g=o.WeakMap;if(e||a.state){var y=a.state||(a.state=new g);y.get=y.get,y.has=y.has,y.set=y.set,r=function(r,n){if(y.has(r))throw new p(v);return n.facade=r,y.set(r,n),n},n=function(r){return y.get(r)||{}},t=function(r){return y.has(r)}}else{var b=l("state");s[b]=!0,r=function(r,n){if(c(r,b))throw new p(v);return n.facade=r,f(r,b,n),n},n=function(r){return c(r,b)?r[b]:{}},t=function(r){return c(r,b)}}return Fn={set:r,get:n,has:t,enforce:function(e){return t(e)?n(e):r(e,{})},getterFor:function(r){return function(t){var e;if(!i(t)||(e=n(t)).type!==r)throw new p("Incompatible receiver, "+r+" required");return e}}}}function Hn(){if(Mn)return Ln.exports;Mn=1;var r=ar(),n=y(),t=yr(),e=nn(),o=b(),u=function(){if(Sn)return wn;Sn=1;var r=b(),n=nn(),t=Function.prototype,e=r&&Object.getOwnPropertyDescriptor,o=n(t,"name"),u=o&&"something"===function(){}.name,i=o&&(!r||r&&e(t,"name").configurable);return wn={EXISTS:o,PROPER:u,CONFIGURABLE:i}}().CONFIGURABLE,i=Nn(),f=Gn(),c=f.enforce,a=f.get,l=String,s=Object.defineProperty,v=r("".slice),p=r("".replace),g=r([].join),h=o&&!n((function(){return 8!==s((function(){}),"length",{value:8}).length})),m=String(String).split("String"),d=Ln.exports=function(r,n,t){"Symbol("===v(l(n),0,7)&&(n="["+p(l(n),/^Symbol\(([^)]*)\).*$/,"$1")+"]"),t&&t.getter&&(n="get "+n),t&&t.setter&&(n="set "+n),(!e(r,"name")||u&&r.name!==n)&&(o?s(r,"name",{value:n,configurable:!0}):r.name=n),h&&t&&e(t,"arity")&&r.length!==t.arity&&s(r,"length",{value:t.arity});try{t&&e(t,"constructor")&&t.constructor?o&&s(r,"prototype",{writable:!1}):r.prototype&&(r.prototype=void 0)}catch(r){}var i=c(r);return e(i,"source")||(i.source=g(m,"string"==typeof n?n:"")),r};return Function.prototype.toString=d((function(){return t(this)&&a(this).source||i(this)}),"toString"),Ln.exports}function Un(){if(In)return kn;In=1;var r=yr(),n=mn(),t=Hn(),e=Xr();return kn=function(o,u,i,f){f||(f={});var c=f.enumerable,a=void 0!==f.name?f.name:u;if(r(i)&&t(i,a,f),f.global)c?o[u]=i:e(u,i);else{try{f.unsafe?o[u]&&(c=!0):delete o[u]}catch(r){}c?o[u]=i:n.f(o,u,{value:i,enumerable:!1,configurable:!f.nonConfigurable,writable:!f.nonWritable})}return o}}var _n,qn,Bn,Wn,$n,Jn,Kn,Qn,Vn,Xn,Yn,Zn,rt,nt,tt,et,ot,ut={};function it(){if(Wn)return Bn;Wn=1;var r=function(){if(qn)return _n;qn=1;var r=Math.ceil,n=Math.floor;return _n=Math.trunc||function(t){var e=+t;return(e>0?n:r)(e)}}();return Bn=function(n){var t=+n;return t!=t||0===t?0:r(t)}}function ft(){if(Jn)return $n;Jn=1;var r=it(),n=Math.max,t=Math.min;return $n=function(e,o){var u=r(e);return u<0?n(u+o,0):t(u,o)}}function ct(){if(Qn)return Kn;Qn=1;var r=it(),n=Math.min;return Kn=function(t){var e=r(t);return e>0?n(e,9007199254740991):0}}function at(){if(Xn)return Vn;Xn=1;var r=ct();return Vn=function(n){return r(n.length)}}function lt(){if(nt)return rt;nt=1;var r=ar(),n=nn(),t=gr(),e=function(){if(Zn)return Yn;Zn=1;var r=gr(),n=ft(),t=at(),e=function(e){return function(o,u,i){var f=r(o),c=t(f);if(0===c)return!e&&-1;var a,l=n(i,c);if(e&&u!=u){for(;c>l;)if((a=f[l++])!=a)return!0}else for(;c>l;l++)if((e||l in f)&&f[l]===u)return e||l||0;return!e&&-1}};return Yn={includes:e(!0),indexOf:e(!1)}}().indexOf,o=Dn(),u=r([].push);return rt=function(r,i){var f,c=t(r),a=0,l=[];for(f in c)!n(o,f)&&n(c,f)&&u(l,f);for(;i.length>a;)n(c,f=i[a++])&&(~e(l,f)||u(l,f));return l}}function st(){return et?tt:(et=1,tt=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"])}var vt,pt,gt,yt,bt,ht,mt,dt,wt,St,Ot,jt,Pt,Tt,Et,xt,Ct,At,Ft,Rt,Mt,kt,It,Lt,Nt,zt,Dt,Gt,Ht={};function Ut(){return vt||(vt=1,Ht.f=Object.getOwnPropertySymbols),Ht}function _t(){if(gt)return pt;gt=1;var r=hr(),n=ar(),t=function(){if(ot)return ut;ot=1;var r=lt(),n=st().concat("length","prototype");return ut.f=Object.getOwnPropertyNames||function(t){return r(t,n)},ut}(),e=Ut(),o=hn(),u=n([].concat);return pt=r("Reflect","ownKeys")||function(r){var n=t.f(o(r)),i=e.f;return i?u(n,i(r)):n}}function qt(){if(bt)return yt;bt=1;var r=nn(),n=_t(),t=cn(),e=mn();return yt=function(o,u,i){for(var f=n(u),c=e.f,a=t.f,l=0;l9007199254740991)throw r("Maximum allowed index exceeded");return n}}function Jt(){if(Et)return Tt;Et=1;var r=b(),n=mn(),t=cr();return Tt=function(e,o,u){r?n.f(e,o,t(0,u)):e[o]=u}}function Kt(){if(Ft)return At;Ft=1;var r=function(){if(Ct)return xt;Ct=1;var r={};return r[en()("toStringTag")]="z",xt="[object z]"===String(r)}(),n=yr(),t=lr(),e=en()("toStringTag"),o=Object,u="Arguments"===t(function(){return arguments}());return At=r?t:function(r){var i,f,c;return void 0===r?"Undefined":null===r?"Null":"string"==typeof(f=function(r,n){try{return r[n]}catch(r){}}(i=o(r),e))?f:u?t(i):"Object"===(c=t(i))&&n(i.callee)?"Arguments":c}}function Qt(){if(Mt)return Rt;Mt=1;var r=ar(),n=y(),t=yr(),e=Kt(),o=hr(),u=Nn(),i=function(){},f=o("Reflect","construct"),c=/^\s*(?:class|function)\b/,a=r(c.exec),l=!c.test(i),s=function(r){if(!t(r))return!1;try{return f(i,[],r),!0}catch(r){return!1}},v=function(r){if(!t(r))return!1;switch(e(r)){case"AsyncFunction":case"GeneratorFunction":case"AsyncGeneratorFunction":return!1}try{return l||!!a(c,u(r))}catch(r){return!0}};return v.sham=!0,Rt=!f||n((function(){var r;return s(s.call)||!s(Object)||!s((function(){r=!0}))||r}))?v:s}function Vt(){if(It)return kt;It=1;var r=Wt(),n=Qt(),t=br(),e=en()("species"),o=Array;return kt=function(u){var i;return r(u)&&(i=u.constructor,(n(i)&&(i===o||r(i.prototype))||t(i)&&null===(i=i[e]))&&(i=void 0)),void 0===i?o:i}}function Xt(){if(Nt)return Lt;Nt=1;var r=Vt();return Lt=function(n,t){return new(r(n))(0===t?0:t)}}function Yt(){if(Dt)return zt;Dt=1;var r=y(),n=en(),t=mr(),e=n("species");return zt=function(n){return t>=51||!r((function(){var r=[];return(r.constructor={})[e]=function(){return{foo:1}},1!==r[n](Boolean).foo}))}}!function(){if(Gt)return o;Gt=1;var r=Bt(),n=y(),t=Wt(),e=br(),u=rn(),i=at(),f=$t(),c=Jt(),a=Xt(),l=Yt(),s=en(),v=mr(),p=s("isConcatSpreadable"),g=v>=51||!n((function(){var r=[];return r[p]=!1,r.concat()[0]!==r})),b=function(r){if(!e(r))return!1;var n=r[p];return void 0!==n?!!n:t(r)};r({target:"Array",proto:!0,arity:1,forced:!g||!l("concat")},{concat:function(r){var n,t,e,o,l,s=u(this),v=a(s,0),p=0;for(n=-1,e=arguments.length;nv;)for(var y,b=c(arguments[v++]),h=p?s(o(b),p(b)):o(b),m=h.length,d=0;m>d;)y=h[d++],r&&!t(g,b,y)||(a[y]=b[y]);return a}:a,ne}();r({target:"Object",stat:!0,arity:2,forced:Object.assign!==n},{assign:n})}(),r.fn.bootstrapTable.locales["en-US"]=r.fn.bootstrapTable.locales.en={formatCopyRows:function(){return"Copy Rows"},formatPrint:function(){return"Print"},formatLoadingMessage:function(){return"Loading, please wait"},formatRecordsPerPage:function(r){return"".concat(r," rows per page")},formatShowingRows:function(r,n,t,e){return void 0!==e&&e>0&&e>t?"Showing ".concat(r," to ").concat(n," of ").concat(t," rows (filtered from ").concat(e," total rows)"):"Showing ".concat(r," to ").concat(n," of ").concat(t," rows")},formatSRPaginationPreText:function(){return"previous page"},formatSRPaginationPageText:function(r){return"to page ".concat(r)},formatSRPaginationNextText:function(){return"next page"},formatDetailPagination:function(r){return"Showing ".concat(r," rows")},formatClearSearch:function(){return"Clear Search"},formatSearch:function(){return"Search"},formatNoMatches:function(){return"No matching records found"},formatPaginationSwitch:function(){return"Hide/Show pagination"},formatPaginationSwitchDown:function(){return"Show pagination"},formatPaginationSwitchUp:function(){return"Hide pagination"},formatRefresh:function(){return"Refresh"},formatToggleOn:function(){return"Show card view"},formatToggleOff:function(){return"Hide card view"},formatColumns:function(){return"Columns"},formatColumnsToggleAll:function(){return"Toggle all"},formatFullscreen:function(){return"Fullscreen"},formatAllRows:function(){return"All"},formatAutoRefresh:function(){return"Auto Refresh"},formatExport:function(){return"Export data"},formatJumpTo:function(){return"GO"},formatAdvancedSearch:function(){return"Advanced search"},formatAdvancedCloseButton:function(){return"Close"},formatFilterControlSwitch:function(){return"Hide/Show controls"},formatFilterControlSwitchHide:function(){return"Hide controls"},formatFilterControlSwitchShow:function(){return"Show controls"}},Object.assign(r.fn.bootstrapTable.defaults,r.fn.bootstrapTable.locales["en-US"])})); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js new file mode 100644 index 000000000..ae4ff00e8 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js @@ -0,0 +1,10 @@ +/** + * bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation) + * + * @version v1.24.1 + * @homepage https://bootstrap-table.com + * @author wenzhixin (http://wenzhixin.net.cn/) + * @license MIT + */ + +!function(r,n){"object"==typeof exports&&"undefined"!=typeof module?n(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],n):n((r="undefined"!=typeof globalThis?globalThis:r||self).jQuery)}(this,(function(r){"use strict";var n,t,e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},o={};function u(){if(t)return n;t=1;var r=function(r){return r&&r.Math===Math&&r};return n=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof e&&e)||r("object"==typeof n&&n)||function(){return this}()||Function("return this")()}var i,f,c,a,l,s,v,p,y={};function b(){return f?i:(f=1,i=function(r){try{return!!r()}catch(r){return!0}})}function g(){if(a)return c;a=1;var r=b();return c=!r((function(){return 7!==Object.defineProperty({},1,{get:function(){return 7}})[1]}))}function h(){if(s)return l;s=1;var r=b();return l=!r((function(){var r=function(){}.bind();return"function"!=typeof r||r.hasOwnProperty("prototype")}))}function m(){if(p)return v;p=1;var r=h(),n=Function.prototype.call;return v=r?n.bind(n):function(){return n.apply(n,arguments)},v}var d,w,S,O,j,P,T,E,x,C,A,F,R,M,z,N,k,I,L,D,_,q,G,B,U,W,$,H,J,K,Q,V,X,Y,Z,rr,nr,tr,er,or,ur,ir={};function fr(){if(d)return ir;d=1;var r={}.propertyIsEnumerable,n=Object.getOwnPropertyDescriptor,t=n&&!r.call({1:2},1);return ir.f=t?function(r){var t=n(this,r);return!!t&&t.enumerable}:r,ir}function cr(){return S?w:(S=1,w=function(r,n){return{enumerable:!(1&r),configurable:!(2&r),writable:!(4&r),value:n}})}function ar(){if(j)return O;j=1;var r=h(),n=Function.prototype,t=n.call,e=r&&n.bind.bind(t,t);return O=r?e:function(r){return function(){return t.apply(r,arguments)}},O}function lr(){if(T)return P;T=1;var r=ar(),n=r({}.toString),t=r("".slice);return P=function(r){return t(n(r),8,-1)}}function sr(){if(x)return E;x=1;var r=ar(),n=b(),t=lr(),e=Object,o=r("".split);return E=n((function(){return!e("z").propertyIsEnumerable(0)}))?function(r){return"String"===t(r)?o(r,""):e(r)}:e}function vr(){return A?C:(A=1,C=function(r){return null==r})}function pr(){if(R)return F;R=1;var r=vr(),n=TypeError;return F=function(t){if(r(t))throw new n("Can't call method on "+t);return t}}function yr(){if(z)return M;z=1;var r=sr(),n=pr();return M=function(t){return r(n(t))}}function br(){if(k)return N;k=1;var r="object"==typeof document&&document.all;return N=void 0===r&&void 0!==r?function(n){return"function"==typeof n||n===r}:function(r){return"function"==typeof r}}function gr(){if(L)return I;L=1;var r=br();return I=function(n){return"object"==typeof n?null!==n:r(n)}}function hr(){if(_)return D;_=1;var r=u(),n=br();return D=function(t,e){return arguments.length<2?(o=r[t],n(o)?o:void 0):r[t]&&r[t][e];var o},D}function mr(){if($)return W;$=1;var r,n,t=u(),e=function(){if(U)return B;U=1;var r=u().navigator,n=r&&r.userAgent;return B=n?String(n):""}(),o=t.process,i=t.Deno,f=o&&o.versions||i&&i.version,c=f&&f.v8;return c&&(n=(r=c.split("."))[0]>0&&r[0]<4?1:+(r[0]+r[1])),!n&&e&&(!(r=e.match(/Edge\/(\d+)/))||r[1]>=74)&&(r=e.match(/Chrome\/(\d+)/))&&(n=+r[1]),W=n}function dr(){if(J)return H;J=1;var r=mr(),n=b(),t=u().String;return H=!!Object.getOwnPropertySymbols&&!n((function(){var n=Symbol("symbol detection");return!t(n)||!(Object(n)instanceof Symbol)||!Symbol.sham&&r&&r<41}))}function wr(){if(Q)return K;Q=1;var r=dr();return K=r&&!Symbol.sham&&"symbol"==typeof Symbol.iterator}function Sr(){if(X)return V;X=1;var r=hr(),n=br(),t=function(){if(G)return q;G=1;var r=ar();return q=r({}.isPrototypeOf)}(),e=wr(),o=Object;return V=e?function(r){return"symbol"==typeof r}:function(e){var u=r("Symbol");return n(u)&&t(u.prototype,o(e))}}function Or(){if(Z)return Y;Z=1;var r=String;return Y=function(n){try{return r(n)}catch(r){return"Object"}}}function jr(){if(nr)return rr;nr=1;var r=br(),n=Or(),t=TypeError;return rr=function(e){if(r(e))return e;throw new t(n(e)+" is not a function")}}function Pr(){if(er)return tr;er=1;var r=jr(),n=vr();return tr=function(t,e){var o=t[e];return n(o)?void 0:r(o)}}function Tr(){if(ur)return or;ur=1;var r=m(),n=br(),t=gr(),e=TypeError;return or=function(o,u){var i,f;if("string"===u&&n(i=o.toString)&&!t(f=r(i,o)))return f;if(n(i=o.valueOf)&&!t(f=r(i,o)))return f;if("string"!==u&&n(i=o.toString)&&!t(f=r(i,o)))return f;throw new e("Can't convert object to primitive value")}}var Er,xr,Cr,Ar,Fr,Rr,Mr,zr,Nr,kr,Ir,Lr,Dr,_r,qr,Gr,Br,Ur,Wr,$r,Hr,Jr,Kr,Qr,Vr={exports:{}};function Xr(){if(Ar)return Cr;Ar=1;var r=u(),n=Object.defineProperty;return Cr=function(t,e){try{n(r,t,{value:e,configurable:!0,writable:!0})}catch(n){r[t]=e}return e}}function Yr(){if(Fr)return Vr.exports;Fr=1;var r=xr?Er:(xr=1,Er=!1),n=u(),t=Xr(),e="__core-js_shared__",o=Vr.exports=n[e]||t(e,{});return(o.versions||(o.versions=[])).push({version:"3.39.0",mode:r?"pure":"global",copyright:"© 2014-2024 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.39.0/LICENSE",source:"https://github.com/zloirock/core-js"}),Vr.exports}function Zr(){if(Mr)return Rr;Mr=1;var r=Yr();return Rr=function(n,t){return r[n]||(r[n]=t||{})}}function rn(){if(Nr)return zr;Nr=1;var r=pr(),n=Object;return zr=function(t){return n(r(t))}}function nn(){if(Ir)return kr;Ir=1;var r=ar(),n=rn(),t=r({}.hasOwnProperty);return kr=Object.hasOwn||function(r,e){return t(n(r),e)}}function tn(){if(Dr)return Lr;Dr=1;var r=ar(),n=0,t=Math.random(),e=r(1..toString);return Lr=function(r){return"Symbol("+(void 0===r?"":r)+")_"+e(++n+t,36)}}function en(){if(qr)return _r;qr=1;var r=u(),n=Zr(),t=nn(),e=tn(),o=dr(),i=wr(),f=r.Symbol,c=n("wks"),a=i?f.for||f:f&&f.withoutSetter||e;return _r=function(r){return t(c,r)||(c[r]=o&&t(f,r)?f[r]:a("Symbol."+r)),c[r]}}function on(){if(Br)return Gr;Br=1;var r=m(),n=gr(),t=Sr(),e=Pr(),o=Tr(),u=en(),i=TypeError,f=u("toPrimitive");return Gr=function(u,c){if(!n(u)||t(u))return u;var a,l=e(u,f);if(l){if(void 0===c&&(c="default"),a=r(l,u,c),!n(a)||t(a))return a;throw new i("Can't convert object to primitive value")}return void 0===c&&(c="number"),o(u,c)}}function un(){if(Wr)return Ur;Wr=1;var r=on(),n=Sr();return Ur=function(t){var e=r(t,"string");return n(e)?e:e+""}}function fn(){if(Kr)return Jr;Kr=1;var r=g(),n=b(),t=function(){if(Hr)return $r;Hr=1;var r=u(),n=gr(),t=r.document,e=n(t)&&n(t.createElement);return $r=function(r){return e?t.createElement(r):{}}}();return Jr=!r&&!n((function(){return 7!==Object.defineProperty(t("div"),"a",{get:function(){return 7}}).a}))}function cn(){if(Qr)return y;Qr=1;var r=g(),n=m(),t=fr(),e=cr(),o=yr(),u=un(),i=nn(),f=fn(),c=Object.getOwnPropertyDescriptor;return y.f=r?c:function(r,a){if(r=o(r),a=u(a),f)try{return c(r,a)}catch(r){}if(i(r,a))return e(!n(t.f,r,a),r[a])},y}var an,ln,sn,vn,pn,yn,bn,gn={};function hn(){if(vn)return sn;vn=1;var r=gr(),n=String,t=TypeError;return sn=function(e){if(r(e))return e;throw new t(n(e)+" is not an object")}}function mn(){if(pn)return gn;pn=1;var r=g(),n=fn(),t=function(){if(ln)return an;ln=1;var r=g(),n=b();return an=r&&n((function(){return 42!==Object.defineProperty((function(){}),"prototype",{value:42,writable:!1}).prototype}))}(),e=hn(),o=un(),u=TypeError,i=Object.defineProperty,f=Object.getOwnPropertyDescriptor,c="enumerable",a="configurable",l="writable";return gn.f=r?t?function(r,n,t){if(e(r),n=o(n),e(t),"function"==typeof r&&"prototype"===n&&"value"in t&&l in t&&!t[l]){var u=f(r,n);u&&u[l]&&(r[n]=t.value,t={configurable:a in t?t[a]:u[a],enumerable:c in t?t[c]:u[c],writable:!1})}return i(r,n,t)}:i:function(r,t,f){if(e(r),t=o(t),e(f),n)try{return i(r,t,f)}catch(r){}if("get"in f||"set"in f)throw new u("Accessors not supported");return"value"in f&&(r[t]=f.value),r},gn}function dn(){if(bn)return yn;bn=1;var r=g(),n=mn(),t=cr();return yn=r?function(r,e,o){return n.f(r,e,t(1,o))}:function(r,n,t){return r[n]=t,r}}var wn,Sn,On,jn,Pn,Tn,En,xn,Cn,An,Fn,Rn,Mn,zn,Nn,kn={exports:{}};function In(){if(jn)return On;jn=1;var r=ar(),n=br(),t=Yr(),e=r(Function.toString);return n(t.inspectSource)||(t.inspectSource=function(r){return e(r)}),On=t.inspectSource}function Ln(){if(xn)return En;xn=1;var r=Zr(),n=tn(),t=r("keys");return En=function(r){return t[r]||(t[r]=n(r))}}function Dn(){return An?Cn:(An=1,Cn={})}function _n(){if(Rn)return Fn;Rn=1;var r,n,t,e=function(){if(Tn)return Pn;Tn=1;var r=u(),n=br(),t=r.WeakMap;return Pn=n(t)&&/native code/.test(String(t))}(),o=u(),i=gr(),f=dn(),c=nn(),a=Yr(),l=Ln(),s=Dn(),v="Object already initialized",p=o.TypeError,y=o.WeakMap;if(e||a.state){var b=a.state||(a.state=new y);b.get=b.get,b.has=b.has,b.set=b.set,r=function(r,n){if(b.has(r))throw new p(v);return n.facade=r,b.set(r,n),n},n=function(r){return b.get(r)||{}},t=function(r){return b.has(r)}}else{var g=l("state");s[g]=!0,r=function(r,n){if(c(r,g))throw new p(v);return n.facade=r,f(r,g,n),n},n=function(r){return c(r,g)?r[g]:{}},t=function(r){return c(r,g)}}return Fn={set:r,get:n,has:t,enforce:function(e){return t(e)?n(e):r(e,{})},getterFor:function(r){return function(t){var e;if(!i(t)||(e=n(t)).type!==r)throw new p("Incompatible receiver, "+r+" required");return e}}}}function qn(){if(Mn)return kn.exports;Mn=1;var r=ar(),n=b(),t=br(),e=nn(),o=g(),u=function(){if(Sn)return wn;Sn=1;var r=g(),n=nn(),t=Function.prototype,e=r&&Object.getOwnPropertyDescriptor,o=n(t,"name"),u=o&&"something"===function(){}.name,i=o&&(!r||r&&e(t,"name").configurable);return wn={EXISTS:o,PROPER:u,CONFIGURABLE:i}}().CONFIGURABLE,i=In(),f=_n(),c=f.enforce,a=f.get,l=String,s=Object.defineProperty,v=r("".slice),p=r("".replace),y=r([].join),h=o&&!n((function(){return 8!==s((function(){}),"length",{value:8}).length})),m=String(String).split("String"),d=kn.exports=function(r,n,t){"Symbol("===v(l(n),0,7)&&(n="["+p(l(n),/^Symbol\(([^)]*)\).*$/,"$1")+"]"),t&&t.getter&&(n="get "+n),t&&t.setter&&(n="set "+n),(!e(r,"name")||u&&r.name!==n)&&(o?s(r,"name",{value:n,configurable:!0}):r.name=n),h&&t&&e(t,"arity")&&r.length!==t.arity&&s(r,"length",{value:t.arity});try{t&&e(t,"constructor")&&t.constructor?o&&s(r,"prototype",{writable:!1}):r.prototype&&(r.prototype=void 0)}catch(r){}var i=c(r);return e(i,"source")||(i.source=y(m,"string"==typeof n?n:"")),r};return Function.prototype.toString=d((function(){return t(this)&&a(this).source||i(this)}),"toString"),kn.exports}function Gn(){if(Nn)return zn;Nn=1;var r=br(),n=mn(),t=qn(),e=Xr();return zn=function(o,u,i,f){f||(f={});var c=f.enumerable,a=void 0!==f.name?f.name:u;if(r(i)&&t(i,a,f),f.global)c?o[u]=i:e(u,i);else{try{f.unsafe?o[u]&&(c=!0):delete o[u]}catch(r){}c?o[u]=i:n.f(o,u,{value:i,enumerable:!1,configurable:!f.nonConfigurable,writable:!f.nonWritable})}return o}}var Bn,Un,Wn,$n,Hn,Jn,Kn,Qn,Vn,Xn,Yn,Zn,rt,nt,tt,et,ot,ut={};function it(){if($n)return Wn;$n=1;var r=function(){if(Un)return Bn;Un=1;var r=Math.ceil,n=Math.floor;return Bn=Math.trunc||function(t){var e=+t;return(e>0?n:r)(e)}}();return Wn=function(n){var t=+n;return t!=t||0===t?0:r(t)}}function ft(){if(Jn)return Hn;Jn=1;var r=it(),n=Math.max,t=Math.min;return Hn=function(e,o){var u=r(e);return u<0?n(u+o,0):t(u,o)}}function ct(){if(Qn)return Kn;Qn=1;var r=it(),n=Math.min;return Kn=function(t){var e=r(t);return e>0?n(e,9007199254740991):0}}function at(){if(Xn)return Vn;Xn=1;var r=ct();return Vn=function(n){return r(n.length)}}function lt(){if(nt)return rt;nt=1;var r=ar(),n=nn(),t=yr(),e=function(){if(Zn)return Yn;Zn=1;var r=yr(),n=ft(),t=at(),e=function(e){return function(o,u,i){var f=r(o),c=t(f);if(0===c)return!e&&-1;var a,l=n(i,c);if(e&&u!=u){for(;c>l;)if((a=f[l++])!=a)return!0}else for(;c>l;l++)if((e||l in f)&&f[l]===u)return e||l||0;return!e&&-1}};return Yn={includes:e(!0),indexOf:e(!1)}}().indexOf,o=Dn(),u=r([].push);return rt=function(r,i){var f,c=t(r),a=0,l=[];for(f in c)!n(o,f)&&n(c,f)&&u(l,f);for(;i.length>a;)n(c,f=i[a++])&&(~e(l,f)||u(l,f));return l}}function st(){return et?tt:(et=1,tt=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"])}var vt,pt,yt,bt,gt,ht,mt,dt,wt,St,Ot,jt,Pt,Tt,Et,xt,Ct,At,Ft,Rt,Mt,zt,Nt,kt,It,Lt,Dt,_t,qt={};function Gt(){return vt||(vt=1,qt.f=Object.getOwnPropertySymbols),qt}function Bt(){if(yt)return pt;yt=1;var r=hr(),n=ar(),t=function(){if(ot)return ut;ot=1;var r=lt(),n=st().concat("length","prototype");return ut.f=Object.getOwnPropertyNames||function(t){return r(t,n)},ut}(),e=Gt(),o=hn(),u=n([].concat);return pt=r("Reflect","ownKeys")||function(r){var n=t.f(o(r)),i=e.f;return i?u(n,i(r)):n}}function Ut(){if(gt)return bt;gt=1;var r=nn(),n=Bt(),t=cn(),e=mn();return bt=function(o,u,i){for(var f=n(u),c=e.f,a=t.f,l=0;l9007199254740991)throw r("Maximum allowed index exceeded");return n}}function Jt(){if(Et)return Tt;Et=1;var r=g(),n=mn(),t=cr();return Tt=function(e,o,u){r?n.f(e,o,t(0,u)):e[o]=u}}function Kt(){if(Ft)return At;Ft=1;var r=function(){if(Ct)return xt;Ct=1;var r={};return r[en()("toStringTag")]="z",xt="[object z]"===String(r)}(),n=br(),t=lr(),e=en()("toStringTag"),o=Object,u="Arguments"===t(function(){return arguments}());return At=r?t:function(r){var i,f,c;return void 0===r?"Undefined":null===r?"Null":"string"==typeof(f=function(r,n){try{return r[n]}catch(r){}}(i=o(r),e))?f:u?t(i):"Object"===(c=t(i))&&n(i.callee)?"Arguments":c}}function Qt(){if(Mt)return Rt;Mt=1;var r=ar(),n=b(),t=br(),e=Kt(),o=hr(),u=In(),i=function(){},f=o("Reflect","construct"),c=/^\s*(?:class|function)\b/,a=r(c.exec),l=!c.test(i),s=function(r){if(!t(r))return!1;try{return f(i,[],r),!0}catch(r){return!1}},v=function(r){if(!t(r))return!1;switch(e(r)){case"AsyncFunction":case"GeneratorFunction":case"AsyncGeneratorFunction":return!1}try{return l||!!a(c,u(r))}catch(r){return!0}};return v.sham=!0,Rt=!f||n((function(){var r;return s(s.call)||!s(Object)||!s((function(){r=!0}))||r}))?v:s}function Vt(){if(Nt)return zt;Nt=1;var r=$t(),n=Qt(),t=gr(),e=en()("species"),o=Array;return zt=function(u){var i;return r(u)&&(i=u.constructor,(n(i)&&(i===o||r(i.prototype))||t(i)&&null===(i=i[e]))&&(i=void 0)),void 0===i?o:i}}function Xt(){if(It)return kt;It=1;var r=Vt();return kt=function(n,t){return new(r(n))(0===t?0:t)}}function Yt(){if(Dt)return Lt;Dt=1;var r=b(),n=en(),t=mr(),e=n("species");return Lt=function(n){return t>=51||!r((function(){var r=[];return(r.constructor={})[e]=function(){return{foo:1}},1!==r[n](Boolean).foo}))}}!function(){if(_t)return o;_t=1;var r=Wt(),n=b(),t=$t(),e=gr(),u=rn(),i=at(),f=Ht(),c=Jt(),a=Xt(),l=Yt(),s=en(),v=mr(),p=s("isConcatSpreadable"),y=v>=51||!n((function(){var r=[];return r[p]=!1,r.concat()[0]!==r})),g=function(r){if(!e(r))return!1;var n=r[p];return void 0!==n?!!n:t(r)};r({target:"Array",proto:!0,arity:1,forced:!y||!l("concat")},{concat:function(r){var n,t,e,o,l,s=u(this),v=a(s,0),p=0;for(n=-1,e=arguments.length;nv;)for(var b,g=c(arguments[v++]),h=p?s(o(g),p(g)):o(g),m=h.length,d=0;m>d;)b=h[d++],r&&!t(y,g,b)||(a[b]=g[b]);return a}:a,ne}();r({target:"Object",stat:!0,arity:2,forced:Object.assign!==n},{assign:n})}(),r.fn.bootstrapTable.locales["zh-CN"]=r.fn.bootstrapTable.locales.zh={formatCopyRows:function(){return"复制行"},formatPrint:function(){return"打印"},formatLoadingMessage:function(){return"正在努力地加载数据中,请稍候"},formatRecordsPerPage:function(r){return"每页显示 ".concat(r," 条记录")},formatShowingRows:function(r,n,t,e){return void 0!==e&&e>0&&e>t?"显示第 ".concat(r," 到第 ").concat(n," 条记录,总共 ").concat(t," 条记录(从 ").concat(e," 总记录中过滤)"):"显示第 ".concat(r," 到第 ").concat(n," 条记录,总共 ").concat(t," 条记录")},formatSRPaginationPreText:function(){return"上一页"},formatSRPaginationPageText:function(r){return"第".concat(r,"页")},formatSRPaginationNextText:function(){return"下一页"},formatDetailPagination:function(r){return"总共 ".concat(r," 条记录")},formatClearSearch:function(){return"清空过滤"},formatSearch:function(){return"搜索"},formatNoMatches:function(){return"没有找到匹配的记录"},formatPaginationSwitch:function(){return"隐藏/显示分页"},formatPaginationSwitchDown:function(){return"显示分页"},formatPaginationSwitchUp:function(){return"隐藏分页"},formatRefresh:function(){return"刷新"},formatToggleOn:function(){return"显示卡片视图"},formatToggleOff:function(){return"隐藏卡片视图"},formatColumns:function(){return"列"},formatColumnsToggleAll:function(){return"切换所有"},formatFullscreen:function(){return"全屏"},formatAllRows:function(){return"所有"},formatAutoRefresh:function(){return"自动刷新"},formatExport:function(){return"导出数据"},formatJumpTo:function(){return"跳转"},formatAdvancedSearch:function(){return"高级搜索"},formatAdvancedCloseButton:function(){return"关闭"},formatFilterControlSwitch:function(){return"隐藏/显示过滤控制"},formatFilterControlSwitchHide:function(){return"隐藏过滤控制"},formatFilterControlSwitchShow:function(){return"显示过滤控制"}},Object.assign(r.fn.bootstrapTable.defaults,r.fn.bootstrapTable.locales["zh-CN"])})); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/bootstrap-table/locale/bootstrap-table-zh-TW.min.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/bootstrap-table/locale/bootstrap-table-zh-TW.min.js new file mode 100644 index 000000000..c7f6497d0 --- /dev/null +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/bootstrap-table/locale/bootstrap-table-zh-TW.min.js @@ -0,0 +1,10 @@ +/** + * bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation) + * + * @version v1.24.1 + * @homepage https://bootstrap-table.com + * @author wenzhixin (http://wenzhixin.net.cn/) + * @license MIT + */ + +!function(r,n){"object"==typeof exports&&"undefined"!=typeof module?n(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],n):n((r="undefined"!=typeof globalThis?globalThis:r||self).jQuery)}(this,(function(r){"use strict";var n,t,e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},o={};function u(){if(t)return n;t=1;var r=function(r){return r&&r.Math===Math&&r};return n=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof e&&e)||r("object"==typeof n&&n)||function(){return this}()||Function("return this")()}var i,f,c,a,l,s,v,p,y={};function b(){return f?i:(f=1,i=function(r){try{return!!r()}catch(r){return!0}})}function g(){if(a)return c;a=1;var r=b();return c=!r((function(){return 7!==Object.defineProperty({},1,{get:function(){return 7}})[1]}))}function m(){if(s)return l;s=1;var r=b();return l=!r((function(){var r=function(){}.bind();return"function"!=typeof r||r.hasOwnProperty("prototype")}))}function h(){if(p)return v;p=1;var r=m(),n=Function.prototype.call;return v=r?n.bind(n):function(){return n.apply(n,arguments)},v}var d,w,S,O,j,P,T,E,x,A,C,F,R,M,k,z,I,L,N,D,_,q,G,W,B,U,$,H,J,K,Q,V,X,Y,Z,rr,nr,tr,er,or,ur,ir={};function fr(){if(d)return ir;d=1;var r={}.propertyIsEnumerable,n=Object.getOwnPropertyDescriptor,t=n&&!r.call({1:2},1);return ir.f=t?function(r){var t=n(this,r);return!!t&&t.enumerable}:r,ir}function cr(){return S?w:(S=1,w=function(r,n){return{enumerable:!(1&r),configurable:!(2&r),writable:!(4&r),value:n}})}function ar(){if(j)return O;j=1;var r=m(),n=Function.prototype,t=n.call,e=r&&n.bind.bind(t,t);return O=r?e:function(r){return function(){return t.apply(r,arguments)}},O}function lr(){if(T)return P;T=1;var r=ar(),n=r({}.toString),t=r("".slice);return P=function(r){return t(n(r),8,-1)}}function sr(){if(x)return E;x=1;var r=ar(),n=b(),t=lr(),e=Object,o=r("".split);return E=n((function(){return!e("z").propertyIsEnumerable(0)}))?function(r){return"String"===t(r)?o(r,""):e(r)}:e}function vr(){return C?A:(C=1,A=function(r){return null==r})}function pr(){if(R)return F;R=1;var r=vr(),n=TypeError;return F=function(t){if(r(t))throw new n("Can't call method on "+t);return t}}function yr(){if(k)return M;k=1;var r=sr(),n=pr();return M=function(t){return r(n(t))}}function br(){if(I)return z;I=1;var r="object"==typeof document&&document.all;return z=void 0===r&&void 0!==r?function(n){return"function"==typeof n||n===r}:function(r){return"function"==typeof r}}function gr(){if(N)return L;N=1;var r=br();return L=function(n){return"object"==typeof n?null!==n:r(n)}}function mr(){if(_)return D;_=1;var r=u(),n=br();return D=function(t,e){return arguments.length<2?(o=r[t],n(o)?o:void 0):r[t]&&r[t][e];var o},D}function hr(){if($)return U;$=1;var r,n,t=u(),e=function(){if(B)return W;B=1;var r=u().navigator,n=r&&r.userAgent;return W=n?String(n):""}(),o=t.process,i=t.Deno,f=o&&o.versions||i&&i.version,c=f&&f.v8;return c&&(n=(r=c.split("."))[0]>0&&r[0]<4?1:+(r[0]+r[1])),!n&&e&&(!(r=e.match(/Edge\/(\d+)/))||r[1]>=74)&&(r=e.match(/Chrome\/(\d+)/))&&(n=+r[1]),U=n}function dr(){if(J)return H;J=1;var r=hr(),n=b(),t=u().String;return H=!!Object.getOwnPropertySymbols&&!n((function(){var n=Symbol("symbol detection");return!t(n)||!(Object(n)instanceof Symbol)||!Symbol.sham&&r&&r<41}))}function wr(){if(Q)return K;Q=1;var r=dr();return K=r&&!Symbol.sham&&"symbol"==typeof Symbol.iterator}function Sr(){if(X)return V;X=1;var r=mr(),n=br(),t=function(){if(G)return q;G=1;var r=ar();return q=r({}.isPrototypeOf)}(),e=wr(),o=Object;return V=e?function(r){return"symbol"==typeof r}:function(e){var u=r("Symbol");return n(u)&&t(u.prototype,o(e))}}function Or(){if(Z)return Y;Z=1;var r=String;return Y=function(n){try{return r(n)}catch(r){return"Object"}}}function jr(){if(nr)return rr;nr=1;var r=br(),n=Or(),t=TypeError;return rr=function(e){if(r(e))return e;throw new t(n(e)+" is not a function")}}function Pr(){if(er)return tr;er=1;var r=jr(),n=vr();return tr=function(t,e){var o=t[e];return n(o)?void 0:r(o)}}function Tr(){if(ur)return or;ur=1;var r=h(),n=br(),t=gr(),e=TypeError;return or=function(o,u){var i,f;if("string"===u&&n(i=o.toString)&&!t(f=r(i,o)))return f;if(n(i=o.valueOf)&&!t(f=r(i,o)))return f;if("string"!==u&&n(i=o.toString)&&!t(f=r(i,o)))return f;throw new e("Can't convert object to primitive value")}}var Er,xr,Ar,Cr,Fr,Rr,Mr,kr,zr,Ir,Lr,Nr,Dr,_r,qr,Gr,Wr,Br,Ur,$r,Hr,Jr,Kr,Qr,Vr={exports:{}};function Xr(){if(Cr)return Ar;Cr=1;var r=u(),n=Object.defineProperty;return Ar=function(t,e){try{n(r,t,{value:e,configurable:!0,writable:!0})}catch(n){r[t]=e}return e}}function Yr(){if(Fr)return Vr.exports;Fr=1;var r=xr?Er:(xr=1,Er=!1),n=u(),t=Xr(),e="__core-js_shared__",o=Vr.exports=n[e]||t(e,{});return(o.versions||(o.versions=[])).push({version:"3.39.0",mode:r?"pure":"global",copyright:"© 2014-2024 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.39.0/LICENSE",source:"https://github.com/zloirock/core-js"}),Vr.exports}function Zr(){if(Mr)return Rr;Mr=1;var r=Yr();return Rr=function(n,t){return r[n]||(r[n]=t||{})}}function rn(){if(zr)return kr;zr=1;var r=pr(),n=Object;return kr=function(t){return n(r(t))}}function nn(){if(Lr)return Ir;Lr=1;var r=ar(),n=rn(),t=r({}.hasOwnProperty);return Ir=Object.hasOwn||function(r,e){return t(n(r),e)}}function tn(){if(Dr)return Nr;Dr=1;var r=ar(),n=0,t=Math.random(),e=r(1..toString);return Nr=function(r){return"Symbol("+(void 0===r?"":r)+")_"+e(++n+t,36)}}function en(){if(qr)return _r;qr=1;var r=u(),n=Zr(),t=nn(),e=tn(),o=dr(),i=wr(),f=r.Symbol,c=n("wks"),a=i?f.for||f:f&&f.withoutSetter||e;return _r=function(r){return t(c,r)||(c[r]=o&&t(f,r)?f[r]:a("Symbol."+r)),c[r]}}function on(){if(Wr)return Gr;Wr=1;var r=h(),n=gr(),t=Sr(),e=Pr(),o=Tr(),u=en(),i=TypeError,f=u("toPrimitive");return Gr=function(u,c){if(!n(u)||t(u))return u;var a,l=e(u,f);if(l){if(void 0===c&&(c="default"),a=r(l,u,c),!n(a)||t(a))return a;throw new i("Can't convert object to primitive value")}return void 0===c&&(c="number"),o(u,c)}}function un(){if(Ur)return Br;Ur=1;var r=on(),n=Sr();return Br=function(t){var e=r(t,"string");return n(e)?e:e+""}}function fn(){if(Kr)return Jr;Kr=1;var r=g(),n=b(),t=function(){if(Hr)return $r;Hr=1;var r=u(),n=gr(),t=r.document,e=n(t)&&n(t.createElement);return $r=function(r){return e?t.createElement(r):{}}}();return Jr=!r&&!n((function(){return 7!==Object.defineProperty(t("div"),"a",{get:function(){return 7}}).a}))}function cn(){if(Qr)return y;Qr=1;var r=g(),n=h(),t=fr(),e=cr(),o=yr(),u=un(),i=nn(),f=fn(),c=Object.getOwnPropertyDescriptor;return y.f=r?c:function(r,a){if(r=o(r),a=u(a),f)try{return c(r,a)}catch(r){}if(i(r,a))return e(!n(t.f,r,a),r[a])},y}var an,ln,sn,vn,pn,yn,bn,gn={};function mn(){if(vn)return sn;vn=1;var r=gr(),n=String,t=TypeError;return sn=function(e){if(r(e))return e;throw new t(n(e)+" is not an object")}}function hn(){if(pn)return gn;pn=1;var r=g(),n=fn(),t=function(){if(ln)return an;ln=1;var r=g(),n=b();return an=r&&n((function(){return 42!==Object.defineProperty((function(){}),"prototype",{value:42,writable:!1}).prototype}))}(),e=mn(),o=un(),u=TypeError,i=Object.defineProperty,f=Object.getOwnPropertyDescriptor,c="enumerable",a="configurable",l="writable";return gn.f=r?t?function(r,n,t){if(e(r),n=o(n),e(t),"function"==typeof r&&"prototype"===n&&"value"in t&&l in t&&!t[l]){var u=f(r,n);u&&u[l]&&(r[n]=t.value,t={configurable:a in t?t[a]:u[a],enumerable:c in t?t[c]:u[c],writable:!1})}return i(r,n,t)}:i:function(r,t,f){if(e(r),t=o(t),e(f),n)try{return i(r,t,f)}catch(r){}if("get"in f||"set"in f)throw new u("Accessors not supported");return"value"in f&&(r[t]=f.value),r},gn}function dn(){if(bn)return yn;bn=1;var r=g(),n=hn(),t=cr();return yn=r?function(r,e,o){return n.f(r,e,t(1,o))}:function(r,n,t){return r[n]=t,r}}var wn,Sn,On,jn,Pn,Tn,En,xn,An,Cn,Fn,Rn,Mn,kn,zn,In={exports:{}};function Ln(){if(jn)return On;jn=1;var r=ar(),n=br(),t=Yr(),e=r(Function.toString);return n(t.inspectSource)||(t.inspectSource=function(r){return e(r)}),On=t.inspectSource}function Nn(){if(xn)return En;xn=1;var r=Zr(),n=tn(),t=r("keys");return En=function(r){return t[r]||(t[r]=n(r))}}function Dn(){return Cn?An:(Cn=1,An={})}function _n(){if(Rn)return Fn;Rn=1;var r,n,t,e=function(){if(Tn)return Pn;Tn=1;var r=u(),n=br(),t=r.WeakMap;return Pn=n(t)&&/native code/.test(String(t))}(),o=u(),i=gr(),f=dn(),c=nn(),a=Yr(),l=Nn(),s=Dn(),v="Object already initialized",p=o.TypeError,y=o.WeakMap;if(e||a.state){var b=a.state||(a.state=new y);b.get=b.get,b.has=b.has,b.set=b.set,r=function(r,n){if(b.has(r))throw new p(v);return n.facade=r,b.set(r,n),n},n=function(r){return b.get(r)||{}},t=function(r){return b.has(r)}}else{var g=l("state");s[g]=!0,r=function(r,n){if(c(r,g))throw new p(v);return n.facade=r,f(r,g,n),n},n=function(r){return c(r,g)?r[g]:{}},t=function(r){return c(r,g)}}return Fn={set:r,get:n,has:t,enforce:function(e){return t(e)?n(e):r(e,{})},getterFor:function(r){return function(t){var e;if(!i(t)||(e=n(t)).type!==r)throw new p("Incompatible receiver, "+r+" required");return e}}}}function qn(){if(Mn)return In.exports;Mn=1;var r=ar(),n=b(),t=br(),e=nn(),o=g(),u=function(){if(Sn)return wn;Sn=1;var r=g(),n=nn(),t=Function.prototype,e=r&&Object.getOwnPropertyDescriptor,o=n(t,"name"),u=o&&"something"===function(){}.name,i=o&&(!r||r&&e(t,"name").configurable);return wn={EXISTS:o,PROPER:u,CONFIGURABLE:i}}().CONFIGURABLE,i=Ln(),f=_n(),c=f.enforce,a=f.get,l=String,s=Object.defineProperty,v=r("".slice),p=r("".replace),y=r([].join),m=o&&!n((function(){return 8!==s((function(){}),"length",{value:8}).length})),h=String(String).split("String"),d=In.exports=function(r,n,t){"Symbol("===v(l(n),0,7)&&(n="["+p(l(n),/^Symbol\(([^)]*)\).*$/,"$1")+"]"),t&&t.getter&&(n="get "+n),t&&t.setter&&(n="set "+n),(!e(r,"name")||u&&r.name!==n)&&(o?s(r,"name",{value:n,configurable:!0}):r.name=n),m&&t&&e(t,"arity")&&r.length!==t.arity&&s(r,"length",{value:t.arity});try{t&&e(t,"constructor")&&t.constructor?o&&s(r,"prototype",{writable:!1}):r.prototype&&(r.prototype=void 0)}catch(r){}var i=c(r);return e(i,"source")||(i.source=y(h,"string"==typeof n?n:"")),r};return Function.prototype.toString=d((function(){return t(this)&&a(this).source||i(this)}),"toString"),In.exports}function Gn(){if(zn)return kn;zn=1;var r=br(),n=hn(),t=qn(),e=Xr();return kn=function(o,u,i,f){f||(f={});var c=f.enumerable,a=void 0!==f.name?f.name:u;if(r(i)&&t(i,a,f),f.global)c?o[u]=i:e(u,i);else{try{f.unsafe?o[u]&&(c=!0):delete o[u]}catch(r){}c?o[u]=i:n.f(o,u,{value:i,enumerable:!1,configurable:!f.nonConfigurable,writable:!f.nonWritable})}return o}}var Wn,Bn,Un,$n,Hn,Jn,Kn,Qn,Vn,Xn,Yn,Zn,rt,nt,tt,et,ot,ut={};function it(){if($n)return Un;$n=1;var r=function(){if(Bn)return Wn;Bn=1;var r=Math.ceil,n=Math.floor;return Wn=Math.trunc||function(t){var e=+t;return(e>0?n:r)(e)}}();return Un=function(n){var t=+n;return t!=t||0===t?0:r(t)}}function ft(){if(Jn)return Hn;Jn=1;var r=it(),n=Math.max,t=Math.min;return Hn=function(e,o){var u=r(e);return u<0?n(u+o,0):t(u,o)}}function ct(){if(Qn)return Kn;Qn=1;var r=it(),n=Math.min;return Kn=function(t){var e=r(t);return e>0?n(e,9007199254740991):0}}function at(){if(Xn)return Vn;Xn=1;var r=ct();return Vn=function(n){return r(n.length)}}function lt(){if(nt)return rt;nt=1;var r=ar(),n=nn(),t=yr(),e=function(){if(Zn)return Yn;Zn=1;var r=yr(),n=ft(),t=at(),e=function(e){return function(o,u,i){var f=r(o),c=t(f);if(0===c)return!e&&-1;var a,l=n(i,c);if(e&&u!=u){for(;c>l;)if((a=f[l++])!=a)return!0}else for(;c>l;l++)if((e||l in f)&&f[l]===u)return e||l||0;return!e&&-1}};return Yn={includes:e(!0),indexOf:e(!1)}}().indexOf,o=Dn(),u=r([].push);return rt=function(r,i){var f,c=t(r),a=0,l=[];for(f in c)!n(o,f)&&n(c,f)&&u(l,f);for(;i.length>a;)n(c,f=i[a++])&&(~e(l,f)||u(l,f));return l}}function st(){return et?tt:(et=1,tt=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"])}var vt,pt,yt,bt,gt,mt,ht,dt,wt,St,Ot,jt,Pt,Tt,Et,xt,At,Ct,Ft,Rt,Mt,kt,zt,It,Lt,Nt,Dt,_t,qt={};function Gt(){return vt||(vt=1,qt.f=Object.getOwnPropertySymbols),qt}function Wt(){if(yt)return pt;yt=1;var r=mr(),n=ar(),t=function(){if(ot)return ut;ot=1;var r=lt(),n=st().concat("length","prototype");return ut.f=Object.getOwnPropertyNames||function(t){return r(t,n)},ut}(),e=Gt(),o=mn(),u=n([].concat);return pt=r("Reflect","ownKeys")||function(r){var n=t.f(o(r)),i=e.f;return i?u(n,i(r)):n}}function Bt(){if(gt)return bt;gt=1;var r=nn(),n=Wt(),t=cn(),e=hn();return bt=function(o,u,i){for(var f=n(u),c=e.f,a=t.f,l=0;l9007199254740991)throw r("Maximum allowed index exceeded");return n}}function Jt(){if(Et)return Tt;Et=1;var r=g(),n=hn(),t=cr();return Tt=function(e,o,u){r?n.f(e,o,t(0,u)):e[o]=u}}function Kt(){if(Ft)return Ct;Ft=1;var r=function(){if(At)return xt;At=1;var r={};return r[en()("toStringTag")]="z",xt="[object z]"===String(r)}(),n=br(),t=lr(),e=en()("toStringTag"),o=Object,u="Arguments"===t(function(){return arguments}());return Ct=r?t:function(r){var i,f,c;return void 0===r?"Undefined":null===r?"Null":"string"==typeof(f=function(r,n){try{return r[n]}catch(r){}}(i=o(r),e))?f:u?t(i):"Object"===(c=t(i))&&n(i.callee)?"Arguments":c}}function Qt(){if(Mt)return Rt;Mt=1;var r=ar(),n=b(),t=br(),e=Kt(),o=mr(),u=Ln(),i=function(){},f=o("Reflect","construct"),c=/^\s*(?:class|function)\b/,a=r(c.exec),l=!c.test(i),s=function(r){if(!t(r))return!1;try{return f(i,[],r),!0}catch(r){return!1}},v=function(r){if(!t(r))return!1;switch(e(r)){case"AsyncFunction":case"GeneratorFunction":case"AsyncGeneratorFunction":return!1}try{return l||!!a(c,u(r))}catch(r){return!0}};return v.sham=!0,Rt=!f||n((function(){var r;return s(s.call)||!s(Object)||!s((function(){r=!0}))||r}))?v:s}function Vt(){if(zt)return kt;zt=1;var r=$t(),n=Qt(),t=gr(),e=en()("species"),o=Array;return kt=function(u){var i;return r(u)&&(i=u.constructor,(n(i)&&(i===o||r(i.prototype))||t(i)&&null===(i=i[e]))&&(i=void 0)),void 0===i?o:i}}function Xt(){if(Lt)return It;Lt=1;var r=Vt();return It=function(n,t){return new(r(n))(0===t?0:t)}}function Yt(){if(Dt)return Nt;Dt=1;var r=b(),n=en(),t=hr(),e=n("species");return Nt=function(n){return t>=51||!r((function(){var r=[];return(r.constructor={})[e]=function(){return{foo:1}},1!==r[n](Boolean).foo}))}}!function(){if(_t)return o;_t=1;var r=Ut(),n=b(),t=$t(),e=gr(),u=rn(),i=at(),f=Ht(),c=Jt(),a=Xt(),l=Yt(),s=en(),v=hr(),p=s("isConcatSpreadable"),y=v>=51||!n((function(){var r=[];return r[p]=!1,r.concat()[0]!==r})),g=function(r){if(!e(r))return!1;var n=r[p];return void 0!==n?!!n:t(r)};r({target:"Array",proto:!0,arity:1,forced:!y||!l("concat")},{concat:function(r){var n,t,e,o,l,s=u(this),v=a(s,0),p=0;for(n=-1,e=arguments.length;nv;)for(var b,g=c(arguments[v++]),m=p?s(o(g),p(g)):o(g),h=m.length,d=0;h>d;)b=m[d++],r&&!t(y,g,b)||(a[b]=g[b]);return a}:a,ne}();r({target:"Object",stat:!0,arity:2,forced:Object.assign!==n},{assign:n})}(),r.fn.bootstrapTable.locales["zh-TW"]={formatCopyRows:function(){return"複製行"},formatPrint:function(){return"列印"},formatLoadingMessage:function(){return"正在努力地載入資料,請稍候"},formatRecordsPerPage:function(r){return"每頁顯示 ".concat(r," 項記錄")},formatShowingRows:function(r,n,t,e){return void 0!==e&&e>0&&e>t?"顯示第 ".concat(r," 到第 ").concat(n," 項記錄,總共 ").concat(t," 項記錄(從 ").concat(e," 總記錄中過濾)"):"顯示第 ".concat(r," 到第 ").concat(n," 項記錄,總共 ").concat(t," 項記錄")},formatSRPaginationPreText:function(){return"上一頁"},formatSRPaginationPageText:function(r){return"第".concat(r,"頁")},formatSRPaginationNextText:function(){return"下一頁"},formatDetailPagination:function(r){return"總共 ".concat(r," 項記錄")},formatClearSearch:function(){return"清空過濾"},formatSearch:function(){return"搜尋"},formatNoMatches:function(){return"沒有找到符合的結果"},formatPaginationSwitch:function(){return"隱藏/顯示分頁"},formatPaginationSwitchDown:function(){return"顯示分頁"},formatPaginationSwitchUp:function(){return"隱藏分頁"},formatRefresh:function(){return"重新整理"},formatToggleOn:function(){return"顯示卡片視圖"},formatToggleOff:function(){return"隱藏卡片視圖"},formatColumns:function(){return"列"},formatColumnsToggleAll:function(){return"切換所有"},formatFullscreen:function(){return"全屏"},formatAllRows:function(){return"所有"},formatAutoRefresh:function(){return"自動刷新"},formatExport:function(){return"導出數據"},formatJumpTo:function(){return"跳轉"},formatAdvancedSearch:function(){return"高級搜尋"},formatAdvancedCloseButton:function(){return"關閉"},formatFilterControlSwitch:function(){return"隱藏/顯示過濾控制"},formatFilterControlSwitchHide:function(){return"隱藏過濾控制"},formatFilterControlSwitchShow:function(){return"顯示過濾控制"}},Object.assign(r.fn.bootstrapTable.defaults,r.fn.bootstrapTable.locales["zh-TW"])})); diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/cronGen/cronGen.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/cronGen/cronGen.js index 3922d7cd1..8e457da6d 100755 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/cronGen/cronGen.js +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/cronGen/cronGen.js @@ -650,7 +650,7 @@ dataType : "json", success : function(data){ if (data.code === 200) { - $('#runTime').val(data.content.join("\n")); + $('#runTime').val(data.data.join("\n")); } else { $('#runTime').val(data.msg); } diff --git a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/cronGen/cronGen_en.js b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/cronGen/cronGen_en.js index 0e2335d55..eb60022fd 100755 --- a/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/cronGen/cronGen_en.js +++ b/pigx-visual/pigx-xxl-job-admin/src/main/resources/static/plugins/cronGen/cronGen_en.js @@ -12,7 +12,7 @@ var cronContainer = $("
    ", { id: "CronContainer", style: "display:none;width:300px;height:300px;" }); var mainDiv = $("
    ", { id: "CronGenMainDiv", style: "width:410px;height:420px;" }); var topMenu = $("