Merge branches 'gva_gormv2_dev' and 'gva_workflow' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev

This commit is contained in:
QM303176530
2020-11-28 10:10:48 +08:00
131 changed files with 9264 additions and 222 deletions
-32
View File
@@ -1,32 +0,0 @@
package v1
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"gin-vue-admin/utils"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// @Tags workflow
// @Summary 注册工作流
// @Produce application/json
// @Param data body model.SysWorkflow true "注册工作流接口"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"注册成功"}"
// @Router /workflow/createWorkFlow [post]
func CreateWorkFlow(c *gin.Context) {
var wk model.SysWorkflow
_ = c.ShouldBindJSON(&wk)
if err := utils.Verify(wk, utils.WorkFlowVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err := service.Create(wk); err != nil {
global.GVA_LOG.Error("注册失败!", zap.Any("err", err))
response.FailWithMessage("注册失败", c)
} else {
response.OkWithMessage("注册成功", c)
}
}
+258
View File
@@ -0,0 +1,258 @@
package v1
import (
"fmt"
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/request"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"github.com/gin-gonic/gin"
)
// @Tags WorkflowProcess
// @Summary 创建WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "创建WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/createWorkflowProcess [post]
func CreateWorkflowProcess(c *gin.Context) {
var workflowProcess model.WorkflowProcess
_ = c.ShouldBindJSON(&workflowProcess)
err := service.CreateWorkflowProcess(workflowProcess)
if err != nil {
response.FailWithMessage(fmt.Sprintf("创建失败,%v", err), c)
} else {
response.OkWithMessage("创建成功", c)
}
}
// @Tags WorkflowProcess
// @Summary 删除WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "删除WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /workflowProcess/deleteWorkflowProcess [delete]
func DeleteWorkflowProcess(c *gin.Context) {
var workflowProcess model.WorkflowProcess
_ = c.ShouldBindJSON(&workflowProcess)
err := service.DeleteWorkflowProcess(workflowProcess)
if err != nil {
response.FailWithMessage(fmt.Sprintf("删除失败,%v", err), c)
} else {
response.OkWithMessage("删除成功", c)
}
}
// @Tags WorkflowProcess
// @Summary 批量删除WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "批量删除WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /workflowProcess/deleteWorkflowProcessByIds [delete]
func DeleteWorkflowProcessByIds(c *gin.Context) {
var IDS request.IdsReq
_ = c.ShouldBindJSON(&IDS)
err := service.DeleteWorkflowProcessByIds(IDS)
if err != nil {
response.FailWithMessage(fmt.Sprintf("删除失败,%v", err), c)
} else {
response.OkWithMessage("删除成功", c)
}
}
// @Tags WorkflowProcess
// @Summary 更新WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "更新WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /workflowProcess/updateWorkflowProcess [put]
func UpdateWorkflowProcess(c *gin.Context) {
var workflowProcess model.WorkflowProcess
_ = c.ShouldBindJSON(&workflowProcess)
err := service.UpdateWorkflowProcess(&workflowProcess)
if err != nil {
response.FailWithMessage(fmt.Sprintf("更新失败,%v", err), c)
} else {
response.OkWithMessage("更新成功", c)
}
}
// @Tags WorkflowProcess
// @Summary 用id查询WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "用id查询WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /workflowProcess/findWorkflowProcess [get]
func FindWorkflowProcess(c *gin.Context) {
var workflowProcess model.WorkflowProcess
_ = c.ShouldBindQuery(&workflowProcess)
err, reworkflowProcess := service.GetWorkflowProcess(workflowProcess.ID)
if err != nil {
response.FailWithMessage(fmt.Sprintf("查询失败,%v", err), c)
} else {
response.OkWithData(gin.H{"reworkflowProcess": reworkflowProcess}, c)
}
}
// @Tags WorkflowProcess
// @Summary 用id查询工作流步骤
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "用id查询WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /workflowProcess/findWorkflowStep [get]
func FindWorkflowStep(c *gin.Context) {
var workflowProcess model.WorkflowProcess
_ = c.ShouldBindQuery(&workflowProcess)
err, workflow := service.FindWorkflowStep(workflowProcess.ID)
if err != nil {
response.FailWithMessage(fmt.Sprintf("查询失败,%v", err), c)
} else {
response.OkWithData(gin.H{"workflow": workflow}, c)
}
}
// @Tags WorkflowProcess
// @Summary 分页获取WorkflowProcess列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.WorkflowProcessSearch true "分页获取WorkflowProcess列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/getWorkflowProcessList [get]
func GetWorkflowProcessList(c *gin.Context) {
var pageInfo request.WorkflowProcessSearch
_ = c.ShouldBindQuery(&pageInfo)
err, list, total := service.GetWorkflowProcessInfoList(pageInfo)
if err != nil {
response.FailWithMessage(fmt.Sprintf("获取数据失败,%v", err), c)
} else {
response.OkWithData(response.PageResult{
List: list,
Total: total,
Page: pageInfo.Page,
PageSize: pageInfo.PageSize,
}, c)
}
}
// @Tags WorkflowProcess
// @Summary 开启工作流
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/startWorkflow [post]
func StartWorkflow(c *gin.Context) {
business := c.Query("businessType")
wfInfo := model.WorkflowBusinessStruct[business]()
c.ShouldBindJSON(wfInfo)
err := service.StartWorkflow(wfInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithMessage("启动成功", c)
}
// @Tags WorkflowProcess
// @Summary 提交工作流
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/completeWorkflowMove [post]
func CompleteWorkflowMove(c *gin.Context) {
business := c.Query("businessType")
wfInfo := model.WorkflowBusinessStruct[business]()
c.ShouldBindJSON(wfInfo)
err := service.CompleteWorkflowMove(wfInfo)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithMessage("启动成功", c)
}
// @Tags WorkflowProcess
// @Summary 我发起的工作流
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/getMyStated [get]
func GetMyStated(c *gin.Context) {
if claims, exists := c.Get("claims"); !exists {
errStr := "从Gin的Context中获取从jwt解析出来的用户ID失败, 请检查路由是否使用jwt中间件"
global.GVA_LOG.Error(errStr)
response.FailWithMessage(errStr, c)
} else {
waitUse := claims.(*request.CustomClaims)
err, wfms := service.GetMyStated(waitUse.ID)
if err != nil {
errStr := err.Error()
global.GVA_LOG.Error(errStr)
response.FailWithMessage(errStr, c)
return
}
response.OkWithData(gin.H{"wfms": wfms}, c)
}
}
// @Tags WorkflowProcess
// @Summary 我的待办
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/getMyNeed [get]
func GetMyNeed(c *gin.Context) {
if claims, exists := c.Get("claims"); !exists {
errStr := "从Gin的Context中获取从jwt解析出来的用户ID失败, 请检查路由是否使用jwt中间件"
global.GVA_LOG.Error(errStr)
response.FailWithMessage(errStr, c)
} else {
waitUse := claims.(*request.CustomClaims)
err, wfms := service.GetMyNeed(waitUse.ID, waitUse.AuthorityId)
if err != nil {
errStr := err.Error()
global.GVA_LOG.Error(errStr)
response.FailWithMessage(errStr, c)
return
}
response.OkWithData(gin.H{"wfms": wfms}, c)
}
}
// @Tags WorkflowProcess
// @Summary 根据id获取当前节点详情和历史
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "根据id获取当前节点详情和过往"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/getWorkflowMoveByID [get]
func GetWorkflowMoveByID(c *gin.Context) {
var req request.GetById
_ = c.ShouldBindQuery(&req)
err, move, moves, business := service.GetWorkflowMoveByID(req.Id)
if err != nil {
errStr := err.Error()
global.GVA_LOG.Error(errStr)
response.FailWithMessage(errStr, c)
return
}
response.OkWithData(gin.H{"move": move, "moves": moves, "business": business}, c)
}
+12
View File
@@ -77,6 +77,18 @@ var Apis = []model.SysApi{
{global.GVA_MODEL{ID: 65, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/user/setUserInfo", "设置用户信息", "user", "PUT"},
{global.GVA_MODEL{ID: 66, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/system/getServerInfo", "获取服务器信息", "system", "POST"},
{global.GVA_MODEL{ID: 67, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/email/emailTest", "发送测试邮件", "email", "POST"},
{global.GVA_MODEL{ID: 68, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/createWorkflowProcess", "新建工作流", "workflowProcess", "POST"},
{global.GVA_MODEL{ID: 69, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/deleteWorkflowProcess", "删除工作流", "workflowProcess", "DELETE"},
{global.GVA_MODEL{ID: 70, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/deleteWorkflowProcessByIds", "批量删除工作流", "workflowProcess", "DELETE"},
{global.GVA_MODEL{ID: 71, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/updateWorkflowProcess", "更新工作流", "workflowProcess", "PUT"},
{global.GVA_MODEL{ID: 72, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/findWorkflowProcess", "根据ID获取工作流", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 73, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/getWorkflowProcessList", "获取工作流", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 74, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/findWorkflowStep", "获取工作流步骤", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 75, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/startWorkflow", "启动工作流", "workflowProcess", "POST"},
{global.GVA_MODEL{ID: 76, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/getMyStated", "获取我发起的工作流", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 77, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/getMyNeed", "获取我的待办", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 78, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/getWorkflowMoveByID", "根据id获取当前节点详情和历史", "workflowProcess", "GET"},
{global.GVA_MODEL{ID: 79, CreatedAt: time.Now(), UpdatedAt: time.Now()}, "/workflowProcess/completeWorkflowMove", "提交工作流", "workflowProcess", "POST"},
}
func InitSysApi(db *gorm.DB) {
+6
View File
@@ -39,6 +39,12 @@ var AuthorityMenus = []SysAuthorityMenus{
{"888", 25},
{"888", 26},
{"888", 27},
{"888", 28},
{"888", 29},
{"888", 30},
{"888", 31},
{"888", 32},
{"888", 33},
{"8881", 1},
{"8881", 2},
{"8881", 8},
+12
View File
@@ -75,6 +75,18 @@ var Carbines = []gormadapter.CasbinRule{
{PType: "p", V0: "888", V1: "/simpleUploader/upload", V2: "POST"},
{PType: "p", V0: "888", V1: "/simpleUploader/checkFileMd5", V2: "GET"},
{PType: "p", V0: "888", V1: "/simpleUploader/mergeFileMd5", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/createWorkflowProcess", V2: "POST"},
{PType: "p", V0: "888", V1: "/workflowProcess/deleteWorkflowProcess", V2: "DELETE"},
{PType: "p", V0: "888", V1: "/workflowProcess/deleteWorkflowProcessByIds", V2: "DELETE"},
{PType: "p", V0: "888", V1: "/workflowProcess/updateWorkflowProcess", V2: "PUT"},
{PType: "p", V0: "888", V1: "/workflowProcess/findWorkflowProcess", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/getWorkflowProcessList", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/findWorkflowStep", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/startWorkflow", V2: "POST"},
{PType: "p", V0: "888", V1: "/workflowProcess/completeWorkflowMove", V2: "POST"},
{PType: "p", V0: "888", V1: "/workflowProcess/getMyStated", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/getMyNeed", V2: "GET"},
{PType: "p", V0: "888", V1: "/workflowProcess/getWorkflowMoveByID", V2: "GET"},
{PType: "p", V0: "8881", V1: "/base/login", V2: "POST"},
{PType: "p", V0: "8881", V1: "/user/register", V2: "POST"},
{PType: "p", V0: "8881", V1: "/api/createApi", V2: "POST"},
+7 -3
View File
@@ -21,6 +21,7 @@ func InitMysqlData(db *gorm.DB) {
InitSysDataAuthorityId(db)
InitSysDictionaryDetail(db)
InitExaFileUploadAndDownload(db)
InitWkProcess(db)
}
func InitMysqlTables(db *gorm.DB) {
@@ -34,21 +35,24 @@ func InitMysqlTables(db *gorm.DB) {
model.ExaFile{},
model.ExaCustomer{},
model.SysBaseMenu{},
model.SysWorkflow{},
model.SysAuthority{},
model.JwtBlacklist{},
model.ExaFileChunk{},
model.SysDictionary{},
model.ExaSimpleUploader{},
model.SysOperationRecord{},
model.SysWorkflowStepInfo{},
model.SysDictionaryDetail{},
model.SysBaseMenuParameter{},
model.ExaFileUploadAndDownload{},
model.WorkflowProcess{},
model.WorkflowNode{},
model.WorkflowEdge{},
model.WorkflowStartPoint{},
model.WorkflowEndPoint{},
)
if err != nil {
color.Warn.Printf("[Mysql]-->初始化数据表失败,err: %v\n", err)
os.Exit(0)
}
color.Info.Println("[Mysql]-->初始化数据表成功")
}
}
+6
View File
@@ -38,6 +38,12 @@ var BaseMenus = []model.SysBaseMenu{
{GVA_MODEL: global.GVA_MODEL{ID: 25, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "simpleUploader", Name: "simpleUploader", Component: "view/example/simpleUploader/simpleUploader", Sort: 6, Meta: model.Meta{Title: "断点续传(插件版)", Icon: "upload"}},
{GVA_MODEL: global.GVA_MODEL{ID: 26, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "https://www.gin-vue-admin.com", Name: "https://www.gin-vue-admin.com", Hidden: false, Component: "/", Sort: 0, Meta: model.Meta{Title: "官方网站", Icon: "s-home"}},
{GVA_MODEL: global.GVA_MODEL{ID: 27, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "state", Name: "state", Hidden: false, Component: "view/system/state.vue", Sort: 6, Meta: model.Meta{Title: "服务器状态", Icon: "cloudy"}},
{GVA_MODEL: global.GVA_MODEL{ID: 28, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "workflow", Name: "workflow", Hidden: false, Component: "view/workflow/index.vue", Sort: 5, Meta: model.Meta{Title: "工作流功能", Icon: "phone"}},
{GVA_MODEL: global.GVA_MODEL{ID: 29, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "28", Path: "workflowCreate", Name: "workflowCreate", Hidden: false, Component: "view/workflow/workflowCreate/workflowCreate.vue", Sort: 0, Meta: model.Meta{Title: "工作流绘制", Icon: "circle-plus"}},
{GVA_MODEL: global.GVA_MODEL{ID: 30, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "28", Path: "workflowProcess", Name: "workflowProcess", Hidden: false, Component: "view/workflow/workflowProcess/workflowProcess.vue", Sort: 0, Meta: model.Meta{Title: "工作流列表", Icon: "s-cooperation"}},
{GVA_MODEL: global.GVA_MODEL{ID: 31, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "28", Path: "workflowUse", Name: "workflowUse", Hidden: true, Component: "view/workflow/workflowUse/workflowUse.vue", Sort: 0, Meta: model.Meta{Title: "使用工作流", Icon: "video-play"}},
{GVA_MODEL: global.GVA_MODEL{ID: 32, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "28", Path: "started", Name: "started", Hidden: false, Component: "view/workflow/userList/started.vue", Sort: 0, Meta: model.Meta{Title: "我发起的", Icon: "s-order"}},
{GVA_MODEL: global.GVA_MODEL{ID: 33, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "28", Path: "need", Name: "need", Hidden: false, Component: "view/workflow/userList/need.vue", Sort: 0, Meta: model.Meta{Title: "我的待办", Icon: "s-platform"}},
}
func InitSysBaseMenus(db *gorm.DB) {
+62
View File
@@ -0,0 +1,62 @@
package datas
import (
"gin-vue-admin/global"
"gin-vue-admin/model"
"github.com/gookit/color"
"gorm.io/gorm"
"os"
"time"
)
var WorkflowProcess = []model.WorkflowProcess{
{ID: "leaveFlow", CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "leaveFlow", Clazz: "process", Label: "请假流程(演示)", HideIcon: false, Description: "请假流程演示", View: "view/iconList/index.vue"},
}
var WorkflowNodes = []model.WorkflowNode{
{ID: "end1603681358043", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "end", Label: "请假失败", Type: "end-node", Shape: "end-node", Description: "", View: "view/exa_wf_leave/exa_wf_leaveFrom.vue", X: 302, Y: 545.5, HideIcon: false, AssignType: "", AssignValue: "", Success: false},
{ID: "end1603681360882", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "end", Label: "请假成功", Type: "end-node", Shape: "end-node", Description: "请假完成,具体结果等待提交", View: "view/exa_wf_leave/exa_wf_leaveFrom.vue", X: 83.5, Y: 546, HideIcon: false, AssignType: "", AssignValue: "", Success: true},
{ID: "start1603681292875", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "start", Label: "发起请假", Type: "start-node", Shape: "start-node", Description: "发起一个请假流程", View: "view/exa_wf_leave/exa_wf_leaveFrom.vue", X: 201, Y: 109, HideIcon: false, AssignType: "", AssignValue: "", Success: false},
{ID: "userTask1603681299962", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "userTask", Label: "审批", Type: "user-task-node", Shape: "user-task-node", Description: "审批会签", View: "view/exa_wf_leave/exa_wf_leaveFrom.vue", X: 202, Y: 320.5, HideIcon: false, AssignType: "user", AssignValue: ",1,2,", Success: false},
}
var WorkflowEdge = []model.WorkflowEdge{
{ID: "flow1604985849039", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "flow", Source: "start1603681292875", Target: "userTask1603681299962", SourceAnchor: 1, TargetAnchor: 3, Shape: "flow-polyline-round", Label: "", HideIcon: false, ConditionExpression: "", Reverse: false},
{ID: "flow1604985879574", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "flow", Source: "userTask1603681299962", Target: "end1603681360882", SourceAnchor: 0, TargetAnchor: 2, Shape: "flow-polyline-round", Label: "同意", HideIcon: false, ConditionExpression: "yes", Reverse: false},
{ID: "flow1604985881207", CreatedAt: time.Now(), UpdatedAt: time.Now(), WorkflowProcessID: "leaveFlow", Clazz: "flow", Source: "userTask1603681299962", Target: "end1603681358043", SourceAnchor: 2, TargetAnchor: 2, Shape: "flow-polyline-round", Label: "不同意", HideIcon: false, ConditionExpression: "no", Reverse: false},
}
var WorkflowStartPoint = []model.WorkflowStartPoint{
{WorkflowEdgeID: "flow1604985849039", GVA_MODEL: global.GVA_MODEL{ID: 31, CreatedAt: time.Now(), UpdatedAt: time.Now()}, X: 137, Y: 201, Index: 1},
{WorkflowEdgeID: "flow1604985879574", GVA_MODEL: global.GVA_MODEL{ID: 32, CreatedAt: time.Now(), UpdatedAt: time.Now()}, X: 320.5, Y: 174, Index: 0},
{WorkflowEdgeID: "flow1604985881207", GVA_MODEL: global.GVA_MODEL{ID: 33, CreatedAt: time.Now(), UpdatedAt: time.Now()}, X: 320.5, Y: 230, Index: 2},
}
var WorkflowEndPoint = []model.WorkflowEndPoint{
{WorkflowEdgeID: "flow1604985849039", GVA_MODEL: global.GVA_MODEL{ID: 31, CreatedAt: time.Now(), UpdatedAt: time.Now()}, X: 270, Y: 202, Index: 3},
{WorkflowEdgeID: "flow1604985879574", GVA_MODEL: global.GVA_MODEL{ID: 32, CreatedAt: time.Now(), UpdatedAt: time.Now()}, X: 518, Y: 83.5, Index: 2},
{WorkflowEdgeID: "flow1604985881207", GVA_MODEL: global.GVA_MODEL{ID: 33, CreatedAt: time.Now(), UpdatedAt: time.Now()}, X: 517.5, Y: 302, Index: 2},
}
func InitWkProcess(db *gorm.DB) {
if err := db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&WorkflowProcess).Error; err != nil { // 遇到错误时回滚事务
return err
}
if err := tx.Create(&WorkflowNodes).Error; err != nil { // 遇到错误时回滚事务
return err
}
if err := tx.Create(&WorkflowEdge).Error; err != nil { // 遇到错误时回滚事务
return err
}
if err := tx.Create(&WorkflowStartPoint).Error; err != nil { // 遇到错误时回滚事务
return err
}
if err := tx.Create(&WorkflowEndPoint).Error; err != nil { // 遇到错误时回滚事务
return err
}
return nil
}); err != nil {
color.Warn.Printf("[Mysql]-->工作流相关 表的初始数据失败,err: %v\n", err)
os.Exit(0)
}
}
+19
View File
@@ -0,0 +1,19 @@
package constant
//定义clazz常量
const (
USER_TASK string = "userTask" // 审批节点
//SCRIPT_TASK string = "scriptTask" //脚本节点
//RECEIVE_TASK string = "receiveTask"
//MAIL_TASK string = "mailTask" //邮件节点
//TIMER_START string = "timerStart" // 定时节点
//MESSAGE_START string = "messageStart" // 消息节点
EXCLUSIVE_GATEWAY string = "exclusiveGateway" // 排他网关
INCLUSIVE_GATEWAY string = "inclusiveGateway" // 包容网关
PARELLEL_GATEWAY string = "parallelGateway" // 并行网关
FLOW string = "flow" // 连线
START string = "start" // 开始节点
END string = "end" // 结束节点
//PROCESS string = "process" // 基础节点
)
+1
View File
@@ -17,6 +17,7 @@ func RunWindowsServer() {
// 初始化redis服务
initialize.Redis()
}
initialize.InitWkMode()
Router := initialize.Routers()
Router.Static("/form-generator", "./resource/page")
+8 -3
View File
@@ -29,8 +29,6 @@ func MysqlTables(db *gorm.DB) {
model.SysBaseMenu{},
model.SysBaseMenuParameter{},
model.JwtBlacklist{},
model.SysWorkflow{},
model.SysWorkflowStepInfo{},
model.SysDictionary{},
model.SysDictionaryDetail{},
model.ExaFileUploadAndDownload{},
@@ -39,6 +37,13 @@ func MysqlTables(db *gorm.DB) {
model.ExaSimpleUploader{},
model.ExaCustomer{},
model.SysOperationRecord{},
model.WorkflowProcess{},
model.WorkflowNode{},
model.WorkflowEdge{},
model.WorkflowStartPoint{},
model.WorkflowEndPoint{},
model.WorkflowMove{},
model.ExaWfLeave{},
)
if err != nil {
global.GVA_LOG.Error("register table failed", zap.Any("err", err))
@@ -90,4 +95,4 @@ func gormConfig(mod bool) *gorm.Config {
DisableForeignKeyConstraintWhenMigrating: true,
}
}
}
}
+1 -1
View File
@@ -38,7 +38,6 @@ func Routers() *gin.Engine {
router.InitEmailRouter(PrivateGroup) // 邮件相关路由
router.InitSystemRouter(PrivateGroup) // system相关路由
router.InitCasbinRouter(PrivateGroup) // 权限相关路由
router.InitWorkflowRouter(PrivateGroup) // 工作流相关路由
router.InitCustomerRouter(PrivateGroup) // 客户路由
router.InitAutoCodeRouter(PrivateGroup) // 创建自动化代码
router.InitAuthorityRouter(PrivateGroup) // 注册角色路由
@@ -47,6 +46,7 @@ func Routers() *gin.Engine {
router.InitSysOperationRecordRouter(PrivateGroup) // 操作记录
router.InitSysDictionaryDetailRouter(PrivateGroup) // 字典详情管理
router.InitFileUploadAndDownloadRouter(PrivateGroup) // 文件上传下载功能路由
router.InitWorkflowProcessRouter(PrivateGroup) // 工作流相关接口
}
global.GVA_LOG.Info("router register success")
return Router
+22
View File
@@ -0,0 +1,22 @@
package initialize
import "gin-vue-admin/model"
func initWorkflowModel() {
model.WorkflowBusinessStruct = make(map[string]func() model.GVA_Workflow)
model.WorkflowBusinessStruct["leave"] = func() model.GVA_Workflow {
return new(model.ExaWfLeaveWorkflow)
}
}
func initWorkflowTable() {
model.WorkflowBusinessTable = make(map[string]func() interface{})
model.WorkflowBusinessTable["leave"] = func() interface{} {
return new(model.ExaWfLeave)
}
}
func InitWkMode() {
initWorkflowModel()
initWorkflowTable()
}
+25
View File
@@ -0,0 +1,25 @@
// 自动生成模板ExaWfLeave
package model
import (
"gin-vue-admin/global"
"time"
)
// 如果含有time.Time 请自行import time包
type ExaWfLeave struct {
global.GVA_MODEL
Cause string `json:"cause" form:"cause" gorm:"column:cause;comment:"`
StartTime time.Time `json:"startTime" form:"startTime" gorm:"column:start_time;comment:"`
EndTime time.Time `json:"endTime" form:"endTime" gorm:"column:end_time;comment:"`
}
type ExaWfLeaveWorkflow struct {
// 工作流操作结构体
WorkflowBase `json:"wf"`
ExaWfLeave `json:"business"`
}
func (ExaWfLeave) TableName() string {
return "exa_wf_leaves"
}
+8
View File
@@ -0,0 +1,8 @@
package request
import "gin-vue-admin/model"
type WorkflowProcessSearch struct {
model.WorkflowProcess
PageInfo
}
+145 -15
View File
@@ -2,24 +2,154 @@ package model
import (
"gin-vue-admin/global"
"gorm.io/gorm"
"time"
)
// 工作流属性表
type SysWorkflow struct {
global.GVA_MODEL
WorkflowNickName string `json:"workflowNickName" gorm:"comment:工作流中文名称"` // 工作流名称
WorkflowName string `json:"workflowName" gorm:"comment:工作流英文名称"` // 工作流英文id
WorkflowDescription string `json:"workflowDescription" gorm:"comment:工作流描述"` // 工作流描述
WorkflowStepInfo []SysWorkflowStepInfo `json:"workflowStep" gorm:"comment:工作流步骤"` // 工作流步骤
var WorkflowBusinessStruct map[string]func() GVA_Workflow
var WorkflowBusinessTable map[string]func() interface{}
type GVA_Workflow interface {
CreateWorkflowMove() *WorkflowMove
GetBusinessType() string
GetBusinessID() uint
GetWorkflowBase() WorkflowBase
}
// 工作流状态表
type SysWorkflowStepInfo struct {
type WorkflowBase struct {
WorkflowMoveID uint `json:"workflowMoveID" gorm:"-"`
BusinessID uint `json:"businessID" gorm:"<-:false;column:id"` // 业务对应IDbusinessID)的返回
BusinessType string `json:"businessType" gorm:"-"`
PromoterID uint `json:"promoterID" gorm:"-"`
OperatorID uint `json:"operatorID" gorm:"-"`
WorkflowProcessID string `json:"workflowProcessID" gorm:"-"`
WorkflowNodeID string `json:"workflowNodeID" gorm:"-"`
Param string `json:"param" gorm:"-"`
Action string `json:"action" gorm:"-"`
}
func (w WorkflowBase) CreateWorkflowMove() (businessModel *WorkflowMove) {
return &WorkflowMove{
GVA_MODEL: global.GVA_MODEL{ID: w.WorkflowMoveID},
BusinessType: w.BusinessType,
PromoterID: w.PromoterID,
OperatorID: w.OperatorID,
Param: w.Param,
WorkflowProcessID: w.WorkflowProcessID,
WorkflowNodeID: w.WorkflowNodeID,
BusinessID: w.BusinessID,
Action: w.Action,
IsActive: true,
}
}
func (w WorkflowBase) GetBusinessType() (businessType string) {
return w.BusinessType
}
func (w WorkflowBase) GetBusinessID() (businessID uint) {
return w.BusinessID
}
func (w WorkflowBase) GetWorkflowBase() (workflowBase WorkflowBase) {
return w
}
type WorkflowMove struct {
global.GVA_MODEL
SysWorkflowID uint `json:"workflowID" gorm:"comment:所属工作流ID"` // 所属工作流ID
IsStart bool `json:"isStart" gorm:"comment:是否是开始流节点"` // 是否是开始流节点
StepName string `json:"stepName" gorm:"comment:工作流节点名称"` // 工作流名称
StepNo float64 `json:"stepNo" gorm:"comment:步骤id (第几步)"` // 步骤id (第几步)
StepAuthorityID string `json:"stepAuthorityID" gorm:"comment:操作者级别id"` // 操作者级别id
IsEnd bool `json:"isEnd" gorm:"comment:是否是完结流节点"` // 是否是完结流节点
WorkflowProcessID string `json:"workflowProcessID" gorm:"comment:工作流模板ID"`
WorkflowProcess WorkflowProcess `gorm:"<-:false" json:"workflowProcess" gorm:"comment:工作流模板具体信息"`
WorkflowNodeID string `json:"workflowNodeID" gorm:"comment:工作流节点ID"`
WorkflowNode WorkflowNode `gorm:"<-:false" json:"workflowNode" gorm:"comment:工作流节点具体信息"`
BusinessType string `json:"businessType" gorm:"comment:业务标记"`
BusinessID uint `json:"businessID" gorm:"comment:业务ID"`
PromoterID uint `json:"promoterID" gorm:"comment:当前流转发起人"`
Promoter SysUser `gorm:"<-:false" json:"promoter" gorm:"comment:当前流转发起人信息"`
OperatorID uint `json:"operatorID" gorm:"comment:当前流转操作人"`
Operator SysUser `gorm:"<-:false" json:"operator" gorm:"comment:当前流转操作人信息"`
Action string `json:"action" gorm:"comment:工作流驱动事件"`
Param string `json:"param" gorm:"comment:工作流驱动参数"`
IsActive bool `json:"isActive" gorm:"comment:是否是活跃节点 "`
}
type WorkflowProcess struct {
ID string `json:"id" form:"id" gorm:"comment:流程标识;primaryKey;unique;not null"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
Name string `json:"name" gorm:"comment:流程名称"`
Category string `json:"category" gorm:"comment:分类"`
Clazz string `json:"clazz" gorm:"comment:类型"`
Label string `json:"label" gorm:"comment:流程标题"`
HideIcon bool `json:"hideIcon" gorm:"comment:是否隐藏图标"`
Description string `json:"description" gorm:"comment:详细介绍"`
View string `json:"view" gorm:"comment:前端视图文件"`
Nodes []WorkflowNode `json:"nodes"` // 流程节点数据
Edges []WorkflowEdge `json:"edges"` // 流程链接数据
}
type WorkflowNode struct {
ID string `json:"id" form:"id" gorm:"comment:节点id;primaryKey;unique;not null"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
WorkflowProcessID string `json:"workflowProcessID" gorm:"comment:流程标识"`
Clazz string `json:"clazz" gorm:"comment:节点类型"`
Label string `json:"label" gorm:"comment:节点名称"`
Type string `json:"type" gorm:"comment:图标类型"`
Shape string `json:"shape" gorm:"comment:形状"`
Description string `json:"description" gorm:"comment:详细介绍"`
View string `json:"view" gorm:"comment:前端视图文件"`
X float64 `json:"y" gorm:"comment:x位置"`
Y float64 `json:"x" gorm:"comment:y位置"`
WaitState string `json:"waitState" gorm:"comment:等待属性"`
StateValue string `json:"stateValue" gorm:"comment:等待值"`
To string `json:"to" gorm:"comment:收件人"`
Subject string `json:"subject" gorm:"comment:标题"`
Content string `json:"content" gorm:"comment:内容"`
Cycle string `json:"cycle" gorm:"comment:循环时间"`
Duration string `json:"duration" gorm:"comment:持续时间"`
HideIcon bool `json:"hideIcon" gorm:"comment:是否隐藏图标"`
DueDate time.Time `json:"dueDate" gorm:"comment:到期时间"`
AssignType string `json:"assignType" gorm:"comment:审批类型"`
AssignValue string `json:"assignValue" gorm:"comment:审批类型值"`
Success bool `json:"success" gorm:"comment:是否成功"`
}
type WorkflowEdge struct {
ID string `json:"id" form:"id" gorm:"comment:唯一标识;primaryKey;unique;not null"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
WorkflowProcessID string `json:"-" gorm:"comment:流程标识"`
Clazz string `json:"clazz" gorm:"comment:类型(线)"`
Source string `json:"source" gorm:"comment:起点节点"`
Target string `json:"target" gorm:"comment:目标节点"`
SourceAnchor int `json:"sourceAnchor" gorm:"comment:起点"`
TargetAnchor int `json:"targetAnchor" gorm:"comment:目标点"`
Description string `json:"description" gorm:"comment:详细介绍"`
Shape string `json:"shape" gorm:"comment:形状"`
StartPoint WorkflowStartPoint `json:"startPoint"` // 起点信息
EndPoint WorkflowEndPoint `json:"endPoint"` // 终点信息
Label string `json:"label" gorm:"comment:标题"`
HideIcon bool `json:"hideIcon" gorm:"comment:隐藏图标"`
ConditionExpression string `json:"conditionExpression" gorm:"comment:条件标识"`
Seq string `json:"seq" gorm:"comment:序号"`
Reverse bool `json:"reverse" gorm:"comment:是否反向"`
}
type WorkflowStartPoint struct {
WorkflowEdgeID string
global.GVA_MODEL
X float64 `json:"x"`
Y float64 `json:"y"`
Index int `json:"index"`
}
type WorkflowEndPoint struct {
WorkflowEdgeID string
global.GVA_MODEL
X float64 `json:"x"`
Y float64 `json:"y"`
Index int `json:"index"`
}
-16
View File
@@ -1,16 +0,0 @@
package model
import (
"gin-vue-admin/global"
)
// 工作流流转表
type SysWorkFlowProcess struct {
global.GVA_MODEL
ApplicationID uint `json:"applicationID" gorm:"comment:当前工作流所属申请的ID"` // 当前工作流所属申请的ID
CurrentNode string `json:"currentNode" gorm:"comment:当前进度节点"` // 当前进度节点
HistoricalNode string `json:"historicalNode" gorm:"comment:上一个进度节点"` // 上一个进度节点
CurrentUser string `json:"currentUser" gorm:"comment:当前进度操作人"` // 当前进度操作人
HistoricalUser string `json:"historicalUser" gorm:"comment:上一个进度的操作人"` // 上一个进度的操作人
State bool `json:"state" gorm:"comment:是否是正在进行的状态"` // 状态 是否是正在进行的状态
}
+1 -1
View File
@@ -78,7 +78,7 @@ func Delete{{.StructName}}ByIds(c *gin.Context) {
func Update{{.StructName}}(c *gin.Context) {
var {{.Abbreviation}} model.{{.StructName}}
_ = c.ShouldBindJSON(&{{.Abbreviation}})
if err := service.Update{{.StructName}}(&{{.Abbreviation}}); err != nil {
if err := service.Update{{.StructName}}({{.Abbreviation}}); err != nil {
global.GVA_LOG.Error("更新失败!", zap.Any("err", err))
response.FailWithMessage("更新失败", c)
} else {
+24 -1
View File
@@ -19,4 +19,27 @@ type {{.StructName}} struct {
func ({{.StructName}}) TableName() string {
return "{{.TableName}}"
}
{{ end }}
{{ end }}
// 如果使用工作流功能 需要打开下方注释 并到initialize的workflow中进行注册 且必须指定TableName
// type {{.StructName}}Workflow struct {
// //
// WorkflowBase `json:"wf"`
// {{.StructName}} `json:"business"`
// }
// func ({{.StructName}}) TableName() string {
// return "{{.TableName}}"
// }
// 工作流注册代码
// initWorkflowModel内部注册
// model.WorkflowBusinessStruct["{{.Abbreviation}}"] = func() model.GVA_Workflow {
// return new(model.{{.StructName}}Workflow)
// }
// initWorkflowTable内部注册
// model.WorkflowBusinessTable["{{.Abbreviation}}"] = func() interface{} {
// return new(model.{{.StructName}})
// }
@@ -45,8 +45,8 @@ func Delete{{.StructName}}ByIds(ids request.IdsReq) (err error) {
//@param: {{.Abbreviation}} *model.{{.StructName}}
//@return: err error
func Update{{.StructName}}({{.Abbreviation}} *model.{{.StructName}}) (err error) {
err = global.GVA_DB.Save({{.Abbreviation}}).Error
func Update{{.StructName}}({{.Abbreviation}} model.{{.StructName}}) (err error) {
err = global.GVA_DB.Save(&{{.Abbreviation}}).Error
return err
}
@@ -0,0 +1,171 @@
<template>
<div>
<el-form :model="formData" label-position="right" label-width="80px">
{{- range .Fields}}
<el-form-item label="{{.FieldDesc}}:">
{{- if eq .FieldType "bool" }}
<el-switch active-color="#13ce66" inactive-color="#ff4949" active-text="是" inactive-text="否" v-model="formData.{{.FieldJson}}" clearable ></el-switch>
{{ end -}}
{{- if eq .FieldType "string" }}
<el-input v-model="formData.{{.FieldJson}}" clearable placeholder="请输入" ></el-input>
{{ end -}}
{{- if eq .FieldType "int" }}
{{- if .DictType}}
<el-select v-model="formData.{{ .FieldJson }}" placeholder="请选择" clearable>
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value"></el-option>
</el-select>
{{ else -}}
<el-input v-model.number="formData.{{ .FieldJson }}" clearable placeholder="请输入"></el-input>
{{ end -}}
{{ end -}}
{{- if eq .FieldType "time.Time" }}
<el-date-picker type="date" placeholder="选择日期" v-model="formData.{{ .FieldJson }}" clearable></el-date-picker>
{{ end -}}
{{- if eq .FieldType "float64" }}
<el-input-number v-model="formData.{{ .FieldJson }}" :precision="2" clearable></el-input-number>
{{ end -}}
</el-form-item>
{{ end -}}
<el-form-item>
<el-button v-if="this.wf.clazz == 'start'" @click="start" type="primary">启动</el-button>
// complete传入流转参数 决定下一步会流转到什么位置 此处可以设置多个按钮来做不同的流转
<el-button v-if="this.wf.clazz == 'userTask'" @click="complete('yes')" type="primary">提交</el-button>
<el-button @click="back" type="primary">返回</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import {
startWorkflow,
completeWorkflowMove
} from "@/api/workflowProcess";
import infoList from "@/mixins/infoList";
import { mapGetters } from "vuex";
export default {
name: "{{.StructName}}",
mixins: [infoList],
props:{
business:{
type:Object,
default:function(){return null}
},
wf:{
type:Object,
default:function(){return{}}
},
workflowMoveID:{
type:Number,
default:0
}
},
data() {
return {
{{- range .Fields}}
{{- if .DictType }}
{{ .DictType }}Options:[],
{{ end -}}
{{end -}}
formData: {
{{range .Fields}}
{{- if eq .FieldType "bool" -}}
{{.FieldJson}}:false,
{{ end -}}
{{- if eq .FieldType "string" -}}
{{.FieldJson}}:"",
{{ end -}}
{{- if eq .FieldType "int" -}}
{{.FieldJson}}:0,
{{ end -}}
{{- if eq .FieldType "time.Time" -}}
{{.FieldJson}}:new Date(),
{{ end -}}
{{- if eq .FieldType "float64" -}}
{{.FieldJson}}:0,
{{ end -}}
{{ end }}
}
};
},
computed:{
canShow(){
if(this.wf.assignType == "user"){
if(this.wf.assginValue.indexOf(","+this.userInfo.ID+",")>0){
return true
}else{
return false
}
}else if(this.wf.assign_type == "authority"){
if(this.wf.assginValue.indexOf(","+this.userInfo.authorityId+",")>0){
return true
}else{
return false
}
}
},
...mapGetters("user", ["userInfo"])
},
methods: {
async start() {
const res = await startWorkflow({
business:this.formData,
wf:{
workflowMoveID:this.workflowMoveID,
businessId:0,
businessType:"{{.Abbreviation}}",
workflowProcessID:this.wf.workflowProcessID,
workflowNodeID:this.wf.id,
promoterID:this.userInfo.ID,
operatorID:this.userInfo.ID,
action:"create",
param:""
}
});
if (res.code == 0) {
this.$message({
type:"success",
message:"启动成功"
})
this.back()
}
},
async complete(param){
const res = await completeWorkflowMove({
business:this.formData,
wf:{
workflowMoveID:this.workflowMoveID,
businessID:this.formData.ID,
businessType:"{{.Abbreviation}}",
workflowProcessID:this.wf.workflowProcessID,
workflowNodeID:this.wf.id,
promoterID:this.userInfo.ID,
operatorID:this.userInfo.ID,
action:"complete",
param:param
}
})
if(res.code == 0){
this.$message({
type:"success",
message:"提交成功"
})
this.back()
}
},
back(){
this.$router.go(-1)
}
},
async created() {
if(this.business){
this.formData = this.business
}
}
};
</script>
<style>
</style>
+14 -3
View File
@@ -6,9 +6,20 @@ import (
"github.com/gin-gonic/gin"
)
func InitWorkflowRouter(Router *gin.RouterGroup) {
WorkflowRouter := Router.Group("workflow").Use(middleware.OperationRecord())
func InitWorkflowProcessRouter(Router *gin.RouterGroup) {
WorkflowProcessRouter := Router.Group("workflowProcess").Use(middleware.OperationRecord())
{
WorkflowRouter.POST("createWorkFlow", v1.CreateWorkFlow) // 创建工作流
WorkflowProcessRouter.POST("createWorkflowProcess", v1.CreateWorkflowProcess) // 新建WorkflowProcess
WorkflowProcessRouter.DELETE("deleteWorkflowProcess", v1.DeleteWorkflowProcess) // 删除WorkflowProcess
WorkflowProcessRouter.DELETE("deleteWorkflowProcessByIds", v1.DeleteWorkflowProcessByIds) // 批量删除WorkflowProcess
WorkflowProcessRouter.PUT("updateWorkflowProcess", v1.UpdateWorkflowProcess) // 更新WorkflowProcess
WorkflowProcessRouter.GET("findWorkflowProcess", v1.FindWorkflowProcess) // 根据ID获取WorkflowProcess
WorkflowProcessRouter.GET("findWorkflowStep", v1.FindWorkflowStep) // 根据ID获取工作流步骤
WorkflowProcessRouter.GET("getWorkflowProcessList", v1.GetWorkflowProcessList) // 获取WorkflowProcess列表
WorkflowProcessRouter.POST("startWorkflow", v1.StartWorkflow) // 开启工作流
WorkflowProcessRouter.POST("completeWorkflowMove", v1.CompleteWorkflowMove) // 提交工作流
WorkflowProcessRouter.GET("getMyStated", v1.GetMyStated) // 获取我发起的工作流
WorkflowProcessRouter.GET("getMyNeed", v1.GetMyNeed) // 获取我的待办
WorkflowProcessRouter.GET("getWorkflowMoveByID", v1.GetWorkflowMoveByID) // 获取我的待办
}
}
+2
View File
@@ -201,6 +201,8 @@ func addAutoMoveFile(data *tplData) {
} else if strings.Contains(data.autoCodePath, "web") {
if strings.Contains(data.autoCodePath, "js") {
data.autoMoveFilePath = filepath.Join("../", "web", "src", dir, base)
} else if strings.Contains(data.autoCodePath, "workflowForm") {
data.autoMoveFilePath = filepath.Join("../", "web", "src", "view", filepath.Base(filepath.Dir(filepath.Dir(data.autoCodePath))), strings.TrimSuffix(base, filepath.Ext(base))+"WorkflowForm.vue")
} else if strings.Contains(data.autoCodePath, "form") {
data.autoMoveFilePath = filepath.Join("../", "web", "src", "view", filepath.Base(filepath.Dir(filepath.Dir(data.autoCodePath))), strings.TrimSuffix(base, filepath.Ext(base))+"Form.vue")
} else if strings.Contains(data.autoCodePath, "table") {
+424 -7
View File
@@ -1,17 +1,434 @@
package service
import (
"errors"
"fmt"
"gin-vue-admin/constant"
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/request"
"gorm.io/gorm"
"gorm.io/gorm/schema"
"strconv"
)
//@author: [piexlmax](https://github.com/piexlmax)
//@function: Create
//@description: 创建工作流
//@param: wk model.SysWorkflow
//@return: error
func getTable(businessType string) interface{} {
return model.WorkflowBusinessTable[businessType]()
}
func Create(wk model.SysWorkflow) error {
err := global.GVA_DB.Create(&wk).Error
//@author: [piexlmax](https://github.com/piexlmax)
//@function: CreateWorkflowProcess
//@description: 创建工作流相关信息
//@param: workflowProcess model.WorkflowProcess
//@return: err error
func CreateWorkflowProcess(workflowProcess model.WorkflowProcess) (err error) {
err = global.GVA_DB.Create(&workflowProcess).Error
return err
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: DeleteWorkflowProcess
//@description: 删除工作流相关信息
//@param: workflowProcess model.WorkflowProcess
//@return: err error
func DeleteWorkflowProcess(workflowProcess model.WorkflowProcess) (err error) {
err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
var txErr error
txErr = tx.Delete(workflowProcess).Error
if txErr != nil {
return txErr
}
var edges []model.WorkflowEdge
txErr = tx.Delete(model.WorkflowNode{}, "workflow_process_id = ?", workflowProcess.ID).Error
if txErr != nil {
return txErr
}
txErr = tx.Find(&edges, "workflow_process_id = ?", workflowProcess.ID).Error
if txErr != nil {
return txErr
}
if len(edges) > 0 {
txErr = tx.Select("StartPoint", "EndPoint").Delete(&edges).Error
}
if txErr != nil {
return txErr
}
return nil
})
return err
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: CreateWorkflowProcess
//@description: 批量删除工作流信息(暂未启用)
//@param: ids request.IdsReq
//@return: err error
func DeleteWorkflowProcessByIds(ids request.IdsReq) (err error) {
err = global.GVA_DB.Delete(&[]model.WorkflowProcess{}, "id in ?", ids.Ids).Error
return err
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: UpdateWorkflowProcess
//@description: 更新工作流相关信息
//@param: workflowProcess *model.WorkflowProcess
//@return: err error
func UpdateWorkflowProcess(workflowProcess *model.WorkflowProcess) (err error) {
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
var txErr error
var edges []model.WorkflowEdge
var edgesIds []string
txErr = tx.Unscoped().Delete(workflowProcess).Error
if txErr != nil {
return txErr
}
txErr = tx.Unscoped().Delete(model.WorkflowNode{}, "workflow_process_id = ?", workflowProcess.ID).Error
if txErr != nil {
return txErr
}
txErr = tx.Unscoped().Find(&edges, "workflow_process_id = ?", workflowProcess.ID).Error
if txErr != nil {
return txErr
}
txErr = tx.Unscoped().Delete(&edges).Error
if txErr != nil {
return txErr
}
for _, v := range edges {
edgesIds = append(edgesIds, v.ID)
}
txErr = tx.Unscoped().Delete(model.WorkflowStartPoint{}, "workflow_edge_id in ?", edgesIds).Error
if txErr != nil {
return txErr
}
txErr = tx.Unscoped().Delete(model.WorkflowEndPoint{}, "workflow_edge_id in ?", edgesIds).Error
if txErr != nil {
return txErr
}
txErr = tx.Create(&workflowProcess).Error
if txErr != nil {
return txErr
}
return nil
})
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetWorkflowProcess
//@description: 获取工作流相关信息
//@param: id string
//@return: err error,workflowProcess model.WorkflowProcess
func GetWorkflowProcess(id string) (err error, workflowProcess model.WorkflowProcess) {
err = global.GVA_DB.Preload("Nodes").Preload("Edges").Where("id = ?", id).First(&workflowProcess).Error
return
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetWorkflowCreateStep
//@description: 获取工作流步骤信息
//@param: id string
//@return: err error, workflowNodes []model.WorkflowNode
func FindWorkflowStep(id string) (err error, workflowNode model.WorkflowProcess) {
err = global.GVA_DB.Preload("Nodes", "clazz = ?", constant.START).Where("id = ?", id).First(&workflowNode).Error
return
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: GetWorkflowProcessInfoList
//@description: 获取工作流列表
//@param: info request.WorkflowProcessSearch
//@return: err error, list interface{}, total int64
func GetWorkflowProcessInfoList(info request.WorkflowProcessSearch) (err error, list interface{}, total int64) {
limit := info.PageSize
offset := info.PageSize * (info.Page - 1)
// 创建db
db := global.GVA_DB.Model(&model.WorkflowProcess{})
var workflowProcesss []model.WorkflowProcess
// 如果有条件搜索 下方会自动创建搜索语句
if info.Name != "" {
db = db.Where("`name` LIKE ?", "%"+info.Name+"%")
}
if info.Label != "" {
db = db.Where("`label` LIKE ?", "%"+info.Label+"%")
}
err = db.Count(&total).Error
err = db.Limit(limit).Offset(offset).Find(&workflowProcesss).Error
return err, workflowProcesss, total
}
//@author: [piexlmax](https://github.com/piexlmax)
//@function: StartWorkflow
//@description: 开启一个工作流
//@param: wfInterface model.GVA_Workflow
//@return: err error
func StartWorkflow(wfInterface model.GVA_Workflow) (err error) {
err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
var txErr error
tableName := getTable(wfInterface.GetBusinessType()).(schema.Tabler).TableName()
txErr = tx.Table(tableName).Create(wfInterface).Error
if txErr != nil {
return txErr
}
wfm := wfInterface.CreateWorkflowMove()
txErr = tx.Create(wfm).Error
if txErr != nil {
return txErr
}
txErr = complete(tx, wfm)
if txErr != nil {
return txErr
}
return nil
})
return err
}
func CompleteWorkflowMove(wfInterface model.GVA_Workflow) (err error) {
err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
var txErr error
tableName := getTable(wfInterface.GetBusinessType()).(schema.Tabler).TableName()
txErr = tx.Table(tableName).Where("id = ?", wfInterface.GetBusinessID()).Updates(wfInterface).Error
if txErr != nil {
return txErr
}
nowWorkflowMove := wfInterface.CreateWorkflowMove()
txErr = complete(tx, nowWorkflowMove)
if txErr != nil {
return txErr
}
return nil
})
return err
}
func complete(tx *gorm.DB, wfm *model.WorkflowMove) (err error) {
var returnWfm model.WorkflowMove
var nodeInfo model.WorkflowNode
var Edges []model.WorkflowEdge
txErr := tx.First(&returnWfm, "id = ? AND is_active = ?", wfm.ID, true).Error
if txErr != nil {
return txErr
}
txErr = tx.First(&nodeInfo, "id = ?", wfm.WorkflowNodeID).Error
if txErr != nil {
return txErr
}
if nodeInfo.Clazz == constant.START || nodeInfo.Clazz == constant.USER_TASK {
txErr = tx.Find(&Edges, "workflow_process_id = ? and source = ?", wfm.WorkflowProcessID, wfm.WorkflowNodeID).Error
if txErr != nil {
return txErr
}
if len(Edges) == 0 {
return errors.New("不存在当前节点为起点的后续流程")
}
if len(Edges) == 1 {
txErr = tx.Model(&returnWfm).Update("param", wfm.Param).Update("is_active", false).Update("action", wfm.Action).Update("operator_id", wfm.OperatorID).Error
if txErr != nil {
return txErr
}
txErr, newWfm := createNewWorkflowMove(tx, &returnWfm, Edges[0].Target)
if txErr != nil {
return txErr
}
if len(newWfm) > 0 {
txErr = tx.Create(&newWfm).Error
if txErr != nil {
return txErr
}
}
// 当target为自动节点时候 需要做一些事情 这里暂时先不处理 后续慢慢完善
}
if len(Edges) > 1 {
var needUseTargetNodeID string
txErr = tx.Model(&returnWfm).Update("param", wfm.Param).Update("is_active", false).Update("action", wfm.Action).Update("operator_id", wfm.OperatorID).Error
if txErr != nil {
return txErr
}
for _, v := range Edges {
if v.ConditionExpression == wfm.Param {
needUseTargetNodeID = v.Target
break
}
}
if needUseTargetNodeID == "" {
return errors.New("未发现流转参数,流转失败")
}
txErr, newWfm := createNewWorkflowMove(tx, &returnWfm, needUseTargetNodeID)
if txErr != nil {
return txErr
}
if len(newWfm) > 0 {
txErr = tx.Create(&newWfm).Error
if txErr != nil {
return txErr
}
}
}
} else if nodeInfo.Clazz == constant.EXCLUSIVE_GATEWAY {
return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
} else if nodeInfo.Clazz == constant.INCLUSIVE_GATEWAY {
return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
} else if nodeInfo.Clazz == constant.PARELLEL_GATEWAY {
return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
} else {
return errors.New("目前只支持start节点和userTask功能,其他功能正在开发中")
}
return nil
}
func createNewWorkflowMove(tx *gorm.DB, oldWfm *model.WorkflowMove, targetNodeID string) (err error, newWfm []model.WorkflowMove) {
// 以下所有非 default的节点的下一步流转均应该处理为递归形式
var nodeInfo model.WorkflowNode
var edge model.WorkflowEdge
var edges []model.WorkflowEdge
var wfms []model.WorkflowMove
txErr := tx.First(&nodeInfo, "id = ?", targetNodeID).Error
if txErr != nil {
return txErr, []model.WorkflowMove{}
}
switch nodeInfo.Clazz {
case constant.EXCLUSIVE_GATEWAY:
// 当为排他网关时候 选择一个参数进行排他线路选择
txErr := tx.First(&edge, "workflow_process_id = ? and source = ? and condition_expression = ?", oldWfm.WorkflowProcessID, nodeInfo.ID, oldWfm.Param).Error
if txErr != nil {
return txErr, []model.WorkflowMove{}
}
newWfm = append(newWfm, model.WorkflowMove{
BusinessID: oldWfm.BusinessID,
BusinessType: oldWfm.BusinessType,
PromoterID: oldWfm.PromoterID,
OperatorID: 0,
WorkflowNodeID: edge.Target,
WorkflowProcessID: oldWfm.WorkflowProcessID,
Param: "",
Action: "",
IsActive: true})
return nil, newWfm
case constant.INCLUSIVE_GATEWAY:
// 当为包容网关时,需要等待其他网关执行结束才进行创建
txErr := tx.Find(&edges, "workflow_process_id = ? and target = ?", oldWfm.WorkflowProcessID, nodeInfo.ID).Error
if txErr != nil {
return txErr, []model.WorkflowMove{}
}
var sourceIds []string
for _, v := range edges {
sourceIds = append(sourceIds, v.Source)
}
txErr = tx.Find(&wfms, "workflow_process_id = ? and business_id = ? and workflow_node_id in (?) and is_active = ?", oldWfm.WorkflowProcessID, oldWfm.BusinessID, sourceIds, false).Error
if txErr != nil {
return txErr, []model.WorkflowMove{}
}
if len(wfms) != len(edges) {
return nil, []model.WorkflowMove{}
}
if len(wfms) == len(edges) {
params := make(map[string]int)
var param string
var temp int
for _, v := range wfms {
params[v.Param]++
}
for k, v := range params {
if temp < v {
temp = v
param = k
}
}
//参数携带模式暂时未定 暂时为少数服从多数原则 后续会增加原则配置 (少数服从多数,仅一关键字即为关键字,所有关键字才为关键字 三种方案)
txErr := tx.First(&edge, "workflow_process_id = ? and source = ? and condition_expression = ?", oldWfm.WorkflowProcessID, nodeInfo.ID, param).Error
if txErr != nil {
return txErr, []model.WorkflowMove{}
}
newWfm = append(newWfm, model.WorkflowMove{
BusinessID: oldWfm.BusinessID,
BusinessType: oldWfm.BusinessType,
PromoterID: oldWfm.PromoterID,
OperatorID: 0,
WorkflowNodeID: edge.Target,
WorkflowProcessID: oldWfm.WorkflowProcessID,
Param: "",
Action: "",
IsActive: true})
}
return nil, newWfm
case constant.PARELLEL_GATEWAY:
// 当为并行网关时候 找出所有线路创建并行节点
txErr := tx.Find(&edges, "workflow_process_id = ? and source = ?", oldWfm.WorkflowProcessID, nodeInfo.ID).Error
if txErr != nil {
return txErr, []model.WorkflowMove{}
}
for _, v := range edges {
newWfm = append(newWfm, model.WorkflowMove{
BusinessID: oldWfm.BusinessID,
BusinessType: oldWfm.BusinessType,
PromoterID: oldWfm.PromoterID,
OperatorID: 0,
WorkflowNodeID: v.Target,
WorkflowProcessID: oldWfm.WorkflowProcessID,
Param: "",
Action: "",
IsActive: true})
}
return nil, newWfm
default:
newWfm = append(newWfm, model.WorkflowMove{
BusinessID: oldWfm.BusinessID,
BusinessType: oldWfm.BusinessType,
PromoterID: oldWfm.PromoterID,
OperatorID: 0,
WorkflowNodeID: targetNodeID,
WorkflowProcessID: oldWfm.WorkflowProcessID,
Param: "",
Action: "",
IsActive: true})
return nil, newWfm
}
}
func GetMyStated(userID uint) (err error, wfms []model.WorkflowMove) {
err = global.GVA_DB.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").Joins("INNER JOIN workflow_nodes as node ON workflow_moves.workflow_node_id = node.id").Find(&wfms, "promoter_id = ? and ( is_active = ? OR node.clazz = ?)", userID, true, "end").Error
return err, wfms
}
func GetMyNeed(userID uint, AuthorityID string) (err error, wfms []model.WorkflowMove) {
user := "%," + strconv.Itoa(int(userID)) + ",%"
auth := "%," + AuthorityID + ",%"
err = global.GVA_DB.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").Joins("INNER JOIN workflow_nodes as node ON workflow_moves.workflow_node_id = node.id").Where("is_active = ? AND (node.assign_type = ? AND node.assign_value LIKE ? ) OR (node.assign_type = ? AND node.assign_value LIKE ? )", true, "user", user, "authority", auth).Find(&wfms).Error
return err, wfms
}
func GetWorkflowMoveByID(id float64) (err error, move model.WorkflowMove, moves []model.WorkflowMove, business interface{}) {
var result interface{}
err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
var txErr error
txErr = tx.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").First(&move, "id = ?", id).Error
if txErr != nil {
return txErr
}
txErr = tx.Preload("Promoter").Preload("Operator").Preload("WorkflowNode").Preload("WorkflowProcess").Find(&moves, "business_id = ? AND business_type = ?", move.BusinessID, move.BusinessType).Error
if txErr != nil {
return txErr
}
result = getTable(move.BusinessType)
fmt.Println(result)
txErr = tx.First(result, "id = ?", move.BusinessID).Error
if txErr != nil {
return txErr
}
return nil
})
return err, move, moves, result
}