Recently, WHEN I was studying the work order system, I found a very bad work order system. As we all know, the most troublesome part of work order system is the maintenance of process and template, and some operations are likely to be added in the process of work order processing, which are called hooks. According to the results of my current research, there is no work order system can achieve such a good.

This work order system on the process design, template design and so on do very good, and the control of permissions is very detailed, including API interface, menu, page button permissions, can be flexible control, very good.

Demo:fdevops.com: 8001 / # / dashboard

Github:github.com/lanyulei/fe…

If you feel good, give the author a star. Your star may be the motivation for the author to keep going.

Function is introduced

System management

  • User management not only includes users, but also the management of roles, positions and departments, which is convenient for the extension of work order processing personnel.
  • Menu management, menu, page buttons, and even API interface management.
  • Login log, which records user login and logout logs.

Process center

  • Process application, process classification management, convenient maintenance and visualization.
  • To-do list, split into 4 categories, including: my to-do list, my created to-do list, my associated to-do list, and all to-do lists.
  • To hand over work orders to someone else if you are currently working on something else.
  • End work order, if a work order development application is not correct, the authority is enough, it can directly end work order.
  • The diversity of work order processing personnel can not only be handled individually, but also can be departments, roles and variables.
  • Handler variables are automatically obtained based on user data, such as founder, founder leader, HRBP, etc.
  • Countersign, if it is multiple selectors, and the countersign function is checked, then it will be passed only after these responsible persons have been processed.
  • Task management can bind tasks to any stage, which is equivalent to the hook operation in the process. The effect achieved is that when the work order is completed, the task will be executed and a lot of labor costs will be reduced.
  • The flexibility of notification can be tied to each phase by task or to the process globally.
  • Gateway, supporting exclusive gateway and parallel gateway, the exclusive gateway is judged by the condition, as long as one condition passes, can enter the next stage; Parallel gateways, that is, all phases must be processed before the next phase can proceed
  • There will also be a number of extensions, including: checkmark, prompt, sub-process and so on.

And so on there’s a lot more to study.

Data structure design

For a complete workflow system, we need to have a process, the template, grouping, users, tasks, etc., and all these things can be flexible customization, because if not flexible customization, for common use this is not very convenient, so for a good workflow system, is a must to achieve flexibility.

So let’s go straight to the design of the data structure.

Process classification

type Classify struct {
	base.Model
	Name    string `gorm:"column:name; type: varchar(128)" json:"name" form:"name"'// Category name Creator int' gorm:"column:creator; type: int(11)" json:"creator" form:"creator"'// creator} func (Classify) TableName() string {return "process_classify"
}
Copy the code

process

type Info struct {
	base.Model
	Name      string          `gorm:"column:name; type:varchar(128)" json:"name" form:"name"'// Process name Structure json.rawMessage' gorm:"column:structure; type:json" json:"structure" form:"structure"'// process structure Classify int' gorm:"column:classify; type:int(11)" json:"classify" form:"classify"'// category ID Tpls json.RawMessage' gorm:"column:tpls; type:json" json:"tpls" form:"tpls"'// template Task json.RawMessage' gorm:"column:task; type:json" json:"task" form:"task"'// Task ID, array, can execute multiple tasks, can be used as a notification task, each node will execute Creator int' gorm:"column:creator; type:int(11)" json:"creator" form:"creator"'// creator} func (Info) TableName() string {return "process_info"
}
Copy the code

template

type Info struct {
	base.Model
	Name          string          `gorm:"column:name; type: varchar(128)" json:"name" form:"name" binding:"required"'// Template name FormStructure json.RawMessage' gorm:"column:form_structure; type: json" json:"form_structure" form:"form_structure" binding:"required"'// Form structure Creator int' gorm:"column:creator; type: int(11)" json:"creator" form:"creator"'// Remarks:"column:remarks; type: longtext" json:"remarks" form:"remarks"'// Remarks} func (Info) TableName() string {return "tpl_info"
}
Copy the code

The repair order

type Info struct {
	base.Model
	Title         string          `gorm:"column:title; type:varchar(128)" json:"title" form:"title"Process int 'gorm:"column:process; type:int(11)" json:"process" form:"process"'// Process ID Classify int' gorm:"column:classify; type:int(11)" json:"classify" form:"classify"'// category ID IsEnd int' gorm:"column:is_end; type:int(11); default:0" json:"is_end" form:"is_end"State json.RawMessage 'gorm:"column:state; type:json" json:"state" form:"state"'// RelatedPerson json.RawMessage' gorm:"column:related_person; type:json" json:"related_person" form:"related_person"'// Creator int' gorm:"column:creator; type:int(11)" json:"creator" form:"creator"'// creator} func (Info) TableName() string {return "work_order_info"
}
Copy the code

Work order binding template

