Browse Source

dept: 部门管理

Yi 11 months ago
parent
commit
25c3f1072e

+ 2 - 1
cmd/http.go

@@ -2,11 +2,12 @@ package cmd
 
 import (
 	"fmt"
-	"gitee.com/xuyiping_admin/pkg/logger/logrus"
 	"kpt-pasture/config"
 	"kpt-pasture/dep"
 	"kpt-pasture/http"
 
+	"gitee.com/xuyiping_admin/pkg/logger/logrus"
+
 	"github.com/spf13/cobra"
 )
 

+ 54 - 0
cmd/job.go

@@ -0,0 +1,54 @@
+package cmd
+
+import (
+	"context"
+	"fmt"
+	"kpt-pasture/config"
+	"kpt-pasture/store/kptstore"
+
+	"go.uber.org/zap"
+
+	"gitee.com/xuyiping_admin/pkg/cmd"
+	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
+	"gitee.com/xuyiping_admin/pkg/xerr"
+	"gitee.com/xuyiping_admin/pkg/xstore/database/migrator"
+	"github.com/spf13/cobra"
+)
+
+func init() {
+	cmd.Instant(JobCmd, "db:migrate", taskDBMigrate, "数据库迁移-执行完立刻退出")
+}
+
+var JobCmd = &cobra.Command{
+	Use:   "job",
+	Short: "内部一次性脚本",
+	Run: func(cmd *cobra.Command, args []string) {
+		fmt.Println("job called")
+	},
+}
+
+// Migration record
+type Migration struct {
+	Id   int    `xorm:"INT AUTOINCR NOTNULL PK"`
+	Name string `xorm:"VARCHAR(1024) NOTNULL UNIQUE"`
+}
+
+// TableName migrations
+func (Migration) TableName() string {
+	return "migrations"
+}
+
+func taskDBMigrate(ctx context.Context, args []string) error {
+	cfg := config.Options()
+	zaplog.Info("boot migrate")
+	db := kptstore.MustMigrateStore(cfg)
+
+	if err := migrator.AutoMigrateFiles(db, "../migration"); err != nil {
+		zaplog.Error("taskDBMigrate", zap.Any("err", err))
+		panic(xerr.WithStack(err))
+	}
+	sqlDB, _ := db.DB()
+	defer sqlDB.Close()
+	zaplog.Info("migrate ok")
+	return nil
+}

+ 2 - 5
cmd/root.go

