Merge branch 'feature/develop1.0'

This commit is contained in:
459816669@qq.com 2021-02-27 13:45:44 +08:00
commit 0779f311e0
16 changed files with 428 additions and 289 deletions

View File

@ -52,6 +52,10 @@
<td><img src="https://qimetons.oss-cn-beijing.aliyuncs.com/de48282f792d4300ba26b7a397464d71.png"/></td>
<td><img src="https://qimetons.oss-cn-beijing.aliyuncs.com/952eaddf26164feaae13ec9ffdbeab35.png"/></td>
</tr>
<tr>
<td><img src="https://qimetons.oss-cn-beijing.aliyuncs.com/593f9a39070b4a5f879b91d94c6cc65e.png"/></td>
<td><img src="https://qimetons.oss-cn-beijing.aliyuncs.com/75db4a86e2224be7bdfd3de6e6cce43b.png"/></td>
</tr>
<tr>
<td><img src="https://qimetons.oss-cn-beijing.aliyuncs.com/416ffa7c1f1f42f8807a24dc2e63a08d.png"/></td>
<td><img src="https://qimetons.oss-cn-beijing.aliyuncs.com/0ffee016a6be4d5eb5b5f18a0291353e.png"/></td>
@ -64,7 +68,7 @@ v1.0 2021-2-24 ding-flow首发
- 2.0 抛弃官方设计器用户组使用ding-flow自带用户流程角色。流程角色实现向下兼容即流程某节点配置父角色其父角色下所有子角色都具有流程审批权限
- 3.0 系统自带请假申请和采购单申请采用类form表单提交保存流程资源表。反序列化表单实现流程中取业务数据。接口通用一个接口按照规定格式设计流程即可。
- 4.0 全局监听器抽象设计,实现任务创建时,钉钉消息通知,待办人实时接收消息,及时处理任务。
- 5.0 任务监听器抽象设计,满足各种节点自定义业务需求,按照各种开发即可。
- 5.0 任务监听器抽象设计,满足各种节点自定义业务需求,按照规则开发即可。
- 6.0 系统创建用户和部门,同步到钉钉用户和部门。实现钉钉移动化办公。
- 7.0 钉钉修改用户和部门,系统异步监听数据变化,实时修改系统数据。实现钉钉和系统数据同步。
- 8.0 账单管理,导出支付宝,微信账单。一键导入系统,系统轻松管理账单数据,日常消费明了清晰。
@ -76,15 +80,15 @@ v1.1 2021-2-26
## 未来规划
- 1.0 角色与钉钉打通
- 2.0 流程表单设计
- 3.0 钉钉工作流与系统工作流打通(让流程移动化)
- 4.0 钉钉同步数据失败后,手工重试
- 5.0 记录消息通知轨迹
- 6.0 钉钉流程和系统流程打通,让流程移动化
- 1.0 流程表单设计
- 2.0 钉钉工作流与系统工作流打通,让流程移动化
- 3.0 钉钉同步数据失败后,手工重试
- 4.0 记录消息通知轨迹
- 5.0 钉钉机器人集成
## 交流群
- QQ群: 577813338 欢迎入群讨论,我们的口号:借助钉钉,致力于流程,让流程更简单
- QQ群: 577813338
- 欢迎入群讨论,我们的口号:**借助钉钉,致力于流程,让流程更简单**
## 我有话说
开源离不开您的参与、支持与鼓励。开源不易如果您觉得项目对您有帮助请您动动小手star一下也是对作者的最大帮助。

View File

