feat: 普惠疗休养优化6
This commit is contained in:
@@ -18,6 +18,7 @@ import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.POST;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -145,6 +146,26 @@ public class SysTaskController {
|
||||
}
|
||||
}
|
||||
|
||||
@At("/runOnce/?")
|
||||
@POST
|
||||
@Ok("json")
|
||||
@SaCheckPermission("sys.manager.task.edit")
|
||||
@SLog(tag = "执行任务一次", msg = "任务名:${args[1].getAttribute('name')}")
|
||||
public Object runOnce(String id, HttpServletRequest req) {
|
||||
Sys_task task = sysTaskService.fetch(id);
|
||||
if (task == null) {
|
||||
return Result.error("任务不存在");
|
||||
}
|
||||
req.setAttribute("name", task.getName());
|
||||
try {
|
||||
taskPlatformService.runOnce(task);
|
||||
return Result.success("已提交执行");
|
||||
} catch (Exception e) {
|
||||
log.error("提交单次任务失败:" + task.getName(), e);
|
||||
return Result.error("提交执行失败");
|
||||
}
|
||||
}
|
||||
|
||||
@At("/enable/?")
|
||||
@Ok("json")
|
||||
@SaCheckPermission("sys.manager.task.edit")
|
||||
|
||||
@@ -1,62 +1,50 @@
|
||||
package com.budwk.app.task.job;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.param.ConditionGroup;
|
||||
import com.budwk.app.sys.enums.SysDataUpdateMode;
|
||||
import com.budwk.app.sys.models.Sys_user_source;
|
||||
import com.budwk.app.sys.param.SysDataUserUpdateParam;
|
||||
import com.budwk.app.sys.services.SysDataUserPullService;
|
||||
import com.budwk.app.sys.services.SysDataUserUpdateService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.Ioc;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.quartz.DisallowConcurrentExecution;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 人员全量更新任务
|
||||
*/
|
||||
@IocBean
|
||||
@Slf4j
|
||||
@DisallowConcurrentExecution
|
||||
public class SysUserAllRenewJob implements Job {
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject("refer:$ioc")
|
||||
private Ioc ioc;
|
||||
@Inject
|
||||
private SysDataUserPullService sysDataUserPullService;
|
||||
@Inject
|
||||
private SysDataUserUpdateService sysDataUserUpdateService;
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||
Date pullTime = sysDataUserPullService.pull();
|
||||
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
|
||||
NutMap conditionGroupMap = (NutMap)jobDataMap.get("conditionGroup");
|
||||
if(conditionGroupMap == null || conditionGroupMap.isEmpty()){
|
||||
log.error("SysUserAllRenewJob定时任务执行中止,原因:conditionGroup为null");
|
||||
}
|
||||
String conditionGroupStr = Json.toJson(conditionGroupMap).replace("@currentDate", DateUtil.today());
|
||||
ConditionGroup conditionGroup = null;
|
||||
try {
|
||||
conditionGroup = Json.fromJson(ConditionGroup.class, conditionGroupStr);
|
||||
SysDataUserUpdateParam param = new SysDataUserUpdateParam();
|
||||
param.setUpdateMode(SysDataUpdateMode.ALL.name());
|
||||
Object conditionGroup = jobExecutionContext.getMergedJobDataMap().get("conditionGroup");
|
||||
if (conditionGroup != null) {
|
||||
String conditionGroupJson = Json.toJson(conditionGroup).replace("@currentDate", DateUtil.today());
|
||||
param.setConditionGroup(Json.fromJson(ConditionGroup.class, conditionGroupJson));
|
||||
}
|
||||
|
||||
param.setPullTime(DateUtil.formatDateTime(sysDataUserPullService.pull()));
|
||||
SysDataUserUpdateService updateService = (SysDataUserUpdateService) ioc.get(SysDataUpdateMode.ALL.getClazz());
|
||||
log.info("人员全量更新任务,拉取批次 {}:{}", param.getPullTime(), updateService.update(param));
|
||||
} catch (Exception e) {
|
||||
log.error("SysUserAllRenewJob定时任务执行失败,原因:{}", e.getMessage());
|
||||
throw new JobExecutionException("人员拉取及全量更新任务执行失败", e);
|
||||
}
|
||||
|
||||
SysDataUserUpdateParam param = new SysDataUserUpdateParam();
|
||||
param.setPullTime(DateUtil.formatDateTime(pullTime));
|
||||
param.setUpdateMode(SysDataUpdateMode.ALL.name());
|
||||
param.setConditionGroup(conditionGroup);
|
||||
|
||||
// sysDataUserUpdateService.update(param);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.budwk.app.task.services;
|
||||
|
||||
import com.budwk.app.sys.models.Sys_task;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -15,6 +17,8 @@ public interface TaskPlatformService {
|
||||
*/
|
||||
boolean isExist(String jobName, String jobGroup);
|
||||
|
||||
void runOnce(Sys_task task) throws Exception;
|
||||
|
||||
/**
|
||||
* 添加新任务
|
||||
*
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
package com.budwk.app.task.services.impl;
|
||||
|
||||
import com.budwk.app.sys.models.Sys_task;
|
||||
import com.budwk.app.task.services.TaskPlatformService;
|
||||
import org.nutz.integration.quartz.QuartzJob;
|
||||
import org.nutz.integration.quartz.QuartzManager;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.quartz.CronExpression;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobBuilder;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.TriggerBuilder;
|
||||
import org.quartz.TriggerUtils;
|
||||
import org.quartz.impl.triggers.CronTriggerImpl;
|
||||
|
||||
@@ -23,6 +33,8 @@ import java.util.List;
|
||||
public class TaskPlatformServiceImpl implements TaskPlatformService {
|
||||
@Inject
|
||||
private QuartzManager quartzManager;
|
||||
@Inject
|
||||
private Scheduler scheduler;
|
||||
|
||||
/**
|
||||
* 判断任务是否存在
|
||||
@@ -35,6 +47,28 @@ public class TaskPlatformServiceImpl implements TaskPlatformService {
|
||||
return quartzManager.exist(new JobKey(jobName, jobGroup));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runOnce(Sys_task task) throws Exception {
|
||||
JobKey key = JobKey.jobKey(task.getId(), task.getId());
|
||||
if (scheduler.checkExists(key)) {
|
||||
scheduler.triggerJob(key);
|
||||
return;
|
||||
}
|
||||
|
||||
Class<? extends Job> jobClass = Class.forName(task.getJobClass()).asSubclass(Job.class);
|
||||
JobDataMap data = new JobDataMap();
|
||||
if (Strings.isNotBlank(task.getData())) {
|
||||
NutMap params = Json.fromJson(NutMap.class, task.getData());
|
||||
if (params != null) {
|
||||
data.putAll(params);
|
||||
}
|
||||
}
|
||||
|
||||
// 没有注册定时调度时,临时注册一个执行后自动移除的单次任务。
|
||||
JobDetail job = JobBuilder.newJob(jobClass).withIdentity(key).usingJobData(data).build();
|
||||
scheduler.scheduleJob(job, TriggerBuilder.newTrigger().forJob(key).startNow().build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加新任务
|
||||
*
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#v4-home-app .portal-top { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 18px; max-width: 1720px; margin: auto; padding: 18px 24px 0; }
|
||||
/* 使用完整不透明背景铺满横幅,会员信息独立成卡,不再覆盖校园景观。 */
|
||||
#v4-home-app .portal-hero { position: relative; min-width: 0; min-height: 260px; overflow: hidden; border-radius: 12px; background: #e8f4ff url('/assets/platform/img/home/service-portal-banner-campus-v4.png') no-repeat right bottom / cover; }
|
||||
#v4-home-app .portal-hero-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: right bottom; }
|
||||
#v4-home-app .portal-hero::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(90deg, #e8f4ff 0%, #e8f4ff 28%, rgba(232,244,255,.92) 39%, rgba(232,244,255,.35) 54%, rgba(232,244,255,0) 68%); }
|
||||
#v4-home-app .portal-hero-inner { position: relative; z-index: 1; display: flex; align-items: center; min-height: 260px; height: 100%; padding: 32px 40px; }
|
||||
#v4-home-app .portal-hero-copy { max-width: 80%; }
|
||||
|
||||
@@ -118,12 +118,14 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
|
||||
</style>
|
||||
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/css/home-portal.css?v=20260929-1" />
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/css/home-portal.css?v=20261111-1" />
|
||||
|
||||
<div class="v4-container home-portal" id="v4-home-app">
|
||||
<!-- 首页banner -->
|
||||
<div class="portal-top">
|
||||
<div class="portal-hero">
|
||||
<img v-if="portalHeroImage" class="portal-hero-bg" :src="portalHeroImage" alt=""
|
||||
@error="portalHeroImage = ''">
|
||||
<div class="portal-hero-inner">
|
||||
<div class="portal-hero-copy">
|
||||
<div class="portal-hero-eyebrow">教职工一站式服务平台</div>
|
||||
@@ -181,7 +183,7 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
data(){
|
||||
return{
|
||||
websiteNews: [],
|
||||
homeBannerList: "${config.AppHomeImg!}".split(",").map(item => item.trim()).filter(item => item)
|
||||
portalHeroImage: ""
|
||||
}
|
||||
},
|
||||
components: {
|
||||
@@ -193,9 +195,19 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
'stats': stats,
|
||||
},
|
||||
mounted() {
|
||||
this.getPortalHeroImage()
|
||||
this.getWebSiteNews()
|
||||
},
|
||||
methods: {
|
||||
getPortalHeroImage() {
|
||||
this.$axios.post("/open/common/getConfigKey", { key: "AppHomeImg" }).then(res => {
|
||||
if (res.code === 0 && typeof res.data === "string") {
|
||||
this.portalHeroImage = res.data.split(",").map(item => item.trim()).find(item => item) || ""
|
||||
}
|
||||
}).catch(() => {
|
||||
this.portalHeroImage = ""
|
||||
})
|
||||
},
|
||||
getWebSiteNews(){
|
||||
this.$axios.post('/platform/home/getNews').then(res => {
|
||||
if (res.code === 0) {
|
||||
|
||||
@@ -85,9 +85,24 @@ layout("/layouts/platform.html"){
|
||||
<el-input maxlength="100" placeholder="参数名" v-model="formData.configKey" auto-complete="off"
|
||||
tabindex="1" type="text"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="configValue" label="参数值">
|
||||
<el-input maxlength="100" placeholder="参数值" v-model="formData.configValue" auto-complete="off"
|
||||
tabindex="2" type="text"></el-input>
|
||||
<el-form-item v-if="addDialogVisible" prop="configValue" label="参数值">
|
||||
<div>
|
||||
<el-radio-group :value="configValueMode" @input="changeConfigValueMode">
|
||||
<el-radio label="text">文本</el-radio>
|
||||
<el-radio label="image">图片</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<file-upload
|
||||
v-if="configValueMode === 'image'"
|
||||
style="--upload-width: 214px;--upload-height:110px"
|
||||
:value.sync="formData.configValue"
|
||||
:upload_number="1"
|
||||
upload_mode="image"
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
<el-input v-else maxlength="100" placeholder="参数值" v-model="formData.configValue"
|
||||
auto-complete="off" tabindex="2" type="text"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="note" label="说 明">
|
||||
<el-input type="textarea" v-model="formData.note"></el-input>
|
||||
@@ -111,7 +126,7 @@ layout("/layouts/platform.html"){
|
||||
disabled
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="configValue" label="参数值">
|
||||
<el-form-item v-if="editDialogVisible" prop="configValue" label="参数值">
|
||||
<template v-if="formData.configKey === 'AppLogo'">
|
||||
<file-upload
|
||||
key="AppLogo"
|
||||
@@ -197,7 +212,22 @@ layout("/layouts/platform.html"){
|
||||
<span>教代会代表证背景图片,通过文件上传配置</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div v-if="'true'===formData.configValue||'false'===formData.configValue">
|
||||
<div>
|
||||
<el-radio-group :value="configValueMode" @input="changeConfigValueMode">
|
||||
<el-radio label="text">文本</el-radio>
|
||||
<el-radio label="image">图片</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<file-upload
|
||||
v-if="configValueMode === 'image'"
|
||||
style="--upload-width: 214px;--upload-height:110px"
|
||||
:value.sync="formData.configValue"
|
||||
:upload_number="1"
|
||||
upload_mode="image"
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
<div v-else-if="'true'===formData.configValue||'false'===formData.configValue">
|
||||
<el-radio-group v-model="formData.configValue">
|
||||
<el-radio label="true">是</el-radio>
|
||||
<el-radio label="false">否</el-radio>
|
||||
@@ -237,6 +267,8 @@ layout("/layouts/platform.html"){
|
||||
tableResizeObserver: null,
|
||||
pageRequestSequence: 0,
|
||||
tableData: [],
|
||||
configValueMode: "text",
|
||||
alternateConfigValue: "",
|
||||
pageForm: {
|
||||
pageSize: 10,
|
||||
pageNumber: 1,
|
||||
@@ -263,7 +295,20 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
openAdd: function () {
|
||||
this.addDialogVisible = true
|
||||
this.formData = {} //打开新增窗口,表单先清空
|
||||
this.formData = {configKey: "", configValue: "", note: ""} //打开新增窗口,表单先清空
|
||||
this.configValueMode = "text"
|
||||
this.alternateConfigValue = ""
|
||||
},
|
||||
changeConfigValueMode: function (mode) {
|
||||
if (mode === this.configValueMode) {
|
||||
return
|
||||
}
|
||||
var currentValue = this.formData.configValue
|
||||
this.formData.configValue = this.alternateConfigValue
|
||||
this.alternateConfigValue = currentValue
|
||||
this.configValueMode = mode
|
||||
var form = this.editDialogVisible ? this.$refs.editForm : this.$refs.addForm
|
||||
form.clearValidate("configValue")
|
||||
},
|
||||
doAdd: function () {
|
||||
var self = this
|
||||
@@ -440,6 +485,9 @@ layout("/layouts/platform.html"){
|
||||
function (data) {
|
||||
if (data.code == 0) {
|
||||
self.formData = data.data //加载后台表单数据
|
||||
self.configValueMode = /^\/platform\/sys\/file\/download\?id=[a-z0-9]+$/i
|
||||
.test(self.formData.configValue || "") ? "image" : "text"
|
||||
self.alternateConfigValue = ""
|
||||
self.editDialogVisible = true //打开编辑窗口
|
||||
} else {
|
||||
self.$message({
|
||||
|
||||
@@ -34,6 +34,9 @@ layout("/layouts/platform.html"){
|
||||
<span class="ti-angle-down"></span>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item v-if="$auth.hasPermission('sys.manager.task.edit')"
|
||||
:disabled="runningOnce[scope.row.id]"
|
||||
:command="{type:'runOnce',id:scope.row.id}">执行一次</el-dropdown-item>
|
||||
<el-dropdown-item :command="{type:'enable',id:scope.row.id,name:scope.row.name,row:scope.row}">启用</el-dropdown-item>
|
||||
<el-dropdown-item :command="{type:'disable',id:scope.row.id,name:scope.row.name,row:scope.row}">
|
||||
禁用
|
||||
@@ -112,6 +115,7 @@ layout("/layouts/platform.html"){
|
||||
addDialogVisible: false,
|
||||
editDialogVisible: false,
|
||||
tableData: [],
|
||||
runningOnce: {},
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
@@ -264,6 +268,19 @@ layout("/layouts/platform.html"){
|
||||
"json"
|
||||
)
|
||||
}
|
||||
if ("runOnce" == command.type && !self.runningOnce[command.id]) {
|
||||
self.$set(self.runningOnce, command.id, true)
|
||||
$.post(base + "/platform/sys/task/runOnce/" + command.id, {}, function (data) {
|
||||
self.$message({
|
||||
message: data.msg,
|
||||
type: data.code == 0 ? "success" : "error"
|
||||
})
|
||||
}, "json").fail(function () {
|
||||
self.$message.error("提交执行失败")
|
||||
}).always(function () {
|
||||
self.$delete(self.runningOnce, command.id)
|
||||
})
|
||||
}
|
||||
if ("edit" == command.type) {
|
||||
$.post(
|
||||
base + "/platform/sys/task/edit/" + command.id,
|
||||
|
||||
@@ -9,7 +9,8 @@ const home = {
|
||||
<span class="home-summary-bar__title">智慧工会</span>
|
||||
</div>
|
||||
<div ref="homeHero" class="home-hero">
|
||||
<img class="home-hero__bg" src="/assets/mobile/img/home/v4/hero-campus.png" alt="">
|
||||
<img class="home-hero__bg" :src="homeHeroImage || '/assets/mobile/img/home/v4/hero-campus.png'" alt=""
|
||||
@error="homeHeroImage = ''">
|
||||
<div class="home-hero__color-layer" aria-hidden="true"></div>
|
||||
<div class="home-hero__content">
|
||||
<div class="home-hero__topbar">
|
||||
@@ -287,6 +288,7 @@ const home = {
|
||||
],
|
||||
appLogo: "",
|
||||
appName: "",
|
||||
homeHeroImage: "",
|
||||
activeBannerIndex: 0,
|
||||
bannerLoadSeq: 0,
|
||||
bannerImageCache: {},
|
||||
@@ -610,6 +612,10 @@ const home = {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getConfigValue("H5AppHomeImg").then(value => {
|
||||
const hero = this.parseBannerList(value)[0]
|
||||
this.homeHeroImage = hero ? hero.src : ""
|
||||
})
|
||||
this.listHomeBrand()
|
||||
this.listRecommendApp()
|
||||
this.listClassroomCourses()
|
||||
|
||||
Reference in New Issue
Block a user