@@ -1,7 +1,3 @@
-/*
-Copyright © 2022 NAME HERE <EMAIL ADDRESS>
-
-*/
 package cmd
 
 import (
@@ -12,7 +8,7 @@ import (
 
 var RootCmd = &cobra.Command{
 	Use:   "kpt-pasture",
-	Short: "科湃腾犊牛饲喂系统",
+	Short: "科湃腾牛群系统",
 }
 
 // Execute adds all child commands to the root command and sets flags appropriately.
@@ -26,4 +22,5 @@ func Execute() {
 
 func init() {
 	RootCmd.AddCommand(httpCmd)
+	RootCmd.AddCommand(JobCmd)
 }

+ 1 - 1
config/app.develop.yaml

@@ -3,7 +3,7 @@ app_environment: test
 debug: true
 http_server_addr: ':8090'
 http_metrics_addr: ':23332'
-jwt_expire_time: 7200
+jwt_expire_time: 172800
 
 store:
   show_sql: true

+ 1 - 1
config/app.test.yaml

@@ -3,7 +3,7 @@ app_environment: test
 debug: true
 http_server_addr: ':8090'
 http_metrics_addr: ':23332'
-jwt_expire_time: 7200
+jwt_expire_time: 172800
 
 store:
   show_sql: true

+ 2 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20230802054950-77dee3d12065
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20240401040019-3fb9a6003d30
 	gitee.com/xuyiping_admin/pkg v0.0.0-20231218082641-aac597b8a015
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/getsentry/sentry-go v0.23.0
@@ -80,6 +80,7 @@ require (
 	github.com/ugorji/go/codec v1.2.11 // indirect
 	github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 // indirect
 	github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 // indirect
+	github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 // indirect
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.8.0 // indirect
 	golang.org/x/arch v0.5.0 // indirect

+ 22 - 11
go.sum

@@ -38,6 +38,24 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20230802054950-77dee3d12065 h1:ITJlIE5ITvh3FiOw6QOrVDgAYOtuimwMBiHM0prmVbQ=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20230802054950-77dee3d12065/go.mod h1:cxbPefIf1o+cyQwvFaM3ndaoUeaK5aWzPV/eZQGJPgE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240328032854-7e1c99c00057 h1:11IpWLdkaeWdtf8Qag9vBT2hKgrdhwacYXmm5amb9H4=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240328032854-7e1c99c00057/go.mod h1:x47UOU+lOkZnrtAENAsOGd7mZ5I8D2JRkMKMqLLRlVw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240328053456-67ab8fd39ce4 h1:85Ak3TToTwPYNaYMADZbp1NAv/VxFRiuNHD2BJplElM=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240328053456-67ab8fd39ce4/go.mod h1:x47UOU+lOkZnrtAENAsOGd7mZ5I8D2JRkMKMqLLRlVw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240329032431-ff066e18fe03 h1:izQ5VdAAUDMdvEWuOV8eVgDbMGU39VcW5YcN9TwCiIo=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240329032431-ff066e18fe03/go.mod h1:x47UOU+lOkZnrtAENAsOGd7mZ5I8D2JRkMKMqLLRlVw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240329070243-93f03a1b569e h1:O9aOktiAliTANbV1LuEadcfhIEMyy/OEhHxjZBaKTqk=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240329070243-93f03a1b569e/go.mod h1:x47UOU+lOkZnrtAENAsOGd7mZ5I8D2JRkMKMqLLRlVw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240329072405-fee6fe04da86 h1:wGWaUoa6XL3PtZWZfRIcy7wTAB4jPrnlUi74LsTHwIU=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240329072405-fee6fe04da86/go.mod h1:x47UOU+lOkZnrtAENAsOGd7mZ5I8D2JRkMKMqLLRlVw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240329080618-ef46fba4262e h1:IPmcM4K4xqSaJvW1QoyS9+X8oyZCqY8j0XlIHtNLj04=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240329080618-ef46fba4262e/go.mod h1:x47UOU+lOkZnrtAENAsOGd7mZ5I8D2JRkMKMqLLRlVw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240329080928-dd9514d636fd h1:osH7VbEah7afqvWODbI1djmLpHlANMB2tYze0ejViZs=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240329080928-dd9514d636fd/go.mod h1:x47UOU+lOkZnrtAENAsOGd7mZ5I8D2JRkMKMqLLRlVw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240329090614-8d1695394747 h1:nZe/zepMRm3iHKIeJWCtRwIwJZ95GTy6R0loYF77JQQ=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240329090614-8d1695394747/go.mod h1:x47UOU+lOkZnrtAENAsOGd7mZ5I8D2JRkMKMqLLRlVw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240401040019-3fb9a6003d30 h1:R80acl0/nOILonC3X86X6H5QlqFN7cBX4wnTpKUcBvw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20240401040019-3fb9a6003d30/go.mod h1:x47UOU+lOkZnrtAENAsOGd7mZ5I8D2JRkMKMqLLRlVw=
 gitee.com/xuyiping_admin/pkg v0.0.0-20231218082641-aac597b8a015 h1:dfb5dRd57L2HKjdwLT93UFmPYFPOmEl56gtZmqcNnaE=
 gitee.com/xuyiping_admin/pkg v0.0.0-20231218082641-aac597b8a015/go.mod h1:Fk4GYI/v0IK3XFrm1Gn+VkgCz5Y7mfswD5hsTJYOG6A=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -336,12 +354,13 @@ github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
 github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
 github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 h1:Chd9DkqERQQuHpXjR/HSV1jLZA6uaoiwwH3vSuF3IW0=
 github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
+github.com/xuri/excelize/v2 v2.8.0 h1:Vd4Qy809fupgp1v7X+nCS/MioeQmYVVzi495UCTqB7U=
 github.com/xuri/excelize/v2 v2.8.0/go.mod h1:6iA2edBTKxKbZAa7X5bDhcCg51xdOn1Ar5sfoXRGrQg=
-github.com/xuri/excelize/v2 v2.8.1 h1:pZLMEwK8ep+CLIUWpWmvW8IWE/yxqG0I1xcN6cVMGuQ=
-github.com/xuri/excelize/v2 v2.8.1/go.mod h1:oli1E4C3Pa5RXg1TBXn4ENCXDV5JUMlBluUhG7c+CEE=
 github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
 github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 h1:qhbILQo1K3mphbwKh1vNm4oGezE1eF9fQWmNiIpSfI4=
 github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
+github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 h1:zzrxE1FKn5ryBNl9eKOeqQ58Y/Qpo3Q9QNxKHX5uzzQ=
+github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -382,8 +401,6 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
 golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
 golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
 golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
-golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
-golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -396,8 +413,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
 golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
-golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -463,8 +480,6 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
 golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos=
 golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
-golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
-golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -542,8 +557,6 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
 golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
-golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -562,8 +575,6 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

+ 75 - 0
http/handler/system/dept.go

@@ -0,0 +1,75 @@
+package system
+
+import (
+	"kpt-pasture/http/middleware"
+	"net/http"
+	"strconv"
+
+	operationPb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/operation"
+
+	"gitee.com/xuyiping_admin/pkg/valid"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	"gitee.com/xuyiping_admin/pkg/apierr"
+	"gitee.com/xuyiping_admin/pkg/ginutil"
+	"github.com/gin-gonic/gin"
+)
+
+func DeptList(c *gin.Context) {
+	var req pasturePb.SearchDeptRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusOK, err)
+		return
+	}
+
+	req.Pagination = &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.SearchSystemDeptList(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func DepIsShow(c *gin.Context) {
+	IDStr := c.Param("id")
+	Id, _ := strconv.Atoi(IDStr)
+
+	if err := valid.Validate(Id, valid.Required, valid.Min(1)); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	if err := middleware.Dependency(c).StoreEventHub.OpsService.SystemDepDelete(c, int64(Id)); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}
+
+func DepCreateOrUpdate(c *gin.Context) {
+	var req pasturePb.SearchDeptRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusOK, err)
+		return
+	}
+
+	if err := middleware.Dependency(c).StoreEventHub.OpsService.SystemDeptCreateOrUpdate(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}

+ 6 - 5
http/handler/system/user.go

@@ -5,6 +5,7 @@ import (
 	"net/http"
 	"strconv"
 
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	operationPb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/operation"
 	"gitee.com/xuyiping_admin/pkg/apierr"
 	"gitee.com/xuyiping_admin/pkg/ginutil"
@@ -13,23 +14,23 @@ import (
 	"github.com/gin-gonic/gin"
 )
 
-// Auth 用户登录
-func Auth(c *gin.Context) {
-	var req operationPb.UserAuthData
+// Login 用户登录
+func Login(c *gin.Context) {
+	var req pasturePb.SearchUserRequest
 	if err := ginutil.BindProto(c, &req); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(&req.UserName, valid.Required),
+		valid.Field(&req.Name, valid.Required),
 		valid.Field(&req.Password, valid.Required),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
 	}
 
-	res, err := middleware.Dependency(c).StoreEventHub.OpsService.Auth(c, &req)
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.Login(c, &req)
 	if err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return

+ 107 - 0
http/middleware/log.go

@@ -0,0 +1,107 @@
+package middleware
+
+import (
+	"bytes"
+	"io/ioutil"
+
+	"net"
+	"net/http"
+	"net/http/httputil"
+	"os"
+	"runtime/debug"
+	"strings"
+	"time"
+
+	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
+	"github.com/gin-gonic/gin"
+	"go.uber.org/zap"
+)
+
+type responseBodyWriter struct {
+	gin.ResponseWriter
+	body *bytes.Buffer
+}
+
+func (r responseBodyWriter) Write(b []byte) (int, error) {
+	r.body.Write(b)
+	return r.ResponseWriter.Write(b)
+}
+
+// GinLogger 接管gin框架默认的日志
+func GinLogger() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		// 获取 response 内容
+		w := &responseBodyWriter{body: &bytes.Buffer{}, ResponseWriter: c.Writer}
+		c.Writer = w
+
+		var requestBody []byte
+		if c.Request.Body != nil {
+			requestBody, _ = ioutil.ReadAll(c.Request.Body)
+			c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(requestBody))
+		}
+		start := time.Now()
+		c.Next()
+		cost := time.Since(start)
+
+		logFields := []zap.Field{
+			zap.Int("status", c.Writer.Status()),
+			zap.String("request", c.Request.Method+" "+c.Request.URL.String()),
+			zap.String("query", c.Request.URL.RawQuery),
+			zap.String("ip", c.ClientIP()),
+			zap.String("user-agent", c.Request.UserAgent()),
+			zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
+			zap.String("time", cost.String()),
+			zap.String("x-request-id", c.Request.Header.Get("X-Request-Id")),
+		}
+		logFields = append(logFields, zap.String("Request body", string(requestBody)))
+		logFields = append(logFields, zap.String("Response body", w.body.String()))
+		zaplog.Info("Http-Access-Log", logFields...)
+	}
+}
+
+// GinRecovery recover掉我的项目可能呈现的panic
+func GinRecovery(stack bool) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		defer func() {
+			if err := recover(); err != nil {
+				// Check for a broken connection, as it is not really a
+				// condition that warrants a panic stack trace.
+				var brokenPipe bool
+				if ne, ok := err.(*net.OpError); ok {
+					if se, ok := ne.Err.(*os.SyscallError); ok {
+						if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
+							brokenPipe = true
+						}
+					}
+				}
+
+				httpRequest, _ := httputil.DumpRequest(c.Request, false)
+				if brokenPipe {
+					zaplog.Error(c.Request.URL.Path,
+						zap.Any("error", err),
+						zap.String("request", string(httpRequest)),
+					)
+					// If the connection is dead, we can't write a status to it.
+					c.Error(err.(error)) // nolint: errcheck
+					c.Abort()
+					return
+				}
+
+				if stack {
+					zaplog.Error("[Recovery from panic]",
+						zap.Any("error", err),
+						zap.String("request", string(httpRequest)),
+						zap.String("stack", string(debug.Stack())),
+					)
+				} else {
+					zaplog.Error("[Recovery from panic]",
+						zap.Any("error", err),
+						zap.String("request", string(httpRequest)),
+					)
+				}
+				c.AbortWithStatus(http.StatusInternalServerError)
+			}
+		}()
+		c.Next()
+	}
+}

