Merge remote-tracking branch 'origin/test' into dev
正在显示
28 个修改的文件
包含
1051 行增加
和
104 行删除
| @@ -11,6 +11,7 @@ require ( | @@ -11,6 +11,7 @@ require ( | ||
| 11 | github.com/gavv/httpexpect v2.0.0+incompatible | 11 | github.com/gavv/httpexpect v2.0.0+incompatible |
| 12 | github.com/go-pg/pg/v10 v10.9.0 | 12 | github.com/go-pg/pg/v10 v10.9.0 |
| 13 | github.com/google/go-querystring v1.1.0 // indirect | 13 | github.com/google/go-querystring v1.1.0 // indirect |
| 14 | + github.com/gookit/event v1.0.6 | ||
| 14 | github.com/imkira/go-interpol v1.1.0 // indirect | 15 | github.com/imkira/go-interpol v1.1.0 // indirect |
| 15 | github.com/linmadan/egglib-go v0.0.0-20210313060205-8b5e456b11f7 | 16 | github.com/linmadan/egglib-go v0.0.0-20210313060205-8b5e456b11f7 |
| 16 | github.com/mattn/go-colorable v0.1.8 // indirect | 17 | github.com/mattn/go-colorable v0.1.8 // indirect |
| @@ -19,7 +20,7 @@ require ( | @@ -19,7 +20,7 @@ require ( | ||
| 19 | github.com/onsi/gomega v1.11.0 | 20 | github.com/onsi/gomega v1.11.0 |
| 20 | github.com/sergi/go-diff v1.2.0 // indirect | 21 | github.com/sergi/go-diff v1.2.0 // indirect |
| 21 | github.com/smartystreets/goconvey v1.6.4 // indirect | 22 | github.com/smartystreets/goconvey v1.6.4 // indirect |
| 22 | - github.com/stretchr/testify v1.7.0 | 23 | + github.com/stretchr/testify v1.7.1 |
| 23 | github.com/tal-tech/go-queue v1.0.5 | 24 | github.com/tal-tech/go-queue v1.0.5 |
| 24 | github.com/tal-tech/go-zero v1.0.27 | 25 | github.com/tal-tech/go-zero v1.0.27 |
| 25 | github.com/valyala/fasthttp v1.23.0 // indirect | 26 | github.com/valyala/fasthttp v1.23.0 // indirect |
| @@ -164,6 +164,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 | @@ -164,6 +164,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 | ||
| 164 | github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | 164 | github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
| 165 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= | 165 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= |
| 166 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | 166 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
| 167 | +github.com/gookit/event v1.0.6 h1:/U95T1tBzt9RSSi23pg4VR3B9VWkyM4xv8TXAGi60IQ= | ||
| 168 | +github.com/gookit/event v1.0.6/go.mod h1:7Udf/q/HQcrK9XE4JZUvbqi46rI1V8r/Pvao2NbPajA= | ||
| 167 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= | 169 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= |
| 168 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | 170 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= |
| 169 | github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= | 171 | github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= |
| @@ -348,8 +350,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV | @@ -348,8 +350,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV | ||
| 348 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | 350 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= |
| 349 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= | 351 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= |
| 350 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | 352 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
| 351 | -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= | ||
| 352 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | 353 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
| 354 | +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= | ||
| 355 | +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
| 353 | github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= | 356 | github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= |
| 354 | github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= | 357 | github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= |
| 355 | github.com/tal-tech/go-queue v1.0.5 h1:cd2o0lPjAFJKIXuEbQvsGypUhzz6FLib4FVVAyxsMtY= | 358 | github.com/tal-tech/go-queue v1.0.5 h1:cd2o0lPjAFJKIXuEbQvsGypUhzz6FLib4FVVAyxsMtY= |
| @@ -26,6 +26,8 @@ type CreateMenuCommand struct { | @@ -26,6 +26,8 @@ type CreateMenuCommand struct { | ||
| 26 | IsPublish int `json:"isPublish" valid:"Required"` | 26 | IsPublish int `json:"isPublish" valid:"Required"` |
| 27 | // 启用状态(启用:1 禁用:2),默认启用 | 27 | // 启用状态(启用:1 禁用:2),默认启用 |
| 28 | EnableStatus int `json:"enableStatus" ` | 28 | EnableStatus int `json:"enableStatus" ` |
| 29 | + // 外链接(需要菜单跳转的时候使用) | ||
| 30 | + Link string `json:"link"` | ||
| 29 | } | 31 | } |
| 30 | 32 | ||
| 31 | func (createMenuCommand *CreateMenuCommand) Valid(validation *validation.Validation) { | 33 | func (createMenuCommand *CreateMenuCommand) Valid(validation *validation.Validation) { |
| @@ -29,6 +29,8 @@ type UpdateMenuCommand struct { | @@ -29,6 +29,8 @@ type UpdateMenuCommand struct { | ||
| 29 | IsPublish int `json:"isPublish,omitempty"` | 29 | IsPublish int `json:"isPublish,omitempty"` |
| 30 | // 启用状态(启用:1 禁用:2),默认启用 | 30 | // 启用状态(启用:1 禁用:2),默认启用 |
| 31 | EnableStatus int `json:"enableStatus"` | 31 | EnableStatus int `json:"enableStatus"` |
| 32 | + // 外链接(需要菜单跳转的时候使用) | ||
| 33 | + Link string `json:"link"` | ||
| 32 | } | 34 | } |
| 33 | 35 | ||
| 34 | func (updateMenuCommand *UpdateMenuCommand) Valid(validation *validation.Validation) { | 36 | func (updateMenuCommand *UpdateMenuCommand) Valid(validation *validation.Validation) { |
| 1 | +package command | ||
| 2 | + | ||
| 3 | +import ( | ||
| 4 | + "fmt" | ||
| 5 | + "reflect" | ||
| 6 | + "strings" | ||
| 7 | + | ||
| 8 | + "github.com/beego/beego/v2/core/validation" | ||
| 9 | +) | ||
| 10 | + | ||
| 11 | +type TerminalReportCommand struct { | ||
| 12 | + TerminalType string `json:"terminalType"` | ||
| 13 | + TerminalId string `json:"terminalId"` | ||
| 14 | + Command string `json:"command"` | ||
| 15 | + Content string `json:"content"` | ||
| 16 | + Table string `json:"table"` | ||
| 17 | + | ||
| 18 | + CompanyId int64 `json:"companyId"` | ||
| 19 | + OrgId int64 `json:"orgId"` | ||
| 20 | +} | ||
| 21 | + | ||
| 22 | +func (terminalReportCommand *TerminalReportCommand) Valid(validation *validation.Validation) { | ||
| 23 | + | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +func (terminalReportCommand *TerminalReportCommand) ValidateCommand() error { | ||
| 27 | + valid := validation.Validation{} | ||
| 28 | + b, err := valid.Valid(terminalReportCommand) | ||
| 29 | + if err != nil { | ||
| 30 | + return err | ||
| 31 | + } | ||
| 32 | + if !b { | ||
| 33 | + elem := reflect.TypeOf(terminalReportCommand).Elem() | ||
| 34 | + for _, validErr := range valid.Errors { | ||
| 35 | + field, isExist := elem.FieldByName(validErr.Field) | ||
| 36 | + if isExist { | ||
| 37 | + return fmt.Errorf(strings.Replace(validErr.Message, validErr.Field, field.Tag.Get("cname"), -1)) | ||
| 38 | + } else { | ||
| 39 | + return fmt.Errorf(validErr.Message) | ||
| 40 | + } | ||
| 41 | + } | ||
| 42 | + } | ||
| 43 | + return nil | ||
| 44 | +} |
pkg/application/terminal/service/terminal.go
0 → 100644
| 1 | +package service | ||
| 2 | + | ||
| 3 | +import ( | ||
| 4 | + "bytes" | ||
| 5 | + "fmt" | ||
| 6 | + "github.com/beego/beego/v2/adapter/utils" | ||
| 7 | + "github.com/gookit/event" | ||
| 8 | + "github.com/linmadan/egglib-go/core/application" | ||
| 9 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/application/factory" | ||
| 10 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/application/terminal/command" | ||
| 11 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/domain" | ||
| 12 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/log" | ||
| 13 | + "io" | ||
| 14 | +) | ||
| 15 | + | ||
| 16 | +var GlobalTerminalManager *TerminalManager | ||
| 17 | + | ||
| 18 | +func init() { | ||
| 19 | + GlobalTerminalManager = NewTerminalManager() | ||
| 20 | + event.On(domain.UserCreateEvent, event.ListenerFunc(GlobalTerminalManager.SyncUser)) | ||
| 21 | + event.On(domain.UserUpdateEvent, event.ListenerFunc(GlobalTerminalManager.SyncUser)) | ||
| 22 | + event.On(domain.UserEnableEvent, event.ListenerFunc(GlobalTerminalManager.EnableUser)) | ||
| 23 | + event.On(domain.UserSyncEvent, event.ListenerFunc(GlobalTerminalManager.SyncUser)) | ||
| 24 | + event.On(DownEntityEvent, event.ListenerFunc(GlobalTerminalManager.DownEntityEvent)) | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +type TerminalService struct { | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +func NewTerminalService(options map[string]interface{}) *TerminalService { | ||
| 31 | + newUserService := &TerminalService{} | ||
| 32 | + return newUserService | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +func (svr *TerminalService) TerminalReport(cmd *command.TerminalReportCommand) (interface{}, error) { | ||
| 36 | + if err := cmd.ValidateCommand(); err != nil { | ||
| 37 | + return nil, application.ThrowError(application.ARG_ERROR, err.Error()) | ||
| 38 | + } | ||
| 39 | + transactionContext, err := factory.CreateTransactionContext(nil) | ||
| 40 | + if err != nil { | ||
| 41 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
| 42 | + } | ||
| 43 | + if err := transactionContext.StartTransaction(); err != nil { | ||
| 44 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
| 45 | + } | ||
| 46 | + defer func() { | ||
| 47 | + transactionContext.RollbackTransaction() | ||
| 48 | + }() | ||
| 49 | + response, err := terminalReport(cmd, transactionContext) | ||
| 50 | + if err != nil { | ||
| 51 | + log.Logger.Error(err.Error()) | ||
| 52 | + return nil, err | ||
| 53 | + } | ||
| 54 | + if err := transactionContext.CommitTransaction(); err != nil { | ||
| 55 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
| 56 | + } | ||
| 57 | + return response, nil | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +func terminalReport(cmd *command.TerminalReportCommand, transactionContext application.TransactionContext) (interface{}, error) { | ||
| 61 | + var ( | ||
| 62 | + response string = "OK" | ||
| 63 | + ) | ||
| 64 | + | ||
| 65 | + switch cmd.Command { | ||
| 66 | + case "getrequest": | ||
| 67 | + device, ok := GlobalTerminalManager.GetDevice(cmd.TerminalId) | ||
| 68 | + if !ok || device == nil { | ||
| 69 | + break | ||
| 70 | + } | ||
| 71 | + if downEntity, ok := device.PopDownEntity(); ok && downEntity != nil { | ||
| 72 | + response = downEntity.DownCommand() | ||
| 73 | + } | ||
| 74 | + break | ||
| 75 | + case "cdata": | ||
| 76 | + parseEntities := ParseData(cmd) | ||
| 77 | + var ( | ||
| 78 | + down DownEntity | ||
| 79 | + err error | ||
| 80 | + handler Handler = ZKClockHandler{TransactionContext: transactionContext} | ||
| 81 | + ) | ||
| 82 | + for _, entity := range parseEntities { | ||
| 83 | + switch TableType(cmd.Table) { | ||
| 84 | + case AttLOG: | ||
| 85 | + down, err = handler.Attendance(entity.(AttLOGUpEntity)) | ||
| 86 | + case BIODATA: | ||
| 87 | + down, err = handler.BioData(entity.(BIODATAEntity)) | ||
| 88 | + case OPERLOG: | ||
| 89 | + //if v, ok := entity.(USEREntity); ok { | ||
| 90 | + // down, err = handler.ReportUser(v) | ||
| 91 | + //} | ||
| 92 | + if v, ok := entity.(BIODATAEntity); ok { | ||
| 93 | + down, err = handler.BioData(v) | ||
| 94 | + } | ||
| 95 | + } | ||
| 96 | + if err != nil { | ||
| 97 | + log.Logger.Error(err.Error()) | ||
| 98 | + continue | ||
| 99 | + } | ||
| 100 | + if down != nil { | ||
| 101 | + response = down.DownCommand() | ||
| 102 | + } | ||
| 103 | + break | ||
| 104 | + } | ||
| 105 | + case "devicecmd": | ||
| 106 | + log.Logger.Debug("【TerminalManager】 收到命令应答 cmd : " + cmd.Content) | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + return map[string]interface{}{ | ||
| 110 | + "response": response, | ||
| 111 | + }, nil | ||
| 112 | +} | ||
| 113 | + | ||
| 114 | +func ParseData(cmd *command.TerminalReportCommand) []interface{} { | ||
| 115 | + result := make([]interface{}, 0) | ||
| 116 | + buf := bytes.NewBufferString(cmd.Content) | ||
| 117 | + for { | ||
| 118 | + line, err := buf.ReadBytes('\n') | ||
| 119 | + if err == io.EOF { | ||
| 120 | + break | ||
| 121 | + } | ||
| 122 | + if err != nil { | ||
| 123 | + log.Logger.Error(err.Error()) | ||
| 124 | + break | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + switch TableType(cmd.Table) { | ||
| 128 | + case AttLOG: | ||
| 129 | + columns := bytes.Split(line, ([]byte)("\t")) | ||
| 130 | + if len(columns) != 11 { //10 + 1 空格 | ||
| 131 | + continue | ||
| 132 | + } | ||
| 133 | + result = append(result, AttLOGUpEntity{ | ||
| 134 | + Pin: string(columns[0]), | ||
| 135 | + CompanyId: cmd.CompanyId, | ||
| 136 | + OrgId: cmd.OrgId, | ||
| 137 | + }) | ||
| 138 | + case BIODATA: | ||
| 139 | + /*BIODATA Pin=3\tNo=0\tIndex=0\tValid=1\tDuress=0\tType=9\tMajorVer=39\tMinorVer=1\tFormat= | ||
| 140 | + 0\tTmp=apUBEBABQo4JACcBAWiOADA7dP4pU9F31Uxom7NAGjM4eO/8X5Ee4uahkIT11c3188+VguMsd3oCO0O29efRyxofdLiohI4QL7woK3U*/ | ||
| 141 | + columns := readLineToMap(line, "BIODATA") | ||
| 142 | + result = append(result, BIODATAEntity{ | ||
| 143 | + Pin: columns["Pin"], | ||
| 144 | + No: columns["No"], | ||
| 145 | + Index: columns["Index"], | ||
| 146 | + Duress: columns["Duress"], | ||
| 147 | + Type: columns["Type"], | ||
| 148 | + MinorVer: columns["MinorVer"], | ||
| 149 | + MajorVer: columns["MajorVer"], | ||
| 150 | + Format: columns["Format"], | ||
| 151 | + Tmp: columns["Tmp"], | ||
| 152 | + CompanyId: cmd.CompanyId, | ||
| 153 | + OrgId: cmd.OrgId, | ||
| 154 | + }) | ||
| 155 | + case OPERLOG: | ||
| 156 | + if bytes.HasPrefix(line, []byte("FP")) { | ||
| 157 | + /* | ||
| 158 | + FP PIN=3 FID=6 Size=1336 Valid=1 TMP=SqtTUzIxAAAD6O8ECA | ||
| 159 | + */ | ||
| 160 | + columns := readLineToMap(line, "FP") | ||
| 161 | + result = append(result, BIODATAEntity{ | ||
| 162 | + Pin: columns["PIN"], | ||
| 163 | + Type: fmt.Sprintf("%v", BioDataType1), | ||
| 164 | + Tmp: columns["TMP"], | ||
| 165 | + CompanyId: cmd.CompanyId, | ||
| 166 | + OrgId: cmd.OrgId, | ||
| 167 | + }) | ||
| 168 | + } else if bytes.HasPrefix(line, []byte("USER")) { | ||
| 169 | + /* | ||
| 170 | + USER PIN=3 Name=杨xx Pri=14 Passwd= Card=3731588478 Grp=1 TZ=0000000100000000 Verify=-1 ViceCard= StartDatetime=0 EndDatetime=0 | ||
| 171 | + */ | ||
| 172 | + columns := readLineToMap(line, "USER") | ||
| 173 | + name := columns["Name"] //GbkToUtf8(columns["Name"]) | ||
| 174 | + result = append(result, USEREntity{ | ||
| 175 | + OPERLOGType: "USER", | ||
| 176 | + Pin: columns["PIN"], | ||
| 177 | + Name: name, | ||
| 178 | + CompanyId: cmd.CompanyId, | ||
| 179 | + OrgId: cmd.OrgId, | ||
| 180 | + }) | ||
| 181 | + } | ||
| 182 | + } | ||
| 183 | + } | ||
| 184 | + return result | ||
| 185 | +} | ||
| 186 | + | ||
| 187 | +func readLineToMap(line []byte, prefix string) map[string]string { | ||
| 188 | + var result = make(map[string]string) | ||
| 189 | + line = bytes.TrimLeft(line, prefix) | ||
| 190 | + line = bytes.TrimSpace(line) | ||
| 191 | + columns := bytes.Fields(line) | ||
| 192 | + for i := range columns { | ||
| 193 | + kv := bytes.SplitN(columns[i], []byte("="), 2) | ||
| 194 | + if len(kv) < 2 { | ||
| 195 | + continue | ||
| 196 | + } | ||
| 197 | + //if string(kv[0]) == "Name" { | ||
| 198 | + // log.Logger.Debug(fmt.Sprintf("%x", kv[1])) | ||
| 199 | + // log.Logger.Debug(fmt.Sprintf("%v", kv[1])) | ||
| 200 | + // log.Logger.Debug(fmt.Sprintf("%s", string(kv[1]))) | ||
| 201 | + //} | ||
| 202 | + result[string(kv[0])] = string(kv[1]) | ||
| 203 | + } | ||
| 204 | + return result | ||
| 205 | +} | ||
| 206 | + | ||
| 207 | +type Handler interface { | ||
| 208 | + Attendance(entity AttLOGUpEntity) (DownEntity, error) | ||
| 209 | + BioData(entity BIODATAEntity) (DownEntity, error) | ||
| 210 | + ReportUser(entity USEREntity) (DownEntity, error) | ||
| 211 | +} | ||
| 212 | + | ||
| 213 | +type ZKClockHandler struct { | ||
| 214 | + TransactionContext application.TransactionContext | ||
| 215 | +} | ||
| 216 | + | ||
| 217 | +func (handler ZKClockHandler) Attendance(entity AttLOGUpEntity) (DownEntity, error) { | ||
| 218 | + var ( | ||
| 219 | + userRepository, _, _ = factory.FastPgUser(handler.TransactionContext, 0) | ||
| 220 | + userBaseRepository, _, _ = factory.FastPgUserBase(handler.TransactionContext, 0) | ||
| 221 | + user *domain.User | ||
| 222 | + userBase *domain.UserBase | ||
| 223 | + err error | ||
| 224 | + ) | ||
| 225 | + if user, err = userRepository.FindOne(map[string]interface{}{"companyId": entity.CompanyId, "orgId": entity.OrgId, "icCardNumber": entity.Pin}); err != nil { | ||
| 226 | + return nil, err | ||
| 227 | + } | ||
| 228 | + if userBase, err = userBaseRepository.FindOne(map[string]interface{}{"userBaseId": user.UserBaseId}); err != nil { | ||
| 229 | + return nil, err | ||
| 230 | + } | ||
| 231 | + var sendQuery bool | ||
| 232 | + // 请求 人脸识别-用户画像 | ||
| 233 | + if len(userBase.UserInfo.FacePortrait) == 0 { | ||
| 234 | + sendQuery = true | ||
| 235 | + //event.Fire(DownEntityEvent, map[string]interface{}{"entity": NewQueryBIODATADownEntity(generateSn(), entity.Pin, BioDataType2)}) | ||
| 236 | + } | ||
| 237 | + // 请求 人脸识别-指纹 | ||
| 238 | + if len(userBase.UserInfo.FingerprintPortrait) == 0 { | ||
| 239 | + sendQuery = true | ||
| 240 | + } | ||
| 241 | + if sendQuery { | ||
| 242 | + event.Fire(DownEntityEvent, map[string]interface{}{"entity": NewQueryUserInfoDownEntity(generateSn(), entity.Pin)}) | ||
| 243 | + } | ||
| 244 | + return nil, nil | ||
| 245 | +} | ||
| 246 | + | ||
| 247 | +func (handler ZKClockHandler) BioData(entity BIODATAEntity) (DownEntity, error) { | ||
| 248 | + var ( | ||
| 249 | + userRepository, _, _ = factory.FastPgUser(handler.TransactionContext, 0) | ||
| 250 | + userBaseRepository, _, _ = factory.FastPgUserBase(handler.TransactionContext, 0) | ||
| 251 | + user *domain.User | ||
| 252 | + userBase *domain.UserBase | ||
| 253 | + err error | ||
| 254 | + updateFlag bool | ||
| 255 | + ) | ||
| 256 | + if user, err = userRepository.FindOne(map[string]interface{}{"companyId": entity.CompanyId, "orgId": entity.OrgId, "icCardNumber": entity.Pin}); err != nil { | ||
| 257 | + return nil, err | ||
| 258 | + } | ||
| 259 | + if userBase, err = userBaseRepository.FindOne(map[string]interface{}{"userBaseId": user.UserBaseId}); err != nil { | ||
| 260 | + return nil, err | ||
| 261 | + } | ||
| 262 | + // 请求 人脸识别-用户画像 | ||
| 263 | + if len(userBase.UserInfo.FacePortrait) == 0 && len(entity.Tmp) > 0 && entity.Type == "9" { | ||
| 264 | + userBase.UserInfo.FacePortrait = entity.Tmp | ||
| 265 | + updateFlag = true | ||
| 266 | + } | ||
| 267 | + // 请求 人脸识别-指纹 | ||
| 268 | + if len(userBase.UserInfo.FingerprintPortrait) == 0 && len(entity.Tmp) > 0 && entity.Type == "1" { | ||
| 269 | + userBase.UserInfo.FingerprintPortrait = entity.Tmp | ||
| 270 | + updateFlag = true | ||
| 271 | + } | ||
| 272 | + if updateFlag { | ||
| 273 | + _, err = userBaseRepository.Save(userBase) | ||
| 274 | + if err != nil { | ||
| 275 | + log.Logger.Error(err.Error()) | ||
| 276 | + } | ||
| 277 | + } | ||
| 278 | + return nil, err | ||
| 279 | +} | ||
| 280 | + | ||
| 281 | +func (handler ZKClockHandler) ReportUser(entity USEREntity) (DownEntity, error) { | ||
| 282 | + var ( | ||
| 283 | + userRepository, _, _ = factory.FastPgUser(handler.TransactionContext, 0) | ||
| 284 | + userBaseRepository, _, _ = factory.FastPgUserBase(handler.TransactionContext, 0) | ||
| 285 | + user *domain.User | ||
| 286 | + userBase *domain.UserBase | ||
| 287 | + err error | ||
| 288 | + updateFlag bool | ||
| 289 | + ) | ||
| 290 | + if user, err = userRepository.FindOne(map[string]interface{}{"companyId": entity.CompanyId, "orgId": entity.OrgId, "icCardNumber": entity.Pin}); err != nil { | ||
| 291 | + return nil, err | ||
| 292 | + } | ||
| 293 | + if userBase, err = userBaseRepository.FindOne(map[string]interface{}{"userBaseId": user.UserBaseId}); err != nil { | ||
| 294 | + return nil, err | ||
| 295 | + } | ||
| 296 | + // 请求 人脸识别-用户画像 | ||
| 297 | + //if len(entity.Pin) > 0 && userBase.UserInfo.Pin != entity.Pin { | ||
| 298 | + // updateFlag = true | ||
| 299 | + // userBase.UserInfo.Pin = entity.Pin | ||
| 300 | + //} | ||
| 301 | + if updateFlag { | ||
| 302 | + _, err = userBaseRepository.Save(userBase) | ||
| 303 | + } | ||
| 304 | + return nil, err | ||
| 305 | +} | ||
| 306 | + | ||
| 307 | +func generateSn() string { | ||
| 308 | + return string(utils.RandomCreateBytes(10)) | ||
| 309 | +} |
| 1 | +package service | ||
| 2 | + | ||
| 3 | +import ( | ||
| 4 | + "container/list" | ||
| 5 | + "github.com/gookit/event" | ||
| 6 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/domain" | ||
| 7 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/log" | ||
| 8 | + "sync" | ||
| 9 | +) | ||
| 10 | + | ||
| 11 | +var ( | ||
| 12 | + DownEntityEvent = "down_entity" | ||
| 13 | +) | ||
| 14 | + | ||
| 15 | +type TerminalManager struct { | ||
| 16 | + TerminalDeviceList []*TerminalDevice | ||
| 17 | + TerminalDevices sync.Map | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | +func NewTerminalManager() *TerminalManager { | ||
| 21 | + return &TerminalManager{ | ||
| 22 | + TerminalDeviceList: make([]*TerminalDevice, 0), | ||
| 23 | + TerminalDevices: sync.Map{}, | ||
| 24 | + } | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +func (term *TerminalManager) GetDevice(terminalId string) (*TerminalDevice, bool) { | ||
| 28 | + device, ok := term.TerminalDevices.Load(terminalId) | ||
| 29 | + if !ok { | ||
| 30 | + device := NewTerminalDevice(terminalId) | ||
| 31 | + term.TerminalDevices.Store(terminalId, device) | ||
| 32 | + log.Logger.Debug("【TerminalManager】 终端上线 add new device:"+terminalId, map[string]interface{}{"device": device}) | ||
| 33 | + term.TerminalDeviceList = append(term.TerminalDeviceList, device) | ||
| 34 | + return nil, false | ||
| 35 | + } | ||
| 36 | + if v, ok := device.(*TerminalDevice); ok { | ||
| 37 | + return v, ok | ||
| 38 | + } | ||
| 39 | + return nil, false | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +func (term *TerminalManager) PopDownEntityByDevice(sn string) (DownEntity, bool) { | ||
| 43 | + device, ok := term.GetDevice(sn) | ||
| 44 | + if !ok { | ||
| 45 | + return nil, false | ||
| 46 | + } | ||
| 47 | + return device.PopDownEntity() | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +func (term *TerminalManager) AddDownEntityByDevice(sn string, entity interface{}) bool { | ||
| 51 | + device, ok := term.GetDevice(sn) | ||
| 52 | + if !ok { | ||
| 53 | + return false | ||
| 54 | + } | ||
| 55 | + device.AddDownEntity(entity) | ||
| 56 | + return true | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +func (term *TerminalManager) BroadcastDownEntity(downEntity interface{}) { | ||
| 60 | + if len(term.TerminalDeviceList) == 0 { | ||
| 61 | + log.Logger.Debug("【TerminalManager】 当前在线终端:0 广播命令退出") | ||
| 62 | + return | ||
| 63 | + } | ||
| 64 | + for i := range term.TerminalDeviceList { | ||
| 65 | + term.TerminalDeviceList[i].AddDownEntity(downEntity) | ||
| 66 | + } | ||
| 67 | +} | ||
| 68 | + | ||
| 69 | +// Listen Event | ||
| 70 | + | ||
| 71 | +func (term *TerminalManager) DownEntityEvent(e event.Event) error { | ||
| 72 | + entity := e.Get("entity") | ||
| 73 | + if entity != nil { | ||
| 74 | + term.BroadcastDownEntity(entity) | ||
| 75 | + } | ||
| 76 | + return nil | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +func (term *TerminalManager) SyncUser(e event.Event) error { | ||
| 80 | + user := e.Get("user") | ||
| 81 | + userBase := e.Get("userBase") | ||
| 82 | + if user != nil && userBase == nil { | ||
| 83 | + assertUser := user.(*domain.User) | ||
| 84 | + if assertUser.Ext.DepName != "制造中心" { | ||
| 85 | + log.Logger.Debug("【TerminalManager】 当前用户部门不是 [制造中心] 不进行同步", map[string]interface{}{"user": user}) | ||
| 86 | + return nil | ||
| 87 | + } | ||
| 88 | + term.BroadcastDownEntity(NewUpdateUserDownEntity(generateSn(), assertUser.Ext.IcCardNumber, assertUser.Ext.UserName)) | ||
| 89 | + return nil | ||
| 90 | + } | ||
| 91 | + if user != nil && userBase != nil { | ||
| 92 | + assertUser := user.(*domain.User) | ||
| 93 | + assertUserBase := userBase.(*domain.UserBase) | ||
| 94 | + if assertUser.Ext.DepName != "制造中心" { | ||
| 95 | + log.Logger.Debug("【TerminalManager】 当前用户部门不是 [制造中心] 不进行同步", map[string]interface{}{"user": user}) | ||
| 96 | + return nil | ||
| 97 | + } | ||
| 98 | + if len(assertUser.Ext.IcCardNumber) == 0 { | ||
| 99 | + return nil | ||
| 100 | + } | ||
| 101 | + if len(assertUserBase.UserInfo.FacePortrait) > 0 { | ||
| 102 | + term.BroadcastDownEntity(NewUpdateUserFacePortraitDownEntity(generateSn(), assertUser.Ext.IcCardNumber, assertUserBase.UserInfo.FacePortrait)) | ||
| 103 | + } | ||
| 104 | + if len(assertUserBase.UserInfo.FingerprintPortrait) > 0 { | ||
| 105 | + term.BroadcastDownEntity(NewUpdateUserFingerprintPortraitDownEntity(generateSn(), assertUser.Ext.IcCardNumber, assertUserBase.UserInfo.FingerprintPortrait)) | ||
| 106 | + } | ||
| 107 | + term.BroadcastDownEntity(NewUpdateUserDownEntity(generateSn(), assertUser.Ext.IcCardNumber, assertUserBase.UserInfo.UserName)) | ||
| 108 | + } | ||
| 109 | + return nil | ||
| 110 | +} | ||
| 111 | + | ||
| 112 | +func (term *TerminalManager) EnableUser(e event.Event) error { | ||
| 113 | + user := e.Get("user") | ||
| 114 | + if user != nil { | ||
| 115 | + assertUser := user.(*domain.User) | ||
| 116 | + if assertUser.EnableStatus == int(domain.UserStatusEnable) { | ||
| 117 | + term.SyncUser(e) | ||
| 118 | + } else if assertUser.EnableStatus == int(domain.UserStatusDisable) { | ||
| 119 | + term.BroadcastDownEntity(NewDeleteDownEntity(generateSn(), assertUser.Ext.IcCardNumber, string(UserInfo))) | ||
| 120 | + } | ||
| 121 | + } | ||
| 122 | + return nil | ||
| 123 | +} | ||
| 124 | + | ||
| 125 | +func (term *TerminalManager) CreateUser(e event.Event) error { | ||
| 126 | + return term.SyncUser(e) | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | +func (term *TerminalManager) UpdateUser(e event.Event) error { | ||
| 130 | + return term.EnableUser(e) | ||
| 131 | +} | ||
| 132 | + | ||
| 133 | +type TerminalDevice struct { | ||
| 134 | + Id string | ||
| 135 | + DownEntityList *list.List | ||
| 136 | +} | ||
| 137 | + | ||
| 138 | +func NewTerminalDevice(terminalId string) *TerminalDevice { | ||
| 139 | + return &TerminalDevice{ | ||
| 140 | + Id: terminalId, | ||
| 141 | + DownEntityList: list.New(), | ||
| 142 | + } | ||
| 143 | +} | ||
| 144 | + | ||
| 145 | +func (device *TerminalDevice) PopDownEntity() (DownEntity, bool) { | ||
| 146 | + element := device.DownEntityList.Front() | ||
| 147 | + if element == nil { | ||
| 148 | + return nil, false | ||
| 149 | + } | ||
| 150 | + device.DownEntityList.Remove(element) | ||
| 151 | + if v, ok := element.Value.(DownEntity); ok { | ||
| 152 | + log.Logger.Debug("【TerminalManager】 发送命令 pop down entity to Sender cmd:"+v.DownCommand(), map[string]interface{}{"entity": v}) | ||
| 153 | + return v, ok | ||
| 154 | + } | ||
| 155 | + return nil, false | ||
| 156 | +} | ||
| 157 | + | ||
| 158 | +func (device *TerminalDevice) AddDownEntity(downEntity interface{}) { | ||
| 159 | + v, ok := downEntity.(DownEntity) | ||
| 160 | + var cmd string | ||
| 161 | + if ok { | ||
| 162 | + cmd = v.DownCommand() | ||
| 163 | + } | ||
| 164 | + log.Logger.Debug("【TerminalManager】 添加命令 add down entity to Profile cmd:"+cmd, map[string]interface{}{"entity": downEntity}) | ||
| 165 | + device.DownEntityList.PushBack(downEntity) | ||
| 166 | +} |
pkg/application/terminal/service/types.go
0 → 100644
| 1 | +package service | ||
| 2 | + | ||
| 3 | +import "fmt" | ||
| 4 | + | ||
| 5 | +type TableType string | ||
| 6 | + | ||
| 7 | +var ( | ||
| 8 | + AttLOG TableType = "ATTLOG" // AttLOG 打卡记录 | ||
| 9 | + UserInfo TableType = "USERINFO" // 用户信息 | ||
| 10 | + FingerTMP TableType = "FINGERTMP" //指纹 | ||
| 11 | + Face TableType = "FACE" //脸部 | ||
| 12 | + OPERLOG TableType = "OPERLOG" //操作记录 | ||
| 13 | + BIODATA TableType = "BIODATA" //一体化数据 (人脸识别等) | ||
| 14 | +) | ||
| 15 | + | ||
| 16 | +// AttLOGUpEntity 打卡记录实体 - 上行命令 | ||
| 17 | +type AttLOGUpEntity struct { | ||
| 18 | + Pin string | ||
| 19 | + Time string | ||
| 20 | + Status string | ||
| 21 | + Verify string | ||
| 22 | + Workcode string | ||
| 23 | + Reserved1 string | ||
| 24 | + Reserved2 string | ||
| 25 | + MaskFlag string | ||
| 26 | + Temperature string | ||
| 27 | + ConvTemperature string | ||
| 28 | + | ||
| 29 | + CompanyId int64 `json:"companyId"` | ||
| 30 | + OrgId int64 `json:"orgId"` | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +// FPEntity 指纹 - 上行命令 OPERLOG | ||
| 34 | +type FPEntity struct { | ||
| 35 | + OPERLOGType string //"FP" "USER" "BIODATA" | ||
| 36 | + Pin string | ||
| 37 | + TFID string | ||
| 38 | + TSize string | ||
| 39 | + TValid string | ||
| 40 | + TTMP string | ||
| 41 | + | ||
| 42 | + CompanyId int64 `json:"companyId"` | ||
| 43 | + OrgId int64 `json:"orgId"` | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +// USEREntity 用户 - 上行命令 OPERLOG | ||
| 47 | +type USEREntity struct { | ||
| 48 | + OPERLOGType string //"FP" "USER" "BIODATA" | ||
| 49 | + Pin string `json:"pin"` | ||
| 50 | + Name string `json:"Name"` | ||
| 51 | + Pri string `json:"Pri"` | ||
| 52 | + Passwd string `json:"Passwd"` | ||
| 53 | + Grp string `json:"Grp"` | ||
| 54 | + TZ string `json:"TZ"` | ||
| 55 | + Verify string `json:"Verify"` | ||
| 56 | + ViceCard string `json:"ViceCard"` | ||
| 57 | + StartDatetime string `json:"StartDatetime"` | ||
| 58 | + EndDatetime string `json:"EndDatetime"` | ||
| 59 | + | ||
| 60 | + CompanyId int64 `json:"companyId"` | ||
| 61 | + OrgId int64 `json:"orgId"` | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +// BIODATAEntity 一体化数据实体 - 上行命令 BIODATA | ||
| 65 | +type BIODATAEntity struct { | ||
| 66 | + Pin string `json:"pin"` | ||
| 67 | + No string `json:"tNo"` | ||
| 68 | + Index string `json:"tIndex"` | ||
| 69 | + Valid string `json:"tValid"` | ||
| 70 | + Duress string `json:"tDuress"` | ||
| 71 | + Type string `json:"tType"` | ||
| 72 | + MajorVer string `json:"tMajorVer"` | ||
| 73 | + MinorVer string `json:"tMinorVer"` | ||
| 74 | + Format string `json:"tFormat"` | ||
| 75 | + Tmp string `json:"Tmp"` | ||
| 76 | + | ||
| 77 | + CompanyId int64 `json:"companyId"` | ||
| 78 | + OrgId int64 `json:"orgId"` | ||
| 79 | +} | ||
| 80 | + | ||
| 81 | +type DownEntity interface { | ||
| 82 | + DownCommand() string | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +func QueryUserInfoRequest(sn string, entity AttLOGUpEntity) string { | ||
| 86 | + return fmt.Sprintf("C:%v:DATA QUERY USERINFO PIN=%v", sn, entity.Pin) | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +// QueryUserInfoDownEntity 查询用户信息-下行命令 | ||
| 90 | +type QueryUserInfoDownEntity struct { | ||
| 91 | + Sn string | ||
| 92 | + Pin string | ||
| 93 | +} | ||
| 94 | + | ||
| 95 | +func (entity QueryUserInfoDownEntity) DownCommand() string { | ||
| 96 | + return fmt.Sprintf("C:%v:DATA QUERY USERINFO PIN=%v", entity.Sn, entity.Pin) | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +func NewQueryUserInfoDownEntity(sn string, pin string) QueryUserInfoDownEntity { | ||
| 100 | + return QueryUserInfoDownEntity{ | ||
| 101 | + Sn: sn, | ||
| 102 | + Pin: pin, | ||
| 103 | + } | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +type BioDataType int | ||
| 107 | + | ||
| 108 | +var ( | ||
| 109 | + BioDataType0 BioDataType = 0 //通用 | ||
| 110 | + BioDataType1 BioDataType = 1 //指纹 | ||
| 111 | + BioDataType2 BioDataType = 0 //面部 | ||
| 112 | + BioDataType3 BioDataType = 3 //声纹 | ||
| 113 | + BioDataType4 BioDataType = 4 //虹膜 | ||
| 114 | + BioDataType5 BioDataType = 5 //视网膜 | ||
| 115 | + BioDataType6 BioDataType = 6 //掌纹 | ||
| 116 | + BioDataType7 BioDataType = 7 //指静脉 | ||
| 117 | + BioDataType8 BioDataType = 8 //手掌 | ||
| 118 | + BioDataType9 BioDataType = 9 //可见光面部 | ||
| 119 | +) | ||
| 120 | + | ||
| 121 | +// QueryBioDataDownEntity 查询一体化-下行命令 | ||
| 122 | +type QueryBioDataDownEntity struct { | ||
| 123 | + Sn string | ||
| 124 | + Pin string | ||
| 125 | + Type BioDataType | ||
| 126 | +} | ||
| 127 | + | ||
| 128 | +func (entity QueryBioDataDownEntity) DownCommand() string { | ||
| 129 | + return fmt.Sprintf("C:%v:DATA QUERY BIODATA Type=%v PIN=%v", entity.Sn, entity.Type, entity.Pin) | ||
| 130 | +} | ||
| 131 | + | ||
| 132 | +func NewQueryBIODATADownEntity(sn string, pin string, t BioDataType) QueryBioDataDownEntity { | ||
| 133 | + return QueryBioDataDownEntity{ | ||
| 134 | + Sn: sn, | ||
| 135 | + Pin: pin, | ||
| 136 | + Type: t, | ||
| 137 | + } | ||
| 138 | +} | ||
| 139 | + | ||
| 140 | +// DeleteDownEntity 删除-下行命令 | ||
| 141 | +type DeleteDownEntity struct { | ||
| 142 | + Sn string | ||
| 143 | + Pin string | ||
| 144 | + Table string | ||
| 145 | +} | ||
| 146 | + | ||
| 147 | +func (entity DeleteDownEntity) DownCommand() string { | ||
| 148 | + return fmt.Sprintf("C:%v:DATA DELETE %v PIN=%v", entity.Sn, entity.Table, entity.Pin) | ||
| 149 | +} | ||
| 150 | + | ||
| 151 | +func NewDeleteDownEntity(sn string, pin string, t string) DeleteDownEntity { | ||
| 152 | + return DeleteDownEntity{ | ||
| 153 | + Sn: sn, | ||
| 154 | + Pin: pin, | ||
| 155 | + Table: t, | ||
| 156 | + } | ||
| 157 | +} | ||
| 158 | + | ||
| 159 | +// UpdateUserDownEntity 更新用户-下行命令 | ||
| 160 | +type UpdateUserDownEntity struct { | ||
| 161 | + Sn string | ||
| 162 | + Pin string | ||
| 163 | + Name string | ||
| 164 | + Card string | ||
| 165 | +} | ||
| 166 | + | ||
| 167 | +func (entity UpdateUserDownEntity) DownCommand() string { | ||
| 168 | + return fmt.Sprintf("C:%v:DATA UPDATE USERINFO PIN=%v\tName=%v\tCard=%v", entity.Sn, entity.Pin, entity.Name, entity.Pin) | ||
| 169 | +} | ||
| 170 | + | ||
| 171 | +func NewUpdateUserDownEntity(sn string, pin string, name string) UpdateUserDownEntity { | ||
| 172 | + return UpdateUserDownEntity{ | ||
| 173 | + Sn: sn, | ||
| 174 | + Pin: pin, | ||
| 175 | + Name: name, | ||
| 176 | + } | ||
| 177 | +} | ||
| 178 | + | ||
| 179 | +// UpdateUserFacePortraitDownEntity 更新用户-人脸识别 -下行命令 | ||
| 180 | +type UpdateUserFacePortraitDownEntity struct { | ||
| 181 | + Sn string | ||
| 182 | + Pin string | ||
| 183 | + FacePortrait string | ||
| 184 | +} | ||
| 185 | + | ||
| 186 | +func (entity UpdateUserFacePortraitDownEntity) DownCommand() string { | ||
| 187 | + return fmt.Sprintf("C:%v:DATA UPDATE BIODATA Pin=%v\tNo=0\tType=9\tMajorVer=39\tMinorVer=1\tFormat=0\tIndex=0\tValid=1\tDuress=0\tTmp=%v", entity.Sn, entity.Pin, entity.FacePortrait) | ||
| 188 | +} | ||
| 189 | + | ||
| 190 | +func NewUpdateUserFacePortraitDownEntity(sn string, pin string, facePortrait string) UpdateUserFacePortraitDownEntity { | ||
| 191 | + return UpdateUserFacePortraitDownEntity{ | ||
| 192 | + Sn: sn, | ||
| 193 | + Pin: pin, | ||
| 194 | + FacePortrait: facePortrait, | ||
| 195 | + } | ||
| 196 | +} | ||
| 197 | + | ||
| 198 | +// UpdateUserFingerprintPortraitDownEntity 更新用户-指纹 -下行命令 | ||
| 199 | +type UpdateUserFingerprintPortraitDownEntity struct { | ||
| 200 | + Sn string | ||
| 201 | + Pin string | ||
| 202 | + FingerprintPortrait string | ||
| 203 | +} | ||
| 204 | + | ||
| 205 | +func (entity UpdateUserFingerprintPortraitDownEntity) DownCommand() string { | ||
| 206 | + return fmt.Sprintf("C:%v:DATA UPDATE FINGERTMP PIN=%v\tFID=5\tSize=%v\tValid=1\tTMP=%v", entity.Sn, entity.Pin, len([]byte(entity.FingerprintPortrait)), entity.FingerprintPortrait) | ||
| 207 | +} | ||
| 208 | + | ||
| 209 | +func NewUpdateUserFingerprintPortraitDownEntity(sn string, pin string, fingerprintPortrait string) UpdateUserFingerprintPortraitDownEntity { | ||
| 210 | + return UpdateUserFingerprintPortraitDownEntity{ | ||
| 211 | + Sn: sn, | ||
| 212 | + Pin: pin, | ||
| 213 | + FingerprintPortrait: fingerprintPortrait, | ||
| 214 | + } | ||
| 215 | +} |
| 1 | +package command | ||
| 2 | + | ||
| 3 | +import ( | ||
| 4 | + "fmt" | ||
| 5 | + "github.com/beego/beego/v2/core/validation" | ||
| 6 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/domain" | ||
| 7 | + "reflect" | ||
| 8 | + "strings" | ||
| 9 | +) | ||
| 10 | + | ||
| 11 | +type SyncToAttendanceMachineCommand struct { | ||
| 12 | + OperateInfo *domain.OperateInfo `json:"-"` | ||
| 13 | + // 用户关联的角色 | ||
| 14 | + Users []int64 `cname:"用户关联的角色" json:"userIds" valid:"Required"` | ||
| 15 | +} | ||
| 16 | + | ||
| 17 | +func (syncToAttendance *SyncToAttendanceMachineCommand) Valid(validation *validation.Validation) { | ||
| 18 | + //validation.SetError("CustomValid", "未实现的自定义认证") | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +func (syncToAttendance *SyncToAttendanceMachineCommand) ValidateCommand() error { | ||
| 22 | + valid := validation.Validation{} | ||
| 23 | + b, err := valid.Valid(syncToAttendance) | ||
| 24 | + if err != nil { | ||
| 25 | + return err | ||
| 26 | + } | ||
| 27 | + if !b { | ||
| 28 | + elem := reflect.TypeOf(syncToAttendance).Elem() | ||
| 29 | + for _, validErr := range valid.Errors { | ||
| 30 | + field, isExist := elem.FieldByName(validErr.Field) | ||
| 31 | + if isExist { | ||
| 32 | + return fmt.Errorf(strings.Replace(validErr.Message, validErr.Field, field.Tag.Get("cname"), -1)) | ||
| 33 | + } else { | ||
| 34 | + return fmt.Errorf(validErr.Message) | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | + return nil | ||
| 39 | +} |
| @@ -34,6 +34,8 @@ type Menu struct { | @@ -34,6 +34,8 @@ type Menu struct { | ||
| 34 | //IsPublish int `json:"isPublish,omitempty"` | 34 | //IsPublish int `json:"isPublish,omitempty"` |
| 35 | // 启用状态(启用:1 禁用:2),默认启用 | 35 | // 启用状态(启用:1 禁用:2),默认启用 |
| 36 | EnableStatus int `json:"enableStatus,omitempty"` | 36 | EnableStatus int `json:"enableStatus,omitempty"` |
| 37 | + // 外链接(需要菜单跳转的时候使用) | ||
| 38 | + Link string `json:"link"` | ||
| 37 | } | 39 | } |
| 38 | 40 | ||
| 39 | func (dto *UserAccessMenuDto) LoadDto(menus []*domain.Menu) error { | 41 | func (dto *UserAccessMenuDto) LoadDto(menus []*domain.Menu) error { |
| @@ -49,6 +51,7 @@ func (dto *UserAccessMenuDto) LoadDto(menus []*domain.Menu) error { | @@ -49,6 +51,7 @@ func (dto *UserAccessMenuDto) LoadDto(menus []*domain.Menu) error { | ||
| 49 | Sort: v.Sort, | 51 | Sort: v.Sort, |
| 50 | EnableStatus: v.EnableStatus, | 52 | EnableStatus: v.EnableStatus, |
| 51 | ParentPath: v.ParentPath, | 53 | ParentPath: v.ParentPath, |
| 54 | + Link: v.Link, | ||
| 52 | }) | 55 | }) |
| 53 | } | 56 | } |
| 54 | 57 |
pkg/application/user/service/attendance.go
0 → 100644
| 1 | +package service | ||
| 2 | + | ||
| 3 | +import ( | ||
| 4 | + "github.com/gookit/event" | ||
| 5 | + "github.com/linmadan/egglib-go/core/application" | ||
| 6 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/application/factory" | ||
| 7 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/application/user/command" | ||
| 8 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/domain" | ||
| 9 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/log" | ||
| 10 | +) | ||
| 11 | + | ||
| 12 | +func (userService *UserService) SyncToAttendanceMachine(cmd *command.SyncToAttendanceMachineCommand) (interface{}, error) { | ||
| 13 | + if err := cmd.ValidateCommand(); err != nil { | ||
| 14 | + return nil, application.ThrowError(application.ARG_ERROR, err.Error()) | ||
| 15 | + } | ||
| 16 | + transactionContext, err := factory.CreateTransactionContext(nil) | ||
| 17 | + if err != nil { | ||
| 18 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
| 19 | + } | ||
| 20 | + if err := transactionContext.StartTransaction(); err != nil { | ||
| 21 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
| 22 | + } | ||
| 23 | + defer func() { | ||
| 24 | + transactionContext.RollbackTransaction() | ||
| 25 | + }() | ||
| 26 | + userRepository, _, _ := factory.FastPgUser(transactionContext, 0) | ||
| 27 | + | ||
| 28 | + _, users, err := userRepository.Find(map[string]interface{}{"companyId": cmd.OperateInfo.CompanyId, "inUserIds": cmd.Users}) | ||
| 29 | + if err != nil { | ||
| 30 | + return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error()) | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + for i := range users { | ||
| 34 | + _, userBase, err := factory.FastPgUserBase(transactionContext, users[i].UserBaseId) | ||
| 35 | + if err != nil { | ||
| 36 | + return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error()) | ||
| 37 | + } | ||
| 38 | + if err, _ := event.Fire(domain.UserSyncEvent, event.M{"user": users[i], "userBase": userBase}); err != nil { | ||
| 39 | + log.Logger.Error(err.Error()) | ||
| 40 | + return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error()) | ||
| 41 | + } | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + if err := transactionContext.CommitTransaction(); err != nil { | ||
| 45 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
| 46 | + } | ||
| 47 | + return struct{}{}, nil | ||
| 48 | +} |
| @@ -2,6 +2,7 @@ package service | @@ -2,6 +2,7 @@ package service | ||
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "fmt" | 4 | "fmt" |
| 5 | + "github.com/gookit/event" | ||
| 5 | "github.com/linmadan/egglib-go/core/application" | 6 | "github.com/linmadan/egglib-go/core/application" |
| 6 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/application/factory" | 7 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/application/factory" |
| 7 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/application/user/command" | 8 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/application/user/command" |
| @@ -66,7 +67,7 @@ func (userService *UserService) BatchAdd2(batchAddCommand *command.BatchAdd2Comm | @@ -66,7 +67,7 @@ func (userService *UserService) BatchAdd2(batchAddCommand *command.BatchAdd2Comm | ||
| 66 | "transactionContext": transactionContext, | 67 | "transactionContext": transactionContext, |
| 67 | }) | 68 | }) |
| 68 | var failRows []*domain.BatchAddUserItem | 69 | var failRows []*domain.BatchAddUserItem |
| 69 | - if failRows, err = batchAddUserService.BatchAddUser2(batchAddCommand.OperateInfo, batchAddCommand.Users, batchAddCommand.Password); err != nil { | 70 | + if failRows, err = batchAddUserService.BatchAddUser(batchAddCommand.OperateInfo, batchAddCommand.Users, batchAddCommand.Password); err != nil { |
| 70 | return batchAddCommand.Users, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | 71 | return batchAddCommand.Users, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) |
| 71 | } | 72 | } |
| 72 | if len(failRows) != 0 { | 73 | if len(failRows) != 0 { |
| @@ -110,6 +111,9 @@ func (userService *UserService) BatchEnable(batchEnableCommand *command.BatchEna | @@ -110,6 +111,9 @@ func (userService *UserService) BatchEnable(batchEnableCommand *command.BatchEna | ||
| 110 | if _, err := userRepository.Save(user); err != nil { | 111 | if _, err := userRepository.Save(user); err != nil { |
| 111 | return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) | 112 | return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) |
| 112 | } | 113 | } |
| 114 | + if err, _ := event.Fire(domain.UserEnableEvent, map[string]interface{}{"user": user}); err != nil { | ||
| 115 | + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) | ||
| 116 | + } | ||
| 113 | } | 117 | } |
| 114 | } | 118 | } |
| 115 | 119 |
| @@ -68,9 +68,10 @@ type Menu struct { | @@ -68,9 +68,10 @@ type Menu struct { | ||
| 68 | ParentPath string `json:"parentPath,omitempty"` | 68 | ParentPath string `json:"parentPath,omitempty"` |
| 69 | // 菜单是否公开状态,[1:显示],[2:隐藏],默认显示 | 69 | // 菜单是否公开状态,[1:显示],[2:隐藏],默认显示 |
| 70 | IsPublish int `json:"isPublish,omitempty"` | 70 | IsPublish int `json:"isPublish,omitempty"` |
| 71 | - // 启用状态(启用:1 禁用:2),默认启用 | 71 | + // 启用状态(启用:1 禁用:2),默认启用 (移除不使用,现在只有is_publish状态) |
| 72 | EnableStatus int `json:"enableStatus,omitempty"` | 72 | EnableStatus int `json:"enableStatus,omitempty"` |
| 73 | - | 73 | + // 外链接(需要菜单跳转的时候使用) |
| 74 | + Link string `json:"link"` | ||
| 74 | // 父级菜单名称 | 75 | // 父级菜单名称 |
| 75 | ParentMenuName string `json:"parentMenuName,omitempty"` | 76 | ParentMenuName string `json:"parentMenuName,omitempty"` |
| 76 | } | 77 | } |
| @@ -3,6 +3,8 @@ package domain | @@ -3,6 +3,8 @@ package domain | ||
| 3 | import ( | 3 | import ( |
| 4 | "fmt" | 4 | "fmt" |
| 5 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/constant" | 5 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/constant" |
| 6 | + "strconv" | ||
| 7 | + "strings" | ||
| 6 | "time" | 8 | "time" |
| 7 | ) | 9 | ) |
| 8 | 10 | ||
| @@ -44,7 +46,7 @@ type Org struct { | @@ -44,7 +46,7 @@ type Org struct { | ||
| 44 | OrgStatus int `json:"orgStatus,omitempty"` | 46 | OrgStatus int `json:"orgStatus,omitempty"` |
| 45 | // 父级ID | 47 | // 父级ID |
| 46 | ParentId int64 `json:"parentId,omitempty"` | 48 | ParentId int64 `json:"parentId,omitempty"` |
| 47 | - // 父级节点路径("0,11,12,") | 49 | + // 父级节点路径("11,12") 注意:parent_id为0时 parentPath "",公司级别的组织没有父级组织 |
| 48 | ParentPath string `json:"parentPath,omitempty"` | 50 | ParentPath string `json:"parentPath,omitempty"` |
| 49 | 51 | ||
| 50 | // 企业id | 52 | // 企业id |
| @@ -197,6 +199,23 @@ func (org *Org) ID() string { | @@ -197,6 +199,23 @@ func (org *Org) ID() string { | ||
| 197 | return org.GetFullPath() | 199 | return org.GetFullPath() |
| 198 | } | 200 | } |
| 199 | 201 | ||
| 202 | +func (org *Org) IsChild(pid int64) bool { | ||
| 203 | + paths := strings.Split(org.ParentPath, PathSegment) | ||
| 204 | + pidStr := strconv.FormatInt(pid, 10) | ||
| 205 | + if org.OrgId == pid { | ||
| 206 | + return true | ||
| 207 | + } | ||
| 208 | + if org.ParentId == pid { | ||
| 209 | + return true | ||
| 210 | + } | ||
| 211 | + for _, v := range paths { | ||
| 212 | + if strings.EqualFold(pidStr, v) { | ||
| 213 | + return true | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + return false | ||
| 217 | +} | ||
| 218 | + | ||
| 200 | /***** 2.缓存模块 *****/ | 219 | /***** 2.缓存模块 *****/ |
| 201 | 220 | ||
| 202 | func (m *Org) CacheKeyFunc() string { | 221 | func (m *Org) CacheKeyFunc() string { |
| @@ -4,6 +4,5 @@ import "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/domain" | @@ -4,6 +4,5 @@ import "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/domain" | ||
| 4 | 4 | ||
| 5 | // PgBatchAddUserService 批量添加用户服务 | 5 | // PgBatchAddUserService 批量添加用户服务 |
| 6 | type PgBatchAddUserService interface { | 6 | type PgBatchAddUserService interface { |
| 7 | - BatchAddUser(optUser *domain.OperateInfo, users []*domain.User, password string) error | ||
| 8 | - BatchAddUser2(optUser *domain.OperateInfo, users []*domain.BatchAddUserItem, password string) ([]*domain.BatchAddUserItem, error) | 7 | + BatchAddUser(optUser *domain.OperateInfo, users []*domain.BatchAddUserItem, password string) ([]*domain.BatchAddUserItem, error) |
| 9 | } | 8 | } |
| @@ -26,6 +26,14 @@ const ( | @@ -26,6 +26,14 @@ const ( | ||
| 26 | UserStatusDestroy UserStatus = 3 | 26 | UserStatusDestroy UserStatus = 3 |
| 27 | ) | 27 | ) |
| 28 | 28 | ||
| 29 | +const ( | ||
| 30 | + UserUpdateEvent = "user_update" | ||
| 31 | + UserDeleteEvent = "user_delete" | ||
| 32 | + UserCreateEvent = "user_create" | ||
| 33 | + UserEnableEvent = "user_enable" //禁用启用事件 | ||
| 34 | + UserSyncEvent = "user_sync" // 用户同步 | ||
| 35 | +) | ||
| 36 | + | ||
| 29 | // 用户 | 37 | // 用户 |
| 30 | type User struct { | 38 | type User struct { |
| 31 | // 用户Id 用户唯一标识 | 39 | // 用户Id 用户唯一标识 |
| @@ -13,9 +13,16 @@ type UserInfo struct { | @@ -13,9 +13,16 @@ type UserInfo struct { | ||
| 13 | 13 | ||
| 14 | // 员工类型 1:固定 2:派遣 3.临时 | 14 | // 员工类型 1:固定 2:派遣 3.临时 |
| 15 | EmployeeType int `json:"employeeType,omitempty"` | 15 | EmployeeType int `json:"employeeType,omitempty"` |
| 16 | - // IC卡号 | 16 | + // IC卡号 = Pin |
| 17 | IcCardNumber string `json:"icCardNumber,omitempty"` | 17 | IcCardNumber string `json:"icCardNumber,omitempty"` |
| 18 | 18 | ||
| 19 | + // 面部识别 | ||
| 20 | + FacePortrait string `json:"facePortrait,omitempty"` | ||
| 21 | + // 指纹识别 | ||
| 22 | + FingerprintPortrait string `json:"fingerprintPortrait,omitempty"` | ||
| 23 | + // 打卡机标识 | ||
| 24 | + // Pin string `json:"pin"` | ||
| 25 | + | ||
| 19 | Referer string `json:"-"` | 26 | Referer string `json:"-"` |
| 20 | // 部门 | 27 | // 部门 |
| 21 | DepartmentName string `cname:"部门" json:"-"` | 28 | DepartmentName string `cname:"部门" json:"-"` |
| @@ -18,71 +18,71 @@ type PgBatchAddUserService struct { | @@ -18,71 +18,71 @@ type PgBatchAddUserService struct { | ||
| 18 | // optUser 操作用户 | 18 | // optUser 操作用户 |
| 19 | // users 待添加用户列表数据 | 19 | // users 待添加用户列表数据 |
| 20 | // password 密码 | 20 | // password 密码 |
| 21 | -func (ptr *PgBatchAddUserService) BatchAddUser(optUser *domain.OperateInfo, users []*domain.User, password string) error { | ||
| 22 | - var ( | ||
| 23 | - err error | ||
| 24 | - ) | ||
| 25 | - orgRepository, err := repository.NewOrgRepository(ptr.transactionContext) | ||
| 26 | - if err != nil { | ||
| 27 | - return err | ||
| 28 | - } | ||
| 29 | - _, orgs, err := orgRepository.Find(map[string]interface{}{"companyId": optUser.CompanyId}) | ||
| 30 | - if err != nil { | ||
| 31 | - return err | ||
| 32 | - } | ||
| 33 | - var mapOrg = make(map[int64]*domain.Org) | ||
| 34 | - for i := range orgs { | ||
| 35 | - mapOrg[orgs[i].OrgId] = orgs[i] | ||
| 36 | - } | ||
| 37 | - | ||
| 38 | - createUserService, _ := NewPgCreateUserService(ptr.transactionContext) | ||
| 39 | - for i := range users { | ||
| 40 | - user := users[i] | ||
| 41 | - if err = ptr.preCheck(user); err != nil { | ||
| 42 | - return err | ||
| 43 | - } | ||
| 44 | - newUser := &domain.User{ | ||
| 45 | - CompanyId: user.CompanyId, | ||
| 46 | - UserType: user.UserType, | ||
| 47 | - UserCode: user.UserCode, | ||
| 48 | - OrganizationId: user.OrganizationId, | ||
| 49 | - DepartmentId: user.DepartmentId, | ||
| 50 | - UserOrg: []*domain.Org{}, | ||
| 51 | - UserRole: []*domain.Role{}, | ||
| 52 | - FavoriteMenus: []string{}, | ||
| 53 | - CooperationInfo: user.CooperationInfo, | ||
| 54 | - UserInfo: user.UserInfo, | ||
| 55 | - EnableStatus: int(domain.UserStatusEnable), | ||
| 56 | - Ext: &domain.Ext{ | ||
| 57 | - Phone: user.UserInfo.Phone, | ||
| 58 | - UserName: user.UserInfo.UserName, | ||
| 59 | - }, | ||
| 60 | - CreatedAt: time.Now(), | ||
| 61 | - UpdatedAt: time.Now(), | ||
| 62 | - } | ||
| 63 | - if user.OrganizationId > 0 { | ||
| 64 | - if v, ok := mapOrg[user.OrganizationId]; ok && v.CompanyId == user.CompanyId { | ||
| 65 | - newUser.Ext.OrgName = v.OrgName | ||
| 66 | - } else { | ||
| 67 | - return fmt.Errorf("导入的组织机构不存在") | ||
| 68 | - } | ||
| 69 | - } | ||
| 70 | - if user.DepartmentId > 0 { | ||
| 71 | - if v, ok := mapOrg[user.DepartmentId]; ok && v.CompanyId == user.CompanyId { | ||
| 72 | - newUser.Ext.DepName = v.OrgName | ||
| 73 | - } else { | ||
| 74 | - return fmt.Errorf("导入的所属部门不存在") | ||
| 75 | - } | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - if newUser, err = createUserService.CreateUser(nil, newUser, password); err != nil { | ||
| 79 | - return err | ||
| 80 | - } | ||
| 81 | - } | ||
| 82 | - return nil | ||
| 83 | -} | 21 | +//func (ptr *PgBatchAddUserService) BatchAddUser(optUser *domain.OperateInfo, users []*domain.User, password string) error { |
| 22 | +// var ( | ||
| 23 | +// err error | ||
| 24 | +// ) | ||
| 25 | +// orgRepository, err := repository.NewOrgRepository(ptr.transactionContext) | ||
| 26 | +// if err != nil { | ||
| 27 | +// return err | ||
| 28 | +// } | ||
| 29 | +// _, orgs, err := orgRepository.Find(map[string]interface{}{"companyId": optUser.CompanyId}) | ||
| 30 | +// if err != nil { | ||
| 31 | +// return err | ||
| 32 | +// } | ||
| 33 | +// var mapOrg = make(map[int64]*domain.Org) | ||
| 34 | +// for i := range orgs { | ||
| 35 | +// mapOrg[orgs[i].OrgId] = orgs[i] | ||
| 36 | +// } | ||
| 37 | +// | ||
| 38 | +// createUserService, _ := NewPgCreateUserService(ptr.transactionContext) | ||
| 39 | +// for i := range users { | ||
| 40 | +// user := users[i] | ||
| 41 | +// if err = ptr.preCheck(user); err != nil { | ||
| 42 | +// return err | ||
| 43 | +// } | ||
| 44 | +// newUser := &domain.User{ | ||
| 45 | +// CompanyId: user.CompanyId, | ||
| 46 | +// UserType: user.UserType, | ||
| 47 | +// UserCode: user.UserCode, | ||
| 48 | +// OrganizationId: user.OrganizationId, | ||
| 49 | +// DepartmentId: user.DepartmentId, | ||
| 50 | +// UserOrg: []*domain.Org{}, | ||
| 51 | +// UserRole: []*domain.Role{}, | ||
| 52 | +// FavoriteMenus: []string{}, | ||
| 53 | +// CooperationInfo: user.CooperationInfo, | ||
| 54 | +// UserInfo: user.UserInfo, | ||
| 55 | +// EnableStatus: int(domain.UserStatusEnable), | ||
| 56 | +// Ext: &domain.Ext{ | ||
| 57 | +// Phone: user.UserInfo.Phone, | ||
| 58 | +// UserName: user.UserInfo.UserName, | ||
| 59 | +// }, | ||
| 60 | +// CreatedAt: time.Now(), | ||
| 61 | +// UpdatedAt: time.Now(), | ||
| 62 | +// } | ||
| 63 | +// if user.OrganizationId > 0 { | ||
| 64 | +// if v, ok := mapOrg[user.OrganizationId]; ok && v.CompanyId == user.CompanyId { | ||
| 65 | +// newUser.Ext.OrgName = v.OrgName | ||
| 66 | +// } else { | ||
| 67 | +// return fmt.Errorf("导入的组织机构不存在") | ||
| 68 | +// } | ||
| 69 | +// } | ||
| 70 | +// if user.DepartmentId > 0 { | ||
| 71 | +// if v, ok := mapOrg[user.DepartmentId]; ok && v.CompanyId == user.CompanyId { | ||
| 72 | +// newUser.Ext.DepName = v.OrgName | ||
| 73 | +// } else { | ||
| 74 | +// return fmt.Errorf("导入的所属部门不存在") | ||
| 75 | +// } | ||
| 76 | +// } | ||
| 77 | +// | ||
| 78 | +// if newUser, err = createUserService.CreateUser(nil, newUser, password); err != nil { | ||
| 79 | +// return err | ||
| 80 | +// } | ||
| 81 | +// } | ||
| 82 | +// return nil | ||
| 83 | +//} | ||
| 84 | 84 | ||
| 85 | -func (ptr *PgBatchAddUserService) BatchAddUser2(optUser *domain.OperateInfo, users []*domain.BatchAddUserItem, password string) ([]*domain.BatchAddUserItem, error) { | 85 | +func (ptr *PgBatchAddUserService) BatchAddUser(optUser *domain.OperateInfo, users []*domain.BatchAddUserItem, password string) ([]*domain.BatchAddUserItem, error) { |
| 86 | var ( | 86 | var ( |
| 87 | err error | 87 | err error |
| 88 | ) | 88 | ) |
| @@ -99,6 +99,10 @@ func (ptr *PgBatchAddUserService) BatchAddUser2(optUser *domain.OperateInfo, use | @@ -99,6 +99,10 @@ func (ptr *PgBatchAddUserService) BatchAddUser2(optUser *domain.OperateInfo, use | ||
| 99 | for i := range orgs { | 99 | for i := range orgs { |
| 100 | mapOrg[orgs[i].OrgCode] = orgs[i] | 100 | mapOrg[orgs[i].OrgCode] = orgs[i] |
| 101 | } | 101 | } |
| 102 | + optUserOrg, err := orgRepository.FindOne(map[string]interface{}{"orgId": optUser.OrgId}) | ||
| 103 | + if err != nil { | ||
| 104 | + return failRows, err | ||
| 105 | + } | ||
| 102 | 106 | ||
| 103 | createUserService, _ := NewPgCreateUserService(ptr.transactionContext) | 107 | createUserService, _ := NewPgCreateUserService(ptr.transactionContext) |
| 104 | for i := range users { | 108 | for i := range users { |
| @@ -108,23 +112,31 @@ func (ptr *PgBatchAddUserService) BatchAddUser2(optUser *domain.OperateInfo, use | @@ -108,23 +112,31 @@ func (ptr *PgBatchAddUserService) BatchAddUser2(optUser *domain.OperateInfo, use | ||
| 108 | failRows = append(failRows, user) | 112 | failRows = append(failRows, user) |
| 109 | continue | 113 | continue |
| 110 | } | 114 | } |
| 111 | - var org, dep *domain.Org | 115 | + var org = optUserOrg |
| 116 | + var dep *domain.Org | ||
| 112 | var ok bool | 117 | var ok bool |
| 113 | - if org, ok = mapOrg[user.Org]; !ok { | ||
| 114 | - user.FailReason = "导入的组织机构不存在:" + user.Org | ||
| 115 | - failRows = append(failRows, user) | ||
| 116 | - continue | ||
| 117 | - } | 118 | + // 使用导入用户的组织作为默认组织 |
| 119 | + //if org, ok = mapOrg[user.Org]; !ok { | ||
| 120 | + // user.FailReason = "导入的组织机构不存在:" + user.Org | ||
| 121 | + // failRows = append(failRows, user) | ||
| 122 | + // continue | ||
| 123 | + //} | ||
| 118 | if dep, ok = mapOrg[user.Department]; !ok && user.UserType != domain.UserTypeCooperation { | 124 | if dep, ok = mapOrg[user.Department]; !ok && user.UserType != domain.UserTypeCooperation { |
| 119 | user.FailReason = "导入的所属部门不存在:" + user.Department | 125 | user.FailReason = "导入的所属部门不存在:" + user.Department |
| 120 | failRows = append(failRows, user) | 126 | failRows = append(failRows, user) |
| 121 | continue | 127 | continue |
| 122 | } | 128 | } |
| 129 | + //TODO:子部门判断 | ||
| 130 | + //if dep != nil && !dep.IsChild(optUser.OrgId) { | ||
| 131 | + // user.FailReason = fmt.Sprintf("导入的所属部门不是当前登录组织(%v)的子部门:%v", optUserOrg.OrgName, user.Department) | ||
| 132 | + // failRows = append(failRows, user) | ||
| 133 | + // continue | ||
| 134 | + //} | ||
| 123 | newUser := &domain.User{ | 135 | newUser := &domain.User{ |
| 124 | CompanyId: user.CompanyId, | 136 | CompanyId: user.CompanyId, |
| 125 | UserType: user.UserType, | 137 | UserType: user.UserType, |
| 126 | UserCode: user.UserCode, | 138 | UserCode: user.UserCode, |
| 127 | - OrganizationId: org.OrgId, | 139 | + OrganizationId: optUser.OrgId, |
| 128 | UserOrg: []*domain.Org{}, | 140 | UserOrg: []*domain.Org{}, |
| 129 | UserRole: []*domain.Role{}, | 141 | UserRole: []*domain.Role{}, |
| 130 | FavoriteMenus: []string{}, | 142 | FavoriteMenus: []string{}, |
| @@ -172,24 +184,24 @@ func (ptr *PgBatchAddUserService) BatchAddUser2(optUser *domain.OperateInfo, use | @@ -172,24 +184,24 @@ func (ptr *PgBatchAddUserService) BatchAddUser2(optUser *domain.OperateInfo, use | ||
| 172 | return failRows, nil | 184 | return failRows, nil |
| 173 | } | 185 | } |
| 174 | 186 | ||
| 175 | -func (ptr *PgBatchAddUserService) preCheck(user *domain.User) error { | ||
| 176 | - if len(user.UserCode) == 0 { | ||
| 177 | - return fmt.Errorf("导入的用户编码为空值") | ||
| 178 | - } | ||
| 179 | - if len(user.UserInfo.UserName) == 0 { | ||
| 180 | - return fmt.Errorf("导入的用户姓名为空值") | ||
| 181 | - } | ||
| 182 | - if len(user.UserInfo.Phone) == 0 || len(user.UserInfo.Phone) != 11 { | ||
| 183 | - return fmt.Errorf("导入的手机号不是有效手机号") | ||
| 184 | - } | ||
| 185 | - if user.OrganizationId == 0 { | ||
| 186 | - return fmt.Errorf("导入的组织机构不存在") | ||
| 187 | - } | ||
| 188 | - if user.DepartmentId == 0 && user.UserType == domain.UserTypeEmployee { | ||
| 189 | - return fmt.Errorf("导入的所属部门不存在") | ||
| 190 | - } | ||
| 191 | - return nil | ||
| 192 | -} | 187 | +//func (ptr *PgBatchAddUserService) preCheck(user *domain.User) error { |
| 188 | +// if len(user.UserCode) == 0 { | ||
| 189 | +// return fmt.Errorf("导入的用户编码为空值") | ||
| 190 | +// } | ||
| 191 | +// if len(user.UserInfo.UserName) == 0 { | ||
| 192 | +// return fmt.Errorf("导入的用户姓名为空值") | ||
| 193 | +// } | ||
| 194 | +// if len(user.UserInfo.Phone) == 0 || len(user.UserInfo.Phone) != 11 { | ||
| 195 | +// return fmt.Errorf("导入的手机号不是有效手机号") | ||
| 196 | +// } | ||
| 197 | +// if user.OrganizationId == 0 { | ||
| 198 | +// return fmt.Errorf("导入的组织机构不存在") | ||
| 199 | +// } | ||
| 200 | +// if user.DepartmentId == 0 && user.UserType == domain.UserTypeEmployee { | ||
| 201 | +// return fmt.Errorf("导入的所属部门不存在") | ||
| 202 | +// } | ||
| 203 | +// return nil | ||
| 204 | +//} | ||
| 193 | 205 | ||
| 194 | func (ptr *PgBatchAddUserService) preCheck2(user *domain.BatchAddUserItem) error { | 206 | func (ptr *PgBatchAddUserService) preCheck2(user *domain.BatchAddUserItem) error { |
| 195 | if len(user.UserCode) == 0 { | 207 | if len(user.UserCode) == 0 { |
| @@ -2,6 +2,7 @@ package domainService | @@ -2,6 +2,7 @@ package domainService | ||
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "fmt" | 4 | "fmt" |
| 5 | + "github.com/gookit/event" | ||
| 5 | pgTransaction "github.com/linmadan/egglib-go/transaction/pg" | 6 | pgTransaction "github.com/linmadan/egglib-go/transaction/pg" |
| 6 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/domain" | 7 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/domain" |
| 7 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/infrastructure/repository" | 8 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/infrastructure/repository" |
| @@ -96,6 +97,10 @@ func (ptr *PgCreateUserService) CreateUser(optUser *domain.User, newUser *domain | @@ -96,6 +97,10 @@ func (ptr *PgCreateUserService) CreateUser(optUser *domain.User, newUser *domain | ||
| 96 | return nil, err | 97 | return nil, err |
| 97 | } | 98 | } |
| 98 | } | 99 | } |
| 100 | + // 新建用户事件 | ||
| 101 | + if err, _ := event.Fire(domain.UserCreateEvent, event.M{"user": newUser, "userBase": userBase}); err != nil { | ||
| 102 | + return nil, err | ||
| 103 | + } | ||
| 99 | return user, nil | 104 | return user, nil |
| 100 | } | 105 | } |
| 101 | 106 |
| @@ -22,6 +22,7 @@ type PgRoleAccessMenusService struct { | @@ -22,6 +22,7 @@ type PgRoleAccessMenusService struct { | ||
| 22 | func (ptr *PgRoleAccessMenusService) AccessMenus(options *domain.OperateInfo, roleIds []int64, option domain.AccessMenusOptions) ([]*domain.Menu, error) { | 22 | func (ptr *PgRoleAccessMenusService) AccessMenus(options *domain.OperateInfo, roleIds []int64, option domain.AccessMenusOptions) ([]*domain.Menu, error) { |
| 23 | var err error | 23 | var err error |
| 24 | var menus []*domain.Menu | 24 | var menus []*domain.Menu |
| 25 | + var hasAdminRole bool = false | ||
| 25 | menuIdSet := hashset.New() | 26 | menuIdSet := hashset.New() |
| 26 | if len(roleIds) == 0 { | 27 | if len(roleIds) == 0 { |
| 27 | return menus, nil | 28 | return menus, nil |
| @@ -34,6 +35,9 @@ func (ptr *PgRoleAccessMenusService) AccessMenus(options *domain.OperateInfo, ro | @@ -34,6 +35,9 @@ func (ptr *PgRoleAccessMenusService) AccessMenus(options *domain.OperateInfo, ro | ||
| 34 | if role, _ = roleRepository.FindOne(map[string]interface{}{"roleId": roleIds[i]}); role == nil { | 35 | if role, _ = roleRepository.FindOne(map[string]interface{}{"roleId": roleIds[i]}); role == nil { |
| 35 | continue | 36 | continue |
| 36 | } | 37 | } |
| 38 | + if role.RoleType&domain.RoleTypeAdmin > 0 { | ||
| 39 | + hasAdminRole = true | ||
| 40 | + } | ||
| 37 | // 只要当前登录组织的有权限菜单 | 41 | // 只要当前登录组织的有权限菜单 |
| 38 | if option.OrgId > 0 && option.OrgId != role.OrgId { | 42 | if option.OrgId > 0 && option.OrgId != role.OrgId { |
| 39 | continue | 43 | continue |
| @@ -66,7 +70,7 @@ func (ptr *PgRoleAccessMenusService) AccessMenus(options *domain.OperateInfo, ro | @@ -66,7 +70,7 @@ func (ptr *PgRoleAccessMenusService) AccessMenus(options *domain.OperateInfo, ro | ||
| 66 | if err != nil { | 70 | if err != nil { |
| 67 | return nil, err | 71 | return nil, err |
| 68 | } | 72 | } |
| 69 | - _, alias, err := customizeMenuRepository.Find(map[string]interface{}{"companyId": option.CompanyId}) | 73 | + _, menuAlias, err := customizeMenuRepository.Find(map[string]interface{}{"companyId": option.CompanyId}) |
| 70 | if err != nil { | 74 | if err != nil { |
| 71 | return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) | 75 | return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) |
| 72 | } | 76 | } |
| @@ -75,17 +79,22 @@ func (ptr *PgRoleAccessMenusService) AccessMenus(options *domain.OperateInfo, ro | @@ -75,17 +79,22 @@ func (ptr *PgRoleAccessMenusService) AccessMenus(options *domain.OperateInfo, ro | ||
| 75 | var mapMenus = make(map[int64]*domain.Menu) | 79 | var mapMenus = make(map[int64]*domain.Menu) |
| 76 | for i := range menus { | 80 | for i := range menus { |
| 77 | menus[i].EnableStatus = domain.MenuStatusDisable | 81 | menus[i].EnableStatus = domain.MenuStatusDisable |
| 82 | + if menus[i].IsPublish == domain.MenuPublic && hasAdminRole { | ||
| 83 | + menus[i].EnableStatus = domain.MenuStatusEnable //管理员角色,返回所有权限 | ||
| 84 | + } | ||
| 78 | mapMenus[menus[i].MenuId] = menus[i] | 85 | mapMenus[menus[i].MenuId] = menus[i] |
| 79 | } | 86 | } |
| 80 | - for i := range alias { | ||
| 81 | - if v, ok := mapMenus[alias[i].MenuId]; ok { | ||
| 82 | - v.MenuName = alias[i].MenuAlias // 设置别名 | ||
| 83 | - v.Sort = alias[i].Sort | 87 | + // 4.1.设置别名 |
| 88 | + for i := range menuAlias { | ||
| 89 | + if v, ok := mapMenus[menuAlias[i].MenuId]; ok { | ||
| 90 | + v.MenuName = menuAlias[i].MenuAlias | ||
| 91 | + v.Sort = menuAlias[i].Sort | ||
| 84 | } | 92 | } |
| 85 | } | 93 | } |
| 94 | + // 4.2.设置菜单权限状态 | ||
| 86 | values := menuIdSet.Values() | 95 | values := menuIdSet.Values() |
| 87 | for i := range values { | 96 | for i := range values { |
| 88 | - menuId := (values[i]).(int64) // 设置菜单权限状态 | 97 | + menuId := (values[i]).(int64) |
| 89 | if v, ok := mapMenus[menuId]; ok { | 98 | if v, ok := mapMenus[menuId]; ok { |
| 90 | v.EnableStatus = domain.MenuStatusEnable | 99 | v.EnableStatus = domain.MenuStatusEnable |
| 91 | } | 100 | } |
| @@ -2,6 +2,7 @@ package domainService | @@ -2,6 +2,7 @@ package domainService | ||
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "fmt" | 4 | "fmt" |
| 5 | + "github.com/gookit/event" | ||
| 5 | pgTransaction "github.com/linmadan/egglib-go/transaction/pg" | 6 | pgTransaction "github.com/linmadan/egglib-go/transaction/pg" |
| 6 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/domain" | 7 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/domain" |
| 7 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/infrastructure/repository" | 8 | "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/infrastructure/repository" |
| @@ -108,6 +109,10 @@ func (ptr *PgUpdateUserService) UpdateUser(optUser *domain.OperateInfo, user *do | @@ -108,6 +109,10 @@ func (ptr *PgUpdateUserService) UpdateUser(optUser *domain.OperateInfo, user *do | ||
| 108 | if user, err = userRepository.Save(user); err != nil { | 109 | if user, err = userRepository.Save(user); err != nil { |
| 109 | return nil, err | 110 | return nil, err |
| 110 | } | 111 | } |
| 112 | + // 新建用户事件 | ||
| 113 | + if err, _ := event.Fire(domain.UserUpdateEvent, event.M{"user": user, "userBase": userBase}); err != nil { | ||
| 114 | + return nil, err | ||
| 115 | + } | ||
| 111 | return user, nil | 116 | return user, nil |
| 112 | } | 117 | } |
| 113 | 118 |
| @@ -28,6 +28,8 @@ type Menu struct { | @@ -28,6 +28,8 @@ type Menu struct { | ||
| 28 | IsPublish int `comment:"菜单是否公开状态,[2:隐藏],[1:显示],默认显示"` | 28 | IsPublish int `comment:"菜单是否公开状态,[2:隐藏],[1:显示],默认显示"` |
| 29 | // 启用状态(启用:1 禁用:2),默认启用 | 29 | // 启用状态(启用:1 禁用:2),默认启用 |
| 30 | EnableStatus int `comment:"启用状态(启用:1 禁用:2),默认启用"` | 30 | EnableStatus int `comment:"启用状态(启用:1 禁用:2),默认启用"` |
| 31 | + // 外链接(需要菜单跳转的时候使用) | ||
| 32 | + Link string `json:"link"` | ||
| 31 | // 删除时间 | 33 | // 删除时间 |
| 32 | //DeletedAt time.Time `comment:"删除时间"` | 34 | //DeletedAt time.Time `comment:"删除时间"` |
| 33 | } | 35 | } |
| @@ -21,5 +21,6 @@ func TransformToMenuDomainModelFromPgModels(menuModel *models.Menu) (*domain.Men | @@ -21,5 +21,6 @@ func TransformToMenuDomainModelFromPgModels(menuModel *models.Menu) (*domain.Men | ||
| 21 | ParentPath: menuModel.ParentPath, | 21 | ParentPath: menuModel.ParentPath, |
| 22 | IsPublish: menuModel.IsPublish, | 22 | IsPublish: menuModel.IsPublish, |
| 23 | EnableStatus: menuModel.EnableStatus, | 23 | EnableStatus: menuModel.EnableStatus, |
| 24 | + Link: menuModel.Link, | ||
| 24 | }, nil | 25 | }, nil |
| 25 | } | 26 | } |
| @@ -204,6 +204,9 @@ func (repository *UserRepository) Find(queryOptions map[string]interface{}) (int | @@ -204,6 +204,9 @@ func (repository *UserRepository) Find(queryOptions map[string]interface{}) (int | ||
| 204 | } | 204 | } |
| 205 | query.SetWhereByQueryOption("company_id=?", "companyId") | 205 | query.SetWhereByQueryOption("company_id=?", "companyId") |
| 206 | query.SetWhereByQueryOption("organization_id=?", "organizationId") | 206 | query.SetWhereByQueryOption("organization_id=?", "organizationId") |
| 207 | + if v, ok := queryOptions["inUserIds"]; ok && len(v.([]int64)) > 0 { | ||
| 208 | + query.Where(`user_id in (?)`, pg.In(v)) | ||
| 209 | + } | ||
| 207 | if v, ok := queryOptions["inOrgIds"]; ok && len(v.([]int64)) > 0 { | 210 | if v, ok := queryOptions["inOrgIds"]; ok && len(v.([]int64)) > 0 { |
| 208 | query.Where(`organization_id in (?)`, pg.In(v)) | 211 | query.Where(`organization_id in (?)`, pg.In(v)) |
| 209 | } | 212 | } |
| 1 | +package controllers | ||
| 2 | + | ||
| 3 | +import ( | ||
| 4 | + "github.com/linmadan/egglib-go/web/beego" | ||
| 5 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/application/terminal/command" | ||
| 6 | + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-user/pkg/application/terminal/service" | ||
| 7 | +) | ||
| 8 | + | ||
| 9 | +type TerminalController struct { | ||
| 10 | + beego.BaseController | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | +func (controller *TerminalController) TerminalReport() { | ||
| 14 | + service := service.NewTerminalService(nil) | ||
| 15 | + terminalReportCommand := &command.TerminalReportCommand{} | ||
| 16 | + controller.Unmarshal(terminalReportCommand) | ||
| 17 | + data, err := service.TerminalReport(terminalReportCommand) | ||
| 18 | + controller.Response(data, err) | ||
| 19 | +} |
| @@ -179,3 +179,12 @@ func (controller *UserController) UpdateAdminUser() { | @@ -179,3 +179,12 @@ func (controller *UserController) UpdateAdminUser() { | ||
| 179 | data, err := userService.UpdateAdminUser(updateUserCommand) | 179 | data, err := userService.UpdateAdminUser(updateUserCommand) |
| 180 | controller.Response(data, err) | 180 | controller.Response(data, err) |
| 181 | } | 181 | } |
| 182 | + | ||
| 183 | +func (controller *UserController) SyncToAttendanceMachine() { | ||
| 184 | + userService := service.NewUserService(nil) | ||
| 185 | + cmd := &command.SyncToAttendanceMachineCommand{} | ||
| 186 | + Must(controller.Unmarshal(cmd)) | ||
| 187 | + cmd.OperateInfo = ParseOperateInfo(controller.BaseController) | ||
| 188 | + data, err := userService.SyncToAttendanceMachine(cmd) | ||
| 189 | + controller.Response(data, err) | ||
| 190 | +} |
pkg/port/beego/routers/terminal_router.go
0 → 100644
| @@ -21,6 +21,8 @@ func init() { | @@ -21,6 +21,8 @@ func init() { | ||
| 21 | web.Router("/user/cooperator", &controllers.UserController{}, "Post:CreateCooperator") | 21 | web.Router("/user/cooperator", &controllers.UserController{}, "Post:CreateCooperator") |
| 22 | web.Router("/user/cooperator/:userId", &controllers.UserController{}, "Put:UpdateCooperator") | 22 | web.Router("/user/cooperator/:userId", &controllers.UserController{}, "Put:UpdateCooperator") |
| 23 | 23 | ||
| 24 | + web.Router("/user/sync-to-attendance-machine", &controllers.UserController{}, "Post:SyncToAttendanceMachine") | ||
| 25 | + | ||
| 24 | web.Router("/admin-user/", &controllers.UserController{}, "Post:CreateAdminUser") | 26 | web.Router("/admin-user/", &controllers.UserController{}, "Post:CreateAdminUser") |
| 25 | web.Router("/admin-user/:userId", &controllers.UserController{}, "Put:UpdateAdminUser") | 27 | web.Router("/admin-user/:userId", &controllers.UserController{}, "Put:UpdateAdminUser") |
| 26 | } | 28 | } |
-
请 注册 或 登录 后发表评论