type TplData struct {
	base.Model
	WorkOrder     int             `gorm:"column:work_order; type: int(11)" json:"work_order" form:"work_order"'// workorder ID FormStructure json.RawMessage' gorm:"column:form_structure; type: json" json:"form_structure" form:"form_structure"'// FormData json.RawMessage' gorm:"column:form_data; type: json" json:"form_data" form:"form_data"'// Form data} func (TplData) TableName() string {return "work_order_tpl_data"
}
Copy the code

Work order transfer history

type CirculationHistory struct {
	base.Model
	Title        string `gorm:"column:title; type: varchar(128)" json:"title" form:"title"WorkOrder int 'gorm:"column:work_order; type: int(11)" json:"work_order" form:"work_order"'// ID State string' gorm:"column:state; type: varchar(128)" json:"state" form:"state"'// Work order status Source string' gorm:"column:source; type: varchar(128)" json:"source" form:"source"'// Source node ID Target string' gorm:"column:target; type: varchar(128)" json:"target" form:"target"'// Object ID Circulation String' GORm:"column:circulation; type: varchar(128)" json:"circulation" form:"circulation"'// Processor string' GORm:"column:processor; type: varchar(45)" json:"processor" form:"processor"'// ProcessorId int' gorm:"column:processor_id; type: int(11)" json:"processor_id" form:"processor_id"'// Handler ID CostDuration string' gorm:"column:cost_duration; type: varchar(128)" json:"cost_duration" form:"cost_duration"'// Processing"column:remarks; type: longtext" json:"remarks" form:"remarks"'// note} func (CirculationHistory) TableName() string {return "work_order_circulation_history"
}
Copy the code

task

type Info struct {
	base.Model
	Name     string `gorm:"column:name; type: varchar(256)" json:"name" form:"name"'// TaskType string' gorm:"column:task_type; type: varchar(45)" json:"task_type" form:"task_type"'// Task Type Content String' gorm:"column:content; type: longtext" json:"content" form:"content"'// Task content Creator int' gorm:"column:creator; type: int(11)" json:"creator" form:"creator"'// Remarks:"column:remarks; type: longtext" json:"remarks" form:"remarks"'// Remarks} func (Info) TableName() string {return "task_info"
}
Copy the code

Task Execution History

type History struct {
	base.Model
	Task          int    `gorm:"column:task; type: int(11)" json:"task" form:"task"'// Task ID Name string' gorm:"column:name; type: varchar(256)" json:"name" form:"name"'// TaskType int' gorm:"column:task_type; type: int(11)" json:"task_type" form:"task_type"'// Task type, Python, shell ExecutionTime String' gorm:"column:execution_time; type: varchar(128)" json:"execution_time" form:"execution_time"'// Execution time Result string' gorm:"column:result; type: longtext" json:"result" form:"result"'// Task return} func (History) TableName() string {return "task_history"
}
Copy the code

Install the deployment

Go >= 1.14vue >= 2.6 NPM >= 6.14Copy the code

Secondary development

The back-end

# 1. Get the code
git https://github.com/lanyulei/ferry.git

# 2. Enter the work path
cd ./ferry

Ferry/config / # 3. Modify the configuration Settings. The dev. Yml
vi ferry/config/settings.dev.yml

Note:Program startup parameters 2. Database information 3. Log path# 4. Initialize database
go run main.go init -c=config/settings.dev.yml

# 5. Start the program
go run main.go server -c=config/settings.dev.yml
Copy the code

The front end

# 1. Get the code
git https://github.com/lanyulei/ferry_web.git

# 2. Enter the work path
cd ./ferry_web

# 3. Install dependencies
npm install

# 4. Start the program
npm run dev
Copy the code

On-line deployment

The back-end

# 1. Enter the project path and cross-compile (centos)Env GOOS = Linux GOARCH = amd64 go build cross-compilation content more, please visit https://www.fdevops.com/2020/03/08/go-locale-configurationUpload the config directory to the project root and verify that the configuration information is correct
vi ferry/config/settings.yml

Note:Program startup parameters 2. Database information 3. Log path# 3. Create log path and static file experience
mkdir -p log static/uploadfile

# 4. Initialize data
./ferry init -c=config/settings.yml

# 5. Start the program. It is recommended to use the "Process Management Tool" for startup maintenance
nohup ./ferry server -c=config/settings.yml > /dev/null 2>&1 &
Copy the code

The front end

# 1. The compilation
npm run build:prod

# 2. Upload the dist directory to the project path.
mv dist web

# 3. Nginx configuration, according to the business can be adjusted
  server {
    listen 8001; # monitor port
    server_name localhost; # Multiple domain names can be separated by Spaces
  
    #charset koi8-r;
  
    #access_log logs/host.access.log main;
    location / {
      root /data/ferry/web;
      index index.html index.htm; If there is no match for index.html, search for index.htm, and so on
    }
  
    # SSL configuration omitted
    location /api {
      # rewrite ^.+api/? (.*)$ /$1 break;Proxy_pass http://127.0.0.1:8002;Node API Server requires the IP address of the proxy
      proxy_redirect off;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  
    # landingLocation /login {proxy_pass http://127.0.0.1:8002;Node API Server requires the IP address of the proxy
    }
  
    # the refresh tokenLocation /refresh_token {proxy_pass http://127.0.0.1:8002;Node API Server requires the IP address of the proxy
    }
  
    Interface addressLocation /swagger {proxy_pass http://127.0.0.1:8002;Node API Server requires the IP address of the proxy
    }
  
    Backend static file pathLocation /static/uploadfile {proxy_pass http://127.0.0.1:8002;Node API Server requires the IP address of the proxy
    }
  
    #error_page 404 /404.html; Error page 404.html is configured
  
    # redirect server error pages to the static page /50x.html
    Redirect the server error page to static page /50x.html
    #error_page 500 502 503 504 /50x.html; location = /50x.html { root html; }}Copy the code

This project is finished. Anyway, I think it is very good. If you also think it is good, please give the author a star.