+ 1 - 1
http/middleware/sso.go

@@ -34,7 +34,7 @@ func GetXRequestId(c *gin.Context) string {
 }
 
 func unauthorized(c *gin.Context) {
-	c.AbortWithStatusJSON(http.StatusBadRequest, apierr.WithContext(c, commonPb.Error_UNAUTHORIZED))
+	c.AbortWithStatusJSON(http.StatusOK, apierr.WithContext(c, commonPb.Error_UNAUTHORIZED))
 }
 
 // RequireAdmin ...

+ 6 - 2
http/route/system_api.go

@@ -17,7 +17,7 @@ func SystemAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		s.NoRoute(handler.Handle404)
 		// Health Check
 		s.GET("/check", handler.Health)
-		s.POST("/auth", system.Auth)
+		s.POST("/api/v1/login", system.Login)
 
 		// system API 组
 		// 系统用户
@@ -47,12 +47,16 @@ func SystemAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		systemRoute.POST("/menu/list", system.SearchSystemMenuList)
 		systemRoute.DELETE("/menu/:menu_id", system.DeleteSystemMenu)
 
+		// 系统部门
+		systemRoute.POST("/dept/list", system.DeptList)
+		systemRoute.DELETE("/dept/:id", system.DepIsShow)
+		systemRoute.POST("/dept/createOrUpdate", system.DepCreateOrUpdate)
 	}
 }
 
 func authRouteGroup(s *gin.Engine, relativePath string) *gin.RouterGroup {
 	group := s.Group(relativePath)
 	// 中间件鉴权
-	group.Use(middleware.RequireAdmin(), middleware.CORS())
+	group.Use( /*middleware.RequireAdmin(),*/ middleware.GinLogger(), middleware.CORS())
 	return group
 }

