Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
amos-boot-biz
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
项目统一框架
amos-boot-biz
Commits
6dc4c21a
Commit
6dc4c21a
authored
Sep 27, 2021
by
suhuiguang
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'developer' of
http://172.16.10.76/moa/amos-boot-biz
into developer
parents
45d38a63
51609e2a
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
87 additions
and
45 deletions
+87
-45
WorkFlowEnum.java
.../com/yeejoin/amos/boot/biz/common/enums/WorkFlowEnum.java
+41
-0
WorkflowExcuteServiceImpl.java
...ot/biz/common/service/impl/WorkflowExcuteServiceImpl.java
+46
-45
No files found.
amos-boot-biz-common/src/main/java/com/yeejoin/amos/boot/biz/common/enums/WorkFlowEnum.java
0 → 100644
View file @
6dc4c21a
package
com
.
yeejoin
.
amos
.
boot
.
biz
.
common
.
enums
;
import
lombok.AllArgsConstructor
;
@AllArgsConstructor
public
enum
WorkFlowEnum
{
BUSINESSKEY
(
"businessKey"
,
"自动生成的ID"
),
processDefinitionKey
(
"processDefinitionKey"
,
"流程定义的KEY"
),
制定计划内容
(
"制定计划+内容"
,
"流程节点的特殊值"
),
现场确认
(
"现场确认"
,
"流程节点的特殊值"
),
CONDITION
(
"conditioncondition"
,
""
),
DATA
(
"data"
,
"data"
),
ID
(
"id"
,
"id"
),
CHECKFLAG
(
"checkFlag"
,
"自定义是否具有执行权限的标识符"
),
TASKID
(
"taskId"
,
"可执行任务的主键"
),
GROUP
(
"group"
,
"角色组"
),
GROUPID
(
"groupId"
,
"角色组的key"
),
GROUPNAME
(
"groupName"
,
"角色组的key"
),
NAME
(
"name"
,
"任务节点的key"
),
ASSIGN
(
"assign"
,
"角色执行人key"
);
private
String
code
;
//对应菜单组件名称
private
String
desc
;
//描述
public
String
getCode
()
{
return
code
;
}
public
void
setCode
(
String
code
)
{
this
.
code
=
code
;
}
public
String
getDesc
()
{
return
desc
;
}
public
void
setDesc
(
String
desc
)
{
this
.
desc
=
desc
;
}
}
amos-boot-biz-common/src/main/java/com/yeejoin/amos/boot/biz/common/service/impl/WorkflowExcuteServiceImpl.java
View file @
6dc4c21a
...
@@ -16,6 +16,7 @@ import org.springframework.transaction.annotation.Transactional;
...
@@ -16,6 +16,7 @@ import org.springframework.transaction.annotation.Transactional;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONObject
;
import
com.alibaba.fastjson.JSONObject
;
import
com.yeejoin.amos.boot.biz.common.bo.ReginParams
;
import
com.yeejoin.amos.boot.biz.common.bo.ReginParams
;
import
com.yeejoin.amos.boot.biz.common.enums.WorkFlowEnum
;
import
com.yeejoin.amos.boot.biz.common.service.IWorkflowExcuteService
;
import
com.yeejoin.amos.boot.biz.common.service.IWorkflowExcuteService
;
import
com.yeejoin.amos.boot.biz.common.workflow.feign.WorkflowFeignService
;
import
com.yeejoin.amos.boot.biz.common.workflow.feign.WorkflowFeignService
;
...
@@ -30,25 +31,25 @@ public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {
...
@@ -30,25 +31,25 @@ public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {
public
String
startAndComplete
(
String
key
,
String
condition
)
throws
Exception
{
public
String
startAndComplete
(
String
key
,
String
condition
)
throws
Exception
{
JSONObject
body
=
new
JSONObject
();
JSONObject
body
=
new
JSONObject
();
String
businessKey
=
buildOrderNo
();
String
businessKey
=
buildOrderNo
();
body
.
put
(
"businessKey"
,
businessKey
);
body
.
put
(
WorkFlowEnum
.
BUSINESSKEY
.
getCode
()
,
businessKey
);
body
.
put
(
"processDefinitionKey"
,
key
);
body
.
put
(
WorkFlowEnum
.
processDefinitionKey
.
getCode
()
,
key
);
JSONObject
jsonObject
=
workflowFeignService
.
startByVariable
(
body
);
JSONObject
jsonObject
=
workflowFeignService
.
startByVariable
(
body
);
if
(
jsonObject
==
null
||
jsonObject
.
getJSONObject
(
"data"
)
==
null
)
{
if
(
jsonObject
==
null
||
jsonObject
.
getJSONObject
(
WorkFlowEnum
.
DATA
.
getCode
()
)
==
null
)
{
throw
new
RuntimeException
(
"启动流程失败"
);
throw
new
RuntimeException
(
"启动流程失败"
);
}
}
if
(
jsonObject
!=
null
)
{
if
(
jsonObject
!=
null
)
{
JSONObject
instance
=
jsonObject
.
getJSONObject
(
"data"
);
JSONObject
instance
=
jsonObject
.
getJSONObject
(
WorkFlowEnum
.
DATA
.
getCode
()
);
if
(!
excuteTask
(
instance
.
getString
(
"id"
),
condition
))
{
if
(!
excuteTask
(
instance
.
getString
(
WorkFlowEnum
.
ID
.
getCode
()
),
condition
))
{
throw
new
RuntimeException
(
"初始执行任务失败"
);
throw
new
RuntimeException
(
"初始执行任务失败"
);
}
}
}
}
return
jsonObject
.
getJSONObject
(
"data"
).
getString
(
"id"
);
return
jsonObject
.
getJSONObject
(
WorkFlowEnum
.
DATA
.
getCode
()).
getString
(
WorkFlowEnum
.
ID
.
getCode
()
);
}
}
@Override
@Override
public
boolean
checkTaskAuth
(
String
processInstanceId
,
ReginParams
userInfo
)
{
public
boolean
checkTaskAuth
(
String
processInstanceId
,
ReginParams
userInfo
)
{
Map
<
String
,
Object
>
map
=
checkTaskAuthMap
(
processInstanceId
,
userInfo
);
Map
<
String
,
Object
>
map
=
checkTaskAuthMap
(
processInstanceId
,
userInfo
);
return
Boolean
.
parseBoolean
(
map
.
get
(
"checkFlag"
).
toString
());
return
Boolean
.
parseBoolean
(
map
.
get
(
WorkFlowEnum
.
CHECKFLAG
.
getCode
()
).
toString
());
}
}
@Override
@Override
...
@@ -57,51 +58,51 @@ public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {
...
@@ -57,51 +58,51 @@ public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {
String
currentLoginUserRole
=
userInfo
.
getRole
().
getRoleName
();
String
currentLoginUserRole
=
userInfo
.
getRole
().
getRoleName
();
String
currentLoginUserId
=
userInfo
.
getUserModel
().
getUserId
();
String
currentLoginUserId
=
userInfo
.
getUserModel
().
getUserId
();
Map
<
String
,
Object
>
map
=
new
HashMap
<
String
,
Object
>();
Map
<
String
,
Object
>
map
=
new
HashMap
<
String
,
Object
>();
map
.
put
(
"checkFlag"
,
false
);
map
.
put
(
WorkFlowEnum
.
CHECKFLAG
.
getCode
()
,
false
);
JSONObject
teskObject
=
workflowFeignService
.
getTaskList
(
processInstanceId
);
JSONObject
teskObject
=
workflowFeignService
.
getTaskList
(
processInstanceId
);
if
(
ObjectUtils
.
isNotEmpty
(
teskObject
.
getJSONArray
(
"data"
)))
{
if
(
ObjectUtils
.
isNotEmpty
(
teskObject
.
getJSONArray
(
WorkFlowEnum
.
DATA
.
getCode
()
)))
{
JSONArray
taskDetailArray
=
teskObject
.
getJSONArray
(
"data"
);
JSONArray
taskDetailArray
=
teskObject
.
getJSONArray
(
WorkFlowEnum
.
DATA
.
getCode
()
);
for
(
Object
obj
:
taskDetailArray
)
{
for
(
Object
obj
:
taskDetailArray
)
{
JSONObject
detail
=
JSONObject
.
parseObject
(
JSONObject
.
toJSONString
(
obj
));
JSONObject
detail
=
JSONObject
.
parseObject
(
JSONObject
.
toJSONString
(
obj
));
if
(
"制定计划+内容"
.
equals
(
detail
.
getString
(
"name"
))
||
"现场确认"
.
equals
(
detail
.
getString
(
"name"
)))
{
if
(
WorkFlowEnum
.
制定计划内容
.
getCode
().
equals
(
detail
.
getString
(
WorkFlowEnum
.
NAME
.
getCode
()))
||
WorkFlowEnum
.
现场确认
.
getCode
().
equals
(
detail
.
getString
(
WorkFlowEnum
.
NAME
.
getCode
()
)))
{
String
groupName
=
getFristFlowDetail
(
processInstanceId
);
String
groupName
=
getFristFlowDetail
(
processInstanceId
);
if
(
StringUtils
.
isBlank
(
groupName
))
{
if
(
StringUtils
.
isBlank
(
groupName
))
{
return
map
;
return
map
;
}
}
map
.
put
(
"taskId"
,
detail
.
getString
(
"id"
));
map
.
put
(
WorkFlowEnum
.
TASKID
.
getCode
(),
detail
.
getString
(
WorkFlowEnum
.
ID
.
getCode
()
));
map
.
put
(
"checkFlag"
,
true
);
map
.
put
(
WorkFlowEnum
.
CHECKFLAG
.
getCode
()
,
true
);
map
.
put
(
"name"
,
detail
.
getString
(
"name"
));
map
.
put
(
WorkFlowEnum
.
NAME
.
getCode
(),
detail
.
getString
(
WorkFlowEnum
.
NAME
.
getCode
()
));
return
map
;
return
map
;
}
}
JSONObject
taskGroupNameObject
=
workflowFeignService
.
getTaskGroupName
(
detail
.
getString
(
"id"
));
JSONObject
taskGroupNameObject
=
workflowFeignService
.
getTaskGroupName
(
detail
.
getString
(
WorkFlowEnum
.
ID
.
getCode
()
));
// 获取流程中原本设置的当前节点的执行权限
// 获取流程中原本设置的当前节点的执行权限
JSONArray
taskGroupNameDetail
=
taskGroupNameObject
.
getJSONArray
(
"data"
);
JSONArray
taskGroupNameDetail
=
taskGroupNameObject
.
getJSONArray
(
WorkFlowEnum
.
DATA
.
getCode
()
);
// 如果拿不到当前任务的执行角色,再去获取当前任务有没有默认的执行人,如果都没有则返回校验失败
// 如果拿不到当前任务的执行角色,再去获取当前任务有没有默认的执行人,如果都没有则返回校验失败
if
(
ObjectUtils
.
isEmpty
(
taskGroupNameDetail
))
{
if
(
ObjectUtils
.
isEmpty
(
taskGroupNameDetail
.
getJSONObject
(
0
)
))
{
JSONObject
taskAssignObject
=
workflowFeignService
.
getTaskAssign
(
detail
.
getString
(
"id"
));
JSONObject
taskAssignObject
=
workflowFeignService
.
getTaskAssign
(
detail
.
getString
(
WorkFlowEnum
.
ID
.
getCode
()
));
String
assignUser
=
taskAssignObject
.
getJSONObject
(
"data"
).
getString
(
"assignee"
);
String
assignUser
=
taskAssignObject
.
getJSONObject
(
WorkFlowEnum
.
DATA
.
getCode
()).
getString
(
WorkFlowEnum
.
ASSIGN
.
getCode
()
);
if
(
StringUtils
.
isNotBlank
(
assignUser
))
{
if
(
StringUtils
.
isNotBlank
(
assignUser
))
{
// 如果当前登录人与当前任务的设定人不一定,则直接返回权限校验失败
// 如果当前登录人与当前任务的设定人不一定,则直接返回权限校验失败
if
(!
assignUser
.
contains
(
currentLoginUserId
))
{
if
(!
assignUser
.
contains
(
currentLoginUserId
))
{
return
map
;
return
map
;
}
}
map
.
put
(
"taskId"
,
detail
.
getString
(
"id"
));
map
.
put
(
WorkFlowEnum
.
TASKID
.
getCode
(),
detail
.
getString
(
WorkFlowEnum
.
ID
.
getCode
()
));
map
.
put
(
"checkFlag"
,
true
);
map
.
put
(
WorkFlowEnum
.
CHECKFLAG
.
getCode
()
,
true
);
map
.
put
(
"name"
,
detail
.
getString
(
"name"
));
map
.
put
(
WorkFlowEnum
.
NAME
.
getCode
(),
detail
.
getString
(
WorkFlowEnum
.
NAME
.
getCode
()
));
map
.
put
(
"assign"
,
assignUser
);
map
.
put
(
WorkFlowEnum
.
ASSIGN
.
getCode
()
,
assignUser
);
return
map
;
return
map
;
}
}
continue
;
continue
;
}
}
String
defaultExecutionRoleProcess
=
taskGroupNameDetail
.
getJSONObject
(
0
).
getString
(
"groupId"
);
String
defaultExecutionRoleProcess
=
taskGroupNameDetail
.
getJSONObject
(
0
).
getString
(
WorkFlowEnum
.
GROUPID
.
getCode
()
);
// 判断当前登录人的角色是不是与流程中设置的当前任务节点权限一致,一致则执行,不一致则退出
// 判断当前登录人的角色是不是与流程中设置的当前任务节点权限一致,一致则执行,不一致则退出
if
(!
defaultExecutionRoleProcess
.
equals
(
currentLoginUserRole
))
{
if
(!
defaultExecutionRoleProcess
.
equals
(
currentLoginUserRole
))
{
continue
;
continue
;
}
}
map
.
put
(
"taskId"
,
detail
.
getString
(
"id"
));
map
.
put
(
WorkFlowEnum
.
TASKID
.
getCode
(),
detail
.
getString
(
WorkFlowEnum
.
ID
.
getCode
()
));
map
.
put
(
"checkFlag"
,
true
);
map
.
put
(
WorkFlowEnum
.
CHECKFLAG
.
getCode
()
,
true
);
map
.
put
(
"name"
,
detail
.
getString
(
"name"
));
map
.
put
(
WorkFlowEnum
.
NAME
.
getCode
(),
detail
.
getString
(
WorkFlowEnum
.
NAME
.
getCode
()
));
map
.
put
(
"groupName"
,
currentLoginUserRole
);
map
.
put
(
WorkFlowEnum
.
GROUPNAME
.
getCode
()
,
currentLoginUserRole
);
}
}
}
}
return
map
;
return
map
;
...
@@ -110,13 +111,13 @@ public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {
...
@@ -110,13 +111,13 @@ public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {
@Override
@Override
public
boolean
excuteTask
(
String
procressId
,
String
condition
)
throws
Exception
{
public
boolean
excuteTask
(
String
procressId
,
String
condition
)
throws
Exception
{
HashMap
<
String
,
Object
>
conditionMap
=
new
HashMap
<
String
,
Object
>();
HashMap
<
String
,
Object
>
conditionMap
=
new
HashMap
<
String
,
Object
>();
conditionMap
.
put
(
"condition"
,
condition
);
conditionMap
.
put
(
WorkFlowEnum
.
CONDITION
.
getCode
()
,
condition
);
JSONObject
teskObject
=
workflowFeignService
.
getTaskList
(
procressId
);
JSONObject
teskObject
=
workflowFeignService
.
getTaskList
(
procressId
);
if
(
ObjectUtils
.
isNotEmpty
(
teskObject
))
{
if
(
ObjectUtils
.
isNotEmpty
(
teskObject
))
{
JSONArray
taskDetailArray
=
teskObject
.
getJSONArray
(
"data"
);
JSONArray
taskDetailArray
=
teskObject
.
getJSONArray
(
WorkFlowEnum
.
DATA
.
getCode
()
);
for
(
Object
obj
:
taskDetailArray
)
{
for
(
Object
obj
:
taskDetailArray
)
{
JSONObject
detail
=
JSONObject
.
parseObject
(
JSONObject
.
toJSONString
(
obj
));
JSONObject
detail
=
JSONObject
.
parseObject
(
JSONObject
.
toJSONString
(
obj
));
workflowFeignService
.
pickupAndCompleteTask
(
detail
.
getString
(
"id"
),
conditionMap
);
workflowFeignService
.
pickupAndCompleteTask
(
detail
.
getString
(
WorkFlowEnum
.
ID
.
getCode
()
),
conditionMap
);
}
}
}
}
return
true
;
return
true
;
...
@@ -128,14 +129,14 @@ public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {
...
@@ -128,14 +129,14 @@ public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {
if
(
ObjectUtils
.
isEmpty
(
teskObject
))
{
if
(
ObjectUtils
.
isEmpty
(
teskObject
))
{
throw
new
RuntimeException
(
"设置任务执行人失败, 任务不存在,请检查processInstanceId"
+
processInstanceId
+
"是否正确"
);
throw
new
RuntimeException
(
"设置任务执行人失败, 任务不存在,请检查processInstanceId"
+
processInstanceId
+
"是否正确"
);
}
}
JSONArray
taskDetailArray
=
teskObject
.
getJSONArray
(
"data"
);
JSONArray
taskDetailArray
=
teskObject
.
getJSONArray
(
WorkFlowEnum
.
DATA
.
getCode
()
);
for
(
Object
obj
:
taskDetailArray
)
{
for
(
Object
obj
:
taskDetailArray
)
{
JSONObject
detail
=
JSONObject
.
parseObject
(
JSONObject
.
toJSONString
(
obj
));
JSONObject
detail
=
JSONObject
.
parseObject
(
JSONObject
.
toJSONString
(
obj
));
JSONObject
taskGroupNameObject
=
workflowFeignService
.
getTaskGroupName
(
detail
.
getString
(
"id"
));
JSONObject
taskGroupNameObject
=
workflowFeignService
.
getTaskGroupName
(
detail
.
getString
(
WorkFlowEnum
.
ID
.
getCode
()
));
try
{
try
{
if
(
taskGroupNameObject
.
getJSONArray
(
"data"
)
==
null
if
(
taskGroupNameObject
.
getJSONArray
(
WorkFlowEnum
.
DATA
.
getCode
()
)
==
null
&&
taskGroupNameObject
.
getJSONArray
(
"data"
).
size
()
<
1
)
{
&&
taskGroupNameObject
.
getJSONArray
(
WorkFlowEnum
.
DATA
.
getCode
()
).
size
()
<
1
)
{
workflowFeignService
.
setTaskUser
(
detail
.
getString
(
"id"
),
userId
);
workflowFeignService
.
setTaskUser
(
detail
.
getString
(
WorkFlowEnum
.
ID
.
getCode
()
),
userId
);
}
}
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"设置任务执行人失败"
);
throw
new
RuntimeException
(
"设置任务执行人失败"
);
...
@@ -147,11 +148,11 @@ public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {
...
@@ -147,11 +148,11 @@ public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {
@Override
@Override
public
boolean
CompleteTask
(
String
processInstanceId
,
String
condition
,
ReginParams
userInfo
)
{
public
boolean
CompleteTask
(
String
processInstanceId
,
String
condition
,
ReginParams
userInfo
)
{
Map
<
String
,
Object
>
map
=
checkTaskAuthMap
(
processInstanceId
,
userInfo
);
Map
<
String
,
Object
>
map
=
checkTaskAuthMap
(
processInstanceId
,
userInfo
);
if
(
Boolean
.
parseBoolean
(
map
.
get
(
"checkFlag"
).
toString
()))
{
if
(
Boolean
.
parseBoolean
(
map
.
get
(
WorkFlowEnum
.
CHECKFLAG
.
getCode
()
).
toString
()))
{
HashMap
<
String
,
Object
>
conditionMap
=
new
HashMap
<
String
,
Object
>();
HashMap
<
String
,
Object
>
conditionMap
=
new
HashMap
<
String
,
Object
>();
conditionMap
.
put
(
"condition"
,
condition
);
conditionMap
.
put
(
WorkFlowEnum
.
CONDITION
.
getCode
()
,
condition
);
try
{
try
{
workflowFeignService
.
pickupAndCompleteTask
(
map
.
get
(
"taskId"
).
toString
(),
conditionMap
);
workflowFeignService
.
pickupAndCompleteTask
(
map
.
get
(
WorkFlowEnum
.
TASKID
.
getCode
()
).
toString
(),
conditionMap
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"完成任务失败"
);
throw
new
RuntimeException
(
"完成任务失败"
);
}
}
...
@@ -184,17 +185,17 @@ public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {
...
@@ -184,17 +185,17 @@ public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {
JSONObject
historyTaskJsonObject
=
workflowFeignService
JSONObject
historyTaskJsonObject
=
workflowFeignService
.
getHistoricTaskForProcessInstanceId
(
processInstanceId
);
.
getHistoricTaskForProcessInstanceId
(
processInstanceId
);
if
(
ObjectUtils
.
isEmpty
(
historyTaskJsonObject
.
getJSONArray
(
"data"
)))
{
if
(
ObjectUtils
.
isEmpty
(
historyTaskJsonObject
.
getJSONArray
(
WorkFlowEnum
.
DATA
.
getCode
()
)))
{
return
null
;
return
null
;
}
}
JSONObject
historyTaskObject
=
historyTaskJsonObject
.
getJSONArray
(
"data"
).
getJSONObject
(
0
);
JSONObject
historyTaskObject
=
historyTaskJsonObject
.
getJSONArray
(
WorkFlowEnum
.
DATA
.
getCode
()
).
getJSONObject
(
0
);
JSONObject
detail
=
workflowFeignService
.
getHistoricIdentityLinksForTask
(
historyTaskObject
.
getString
(
"id"
));
JSONObject
detail
=
workflowFeignService
.
getHistoricIdentityLinksForTask
(
historyTaskObject
.
getString
(
WorkFlowEnum
.
ID
.
getCode
()
));
JSONArray
resultArray
=
detail
.
getJSONArray
(
"data"
);
JSONArray
resultArray
=
detail
.
getJSONArray
(
WorkFlowEnum
.
DATA
.
getCode
()
);
if
(
ObjectUtils
.
isNotEmpty
(
resultArray
))
{
if
(
ObjectUtils
.
isNotEmpty
(
resultArray
))
{
for
(
int
i
=
0
;
i
<
resultArray
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
resultArray
.
size
();
i
++)
{
JSONObject
result
=
resultArray
.
getJSONObject
(
i
);
JSONObject
result
=
resultArray
.
getJSONObject
(
i
);
if
(
result
.
getBooleanValue
(
"group"
))
{
if
(
result
.
getBooleanValue
(
WorkFlowEnum
.
GROUP
.
getCode
()
))
{
return
result
.
getString
(
"groupId"
);
return
result
.
getString
(
WorkFlowEnum
.
GROUPID
.
getCode
()
);
}
}
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment