This commit is contained in:
2026-03-08 13:45:51 +08:00
27 changed files with 926 additions and 249 deletions
@@ -2,38 +2,138 @@ package com.budwk.app.base.sms;
import java.util.List;
/**
* 短信/消息发送服务接口
* 保持参数直观可见,调用者无需查看实体类即可知晓参数含义
*/
public interface SmsService {
/**
* 单发
* @param loginName 工号
* @param content 内容
*/
void send(String loginName, String content);
/**
* 单发普通消息(无标题)
* @param loginName 接收人工号(必填)
* @param content 消息内容(必填)
* @return
*/
void sendSingleMessage(String loginName, String content);
/**
* 单发
* @param loginName 工号
* @param title 标题
* @param content 内容
*/
void send(String loginName, String title, String content);
/**
* 单发普通消息(带标题)
* @param loginName 接收人工号(必填)
* @param title 消息标题(可选,可为null
* @param content 消息内容(必填)
* @return
*/
void sendSingleMessage(String loginName, String title, String content);
/**
* 单发
* @param loginName 工号
* @param title 标题
* @param content 内容
* @param link 链接
*/
void send(String loginName, String title, String content, String link);
/**
* 单发文本卡片消息
* @param loginName 接收人工号(必填)
* @param content 卡片内容(必填)
* @param pcUrl PC端跳转链接(必填)
* @param mobileUrl 移动端跳转链接(必填)
* @return
*/
void sendSingleTextCard(String loginName, String content, String pcUrl, String mobileUrl);
/**
* 群发 多人接收内容相同时使用该方法
* @param loginNames 工号
* @param title 标题
* @param content 内容
* @param link 链接
*/
void massSend(List<String> loginNames, String title, String content, String link);
/**
* 单发文本卡片消息(带标题)
* @param loginName 接收人工号(必填)
* @param title 卡片标题(可选,可为null
* @param content 卡片内容(必填)
* @param pcUrl PC端跳转链接(必填)
* @param mobileUrl 移动端跳转链接(必填)
* @return
*/
void sendSingleTextCard(String loginName, String title, String content, String pcUrl, String mobileUrl);
/**
* 单发图文卡片消息
* @param loginName 接收人工号(必填)
* @param content 卡片内容(必填)
* @param pcUrl PC端跳转链接(必填)
* @param mobileUrl 移动端跳转链接(必填)
* @param picUrl 图片链接(必填)
* @return
*/
void sendSinglePicTextCard(String loginName, String content, String pcUrl, String mobileUrl, String picUrl);
/**
* 单发图文卡片消息(带标题)
* @param loginName 接收人工号(必填)
* @param title 卡片标题(可选,可为null)
* @param content 卡片内容(必填)
* @param pcUrl PC端跳转链接(必填)
* @param mobileUrl 移动端跳转链接(必填)
* @param picUrl 图片链接(必填)
* @return
*/
void sendSinglePicTextCard(String loginName, String title, String content, String pcUrl, String mobileUrl, String picUrl);
/**
* 群发普通消息(多人接收相同内容)
* @param loginNames 接收人工号列表(必填,不能为空列表)
* @param content 消息内容(必填)
* @return void
*/
void massSendMessage(List<String> loginNames, String content);
/**
* 群发普通消息(多人接收相同内容)
* @param loginNames 接收人工号列表(必填,不能为空列表)
* @param title 消息标题(可选,可为null)
* @param content 消息内容(必填)
* @return void
*/
void massSendMessage(List<String> loginNames, String title, String content);
/**
* 群发短信文本卡片消息
* @param loginNames 接收人工号列表(必填,不能为空列表)
* @param content 卡片内容(必填)
* @param pcUrl PC端跳转链接(必填)
* @param mobileUrl 移动端跳转链接(必填)
* @return
*/
void massSendTextCard(List<String> loginNames, String content, String pcUrl, String mobileUrl);
/**
* 群发短信文本卡片消息
* @param loginNames 接收人工号列表(必填,不能为空列表)
* @param title 卡片标题(可选,可为null)
* @param content 卡片内容(必填)
* @param pcUrl PC端跳转链接(必填)
* @param mobileUrl 移动端跳转链接(必填)
* @return
*/
void massSendTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl);
/**
* 群发图文卡片消息
* @param loginNames 接收人工号列表(必填,不能为空列表)
* @param content 卡片内容(必填)
* @param pcUrl PC端跳转链接(必填)
* @param mobileUrl 移动端跳转链接(必填)
* @param picUrl 图片链接(必填)
* @return
*/
void massSendPicTextCard(List<String> loginNames, String content, String pcUrl, String mobileUrl, String picUrl);
/**
* 群发图文卡片消息
* @param loginNames 接收人工号列表(必填,不能为空列表)
* @param title 卡片标题(可选,可为null)
* @param content 卡片内容(必填)
* @param pcUrl PC端跳转链接(必填)
* @param mobileUrl 移动端跳转链接(必填)
* @param picUrl 图片链接(必填)
* @return
*/
void massSendPicTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl, String picUrl);
/**
* 消息撤回
* @param msgId 消息Id
* @return
*/
void recallMsg(String msgId);
}
@@ -1,21 +1,23 @@
package com.budwk.app.base.sms.impl.jshvc;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.budwk.app.base.sms.SmsService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.todo.platform.TodoPlatformConfig;
import com.wisedu.casp.sdk.api.mc.ReceiverDto;
import com.wisedu.casp.sdk.api.mc.SendMsgRequest;
import com.wisedu.casp.sdk.api.mc.SendMsgResponse;
import com.wisedu.casp.sdk.api.mc.constants.MsgType_Constants;
import com.wisedu.casp.sdk.api.mc.constants.SendType_Constants;
import com.wisedu.casp.sdk.api.mc.constants.WxSendType_Constants;
import com.wisedu.casp.sdk.api.mc.recallMsg.RecallMsgRequest;
import com.wisedu.casp.sdk.api.mc.recallMsg.RecallMsgResponse;
import com.wisedu.casp.sdk.core.Client;
import com.wisedu.casp.sdk.core.DefaultClient;
import lombok.extern.slf4j.Slf4j;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import java.util.List;
import java.util.Map;
/**
* @ClassName SmsJshvcServiceImpl
@@ -28,128 +30,144 @@ import java.util.Map;
@IocBean
public class SmsJshvcServiceImpl implements SmsService {
private static final String APPID = "1430576717768122368";
private static final String APP_SECRET = "19A0ACB03FBQHL4R4XQD";
private static final String TOKEN_URL = "https://gateway.jshvc.edu.cn/token/gateway/accessToken";
private static final String MSG_URL = "https://gateway.jshvc.edu.cn/mp/restful/v2/message/send";
private static final String REDIS_KEY_MSG_ACCESS_TOKEN = "msg:token:";
@Inject
private RedisService redisService;
@Override
public void send(String loginName, String content) {
send(loginName, "智慧工会", content);
public void sendSingleMessage(String loginName, String content) {
this.sendSingleMessage(loginName, "智慧工会", content);
}
@Override
public void send(String loginName, String title, String content) {
send(loginName, "智慧工会", content, null);
public void sendSingleMessage(String loginName, String title, String content) {
this.massSendMessage(List.of(loginName), title, content);
}
@Override
public void send(String loginName, String title, String content, String link) {
Map<String, String> paramMap = Map.of("userId", loginName);
doSend(title, content, List.of(paramMap), link);
public void sendSingleTextCard(String loginName, String content, String pcUrl, String mobileUrl) {
this.sendSingleTextCard(loginName, "智慧工会", content, pcUrl, mobileUrl);
}
@Override
public void massSend(List<String> loginNames, String title, String content, String link) {
List<Map<String, String>> receivers = loginNames.stream()
.map(name -> Map.of("userId", name))
.toList();
doSend(title, content, receivers, link);
public void sendSingleTextCard(String loginName, String title, String content, String pcUrl, String mobileUrl) {
this.massSendTextCard(List.of(loginName), title, content, pcUrl, mobileUrl);
}
/**
* sign: 请求签名:accessToken + 第一个receivers 的userID )的32位小写的MD5加密值,其中如果相应部分没有则忽略
* msgType: 0: 普通消息(默认) 1: 必读消息 2: 验证码(为验证码时消息一定不入收件箱)
* expiredTime: 当msgType 为1必读消息 ,该字段为必填字段 格式:yyyy-MM-dd HH:mm:ss
* sendType: 1.只发送PC门户 2.只发送移动校园 3.邮件 4.短信 5.微信企业号 6.钉钉企业内部应用工作通知 7.微信服务号 8.welink
* wxSendType: 当发送类型为5时此字段才会生效:text(文本消息)、textcard(文本卡片)、nes(图文卡片,如果图文,则qyWeChatImgUrl必填)、button(按钮卡片详见示例),不传默认为text
* receiverType: 1:用户 2:用户组 3:部门,默认为1
*
* @param title
* @param content
* @param receivers
*/
private void doSend(String title, String content, List<Map<String, String>> receivers, String link) {
@Override
public void sendSinglePicTextCard(String loginName, String content, String pcUrl, String mobileUrl, String picUrl) {
this.sendSinglePicTextCard(loginName, "智慧工会", content, pcUrl, mobileUrl, picUrl);
}
if(!SecurityUtil.getUserLoginname().equals("superadmin")) {
return;
@Override
public void sendSinglePicTextCard(String loginName, String title, String content, String pcUrl, String mobileUrl, String picUrl) {
this.massSendPicTextCard(List.of(loginName), title, content, pcUrl, mobileUrl, picUrl);
}
@Override
public void massSendMessage(List<String> loginNames, String content) {
this.massSendMessage(loginNames, "智慧工会", content);
}
@Override
public void massSendMessage(List<String> loginNames, String title, String content) {
List<ReceiverDto> list = loginNames.stream().map(loginName -> {
ReceiverDto receiverDto = new ReceiverDto();
receiverDto.setUserId(loginName);
return receiverDto;
}).toList();
this.doSend(WxSendType_Constants.TEXT, list, title, content, null, null, null);
}
@Override
public void massSendTextCard(List<String> loginNames, String content, String pcUrl, String mobileUrl) {
this.massSendTextCard(loginNames, "智慧工会", content, pcUrl, mobileUrl);
}
@Override
public void massSendTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl) {
List<ReceiverDto> list = loginNames.stream().map(loginName -> {
ReceiverDto receiverDto = new ReceiverDto();
receiverDto.setUserId(loginName);
return receiverDto;
}).toList();
this.doSend(WxSendType_Constants.TEXT_CARD, list, title, content, pcUrl, mobileUrl, null);
}
@Override
public void massSendPicTextCard(List<String> loginNames, String content, String pcUrl, String mobileUrl, String picUrl) {
this.massSendPicTextCard(loginNames, "智慧工会", content, pcUrl, mobileUrl, picUrl);
}
@Override
public void massSendPicTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl, String picUrl) {
List<ReceiverDto> list = loginNames.stream().map(loginName -> {
ReceiverDto receiverDto = new ReceiverDto();
receiverDto.setUserId(loginName);
return receiverDto;
}).toList();
this.doSend(WxSendType_Constants.NEWS, list, title, content, pcUrl, mobileUrl, picUrl);
}
@Override
public void recallMsg(String msgId) {
try {
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_BASE_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
RecallMsgRequest request = new RecallMsgRequest();
request.setMsgId(msgId);
log.info("撤回企业微信消息,请求参数:{}", Json.toJson(request));
RecallMsgResponse response = client.execute(request);
log.info("撤回企业微信消息,接口响应数据:{}", Json.toJson(response));
} catch (Exception e) {
log.error("撤回企业微信消息失败", e);
}
}
private void doSend(String sendType,
List<ReceiverDto> receivers,
String title,
String content,
String pcUrl,
String mobileUrl,
String picUrl) {
if (Lang.isEmpty(receivers)) {
log.error("send fail by receivers is null");
return;
}
// 获取token
String accessToken = buildAccessToken();
// 获取第一个接收人的userID
String firstUserId = receivers.get(0).get("userId");
// md5小写加密生成签名
String sign = DigestUtil.md5Hex(accessToken + firstUserId);
NutMap paramsMap = new NutMap();
paramsMap.put("sign", sign);
paramsMap.put("msgType", "0");
paramsMap.put("subject", title);
paramsMap.put("content", content);
paramsMap.put("sendType", "5");
paramsMap.put("receivers", receivers);
if (StrUtil.isBlank(link)) {
paramsMap.put("wxSendType", "text");
} else {
paramsMap.put("wxSendType", "textcard");
paramsMap.put("mobileUrl", link);
// 这是图文卡片,后面用到再对接吧
// paramsMap.put("qyWeChatImgUrl", "");
}
log.debug("send params: {}", Json.toJson(paramsMap));
HttpRequest request = HttpRequest.post(MSG_URL)
.header("appId", APPID)
.header("accessToken", accessToken)
.body(Json.toJson(paramsMap));
try {
HttpResponse response = request.execute();
log.info("send response body: {}", response.body());
// 创建客户端
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_BASE_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
SendMsgRequest request = new SendMsgRequest();
request.setSubject(title);
request.setContent(content);
request.setMsgType(MsgType_Constants.COMMON);
request.setSendType(SendType_Constants.WECHAT_ENTERPRISE);
request.setWxSendType(sendType);
request.setReceivers(receivers);
NutMap bodyMap = Json.fromJson(NutMap.class, response.body());
if (bodyMap.getInt("status") == 200) {
log.info("send success code: {}, msg: {}", bodyMap.getInt("status"), bodyMap.getString("msg"));
if (WxSendType_Constants.TEXT_CARD.equals(sendType)) {
request.setPcUrl(pcUrl);
request.setMobileUrl(mobileUrl);
request.setUrlDesc("查看详情");
}
if (WxSendType_Constants.NEWS.equals(sendType)) {
request.setPcUrl(pcUrl);
request.setMobileUrl(mobileUrl);
request.setUrlDesc("查看详情");
request.setQyWeChatImgUrl(picUrl);
}
log.info("发送企业微信通知,请求参数:{}", Json.toJson(request));
SendMsgResponse response = client.execute(request);
log.info("发送企业微信通知,接口响应数据:{}", Json.toJson(response));
if (response.isSuccess() && response.getStatus() == 200) {
// TODO 消息Id,后面可以存着,撤回要用到
String msgId = response.getMsgId();
log.info("发送企业微信通知成功: {}, msg: {}", response.getStatus(), response.getMsg());
} else {
log.error("send error code: {}, msg: {}", bodyMap.getInt("status"), bodyMap.getString("msg"));
log.info("发送企业微信通知失败:{}", response.getMsg());
}
} catch (Exception e) {
log.error("Failed to send: {}", e.getMessage(), e);
log.error("发送企业微信通知失败", e);
}
}
private String buildAccessToken() {
String token = redisService.get(REDIS_KEY_MSG_ACCESS_TOKEN);
if (StrUtil.isNotBlank(token)) {
return token;
}
HttpRequest request = HttpRequest.get(TOKEN_URL);
request.header("appId", APPID);
request.header("appSecret", APP_SECRET);
HttpResponse response = request.execute();
log.info("accessToken response: {}", Json.toJson(response.body()));
NutMap bodyMap = Json.fromJson(NutMap.class, response.body());
if (bodyMap.getInt("errcode") == 0) {
log.info("accessToken status: {}", bodyMap.getInt("errorcode"));
redisService.setex(REDIS_KEY_MSG_ACCESS_TOKEN, 60 * 120, bodyMap.getString("data"));
return bodyMap.getString("data");
} else {
log.error("accessToken status: {}", bodyMap.getInt("errorcode"));
}
return "";
}
}
@@ -117,6 +117,7 @@ public class FlowTodoCenterController {
if (StrUtil.isNotBlank(searchKeyword)) {
cnd.where().andLike("ins.variable ->> '$.instanceName'", searchKeyword);
}
cnd.and("t.taskName", "!=", "startTask");
cnd.desc("t.createdAt");
sql.setCondition(cnd);
Pagination pagination = sysUserService.listPageMap(pageNumber, pageSize, sql);
@@ -1,6 +1,7 @@
package com.budwk.app.flow.listenter;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.event.ProcessEvent;
import com.budwk.app.flow.engine.event.ProcessEventListener;
@@ -9,6 +10,8 @@ import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.entity.ProcessTaskActor;
import com.budwk.app.flow.enums.ProcessEventTypeEnum;
import com.budwk.app.todo.service.TodoService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.web.commons.base.Globals;
import com.budwk.app.zhgh.dayofficework.message.service.GlobalMessageSendService;
import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Cnd;
@@ -61,9 +64,15 @@ public class ProcessTaskStartEventListener implements ProcessEventListener {
for (ProcessTaskActor taskActor : taskActors) {
// 模拟发送消息
String message = StrUtil.format("您有一条待办任务,实例:{},处理环节:{}", taskActor.getActorName(), instanceName, taskDisplayName);
String message = StrUtil.format("您有一条待办任务,实例:{},处理环节:{}", instanceName, taskDisplayName);
log.info(message);
globalMessageSendService.sendMessage(taskDisplayName, message, 2, List.of(taskActor.getActorId()), null);
if (!List.of("superadmin" ,"CS2025015", "20182040").contains(SecurityUtil.getUserLoginname())) {
break;
}
JSONObject config = new JSONObject();
config.set("pcUrl", Globals.AppDomain + task.getFormKey());
config.set("mobileUrl", Globals.AppDomain + task.getH5FormKey());
globalMessageSendService.sendMessage(taskDisplayName, message, 2, List.of(taskActor.getActorId()), config);
}
todoService.saveTask(task);
@@ -32,6 +32,8 @@ import com.budwk.app.flow.service.ProcessTaskService;
import com.budwk.app.flow.vo.HighLightVO;
import com.budwk.app.flow.vo.ProcessInstanceVO;
import com.budwk.app.flow.vo.ProcessTaskVO;
import com.budwk.app.todo.service.TodoService;
import com.budwk.app.todo.service.impl.TodoServiceImpl;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
@@ -43,6 +45,7 @@ import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.Mvcs;
import java.util.*;
import java.util.stream.Collectors;
@@ -558,6 +561,10 @@ public class ProcessInstanceServiceImpl extends BaseServiceImpl<ProcessInstance>
List<Long> taskIds = taskList.stream().map(ProcessTask::getId).toList();
dao().clear(ProcessTask.class, Cnd.where(ProcessTask::getId, "in", taskIds));
dao().clear(ProcessInstance.class, Cnd.where(ProcessInstance::getId, "=", processInstanceId));
// 删除学校待办
TodoService todoService = Mvcs.getIoc().get(TodoServiceImpl.class);
todoService.deleteProcessInstance(processInstanceId.toString());
}
@Override
@@ -7,6 +7,7 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.RepeatSubmit;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
@@ -16,16 +17,23 @@ import com.budwk.app.sys.models.Sys_role;
import com.budwk.app.sys.services.SysMsgService;
import com.budwk.app.sys.services.SysMsgUserService;
import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.club.model.ClubUser;
import com.budwk.app.zhgh.club.model.SysClub;
import com.budwk.app.zhgh.club.service.SysClubService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
@@ -47,6 +55,8 @@ public class SysMsgController {
private SysMsgUserService sysMsgUserService;
@Inject
private SysUserService sysUserService;
@Inject
private SysClubService sysClubService;
@At({"/", "/list/?"})
@Ok("beetl:/platform/sys/msg/index.html")
@@ -73,6 +83,9 @@ public class SysMsgController {
$condition
""");
Cnd cnd = Cnd.NEW();
if(!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
cnd.and("msg.createdBy", "=", SecurityUtil.getUserId());
}
cnd.groupBy("msg.id");
if (Strings.isNotBlank(searchType) && !"all".equals(searchType)) {
cnd.and("msg.type", "=", searchType);
@@ -197,6 +210,28 @@ public class SysMsgController {
if (Strings.isNotBlank(pageForm.getPageOrderName()) && Strings.isNotBlank(pageForm.getPageOrderBy())) {
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
}
SqlExpressionGroup group = new SqlExpressionGroup();
if(!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
if(AuthUtil.hasRoleOr(RoleConstant.BRANCH_UNION_ADMIN.name(), RoleConstant.BRANCH_UNION_CHAIRMAN.name())) {
group.or("u.unionId", "=", SecurityUtil.getUnionId());
}
if(AuthUtil.hasRoleOr(RoleConstant.CLUB_PRESIDENT.name(), RoleConstant.CLUB_MANAGER.name(),RoleConstant.CLUB_SECRETARY.name())) {
List<SysClub> myManageClub = sysClubService.getMyManageClub();
if(Lang.isNotEmpty(myManageClub)) {
List<String> list = myManageClub.stream().map(SysClub::getId).toList();
List<ClubUser> clubUsers = sysClubService.dao().query(ClubUser.class, Cnd.where(ClubUser::getClubId, "in", list));
if(Lang.isNotEmpty(clubUsers)) {
List<String> clubUserList = clubUsers.stream().map(ClubUser::getUserId).distinct().toList();
group.or("u.id", "in", clubUserList);
}
}
}
}
if(!group.isEmpty()) {
cnd.and(group);
}
sql.setCondition(cnd);
return Result.success().addData(sysUserService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql));
} catch (Exception e) {
@@ -131,7 +131,7 @@ public class SysSignatureController {
@Aop(TransAop.READ_COMMITTED)
public Result update(@Param("file") TempFile tempFile) {
String url = sysFileService.uploadReturnUrl(SysFileEngineTypeEnum.MINIO.getValue(), tempFile);
Sys_user_signature sysUserSignature = dao.fetch(Sys_user_signature.class);
Sys_user_signature sysUserSignature = dao.fetch(Sys_user_signature.class, Cnd.where("userId", "=", SecurityUtil.getUserId()));
if (ObjectUtil.isNull(sysUserSignature)) {
sysUserSignature = new Sys_user_signature();
}
@@ -361,10 +361,15 @@ public class SysUserController {
if (StrUtil.isBlank(pathname)) {
}
int i = pathname.indexOf("?");
if(i > 0) {
pathname = pathname.substring(0, i);
}
int i = pathname.indexOf("?");
if (i > 0) {
pathname = pathname.substring(0, i);
}
if (pathname.contains("webvpn")) {
int platform = pathname.indexOf("/platform");
pathname = pathname.substring(platform);
}
// Sys_menu menu = sysMenuService.fetch(Cnd.where(Sys_menu::getHref, "like", pathname + "%"));
Sys_menu menu = sysMenuService.fetch(Cnd.where(Sys_menu::getHref, "=", pathname));
if (menu == null) {
@@ -57,6 +57,12 @@ public class Sys_msg extends BaseModel implements Serializable {
@Many(field = "msgId")
private List<Sys_msg_user> userList;
@Column
@Comment("同步企业微信")
@ColDefine(type = ColType.BOOLEAN)
@Default("0")
private Boolean wechatEnterprise;
@Column
@Comment("是否需要反馈")
@ColDefine(type = ColType.BOOLEAN)
@@ -105,10 +105,12 @@ public class SysMsgServiceImpl extends BaseServiceImpl<Sys_msg> implements SysMs
// for (String loginName : loginNames) {
// smsService.send(loginName, sysMsg.getTitle(), sysMsg.getNote());
// }
ThreadUtil.execute(() -> {
//smsService.massSend(loginNames, sysMsg.getTitle(), HtmlUtil.cleanHtmlTag(StrUtil.blankToDefault(sysMsg.getNote(),"")), sysMsg.getUrl());
});
if(sysMsg.getWechatEnterprise()) {
ThreadUtil.execute(() -> {
//smsService.massSend(loginNames, sysMsg.getTitle(), HtmlUtil.cleanHtmlTag(StrUtil.blankToDefault(sysMsg.getNote(),"")), sysMsg.getUrl());
smsService.massSendMessage(loginNames, HtmlUtil.cleanHtmlTag(StrUtil.blankToDefault(sysMsg.getNote(),"")));
});
}
return sysMsg;
}
@@ -12,7 +12,9 @@ public class TodoPlatformConfig {
// token 获取
public static final String TOKEN_URL = "https://gateway.jshvc.edu.cn/token/gateway/accessToken";
// 待办平台基础地址
public static final String TODO_PLATFORM_BASE_URL = "https://gateway.jshvc.edu.cn/casp-tdc/task/saveOrUpdate";
public static final String TODO_PLATFORM_BASE_URL = "https://gateway.jshvc.edu.cn";
// 待办平台新增或者修改
public static final String TODO_PLATFORM_SAVE_OR_UPDATE_URL = "https://gateway.jshvc.edu.cn/casp-tdc/task/saveOrUpdate";
// 待办平台修改地址
public static final String TODO_PLATFORM_MODIFY_URL = "https://gateway.jshvc.edu.cn/casp-tdc/task/modifyInfo";
// 待办平台删除任务地址
@@ -1,7 +1,6 @@
package com.budwk.app.todo.service;
import com.budwk.app.flow.entity.ProcessTask;
import com.wisedu.casp.sdk.api.BaseResponse;
/**
* @ClassName TodoService
@@ -12,7 +12,12 @@ import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.todo.platform.TodoPlatformConfig;
import com.budwk.app.todo.service.TodoService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.web.commons.base.Globals;
import com.wisedu.casp.sdk.api.BaseResponse;
import com.wisedu.casp.sdk.api.mc.ChannelInfo;
import com.wisedu.casp.sdk.api.mc.GetEnableChannelByTypeRequest;
import com.wisedu.casp.sdk.api.mc.GetEnableChannelByTypeResponse;
import com.wisedu.casp.sdk.api.mc.constants.ChannelType_Constants;
import com.wisedu.casp.sdk.api.tdc.constants.*;
import com.wisedu.casp.sdk.api.tdc.model.*;
import com.wisedu.casp.sdk.api.tdc.pushtask.ProcessInstanceRealDeleteRequest;
@@ -28,6 +33,7 @@ import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import java.util.Arrays;
@@ -55,7 +61,7 @@ public class TodoServiceImpl implements TodoService {
@Override
public void saveTask(ProcessTask task) {
if(!SecurityUtil.getUserLoginname().equals("superadmin")) {
if (!List.of("superadmin" ,"CS2025015", "20182040").contains(SecurityUtil.getUserLoginname())) {
return;
}
log.info("新增待办任务,任务数据:{}", Json.toJson(task));
@@ -66,6 +72,7 @@ public class TodoServiceImpl implements TodoService {
ProcessDefine define = dao.fetch(ProcessDefine.class, instance.getProcessDefineId());
// 获取流程发起人
String initiatorAccount = Json.fromJson(NutMap.class, instance.getVariable()).getString(FlowConst.INITIATOR_ACCOUNT);
String instanceName = Json.fromJson(NutMap.class, instance.getVariable()).getString("instanceName");
// 获取任务执行人
List<ProcessTaskActor> taskActors = dao.query(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", task.getId()));
List<Processor> processorList = taskActors.stream().map(o -> new Processor(o.getActorAccount())).toList();
@@ -79,25 +86,45 @@ public class TodoServiceImpl implements TodoService {
insertModel.setTaskId(task.getId().toString());
insertModel.setInitiatorId(initiatorAccount);
insertModel.setInitiatorType(ProcessorType.USER_ACCOUNT);
insertModel.setSubject(define.getDisplayName());
insertModel.setSubject(instanceName);
insertModel.setPriority(PriorityType.COMMON);
insertModel.setTaskType(TaskType.COMMON);
insertModel.setProcessors(processorList);
insertModel.setProcessType(ProcessType.OR_SIGN);
insertModel.setNodeId(task.getId().toString());
insertModel.setNodeName(task.getTaskName());
insertModel.setPcViewUrl(task.getFormKey());
insertModel.setH5ViewUrl(task.getH5FormKey());
insertModel.setNodeName(task.getDisplayName());
insertModel.setPcViewUrl(Globals.AppDomain + task.getFormKey());
insertModel.setH5ViewUrl(Globals.AppDomain + task.getH5FormKey());
// insertModel.setServiceId("xxx");
// insertModel.setServiceName("xxx");
// 任务关联的申请信息
ApplicationModel applicationModel = new ApplicationModel();
applicationModel.setProcessInstanceId(instance.getId().toString());
applicationModel.setSubject(define.getDisplayName());
applicationModel.setProcessors(processorList);
applicationModel.setProcessInstanceStatus(ProcessInstanceStatusType.RUNNING);
applicationModel.setNodeId(task.getId().toString());
applicationModel.setNodeName(task.getDisplayName());
insertModel.setApplicationModel(applicationModel);
request.setInsertModel(Collections.singletonList(insertModel));
/*Client channelClient = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_BASE_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
GetEnableChannelByTypeRequest channelByTypeRequest = new GetEnableChannelByTypeRequest();
channelByTypeRequest.setChannelType(ChannelType_Constants.QYWECHAT);
GetEnableChannelByTypeResponse channelByTypeResponse = channelClient.execute(channelByTypeRequest);
log.info("获取待办消息渠道,接口响应数据:{}", Json.toJson(channelByTypeResponse));
if (channelByTypeResponse.isSuccess()) {
List<ChannelInfo> list = channelByTypeResponse.getData();
if(Lang.isNotEmpty(list)) {
request.setIsSendMsg(1);
request.setSendChannels("1184803022838996992");
request.setWxSendType("textcard");
}
}*/
log.info("新增待办任务,请求参数:{}", Json.toJson(request));
BaseResponse response = client.execute(request);
log.info("新增待办任务,接口响应数据:{}", Json.toJson(response));
} catch (Exception e) {
@@ -107,7 +134,7 @@ public class TodoServiceImpl implements TodoService {
@Override
public void updateTask(ProcessTask task) {
if(!SecurityUtil.getUserLoginname().equals("superadmin")) {
if (!List.of("superadmin" ,"CS2025015", "20182040").contains(SecurityUtil.getUserLoginname())) {
return;
}
log.info("更新待办任务,任务数据:{}", Json.toJson(task));
@@ -123,7 +150,7 @@ public class TodoServiceImpl implements TodoService {
ProcessTaskVO taskVO = flowEngine.processTaskService().findById(task.getId());
// 创建客户端
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_MODIFY_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_BASE_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
// 创建请求对象
SaveOrUpdateRequest request = new SaveOrUpdateRequest();
@@ -142,11 +169,12 @@ public class TodoServiceImpl implements TodoService {
applyModel.setProcessInstanceId(instance.getId().toString());
applyModel.setProcessInstanceStatus(ProcessInstanceStatusType.RUNNING);
applyModel.setNodeId(task.getId().toString());
applyModel.setNodeName(task.getTaskName());
applyModel.setNodeName(task.getDisplayName());
applyModel.setProcessors(processorList);
updateModel.setApplyModels(Collections.singletonList(applyModel));
request.setUpdateModel(updateModel);
log.info("更新待办任务,请求参数:{}", Json.toJson(request));
BaseResponse response = client.execute(request);
log.info("更新待办任务,接口响应数据:{}", Json.toJson(response));
} catch (Exception e) {
@@ -156,13 +184,13 @@ public class TodoServiceImpl implements TodoService {
@Override
public void modifyInfo(ProcessTask task) {
if(!SecurityUtil.getUserLoginname().equals("superadmin")) {
if (!List.of("superadmin" ,"CS2025015", "20182040").contains(SecurityUtil.getUserLoginname())) {
return;
}
log.info("修改待办任务,任务数据:{}", Json.toJson(task));
try {
// 创建客户端
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_MODIFY_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_BASE_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
// 创建请求对象
TaskModifyInfoRequest request = new TaskModifyInfoRequest();
// 需要修改什么后面扩展吧
@@ -170,6 +198,7 @@ public class TodoServiceImpl implements TodoService {
request.setSubject("test");
request.setProcessors(Arrays.asList(new Processor("user01"), new Processor("user02")));
log.info("修改待办任务,请求参数:{}", Json.toJson(request));
BaseResponse response = client.execute(request);
log.info("修改待办任务,接口响应数据:{}", Json.toJson(response));
} catch (Exception e) {
@@ -179,16 +208,18 @@ public class TodoServiceImpl implements TodoService {
@Override
public void deleteTask(String taskId) {
if(!SecurityUtil.getUserLoginname().equals("superadmin")) {
if (!List.of("superadmin" ,"CS2025015", "20182040").contains(SecurityUtil.getUserLoginname())) {
return;
}
log.info("删除待办任务,任务ID{}", taskId);
try {
// 创建客户端
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_DELETE_TASK_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_BASE_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
// 创建请求对象
TaskRealDeleteRequest request = new TaskRealDeleteRequest();
request.setTaskId(taskId);
log.info("删除待办任务,请求参数:{}", Json.toJson(request));
BaseResponse response = client.execute(request);
log.info("删除待办任务,接口响应数据:{}", Json.toJson(response));
} catch (Exception e) {
@@ -198,16 +229,18 @@ public class TodoServiceImpl implements TodoService {
@Override
public void deleteProcessInstance(String processInstanceId) {
if(!SecurityUtil.getUserLoginname().equals("superadmin")) {
if (!List.of("superadmin" ,"CS2025015", "20182040").contains(SecurityUtil.getUserLoginname())) {
return;
}
log.info("删除待办流程,实例ID{}", processInstanceId);
try {
// 创建客户端
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_DELETE_INSTANCE_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_BASE_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
// 创建请求对象
ProcessInstanceRealDeleteRequest request = new ProcessInstanceRealDeleteRequest();
request.setProcessInstanceId(processInstanceId);
log.info("删除待办流程,请求参数:{}", Json.toJson(request));
BaseResponse response = client.execute(request);
log.info("删除待办流程,接口响应数据:{}", Json.toJson(response));
} catch (Exception e) {
@@ -34,7 +34,7 @@ public class Globals {
//项目LOGO
public static String AppLogo = "";
//项目域名
public static String AppDomain = "http://127.0.0.1";
public static String AppDomain = "https://zhgh.jshvc.edu.cn";
//文件访问域名
public static String AppFileDomain = "";
//学校代码
@@ -145,6 +145,7 @@ public class ActivityReimbursementApplyController {
args.set("outlayManageSource", activityReimbursementInfo.getOutlayManageSource());
args.set("actualMoney", activityReimbursementInfo.getActualMoney());
args.set("next", activityReimbursementInfo.getReimbursementIdentity());
args.set("clubId",activityReimbursementInfo.getClubId());
ProcessInstance instance = flowEngine.startProcessInstanceByKey("HDBX", activityReimbursementInfo.getId(), SecurityUtil.getUserId(), args);
// 自动完成第一个申请任务
@@ -5,14 +5,18 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.convert.NumberWordFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.base.utils.OfficePlusUtil;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
import com.budwk.app.flow.engine.FlowEngine;
@@ -39,6 +43,7 @@ import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
@@ -47,9 +52,12 @@ import org.nutz.mvc.annotation.Ok;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.*;
/**
@@ -129,24 +137,24 @@ public class ActivityReimbursementMineController {
""");
Cnd cnd = Cnd.NEW();
SqlExpressionGroup group = new SqlExpressionGroup();
if (AuthUtil.hasPermission("activityReimbursement.apply.schoolHas")){
group.or("info.reimbursementIdentity","=","school");
/*if (AuthUtil.hasPermission("activityReimbursement.apply.schoolHas")) {
group.or("info.reimbursementIdentity", "=", "school");
}
if (AuthUtil.hasPermission("activityReimbursement.apply.unionHas")){
if (AuthUtil.hasPermission("activityReimbursement.apply.unionHas")) {
SqlExpressionGroup unionGroup = new SqlExpressionGroup();
unionGroup.and("info.unionId", "=", SecurityUtil.getUnionId());
unionGroup.and("info.reimbursementIdentity","=","union");
unionGroup.and("info.reimbursementIdentity", "=", "union");
group.or(unionGroup);
}
if (AuthUtil.hasPermission("activityReimbursement.apply.clubHas")){
if (AuthUtil.hasPermission("activityReimbursement.apply.clubHas")) {
SqlExpressionGroup clubGroup = new SqlExpressionGroup();
clubGroup.and("info.clubId", "in", SecurityUtil.getClubIds());
clubGroup.and("info.reimbursementIdentity","=","club");
clubGroup.and("info.reimbursementIdentity", "=", "club");
group.or(clubGroup);
}
if (Lang.isNotEmpty(group)){
cnd.and(group);
}else{
}*/
if (!group.isEmpty()) {
cnd.and(group);
} else {
cnd.and("info.userId", "=", SecurityUtil.getUserId());
}
@@ -158,7 +166,7 @@ public class ActivityReimbursementMineController {
cnd.orderBy("info." + pageParam.getPageOrderName(), PageUtil.getOrder(pageParam.getPageOrderBy()));
}
// cnd.groupBy("t.id");
cnd.groupBy("info.id");
cnd.groupBy("info.id");
sql.setCondition(cnd);
Pagination<NutMap> pagination = activityReimbursementService.listPageMap(pageParam.getPageNumber(), pageParam.getPageSize(), sql);
return Result.success().addData(pagination);
@@ -207,9 +215,11 @@ public class ActivityReimbursementMineController {
Sql sql = Sqls.create("""
SELECT
info.*,
us.mobile,
ins.id AS instanceId
FROM
`activity_reimbursement_info` info
LEFT JOIN sys_user us on us.id=info.userId
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
WHERE
ins.state = 20 AND info.id = @id
@@ -257,7 +267,13 @@ public class ActivityReimbursementMineController {
// 组合结果
String actualMoneyChinese = integerChinese + decimalChinese;
info.put("actualMoney", actualMoneyChinese);
info.put("bigActualMoney", actualMoneyChinese);
info.put("actualMoney", info.getString("actualMoney"));
info.put("sign", sysOfficeTemplateUtil.createPictureRenderData(info.getString("sign")));
info.put("applyTime", info.getString("applyTime").substring(0, 10));
List<NutMap> billFiles = Json.fromJsonAsList(NutMap.class, info.getString("billFiles"));
info.put("fileNum", billFiles.size());
docData.put("schoolName", Globals.AppName);
docData.put("info", info);
@@ -325,68 +341,101 @@ public class ActivityReimbursementMineController {
doneTaskVos.add(taskVO);
}
List<NutMap> auditList = new ArrayList<>();
// 分工会审核
doneTaskVos.stream().filter(task -> "分工会审核".equals(task.getDisplayName()))
.max(Comparator.comparing(ProcessTaskVO::getCreatedAt))
.ifPresent(v -> {
Dict taskFormData = v.getTaskFormData();
HashMap<String, Object> approval = new HashMap<>();
approval.put("date", DateUtil.format(v.getFinishTime(), "yyyy年MM月dd日"));
approval.put("user", taskFormData.getStr("tf_userName"));
if (StrUtil.isNotBlank(taskFormData.getStr("tf_sign"))) {
approval.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("tf_sign")));
NutMap map = new NutMap();
map.put("unit", "分工会审核");
map.put("date", DateUtil.format(v.getFinishTime(), "yyyy年MM月dd日"));
map.put("userName", taskFormData.getStr("tf_userName"));
if (StrUtil.isNotBlank(taskFormData.getStr("tf_userSign"))) {
map.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("tf_userSign")));
}
approval.put("opinion", taskFormData.getStr("tf_opinion"));
docData.put("fgh", approval);
map.put("opinion", taskFormData.getStr("tf_opinion"));
auditList.add(map);
});
// 协会负责人审核
doneTaskVos.stream().filter(task -> "协会负责人审核".equals(task.getDisplayName()))
.max(Comparator.comparing(ProcessTaskVO::getCreatedAt))
.ifPresent(v -> {
Dict taskFormData = v.getTaskFormData();
HashMap<String, Object> approval = new HashMap<>();
approval.put("date", DateUtil.format(v.getFinishTime(), "yyyy年MM月dd日"));
approval.put("user", taskFormData.getStr("tf_userName"));
if (StrUtil.isNotBlank(taskFormData.getStr("tf_sign"))) {
approval.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("tf_sign")));
NutMap map = new NutMap();
map.put("unit", "协会负责人审核");
map.put("date", DateUtil.format(v.getFinishTime(), "yyyy年MM月dd日"));
map.put("userName", taskFormData.getStr("tf_userName"));
if (StrUtil.isNotBlank(taskFormData.getStr("tf_userSign"))) {
map.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("tf_userSign")));
}
approval.put("opinion", taskFormData.getStr("tf_opinion"));
docData.put("xh", approval);
map.put("opinion", taskFormData.getStr("tf_opinion"));
auditList.add(map);
});
// 校工会负责人审核
doneTaskVos.stream().filter(task -> "校工会负责人审核".equals(task.getDisplayName()))
// 会负责人审核
doneTaskVos.stream().filter(task -> "校工会财务审核".equals(task.getDisplayName()))
.max(Comparator.comparing(ProcessTaskVO::getCreatedAt))
.ifPresent(v -> {
Dict taskFormData = v.getTaskFormData();
HashMap<String, Object> approval = new HashMap<>();
approval.put("date", DateUtil.format(v.getFinishTime(), "yyyy年MM月dd日"));
approval.put("user", taskFormData.getStr("tf_userName"));
if (StrUtil.isNotBlank(taskFormData.getStr("tf_sign"))) {
approval.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("tf_sign")));
NutMap map = new NutMap();
map.put("unit", "校工会财务审核");
map.put("date", DateUtil.format(v.getFinishTime(), "yyyy年MM月dd日"));
map.put("userName", taskFormData.getStr("tf_userName"));
if (StrUtil.isNotBlank(taskFormData.getStr("tf_userSign"))) {
map.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("tf_userSign")));
}
approval.put("opinion", taskFormData.getStr("tf_opinion"));
docData.put("xfzr", approval);
map.put("opinion", taskFormData.getStr("tf_opinion"));
auditList.add(map);
});
// 校工会负责人审核
doneTaskVos.stream().filter(task -> "校工会预审".equals(task.getDisplayName()))
.max(Comparator.comparing(ProcessTaskVO::getCreatedAt))
.ifPresent(v -> {
Dict taskFormData = v.getTaskFormData();
NutMap map = new NutMap();
map.put("unit", "校工会预审");
map.put("date", DateUtil.format(v.getFinishTime(), "yyyy年MM月dd日"));
map.put("userName", taskFormData.getStr("tf_userName"));
if (StrUtil.isNotBlank(taskFormData.getStr("tf_userSign"))) {
map.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("tf_userSign")));
}
map.put("opinion", taskFormData.getStr("tf_opinion"));
auditList.add(map);
});
doneTaskVos.stream().filter(task -> "校工会副主席审核".equals(task.getDisplayName()))
.max(Comparator.comparing(ProcessTaskVO::getCreatedAt))
.ifPresent(v -> {
Dict taskFormData = v.getTaskFormData();
NutMap map = new NutMap();
map.put("unit", "校工会副主席审核");
map.put("date", DateUtil.format(v.getFinishTime(), "yyyy年MM月dd日"));
map.put("userName", taskFormData.getStr("tf_userName"));
if (StrUtil.isNotBlank(taskFormData.getStr("tf_userSign"))) {
map.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("tf_userSign")));
}
map.put("opinion", taskFormData.getStr("tf_opinion"));
auditList.add(map);
});
// 校工会主席审核
doneTaskVos.stream().filter(task -> "校工会主席审核".equals(task.getDisplayName()))
.max(Comparator.comparing(ProcessTaskVO::getCreatedAt))
.ifPresent(v -> {
Dict taskFormData = v.getTaskFormData();
HashMap<String, Object> approval = new HashMap<>();
approval.put("date", DateUtil.format(v.getFinishTime(), "yyyy年MM月dd日"));
approval.put("user", taskFormData.getStr("tf_userName"));
if (StrUtil.isNotBlank(taskFormData.getStr("tf_sign"))) {
approval.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("tf_sign")));
NutMap map = new NutMap();
map.put("unit", "校工会主席审核");
map.put("date", DateUtil.format(v.getFinishTime(), "yyyy年MM月dd日"));
map.put("userName", taskFormData.getStr("tf_userName"));
if (StrUtil.isNotBlank(taskFormData.getStr("tf_userSign"))) {
map.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("tf_userSign")));
}
approval.put("opinion", taskFormData.getStr("tf_opinion"));
docData.put("xzx", approval);
map.put("opinion", taskFormData.getStr("tf_opinion"));
auditList.add(map);
});
String budgetsStr = info.getString("budgets");
@@ -396,17 +445,29 @@ public class ActivityReimbursementMineController {
}
docData.put("budgets", list);
docData.put("auditList", auditList);
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
Configure config = Configure.builder()
.bind("budgets", policy)
.bind("auditList", policy)
.build();
String fileName = Globals.AppName + "" + info.getString("activityName") + "】报销凭证表.docx";
String fileName = Globals.AppName + "" + info.getString("activityName") + "】报销凭证表.pdf";
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
XWPFTemplate.compile(sysOfficeTemplateUtil.getTemplate("activity_reimbursement_voucher"), config).render(docData).writeAndClose(byteArrayOutputStream);
CommonDownloadUtil.download(fileName, byteArrayOutputStream.toByteArray(), response);
byte[] bytes = byteArrayOutputStream.toByteArray();
File sourceFile = File.createTempFile("file_convert_origin", ".docx");
Files.write(sourceFile.toPath(), bytes, StandardOpenOption.WRITE);
File pdfFile = File.createTempFile("file_convert", ".pdf");
OfficePlusUtil.convert(sourceFile.getPath(), pdfFile.getPath());
CommonDownloadUtil.download(fileName, IoUtil.readBytes(FileUtil.getInputStream(pdfFile)), response);
// 删除临时文件
FileUtil.del(sourceFile);
FileUtil.del(pdfFile.toPath());
} catch (IOException e) {
log.error("报销凭证表导出失败,id:{},错误信息:{}", id, e.getMessage());
}
@@ -42,7 +42,7 @@ public class WechatEnterpriseMessageSendStrategy implements GlobalMessageSendStr
@Override
public boolean isEnabled() {
return GlobalMessageSendStrategy.super.isEnabled();
return true;
}
@Override
@@ -82,6 +82,6 @@ public class WechatEnterpriseMessageSendStrategy implements GlobalMessageSendStr
return;
}
List<String> list = users.stream().map(Sys_user::getLoginname).toList();
smsService.massSend(list, title, content, "");
smsService.massSendTextCard(list, "智慧工会", content, config.getStr("pcUrl"), config.getStr("mobileUrl"));
}
}
@@ -1,20 +1,20 @@
<template>
<div>
<div class="file-preview-container" v-if="fileList && fileList.length > 0">
<div class="file-item" title="点击查看" v-for="item in fileList" :key="item.id">
<div class="file-item" title="点击查看" v-for="(item, index) in fileList" :key="item.id">
<el-image
v-if="item.suffix === 'jpg' || item.suffix === 'png' || item.suffix === 'jpeg' || item.suffix === 'gif'"
:src="item.thumbnail"
:fit="'cover'"
:style="{ width: '100%', height: '100%' }"
@click.stop="$commonUtil.previewFile(item)"
@click.stop="onPreView(item, index)"
></el-image>
<el-image
v-else
:src="$commonUtil.getFileItemShowIcon(item.suffix)"
:fit="'cover'"
@click.stop="$commonUtil.previewFile(item)"
@click.stop="onPreView(item, index)"
:style="{ width: '100%', height: '100%' }"
></el-image>
@@ -25,6 +25,62 @@
</div>
</div>
<el-empty v-else description="暂无" :image-size="60"></el-empty>
<el-drawer class="file-preview-drawer" title="附件查看" size="78%" :visible.sync="fileDialog" :append-to-body="true">
<div class="file-preview-title">附件数量{{ fileList.length }}</div>
<el-row>
<el-col :span="5">
<el-menu class="file-preview-menu" :default-active="defaultActive + ''" @select="menuSelect">
<el-menu-item v-for="(file, index) in fileList" :key="index" :index="index + ''">
<el-image
:src="$commonUtil.getFileItemShowIcon(file.suffix)"
fit="cover"
:style="{ width: '30px', height: '30px' }"
></el-image>
<span slot="title">{{ file.name }}</span>
</el-menu-item>
</el-menu>
</el-col>
<el-col :span="19" class="preview-content-col">
<div class="preview-content-wrapper">
<div class="preview-main-content" v-loading="officeLoading" element-loading-text="拼命加载中">
<el-image
v-if="file?.suffix === 'jpg' || file?.suffix === 'png' || file?.suffix === 'jpeg' || file?.suffix === 'gif'"
:src="file.downloadPath"
:fit="'cover'"
@click.stop="$commonUtil.previewFile(file)"
@load="officeLoading = false"
@error="officeLoading = false"
class="file-preview-image"
></el-image>
<div v-else style="height: 100%">
<iframe v-if="['doc', 'docx', 'xls', 'xlsx'].includes(file?.suffix)"
frameborder="0"
width="100%"
height="100%"
@load="officeLoading = false"
:src="'/assets/platform/plugins/pdfJs/web/viewer.html?file=/platform/sys/file/convertPDF?id=' + file.id"
></iframe>
<iframe v-if="['pdf'].includes(file?.suffix)"
frameborder="0"
width="100%"
height="100%"
@load="officeLoading = false"
:src="'/assets/platform/plugins/pdfJs/web/viewer.html?file=' + file.downloadPath"
></iframe>
</div>
</div>
<div class="preview-footer">
<el-button type="primary" size="small" @click="previous">上一个</el-button>
<el-button type="primary" size="small" @click="next">下一个</el-button>
<el-button type="primary" size="small" @click="fileDialog = false">关闭</el-button>
</div>
</div>
</el-col>
</el-row>
</el-drawer>
</div>
</template>
@@ -57,10 +113,46 @@ module.exports = {
},
data() {
return {
fileList: []
fileList: [],
fileDialog: false,
defaultActive: 0,
file: {},
officeLoading: true,
}
},
methods: {
next() {
this.defaultActive = Number(this.defaultActive)
if(this.defaultActive === this.fileList.length - 1) {
this.$message.error('已经是最后一个附件了')
return
}
this.defaultActive = this.defaultActive + 1
this.file = this.fileList[this.defaultActive]
},
previous() {
this.defaultActive = Number(this.defaultActive)
if(this.defaultActive === 0) {
this.$message.error('已经是第一个附件了')
return
}
this.defaultActive = this.defaultActive - 1
this.file = this.fileList[this.defaultActive]
},
menuSelect(index) {
index = Number(index)
this.defaultActive = Number(this.defaultActive)
if(index !== this.defaultActive) {
this.officeLoading = true
}
this.defaultActive = index
this.file = this.fileList[index]
},
onPreView(item, index) {
this.file = item
this.defaultActive = index
this.fileDialog = true
},
buildEchoFileObject(val) {
let ids = []
if (this.complete_result) {
@@ -111,6 +203,76 @@ module.exports = {
}
</script>
<style>
.file-preview-drawer .el-row {
margin: 0;
height: calc(100vh - 43px - 32px - 20px - 10px);
}
.file-preview-drawer .el-col {
height: 100%;
padding: 0;
}
.file-preview-title {
padding-left: 20px;
font-weight: bold;
margin-bottom: 10px;
}
.file-preview-menu {
height: 100%;
padding-left: 10px;
}
.file-preview-menu .el-menu-item,
.file-preview-menu .el-submenu__title {
height: 40px;
line-height: 40px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.file-preview-drawer iframe {
vertical-align: bottom;
display: block;
}
.preview-content-col {
/*padding: 0 20px 10px;*/
}
.preview-content-wrapper {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.preview-main-content {
flex: 1;
overflow: auto;
margin: 0 10px 10px;
box-sizing: border-box;
}
.preview-main-content .file-preview-image {
margin: 0 auto;
max-width: 80%;
display: block;
}
.preview-footer {
line-height: 60px;
padding: 0 10px;
border-top: 1px solid #e6e6e6;
background-color: white;
text-align: right;
box-sizing: border-box;
/* position: sticky;
bottom: 0; */
}
.file-preview-drawer .el-menu-item.is-active {
font-weight: bold;
}
.file-preview-drawer .el-drawer__body {
padding: 0;
}
</style>
<style scoped>
.file-preview-container {
position: relative;
@@ -0,0 +1,169 @@
<template>
<div>
<div class="file-preview-container" v-if="fileList && fileList.length > 0">
<div class="file-item" title="点击查看" v-for="item in fileList" :key="item.id">
<el-image
v-if="item.suffix === 'jpg' || item.suffix === 'png' || item.suffix === 'jpeg' || item.suffix === 'gif'"
:src="item.thumbnail"
:fit="'cover'"
:style="{ width: '100%', height: '100%' }"
@click.stop="$commonUtil.previewFile(item)"
></el-image>
<el-image
v-else
:src="$commonUtil.getFileItemShowIcon(item.suffix)"
:fit="'cover'"
@click.stop="$commonUtil.previewFile(item)"
:style="{ width: '100%', height: '100%' }"
></el-image>
<div class="file-download" title="点击下载" @click="$downLoad(item.downloadPath)">
<i class="el-icon-download"></i>
{{ item.name }}
</div>
</div>
</div>
<el-empty v-else description="暂无" :image-size="60"></el-empty>
</div>
</template>
<script>
module.exports = {
name: "sysFilePreview",
props: {
files: {
type: [String, Array],
default: undefined,
required: false
},
complete_result: {
type: Boolean,
default: false,
required: false
}
},
watch: {
files: {
handler(val) {
if (val) {
this.buildEchoFileObject(val)
} else {
this.fileList = []
}
},
immediate: true
}
},
data() {
return {
fileList: []
}
},
methods: {
buildEchoFileObject(val) {
let ids = []
if (this.complete_result) {
if (Array.isArray(val)) {
ids = val.map((item) => {
if (item.response.data.includes("=")) {
return item?.response?.data.substring(item?.response?.data.lastIndexOf("=") + 1)
} else {
return item?.response?.data
}
})
} else {
try {
ids = JSON.parse(val).map((item) => {
if (item.response.data.includes("=")) {
return item?.response?.data.substring(item?.response?.data.lastIndexOf("=") + 1)
} else {
return item?.response?.data
}
})
} catch (err) {
this.fileList = []
}
}
} else {
// id
if (Array.isArray(val)) {
ids = val.map((item) => {
return item.substring(item.lastIndexOf("=") + 1)
})
} else {
ids = val.split(",").map((item) => {
return item.substring(item.lastIndexOf("=") + 1)
})
}
}
this.requestFullFile(ids)
},
requestFullFile(ids) {
this.$axios.post("/platform/sys/file/previewFileData", { ids: JSON.stringify(ids) }).then((res) => {
if (res.code === 0) {
this.fileList = res.data
}
})
}
}
}
</script>
<style scoped>
.file-preview-container {
position: relative;
display: flex;
width: 100%;
flex-direction: row;
flex-wrap: wrap;
column-gap: 10px;
}
.file-preview-container .file-item {
width: 118px;
height: 118px;
position: relative;
transition: all 500ms;
border-radius: 5px;
cursor: pointer;
text-align: center;
column-gap: 15px;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.file-preview-container .file-item:hover {
background: rgb(230, 230, 230);
}
.file-preview-container .file-item .el-image {
width: 90px !important;
height: 100%;
transform: translateY(10px);
}
.file-preview-container .file-item .file-download {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 24px;
line-height: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: white;
background-color: rgb(160, 160, 160);
border-radius: 2px;
opacity: 0.95;
}
.el-empty {
padding: 0;
}
</style>
@@ -70,10 +70,10 @@
<script src="${base!}/assets/platform/plugins/g2plot/g2plot.min.js"></script>
<!-- <script src="https://cdn.jsdelivr.net/npm/goober@2.1.10/dist/goober.umd.js"></script>-->
<script
<!--<script
type="text/javascript"
src="https://webapi.amap.com/maps?v=2.0&key=57f0d098ba1b881ecc436c4cfd23bbbf&plugin=AMap.PolyEditor,AMap.Geolocation"
></script>
></script>-->
<script src="https://map.qq.com/api/gljs?v=2.exp&key=MLLBZ-GQECI-ASXG7-5GNOZ-XW2OF-H5BVH"></script>
<script nonce="${cspNonce!}">
@@ -284,9 +284,11 @@ layout("/layouts/v4/baseLayout.html"){
<!-- 表格展示 -->
<el-table v-loading="loading" :data="tasks" style="width: 100%" :key="activeTab"
:header-cell-style="{backgroundColor: '#f5f7fa'}">
<el-table-column prop="instanceName" label="流程名称" min-width="180" show-overflow-tooltip></el-table-column>
<el-table-column prop="instanceName" label="流程名称" min-width="180"
show-overflow-tooltip></el-table-column>
<el-table-column prop="taskName" label="任务节点" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column prop="categoryName" label="流程分类" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column prop="categoryName" label="流程分类" min-width="150"
show-overflow-tooltip></el-table-column>
<el-table-column prop="initiatorName" label="申请人" min-width="120">
<template slot-scope="{row}">{{row.variable.initiatorName}}</template>
</el-table-column>
@@ -374,7 +376,7 @@ layout("/layouts/v4/baseLayout.html"){
},
created() {
if(GetQueryString("status")){
if (GetQueryString("status")) {
this.activeTab = GetQueryString("status")
}
this.initData()
@@ -464,7 +466,14 @@ layout("/layouts/v4/baseLayout.html"){
this.$message.warning("当前流程没有配置地址")
return
}
window.open(formKey + "?taskId=" + taskId + "bizId=" + businessNo + "taskKey=" + taskKey)
if (this.activeTab === "todo") {
window.open(formKey + "?taskId=" + taskId + "bizId=" + businessNo + "taskKey=" + taskKey)
} else if (this.activeTab === "done") {
window.open(formKey + "?taskId=" + taskId + "bizId=" + businessNo + "taskKey=" + taskKey)
} else {
window.open(formKey)
}
},
// 获取空状态文本
@@ -7,6 +7,15 @@ const MSG_FORM_TEMPLATE = {
</el-form-item>
<el-form-item prop="url" label="链接地址">
<el-input placeholder="请输入链接地址" v-model="formData.url"></el-input>
</el-form-item>
<el-form-item prop="wechatEnterprise" label="同步企业微信">
<div style="color: grey; font-size: 13px">
温馨提醒如选择是将会同步发送到企业微信同时链接地址是否需要反馈消息附件可无需填写
</div>
<el-radio-group v-model="formData.wechatEnterprise" size="small">
<el-radio border :label="true"></el-radio>
<el-radio border :label="false"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="needBack" label="是否需要反馈">
<el-radio-group v-model="formData.needBack" size="small">
@@ -31,10 +40,9 @@ const MSG_FORM_TEMPLATE = {
<el-table-column prop="sex" label="性别" width="50"></el-table-column>
<el-table-column prop="userState" label="在职状态" width="120"></el-table-column>
<el-table-column prop="personType" label="教职工类别" width="120"></el-table-column>
<el-table-column prop="preparedBy" label="编制类别" width="120"></el-table-column>
<el-table-column prop="mobile" label="手机" width="120"></el-table-column>
<el-table-column prop="unitName" label="所属单位" show-overflow-tooltip></el-table-column>
<el-table-column prop="unionName" label="所属工会" show-overflow-tooltip></el-table-column>
<el-table-column prop="unitname" label="所属单位" show-overflow-tooltip></el-table-column>
<el-table-column prop="unionname" label="所属工会" show-overflow-tooltip></el-table-column>
</el-table>
<p style="color: var(--color-primary)">总计{{userTableData.length}}</p>
</el-form-item>
@@ -58,7 +66,7 @@ const MSG_FORM_TEMPLATE = {
<el-dialog title="选择用户" :visible.sync="selectDialogVisible" width="65%" append-to-body top="2%">
<div class="btn-group tool-button">
<el-input placeholder="请输入内容" v-model="pageForm.searchKeyword" @keyup.enter.native="doSearch" style="width: 300px">
<el-input placeholder="请输入内容" v-model="pageForm.searchKeyword" @keyup.enter.native="doSearch" style="width: 240px">
<el-select v-model="pageForm.searchName" slot="prepend" placeholder="查询类型" style="width: 80px">
<el-option label="工号" value="u.loginname"></el-option>
<el-option label="姓名" value="u.username"></el-option>
@@ -94,10 +102,9 @@ const MSG_FORM_TEMPLATE = {
<el-table-column prop="sex" label="性别" width="50"></el-table-column>
<el-table-column prop="userState" label="在职状态" width="120"></el-table-column>
<el-table-column prop="personType" label="教职工类别" width="120"></el-table-column>
<el-table-column prop="preparedBy" label="编制类别" width="120"></el-table-column>
<el-table-column prop="mobile" label="手机" width="120"></el-table-column>
<el-table-column prop="unitName" label="所属单位" show-overflow-tooltip></el-table-column>
<el-table-column prop="unionName" label="所属工会" show-overflow-tooltip></el-table-column>
<el-table-column prop="unitname" label="所属单位" show-overflow-tooltip></el-table-column>
<el-table-column prop="unionname" label="所属工会" show-overflow-tooltip></el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
<span slot="footer" class="dialog-footer">
@@ -136,6 +143,7 @@ const MSG_FORM_TEMPLATE = {
title: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
note: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
needBack: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
wechatEnterprise: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
type: [{ required: true, message: "必填", trigger: ["blur", "change"] }]
},
selectDialogVisible: false,
@@ -216,7 +224,8 @@ const MSG_FORM_TEMPLATE = {
this.formData = {
id: "",
type: "user",
needBack: false
needBack: false,
wechatEnterprise: false,
}
if (this.$refs["addForm"]) this.$refs["addForm"].resetFields()
},
@@ -3,7 +3,7 @@ const VIEW_USER_TEMPLATE = {
<div>
<el-dialog :title="viewUserTitle" :visible.sync="viewDialogVisible" width="65%" top="2%">
<div class="btn-group tool-button">
<el-input placeholder="请输入内容" v-model="pageForm.searchKeyword" size="small" @keyup.enter.native="doSearch" style="width: 300px">
<el-input placeholder="请输入内容" v-model="pageForm.searchKeyword" size="small" @keyup.enter.native="doSearch" style="width: 240px">
<el-select v-model="pageForm.searchName" slot="prepend" placeholder="查询类型" style="width: 80px">
<el-option label="工号" value="u.loginname"></el-option>
<el-option label="姓名" value="u.username"></el-option>
@@ -28,8 +28,8 @@ const VIEW_USER_TEMPLATE = {
<el-table-column prop="username" label="姓名" width="120"></el-table-column>
<el-table-column prop="sex" label="性别" width="120"></el-table-column>
<el-table-column prop="mobile" label="联系方式"></el-table-column>
<el-table-column prop="unitName" label="所属单位"></el-table-column>
<el-table-column prop="unionName" label="所属工会"></el-table-column>
<el-table-column prop="unitname" label="所属单位"></el-table-column>
<el-table-column prop="unionname" label="所属工会"></el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
<span slot="footer" class="dialog-footer">
@@ -186,7 +186,7 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
placeholder="请选择主办单位"
style="width: 100%">
<el-option
v-for="item in unitOptions"
v-for="item in hostUnitOptions"
:key="item.id"
:label="item.name"
:value="item.id">
@@ -618,6 +618,7 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
{prop: "unionName", label: "所属工会"}
],
hostUnitOptions: [],
unitOptions: [],
clubOptions: [],
}
@@ -978,8 +979,11 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
this.clubOptions.map((v) => {
v.name = v.clubName
})
const unions = await this.$businessTool.listUnion()
this.unitOptions = this.clubOptions.concat(unions)
const units = await this.$businessTool.listUnit()
this.unitOptions = this.clubOptions.concat(units)
this.hostUnitOptions = this.clubOptions.concat(units)
},
async queryUserByIds(ids) {
const {data} = await this.$axios.post("/platform/activity/culture/applyActivity/queryUserByIds", {ids: JSON.stringify(ids)})
@@ -255,7 +255,7 @@ layout("/layouts/platform.html"){
<el-form-item prop="billFiles" label="发票等">
<file-upload :value.sync="formData.billFiles"
upload_mode="drag"
:upload_number="10" upload_result_category="array"
:upload_number="20" upload_result_category="array"
accept=".doc, .docx, .xls, .xlsx, .pdf, .ppt, .jpg, .jpeg, .png"
complete_result></file-upload>
</el-form-item>
@@ -265,7 +265,7 @@ layout("/layouts/platform.html"){
<el-form-item prop="photoFiles" label="活动报道照片/总结/链接">
<file-upload :value.sync="formData.photoFiles"
upload_mode="drag"
:upload_number="10" upload_result_category="array"
:upload_number="20" upload_result_category="array"
accept=".doc, .docx, .xls, .xlsx, .pdf, .ppt, .jpg, .jpeg, .png"
complete_result></file-upload>
</el-form-item>
@@ -275,7 +275,7 @@ layout("/layouts/platform.html"){
<el-form-item prop="otherFiles" label="奖品/纪念品/服装/道具等活动人员名单">
<file-upload :value.sync="formData.otherFiles"
upload_mode="drag"
:upload_number="10" upload_result_category="array"
:upload_number="20" upload_result_category="array"
accept=".doc, .docx, .xls, .xlsx, .pdf, .ppt, .jpg, .jpeg, .png"
complete_result></file-upload>
</el-form-item>
@@ -100,7 +100,7 @@ layout("/layouts/platform.html"){
size="mini" type="danger">删除
</el-button>
<el-button @click="doExportDeclare(row)" size="mini" type="primary">申请表导出</el-button>
<!-- <el-button @click="doExportDeclare(row)" size="mini" type="primary">申请表导出</el-button>-->
<el-button v-if="row.instanceState === 20" @click="doExportReimbursement(row)" size="mini"
type="primary">报销凭证导出
</el-button>
@@ -155,7 +155,7 @@ layout("/layouts/platform.html"){
methods: {
// 导出示例
doExportDeclare(row) {
this.$downLoad('/platform/activityDeclare/mine/doExportDeclare?id=' + row.declareId)
this.$downLoad('/platform/activityDeclare/mine/doExportDeclare?id=' + row.id)
},
// 导出报销凭证
doExportReimbursement(row) {