+ 6 - 0
migrator/v0001_demo.sql

@@ -0,0 +1,6 @@
+CREATE TABLE IF NOT EXISTS `demo` (
+   `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键自增id',
+   `created_at` bigint(20) unsigned NOT NULL COMMENT '创建时间',
+   `updated_at` bigint(20) unsigned NOT NULL COMMENT '更新时间',
+   PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='demo';

+ 47 - 0
model/system_dept.go

@@ -0,0 +1,47 @@
+package model
+
+import (
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+type SystemDept struct {
+	Id        int64                 `json:"id"`
+	Name      string                `json:"name"`
+	Remarks   string                `json:"remarks"`
+	DeptType  pasturePb.Depth_Kind  `json:"dept_type"`
+	LeaderId  int64                 `json:"leader_id"`
+	ParentId  int64                 `json:"parent_id"`
+	Sort      int32                 `json:"sort"`
+	IsShow    pasturePb.IsShow_Kind `json:"is_show"`
+	IsDelete  pasturePb.IsShow_Kind `json:"is_delete"`
+	CreatedAt int64                 `json:"created_at"`
+	UpdatedAt int64                 `json:"updated_at"`
+}
+
+func (s *SystemDept) TableName() string {
+	return "system_dept"
+}
+
+type SystemDeptSlice []*SystemDept
+
+func (s SystemDeptSlice) ToPB() []*pasturePb.SearchDeptRequest {
+	res := make([]*pasturePb.SearchDeptRequest, len(s))
+	for i, d := range s {
+		res[i] = &pasturePb.SearchDeptRequest{
+			Id:              int32(d.Id),
+			Name:            d.Name,
+			Remarks:         d.Remarks,
+			ParentId:        int32(d.ParentId),
+			DepthType:       d.DeptType,
+			LeaderId:        int32(d.LeaderId),
+			Sort:            d.Sort,
+			IsShow:          d.IsShow,
+			IsDelete:        d.IsDelete,
+			CreatedAtFormat: time.Unix(d.CreatedAt, 0).Format(LayoutTime),
+			UpdatedAtFormat: time.Unix(d.UpdatedAt, 0).Format(LayoutTime),
+		}
+	}
+	return res
+}

+ 22 - 74
model/system_user.go

@@ -1,28 +1,30 @@
 package model
 
 import (
-	"fmt"
-	operationPb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/operation"
 	"net/http"
-	"strconv"
-	"strings"
 	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	operationPb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/operation"
 )
 
 const InitManagerPassword = "123456"
 
 type SystemUser struct {
-	Id           int64                   `json:"id"`
-	Name         string                  `json:"name"`
-	EmployeeName string                  `json:"employee_name"`
-	Phone        string                  `json:"phone"`
-	Password     string                  `json:"password"`
-	RoleIds      string                  `json:"role_ids"`
-	CreateUser   string                  `json:"create_user"`
-	IsShow       operationPb.IsShow_Kind `json:"is_show"`
-	IsDelete     operationPb.IsShow_Kind `json:"is_delete"`
-	CreatedAt    int64                   `json:"created_at"`
-	UpdatedAt    int64                   `json:"updated_at"`
+	Id        int64                  `json:"id"`
+	Name      string                 `json:"name"`
+	NickName  string                 `json:"nick_name"`
+	Mobile    string                 `json:"mobile"`
+	Password  string                 `json:"password"`
+	Avatar    string                 `json:"avatar"`
+	RoleId    int64                  `json:"role_id"`
+	DeptId    int64                  `json:"dept_id"`
+	Remarks   string                 `json:"remarks"`
+	Gender    pasturePb.Genders_Kind `json:"gender"`
+	IsShow    pasturePb.IsShow_Kind  `json:"is_show"`
+	IsDelete  pasturePb.IsShow_Kind  `json:"is_delete"`
+	CreatedAt int64                  `json:"created_at"`
+	UpdatedAt int64                  `json:"updated_at"`
 }
 
 func (s *SystemUser) TableName() string {
@@ -42,38 +44,13 @@ func (s *SystemUser) SystemUserFormat(userRoles []*SystemRole, pastures []*opera
 		Code: http.StatusOK,
 		Msg:  "ok",
 		Data: &operationPb.UserAuthData{
-			UserName:     s.Name,
-			Phone:        s.Phone,
-			EmployeeName: s.EmployeeName,
-			Roles:        roles,
-			Pastures:     pastures,
+			UserName: s.Name,
+			Roles:    roles,
+			Pastures: pastures,
 		},
 	}
 }
 
-func (s *SystemUser) SystemUserRoleFormat(req *operationPb.AddSystemUser) {
-	roleIds := ""
-	for _, role := range req.Roles {
-		roleIds += fmt.Sprintf("%d,", role.Id)
-	}
-	if roleIds != "" {
-		s.RoleIds = strings.TrimRight(roleIds, ",")
-	}
-}
-
-func (s *SystemUser) SystemUserRoleToSlice() []int {
-	roleIds := make([]int, 0)
-	if s.RoleIds != "" {
-		roleIdsStr := strings.Split(s.RoleIds, ",")
-		for _, v := range roleIdsStr {
-			roleIdsInt, _ := strconv.Atoi(v)
-			roleIds = append(roleIds, roleIdsInt)
-		}
-	}
-
-	return roleIds
-}
-
 type SystemUserSlice []*SystemUser
 
 func (s SystemUserSlice) ToPB(roleList []*SystemRole) []*operationPb.AddSystemUser {
@@ -82,50 +59,21 @@ func (s SystemUserSlice) ToPB(roleList []*SystemRole) []*operationPb.AddSystemUs
 		res[i] = &operationPb.AddSystemUser{
 			Id:              int32(v.Id),
 			Name:            v.Name,
-			Phone:           v.Phone,
-			EmployeeName:    v.EmployeeName,
-			CreateUser:      v.CreateUser,
-			IsShow:          v.IsShow,
 			CreatedAt:       int32(v.CreatedAt),
 			CreatedAtFormat: time.Unix(v.CreatedAt, 0).Format(LayoutTime),
-			RoleName:        strings.TrimRight(v.UserRoleFormat(roleList), ","),
+			RoleName:        "",
 		}
 	}
 	return res
 }
 
-func (s *SystemUser) UserRoleFormat(roleList []*SystemRole) string {
-	ids := strings.Split(s.RoleIds, ",")
-	roleListName := ""
-	for _, id := range ids {
-		for _, r := range roleList {
-			if fmt.Sprintf("%d", r.Id) != id {
-				continue
-			}
-			roleListName += fmt.Sprintf("%s,", r.Name)
-		}
-	}
-	return roleListName
-}
-
 func (s *SystemUser) ToPb() *operationPb.AddSystemUser {
 
-	roles := make([]int32, 0)
-	roleIds := strings.Split(s.RoleIds, ",")
-	for _, roleId := range roleIds {
-		id, _ := strconv.Atoi(roleId)
-		roles = append(roles, int32(id))
-	}
-
 	return &operationPb.AddSystemUser{
 		Id:              int32(s.Id),
 		Name:            s.Name,
-		Phone:           s.Phone,
-		CreateUser:      s.CreateUser,
-		EmployeeName:    s.EmployeeName,
-		IsShow:          s.IsShow,
 		CreatedAt:       int32(s.CreatedAt),
 		CreatedAtFormat: time.Unix(s.CreatedAt, 0).Format(LayoutTime),
-		RoleIds:         roles,
+		RoleIds:         []int32{},
 	}
 }

+ 8 - 2
module/backend/interface.go

@@ -6,6 +6,7 @@ import (
 	"kpt-pasture/service/wechat"
 	"kpt-pasture/store/kptstore"
 
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	operationPb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/operation"
 	"gitee.com/xuyiping_admin/pkg/di"
 
@@ -46,8 +47,8 @@ type KptService interface {
 
 //go:generate mockgen -destination mock/SystemService.go -package kptservicemock kpt-pasture/module/backend SystemService
 type SystemService interface {
-	// Auth 系统用户相关
-	Auth(ctx context.Context, auth *operationPb.UserAuthData) (*operationPb.SystemToken, error)
+	// Login 系统用户相关
+	Login(ctx context.Context, req *pasturePb.SearchUserRequest) (*pasturePb.SystemUserResponse, error)
 	GetCurrentUserName(ctx context.Context) (string, error)
 	GetUserInfo(ctx context.Context, token string) (*operationPb.UserAuth, error)
 	CreateSystemUser(ctx context.Context, req *operationPb.AddSystemUser) error
@@ -72,4 +73,9 @@ type SystemService interface {
 	IsShowSystemMenu(ctx context.Context, req *operationPb.IsShowSystemMenuRequest) error
 	SearchSystemMenuList(ctx context.Context, req *operationPb.SearchMenuRequest) (*operationPb.SearchMenuResponse, error)
 	DeleteSystemMenu(ctx context.Context, menuId int64) error
+
+	// SearchSystemDeptList 部门列表
+	SearchSystemDeptList(ctx context.Context, req *pasturePb.SearchDeptRequest) (*pasturePb.SearchDeptResponse, error)
+	SystemDepDelete(ctx context.Context, id int64) error
+	SystemDeptCreateOrUpdate(ctx context.Context, req *pasturePb.SearchDeptRequest) error
 }

+ 95 - 27
module/backend/system_service.go

@@ -4,34 +4,38 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"kpt-pasture/model"
+	"kpt-pasture/util"
+	"net/http"
+	"sort"
+	"strings"
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	operationPb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/operation"
 	"gitee.com/xuyiping_admin/pkg/jwt"
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
 	"gitee.com/xuyiping_admin/pkg/tool"
 	"gitee.com/xuyiping_admin/pkg/xerr"
 	"go.uber.org/zap"
-	"kpt-pasture/model"
-	"net/http"
-	"sort"
-	"strings"
-	"time"
 
 	"gorm.io/gorm"
 )
 
 const CurrentUserName = "userName"
 
-// Auth 用户登录
-func (s *StoreEntry) Auth(ctx context.Context, auth *operationPb.UserAuthData) (*operationPb.SystemToken, error) {
+// Login 用户登录
+func (s *StoreEntry) Login(ctx context.Context, req *pasturePb.SearchUserRequest) (*pasturePb.SystemUserResponse, error) {
 	systemUser := &model.SystemUser{}
-
-	if err := s.DB.Where("name = ?", auth.UserName).Find(systemUser).Error; err != nil {
+	if err := s.DB.Where("name = ?", req.Name).Find(systemUser).Error; err != nil {
 		return nil, xerr.WithStack(err)
 	}
-	if systemUser.Password != auth.Password {
-		return nil, xerr.Customf("密码错误,来自用户:%s", auth.UserName)
+
+	if systemUser.Password != req.Password {
+		return nil, xerr.Customf("密码错误,来自用户:%s", req.Name)
 	}
-	if systemUser.IsShow == operationPb.IsShow_NO {
+
+	if systemUser.IsShow == pasturePb.IsShow_No {
 		return nil, xerr.Customf("该账号已被禁用,请联系管理员")
 	}
 
@@ -44,10 +48,18 @@ func (s *StoreEntry) Auth(ctx context.Context, auth *operationPb.UserAuthData) (
 		return nil, xerr.Custom("获取token错误")
 	}
 
-	return &operationPb.SystemToken{
-		Code: http.StatusOK,
-		Msg:  "ok",
-		Data: &operationPb.TokenData{Token: token},
+	expires := time.Now().Add(time.Duration(s.Cfg.JwtExpireTime) * time.Second).Format(util.LayoutTime)
+	return &pasturePb.SystemUserResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.SystemUserData{
+			AccessToken:  token,
+			Expires:      expires,
+			RefreshToken: expires,
+			Username:     systemUser.Name,
+			Roles:        []string{"admin"},
+			Avatar:       systemUser.Avatar,
+		},
 	}, nil
 }
 
@@ -82,17 +94,16 @@ func (s *StoreEntry) GetUserInfo(ctx context.Context, token string) (*operationP
 
 // CreateSystemUser 创建系统用户
 func (s *StoreEntry) CreateSystemUser(ctx context.Context, req *operationPb.AddSystemUser) error {
-
 	systemUsers := &model.SystemUser{
-		Name:         req.Name,
-		EmployeeName: req.EmployeeName,
+		Name: req.Name,
+		/*EmployeeName: req.EmployeeName,
 		Phone:        req.Phone,
 		Password:     tool.Md5String(model.InitManagerPassword),
 		CreateUser:   req.CreateUser,
 		IsShow:       operationPb.IsShow_OK,
-		IsDelete:     operationPb.IsShow_OK,
+		IsDelete:     operationPb.IsShow_OK,*/
 	}
-	systemUsers.SystemUserRoleFormat(req)
+	/*systemUsers.SystemUserRoleFormat(req)*/
 
 	if err := s.DB.Create(systemUsers).Error; err != nil {
 		return xerr.WithStack(err)
@@ -154,11 +165,11 @@ func (s *StoreEntry) EditSystemUser(ctx context.Context, req *operationPb.AddSys
 	}
 
 	updateData := &model.SystemUser{
-		Name:         req.Name,
-		EmployeeName: req.EmployeeName,
-		Phone:        req.Phone,
+		Name: req.Name,
+		/*EmployeeName: req.EmployeeName,
+		Phone:        req.Phone,*/
 	}
-	updateData.SystemUserRoleFormat(req)
+	/*updateData.SystemUserRoleFormat(req)*/
 
 	if err := s.DB.Model(new(model.SystemUser)).Omit("is_show", "password", "is_delete", "create_user").
 		Where("id = ?", systemUser.Id).
@@ -257,8 +268,8 @@ func (s *StoreEntry) GetSystemUserPermissions(ctx context.Context, token string)
 		}
 		return nil, xerr.WithStack(err)
 	}
-	roleIds := systemUser.SystemUserRoleToSlice()
-
+	/*roleIds := systemUser.SystemUserRoleToSlice()*/
+	roleIds := []int64{1}
 	// 获取用户角色数据
 	systemRoles := make([]*model.SystemRole, 0)
 	if err = s.DB.Where("is_show = ?", operationPb.IsShow_OK).Find(&systemRoles, roleIds).Error; err != nil {
@@ -656,3 +667,60 @@ func (s *StoreEntry) DeleteSystemMenu(ctx context.Context, menuId int64) error {
 	}
 	return nil
 }
+
+func (s *StoreEntry) SearchSystemDeptList(ctx context.Context, req *pasturePb.SearchDeptRequest) (*pasturePb.SearchDeptResponse, error) {
+	deptList := make([]*model.SystemDept, 0)
+	var count int64 = 0
+	pref := s.DB.Model(new(model.SystemDept)).Where("is_delete = ?", operationPb.IsShow_OK)
+	if req.Name != "" {
+		pref.Where("name like ?", fmt.Sprintf("%s%s%s", "%", req.Name, "%"))
+	}
+
+	if req.IsShow > 0 {
+		pref.Where("is_show = ?", req.IsShow)
+	}
+
+	if err := pref.Order("sort desc").Count(&count).Limit(int(req.Pagination.PageSize)).Offset(int(req.Pagination.PageOffset)).
+		Find(&deptList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return &pasturePb.SearchDeptResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data:    model.SystemDeptSlice(deptList).ToPB(),
+	}, nil
+}
+
+func (s *StoreEntry) SystemDepDelete(ctx context.Context, id int64) error {
+	dept := &model.SystemDept{Id: id}
+	if err := s.DB.First(dept).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if dept.IsShow == pasturePb.IsShow_No {
+		return nil
+	}
+	if err := s.DB.Model(dept).Update("is_delete", operationPb.IsShow_NO).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}
+
+func (s *StoreEntry) SystemDeptCreateOrUpdate(ctx context.Context, req *pasturePb.SearchDeptRequest) error {
+	if err := s.DB.Model(&model.SystemDept{}).Where(map[string]interface{}{
+		"id": req.Id,
+	}).Assign(map[string]interface{}{
+		"name":      req.Name,
+		"sort":      req.Sort,
+		"parent_id": req.ParentId,
+		"remarks":   req.Remarks,
+		"is_delete": operationPb.IsShow_OK,
+		"is_show":   req.IsShow,
+		"dept_type": pasturePb.Depth_Department,
+		"leader_id": req.LeaderId,
+	}).FirstOrCreate(&model.SystemDept{}).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}

+ 24 - 8
store/kptstore/rw_store.go

@@ -33,15 +33,15 @@ func (g goRmLog) Printf(s string, i ...interface{}) {
 	logrus.Infof(s, i...)
 }
 
-func MustNewStore(cfg *config.AppConfig) *DB {
-	newLogger := logger.New(
-		goRmLog{},
-		logger.Config{
-			SlowThreshold: 5 * time.Second,
-			LogLevel:      logger.Info,
-		},
-	)
+var newLogger = logger.New(
+	goRmLog{},
+	logger.Config{
+		SlowThreshold: 5 * time.Second,
+		LogLevel:      logger.Info,
+	},
+)
 
+func MustNewStore(cfg *config.AppConfig) *DB {
 	db, err := gorm.Open(mysql.New(mysql.Config{
 		DriverName: cfg.StoreSetting.DriverName,
 		DSN:        cfg.StoreSetting.KptRW}),
@@ -57,3 +57,19 @@ func MustNewStore(cfg *config.AppConfig) *DB {
 
 	return NewStore(db)
 }
+
+func MustMigrateStore(cfg *config.AppConfig) *gorm.DB {
+	db, err := gorm.Open(mysql.New(mysql.Config{
+		DriverName: cfg.StoreSetting.DriverName,
+		DSN:        cfg.StoreSetting.KptMigr}),
+		&gorm.Config{Logger: newLogger},
+	)
+	if err != nil {
+		panic(xerr.WithStack(err))
+	}
+
+	if cfg.StoreSetting.ShowSQL {
+		db.Logger.LogMode(logger.Info)
+	}
+	return db
+}

+ 6 - 0
util/util.go

@@ -0,0 +1,6 @@
+package util
+
+const (
+	LocationName = "Asia/Shanghai"
+	LayoutTime   = "2006-01-02 15:04:05"
+)