@ -1,14 +1,12 @@
package com.snow.web.controller.common;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fasterxml.uuid.impl.UUIDUtil;
import com.snow.common.utils.uuid.IdUtils;
import com.snow.common.utils.uuid.UUID;
import com.snow.common.config.Global;
import com.snow.common.constant.Constants;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.utils.StringUtils;
import com.snow.common.utils.file.FileUtils;
import com.snow.framework.storage.StorageService;
import com.snow.system.domain.SysFile;
import org.apache.logging.log4j.core.util.UuidUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -17,13 +15,9 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.snow.common.config.Global;
import com.snow.common.config.ServerConfig;
import com.snow.common.constant.Constants;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.utils.StringUtils;
import com.snow.common.utils.file.FileUploadUtils;
import com.snow.common.utils.file.FileUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 通用请求处理
@ -35,8 +29,7 @@ public class CommonController
{
private static final Logger log = LoggerFactory.getLogger(CommonController.class);
@Autowired
private ServerConfig serverConfig;
@Autowired
private StorageService storageService;

View File

@ -1,8 +1,11 @@
package com.snow.web.controller.dingtalk;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dingtalk.oapi.lib.aes.DingTalkEncryptor;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.snow.common.constant.Constants;
import com.snow.common.enums.DingTalkListenerType;
import com.snow.dingtalk.common.EventNameEnum;
@ -11,12 +14,16 @@ import com.snow.dingtalk.sync.SyncSysInfoFactory;
import com.snow.system.domain.DingtalkCallBack;
import com.snow.system.service.impl.DingtalkCallBackServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.List;
import java.util.Map;
/**
* @author qimingjin
@ -85,4 +92,75 @@ public class DingTalkCallBackController {
return Constants.CALL_BACK_FAIL_RETURN;
}
}
/**
* 接收钉钉dingFlow机器人消息
* @return
*/
@PostMapping(value = "/dingFlowRobot")
public void dingFlowRobotCallback(@RequestBody(required = false) JSONObject body){
log.info("dingFlowRobot"+body);
//todo 校验是否是钉钉群发送过来的消息
}
/**
* 测试给钉钉群发消息
*
* @param args
*/
public static void main(String[] args){
try {
//钉钉机器人地址配置机器人的webhook
String dingUrl = "";
//是否通知所有人
boolean isAtAll = false;
//通知具体人的手机号码列表
List<String> mobileList = Lists.newArrayList();
//钉钉机器人消息内容
String content ="TEST"+ "小哥,你好!";
//组装请求内容
String reqStr = buildReqStr(content, isAtAll, mobileList);
//推送消息http请求
String result = HttpUtil.post(dingUrl, reqStr);
System.out.println("result == " + result);
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 组装请求报文
* @param content
* @return
*/
private static String buildReqStr(String content, boolean isAtAll, List<String> mobileList) {
//消息内容
Map<String, String> contentMap = Maps.newHashMap();
contentMap.put("content", content);
//通知人
Map<String, Object> atMap = Maps.newHashMap();
//1.是否通知所有人
atMap.put("isAtAll", isAtAll);
//2.通知具体人的手机号码列表
atMap.put("atMobiles", mobileList);
Map<String, Object> reqMap = Maps.newHashMap();
reqMap.put("msgtype", "text");
reqMap.put("text", contentMap);
reqMap.put("at", atMap);
return JSON.toJSONString(reqMap);
}
}

View File

@ -28,6 +28,10 @@ public class SyncInitDataController {
@Autowired
private SysDeptServiceImpl sysDeptService;
/**
* 钉钉部门数据初始化到系统
*/
@GetMapping("/initDepartment")
public void initDepartment(){
List<OapiDepartmentListResponse.Department> dingTalkDepartmentList = departmentService.getDingTalkDepartmentList();

View File

@ -68,6 +68,7 @@ public class FlowController extends BaseController {
* @return
*/
@PostMapping("/finishTask")
@RequiresPermissions("system:flow:finishTask")
@ResponseBody
@RepeatSubmit
public AjaxResult finishTask(CompleteTaskDTO completeTaskDTO)
@ -89,8 +90,9 @@ public class FlowController extends BaseController {
return prefix+"/myTask";
}
/**
* 获取我的待办
* 获取我的待办列表
*/
@RequiresPermissions("flow:get:todoList")
@PostMapping("/findTasksByUserId")
@ -101,6 +103,7 @@ public class FlowController extends BaseController {
PageModel<TaskVO> taskList = flowableTaskService.findTasksByUserId(String.valueOf(userId), taskBaseDTO);
return getFlowDataTable(taskList);
}
/**
* 获取所有节点
* @param processInstanceId
@ -163,7 +166,7 @@ public class FlowController extends BaseController {
}
/**
* 我参与的任务
* 跳转我的已办
* @return
*/
@RequiresPermissions("flow:process:getMyTakePartInProcess")

View File

@ -52,7 +52,7 @@ public class FlowUserController extends BaseController {
}
/**
* 获取用户列表
* 获取用户列表
* @param filter
*/
@GetMapping(value = "/rest/getUserGroupList")

View File

@ -109,7 +109,11 @@ public class SysIndexController extends BaseController
@GetMapping("/system/main")
public String main(ModelMap mmap)
{
SysUser sysUser = ShiroUtils.getSysUser();
mmap.put("version", Global.getVersion());
//流程概况
FlowGeneralSituationVO flowGeneralSituation = flowableService.getFlowGeneralSituation(String.valueOf(sysUser.getUserId()));
mmap.put("flowGeneralSituation",flowGeneralSituation);
return "main_v1";
}

View File

@ -1,5 +1,7 @@
package com.snow.web.controller.system;
import com.snow.framework.storage.StorageService;
import com.snow.system.domain.SysFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -42,6 +44,9 @@ public class SysProfileController extends BaseController
@Autowired
private SysPasswordService passwordService;
@Autowired
private StorageService storageService;
/**
* 个人信息
*/
@ -154,8 +159,8 @@ public class SysProfileController extends BaseController
{
if (!file.isEmpty())
{
String avatar = FileUploadUtils.upload(Global.getAvatarPath(), file);
currentUser.setAvatar(avatar);
SysFile store = storageService.store(file.getInputStream(), file.getSize(), file.getContentType(), file.getOriginalFilename());
currentUser.setAvatar(store.getUrl());
if (userService.updateUserInfo(currentUser) > 0)
{
ShiroUtils.setSysUser(userService.selectUserById(currentUser.getUserId()));

View File

@ -6,9 +6,9 @@ spring:
druid:
# 主库数据源
master:
url: jdbc:mysql://rm-bp1j1554xv1qs04295o.mysql.rds.aliyuncs.com:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: cloud_root
password: Jin!152377
url: jdbc:mysql://127.0.0.1:3306/snow?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: root
# 从库数据源
slave:
# 从数据源开关/默认关闭
@ -31,6 +31,7 @@ spring:
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -19,56 +19,62 @@
<div class="col-sm-3">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label label-success pull-right"></span>
<h5>收入</h5>
<!-- <span class="label label-success pull-right">月</span>-->
<h5>待办任务数</h5>
</div>
<div class="ibox-content">
<h1 class="no-margins">40 886,200</h1>
<div class="stat-percent font-bold text-success">98% <i class="fa fa-bolt"></i>
</div>
<small>总收入</small>
<h1 class="no-margins" th:text="${flowGeneralSituation.todoTaskNum}"></h1>
<div class="stat-percent font-bold text-success">
<i class="fa fa-level-down"></i>
<a onclick="toDoMyTask()">去完成</a>
</div>
<!--<small>总收入</small>-->
</div>
</div>
</div>
<div class="col-sm-3">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label label-info pull-right">全年</span>
<h5>订单</h5>
<!-- <span class="label label-info pull-right">全年</span>-->
<h5>已办任务数</h5>
</div>
<div class="ibox-content">
<h1 class="no-margins">275,800</h1>
<div class="stat-percent font-bold text-info">20% <i class="fa fa-level-up"></i>
<h1 class="no-margins" th:text="${flowGeneralSituation.doneTaskNum}"></h1>
<div class="stat-percent font-bold text-info">
<i class="fa fa-level-up"></i>
<a onclick="toMyTakePartInProcess()">详情</a>
</div>
<small>新订单</small>
<!--<small>新订单</small>-->
</div>
</div>
</div>
<div class="col-sm-3">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label label-primary pull-right">今天</span>
<h5>访客</h5>
<!-- <span class="label label-primary pull-right">今天</span>-->
<h5>发起流程数</h5>
</div>
<div class="ibox-content">
<h1 class="no-margins">106,120</h1>
<div class="stat-percent font-bold text-navy">44% <i class="fa fa-level-up"></i>
<h1 class="no-margins" th:text="${flowGeneralSituation.myStartProcessInstanceNum}"></h1>
<div class="stat-percent font-bold text-navy">
<i class="fa fa-level-up"></i>
</div>
<small>新访客</small>
<!-- <small>新访客</small>-->
</div>
</div>
</div>
<div class="col-sm-3">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label label-danger pull-right">最近一个月</span>
<h5>活跃用户</h5>
<!--<span class="label label-danger pull-right">最近一个月</span>-->
<h5>任务超时数3天</h5>
</div>
<div class="ibox-content">
<h1 class="no-margins">80,600</h1>
<div class="stat-percent font-bold text-danger">38% <i class="fa fa-level-down"></i>
<h1 class="no-margins" th:text="${flowGeneralSituation.threeTodoTaskNum}"></h1>
<div class="stat-percent font-bold text-danger">
<i class="fa fa-level-down"></i>
</div>
<small>12月</small>
<!-- <small>12月</small>-->
</div>
</div>
</div>
@ -198,6 +204,16 @@
var preViewUrl=prefixFlow+'/toFinishTask?taskId='+taskId;
$.modal.openTab("审批", preViewUrl);
}
function toDoMyTask() {
var preViewUrl=prefixFlow+'/toDoMyTask?';
$.modal.openTab("我的待办任务", preViewUrl);
}
function toMyTakePartInProcess() {
var preViewUrl=prefixFlow+'/toMyTakePartInProcess?';
$.modal.openTab("我的已办任务", preViewUrl);
}
</script>
</body>
</html>

View File

@ -4,258 +4,258 @@
<th:block th:include="include :: header('修改用户头像')" />
<th:block th:include="include :: cropper-css" />
<style type='text/css'>
/* avator css start */
.container {
margin: 10px 5px 5px 5px;
}
.action {
padding: 5px 0px;
}
.cropped {
width: 200px;
height: 345px;
border: 1px #ddd solid;
box-shadow: 0px 0px 12px #ddd;
}
.img-preview {
border-radius: 50%;
box-shadow: 0px 0px 12px #7e7e7e;
display: inline-block;
}
.preview-box {
text-align: center;
margin: 0px auto;
margin-top: 10px;
color: #bbb;
}
.preview-md {
width: 128px;
height: 128px;
}
.preview-sm {
width: 96px;
height: 96px;
}
.preview-xs {
width: 64px;
height: 64px;
}
.imageBox {
border: 1px solid #aaa;
overflow: hidden;
cursor: move;
box-shadow: 4px 4px 12px #B0B0B0;
margin: 0px auto;
}
.btn-custom {
float: right;
width: 46px;
display: inline-block;
margin-bottom: 10px;
height: 37px;
line-height: 37px;
font-size: 14px;
color: #FFFFFF;
margin: 0px 2px;
background-color: #f38e81;
border-radius: 3px;
text-decoration: none;
cursor: pointer;
box-shadow: 0px 0px 5px #B0B0B0;
border: 0px #fff solid;
}
/*选择文件上传*/
.new-contentarea {
width: 165px;
overflow: hidden;
margin: 0 auto;
position: relative;
float: left;
}
.new-contentarea label {
width: 100%;
height: 100%;
display: block;
}
.new-contentarea input[type=file] {
width: 188px;
height: 60px;
background: #333;
margin: 0 auto;
position: absolute;
right: 50%;
margin-right: -94px;
top: 0;
right/*\**/: 0px\9;
margin-right/*\**/: 0px\9;
width/*\**/: 10px\9;
opacity: 0;
filter: alpha(opacity=0);
z-index: 2;
}
a.upload-img {
width: 165px;
display: inline-block;
margin-bottom: 10px;
height: 37px;
line-height: 37px;
font-size: 14px;
color: #FFFFFF;
background-color: #f38e81;
border-radius: 3px;
text-decoration: none;
cursor: pointer;
border: 0px #fff solid;
box-shadow: 0px 0px 5px #B0B0B0;
}
a.upload-img:hover {
background-color: #ec7e70;
}
.tc {
text-align: center;
}
/* avator css end */
/* avator css start */
.container {
margin: 10px 5px 5px 5px;
}
.action {
padding: 5px 0px;
}
.cropped {
width: 200px;
border: 1px #ddd solid;
box-shadow: 0px 0px 12px #ddd;
}
.img-preview {
border-radius: 50%;
box-shadow: 0px 0px 12px #7e7e7e;
display: inline-block;
}
.preview-box {
text-align: center;
margin: 0px auto;
margin-top: 10px;
color: #bbb;
}
.preview-md {
width: 128px;
height: 128px;
}
.preview-sm {
width: 96px;
height: 96px;
}
.preview-xs {
width: 64px;
height: 64px;
}
.imageBox {
border: 1px solid #aaa;
overflow: hidden;
cursor: move;
box-shadow: 4px 4px 12px #B0B0B0;
margin: 0px auto;
}
.btn-custom {
float: right;
width: 46px;
display: inline-block;
margin-bottom: 10px;
height: 37px;
line-height: 37px;
font-size: 14px;
color: #FFFFFF;
margin: 0px 2px;
background-color: #f38e81;
border-radius: 3px;
text-decoration: none;
cursor: pointer;
box-shadow: 0px 0px 5px #B0B0B0;
border: 0px #fff solid;
}
/*选择文件上传*/
.new-contentarea {
width: 165px;
overflow: hidden;
margin: 0 auto;
position: relative;
float: left;
}
.new-contentarea label {
width: 100%;
height: 100%;
display: block;
}
.new-contentarea input[type=file] {
width: 188px;
height: 60px;
background: #333;
margin: 0 auto;
position: absolute;
right: 50%;
margin-right: -94px;
top: 0;
right/*\**/: 0px\9;
margin-right/*\**/: 0px\9;
width/*\**/: 10px\9;
opacity: 0;
filter: alpha(opacity=0);
z-index: 2;
}
a.upload-img {
width: 165px;
display: inline-block;
margin-bottom: 10px;
height: 37px;
line-height: 37px;
font-size: 14px;
color: #FFFFFF;
background-color: #f38e81;
border-radius: 3px;
text-decoration: none;
cursor: pointer;
border: 0px #fff solid;
box-shadow: 0px 0px 5px #B0B0B0;
}
a.upload-img:hover {
background-color: #ec7e70;
}
.tc {
text-align: center;
}
/* avator css end */
</style>
</head>
<body class="white-bg">
<div class="row container">
<div class="col-md-10">
<div class="imageBox">
<img id="avatar" th:src="(${user.avatar} == '') ? @{/img/profile.jpg} : @{${user.avatar}}" >
</div>
<div class="action">
<div class="new-contentarea tc">
<a href="javascript:void(0)" class="upload-img"><label for="inputImage">上传图像</label> </a>
<input type="file" name="avatar" id="inputImage" accept="image/*"/>
</div>
<button type="button" class="btn-custom" data-method="zoom" data-option="0.1"><i class="fa fa-search-plus"></i></button>
<button type="button" class="btn-custom" data-method="zoom" data-option="-0.1"><i class="fa fa-search-minus"></i></button>
<button type="button" class="btn-custom" data-method="rotate" data-option="-45"><i class="fa fa-rotate-left"></i></button>
<button type="button" class="btn-custom" data-method="rotate" data-option="45"><i class="fa fa-rotate-right"></i></button>
<button type="button" class="btn-custom" data-method="scaleX" data-option="-1"><i class="fa fa-arrows-h"></i></button>
<button type="button" class="btn-custom" data-method="scaleY" data-option="-1"><i class="fa fa-arrows-v"></i></button>
<button type="button" class="btn-custom" data-method="reset"><i class="fa fa-refresh"></i></button>
</div>
<div class="row container">
<div class="col-md-10">
<div class="imageBox">
<img id="avatar" th:src="(${#strings.isEmpty(user.avatar)}) ? @{/img/profile.jpg} : @{${user.avatar}}" th:onerror="'this.src=\'' + @{'/img/profile.jpg'} + '\''">
</div>
<div class="col-md-2">
<div class="cropped">
<div class="preview-box">
<div class="img-preview preview-xs"></div>
</div>
<div class="preview-box">
<div class="img-preview preview-sm"></div>
</div>
<div class="preview-box">
<div class="img-preview preview-md"></div>
</div>
<div class="action">
<div class="new-contentarea tc">
<a href="javascript:void(0)" class="upload-img"><label for="inputImage">上传图像</label> </a>
<input type="file" name="avatar" id="inputImage" accept="image/*"/>
</div>
<button type="button" class="btn-custom" data-method="zoom" data-option="0.1"><i class="fa fa-search-plus"></i></button>
<button type="button" class="btn-custom" data-method="zoom" data-option="-0.1"><i class="fa fa-search-minus"></i></button>
<button type="button" class="btn-custom" data-method="rotate" data-option="-45"><i class="fa fa-rotate-left"></i></button>
<button type="button" class="btn-custom" data-method="rotate" data-option="45"><i class="fa fa-rotate-right"></i></button>
<button type="button" class="btn-custom" data-method="scaleX" data-option="-1"><i class="fa fa-arrows-h"></i></button>
<button type="button" class="btn-custom" data-method="scaleY" data-option="-1"><i class="fa fa-arrows-v"></i></button>
<button type="button" class="btn-custom" data-method="reset"><i class="fa fa-refresh"></i></button>
</div>
</div>
<div class="col-md-2">
<div class="cropped">
<div class="preview-box">
<div class="img-preview preview-xs"></div>
</div>
<div class="preview-box">
<div class="img-preview preview-sm"></div>
</div>
<div class="preview-box">
<div class="img-preview preview-md"></div>
</div>
</div>
</div>
</div>
<th:block th:include="include :: footer" />
<th:block th:include="include :: cropper-js" />
<script type="text/javascript">
var cropper;
var croppable = false;
$(window).load(function() {
var image = document.getElementById('avatar');
cropper = new Cropper(image, {
aspectRatio: 1,
viewMode: 1,
autoCropArea: 0.9,
preview: '.img-preview',
ready: function () {
croppable = true;
}
})
var cropper;
var croppable = false;
$(window).load(function() {
var image = document.getElementById('avatar');
cropper = new Cropper(image, {
aspectRatio: 1,
viewMode: 1,
autoCropArea: 0.9,
preview: '.img-preview',
ready: function () {
croppable = true;
}
})
$('#inputImage').on('change', function() {
var reader = new FileReader();
var file = $('#inputImage')[0].files[0];
if (/^image\/\w+$/.test(file.type)) {
reader.onload = function(e) {
if(croppable){
cropper.replace(e.target.result)
}
}
reader.readAsDataURL(this.files[0]);
} else {
$.modal.alertWarning('请选择一个图片文件。');
}
});
$('#inputImage').on('change', function() {
var reader = new FileReader();
var file = $('#inputImage')[0].files[0];
if (/^image\/\w+$/.test(file.type)) {
reader.onload = function(e) {
if(croppable){
cropper.replace(e.target.result)
}
}
reader.readAsDataURL(this.files[0]);
} else {
$.modal.alertWarning('请选择一个图片文件。');
}
});
$('.btn-custom').on('click',function (e) {
if (!croppable) {
$.modal.alertWarning("裁剪框加载中,请稍后...");
return;
}
var data = {
method: $(this).data('method'),
option: $(this).data('option') || undefined,
};
var result = cropper[data.method](data.option, data.secondOption);
if(['scaleX','scaleY'].indexOf(data.method) !== -1){
$(this).data('option', -data.option)
}
})
});
function submitHandler() {
if (!croppable) {
$.modal.alertWarning("裁剪框加载中,请稍后...");
return
}
cropper.getCroppedCanvas().toBlob(function(img) {
var formdata = new FormData();
formdata.append("avatarfile", img);
$.ajax({
url: ctx + "system/user/profile/updateAvatar",
data: formdata,
type: "post",
processData: false,
contentType: false,
success: function(result) {
$.operate.saveSuccess(result);
$('.btn-custom').on('click',function (e) {
if (!croppable) {
$.modal.alertWarning("裁剪框加载中,请稍后...");
return;
}
var data = {
method: $(this).data('method'),
option: $(this).data('option') || undefined,
};
var result = cropper[data.method](data.option, data.secondOption);
if(['scaleX','scaleY'].indexOf(data.method) !== -1){
$(this).data('option', -data.option)
}
})
});
}
$(window).resize(function() {
$('.imageBox').height($(window).height() - 80);
}).resize();
if (!HTMLCanvasElement.prototype.toBlob) {
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
value: function(callback, type, quality) {
var canvas = this;
setTimeout(function() {
var binStr = atob(canvas.toDataURL(type, quality).split(',')[1]);
var len = binStr.length;
var arr = new Uint8Array(len);
for (var i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i);
}
callback(new Blob([arr], {
type: type || 'image/png'
}));
});
function submitHandler() {
if (!croppable) {
$.modal.alertWarning("裁剪框加载中,请稍后...");
return
}
});
}
cropper.getCroppedCanvas().toBlob(function(img) {
var formdata = new FormData();
formdata.append("avatarfile", img);
$.ajax({
url: ctx + "system/user/profile/updateAvatar",
data: formdata,
type: "post",
processData: false,
contentType: false,
success: function(result) {
$.operate.saveSuccess(result);
}
})
});
}
$(window).resize(function() {
$('.imageBox').height($(window).height() - 80);
$('.cropped').height($(window).height() - 40);
}).resize();
if (!HTMLCanvasElement.prototype.toBlob) {
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
value: function(callback, type, quality) {
var canvas = this;
setTimeout(function() {
var binStr = atob(canvas.toDataURL(type, quality).split(',')[1]);
var len = binStr.length;
var arr = new Uint8Array(len);
for (var i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i);
}
callback(new Blob([arr], {
type: type || 'image/png'
}));
});
}
});
}
</script>
</body>
</html>

View File

@ -64,7 +64,7 @@ public class SendMessageEventLister extends AbstractEventListener {
protected void taskCreated(FlowableEngineEntityEvent event) {
//任务创建可发送短信邮件通知接收人(代办人)
log.info("ManagerTaskEventListener----taskCreated任务创建监听{}",JSON.toJSONString(event));
// sendDingTalkMessage(event);
sendDingTalkMessage(event);
//todo 邮件通知
}

View File

@ -449,6 +449,7 @@ public class FlowableServiceImpl implements FlowableService {
public ProcessInstance getProcessInstanceById(String id){
return runtimeService.createProcessInstanceQuery()
.processInstanceId(id)
.includeProcessVariables()
.singleResult();
}
@ -669,6 +670,8 @@ public class FlowableServiceImpl implements FlowableService {
historicProcessInstanceQuery.includeProcessVariables();
return historicProcessInstanceQuery;
}
/**
* 赋值ProcessInstanceVOs
* @param processInstanceVOS
@ -698,6 +701,7 @@ public class FlowableServiceImpl implements FlowableService {
t.setStartUserName(sysUser.getUserName());
});
}
@Override
public PageModel<HistoricTaskInstanceVO> getHistoricTaskInstance(HistoricTaskInstanceDTO historicTaskInstanceDTO) {
HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();

View File

@ -0,0 +1,26 @@
package com.snow.framework.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @program: snow
* @description 允许跨域
* @author: 没用的阿吉
* @create: 2021-02-27 13:28
**/
@Configuration
public class CrossConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}

View File

@ -282,6 +282,7 @@ public class ShiroConfig
filterChainDefinitionMap.put("/modeler/**", "anon");
filterChainDefinitionMap.put("/captcha/captchaImage**", "anon");
filterChainDefinitionMap.put("/dingTalk/dingTalkCallBack", "anon");
filterChainDefinitionMap.put("/dingTalk/dingFlowRobot", "anon");
// 退出 logout地址shiro去清除session
filterChainDefinitionMap.put("/logout", "logout");
// 不需要拦截的访问