node.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. package flow
  2. import (
  3. "container/list"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "log"
  8. "os"
  9. "strconv"
  10. "time"
  11. "github.com/mumushuiding/util"
  12. )
  13. // Node represents a specific logical unit of processing and routing
  14. // in a workflow.
  15. // 流程中的一个节点
  16. type Node struct {
  17. Name string `json:"name,omitempty"`
  18. Type string `json:"type,omitempty"`
  19. NodeID string `json:"nodeId,omitempty"`
  20. PrevID string `json:"prevId,omitempty"`
  21. ChildNode *Node `json:"childNode,omitempty"`
  22. ConditionNodes []*Node `json:"conditionNodes,omitempty"`
  23. Properties *NodeProperties `json:"properties,omitempty"`
  24. }
  25. // ActionConditionType 条件类型
  26. type ActionConditionType int
  27. const (
  28. // RANGE 条件类型: 范围
  29. RANGE ActionConditionType = iota
  30. // VALUE 条件类型: 值
  31. VALUE
  32. )
  33. // ActionConditionTypes 所有条件类型
  34. var ActionConditionTypes = [...]string{RANGE: "dingtalk_actioner_range_condition", VALUE: "dingtalk_actioner_value_condition"}
  35. // NodeType 节点类型
  36. type NodeType int
  37. const (
  38. // START 类型start
  39. START NodeType = iota
  40. ROUTE
  41. CONDITION
  42. APPROVER
  43. NOTIFIER
  44. )
  45. // ActionRuleType 审批人类型
  46. type ActionRuleType int
  47. const (
  48. MANAGER ActionRuleType = iota
  49. LABEL
  50. )
  51. // NodeTypes 节点类型
  52. var NodeTypes = [...]string{START: "start", ROUTE: "route", CONDITION: "condition", APPROVER: "approver", NOTIFIER: "notifier"}
  53. var actionRuleTypes = [...]string{MANAGER: "target_management", LABEL: "target_label"}
  54. type NodeInfoType int
  55. const (
  56. STARTER NodeInfoType = iota
  57. )
  58. var NodeInfoTypes = [...]string{STARTER: "starter"}
  59. type ActionerRule struct {
  60. Type string `json:"type,omitempty"`
  61. LabelNames string `json:"labelNames,omitempty"`
  62. Labels int `json:"labels,omitempty"`
  63. IsEmpty bool `json:"isEmpty,omitempty"`
  64. // 表示需要通过的人数 如果是会签
  65. MemberCount int8 `json:"memberCount,omitempty"`
  66. // and 表示会签 or表示或签,默认为或签
  67. ActType string `json:"actType,omitempty"`
  68. Level int8 `json:"level,omitempty"`
  69. AutoUp bool `json:"autoUp,omitempty"`
  70. }
  71. type NodeProperties struct {
  72. // ONE_BY_ONE 代表依次审批
  73. ActivateType string `json:"activateType,omitempty"`
  74. AgreeAll bool `json:"agreeAll,omitempty"`
  75. Conditions [][]*NodeCondition `json:"conditions,omitempty"`
  76. ActionerRules []*ActionerRule `json:"actionerRules,omitempty"`
  77. NoneActionerAction string `json:"noneActionerAction,omitempty"`
  78. }
  79. type NodeCondition struct {
  80. Type string `json:"type,omitempty"`
  81. ParamKey string `json:"paramKey,omitempty"`
  82. ParamLabel string `json:"paramLabel,omitempty"`
  83. IsEmpty bool `json:"isEmpty,omitempty"`
  84. // 类型为range
  85. LowerBound string `json:"lowerBound,omitempty"`
  86. LowerBoundEqual string `json:"lowerBoundEqual,omitempty"`
  87. UpperBoundEqual string `json:"upperBoundEqual,omitempty"`
  88. UpperBound string `json:"upperBound,omitempty"`
  89. BoundEqual string `json:"boundEqual,omitempty"`
  90. Unit string `json:"unit,omitempty"`
  91. // 类型为 value
  92. ParamValues []string `json:"paramValues,omitempty"`
  93. OriValue []string `json:"oriValue,omitempty"`
  94. Conds []*NodeCond `json:"conds,omitempty"`
  95. }
  96. type NodeCond struct {
  97. Type string `json:"type,omitempty"`
  98. Value string `json:"value,omitempty"`
  99. Attrs *NodeUser `json:"attrs,omitempty"`
  100. }
  101. type NodeUser struct {
  102. Name string `json:"name,omitempty"`
  103. Avatar string `json:"avatar,omitempty"`
  104. }
  105. // NodeInfo 节点信息
  106. type NodeInfo struct {
  107. NodeID string `json:"nodeId"`
  108. Type string `json:"type"`
  109. Aprover string `json:"approver"`
  110. AproverType string `json:"aproverType"`
  111. MemberCount int8 `json:"memberCount"`
  112. Level int8 `json:"level"`
  113. ActType string `json:"actType"`
  114. }
  115. // GetProcessConfigFromJSONFile test
  116. func (n *Node) GetProcessConfigFromJSONFile() {
  117. file, err := os.Open("D:/Workspaces/go/src/github.com/go-workflow/go-workflow/processConfig2.json")
  118. if err != nil {
  119. log.Printf("cannot open file processConfig.json:%v", err)
  120. panic(err)
  121. }
  122. decoder := json.NewDecoder(file)
  123. err = decoder.Decode(n)
  124. if err != nil {
  125. log.Printf("decode processConfig.json failed:%v", err)
  126. }
  127. }
  128. func (n *Node) add2ExecutionList(list *list.List) {
  129. switch n.Type {
  130. case NodeTypes[APPROVER], NodeTypes[NOTIFIER]:
  131. var aprover string
  132. if n.Properties.ActionerRules[0].Type == actionRuleTypes[MANAGER] {
  133. aprover = "主管"
  134. } else {
  135. aprover = n.Properties.ActionerRules[0].LabelNames
  136. }
  137. list.PushBack(NodeInfo{
  138. NodeID: n.NodeID,
  139. Type: n.Properties.ActionerRules[0].Type,
  140. Aprover: aprover,
  141. AproverType: n.Type,
  142. MemberCount: n.Properties.ActionerRules[0].MemberCount,
  143. ActType: n.Properties.ActionerRules[0].ActType,
  144. })
  145. break
  146. default:
  147. }
  148. }
  149. // IfProcessConifgIsValid 检查流程配置是否有效
  150. func IfProcessConifgIsValid(node *Node) error {
  151. // 节点名称是否有效
  152. if len(node.NodeID) == 0 {
  153. return errors.New("节点的【nodeId】不能为空!!")
  154. }
  155. // 检查类型是否有效
  156. if len(node.Type) == 0 {
  157. return errors.New("节点【" + node.NodeID + "】的类型【type】不能为空")
  158. }
  159. var flag = false
  160. for _, val := range NodeTypes {
  161. if val == node.Type {
  162. flag = true
  163. break
  164. }
  165. }
  166. if !flag {
  167. str, _ := util.ToJSONStr(NodeTypes)
  168. return errors.New("节点【" + node.NodeID + "】的类型为【" + node.Type + "】,为无效类型,有效类型为" + str)
  169. }
  170. // 当前节点是否设置有审批人
  171. if node.Type == NodeTypes[APPROVER] || node.Type == NodeTypes[NOTIFIER] {
  172. if node.Properties == nil || node.Properties.ActionerRules == nil {
  173. return errors.New("节点【" + node.NodeID + "】的Properties属性不能为空,如:`\"properties\": {\"actionerRules\": [{\"type\": \"target_label\",\"labelNames\": \"人事\",\"memberCount\": 1,\"actType\": \"and\"}],}`")
  174. }
  175. }
  176. // 条件节点是否存在
  177. if node.ConditionNodes != nil { // 存在条件节点
  178. if len(node.ConditionNodes) == 1 {
  179. return errors.New("节点【" + node.NodeID + "】条件节点下的节点数必须大于1")
  180. }
  181. // 根据条件变量选择节点索引
  182. err := CheckConditionNode(node.ConditionNodes)
  183. if err != nil {
  184. return err
  185. }
  186. }
  187. // 子节点是否存在
  188. if node.ChildNode != nil {
  189. return IfProcessConifgIsValid(node.ChildNode)
  190. }
  191. return nil
  192. }
  193. // CheckConditionNode 检查条件节点
  194. func CheckConditionNode(nodes []*Node) error {
  195. for _, node := range nodes {
  196. if node.Properties == nil {
  197. return errors.New("节点【" + node.NodeID + "】的Properties对象为空值!!")
  198. }
  199. if len(node.Properties.Conditions) == 0 {
  200. return errors.New("节点【" + node.NodeID + "】的Conditions对象为空值!!")
  201. }
  202. err := IfProcessConifgIsValid(node)
  203. if err != nil {
  204. return err
  205. }
  206. }
  207. return nil
  208. }
  209. // ParseProcessConfig 解析流程定义json数据
  210. func ParseProcessConfig(node *Node, variable *map[string]string) (*list.List, error) {
  211. // defer fmt.Println("----------解析结束--------")
  212. list := list.New()
  213. err := parseProcessConfig(node, variable, list)
  214. return list, err
  215. }
  216. func parseProcessConfig(node *Node, variable *map[string]string, list *list.List) (err error) {
  217. // fmt.Printf("nodeId=%s\n", node.NodeID)
  218. node.add2ExecutionList(list)
  219. // 存在条件节点
  220. if node.ConditionNodes != nil {
  221. // 如果条件节点只有一个或者条件只有一个,直接返回第一个
  222. if variable == nil || len(node.ConditionNodes) == 1 {
  223. err = parseProcessConfig(node.ConditionNodes[0].ChildNode, variable, list)
  224. if err != nil {
  225. return err
  226. }
  227. } else {
  228. // 根据条件变量选择节点索引
  229. condNode, err := GetConditionNode(node.ConditionNodes, variable)
  230. if err != nil {
  231. return err
  232. }
  233. if condNode == nil {
  234. str, _ := util.ToJSONStr(variable)
  235. return errors.New("节点【" + node.NodeID + "】找不到符合条件的子节点,检查变量【var】值是否匹配," + str)
  236. // panic(err)
  237. }
  238. err = parseProcessConfig(condNode, variable, list)
  239. if err != nil {
  240. return err
  241. }
  242. }
  243. }
  244. // 存在子节点
  245. if node.ChildNode != nil {
  246. err = parseProcessConfig(node.ChildNode, variable, list)
  247. if err != nil {
  248. return err
  249. }
  250. }
  251. return nil
  252. }
  253. // GetConditionNode 获取条件节点
  254. func GetConditionNode(nodes []*Node, maps *map[string]string) (result *Node, err error) {
  255. map2 := *maps
  256. for _, node := range nodes {
  257. var flag int
  258. for _, v := range node.Properties.Conditions[0] {
  259. paramValue := map2[v.ParamKey]
  260. if len(paramValue) == 0 {
  261. return nil, errors.New("流程启动变量【var】的key【" + v.ParamKey + "】的值不能为空")
  262. }
  263. yes, err := checkConditions(v, paramValue)
  264. if err != nil {
  265. return nil, err
  266. }
  267. if yes {
  268. flag++
  269. }
  270. }
  271. // fmt.Printf("flag=%d\n", flag)
  272. // 满足所有条件
  273. if flag == len(node.Properties.Conditions[0]) {
  274. result = node
  275. }
  276. }
  277. return result, nil
  278. }
  279. func getConditionNode(nodes []*Node, maps *map[string]string) (result *Node, err error) {
  280. map2 := *maps
  281. // 获取所有conditionNodes
  282. getNodesChan := func() <-chan *Node {
  283. nodesChan := make(chan *Node, len(nodes))
  284. go func() {
  285. // defer fmt.Println("关闭nodeChan通道")
  286. defer close(nodesChan)
  287. for _, v := range nodes {
  288. nodesChan <- v
  289. }
  290. }()
  291. return nodesChan
  292. }
  293. //获取所有conditions
  294. getConditionNode := func(nodesChan <-chan *Node, done <-chan interface{}) <-chan *Node {
  295. resultStream := make(chan *Node, 2)
  296. go func() {
  297. // defer fmt.Println("关闭resultStream通道")
  298. defer close(resultStream)
  299. for {
  300. select {
  301. case <-done:
  302. return
  303. case <-time.After(10 * time.Millisecond):
  304. fmt.Println("Time out.")
  305. case node, ok := <-nodesChan:
  306. if ok {
  307. // for _, v := range node.Properties.Conditions[0] {
  308. // conStream <- v
  309. // fmt.Printf("接收 condition:%s\n", v.Type)
  310. // }
  311. var flag int
  312. for _, v := range node.Properties.Conditions[0] {
  313. // fmt.Println(v.ParamKey)
  314. // fmt.Println(map2[v.ParamKey])
  315. paramValue := map2[v.ParamKey]
  316. if len(paramValue) == 0 {
  317. log.Printf("key:%s的值为空\n", v.ParamKey)
  318. // nodeAndErr.Err = errors.New("key:" + v.ParamKey + "的值为空")
  319. break
  320. }
  321. yes, err := checkConditions(v, paramValue)
  322. if err != nil {
  323. // nodeAndErr.Err = err
  324. break
  325. }
  326. if yes {
  327. flag++
  328. }
  329. }
  330. // fmt.Printf("flag=%d\n", flag)
  331. // 满足所有条件
  332. if flag == len(node.Properties.Conditions[0]) {
  333. // fmt.Printf("flag=%d\n,send node:%s\n", flag, node.NodeID)
  334. resultStream <- node
  335. } else {
  336. // fmt.Println("条件不完全满足")
  337. }
  338. }
  339. }
  340. }
  341. }()
  342. return resultStream
  343. }
  344. done := make(chan interface{})
  345. // defer fmt.Println("结束所有goroutine")
  346. defer close(done)
  347. nodeStream := getNodesChan()
  348. // for i := len(nodes); i > 0; i-- {
  349. // getConditionNode(resultStream, nodeStream, done)
  350. // }
  351. resultStream := getConditionNode(nodeStream, done)
  352. // for node := range resultStream {
  353. // return node, nil
  354. // }
  355. for {
  356. select {
  357. case <-time.After(1 * time.Second):
  358. fmt.Println("Time out")
  359. return
  360. case node := <-resultStream:
  361. // result = node
  362. return node, nil
  363. }
  364. }
  365. // setResult(resultStream, done)
  366. // time.Sleep(1 * time.Second)
  367. // log.Println("----------寻找节点结束--------")
  368. // return result, err
  369. }
  370. func checkConditions(cond *NodeCondition, value string) (bool, error) {
  371. // 判断类型
  372. switch cond.Type {
  373. case ActionConditionTypes[RANGE]:
  374. val, err := strconv.Atoi(value)
  375. if err != nil {
  376. return false, err
  377. }
  378. if len(cond.LowerBound) == 0 && len(cond.UpperBound) == 0 && len(cond.LowerBoundEqual) == 0 && len(cond.UpperBoundEqual) == 0 && len(cond.BoundEqual) == 0 {
  379. return false, errors.New("条件【" + cond.Type + "】的上限或者下限值不能全为空")
  380. }
  381. // 判断下限,lowerBound
  382. if len(cond.LowerBound) > 0 {
  383. low, err := strconv.Atoi(cond.LowerBound)
  384. if err != nil {
  385. return false, err
  386. }
  387. if val <= low {
  388. // fmt.Printf("val:%d小于lowerBound:%d\n", val, low)
  389. return false, nil
  390. }
  391. }
  392. if len(cond.LowerBoundEqual) > 0 {
  393. le, err := strconv.Atoi(cond.LowerBoundEqual)
  394. if err != nil {
  395. return false, err
  396. }
  397. if val < le {
  398. // fmt.Printf("val:%d小于lowerBound:%d\n", val, low)
  399. return false, nil
  400. }
  401. }
  402. // 判断上限,upperBound包含等于
  403. if len(cond.UpperBound) > 0 {
  404. upper, err := strconv.Atoi(cond.UpperBound)
  405. if err != nil {
  406. return false, err
  407. }
  408. if val >= upper {
  409. return false, nil
  410. }
  411. }
  412. if len(cond.UpperBoundEqual) > 0 {
  413. ge, err := strconv.Atoi(cond.UpperBoundEqual)
  414. if err != nil {
  415. return false, err
  416. }
  417. if val > ge {
  418. return false, nil
  419. }
  420. }
  421. if len(cond.BoundEqual) > 0 {
  422. equal, err := strconv.Atoi(cond.BoundEqual)
  423. if err != nil {
  424. return false, err
  425. }
  426. if val != equal {
  427. return false, nil
  428. }
  429. }
  430. return true, nil
  431. case ActionConditionTypes[VALUE]:
  432. if len(cond.ParamValues) == 0 {
  433. return false, errors.New("条件节点【" + cond.Type + "】的 【paramValues】数组不能为空,值如:'paramValues:['调休','年假']")
  434. }
  435. for _, val := range cond.ParamValues {
  436. if value == val {
  437. return true, nil
  438. }
  439. }
  440. // log.Printf("key:" + cond.ParamKey + "找不到对应的值")
  441. return false, nil
  442. default:
  443. str, _ := util.ToJSONStr(ActionConditionTypes)
  444. return false, errors.New("未知的NodeCondition类型【" + cond.Type + "】,正确类型应为以下中的一个:" + str)
  445. }
  446. }