diff --git a/cmd/erp.go b/cmd/erp.go
index e1c8c61..7ed2b28 100644
--- a/cmd/erp.go
+++ b/cmd/erp.go
@@ -65,7 +65,7 @@ func runErp(ctx context.Context) error {
rander, err := tpl.New(session, biz.SystemV1().MenuBiz())
checkError(err)
- handler := handler.NewHandler(conf, rander, redis, session, biz)
+ handler := handler.NewHandler(conf, rander, redis, session, biz, middleware)
address := fmt.Sprintf("%s:%d", conf.App.Host, conf.App.Port)
log.Printf("Starting erp manage server on %s", address)
diff --git a/cmd/manage.go b/cmd/manage.go
deleted file mode 100644
index 6e15cd0..0000000
--- a/cmd/manage.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package cmd
-
-import (
- "context"
- "fmt"
- "log"
-
- "management/internal/config"
- "management/internal/pkg/logger"
- "management/internal/pkg/snowflake"
-
- dbinit "management/internal/db/init"
- db "management/internal/db/sqlc"
-
- router "management/internal/router/manage"
-
- "github.com/spf13/cobra"
-)
-
-var manageCmd = &cobra.Command{
- Use: "manage",
- Short: "Start management server",
- Long: `A Service to management manage`,
- Run: func(cmd *cobra.Command, args []string) {
- err := runManage(cmd.Context())
- if err != nil {
- log.Fatalf("run manage failed: %v", err)
- }
- },
-}
-
-func init() {
- manageCmd.Flags().StringVarP(&configPath, "config", "c", "", "Custom config file path")
- rootCmd.AddCommand(manageCmd)
-}
-
-func runManage(ctx context.Context) error {
- mustInitAny(configPath, config.Init)
- logger.Init()
- mustInitAny(ctx, db.NewStore)
- // 初始化数据
- dbinit.InitSeed()
- // mustInit(redis.Init)
- // session.Init()
- mustInit(snowflake.Init)
- // mustInit(token.NewPasetoMaker)
- // mustInit(tencentoss.Init)
- // mustInit(tpl.Init)
-
- address := fmt.Sprintf("%s:%d", config.File.App.Host, config.File.App.Port)
- log.Printf("Starting manage server on %s", address)
- server := InitServer(address, router.NewRouter())
- return server.ListenAndServe()
-}
diff --git a/go.mod b/go.mod
index 254bd39..2875fa2 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,6 @@ require (
github.com/aead/chacha20poly1305 v0.0.0-20201124145622-1a5aba2a8b29
github.com/alexedwards/scs/pgxstore v0.0.0-20250212122300-421ef1d8611c
github.com/alexedwards/scs/v2 v2.8.0
- github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
github.com/bwmarrin/snowflake v0.3.0
github.com/fsnotify/fsnotify v1.8.0
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
@@ -14,25 +13,24 @@ require (
github.com/go-chi/chi/v5 v5.2.1
github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.18.1
- github.com/go-playground/validator/v10 v10.25.0
+ github.com/go-playground/validator/v10 v10.26.0
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/uuid v1.6.0
github.com/gorilla/schema v1.4.1
github.com/h2non/filetype v1.1.3
github.com/hirochachacha/go-smb2 v1.1.0
github.com/jackc/pgconn v1.14.3
- github.com/jackc/pgx/v5 v5.7.2
+ github.com/jackc/pgx/v5 v5.7.4
github.com/justinas/nosurf v1.1.1
github.com/matoous/go-nanoid/v2 v2.1.0
github.com/mojocn/base64Captcha v1.3.8
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/o1egl/paseto v1.0.0
- github.com/redis/go-redis/v9 v9.7.1
- github.com/rs/zerolog v1.33.0
+ github.com/redis/go-redis/v9 v9.7.3
+ github.com/rs/zerolog v1.34.0
github.com/spf13/cobra v1.9.1
- github.com/spf13/viper v1.20.0
+ github.com/spf13/viper v1.20.1
github.com/sqids/sqids-go v0.4.1
- github.com/tencentyun/cos-go-sdk-v5 v0.7.61
github.com/zhang2092/browser v0.0.2
golang.org/x/crypto v0.36.0
)
@@ -45,7 +43,6 @@ require (
github.com/bytedance/sonic v1.12.9 // indirect
github.com/bytedance/sonic/loader v0.2.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
- github.com/clbanning/mxj v1.8.4 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
@@ -54,7 +51,6 @@ require (
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
- github.com/google/go-querystring v1.1.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgio v1.0.0 // indirect
@@ -67,13 +63,11 @@ require (
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/mozillazg/go-httpheader v0.4.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pkg/errors v0.9.1 // indirect
- github.com/sagikazarmark/locafero v0.8.0 // indirect
+ github.com/sagikazarmark/locafero v0.9.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.14.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
@@ -84,11 +78,10 @@ require (
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.14.0 // indirect
golang.org/x/image v0.25.0 // indirect
- golang.org/x/net v0.37.0 // indirect
+ golang.org/x/net v0.38.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
- golang.org/x/time v0.10.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index 2ad01ef..e9390b1 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,5 @@
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
-github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/chacha20poly1305 v0.0.0-20170617001512-233f39982aeb/go.mod h1:UzH9IX1MMqOcwhoNOIjmTQeAxrFgzs50j4golQtXXxU=
@@ -12,8 +11,6 @@ github.com/alexedwards/scs/pgxstore v0.0.0-20250212122300-421ef1d8611c h1:Y33ELO
github.com/alexedwards/scs/pgxstore v0.0.0-20250212122300-421ef1d8611c/go.mod h1:hwveArYcjyOK66EViVgVU5Iqj7zyEsWjKXMQhDJrTLI=
github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw=
github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
-github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
-github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
@@ -29,8 +26,6 @@ github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wio
github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I=
-github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
@@ -64,8 +59,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
-github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
+github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
+github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
@@ -75,14 +70,9 @@ github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17w
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
-github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
-github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
@@ -112,8 +102,8 @@ github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZ
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
-github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
-github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
+github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
+github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
@@ -147,9 +137,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
-github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -157,9 +144,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mojocn/base64Captcha v1.3.8 h1:rrN9BhCwXKS8ht1e21kvR3iTaMgf4qPC9sRoV52bqEg=
github.com/mojocn/base64Captcha v1.3.8/go.mod h1:QFZy927L8HVP3+VV5z2b1EAEiv1KxVJKZbAucVgLUy4=
-github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
-github.com/mozillazg/go-httpheader v0.4.0 h1:aBn6aRXtFzyDLZ4VIRLsZbbJloagQfMnCiYgOq6hK4w=
-github.com/mozillazg/go-httpheader v0.4.0/go.mod h1:PuT8h0pw6efvp8ZeUec1Rs7dwjK08bt6gKSReGMqtdA=
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
github.com/o1egl/paseto v1.0.0 h1:bwpvPu2au176w4IBlhbyUv/S5VPptERIA99Oap5qUd0=
@@ -171,17 +155,17 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/redis/go-redis/v9 v9.7.1 h1:4LhKRCIduqXqtvCUlaq9c8bdHOkICjDMrr1+Zb3osAc=
-github.com/redis/go-redis/v9 v9.7.1/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
+github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
+github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
-github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
-github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
-github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
+github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
+github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/sagikazarmark/locafero v0.8.0 h1:mXaMVw7IqxNBxfv3LdWt9MDmcWDQ1fagDH918lOdVaQ=
-github.com/sagikazarmark/locafero v0.8.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
+github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k=
+github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
@@ -196,8 +180,8 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.20.0 h1:zrxIyR3RQIOsarIrgL8+sAvALXul9jeEPa06Y0Ph6vY=
-github.com/spf13/viper v1.20.0/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
+github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
+github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
github.com/sqids/sqids-go v0.4.1 h1:eQKYzmAZbLlRwHeHYPF35QhgxwZHLnlmVj9AkIj/rrw=
github.com/sqids/sqids-go v0.4.1/go.mod h1:EMwHuPQgSNFS0A49jESTfIQS+066XQTVhukrzEPScl8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -216,10 +200,6 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0=
-github.com/tencentyun/cos-go-sdk-v5 v0.7.61 h1:tKNIjvsezkdtajqE887XAw1VL8Pq1HNtpc7rfgz25lA=
-github.com/tencentyun/cos-go-sdk-v5 v0.7.61/go.mod h1:8+hG+mQMuRP/OIS9d83syAvXvrMj9HhkND6Q1fLghw0=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
@@ -258,8 +238,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
-golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
-golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
+golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
+golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -306,8 +286,6 @@ golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
-golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
-golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
@@ -315,7 +293,6 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/internal/db/init/config.go b/internal/db/init/config.go
index 8c6177a..8e236ea 100644
--- a/internal/db/init/config.go
+++ b/internal/db/init/config.go
@@ -5,7 +5,7 @@ import (
"encoding/json"
db "management/internal/db/sqlc"
- "management/internal/global/pearadmin"
+ "management/internal/pkg/know/pearadmin"
)
func initConfig() error {
diff --git a/internal/db/init/init.go b/internal/db/init/init.go
index 1a14c19..38f0b39 100644
--- a/internal/db/init/init.go
+++ b/internal/db/init/init.go
@@ -5,7 +5,7 @@ import (
"log"
db "management/internal/db/sqlc"
- "management/internal/global/pearadmin"
+ "management/internal/pkg/know/pearadmin"
)
func InitSeed() {
diff --git a/internal/erpserver/biz/biz.go b/internal/erpserver/biz/biz.go
index 8acad7f..c3d20b3 100644
--- a/internal/erpserver/biz/biz.go
+++ b/internal/erpserver/biz/biz.go
@@ -2,8 +2,11 @@ package biz
import (
db "management/internal/db/sqlc"
+ budgetv1 "management/internal/erpserver/biz/v1/budget"
commonv1 "management/internal/erpserver/biz/v1/common"
customerv1 "management/internal/erpserver/biz/v1/customer"
+ expensev1 "management/internal/erpserver/biz/v1/expense"
+ incomev1 "management/internal/erpserver/biz/v1/income"
projectv1 "management/internal/erpserver/biz/v1/project"
systemv1 "management/internal/erpserver/biz/v1/system"
"management/internal/pkg/redis"
@@ -18,8 +21,14 @@ type IBiz interface {
SystemV1() systemv1.SystemBiz
// 项目管理
ProjectV1() projectv1.ProjectBiz
+ // 预算管理
+ BudgetV1() budgetv1.BudgetBiz
// 客户管理
CustomerV1() customerv1.CustomerBiz
+ // 收入管理
+ IncomeV1() incomev1.IncomeBiz
+ // 支出管理
+ ExpenseV1() expensev1.ExpenseBiz
}
// biz 是 IBiz 的一个具体实现.
@@ -55,6 +64,18 @@ func (b *biz) ProjectV1() projectv1.ProjectBiz {
return projectv1.New(b.store, b.redis)
}
+func (b *biz) BudgetV1() budgetv1.BudgetBiz {
+ return budgetv1.New(b.store, b.redis)
+}
+
func (b *biz) CustomerV1() customerv1.CustomerBiz {
return customerv1.New(b.store, b.redis)
}
+
+func (b *biz) IncomeV1() incomev1.IncomeBiz {
+ return incomev1.New(b.store, b.redis)
+}
+
+func (b *biz) ExpenseV1() expensev1.ExpenseBiz {
+ return expensev1.New(b.store, b.redis)
+}
diff --git a/internal/erpserver/biz/v1/budget/budget.go b/internal/erpserver/biz/v1/budget/budget.go
new file mode 100644
index 0000000..c26982a
--- /dev/null
+++ b/internal/erpserver/biz/v1/budget/budget.go
@@ -0,0 +1,45 @@
+package budget
+
+import (
+ "context"
+
+ db "management/internal/db/sqlc"
+ "management/internal/pkg/redis"
+)
+
+type BudgetBiz interface {
+ Create(ctx context.Context, arg *db.CreateBudgetParams) (*db.Budget, error)
+ Update(ctx context.Context, arg *db.UpdateBudgetParams) (*db.Budget, error)
+ List(ctx context.Context, arg *db.ListBudgetConditionParam) ([]*db.BudgetView, int64, error)
+ Get(ctx context.Context, id int64) (*db.Budget, error)
+}
+
+type budgetBiz struct {
+ store db.Store
+ redis redis.IRedis
+}
+
+var _ BudgetBiz = (*budgetBiz)(nil)
+
+func New(store db.Store, redis redis.IRedis) *budgetBiz {
+ return &budgetBiz{
+ store: store,
+ redis: redis,
+ }
+}
+
+func (b *budgetBiz) Create(ctx context.Context, arg *db.CreateBudgetParams) (*db.Budget, error) {
+ return b.store.CreateBudget(ctx, arg)
+}
+
+func (b *budgetBiz) Update(ctx context.Context, arg *db.UpdateBudgetParams) (*db.Budget, error) {
+ return b.store.UpdateBudget(ctx, arg)
+}
+
+func (b *budgetBiz) List(ctx context.Context, arg *db.ListBudgetConditionParam) ([]*db.BudgetView, int64, error) {
+ return b.store.ListBudgetCondition(ctx, arg)
+}
+
+func (b *budgetBiz) Get(ctx context.Context, id int64) (*db.Budget, error) {
+ return b.store.GetBudget(ctx, id)
+}
diff --git a/internal/erpserver/biz/v1/expense/expsense.go b/internal/erpserver/biz/v1/expense/expsense.go
new file mode 100644
index 0000000..cfa97a3
--- /dev/null
+++ b/internal/erpserver/biz/v1/expense/expsense.go
@@ -0,0 +1,67 @@
+package expense
+
+import (
+ "context"
+
+ db "management/internal/db/sqlc"
+ "management/internal/pkg/redis"
+
+ "github.com/jackc/pgx/v5/pgtype"
+)
+
+type ExpenseBiz interface {
+ Create(ctx context.Context, arg *db.CreateExpenseParams) (*db.Expense, error)
+ Update(ctx context.Context, arg *db.UpdateExpenseParams) (*db.Expense, error)
+ List(ctx context.Context, arg *db.ListExpenseConditionParam) ([]*db.ExpenseView, int64, error)
+ Get(ctx context.Context, id int64) (*db.Expense, error)
+ Sum(ctx context.Context) (pgtype.Numeric, error)
+ SumByProjectID(ctx context.Context, id int64) (pgtype.Numeric, error)
+ Statistics(ctx context.Context) ([]*db.StatisticsExpenseRow, error)
+ StatisticsByProjectID(ctx context.Context, projectID int64) ([]*db.StatisticsExpenseByProjectIDRow, error)
+}
+
+type expenseBiz struct {
+ store db.Store
+ redis redis.IRedis
+}
+
+var _ ExpenseBiz = (*expenseBiz)(nil)
+
+func New(store db.Store, redis redis.IRedis) *expenseBiz {
+ return &expenseBiz{
+ store: store,
+ redis: redis,
+ }
+}
+
+func (b *expenseBiz) Create(ctx context.Context, arg *db.CreateExpenseParams) (*db.Expense, error) {
+ return b.store.CreateExpense(ctx, arg)
+}
+
+func (b *expenseBiz) Update(ctx context.Context, arg *db.UpdateExpenseParams) (*db.Expense, error) {
+ return b.store.UpdateExpense(ctx, arg)
+}
+
+func (b *expenseBiz) List(ctx context.Context, arg *db.ListExpenseConditionParam) ([]*db.ExpenseView, int64, error) {
+ return b.store.ListExpenseCondition(ctx, arg)
+}
+
+func (b *expenseBiz) Get(ctx context.Context, id int64) (*db.Expense, error) {
+ return b.store.GetExpense(ctx, id)
+}
+
+func (b *expenseBiz) Sum(ctx context.Context) (pgtype.Numeric, error) {
+ return b.store.SumExpense(ctx)
+}
+
+func (b *expenseBiz) SumByProjectID(ctx context.Context, id int64) (pgtype.Numeric, error) {
+ return b.store.SumExpenseByProjectID(ctx, id)
+}
+
+func (b *expenseBiz) Statistics(ctx context.Context) ([]*db.StatisticsExpenseRow, error) {
+ return b.store.StatisticsExpense(ctx)
+}
+
+func (b *expenseBiz) StatisticsByProjectID(ctx context.Context, projectID int64) ([]*db.StatisticsExpenseByProjectIDRow, error) {
+ return b.store.StatisticsExpenseByProjectID(ctx, projectID)
+}
diff --git a/internal/erpserver/biz/v1/income/income.go b/internal/erpserver/biz/v1/income/income.go
new file mode 100644
index 0000000..fac15be
--- /dev/null
+++ b/internal/erpserver/biz/v1/income/income.go
@@ -0,0 +1,67 @@
+package income
+
+import (
+ "context"
+
+ db "management/internal/db/sqlc"
+ "management/internal/pkg/redis"
+
+ "github.com/jackc/pgx/v5/pgtype"
+)
+
+type IncomeBiz interface {
+ Create(ctx context.Context, arg *db.CreateIncomeParams) (*db.Income, error)
+ Update(ctx context.Context, arg *db.UpdateIncomeParams) (*db.Income, error)
+ List(ctx context.Context, arg *db.ListIncomeConditionParam) ([]*db.IncomeView, int64, error)
+ Get(ctx context.Context, id int64) (*db.Income, error)
+ Sum(ctx context.Context) (pgtype.Numeric, error)
+ SumByProjectID(ctx context.Context, id int64) (pgtype.Numeric, error)
+ Statistics(ctx context.Context) ([]*db.StatisticsIncomeRow, error)
+ StatisticsByProjectID(ctx context.Context, projectID int64) ([]*db.StatisticsIncomeByProjectIDRow, error)
+}
+
+type incomeBiz struct {
+ store db.Store
+ redis redis.IRedis
+}
+
+var _ IncomeBiz = (*incomeBiz)(nil)
+
+func New(store db.Store, redis redis.IRedis) *incomeBiz {
+ return &incomeBiz{
+ store: store,
+ redis: redis,
+ }
+}
+
+func (b *incomeBiz) Create(ctx context.Context, arg *db.CreateIncomeParams) (*db.Income, error) {
+ return b.store.CreateIncome(ctx, arg)
+}
+
+func (b *incomeBiz) Update(ctx context.Context, arg *db.UpdateIncomeParams) (*db.Income, error) {
+ return b.store.UpdateIncome(ctx, arg)
+}
+
+func (b *incomeBiz) List(ctx context.Context, arg *db.ListIncomeConditionParam) ([]*db.IncomeView, int64, error) {
+ return b.store.ListIncomeCondition(ctx, arg)
+}
+
+func (b *incomeBiz) Get(ctx context.Context, id int64) (*db.Income, error) {
+ return b.store.GetIncome(ctx, id)
+}
+
+func (b *incomeBiz) Sum(ctx context.Context) (pgtype.Numeric, error) {
+ return b.store.SumIncome(ctx)
+}
+
+func (b *incomeBiz) SumByProjectID(ctx context.Context, id int64) (pgtype.Numeric, error) {
+ return b.store.SumIncomeByProjectID(ctx, id)
+}
+
+func (b *incomeBiz) Statistics(ctx context.Context) ([]*db.StatisticsIncomeRow, error) {
+ return b.store.StatisticsIncome(ctx)
+}
+
+func (b *incomeBiz) StatisticsByProjectID(ctx context.Context, projectID int64) ([]*db.StatisticsIncomeByProjectIDRow, error) {
+ return b.store.StatisticsIncomeByProjectID(ctx, projectID)
+}
diff --git a/internal/erpserver/biz/v1/project/project.go b/internal/erpserver/biz/v1/project/project.go
index d521c4b..fd475df 100644
--- a/internal/erpserver/biz/v1/project/project.go
+++ b/internal/erpserver/biz/v1/project/project.go
@@ -2,9 +2,12 @@ package project
import (
"context"
+ "strconv"
db "management/internal/db/sqlc"
+ "management/internal/erpserver/model/view"
"management/internal/pkg/redis"
+ "management/internal/pkg/tpl/html"
)
type ProjectBiz interface {
@@ -13,11 +16,17 @@ type ProjectBiz interface {
List(ctx context.Context, q *db.ListProjectConditionParam) ([]*db.ProjectView, int64, error)
Get(ctx context.Context, id int64) (*db.Project, error)
+ XmSelect(ctx context.Context) ([]*view.XmSelect, error)
+ ListHtml(ctx context.Context) ([]*html.SelectDict, error)
+
ProjectExpansion
}
type ProjectExpansion interface {
ListProjectFiles(ctx context.Context, projectID int64) ([]*db.ProjectFile, error)
+
+ Statistics(ctx context.Context) ([]*db.StatisticsProjectsRow, error)
+ StatisticsItem(ctx context.Context, id int64) (*db.StatisticsProjectItemRow, error)
}
type projectBiz struct {
@@ -91,3 +100,49 @@ func (b *projectBiz) Get(ctx context.Context, id int64) (*db.Project, error) {
func (b *projectBiz) ListProjectFiles(ctx context.Context, projectID int64) ([]*db.ProjectFile, error) {
return b.store.ListProjectFiles(ctx, projectID)
}
+
+func (b *projectBiz) XmSelect(ctx context.Context) ([]*view.XmSelect, error) {
+ all, err := b.store.AllProjects(ctx)
+ if err != nil || len(all) == 0 {
+ return nil, err
+ }
+
+ var res []*view.XmSelect
+ for _, item := range all {
+ res = append(res, &view.XmSelect{
+ Name: item.Name,
+ Value: strconv.FormatInt(item.ID, 10),
+ })
+ }
+ return res, nil
+}
+
+func (b *projectBiz) ListHtml(ctx context.Context) ([]*html.SelectDict, error) {
+ all, err := b.store.AllProjects(ctx)
+ if err != nil || len(all) == 0 {
+ return nil, err
+ }
+
+ var res []*html.SelectDict
+ res = append(res, &html.SelectDict{
+ Name: "请选择",
+ Value: "0",
+ })
+ for _, v := range all {
+ item := html.SelectDict{
+ Name: v.Name,
+ Value: strconv.Itoa(int(v.ID)),
+ }
+ res = append(res, &item)
+ }
+
+ return res, nil
+}
+
+func (b *projectBiz) Statistics(ctx context.Context) ([]*db.StatisticsProjectsRow, error) {
+ return b.store.StatisticsProjects(ctx)
+}
+
+func (b *projectBiz) StatisticsItem(ctx context.Context, id int64) (*db.StatisticsProjectItemRow, error) {
+ return b.store.StatisticsProjectItem(ctx, id)
+}
diff --git a/internal/erpserver/biz/v1/system/category.go b/internal/erpserver/biz/v1/system/category.go
index 26b44ca..571644e 100644
--- a/internal/erpserver/biz/v1/system/category.go
+++ b/internal/erpserver/biz/v1/system/category.go
@@ -10,7 +10,7 @@ import (
"management/internal/db/model/dto"
db "management/internal/db/sqlc"
"management/internal/erpserver/model/view"
- "management/internal/global/keys"
+ "management/internal/pkg/know"
"management/internal/pkg/redis"
"management/internal/pkg/tpl/html"
)
@@ -25,6 +25,7 @@ type CategoryBiz interface {
RebuildParentPath(ctx context.Context) error
Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error)
+ XmSelect(ctx context.Context, letter string) ([]*view.XmSelect, error)
XmSelectTree(ctx context.Context, id int32) ([]*view.XmSelectTree, error)
ListHtmlByLetter(ctx context.Context, letter string) ([]*html.SelectDict, error)
@@ -45,7 +46,7 @@ func NewCategory(store db.Store, redis redis.IRedis) *categoryBiz {
}
func (b *categoryBiz) All(ctx context.Context) ([]*db.Category, error) {
- key := keys.GetManageKey(ctx, keys.AllCategories)
+ key := know.GetManageKey(ctx, know.AllCategories)
bs, err := redis.GetBytes(ctx, key)
if err == nil {
var res []*db.Category
@@ -115,8 +116,8 @@ func (b *categoryBiz) Refresh(ctx context.Context) ([]*db.Category, error) {
return nil, err
}
- redis.Del(ctx, keys.GetManageKey(ctx, keys.AllCategorySimple))
- key := keys.GetManageKey(ctx, keys.AllCategories)
+ redis.Del(ctx, know.GetManageKey(ctx, know.AllCategorySimple))
+ key := know.GetManageKey(ctx, know.AllCategories)
err = redis.Set(ctx, key, bs, time.Hour*6)
return all, err
}
@@ -134,6 +135,36 @@ func (b *categoryBiz) Tree(ctx context.Context, id int32) ([]*view.LayuiTree, er
return b.toTree(id, all), nil
}
+func (b *categoryBiz) XmSelect(ctx context.Context, letter string) ([]*view.XmSelect, error) {
+ all, err := b.All(ctx)
+ if err != nil || len(all) == 0 {
+ return nil, err
+ }
+
+ var current *db.Category
+ for _, v := range all {
+ if v.Letter == letter {
+ current = v
+ break
+ }
+ }
+ if current == nil {
+ return nil, errors.New("未找到当前类别")
+ }
+
+ var res []*view.XmSelect
+ for _, v := range all {
+ if v.ParentID == current.ID {
+ item := view.XmSelect{
+ Name: v.Name,
+ Value: strconv.FormatInt(int64(v.ID), 10),
+ }
+ res = append(res, &item)
+ }
+ }
+ return res, nil
+}
+
func (b *categoryBiz) XmSelectTree(ctx context.Context, id int32) ([]*view.XmSelectTree, error) {
all, err := b.All(ctx)
if err != nil {
diff --git a/internal/erpserver/biz/v1/system/config.go b/internal/erpserver/biz/v1/system/config.go
index 05411c0..b38a140 100644
--- a/internal/erpserver/biz/v1/system/config.go
+++ b/internal/erpserver/biz/v1/system/config.go
@@ -7,8 +7,8 @@ import (
"management/internal/db/model/dto"
db "management/internal/db/sqlc"
- "management/internal/global/keys"
- "management/internal/global/pearadmin"
+ "management/internal/pkg/know"
+ "management/internal/pkg/know/pearadmin"
"management/internal/pkg/redis"
)
@@ -71,7 +71,7 @@ func (b *configBiz) List(ctx context.Context, q dto.SearchDto) ([]*db.SysConfig,
func (b *configBiz) Pear(ctx context.Context) (*dto.PearConfig, error) {
// 判断redis是否存储
- key := keys.GetManageKey(ctx, keys.PearAdmin)
+ key := know.GetManageKey(ctx, know.PearAdmin)
bs, err := b.redis.GetBytes(ctx, key)
if err == nil {
var res *dto.PearConfig
diff --git a/internal/erpserver/biz/v1/system/department.go b/internal/erpserver/biz/v1/system/department.go
index 28f384a..b17836f 100644
--- a/internal/erpserver/biz/v1/system/department.go
+++ b/internal/erpserver/biz/v1/system/department.go
@@ -9,7 +9,7 @@ import (
"management/internal/db/model/dto"
db "management/internal/db/sqlc"
"management/internal/erpserver/model/view"
- "management/internal/global/keys"
+ "management/internal/pkg/know"
"management/internal/pkg/redis"
)
@@ -45,7 +45,7 @@ func NewDepartment(store db.Store, redis redis.IRedis) *departmentBiz {
}
func (b *departmentBiz) All(ctx context.Context) ([]*db.SysDepartment, error) {
- key := keys.GetManageKey(ctx, keys.AllDepartments)
+ key := know.GetManageKey(ctx, know.AllDepartments)
bs, err := redis.GetBytes(ctx, key)
if err == nil {
var res []*db.SysDepartment
@@ -115,7 +115,7 @@ func (b *departmentBiz) Refresh(ctx context.Context) ([]*db.SysDepartment, error
return nil, err
}
- key := keys.GetManageKey(ctx, keys.AllDepartments)
+ key := know.GetManageKey(ctx, know.AllDepartments)
err = redis.Set(ctx, key, bs, time.Hour*6)
if err != nil {
return nil, err
diff --git a/internal/erpserver/biz/v1/system/menu.go b/internal/erpserver/biz/v1/system/menu.go
index b3884c5..4d5fe58 100644
--- a/internal/erpserver/biz/v1/system/menu.go
+++ b/internal/erpserver/biz/v1/system/menu.go
@@ -11,7 +11,7 @@ import (
"management/internal/db/model/dto"
db "management/internal/db/sqlc"
"management/internal/erpserver/model/view"
- "management/internal/global/keys"
+ "management/internal/pkg/know"
"management/internal/pkg/redis"
)
@@ -71,7 +71,7 @@ func (b *menuBiz) GetSysMenuByUrl(ctx context.Context, url string) (*db.SysMenu,
}
func (b *menuBiz) AllMenusCache(ctx context.Context) ([]*db.SysMenu, error) {
- key := keys.GetManageKey(ctx, keys.AllMenus)
+ key := know.GetManageKey(ctx, know.AllMenus)
bs, err := b.redis.GetBytes(ctx, key)
if err == nil {
var res []*db.SysMenu
@@ -105,7 +105,7 @@ func (b *menuBiz) ListMenuTree(ctx context.Context) ([]*db.SysMenuDto, error) {
func (b *menuBiz) ListOwnerMenuByRoleID(ctx context.Context, roleID int32) ([]*dto.OwnerMenuDto, error) {
// 判断redis是否存储
- key := keys.GetManageKey(ctx, keys.OwnerMenus, roleID)
+ key := know.GetManageKey(ctx, know.OwnerMenus, roleID)
bs, err := b.redis.GetBytes(ctx, key)
if err == nil {
var res []*dto.OwnerMenuDto
@@ -141,14 +141,14 @@ func (b *menuBiz) SetOwnerListMenuByRoleID(ctx context.Context, roleID int32) ([
return nil, err
}
- key := keys.GetManageKey(ctx, keys.OwnerMenus, roleID)
+ key := know.GetManageKey(ctx, know.OwnerMenus, roleID)
_ = redis.Set(ctx, key, bs, time.Hour*6)
return res, nil
}
func (b *menuBiz) RecursiveSysMenus(ctx context.Context, roleID int32) ([]*dto.MenuUIDto, error) {
// 判断redis是否存储
- key := keys.GetManageKey(ctx, keys.RecursiveMenus, roleID)
+ key := know.GetManageKey(ctx, know.RecursiveMenus, roleID)
bs, err := b.redis.GetBytes(ctx, key)
if err == nil {
var res []*dto.MenuUIDto
@@ -195,14 +195,14 @@ func (b *menuBiz) SetRecursiveSysMenus(ctx context.Context, roleID int32) ([]*dt
return nil, err
}
- key := keys.GetManageKey(ctx, keys.RecursiveMenus, roleID)
+ key := know.GetManageKey(ctx, know.RecursiveMenus, roleID)
_ = redis.Set(ctx, key, bs, time.Hour*6)
return tree, nil
}
func (b *menuBiz) MapOwnerMenuByRoleID(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error) {
// 判断redis是否存储
- key := keys.GetManageKey(ctx, keys.OwnerMenus, roleID)
+ key := know.GetManageKey(ctx, know.OwnerMenus, roleID)
bs, err := b.redis.GetBytes(ctx, key)
if err == nil {
var res map[string]*dto.OwnerMenuDto
@@ -238,7 +238,7 @@ func (b *menuBiz) SetOwnerMapMenuByRoleID(ctx context.Context, roleID int32) (ma
return nil, err
}
- key := keys.GetManageKey(ctx, keys.OwnerMenus, roleID)
+ key := know.GetManageKey(ctx, know.OwnerMenus, roleID)
_ = redis.Set(ctx, key, bs, time.Hour*6)
return result, nil
}
@@ -254,7 +254,7 @@ func (b *menuBiz) RefreshMenus(ctx context.Context) error {
return err
}
- key := keys.GetManageKey(ctx, keys.AllMenus)
+ key := know.GetManageKey(ctx, know.AllMenus)
err = redis.Set(ctx, key, bs, time.Hour*6)
return err
}
diff --git a/internal/erpserver/biz/v1/system/role.go b/internal/erpserver/biz/v1/system/role.go
index 248a0ac..5c673d2 100644
--- a/internal/erpserver/biz/v1/system/role.go
+++ b/internal/erpserver/biz/v1/system/role.go
@@ -9,7 +9,7 @@ import (
"management/internal/db/model/dto"
db "management/internal/db/sqlc"
"management/internal/erpserver/model/view"
- "management/internal/global/keys"
+ "management/internal/pkg/know"
"management/internal/pkg/redis"
)
@@ -53,7 +53,7 @@ func (b *roleBiz) Update(ctx context.Context, arg *db.UpdateSysRoleParams) (*db.
}
func (b *roleBiz) All(ctx context.Context) ([]*db.SysRole, error) {
- key := keys.GetManageKey(ctx, keys.AllRoles)
+ key := know.GetManageKey(ctx, know.AllRoles)
bs, err := redis.GetBytes(ctx, key)
if err == nil {
var res []*db.SysRole
@@ -115,7 +115,7 @@ func (b *roleBiz) Refresh(ctx context.Context) ([]*db.SysRole, error) {
return nil, err
}
- key := keys.GetManageKey(ctx, keys.AllRoles)
+ key := know.GetManageKey(ctx, know.AllRoles)
err = redis.Set(ctx, key, bs, time.Hour*6)
if err != nil {
return nil, err
diff --git a/internal/erpserver/biz/v1/system/user.go b/internal/erpserver/biz/v1/system/user.go
index 29bf9d1..466c3d9 100644
--- a/internal/erpserver/biz/v1/system/user.go
+++ b/internal/erpserver/biz/v1/system/user.go
@@ -11,8 +11,8 @@ import (
db "management/internal/db/sqlc"
"management/internal/erpserver/model/req"
"management/internal/erpserver/model/view"
- "management/internal/global/know"
"management/internal/pkg/crypto"
+ "management/internal/pkg/know"
"management/internal/pkg/session"
)
diff --git a/internal/erpserver/handler/budget/budget.go b/internal/erpserver/handler/budget/budget.go
new file mode 100644
index 0000000..8060245
--- /dev/null
+++ b/internal/erpserver/handler/budget/budget.go
@@ -0,0 +1,274 @@
+package budget
+
+import (
+ "errors"
+ "net/http"
+ "strconv"
+ "strings"
+ "time"
+
+ "management/internal/db/model/form"
+ db "management/internal/db/sqlc"
+ "management/internal/erpserver/biz"
+ "management/internal/pkg/convertor"
+ "management/internal/pkg/know"
+ "management/internal/pkg/middleware"
+ "management/internal/pkg/tpl"
+ "management/internal/pkg/tpl/html"
+
+ "github.com/jackc/pgx/v5/pgtype"
+)
+
+type BudgetHandler interface {
+ List(w http.ResponseWriter, r *http.Request)
+ Add(w http.ResponseWriter, r *http.Request)
+ Edit(w http.ResponseWriter, r *http.Request)
+ Save(w http.ResponseWriter, r *http.Request)
+ Data(w http.ResponseWriter, r *http.Request)
+}
+
+type budgetHandler struct {
+ render tpl.Renderer
+ biz biz.IBiz
+ mi middleware.IMiddleware
+}
+
+var _ BudgetHandler = (*budgetHandler)(nil)
+
+func NewBudgetHandler(render tpl.Renderer, biz biz.IBiz, mi middleware.IMiddleware) *budgetHandler {
+ return &budgetHandler{
+ render: render,
+ biz: biz,
+ mi: mi,
+ }
+}
+
+func (h *budgetHandler) List(w http.ResponseWriter, r *http.Request) {
+ switch r.Method {
+ case http.MethodGet:
+ ctx := r.Context()
+ pp, _ := h.biz.ProjectV1().ListHtml(ctx)
+ cc, _ := h.biz.SystemV1().CategoryBiz().ListHtmlByLetter(ctx, know.BudgetCategory)
+ h.render.HTML(w, r, "budget/list.tmpl", map[string]any{
+ "Statuses": html.NewSelectControls(html.Statuses, "0"),
+ "Projects": html.NewSelectControls(pp, "0"),
+ "Categories": html.NewSelectControls(cc, "0"),
+ })
+ case http.MethodPost:
+ ctx := r.Context()
+ project := convertor.ConvertInt[int64](r.PostFormValue("project"), 9999)
+ if project == 0 {
+ project = 9999
+ }
+
+ budgetType := convertor.ConvertInt[int32](r.PostFormValue("budgetType"), 9999)
+ if budgetType == 0 {
+ budgetType = 9999
+ }
+
+ category := convertor.ConvertInt[int32](r.PostFormValue("category"), 9999)
+ if category == 0 {
+ category = 9999
+ }
+
+ title := strings.TrimSpace(r.PostFormValue("title"))
+ var search string
+ if len(title) > 0 {
+ search = "%" + title + "%"
+ if strings.HasSuffix(title, ":") {
+ search = title[:len(title)-1] + "%"
+ }
+ }
+ arg := &db.ListBudgetConditionParam{
+ ProjectID: project,
+ BudgetType: budgetType,
+ Category: category,
+ IsTitle: len(search) > 0,
+ Title: search,
+ Status: convertor.ConvertInt[int16](r.PostFormValue("status"), 9999),
+ PageID: convertor.ConvertInt[int32](r.PostFormValue("page"), 1),
+ PageSize: convertor.ConvertInt[int32](r.PostFormValue("rows"), 10),
+ }
+ arg.TimeBegin, arg.TimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
+ res, total, err := h.biz.BudgetV1().List(ctx, arg)
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+
+ data := tpl.ResponseList{
+ Code: 0,
+ Message: "ok",
+ Count: total,
+ Data: res,
+ }
+ h.render.JSON(w, data)
+ default:
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ }
+}
+
+func (h *budgetHandler) Add(w http.ResponseWriter, r *http.Request) {
+ h.render.HTML(w, r, "budget/edit.tmpl", map[string]any{
+ "Item": &form.BudgetForm{
+ BudgetType: 1,
+ },
+ "Statuses": html.NewSelectControls(html.Statuses, "0"),
+ })
+}
+
+func (h *budgetHandler) Edit(w http.ResponseWriter, r *http.Request) {
+ vars := r.URL.Query()
+ id := convertor.QueryInt[int64](vars, "id", 0)
+ budget := &form.BudgetForm{}
+ ctx := r.Context()
+ if id > 0 {
+ if cus, err := h.biz.BudgetV1().Get(ctx, id); err == nil {
+ budget = budget.ToForm(cus)
+ if u, err := h.biz.SystemV1().UserBiz().Get(ctx, cus.CreatedUserID); err == nil {
+ budget.CreatedName = u.Username
+ }
+ if u, err := h.biz.SystemV1().UserBiz().Get(ctx, cus.UpdatedUserID); err == nil {
+ budget.UpdatedName = u.Username
+ }
+ }
+ }
+ h.render.HTML(w, r, "budget/edit.tmpl", map[string]any{
+ "Item": budget,
+ "Statuses": html.NewSelectControls(html.Statuses, strconv.Itoa(int(budget.Status))),
+ })
+}
+
+func (h *budgetHandler) Save(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+ data, err := validForm(r)
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+
+ authUser := h.mi.AuthUser(ctx)
+ if data.ID > 0 {
+ arg := &db.UpdateBudgetParams{
+ ID: data.ID,
+ ProjectID: pgtype.Int8{
+ Int64: data.ProjectID,
+ Valid: true,
+ },
+ Name: pgtype.Text{
+ String: data.Name,
+ Valid: true,
+ },
+ BudgetType: pgtype.Int4{
+ Int32: data.BudgetType,
+ Valid: true,
+ },
+ Category: pgtype.Int4{
+ Int32: data.Category,
+ Valid: true,
+ },
+ StartAt: pgtype.Timestamptz{
+ Time: data.StartAt,
+ Valid: true,
+ },
+ EndAt: pgtype.Timestamptz{
+ Time: data.EndAt,
+ Valid: true,
+ },
+ Amount: data.AmountF,
+ UsedAmount: data.UsedAmountF,
+ RemainingAmount: data.RemainingAmountF,
+ Remark: pgtype.Text{
+ String: data.Remark,
+ Valid: true,
+ },
+ Status: pgtype.Int2{
+ Int16: data.Status,
+ Valid: true,
+ },
+ UpdatedUserID: pgtype.Int4{
+ Int32: authUser.ID,
+ Valid: true,
+ },
+ }
+ _, err := h.biz.BudgetV1().Update(ctx, arg)
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+ h.render.JSONOK(w, "更新成功")
+ } else {
+ arg := &db.CreateBudgetParams{
+ ProjectID: data.ProjectID,
+ Name: data.Name,
+ BudgetType: data.BudgetType,
+ Category: data.Category,
+ StartAt: data.StartAt,
+ EndAt: data.EndAt,
+ Amount: data.AmountF,
+ UsedAmount: data.UsedAmountF,
+ RemainingAmount: data.RemainingAmountF,
+ Remark: data.Remark,
+ CreatedUserID: authUser.ID,
+ }
+ _, err := h.biz.BudgetV1().Create(ctx, arg)
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+ h.render.JSONOK(w, "添加成功")
+ }
+}
+
+func (h *budgetHandler) Data(w http.ResponseWriter, r *http.Request) {}
+
+func validForm(r *http.Request) (form.BudgetForm, error) {
+ var err error
+ data := form.BudgetForm{}
+
+ data.ID = convertor.ConvertInt[int64](r.PostFormValue("ID"), 0)
+ data.ProjectID, err = strconv.ParseInt(r.PostFormValue("ProjectID"), 10, 64)
+ if err != nil || data.ProjectID == 0 {
+ return data, errors.New("项目不能为空")
+ }
+
+ data.Name = r.PostFormValue("Name")
+ if len(data.Name) == 0 {
+ return data, errors.New("预算名称不能为空")
+ }
+
+ budgetType, err := strconv.ParseInt(r.PostFormValue("BudgetType"), 10, 32)
+ if err != nil {
+ return data, errors.New("预算类型不能为空")
+ }
+ data.BudgetType = int32(budgetType)
+
+ category, err := strconv.ParseInt(r.PostFormValue("Category"), 10, 32)
+ if err != nil {
+ return data, errors.New("预算类别不能为空")
+ }
+ data.Category = int32(category)
+
+ data.StartAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("StartAt"), time.Local)
+ if err != nil {
+ return data, errors.New("开始时间格式错误")
+ }
+ data.EndAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("EndAt"), time.Local)
+ if err != nil {
+ return data, errors.New("结束时间格式错误")
+ }
+
+ if err := data.AmountF.Scan(r.PostFormValue("Amount")); err != nil {
+ return data, errors.New("预算金额格式错误")
+ }
+ if err := data.UsedAmountF.Scan(r.PostFormValue("UsedAmount")); err != nil {
+ return data, errors.New("已支付金额格式错误")
+ }
+ if err := data.RemainingAmountF.Scan(r.PostFormValue("RemainingAmount")); err != nil {
+ return data, errors.New("剩余金额格式错误")
+ }
+
+ data.Remark = r.PostFormValue("Remark")
+ data.Status = convertor.ConvertInt[int16](r.PostFormValue("Status"), 9999)
+ return data, nil
+}
diff --git a/internal/erpserver/handler/customer/customer.go b/internal/erpserver/handler/customer/customer.go
index 43fa65b..35455e9 100644
--- a/internal/erpserver/handler/customer/customer.go
+++ b/internal/erpserver/handler/customer/customer.go
@@ -8,12 +8,12 @@ import (
"management/internal/db/model/form"
db "management/internal/db/sqlc"
"management/internal/erpserver/biz"
- "management/internal/middleware/manage/auth"
"management/internal/pkg/convertor"
"management/internal/pkg/know"
+ "management/internal/pkg/middleware"
"management/internal/pkg/snowflake"
+ "management/internal/pkg/tpl"
"management/internal/pkg/tpl/html"
- "management/internal/tpl"
"github.com/jackc/pgx/v5/pgtype"
)
@@ -28,14 +28,16 @@ type CustomerHandler interface {
type customerHandler struct {
render tpl.Renderer
biz biz.IBiz
+ mi middleware.IMiddleware
}
var _ CustomerHandler = (*customerHandler)(nil)
-func NewCustomerHandler(render tpl.Renderer, biz biz.IBiz) *customerHandler {
+func NewCustomerHandler(render tpl.Renderer, biz biz.IBiz, mi middleware.IMiddleware) *customerHandler {
return &customerHandler{
render: render,
biz: biz,
+ mi: mi,
}
}
@@ -143,7 +145,7 @@ func (h *customerHandler) Save(w http.ResponseWriter, r *http.Request) {
}
ctx := r.Context()
- authUser := auth.AuthUser(ctx)
+ authUser := h.mi.AuthUser(ctx)
if data.ID > 0 {
arg := &db.UpdateCustomerParams{
ID: data.ID,
diff --git a/internal/erpserver/handler/expense/expense.go b/internal/erpserver/handler/expense/expense.go
new file mode 100644
index 0000000..b14a046
--- /dev/null
+++ b/internal/erpserver/handler/expense/expense.go
@@ -0,0 +1,231 @@
+package expense
+
+import (
+ "errors"
+ "net/http"
+ "strconv"
+ "strings"
+ "time"
+
+ "management/internal/db/model/form"
+ db "management/internal/db/sqlc"
+ "management/internal/erpserver/biz"
+ "management/internal/pkg/convertor"
+ "management/internal/pkg/know"
+ "management/internal/pkg/middleware"
+ "management/internal/pkg/tpl"
+ "management/internal/pkg/tpl/html"
+
+ "github.com/jackc/pgx/v5/pgtype"
+)
+
+type ExpenseHandler interface {
+ List(w http.ResponseWriter, r *http.Request)
+ Add(w http.ResponseWriter, r *http.Request)
+ Edit(w http.ResponseWriter, r *http.Request)
+ Save(w http.ResponseWriter, r *http.Request)
+}
+
+type expenseHandler struct {
+ render tpl.Renderer
+ biz biz.IBiz
+ mi middleware.IMiddleware
+}
+
+var _ ExpenseHandler = (*expenseHandler)(nil)
+
+func NewExpenseHandler(render tpl.Renderer, biz biz.IBiz, mi middleware.IMiddleware) *expenseHandler {
+ return &expenseHandler{
+ render: render,
+ biz: biz,
+ mi: mi,
+ }
+}
+
+func (h *expenseHandler) List(w http.ResponseWriter, r *http.Request) {
+ switch r.Method {
+ case http.MethodGet:
+ ctx := r.Context()
+ pp, _ := h.biz.ProjectV1().ListHtml(ctx)
+ cc, _ := h.biz.SystemV1().CategoryBiz().ListHtmlByLetter(ctx, know.ExpenseCategory)
+ h.render.HTML(w, r, "expense/list.tmpl", map[string]any{
+ "Statuses": html.NewSelectControls(html.Statuses, "0"),
+ "Projects": html.NewSelectControls(pp, "0"),
+ "Categories": html.NewSelectControls(cc, "0"),
+ })
+ case http.MethodPost:
+ ctx := r.Context()
+ project := convertor.ConvertInt[int64](r.PostFormValue("project"), 9999)
+ if project == 0 {
+ project = 9999
+ }
+ budget := convertor.ConvertInt[int64](r.PostFormValue("budget"), 9999)
+ if budget == 0 {
+ budget = 9999
+ }
+ category := convertor.ConvertInt[int32](r.PostFormValue("category"), 9999)
+ if category == 0 {
+ category = 9999
+ }
+
+ title := strings.TrimSpace(r.PostFormValue("title"))
+ var search string
+ if len(title) > 0 {
+ search = "%" + title + "%"
+ if strings.HasSuffix(title, ":") {
+ search = title[:len(title)-1] + "%"
+ }
+ }
+ arg := &db.ListExpenseConditionParam{
+ ProjectID: project,
+ BudgetID: budget,
+ ExpenseType: category,
+ IsTitle: len(search) > 0,
+ Title: search,
+ Status: convertor.ConvertInt[int16](r.PostFormValue("status"), 9999),
+ PageID: convertor.ConvertInt[int32](r.PostFormValue("page"), 1),
+ PageSize: convertor.ConvertInt[int32](r.PostFormValue("rows"), 10),
+ }
+ arg.TimeBegin, arg.TimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
+ res, total, err := h.biz.ExpenseV1().List(ctx, arg)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ data := tpl.ResponseList{
+ Code: 0,
+ Message: "ok",
+ Count: total,
+ Data: res,
+ }
+ h.render.JSON(w, data)
+ default:
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ }
+}
+
+func (h *expenseHandler) Add(w http.ResponseWriter, r *http.Request) {
+ h.render.HTML(w, r, "expense/edit.tmpl", map[string]any{
+ "Item": &form.ExpenseForm{},
+ "Statuses": html.NewSelectControls(html.Statuses, "0"),
+ })
+}
+
+func (h *expenseHandler) Edit(w http.ResponseWriter, r *http.Request) {
+ vars := r.URL.Query()
+ id := convertor.QueryInt[int64](vars, "id", 0)
+ expense := &form.ExpenseForm{}
+ ctx := r.Context()
+ if id > 0 {
+ if cus, err := h.biz.ExpenseV1().Get(ctx, id); err == nil {
+ expense = expense.ToForm(cus)
+ if u, err := h.biz.SystemV1().UserBiz().Get(ctx, cus.CreatedUserID); err == nil {
+ expense.CreatedName = u.Username
+ }
+ if u, err := h.biz.SystemV1().UserBiz().Get(ctx, cus.UpdatedUserID); err == nil {
+ expense.UpdatedName = u.Username
+ }
+ }
+ }
+ h.render.HTML(w, r, "expense/edit.tmpl", map[string]any{
+ "Item": expense,
+ "Statuses": html.NewSelectControls(html.Statuses, strconv.Itoa(int(expense.Status))),
+ })
+}
+
+func (h *expenseHandler) Save(w http.ResponseWriter, r *http.Request) {
+ data, err := validForm(r)
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+
+ ctx := r.Context()
+ authUser := h.mi.AuthUser(ctx)
+ if data.ID > 0 {
+ arg := &db.UpdateExpenseParams{
+ ID: data.ID,
+ ProjectID: pgtype.Int8{
+ Int64: data.ProjectID,
+ Valid: true,
+ },
+ BudgetID: pgtype.Int8{
+ Int64: data.BudgetID,
+ Valid: true,
+ },
+ Amount: data.AmountF,
+ ExpensesAt: pgtype.Timestamptz{
+ Time: data.ExpensesAt,
+ Valid: true,
+ },
+ ExpensesType: pgtype.Int4{
+ Int32: data.ExpensesType,
+ Valid: true,
+ },
+ Remark: pgtype.Text{
+ String: data.Remark,
+ Valid: true,
+ },
+ Status: pgtype.Int2{
+ Int16: data.Status,
+ Valid: true,
+ },
+ UpdatedUserID: pgtype.Int4{
+ Int32: authUser.ID,
+ Valid: true,
+ },
+ }
+ _, err := h.biz.ExpenseV1().Update(ctx, arg)
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+ h.render.JSONOK(w, "更新成功")
+ } else {
+ arg := &db.CreateExpenseParams{
+ ProjectID: data.ProjectID,
+ BudgetID: data.BudgetID,
+ Amount: data.AmountF,
+ ExpensesAt: data.ExpensesAt,
+ ExpensesType: data.ExpensesType,
+ Remark: data.Remark,
+ Status: data.Status,
+ CreatedUserID: authUser.ID,
+ }
+ _, err := h.biz.ExpenseV1().Create(ctx, arg)
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+ h.render.JSONOK(w, "添加成功")
+ }
+}
+
+func validForm(r *http.Request) (form.ExpenseForm, error) {
+ var err error
+ data := form.ExpenseForm{}
+
+ data.ID = convertor.ConvertInt[int64](r.PostFormValue("ID"), 0)
+ data.ProjectID, err = strconv.ParseInt(r.PostFormValue("ProjectID"), 10, 64)
+ if err != nil || data.ProjectID == 0 {
+ return data, errors.New("项目不能为空")
+ }
+ data.BudgetID, err = strconv.ParseInt(r.PostFormValue("BudgetID"), 10, 64)
+
+ if err := data.AmountF.Scan(r.PostFormValue("Amount")); err != nil {
+ return data, errors.New("报销金额格式错误")
+ }
+ data.ExpensesAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("ExpensesAt"), time.Local)
+ if err != nil {
+ return data, errors.New("报销时间格式错误")
+ }
+ expensesType, err := strconv.ParseInt(r.PostFormValue("ExpensesType"), 10, 64)
+ if err != nil || expensesType == 0 {
+ return data, errors.New("报销类型不能为空")
+ }
+ data.ExpensesType = int32(expensesType)
+
+ data.Status = convertor.ConvertInt[int16](r.PostFormValue("Status"), 9999)
+ return data, nil
+}
diff --git a/internal/erpserver/handler/handler.go b/internal/erpserver/handler/handler.go
index aa731dc..873cf55 100644
--- a/internal/erpserver/handler/handler.go
+++ b/internal/erpserver/handler/handler.go
@@ -3,10 +3,14 @@ package handler
import (
"management/internal/config"
"management/internal/erpserver/biz"
+ "management/internal/erpserver/handler/budget"
"management/internal/erpserver/handler/common"
"management/internal/erpserver/handler/customer"
+ "management/internal/erpserver/handler/expense"
+ "management/internal/erpserver/handler/income"
"management/internal/erpserver/handler/project"
"management/internal/erpserver/handler/system"
+ "management/internal/pkg/middleware"
"management/internal/pkg/redis"
"management/internal/pkg/session"
"management/internal/pkg/tpl"
@@ -18,8 +22,11 @@ type IHandler interface {
CommonHandler() common.CommonHandler
// 获取 System Handler 接口.
SystemHandler() system.SystemHandler
- PorjectHandler() project.PorjectHandler
+ ProjectHandler() project.ProjectHandler
+ BudgetHandler() budget.BudgetHandler
CustomerHandler() customer.CustomerHandler
+ IncomeHandler() income.IncomeHandler
+ ExpenseHandler() expense.ExpenseHandler
}
// handler 是 IHandler 的一个具体实现.
@@ -29,19 +36,21 @@ type handler struct {
redis redis.IRedis
session session.ISession
biz biz.IBiz
+ mi middleware.IMiddleware
}
// 确保 handler 实现了 IHandler 接口.
var _ IHandler = (*handler)(nil)
// NewHandler 创建一个 IHandler 类型的实例.
-func NewHandler(conf *config.Config, render tpl.Renderer, redis redis.IRedis, session session.ISession, biz biz.IBiz) *handler {
+func NewHandler(conf *config.Config, render tpl.Renderer, redis redis.IRedis, session session.ISession, biz biz.IBiz, mi middleware.IMiddleware) *handler {
return &handler{
conf: conf,
render: render,
redis: redis,
session: session,
biz: biz,
+ mi: mi,
}
}
@@ -52,15 +61,30 @@ func (h *handler) CommonHandler() common.CommonHandler {
// SystemHandler 返回一个实现了 SystemHandler 接口的实例.
func (h *handler) SystemHandler() system.SystemHandler {
- return system.NewSystemHandler(h.render, h.redis, h.session, h.biz)
+ return system.NewSystemHandler(h.render, h.redis, h.session, h.biz, h.mi)
}
-// PorjectHandler 返回一个实现了 PorjectHandler 接口的实例.
-func (h *handler) PorjectHandler() project.PorjectHandler {
- return project.NewPorjectHandler(h.render, h.biz)
+// ProjectHandler 返回一个实现了 ProjectHandler 接口的实例.
+func (h *handler) ProjectHandler() project.ProjectHandler {
+ return project.NewProjectHandler(h.render, h.biz, h.mi)
+}
+
+// BudgetHandler 返回一个实现了 BudgetHandler 接口的实例.
+func (h *handler) BudgetHandler() budget.BudgetHandler {
+ return budget.NewBudgetHandler(h.render, h.biz, h.mi)
}
// CustomerHandler 返回一个实现了 CustomerHandler 接口的实例.
func (h *handler) CustomerHandler() customer.CustomerHandler {
- return customer.NewCustomerHandler(h.render, h.biz)
+ return customer.NewCustomerHandler(h.render, h.biz, h.mi)
+}
+
+// IncomeHandler 返回一个实现了 IncomeHandler 接口的实例.
+func (h *handler) IncomeHandler() income.IncomeHandler {
+ return income.NewIncomeHandler(h.render, h.biz, h.mi)
+}
+
+// ExpenseHandler 返回一个实现了 ExpenseHandler 接口的实例.
+func (h *handler) ExpenseHandler() expense.ExpenseHandler {
+ return expense.NewExpenseHandler(h.render, h.biz, h.mi)
}
diff --git a/internal/erpserver/handler/income/income.go b/internal/erpserver/handler/income/income.go
new file mode 100644
index 0000000..4723851
--- /dev/null
+++ b/internal/erpserver/handler/income/income.go
@@ -0,0 +1,249 @@
+package income
+
+import (
+ "errors"
+ "net/http"
+ "strconv"
+ "strings"
+ "time"
+
+ "management/internal/db/model/form"
+ db "management/internal/db/sqlc"
+ "management/internal/erpserver/biz"
+ "management/internal/pkg/convertor"
+ "management/internal/pkg/know"
+ "management/internal/pkg/middleware"
+ "management/internal/pkg/tpl"
+ "management/internal/pkg/tpl/html"
+
+ "github.com/jackc/pgx/v5/pgtype"
+)
+
+type IncomeHandler interface {
+ List(w http.ResponseWriter, r *http.Request)
+ Add(w http.ResponseWriter, r *http.Request)
+ Edit(w http.ResponseWriter, r *http.Request)
+ Save(w http.ResponseWriter, r *http.Request)
+}
+
+type incomeHandler struct {
+ render tpl.Renderer
+ biz biz.IBiz
+ mi middleware.IMiddleware
+}
+
+var _ IncomeHandler = (*incomeHandler)(nil)
+
+func NewIncomeHandler(render tpl.Renderer, biz biz.IBiz, mi middleware.IMiddleware) *incomeHandler {
+ return &incomeHandler{
+ render: render,
+ biz: biz,
+ mi: mi,
+ }
+}
+
+func (h *incomeHandler) List(w http.ResponseWriter, r *http.Request) {
+ switch r.Method {
+ case http.MethodGet:
+ ctx := r.Context()
+ pp, _ := h.biz.ProjectV1().ListHtml(ctx)
+ cc, _ := h.biz.SystemV1().CategoryBiz().ListHtmlByLetter(ctx, know.IncomeCategory)
+ h.render.HTML(w, r, "income/list.tmpl", map[string]any{
+ "Statuses": html.NewSelectControls(html.Statuses, "0"),
+ "Projects": html.NewSelectControls(pp, "0"),
+ "Categories": html.NewSelectControls(cc, "0"),
+ })
+ case http.MethodPost:
+ ctx := r.Context()
+ project := convertor.ConvertInt[int64](r.PostFormValue("project"), 9999)
+ if project == 0 {
+ project = 9999
+ }
+ budget := convertor.ConvertInt[int64](r.PostFormValue("budget"), 9999)
+ if budget == 0 {
+ budget = 9999
+ }
+ category := convertor.ConvertInt[int32](r.PostFormValue("category"), 9999)
+ if category == 0 {
+ category = 9999
+ }
+
+ title := strings.TrimSpace(r.PostFormValue("title"))
+ var search string
+ if len(title) > 0 {
+ search = "%" + title + "%"
+ if strings.HasSuffix(title, ":") {
+ search = title[:len(title)-1] + "%"
+ }
+ }
+ arg := &db.ListIncomeConditionParam{
+ ProjectID: project,
+ BudgetID: budget,
+ IncomeType: category,
+ IsTitle: len(search) > 0,
+ Title: search,
+ Status: convertor.ConvertInt[int16](r.PostFormValue("status"), 9999),
+ PageID: convertor.ConvertInt[int32](r.PostFormValue("page"), 1),
+ PageSize: convertor.ConvertInt[int32](r.PostFormValue("rows"), 10),
+ }
+ arg.TimeBegin, arg.TimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
+ res, total, err := h.biz.IncomeV1().List(ctx, arg)
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+
+ data := tpl.ResponseList{
+ Code: 0,
+ Message: "ok",
+ Count: total,
+ Data: res,
+ }
+ h.render.JSON(w, data)
+ default:
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ }
+}
+
+func (h *incomeHandler) Add(w http.ResponseWriter, r *http.Request) {
+ h.render.HTML(w, r, "income/edit.tmpl", map[string]any{
+ "Item": &form.IncomeForm{},
+ "Statuses": html.NewSelectControls(html.Statuses, "0"),
+ })
+}
+
+func (h *incomeHandler) Edit(w http.ResponseWriter, r *http.Request) {
+ vars := r.URL.Query()
+ id := convertor.ConvertInt[int64](vars.Get("id"), 0)
+ income := &form.IncomeForm{}
+ ctx := r.Context()
+ if id > 0 {
+ if cus, err := h.biz.IncomeV1().Get(ctx, id); err == nil {
+ income = income.ToForm(cus)
+ if u, err := h.biz.SystemV1().UserBiz().Get(ctx, cus.CreatedUserID); err == nil {
+ income.CreatedName = u.Username
+ }
+ if u, err := h.biz.SystemV1().UserBiz().Get(ctx, cus.UpdatedUserID); err == nil {
+ income.UpdatedName = u.Username
+ }
+ }
+ }
+ h.render.HTML(w, r, "income/edit.tmpl", map[string]any{
+ "Item": income,
+ "Statuses": html.NewSelectControls(html.Statuses, strconv.Itoa(int(income.Status))),
+ })
+}
+
+func (h *incomeHandler) Save(w http.ResponseWriter, r *http.Request) {
+ data, err := validForm(r)
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+
+ ctx := r.Context()
+ authUser := h.mi.AuthUser(ctx)
+ if data.ID > 0 {
+ arg := &db.UpdateIncomeParams{
+ ID: data.ID,
+ ProjectID: pgtype.Int8{
+ Int64: data.ProjectID,
+ Valid: true,
+ },
+ BudgetID: pgtype.Int8{
+ Int64: data.BudgetID,
+ Valid: true,
+ },
+ Amount: data.AmountF,
+ IncomeAt: pgtype.Timestamptz{
+ Time: data.IncomeAt,
+ Valid: true,
+ },
+ IncomeType: pgtype.Int4{
+ Int32: data.IncomeType,
+ Valid: true,
+ },
+ IncomeBank: pgtype.Int4{
+ Int32: data.IncomeBank,
+ Valid: true,
+ },
+ Remark: pgtype.Text{
+ String: data.Remark,
+ Valid: true,
+ },
+ Status: pgtype.Int2{
+ Int16: data.Status,
+ Valid: true,
+ },
+ UpdatedUserID: pgtype.Int4{
+ Int32: authUser.ID,
+ Valid: true,
+ },
+ }
+ _, err := h.biz.IncomeV1().Update(ctx, arg)
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+ h.render.JSONOK(w, "更新成功")
+ } else {
+ arg := &db.CreateIncomeParams{
+ ProjectID: data.ProjectID,
+ BudgetID: data.BudgetID,
+ Amount: data.AmountF,
+ IncomeAt: data.IncomeAt,
+ IncomeType: data.IncomeType,
+ IncomeBank: data.IncomeBank,
+ Remark: data.Remark,
+ Status: data.Status,
+ CreatedUserID: authUser.ID,
+ }
+ _, err := h.biz.IncomeV1().Create(ctx, arg)
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+ h.render.JSONOK(w, "添加成功")
+ }
+}
+
+func validForm(r *http.Request) (form.IncomeForm, error) {
+ var err error
+ data := form.IncomeForm{}
+ data.ID = convertor.ConvertInt[int64](r.PostFormValue("ID"), 0)
+
+ data.ProjectID, err = strconv.ParseInt(r.PostFormValue("ProjectID"), 10, 64)
+ if err != nil || data.ProjectID == 0 {
+ return data, errors.New("项目不能为空")
+ }
+
+ data.BudgetID, err = strconv.ParseInt(r.PostFormValue("BudgetID"), 10, 64)
+ if err != nil {
+ data.BudgetID = 0
+ }
+
+ if err := data.AmountF.Scan(r.PostFormValue("Amount")); err != nil {
+ return data, errors.New("报销金额格式错误")
+ }
+
+ data.IncomeAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("IncomeAt"), time.Local)
+ if err != nil {
+ return data, errors.New("回款时间格式错误")
+ }
+
+ incomeType, err := strconv.ParseInt(r.PostFormValue("IncomeType"), 10, 64)
+ if err != nil {
+ return data, errors.New("收入类型数据错误")
+ }
+ data.IncomeType = int32(incomeType)
+
+ incomeBank, err := strconv.ParseInt(r.PostFormValue("IncomeBank"), 10, 64)
+ if err != nil {
+ return data, errors.New("收入银行数据错误")
+ }
+ data.IncomeBank = int32(incomeBank)
+
+ data.Remark = r.PostFormValue("Remark")
+ data.Status = convertor.ConvertInt[int16](r.PostFormValue("Status"), 9999)
+ return data, nil
+}
diff --git a/internal/erpserver/handler/project/dashboard.go b/internal/erpserver/handler/project/dashboard.go
new file mode 100644
index 0000000..ae4bd12
--- /dev/null
+++ b/internal/erpserver/handler/project/dashboard.go
@@ -0,0 +1,369 @@
+package project
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+
+ "management/internal/db/model/view"
+ "management/internal/pkg/convertor"
+ "management/internal/pkg/tpl"
+)
+
+func (h *projectHandler) Dashboard(w http.ResponseWriter, r *http.Request) {
+ switch r.Method {
+ case http.MethodGet:
+ pp, _ := h.biz.ProjectV1().ListHtml(r.Context())
+ h.render.HTML(w, r, "project/dashboard.tmpl", map[string]any{
+ "Projects": pp,
+ })
+ case http.MethodPost:
+ ctx := r.Context()
+ t := r.PostFormValue("type")
+ if t == "project" {
+ var projectIncome float64
+ var projectExpense float64
+ projectID := convertor.ConvertInt[int64](r.PostFormValue("projectID"), 0)
+ if projectID == 0 {
+ si, _ := h.biz.IncomeV1().Sum(ctx)
+ projectIncome = convertor.NumericToFloat64(si)
+ se, _ := h.biz.ExpenseV1().Sum(ctx)
+ projectExpense = convertor.NumericToFloat64(se)
+ } else {
+ pi, _ := h.biz.IncomeV1().SumByProjectID(ctx, projectID)
+ projectIncome = convertor.NumericToFloat64(pi)
+ pe, _ := h.biz.ExpenseV1().SumByProjectID(ctx, projectID)
+ projectExpense = convertor.NumericToFloat64(pe)
+ }
+
+ projectProfit := projectIncome - projectExpense
+ var projectProfitRate float64 = 0
+ if projectExpense > 0 {
+ projectProfitRate = projectProfit / projectExpense
+ }
+
+ res := &view.DashboardProject{
+ ProjectIncome: projectIncome,
+ ProjectExpense: projectExpense,
+ ProjectProfit: projectProfit,
+ ProjectProfitRate: fmt.Sprintf("%0.2f%%", projectProfitRate*100),
+ IncomeExpenseEcharts: h.incomeExpenseEcharts(ctx, projectID),
+ IncomeEcharts: h.incomeEcharts(ctx, projectID),
+ ExpenseEcharts: h.expenseEcharts(ctx, projectID),
+ }
+ h.render.JSON(w, tpl.Response{Success: true, Message: "ok", Data: res})
+ return
+ } else if t == "budget" {
+ }
+ h.render.JSONERR(w, "failed to valid type")
+ default:
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ }
+}
+
+func (h *projectHandler) incomeExpenseEcharts(ctx context.Context, projectId int64) view.EchartsOption {
+ var name []string
+ var income []float64
+ var expense []float64
+
+ if projectId == 0 {
+ rows, err := h.biz.ProjectV1().Statistics(ctx)
+ if err != nil || len(rows) == 0 {
+ return view.EchartsOption{}
+ }
+
+ for _, row := range rows {
+ name = append(name, row.Name)
+ income = append(income, convertor.NumericToFloat64(row.Income))
+ expense = append(expense, convertor.NumericToFloat64(row.Expense))
+ }
+ } else {
+ row, err := h.biz.ProjectV1().StatisticsItem(ctx, projectId)
+ if err != nil || row == nil {
+ return view.EchartsOption{}
+ }
+ name = append(name, row.Name)
+ income = append(income, convertor.NumericToFloat64(row.Income))
+ expense = append(expense, convertor.NumericToFloat64(row.Expense))
+ }
+
+ return view.EchartsOption{
+ Title: view.Title{
+ Text: "项目收支情况",
+ Left: "center",
+ Top: 2,
+ FontSize: 15,
+ TextStyle: view.TextStyle{
+ Color: "#666666",
+ FontWeight: "normal",
+ },
+ },
+ Color: []string{"#fed46b", "#2194ff"},
+ ToolTip: view.ToolTip{
+ Trigger: "axis",
+ AxisPointer: view.AxisPointer{
+ Type: "shadow",
+ },
+ },
+ Grid: view.Grid{
+ Left: "3%",
+ Right: "4%",
+ Bottom: "10%",
+ ContainLabel: true,
+ },
+ Legend: view.Legend{
+ Left: "center",
+ Top: "bottom",
+ Data: []string{"支出金额", "收入金额"},
+ },
+ XAxis: []view.XAxis{
+ {
+ Type: "category",
+ Data: name,
+ AxisTick: view.AxisTick{
+ AlignWithLabel: true,
+ },
+ },
+ },
+ YAxis: []view.YAxis{
+ {
+ Type: "value",
+ Name: "单位:元",
+ },
+ },
+ BarMaxWidth: "30",
+ Label: view.Label{
+ Show: true,
+ Position: "top",
+ },
+ Series: []view.Series{
+ {
+ Name: "支出金额",
+ Type: "bar",
+ Data: expense,
+ ItemStyle: view.ItemStyle{
+ Normal: view.Normal{
+ Color: "#f89588",
+ },
+ },
+ },
+ {
+ Name: "收入金额",
+ Type: "bar",
+ Data: income,
+ ItemStyle: view.ItemStyle{
+ Normal: view.Normal{
+ Color: "#76da91",
+ },
+ },
+ },
+ },
+ }
+}
+
+func (h *projectHandler) incomeEcharts(ctx context.Context, projectId int64) view.EchartsOption {
+ var name []string
+ data := []view.DataItem{}
+
+ if projectId == 0 {
+ rows, err := h.biz.IncomeV1().Statistics(ctx)
+ if err != nil || len(rows) == 0 {
+ return view.EchartsOption{}
+ }
+
+ for _, row := range rows {
+ name = append(name, row.IncomeTypeName)
+ data = append(data, view.DataItem{
+ Name: row.IncomeTypeName,
+ Value: convertor.NumericToFloat64(row.TotalAmount),
+ })
+ }
+ } else {
+ rows, err := h.biz.IncomeV1().StatisticsByProjectID(ctx, projectId)
+ if err != nil || len(rows) == 0 {
+ return view.EchartsOption{}
+ }
+
+ for _, row := range rows {
+ name = append(name, row.IncomeTypeName)
+ data = append(data, view.DataItem{
+ Name: row.IncomeTypeName,
+ Value: convertor.NumericToFloat64(row.TotalAmount),
+ })
+ }
+ }
+
+ return view.EchartsOption{
+ Title: view.Title{
+ Text: "收入分布",
+ Left: "center",
+ Orient: "vertical",
+ FontSize: 15,
+ TextStyle: view.TextStyle{
+ Color: "#666666",
+ FontWeight: "normal",
+ },
+ },
+ ToolTip: view.ToolTip{
+ Trigger: "item",
+ },
+ Legend: view.Legend{
+ Left: "center",
+ Top: "bottom",
+ Data: name,
+ },
+ Color: []string{"#63b2ee", "#76da91", "#f8cb7f", "#f89588", "#7cd6cf", "#9192ab", "#7898e1", "#efa666", "#eddd86", "#9987ce", "#63b2ee", "#76da91"},
+ Series: []view.Series{
+ {
+ Type: "pie",
+ Radius: "50%",
+ Data: data,
+ Label: view.Label{
+ Show: true,
+ TextStyle: view.TextStyle{
+ Color: "#666666",
+ },
+ Normal: view.LableNormal{
+ Formatter: "{c} ({d}%)",
+ TextStyle: view.TextStyle{
+ Color: "#666666",
+ FontWeight: "normal",
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func (h *projectHandler) expenseEcharts(ctx context.Context, projectId int64) view.EchartsOption {
+ var name []string
+ data := []view.DataItem{}
+
+ if projectId == 0 {
+ rows, err := h.biz.ExpenseV1().Statistics(ctx)
+ if err != nil || len(rows) == 0 {
+ return view.EchartsOption{}
+ }
+
+ for _, row := range rows {
+ name = append(name, row.ExpensesTypeName)
+ data = append(data, view.DataItem{
+ Name: row.ExpensesTypeName,
+ Value: convertor.NumericToFloat64(row.TotalAmount),
+ })
+ }
+ } else {
+ rows, err := h.biz.ExpenseV1().StatisticsByProjectID(ctx, projectId)
+ if err != nil || len(rows) == 0 {
+ return view.EchartsOption{}
+ }
+
+ for _, row := range rows {
+ name = append(name, row.ExpensesTypeName)
+ data = append(data, view.DataItem{
+ Name: row.ExpensesTypeName,
+ Value: convertor.NumericToFloat64(row.TotalAmount),
+ })
+ }
+ }
+
+ return view.EchartsOption{
+ Title: view.Title{
+ Text: "支出分布",
+ Left: "center",
+ Orient: "vertical",
+ FontSize: 15,
+ TextStyle: view.TextStyle{
+ Color: "#666666",
+ FontWeight: "normal",
+ },
+ },
+ ToolTip: view.ToolTip{
+ Trigger: "item",
+ },
+ Legend: view.Legend{
+ Left: "center",
+ Top: "bottom",
+ Data: name,
+ },
+ Color: []string{"#63b2ee", "#76da91", "#f8cb7f", "#f89588", "#7cd6cf", "#9192ab", "#7898e1", "#efa666", "#eddd86", "#9987ce", "#63b2ee", "#76da91"},
+ Series: []view.Series{
+ {
+ Type: "pie",
+ Radius: "50%",
+ Data: data,
+ Label: view.Label{
+ Show: true,
+ TextStyle: view.TextStyle{
+ Color: "#666666",
+ },
+ Normal: view.LableNormal{
+ Formatter: "{c} ({d}%)",
+ TextStyle: view.TextStyle{
+ Color: "#666666",
+ FontWeight: "normal",
+ },
+ },
+ },
+ },
+ },
+ }
+
+ // return view.EchartsOption{
+ // Title: view.Title{
+ // Text: "支出分布",
+ // Left: "center",
+ // Top: 2,
+ // FontSize: 15,
+ // TextStyle: view.TextStyle{
+ // Color: "#666666",
+ // FontWeight: "normal",
+ // },
+ // },
+ // Color: []string{"#fed46b", "#2194ff"},
+ // ToolTip: view.ToolTip{
+ // Trigger: "axis",
+ // AxisPointer: view.AxisPointer{
+ // Type: "shadow",
+ // },
+ // },
+ // Grid: view.Grid{
+ // Left: "3%",
+ // Right: "4%",
+ // Bottom: "10%",
+ // ContainLabel: true,
+ // },
+ // XAxis: []view.XAxis{
+ // {
+ // Type: "category",
+ // Data: name,
+ // AxisTick: view.AxisTick{
+ // AlignWithLabel: true,
+ // },
+ // },
+ // },
+ // YAxis: []view.YAxis{
+ // {
+ // Type: "value",
+ // Name: "单位:元",
+ // },
+ // },
+ // BarMaxWidth: "30",
+ // Label: view.Label{
+ // Show: true,
+ // Position: "top",
+ // },
+ // Series: []view.Series{
+ // {
+ // Type: "bar",
+ // Data: expense,
+ // ItemStyle: view.ItemStyle{
+ // Normal: view.Normal{
+ // Color: "#f89588",
+ // },
+ // },
+ // },
+ // },
+ // }
+}
diff --git a/internal/erpserver/handler/project/project.go b/internal/erpserver/handler/project/project.go
index 18cbbc9..2ab8ee8 100644
--- a/internal/erpserver/handler/project/project.go
+++ b/internal/erpserver/handler/project/project.go
@@ -10,43 +10,45 @@ import (
formDto "management/internal/db/model/form"
db "management/internal/db/sqlc"
"management/internal/erpserver/biz"
- "management/internal/global"
- "management/internal/global/html"
- "management/internal/middleware/manage/auth"
"management/internal/pkg/convertor"
+ "management/internal/pkg/middleware"
"management/internal/pkg/snowflake"
- "management/internal/router/manage/util"
- "management/internal/tpl"
+ "management/internal/pkg/tpl"
+ "management/internal/pkg/tpl/html"
"github.com/jackc/pgx/v5/pgtype"
)
-type PorjectHandler interface {
+type ProjectHandler interface {
List(w http.ResponseWriter, r *http.Request)
Add(w http.ResponseWriter, r *http.Request)
Edit(w http.ResponseWriter, r *http.Request)
Save(w http.ResponseWriter, r *http.Request)
+ Data(w http.ResponseWriter, r *http.Request)
+ Dashboard(w http.ResponseWriter, r *http.Request)
}
-type porjectHandler struct {
+type projectHandler struct {
render tpl.Renderer
biz biz.IBiz
+ mi middleware.IMiddleware
}
-var _ PorjectHandler = (*porjectHandler)(nil)
+var _ ProjectHandler = (*projectHandler)(nil)
-func NewPorjectHandler(render tpl.Renderer, biz biz.IBiz) *porjectHandler {
- return &porjectHandler{
+func NewProjectHandler(render tpl.Renderer, biz biz.IBiz, mi middleware.IMiddleware) *projectHandler {
+ return &projectHandler{
render: render,
biz: biz,
+ mi: mi,
}
}
-func (h *porjectHandler) List(w http.ResponseWriter, r *http.Request) {
+func (h *projectHandler) List(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
h.render.HTML(w, r, "project/list.tmpl", map[string]any{
- "Statuses": html.NewSelectControls(global.ProjectStatuses, 0),
+ "Statuses": html.NewSelectControls(html.ProjectStatuses, "0"),
})
case http.MethodPost:
title := strings.TrimSpace(r.PostFormValue("title"))
@@ -64,7 +66,7 @@ func (h *porjectHandler) List(w http.ResponseWriter, r *http.Request) {
PageID: convertor.ConvertInt[int32](r.PostFormValue("page"), 1),
PageSize: convertor.ConvertInt[int32](r.PostFormValue("rows"), 10),
}
- arg.TimeBegin, arg.TimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
+ arg.TimeBegin, arg.TimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
res, total, err := h.biz.ProjectV1().List(r.Context(), arg)
if err != nil {
h.render.JSONERR(w, err.Error())
@@ -83,8 +85,8 @@ func (h *porjectHandler) List(w http.ResponseWriter, r *http.Request) {
}
}
-func (h *porjectHandler) Add(w http.ResponseWriter, r *http.Request) {
- authUser := auth.AuthUser(r.Context())
+func (h *projectHandler) Add(w http.ResponseWriter, r *http.Request) {
+ authUser := h.mi.AuthUser(r.Context())
h.render.HTML(w, r, "project/edit.tmpl", map[string]any{
"Item": &formDto.ProjectForm{
ApplyUserID: authUser.ID,
@@ -92,11 +94,11 @@ func (h *porjectHandler) Add(w http.ResponseWriter, r *http.Request) {
ProjectFileItems: []*formDto.ProjectFileItemForm{},
},
},
- "Statuses": html.NewSelectControls(global.ProjectStatuses, 0),
+ "Statuses": html.NewSelectControls(html.ProjectStatuses, "0"),
})
}
-func (h *porjectHandler) Edit(w http.ResponseWriter, r *http.Request) {
+func (h *projectHandler) Edit(w http.ResponseWriter, r *http.Request) {
form := &formDto.ProjectForm{}
id := convertor.ConvertInt[int64](r.URL.Query().Get("id"), 0)
if id > 0 {
@@ -109,7 +111,7 @@ func (h *porjectHandler) Edit(w http.ResponseWriter, r *http.Request) {
}
form = form.ToForm(po, pfs)
if form.ApplyUserID == 0 {
- authUser := auth.AuthUser(ctx)
+ authUser := h.mi.AuthUser(ctx)
form.ApplyUserID = authUser.ID
}
// if c, err := db.Engine.GetCustomer(ctx, po.CustomerID); err == nil {
@@ -125,19 +127,19 @@ func (h *porjectHandler) Edit(w http.ResponseWriter, r *http.Request) {
}
h.render.HTML(w, r, "project/edit.tmpl", map[string]any{
"Item": form,
- "Statuses": html.NewSelectControls(global.ProjectStatuses, form.Status),
+ "Statuses": html.NewSelectControls(html.ProjectStatuses, strconv.Itoa(int(form.Status))),
})
}
-func (h *porjectHandler) Save(w http.ResponseWriter, r *http.Request) {
+func (h *projectHandler) Save(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
form, err := validForm(r)
if err != nil {
- tpl.JSONERR(w, err.Error())
+ h.render.JSONERR(w, err.Error())
return
}
- authUser := auth.AuthUser(ctx)
+ authUser := h.mi.AuthUser(ctx)
if form.ID > 0 {
p := &db.UpdateProjectParams{
ID: form.ID,
@@ -199,10 +201,10 @@ func (h *porjectHandler) Save(w http.ResponseWriter, r *http.Request) {
}
err := h.biz.ProjectV1().Update(ctx, p, cpfs)
if err != nil {
- tpl.JSONERR(w, err.Error())
+ h.render.JSONERR(w, err.Error())
return
}
- tpl.JSONOK(w, "更新成功")
+ h.render.JSONOK(w, "更新成功")
} else {
p := &db.CreateProjectParams{
ID: snowflake.GetId(),
@@ -231,13 +233,30 @@ func (h *porjectHandler) Save(w http.ResponseWriter, r *http.Request) {
}
err := h.biz.ProjectV1().Create(ctx, p, cpfs)
if err != nil {
- tpl.JSONERR(w, err.Error())
+ h.render.JSONERR(w, err.Error())
return
}
- tpl.JSONOK(w, "添加成功")
+ h.render.JSONOK(w, "添加成功")
}
}
+func (h *projectHandler) Data(w http.ResponseWriter, r *http.Request) {
+ vars := r.URL.Query()
+ t := vars.Get("type")
+ if t == "xmselect" {
+ res, err := h.biz.ProjectV1().XmSelect(r.Context())
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+
+ h.render.JSON(w, res)
+ return
+ }
+
+ h.render.JSON(w, nil)
+}
+
func validForm(r *http.Request) (formDto.ProjectForm, error) {
var err error
form := formDto.ProjectForm{}
diff --git a/internal/erpserver/handler/system/audit.go b/internal/erpserver/handler/system/audit.go
index 095588e..d7196a5 100644
--- a/internal/erpserver/handler/system/audit.go
+++ b/internal/erpserver/handler/system/audit.go
@@ -7,7 +7,6 @@ import (
"management/internal/erpserver/biz"
"management/internal/pkg/convertor"
"management/internal/pkg/tpl"
- "management/internal/router/manage/util"
)
type AuditHandler interface {
@@ -34,7 +33,7 @@ func (h *auditHandler) List(w http.ResponseWriter, r *http.Request) {
h.render.HTML(w, r, "audit_log/list.tmpl", nil)
case http.MethodPost:
var q dto.SearchDto
- q.SearchTimeBegin, q.SearchTimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
+ q.SearchTimeBegin, q.SearchTimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
q.SearchName = r.PostFormValue("name")
q.SearchEmail = r.PostFormValue("email")
q.Page = convertor.ConvertInt(r.PostFormValue("page"), 1)
diff --git a/internal/erpserver/handler/system/category.go b/internal/erpserver/handler/system/category.go
index 4839788..ab363c2 100644
--- a/internal/erpserver/handler/system/category.go
+++ b/internal/erpserver/handler/system/category.go
@@ -214,6 +214,15 @@ func (h *categoryHandler) Data(w http.ResponseWriter, r *http.Request) {
return
}
+ h.render.JSON(w, res)
+ return
+ } else if t == "xmselect" {
+ res, err := h.biz.SystemV1().CategoryBiz().XmSelect(ctx, vars.Get("letter"))
+ if err != nil {
+ h.render.JSONERR(w, err.Error())
+ return
+ }
+
h.render.JSON(w, res)
return
}
diff --git a/internal/erpserver/handler/system/config.go b/internal/erpserver/handler/system/config.go
index 3575cf1..65c2e48 100644
--- a/internal/erpserver/handler/system/config.go
+++ b/internal/erpserver/handler/system/config.go
@@ -8,8 +8,8 @@ import (
"management/internal/db/model/dto"
db "management/internal/db/sqlc"
"management/internal/erpserver/biz"
- "management/internal/global/pearadmin"
"management/internal/pkg/convertor"
+ "management/internal/pkg/know/pearadmin"
"management/internal/pkg/redis"
"management/internal/pkg/tpl"
)
diff --git a/internal/erpserver/handler/system/login_log.go b/internal/erpserver/handler/system/login_log.go
index 9e5e5fd..e592e28 100644
--- a/internal/erpserver/handler/system/login_log.go
+++ b/internal/erpserver/handler/system/login_log.go
@@ -7,7 +7,6 @@ import (
"management/internal/erpserver/biz"
"management/internal/pkg/convertor"
"management/internal/pkg/tpl"
- "management/internal/router/manage/util"
)
type LoginLogHandler interface {
@@ -34,7 +33,7 @@ func (h *loginLogHandler) List(w http.ResponseWriter, r *http.Request) {
h.render.HTML(w, r, "login_log/list.tmpl", nil)
case http.MethodPost:
var q dto.SearchDto
- q.SearchTimeBegin, q.SearchTimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
+ q.SearchTimeBegin, q.SearchTimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
q.SearchName = r.PostFormValue("name")
q.SearchEmail = r.PostFormValue("email")
q.Page = convertor.ConvertInt(r.PostFormValue("page"), 1)
diff --git a/internal/erpserver/handler/system/menu.go b/internal/erpserver/handler/system/menu.go
index d267ad8..9622b49 100644
--- a/internal/erpserver/handler/system/menu.go
+++ b/internal/erpserver/handler/system/menu.go
@@ -10,8 +10,8 @@ import (
"management/internal/db/model/dto"
db "management/internal/db/sqlc"
"management/internal/erpserver/biz"
- "management/internal/global/know"
"management/internal/pkg/convertor"
+ "management/internal/pkg/know"
"management/internal/pkg/session"
"management/internal/pkg/tpl"
diff --git a/internal/erpserver/handler/system/role.go b/internal/erpserver/handler/system/role.go
index 53a8765..93da345 100644
--- a/internal/erpserver/handler/system/role.go
+++ b/internal/erpserver/handler/system/role.go
@@ -11,7 +11,6 @@ import (
"management/internal/erpserver/biz"
"management/internal/pkg/convertor"
"management/internal/pkg/tpl"
- "management/internal/router/manage/util"
)
type RoleHandler interface {
@@ -302,7 +301,7 @@ func (h *roleHandler) SetMenu(w http.ResponseWriter, r *http.Request) {
var menuList []*db.SysMenu
for _, v := range menuArr {
- menuID := util.ConvertInt(v, 0)
+ menuID := convertor.ConvertInt(v, 0)
if menuID > 0 {
menu, err := h.biz.SystemV1().MenuBiz().Get(ctx, int32(menuID))
if err != nil {
diff --git a/internal/erpserver/handler/system/system.go b/internal/erpserver/handler/system/system.go
index bc45d33..9459de0 100644
--- a/internal/erpserver/handler/system/system.go
+++ b/internal/erpserver/handler/system/system.go
@@ -4,6 +4,7 @@ import (
"net/http"
"management/internal/erpserver/biz"
+ "management/internal/pkg/middleware"
"management/internal/pkg/redis"
"management/internal/pkg/session"
"management/internal/pkg/tpl"
@@ -26,16 +27,18 @@ type systemHandler struct {
redis redis.IRedis
session session.ISession
biz biz.IBiz
+ mi middleware.IMiddleware
}
var _ SystemHandler = (*systemHandler)(nil)
-func NewSystemHandler(render tpl.Renderer, redis redis.IRedis, session session.ISession, biz biz.IBiz) *systemHandler {
+func NewSystemHandler(render tpl.Renderer, redis redis.IRedis, session session.ISession, biz biz.IBiz, mi middleware.IMiddleware) *systemHandler {
return &systemHandler{
render: render,
redis: redis,
session: session,
biz: biz,
+ mi: mi,
}
}
@@ -44,7 +47,7 @@ func (h *systemHandler) Home(w http.ResponseWriter, r *http.Request) {
}
func (h *systemHandler) UserHandler() UserHandler {
- return NewUserHandler(h.render, h.session, h.biz)
+ return NewUserHandler(h.render, h.session, h.biz, h.mi)
}
func (h *systemHandler) MenuHandler() MenuHandler {
diff --git a/internal/erpserver/handler/system/user.go b/internal/erpserver/handler/system/user.go
index f7c26da..84066fc 100644
--- a/internal/erpserver/handler/system/user.go
+++ b/internal/erpserver/handler/system/user.go
@@ -10,16 +10,14 @@ import (
db "management/internal/db/sqlc"
"management/internal/erpserver/biz"
"management/internal/erpserver/model/req"
- "management/internal/global"
- "management/internal/global/html"
- "management/internal/global/know"
- "management/internal/middleware/manage/auth"
"management/internal/pkg/convertor"
"management/internal/pkg/crypto"
+ "management/internal/pkg/know"
+ "management/internal/pkg/middleware"
"management/internal/pkg/rand"
"management/internal/pkg/session"
"management/internal/pkg/tpl"
- "management/internal/router/manage/util"
+ "management/internal/pkg/tpl/html"
"github.com/google/uuid"
"github.com/zhang2092/browser"
@@ -46,16 +44,18 @@ type userHandler struct {
render tpl.Renderer
session session.ISession
biz biz.IBiz
+ mi middleware.IMiddleware
}
// 确保 userHandler 实现了 UserHandler 接口.
var _ UserHandler = (*userHandler)(nil)
-func NewUserHandler(render tpl.Renderer, session session.ISession, biz biz.IBiz) *userHandler {
+func NewUserHandler(render tpl.Renderer, session session.ISession, biz biz.IBiz, mi middleware.IMiddleware) *userHandler {
return &userHandler{
render: render,
session: session,
biz: biz,
+ mi: mi,
}
}
@@ -200,16 +200,16 @@ func (h *userHandler) List(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
h.render.HTML(w, r, "user/list.tmpl", map[string]any{
- "Statuses": html.NewSelectControls(global.SearchStatuses, 0),
+ "Statuses": html.NewSelectControls(html.SearchStatuses, "0"),
})
case http.MethodPost:
var q dto.SearchDto
- q.SearchStatus = util.ConvertInt(r.PostFormValue("status"), 9999)
+ q.SearchStatus = convertor.ConvertInt(r.PostFormValue("status"), 9999)
q.SearchName = r.PostFormValue("name")
q.SearchEmail = r.PostFormValue("email")
q.SearchID = convertor.ConvertInt[int64](r.PostFormValue("id"), 0)
- q.Page = util.ConvertInt(r.PostFormValue("page"), 1)
- q.Rows = util.ConvertInt(r.PostFormValue("rows"), 10)
+ q.Page = convertor.ConvertInt(r.PostFormValue("page"), 1)
+ q.Rows = convertor.ConvertInt(r.PostFormValue("rows"), 10)
res, count, err := h.biz.SystemV1().UserBiz().List(r.Context(), q)
if err != nil {
h.render.JSONERR(w, err.Error())
@@ -230,7 +230,7 @@ func (h *userHandler) List(w http.ResponseWriter, r *http.Request) {
func (h *userHandler) Profile(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
- user := auth.AuthUser(ctx)
+ user := h.mi.AuthUser(ctx)
vm, _ := h.biz.SystemV1().UserBiz().Get(ctx, user.ID)
h.render.HTML(w, r, "user/profile.tmpl", map[string]any{
"Item": vm,
diff --git a/internal/erpserver/http.go b/internal/erpserver/http.go
index 955ce58..3336ded 100644
--- a/internal/erpserver/http.go
+++ b/internal/erpserver/http.go
@@ -144,14 +144,45 @@ func NewRouter(handler handler.IHandler, mw mw.IMiddleware) *chi.Mux {
// 项目
r.Route("/project", func(r chi.Router) {
r.Use(mw.Authorize)
- r.Get("/list", handler.PorjectHandler().List)
- r.Post("/list", handler.PorjectHandler().List)
- r.Get("/add", handler.PorjectHandler().Add)
- r.Get("/edit", handler.PorjectHandler().Edit)
- r.Post("/save", handler.PorjectHandler().Save)
- // r.Post("/xmselect", projecthandler.XmSelect)
- // r.Get("/dashboard", projecthandler.Dashboard)
- // r.Post("/dashboard", projecthandler.PostDashboard)
+ r.Get("/list", handler.ProjectHandler().List)
+ r.Post("/list", handler.ProjectHandler().List)
+ r.Get("/add", handler.ProjectHandler().Add)
+ r.Get("/edit", handler.ProjectHandler().Edit)
+ r.Post("/save", handler.ProjectHandler().Save)
+ r.Post("/data", handler.ProjectHandler().Data)
+ r.Get("/dashboard", handler.ProjectHandler().Dashboard)
+ r.Post("/dashboard", handler.ProjectHandler().Dashboard)
+ })
+
+ // 项目预算
+ r.Route("/budget", func(r chi.Router) {
+ r.Use(mw.Authorize)
+ r.Get("/list", handler.BudgetHandler().List)
+ r.Post("/list", handler.BudgetHandler().List)
+ r.Get("/add", handler.BudgetHandler().Add)
+ r.Get("/edit", handler.BudgetHandler().Edit)
+ r.Post("/save", handler.BudgetHandler().Save)
+ r.Post("/data", handler.BudgetHandler().Data)
+ })
+
+ // 回款单
+ r.Route("/income", func(r chi.Router) {
+ r.Use(mw.Authorize)
+ r.Get("/list", handler.IncomeHandler().List)
+ r.Post("/list", handler.IncomeHandler().List)
+ r.Get("/add", handler.IncomeHandler().Add)
+ r.Get("/edit", handler.IncomeHandler().Edit)
+ r.Post("/save", handler.IncomeHandler().Save)
+ })
+
+ // 费用报销单
+ r.Route("/expense", func(r chi.Router) {
+ r.Use(mw.Authorize)
+ r.Get("/list", handler.ExpenseHandler().List)
+ r.Post("/list", handler.ExpenseHandler().List)
+ r.Get("/add", handler.ExpenseHandler().Add)
+ r.Get("/edit", handler.ExpenseHandler().Edit)
+ r.Post("/save", handler.ExpenseHandler().Save)
})
})
diff --git a/internal/global/auth/auth.go b/internal/global/auth/auth.go
deleted file mode 100644
index 6fb323d..0000000
--- a/internal/global/auth/auth.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package auth
-
-const (
- CookieName = "authorize"
- StoreName = "authorize_user"
-)
diff --git a/internal/global/html/select.go b/internal/global/html/select.go
deleted file mode 100644
index ea7c033..0000000
--- a/internal/global/html/select.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package html
-
-import (
- db "management/internal/db/sqlc"
- "management/internal/global"
-)
-
-func NewSelectControls(data []*global.DataDict16, value int16) []*global.DataDict16 {
- for _, item := range data {
- item.Selected = false
- if item.Value == value {
- item.Selected = true
- }
- }
- return data
-}
-
-func NewSelectStringControls(data []*global.DataDict, value string) []*global.DataDict {
- for _, item := range data {
- item.Selected = false
- if item.Value == value {
- item.Selected = true
- }
- }
- return data
-}
-
-const (
- Course int32 = 5
- Grade int32 = 6
- Published int32 = 7
- Class int32 = 8
- Answer int32 = 80
- Getted int32 = 10
- DocumentType int32 = 45
- ValueType int32 = 54
- Period int32 = 61
-)
-
-func NewSelectPaperControls(data []*db.Category, value int16, Link int32) []*global.DataDict16 {
- var res []*global.DataDict16
- for _, item := range data {
- if item.ParentID == Link {
- tmp := global.DataDict16{
- Name: item.Name,
- Value: int16(item.ID),
- Selected: false,
- }
- if int16(item.ID) == value {
- tmp.Selected = true
- }
- res = append(res, &tmp)
- }
- }
- return res
-}
diff --git a/internal/global/keys/key.go b/internal/global/keys/key.go
deleted file mode 100644
index dfe4db0..0000000
--- a/internal/global/keys/key.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package keys
-
-import (
- "context"
- "fmt"
-)
-
-var (
- // pear admin 配置
- PearAdmin = "m:pearjson"
-
- // 所有类别
- AllCategories = "m:category:all"
- // 所有类别 简单信息
- AllCategorySimple = "m:categorysimple:all"
- // 类别列表 根据 父id 获取
- ListCategoriesByParentID = "m:category:parent_id:%d"
-
- // 所有部门
- AllDepartments = "m:department:all"
-
- // 所有菜单
- AllMenus = "m:menus:all"
- // 递归菜单
- RecursiveMenus = "m:rec_menus:%d"
- // 根据用户ID获取菜单
- AdminMenus = "m:admin_menus:%d"
- // 登陆用户的菜单
- OwnerMenus = "m:owner_menus:%d"
- // 登陆用户的菜单
- OwnerMenusMap = "m:owner_menus_map:%d"
-
- // 所有角色
- AllRoles = "m:role:all"
-)
-
-func GetManageKey(ctx context.Context, key string, arg ...any) string {
- key = fmt.Sprintf(key, arg...)
- return key
-}
diff --git a/internal/global/know/know.go b/internal/global/know/know.go
deleted file mode 100644
index 1d30ebd..0000000
--- a/internal/global/know/know.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package know
-
-const (
- CustomerCategory = "customer_category"
- CustomerSource = "customer_source"
-
- BudgetCategory = "budget_category"
-
- IncomeBank = "income_bank"
- IncomeCategory = "income_category"
-
- ExpenseCategory = "expense_category"
-
- CookieName = "authorize"
- StoreName = "authorize_user"
-)
-
-var (
- // pear admin 配置
- PearAdmin = "m:pearjson"
-
- // 所有类别
- AllCategories = "m:category:all"
- // 所有类别 简单信息
- AllCategorySimple = "m:categorysimple:all"
- // 类别列表 根据 父id 获取
- ListCategoriesByParentID = "m:category:parent_id:%d"
-
- // 所有部门
- AllDepartments = "m:department:all"
-
- // 所有菜单
- AllMenus = "m:menus:all"
- // 递归菜单
- RecursiveMenus = "m:rec_menus:%d"
- // 根据用户ID获取菜单
- AdminMenus = "m:admin_menus:%d"
- // 登陆用户的菜单
- OwnerMenus = "m:owner_menus:%d"
- // 登陆用户的菜单
- OwnerMenusMap = "m:owner_menus_map:%d"
-
- // 所有角色
- AllRoles = "m:role:all"
-)
diff --git a/internal/global/model.go b/internal/global/model.go
deleted file mode 100644
index 2fdf359..0000000
--- a/internal/global/model.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package global
-
-type DataDict16 struct {
- Name string
- Value int16
- Selected bool
-}
-
-type DataDict struct {
- Name string
- Value string
- Selected bool
-}
diff --git a/internal/global/status.go b/internal/global/status.go
deleted file mode 100644
index 522ccd9..0000000
--- a/internal/global/status.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package global
-
-var SearchStatuses = []*DataDict16{
- {Name: "状态", Value: 9999, Selected: false},
- {Name: "正常", Value: 0, Selected: false},
- {Name: "删除", Value: -1, Selected: false},
-}
-
-var Statuses = []*DataDict16{
- {Name: "正常", Value: 0, Selected: false},
- {Name: "删除", Value: -1, Selected: false},
-}
-
-var ProjectStatuses = []*DataDict16{
- {Name: "未开始", Value: 0, Selected: false},
- {Name: "进行中", Value: 10, Selected: false},
- {Name: "已结项", Value: 20, Selected: false},
- {Name: "已删除", Value: -1, Selected: false},
-}
diff --git a/internal/global/util.go b/internal/global/util.go
deleted file mode 100644
index d93e5da..0000000
--- a/internal/global/util.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package global
-
-func FindItemByID(data []*DataDict16, id int16) (*DataDict16, bool) {
- for _, item := range data {
- if item.Value == id {
- return item, true
- }
- }
- return nil, false
-}
-
-func FindItemByName(data []*DataDict16, name string) (*DataDict16, bool) {
- for _, item := range data {
- if item.Name == name {
- return item, true
- }
- }
- return nil, false
-}
diff --git a/internal/middleware/manage/audit/audit.go b/internal/middleware/manage/audit/audit.go
deleted file mode 100644
index 5c1bc2a..0000000
--- a/internal/middleware/manage/audit/audit.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package audit
-
-import (
- "context"
- "net/http"
- "strconv"
- "strings"
- "time"
-
- db "management/internal/db/sqlc"
- "management/internal/middleware/manage/auth"
- systemservice "management/internal/service/system"
-
- "github.com/zhang2092/browser"
-)
-
-func Audit(next http.Handler) http.Handler {
- fn := func(w http.ResponseWriter, r *http.Request) {
- start := time.Now()
- defer func(res http.ResponseWriter, req *http.Request) {
- // 记录审计日志
- go writeLog(req, start)
- }(w, r)
- next.ServeHTTP(w, r)
- }
-
- return http.HandlerFunc(fn)
-}
-
-func writeLog(req *http.Request, start time.Time) {
- end := time.Now()
- duration := end.Sub(start)
- var params string
- method := req.Method
- if method == "GET" {
- params = req.URL.Query().Encode()
- } else if method == "POST" {
- contentType := req.Header.Get("Content-Type")
- if strings.Contains(contentType, "application/json") {
- body := make([]byte, req.ContentLength)
- req.Body.Read(body)
- params = string(body)
- } else if strings.Contains(contentType, "application/x-www-form-urlencoded") {
- params = req.Form.Encode()
- }
- }
-
- ctx := req.Context()
- au := auth.AuthUser(ctx)
- arg := &db.CreateSysAuditLogParams{
- CreatedAt: time.Now(),
- Email: au.Email,
- Username: au.Username,
- UserUuid: au.Uuid,
- StartAt: start,
- EndAt: end,
- Duration: strconv.FormatInt(duration.Milliseconds(), 10),
- Url: req.URL.RequestURI(),
- Method: method,
- Parameters: params,
- RefererUrl: req.Header.Get("Referer"),
- Ip: req.RemoteAddr,
- Remark: "",
- }
- br, err := browser.NewBrowser(req.Header.Get("User-Agent"))
- if err == nil {
- arg.Os = br.Platform().Name()
- arg.Browser = br.Name()
- }
-
- c, cancel := context.WithTimeout(context.Background(), time.Second*3)
- defer cancel()
-
- _ = systemservice.CreateSysAuditLog(c, arg)
-}
diff --git a/internal/middleware/manage/auth/authorize.go b/internal/middleware/manage/auth/authorize.go
deleted file mode 100644
index 964a90c..0000000
--- a/internal/middleware/manage/auth/authorize.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package auth
-
-import (
- "context"
- "net/http"
-
- "management/internal/db/model/dto"
- systemservice "management/internal/service/system"
-)
-
-var defaultMenus = map[string]bool{
- "/home.html": true,
- "/system/menus": true,
- "/upload/img": true,
- "/upload/file": true,
- "/upload/mutilfile": true,
- "/pear.json": true,
-}
-
-func Authorize(next http.Handler) http.Handler {
- fn := func(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- user, ok := isLogin(ctx)
- if !ok {
- http.Redirect(w, r, "/", http.StatusFound)
- return
- }
-
- if user == nil {
- http.Error(w, "user not found", http.StatusUnauthorized)
- return
- }
-
- // 登陆成功 判断权限
-
- // 默认权限判断
- path := r.URL.Path
- if b, ok := defaultMenus[path]; ok && b {
- next.ServeHTTP(w, r)
- return
- }
-
- menus, err := systemservice.MapOwnerMenuByRoleID(ctx, user.RoleID)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- if _, ok := menus[path]; ok {
- next.ServeHTTP(w, r)
- return
- }
-
- http.Error(w, "Unauthorized", http.StatusUnauthorized)
- }
-
- return http.HandlerFunc(fn)
-}
-
-func isLogin(ctx context.Context) (*dto.AuthorizeUser, bool) {
- // if exists := session.Exists(ctx, auth.StoreName); exists {
- // b := session.GetBytes(ctx, auth.StoreName)
- // var user dto.AuthorizeUser
- // if err := json.Unmarshal(b, &user); err != nil {
- // return nil, false
- // }
- // return &user, true
- // }
-
- return nil, false
-}
-
-func AuthUser(ctx context.Context) dto.AuthorizeUser {
- var user dto.AuthorizeUser
- // if exists := session.Exists(ctx, auth.StoreName); exists {
- // b := session.GetBytes(ctx, auth.StoreName)
- // _ = json.Unmarshal(b, &user)
- // }
- return user
-}
diff --git a/internal/middleware/manage/nosurf/nocsrf.go b/internal/middleware/manage/nosurf/nocsrf.go
deleted file mode 100644
index 7dd6c10..0000000
--- a/internal/middleware/manage/nosurf/nocsrf.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package nosurf
-
-import (
- "net/http"
-
- "github.com/justinas/nosurf"
-)
-
-func NoSurf(next http.Handler) http.Handler {
- return nosurf.New(next)
-}
diff --git a/internal/middleware/manage/session/session.go b/internal/middleware/manage/session/session.go
deleted file mode 100644
index 2af6705..0000000
--- a/internal/middleware/manage/session/session.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package session
-
-import (
- "net/http"
-
- "management/internal/pkg/session"
-)
-
-func LoadSession(session session.ISession, next http.Handler) http.Handler {
- return session.LoadAndSave(next)
-}
diff --git a/internal/pkg/know/know.go b/internal/pkg/know/know.go
index 1d30ebd..aa2b4ee 100644
--- a/internal/pkg/know/know.go
+++ b/internal/pkg/know/know.go
@@ -1,5 +1,10 @@
package know
+import (
+ "context"
+ "fmt"
+)
+
const (
CustomerCategory = "customer_category"
CustomerSource = "customer_source"
@@ -43,3 +48,8 @@ var (
// 所有角色
AllRoles = "m:role:all"
)
+
+func GetManageKey(ctx context.Context, key string, arg ...any) string {
+ key = fmt.Sprintf(key, arg...)
+ return key
+}
diff --git a/internal/global/pearadmin/pearadmin.go b/internal/pkg/know/pearadmin/pearadmin.go
similarity index 100%
rename from internal/global/pearadmin/pearadmin.go
rename to internal/pkg/know/pearadmin/pearadmin.go
diff --git a/internal/pkg/middleware/authorize.go b/internal/pkg/middleware/authorize.go
index 6fd1a5e..c78e988 100644
--- a/internal/pkg/middleware/authorize.go
+++ b/internal/pkg/middleware/authorize.go
@@ -6,7 +6,7 @@ import (
"net/http"
"management/internal/db/model/dto"
- "management/internal/global/auth"
+ "management/internal/pkg/know"
)
var defaultMenus = map[string]bool{
@@ -59,8 +59,8 @@ func (m *middleware) Authorize(next http.Handler) http.Handler {
}
func (m *middleware) isLogin(ctx context.Context) (*dto.AuthorizeUser, bool) {
- if exists := m.session.Exists(ctx, auth.StoreName); exists {
- b := m.session.GetBytes(ctx, auth.StoreName)
+ if exists := m.session.Exists(ctx, know.StoreName); exists {
+ b := m.session.GetBytes(ctx, know.StoreName)
var user dto.AuthorizeUser
if err := json.Unmarshal(b, &user); err != nil {
return nil, false
@@ -73,8 +73,8 @@ func (m *middleware) isLogin(ctx context.Context) (*dto.AuthorizeUser, bool) {
func (m *middleware) AuthUser(ctx context.Context) dto.AuthorizeUser {
var user dto.AuthorizeUser
- if exists := m.session.Exists(ctx, auth.StoreName); exists {
- b := m.session.GetBytes(ctx, auth.StoreName)
+ if exists := m.session.Exists(ctx, know.StoreName); exists {
+ b := m.session.GetBytes(ctx, know.StoreName)
_ = json.Unmarshal(b, &user)
}
return user
diff --git a/internal/pkg/middleware/middleware.go b/internal/pkg/middleware/middleware.go
index bc51e37..3172bdd 100644
--- a/internal/pkg/middleware/middleware.go
+++ b/internal/pkg/middleware/middleware.go
@@ -1,8 +1,10 @@
package middleware
import (
+ "context"
"net/http"
+ "management/internal/db/model/dto"
systemv1 "management/internal/erpserver/biz/v1/system"
"management/internal/pkg/session"
)
@@ -12,6 +14,7 @@ type IMiddleware interface {
NoSurf(next http.Handler) http.Handler
LoadSession(next http.Handler) http.Handler
Authorize(next http.Handler) http.Handler
+ AuthUser(ctx context.Context) dto.AuthorizeUser
}
type middleware struct {
diff --git a/internal/pkg/tpl/util.go b/internal/pkg/tpl/util.go
index 1c7be4c..d98e6a3 100644
--- a/internal/pkg/tpl/util.go
+++ b/internal/pkg/tpl/util.go
@@ -13,7 +13,7 @@ import (
"strings"
"management/internal/db/model/dto"
- "management/internal/global/auth"
+ "management/internal/pkg/know"
templates "management/web/templates/manage"
"github.com/justinas/nosurf"
@@ -25,11 +25,11 @@ func (r *render) setDefaultData(req *http.Request, data map[string]any) map[stri
}
ctx := req.Context()
- isAuth := r.session.Exists(ctx, auth.StoreName)
+ isAuth := r.session.Exists(ctx, know.StoreName)
data["IsAuthenticated"] = isAuth
if isAuth {
var authUser dto.AuthorizeUser
- u := r.session.GetBytes(ctx, auth.StoreName)
+ u := r.session.GetBytes(ctx, know.StoreName)
_ = json.Unmarshal(u, &authUser)
data["AuthorizeMenus"] = r.getCurrentPathBtns(ctx, authUser.RoleID, req.URL.Path)
diff --git a/internal/router/manage/budget/budget.go b/internal/router/manage/budget/budget.go
deleted file mode 100644
index e87c448..0000000
--- a/internal/router/manage/budget/budget.go
+++ /dev/null
@@ -1,267 +0,0 @@
-package budget
-
-import (
- "errors"
- "net/http"
- "strconv"
- "strings"
- "time"
-
- "management/internal/db/model/dto"
- "management/internal/db/model/form"
- db "management/internal/db/sqlc"
- "management/internal/global"
- "management/internal/global/html"
- "management/internal/global/know"
- "management/internal/middleware/manage/auth"
- "management/internal/pkg/convertor"
- "management/internal/router/manage/util"
- categoryservice "management/internal/service/category"
- projectservice "management/internal/service/project"
- "management/internal/tpl"
-
- "github.com/jackc/pgx/v5/pgtype"
-)
-
-func List(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- pp := projectservice.AllProjects(ctx)
- cc, _ := categoryservice.GetParentCategorySelectLetter(ctx, know.BudgetCategory)
- tpl.HTML(w, r, "budget/list.tmpl", map[string]any{
- "Statuses": html.NewSelectControls(global.Statuses, 0),
- "Projects": html.NewSelectStringControls(pp, "0"),
- "Categories": html.NewSelectStringControls(cc, "0"),
- })
-}
-
-func PostList(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- project := convertor.ConvertInt[int64](r.PostFormValue("project"), 9999)
- if project == 0 {
- project = 9999
- }
-
- budgetType := convertor.ConvertInt[int32](r.PostFormValue("budgetType"), 9999)
- if budgetType == 0 {
- budgetType = 9999
- }
-
- category := convertor.ConvertInt[int32](r.PostFormValue("category"), 9999)
- if category == 0 {
- category = 9999
- }
-
- title := strings.TrimSpace(r.PostFormValue("title"))
- var search string
- if len(title) > 0 {
- search = "%" + title + "%"
- if strings.HasSuffix(title, ":") {
- search = title[:len(title)-1] + "%"
- }
- }
- arg := &db.ListBudgetConditionParam{
- ProjectID: project,
- BudgetType: budgetType,
- Category: category,
- IsTitle: len(search) > 0,
- Title: search,
- Status: util.ConvertInt16(r.PostFormValue("status"), 9999),
- PageID: util.ConvertInt32(r.PostFormValue("page"), 1),
- PageSize: util.ConvertInt32(r.PostFormValue("rows"), 10),
- }
- arg.TimeBegin, arg.TimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
- res, total, err := db.Engine.ListBudgetCondition(ctx, arg)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: total,
- Data: res,
- }
- tpl.JSON(w, data)
-}
-
-func Add(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "budget/edit.tmpl", map[string]any{
- "Item": &form.BudgetForm{
- BudgetType: 1,
- },
- "Statuses": html.NewSelectControls(global.Statuses, 0),
- })
-}
-
-func Edit(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- id := util.ConvertInt[int64](vars.Get("id"), 0)
- budget := &form.BudgetForm{}
- ctx := r.Context()
- if id > 0 {
- if cus, err := db.Engine.GetBudget(ctx, id); err == nil {
- budget = budget.ToForm(cus)
- if u, err := db.Engine.GetSysUser(ctx, cus.CreatedUserID); err == nil {
- budget.CreatedName = u.Username
- }
- if u, err := db.Engine.GetSysUser(ctx, cus.UpdatedUserID); err == nil {
- budget.UpdatedName = u.Username
- }
- }
- }
- tpl.HTML(w, r, "budget/edit.tmpl", map[string]any{
- "Item": budget,
- "Statuses": html.NewSelectControls(global.Statuses, budget.Status),
- })
-}
-
-func Save(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- data, err := validForm(r)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
-
- authUser := auth.AuthUser(ctx)
- if data.ID > 0 {
- arg := &db.UpdateBudgetParams{
- ID: data.ID,
- ProjectID: pgtype.Int8{
- Int64: data.ProjectID,
- Valid: true,
- },
- Name: pgtype.Text{
- String: data.Name,
- Valid: true,
- },
- BudgetType: pgtype.Int4{
- Int32: data.BudgetType,
- Valid: true,
- },
- Category: pgtype.Int4{
- Int32: data.Category,
- Valid: true,
- },
- StartAt: pgtype.Timestamptz{
- Time: data.StartAt,
- Valid: true,
- },
- EndAt: pgtype.Timestamptz{
- Time: data.EndAt,
- Valid: true,
- },
- Amount: data.AmountF,
- UsedAmount: data.UsedAmountF,
- RemainingAmount: data.RemainingAmountF,
- Remark: pgtype.Text{
- String: data.Remark,
- Valid: true,
- },
- Status: pgtype.Int2{
- Int16: data.Status,
- Valid: true,
- },
- UpdatedUserID: pgtype.Int4{
- Int32: authUser.ID,
- Valid: true,
- },
- }
- _, err := db.Engine.UpdateBudget(ctx, arg)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
- tpl.JSONOK(w, "更新成功")
- } else {
- arg := &db.CreateBudgetParams{
- ProjectID: data.ProjectID,
- Name: data.Name,
- BudgetType: data.BudgetType,
- Category: data.Category,
- StartAt: data.StartAt,
- EndAt: data.EndAt,
- Amount: data.AmountF,
- UsedAmount: data.UsedAmountF,
- RemainingAmount: data.RemainingAmountF,
- Remark: data.Remark,
- CreatedUserID: authUser.ID,
- }
- _, err := db.Engine.CreateBudget(ctx, arg)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
- tpl.JSONOK(w, "添加成功")
- }
-}
-
-func XmSelect(w http.ResponseWriter, r *http.Request) {
- projectID := convertor.ConvertInt[int64](r.URL.Query().Get("projectId"), 0)
- all, err := db.Engine.ListBudgets(r.Context(), projectID)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
-
- res := []*dto.XmSelectStrDto{}
- for _, v := range all {
- res = append(res, &dto.XmSelectStrDto{
- Name: v.Name,
- Value: strconv.FormatInt(v.ID, 10),
- })
- }
- tpl.JSON(w, res)
-}
-
-func validForm(r *http.Request) (form.BudgetForm, error) {
- var err error
- data := form.BudgetForm{}
-
- data.ID = convertor.ConvertInt[int64](r.PostFormValue("ID"), 0)
- data.ProjectID, err = strconv.ParseInt(r.PostFormValue("ProjectID"), 10, 64)
- if err != nil || data.ProjectID == 0 {
- return data, errors.New("项目不能为空")
- }
-
- data.Name = r.PostFormValue("Name")
- if len(data.Name) == 0 {
- return data, errors.New("预算名称不能为空")
- }
-
- budgetType, err := strconv.ParseInt(r.PostFormValue("BudgetType"), 10, 32)
- if err != nil {
- return data, errors.New("预算类型不能为空")
- }
- data.BudgetType = int32(budgetType)
-
- category, err := strconv.ParseInt(r.PostFormValue("Category"), 10, 32)
- if err != nil {
- return data, errors.New("预算类别不能为空")
- }
- data.Category = int32(category)
-
- data.StartAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("StartAt"), time.Local)
- if err != nil {
- return data, errors.New("开始时间格式错误")
- }
- data.EndAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("EndAt"), time.Local)
- if err != nil {
- return data, errors.New("结束时间格式错误")
- }
-
- if err := data.AmountF.Scan(r.PostFormValue("Amount")); err != nil {
- return data, errors.New("预算金额格式错误")
- }
- if err := data.UsedAmountF.Scan(r.PostFormValue("UsedAmount")); err != nil {
- return data, errors.New("已支付金额格式错误")
- }
- if err := data.RemainingAmountF.Scan(r.PostFormValue("RemainingAmount")); err != nil {
- return data, errors.New("剩余金额格式错误")
- }
-
- data.Remark = r.PostFormValue("Remark")
- data.Status = convertor.ConvertInt[int16](r.PostFormValue("Status"), 9999)
- return data, nil
-}
diff --git a/internal/router/manage/cache/cache.go b/internal/router/manage/cache/cache.go
deleted file mode 100644
index f26918b..0000000
--- a/internal/router/manage/cache/cache.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package cache
-
-import (
- "net/http"
- "sort"
- "strings"
-
- "management/internal/pkg/redis"
- "management/internal/router/manage/util"
- "management/internal/tpl"
-)
-
-func List(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "cache/list.tmpl", nil)
-}
-
-type Key struct {
- Name string `json:"name"`
-}
-
-func PostList(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- keyword := strings.TrimSpace(r.PostFormValue("title"))
- pageID := util.ConvertInt(r.PostFormValue("page"), 1)
- pageSize := util.ConvertInt(r.PostFormValue("rows"), 10)
- if len(keyword) == 0 {
- keyword = "*"
- } else {
- keyword = keyword + "*"
- }
-
- result, count, err := redis.ListKeys(ctx, keyword, pageID, pageSize)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- sort.Sort(sort.StringSlice(result))
-
- var res []Key
- for _, key := range result {
- res = append(res, Key{
- Name: key,
- })
- }
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: int64(count),
- Data: res,
- }
- tpl.JSON(w, data)
-}
-
-func Refresh(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- name := strings.TrimSpace(r.PostFormValue("name"))
- err := redis.Del(ctx, name)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- tpl.JSON(w, tpl.Response{Success: true, Message: "刷新成功"})
-}
diff --git a/internal/router/manage/category/category.go b/internal/router/manage/category/category.go
deleted file mode 100644
index 9c5576b..0000000
--- a/internal/router/manage/category/category.go
+++ /dev/null
@@ -1,247 +0,0 @@
-package category
-
-import (
- "fmt"
- "net/http"
- "strconv"
- "strings"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
- "management/internal/pkg/convertor"
- "management/internal/router/manage/util"
- categoryservice "management/internal/service/category"
- "management/internal/tpl"
-
- "github.com/google/uuid"
- "github.com/jackc/pgx/v5/pgtype"
-)
-
-type CategoryHandler struct{}
-
-func NewCategoryHandler() *CategoryHandler {
- return &CategoryHandler{}
-}
-
-func (h *CategoryHandler) List(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "category/list.tmpl", nil)
-}
-
-func (h *CategoryHandler) PostList(w http.ResponseWriter, r *http.Request) {
- var q dto.SearchDto
- q.SearchStatus = convertor.ConvertInt(r.PostFormValue("status"), 9999)
- q.SearchParentID = convertor.ConvertInt(r.PostFormValue("parentId"), 0)
- q.SearchName = r.PostFormValue("name")
- q.SearchID = convertor.ConvertInt[int64](r.PostFormValue("id"), 0)
- q.Page = convertor.ConvertInt(r.PostFormValue("page"), 1)
- q.Rows = convertor.ConvertInt(r.PostFormValue("rows"), 10)
- res, count, err := categoryservice.ListCategoriesCondition(r.Context(), q)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: count,
- Data: res,
- }
- tpl.JSON(w, data)
-}
-
-func (h *CategoryHandler) Add(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "category/edit.tmpl", map[string]any{
- "Item": &db.Category{Sort: 6666},
- })
-}
-
-func (h *CategoryHandler) AddChildren(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- parentID := util.DefaultInt(vars, "parentID", 0)
- vm := &db.Category{ParentID: int32(parentID), Sort: 6666}
- tpl.HTML(w, r, "category/edit.tmpl", map[string]any{
- "Item": vm,
- })
-}
-
-func (h *CategoryHandler) Edit(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- id := util.DefaultInt(vars, "id", 0)
- vm := &db.Category{Sort: 6666}
- if id > 0 {
- ctx := r.Context()
- vm, _ = db.Engine.GetCategory(ctx, int32(id))
- }
- tpl.HTML(w, r, "category/edit.tmpl", map[string]any{
- "Item": vm,
- })
-}
-
-func (h *CategoryHandler) Save(w http.ResponseWriter, r *http.Request) {
- id := util.ConvertInt(r.PostFormValue("ID"), 0)
- parentID := util.ConvertInt(r.PostFormValue("ParentID"), 0)
- name := r.PostFormValue("Name")
- icon := r.PostFormValue("File")
- if len(icon) > 0 && !strings.HasPrefix(icon, "/") {
- icon = "/" + icon
- }
- description := r.PostFormValue("Description")
- letter := r.PostFormValue("Letter")
- if len(letter) == 0 {
- letter = uuid.New().String()
- }
- sort := util.ConvertInt(r.PostFormValue("Sort"), 6666)
- status := util.ConvertInt(r.PostFormValue("Status"), 9999)
-
- ctx := r.Context()
- var parent *db.Category
- if parentID > 0 {
- var err error
- parent, err = db.Engine.GetCategory(ctx, int32(parentID))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: "父级节点错误"})
- return
- }
- }
-
- path := fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID)
- path = strings.ReplaceAll(path, ",,", ",")
- if id == 0 {
- arg := &db.CreateCategoryParams{
- Name: name,
- Icon: icon,
- Description: description,
- Letter: letter,
- ParentID: int32(parentID),
- ParentPath: path,
- Status: int16(status),
- Sort: int32(sort),
- }
- _, err := db.Engine.CreateCategory(ctx, arg)
- if err != nil {
- if db.IsUniqueViolation(err) {
- tpl.JSON(w, tpl.Response{Success: false, Message: "名称已存在"})
- return
- }
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "添加成功"})
- } else {
- arg := &db.UpdateCategoryParams{
- ID: int32(id),
- Name: pgtype.Text{
- String: name,
- Valid: true,
- },
- Icon: pgtype.Text{
- String: icon,
- Valid: len(icon) > 0,
- },
- Description: pgtype.Text{
- String: description,
- Valid: len(description) > 0,
- },
- Letter: pgtype.Text{
- String: letter,
- Valid: len(letter) > 0,
- },
- ParentID: pgtype.Int4{
- Int32: int32(parentID),
- Valid: true,
- },
- ParentPath: pgtype.Text{
- String: path,
- Valid: true,
- },
- Sort: pgtype.Int4{
- Int32: int32(sort),
- Valid: true,
- },
- Status: pgtype.Int2{
- Int16: int16(status),
- Valid: true,
- },
- }
- _, err := db.Engine.UpdateCategory(ctx, arg)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "更新成功"})
- }
-}
-
-func (h *CategoryHandler) DTree(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- vars := r.URL.Query()
- id := util.DefaultInt(vars, "id", 0)
- res, err := categoryservice.DTreeCategory(ctx, int32(id))
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- rsp := tpl.ResponseDtree{
- Status: tpl.ResponseDtreeStatus{
- Code: 200,
- Message: "OK",
- },
- Data: res,
- }
- tpl.JSON(w, rsp)
-}
-
-func (h *CategoryHandler) XmSelect(w http.ResponseWriter, r *http.Request) {
- letter := r.URL.Query().Get("letter")
- ctx := r.Context()
- if len(letter) > 0 {
- all, err := categoryservice.ListByLetter(ctx, letter)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
-
- var res []*dto.XmSelectStrDto
- for _, v := range all {
- res = append(res, &dto.XmSelectStrDto{
- Name: v.Name,
- Value: strconv.FormatInt(int64(v.ID), 10),
- })
- }
- tpl.JSON(w, res)
- return
- }
-
- res, err := categoryservice.XmSelectCategory(ctx, 0)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
-
- tpl.JSON(w, res)
-}
-
-func (h *CategoryHandler) Refresh(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- err := categoryservice.RefreshCategory(ctx)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "刷新成功"})
-}
-
-func (h *CategoryHandler) RebuildParentPath(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- err := db.Engine.CategoryRebuildPath(ctx)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "重建成功"})
-}
diff --git a/internal/router/manage/common/captcha.go b/internal/router/manage/common/captcha.go
deleted file mode 100644
index 061771a..0000000
--- a/internal/router/manage/common/captcha.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package common
-
-import (
- "net/http"
-
- "management/internal/config"
- captchaservice "management/internal/service/captcha"
- "management/internal/tpl"
-)
-
-type CaptchaResponse struct {
- CaptchaID string `json:"captcha_id"`
- PicPath string `json:"pic_path"`
- CaptchaLength int `json:"captcha_length"`
- OpenCaptcha int `json:"open_captcha"`
-}
-
-func Captcha(w http.ResponseWriter, r *http.Request) {
- keyLong := config.File.Captcha.KeyLong
- oc := config.File.Captcha.OpenCaptcha
- id, b64s, _, err := captchaservice.Generate(config.File.Captcha.ImgHeight, config.File.Captcha.ImgWidth, keyLong, 0.7, 80)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: "获取验证码失败"})
- return
- }
-
- rsp := CaptchaResponse{
- CaptchaID: id,
- PicPath: b64s,
- CaptchaLength: keyLong,
- OpenCaptcha: oc,
- }
- tpl.JSON(w, tpl.Response{Success: true, Message: "ok", Data: rsp})
-}
diff --git a/internal/router/manage/common/upload.go b/internal/router/manage/common/upload.go
deleted file mode 100644
index e693c7c..0000000
--- a/internal/router/manage/common/upload.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package common
-
-import (
- "io"
- "mime/multipart"
- "net/http"
-
- "management/internal/tpl"
-
- fileutil "management/internal/pkg/file"
-)
-
-const maxImageSize = 100 << 20 // 100 MB
-
-func UploadImg(w http.ResponseWriter, r *http.Request) {
- defer r.Body.Close()
-
- _, fh, err := r.FormFile("files")
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- path, err := fileutil.UploadFile(fh, fileutil.IMG)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "ok", Data: path})
-}
-
-func UploadFile(w http.ResponseWriter, r *http.Request) {
- defer r.Body.Close()
-
- _, fh, err := r.FormFile("files")
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- path, err := fileutil.UploadFile(fh, fileutil.ALL)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "ok", Data: path})
-}
-
-type UploadFileRes struct {
- Name string `json:"name"`
- Path string `json:"path"`
-}
-
-func UploadMutilFiles(w http.ResponseWriter, r *http.Request) {
- defer func(Body io.ReadCloser) {
- _ = Body.Close()
- }(r.Body)
-
- err := r.ParseMultipartForm(int64(maxImageSize))
- if err != nil {
- return
- }
- files := r.MultipartForm.File["files"]
-
- var res []UploadFileRes
- c := make(chan UploadFileRes, 2)
- defer close(c)
-
- for i, file := range files {
- go func(item *multipart.FileHeader, key int) {
- ufr := UploadFileRes{Name: item.Filename}
-
- filePath, err := fileutil.UploadFile(item, fileutil.ALL)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
-
- ufr.Path = filePath
- c <- ufr
- }(file, i)
- }
-
- for {
- v, ok := <-c
- if ok {
- res = append(res, v)
- }
- if len(files) == len(res) {
- break
- }
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "ok", Data: res})
-}
diff --git a/internal/router/manage/customer/customer.go b/internal/router/manage/customer/customer.go
deleted file mode 100644
index fb6975a..0000000
--- a/internal/router/manage/customer/customer.go
+++ /dev/null
@@ -1,202 +0,0 @@
-package customer
-
-import (
- "net/http"
- "strconv"
- "strings"
-
- "management/internal/db/model/dto"
- "management/internal/db/model/form"
- db "management/internal/db/sqlc"
- "management/internal/global"
- "management/internal/global/html"
- "management/internal/global/know"
- "management/internal/middleware/manage/auth"
- "management/internal/pkg/snowflake"
- "management/internal/router/manage/util"
- categoryservice "management/internal/service/category"
- "management/internal/tpl"
-
- "github.com/jackc/pgx/v5/pgtype"
-)
-
-func List(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- cc, _ := categoryservice.GetParentCategorySelectLetter(ctx, know.CustomerCategory)
- ss, _ := categoryservice.GetParentCategorySelectLetter(ctx, know.CustomerSource)
- tpl.HTML(w, r, "customer/list.tmpl", map[string]any{
- "Statuses": html.NewSelectControls(global.Statuses, 0),
- "Categories": html.NewSelectStringControls(cc, "0"),
- "Sources": html.NewSelectStringControls(ss, "0"),
- })
-}
-
-func PostList(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- category := util.ConvertInt32(r.PostFormValue("category"), 9999)
- if category == 0 {
- category = 9999
- }
- source := util.ConvertInt32(r.PostFormValue("source"), 9999)
- if source == 0 {
- source = 9999
- }
-
- title := strings.TrimSpace(r.PostFormValue("title"))
- var search string
- if len(title) > 0 {
- search = "%" + title + "%"
- if strings.HasSuffix(title, ":") {
- search = title[:len(title)-1] + "%"
- }
- }
- arg := &db.ListCustomerConditionParam{
- IsTitle: len(search) > 0,
- Title: search,
- Status: util.ConvertInt16(r.PostFormValue("status"), 9999),
- Category: category,
- Source: source,
- PageID: util.ConvertInt32(r.PostFormValue("page"), 1),
- PageSize: util.ConvertInt32(r.PostFormValue("rows"), 10),
- }
- arg.TimeBegin, arg.TimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
- res, total, err := db.Engine.ListCustomerCondition(ctx, arg)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: total,
- Data: res,
- }
- tpl.JSON(w, data)
-}
-
-func Add(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- cc, _ := categoryservice.GetParentCategorySelectLetter(ctx, know.CustomerCategory)
- ss, _ := categoryservice.GetParentCategorySelectLetter(ctx, know.CustomerSource)
- tpl.HTML(w, r, "customer/edit.tmpl", map[string]any{
- "Item": &form.CustomerForm{},
- "Statuses": html.NewSelectControls(global.Statuses, 0),
- "Categories": html.NewSelectStringControls(cc, "0"),
- "Sources": html.NewSelectStringControls(ss, "0"),
- })
-}
-
-func Edit(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- id := util.ConvertInt[int64](vars.Get("id"), 0)
- customer := &form.CustomerForm{}
- ctx := r.Context()
- if id > 0 {
- if cus, err := db.Engine.GetCustomer(ctx, id); err == nil {
- customer = customer.ToForm(cus)
- if u, err := db.Engine.GetSysUser(ctx, cus.CreatedBy); err == nil {
- customer.CreatedBy = u.Username
- }
- if u, err := db.Engine.GetSysUser(ctx, cus.UpdatedBy); err == nil {
- customer.UpdatedBy = u.Username
- }
- }
- }
- cc, _ := categoryservice.GetParentCategorySelectLetter(ctx, know.CustomerCategory)
- ss, _ := categoryservice.GetParentCategorySelectLetter(ctx, know.CustomerSource)
- tpl.HTML(w, r, "customer/edit.tmpl", map[string]any{
- "Item": customer,
- "Statuses": html.NewSelectControls(global.Statuses, customer.Status),
- "Categories": html.NewSelectStringControls(cc, strconv.Itoa(int(customer.Category))),
- "Sources": html.NewSelectStringControls(ss, strconv.Itoa(int(customer.Source))),
- })
-}
-
-func Save(w http.ResponseWriter, r *http.Request) {
- data := &form.CustomerForm{}
- if err := form.BindForm(r, data); err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
-
- ctx := r.Context()
- authUser := auth.AuthUser(ctx)
- if data.ID > 0 {
- arg := &db.UpdateCustomerParams{
- ID: data.ID,
- Name: pgtype.Text{
- String: data.Name,
- Valid: true,
- },
- Category: pgtype.Int4{
- Int32: data.Category,
- Valid: true,
- },
- Source: pgtype.Int4{
- Int32: data.Source,
- Valid: true,
- },
- Address: pgtype.Text{
- String: data.Address,
- Valid: true,
- },
- ContactName: pgtype.Text{
- String: data.ContactName,
- Valid: true,
- },
- ContactPhone: pgtype.Text{
- String: data.ContactPhone,
- Valid: true,
- },
- Status: pgtype.Int2{
- Int16: data.Status,
- Valid: true,
- },
- UpdatedBy: pgtype.Int4{
- Int32: authUser.ID,
- Valid: true,
- },
- }
- _, err := db.Engine.UpdateCustomer(ctx, arg)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
- tpl.JSONOK(w, "更新成功")
- } else {
- arg := &db.CreateCustomerParams{
- ID: snowflake.GetId(),
- Name: data.Name,
- Category: data.Category,
- Source: data.Source,
- Address: data.Address,
- ContactName: data.ContactName,
- ContactPhone: data.ContactPhone,
- CreatedBy: authUser.ID,
- }
- _, err := db.Engine.CreateCustomer(ctx, arg)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
- tpl.JSONOK(w, "添加成功")
- }
-}
-
-func XmSelect(w http.ResponseWriter, r *http.Request) {
- all, err := db.Engine.AllCustomers(r.Context())
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
-
- var res []*dto.XmSelectStrDto
- for _, v := range all {
- res = append(res, &dto.XmSelectStrDto{
- Name: v.Name,
- Value: strconv.FormatInt(v.ID, 10),
- })
- }
- tpl.JSON(w, res)
-}
diff --git a/internal/router/manage/expense/expense.go b/internal/router/manage/expense/expense.go
deleted file mode 100644
index 391abcf..0000000
--- a/internal/router/manage/expense/expense.go
+++ /dev/null
@@ -1,208 +0,0 @@
-package expense
-
-import (
- "errors"
- "net/http"
- "strconv"
- "strings"
- "time"
-
- "management/internal/db/model/form"
- db "management/internal/db/sqlc"
- "management/internal/global"
- "management/internal/global/html"
- "management/internal/global/know"
- "management/internal/middleware/manage/auth"
- "management/internal/pkg/convertor"
- "management/internal/router/manage/util"
- categoryservice "management/internal/service/category"
- projectservice "management/internal/service/project"
- "management/internal/tpl"
-
- "github.com/jackc/pgx/v5/pgtype"
-)
-
-func List(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- pp := projectservice.AllProjects(ctx)
- cc, _ := categoryservice.GetParentCategorySelectLetter(ctx, know.ExpenseCategory)
- tpl.HTML(w, r, "expense/list.tmpl", map[string]any{
- "Statuses": html.NewSelectControls(global.Statuses, 0),
- "Projects": html.NewSelectStringControls(pp, "0"),
- "Categories": html.NewSelectStringControls(cc, "0"),
- })
-}
-
-func PostList(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- project := convertor.ConvertInt[int64](r.PostFormValue("project"), 9999)
- if project == 0 {
- project = 9999
- }
- budget := convertor.ConvertInt[int64](r.PostFormValue("budget"), 9999)
- if budget == 0 {
- budget = 9999
- }
- category := convertor.ConvertInt[int32](r.PostFormValue("category"), 9999)
- if category == 0 {
- category = 9999
- }
-
- title := strings.TrimSpace(r.PostFormValue("title"))
- var search string
- if len(title) > 0 {
- search = "%" + title + "%"
- if strings.HasSuffix(title, ":") {
- search = title[:len(title)-1] + "%"
- }
- }
- arg := &db.ListExpenseConditionParam{
- ProjectID: project,
- BudgetID: budget,
- ExpenseType: category,
- IsTitle: len(search) > 0,
- Title: search,
- Status: util.ConvertInt16(r.PostFormValue("status"), 9999),
- PageID: util.ConvertInt32(r.PostFormValue("page"), 1),
- PageSize: util.ConvertInt32(r.PostFormValue("rows"), 10),
- }
- arg.TimeBegin, arg.TimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
- res, total, err := db.Engine.ListExpenseCondition(ctx, arg)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: total,
- Data: res,
- }
- tpl.JSON(w, data)
-}
-
-func Add(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "expense/edit.tmpl", map[string]any{
- "Item": &form.ExpenseForm{},
- "Statuses": html.NewSelectControls(global.Statuses, 0),
- })
-}
-
-func Edit(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- id := util.ConvertInt[int64](vars.Get("id"), 0)
- expense := &form.ExpenseForm{}
- ctx := r.Context()
- if id > 0 {
- if cus, err := db.Engine.GetExpense(ctx, id); err == nil {
- expense = expense.ToForm(cus)
- if u, err := db.Engine.GetSysUser(ctx, cus.CreatedUserID); err == nil {
- expense.CreatedName = u.Username
- }
- if u, err := db.Engine.GetSysUser(ctx, cus.UpdatedUserID); err == nil {
- expense.UpdatedName = u.Username
- }
- }
- }
- tpl.HTML(w, r, "expense/edit.tmpl", map[string]any{
- "Item": expense,
- "Statuses": html.NewSelectControls(global.Statuses, expense.Status),
- })
-}
-
-func Save(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- data, err := validForm(r)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
-
- authUser := auth.AuthUser(ctx)
- if data.ID > 0 {
- arg := &db.UpdateExpenseParams{
- ID: data.ID,
- ProjectID: pgtype.Int8{
- Int64: data.ProjectID,
- Valid: true,
- },
- BudgetID: pgtype.Int8{
- Int64: data.BudgetID,
- Valid: true,
- },
- Amount: data.AmountF,
- ExpensesAt: pgtype.Timestamptz{
- Time: data.ExpensesAt,
- Valid: true,
- },
- ExpensesType: pgtype.Int4{
- Int32: data.ExpensesType,
- Valid: true,
- },
- Remark: pgtype.Text{
- String: data.Remark,
- Valid: true,
- },
- Status: pgtype.Int2{
- Int16: data.Status,
- Valid: true,
- },
- UpdatedUserID: pgtype.Int4{
- Int32: authUser.ID,
- Valid: true,
- },
- }
- _, err := db.Engine.UpdateExpense(ctx, arg)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
- tpl.JSONOK(w, "更新成功")
- } else {
- arg := &db.CreateExpenseParams{
- ProjectID: data.ProjectID,
- BudgetID: data.BudgetID,
- Amount: data.AmountF,
- ExpensesAt: data.ExpensesAt,
- ExpensesType: data.ExpensesType,
- Remark: data.Remark,
- Status: data.Status,
- CreatedUserID: authUser.ID,
- }
- _, err := db.Engine.CreateExpense(ctx, arg)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
- tpl.JSONOK(w, "添加成功")
- }
-}
-
-func validForm(r *http.Request) (form.ExpenseForm, error) {
- var err error
- data := form.ExpenseForm{}
-
- data.ID = convertor.ConvertInt[int64](r.PostFormValue("ID"), 0)
- data.ProjectID, err = strconv.ParseInt(r.PostFormValue("ProjectID"), 10, 64)
- if err != nil || data.ProjectID == 0 {
- return data, errors.New("项目不能为空")
- }
- data.BudgetID, err = strconv.ParseInt(r.PostFormValue("BudgetID"), 10, 64)
-
- if err := data.AmountF.Scan(r.PostFormValue("Amount")); err != nil {
- return data, errors.New("报销金额格式错误")
- }
- data.ExpensesAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("ExpensesAt"), time.Local)
- if err != nil {
- return data, errors.New("报销时间格式错误")
- }
- expensesType, err := strconv.ParseInt(r.PostFormValue("ExpensesType"), 10, 64)
- if err != nil || expensesType == 0 {
- return data, errors.New("报销类型不能为空")
- }
- data.ExpensesType = int32(expensesType)
-
- data.Status = convertor.ConvertInt[int16](r.PostFormValue("Status"), 9999)
- return data, nil
-}
diff --git a/internal/router/manage/home.go b/internal/router/manage/home.go
deleted file mode 100644
index bc09b86..0000000
--- a/internal/router/manage/home.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package router
-
-import (
- "net/http"
-
- "management/internal/tpl"
-)
-
-func Home(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "home/home.tmpl", nil)
-}
diff --git a/internal/router/manage/income/income.go b/internal/router/manage/income/income.go
deleted file mode 100644
index e073654..0000000
--- a/internal/router/manage/income/income.go
+++ /dev/null
@@ -1,226 +0,0 @@
-package expense
-
-import (
- "errors"
- "net/http"
- "strconv"
- "strings"
- "time"
-
- "management/internal/db/model/form"
- db "management/internal/db/sqlc"
- "management/internal/global"
- "management/internal/global/html"
- "management/internal/global/know"
- "management/internal/middleware/manage/auth"
- "management/internal/pkg/convertor"
- "management/internal/router/manage/util"
- categoryservice "management/internal/service/category"
- projectservice "management/internal/service/project"
- "management/internal/tpl"
-
- "github.com/jackc/pgx/v5/pgtype"
-)
-
-func List(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- pp := projectservice.AllProjects(ctx)
- cc, _ := categoryservice.GetParentCategorySelectLetter(ctx, know.IncomeCategory)
- tpl.HTML(w, r, "income/list.tmpl", map[string]any{
- "Statuses": html.NewSelectControls(global.Statuses, 0),
- "Projects": html.NewSelectStringControls(pp, "0"),
- "Categories": html.NewSelectStringControls(cc, "0"),
- })
-}
-
-func PostList(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- project := convertor.ConvertInt[int64](r.PostFormValue("project"), 9999)
- if project == 0 {
- project = 9999
- }
- budget := convertor.ConvertInt[int64](r.PostFormValue("budget"), 9999)
- if budget == 0 {
- budget = 9999
- }
- category := convertor.ConvertInt[int32](r.PostFormValue("category"), 9999)
- if category == 0 {
- category = 9999
- }
-
- title := strings.TrimSpace(r.PostFormValue("title"))
- var search string
- if len(title) > 0 {
- search = "%" + title + "%"
- if strings.HasSuffix(title, ":") {
- search = title[:len(title)-1] + "%"
- }
- }
- arg := &db.ListIncomeConditionParam{
- ProjectID: project,
- BudgetID: budget,
- IncomeType: category,
- IsTitle: len(search) > 0,
- Title: search,
- Status: util.ConvertInt16(r.PostFormValue("status"), 9999),
- PageID: util.ConvertInt32(r.PostFormValue("page"), 1),
- PageSize: util.ConvertInt32(r.PostFormValue("rows"), 10),
- }
- arg.TimeBegin, arg.TimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
- res, total, err := db.Engine.ListIncomeCondition(ctx, arg)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: total,
- Data: res,
- }
- tpl.JSON(w, data)
-}
-
-func Add(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "income/edit.tmpl", map[string]any{
- "Item": &form.IncomeForm{},
- "Statuses": html.NewSelectControls(global.Statuses, 0),
- })
-}
-
-func Edit(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- id := util.ConvertInt[int64](vars.Get("id"), 0)
- income := &form.IncomeForm{}
- ctx := r.Context()
- if id > 0 {
- if cus, err := db.Engine.GetIncome(ctx, id); err == nil {
- income = income.ToForm(cus)
- if u, err := db.Engine.GetSysUser(ctx, cus.CreatedUserID); err == nil {
- income.CreatedName = u.Username
- }
- if u, err := db.Engine.GetSysUser(ctx, cus.UpdatedUserID); err == nil {
- income.UpdatedName = u.Username
- }
- }
- }
- tpl.HTML(w, r, "income/edit.tmpl", map[string]any{
- "Item": income,
- "Statuses": html.NewSelectControls(global.Statuses, income.Status),
- })
-}
-
-func Save(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- data, err := validForm(r)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
-
- authUser := auth.AuthUser(ctx)
- if data.ID > 0 {
- arg := &db.UpdateIncomeParams{
- ID: data.ID,
- ProjectID: pgtype.Int8{
- Int64: data.ProjectID,
- Valid: true,
- },
- BudgetID: pgtype.Int8{
- Int64: data.BudgetID,
- Valid: true,
- },
- Amount: data.AmountF,
- IncomeAt: pgtype.Timestamptz{
- Time: data.IncomeAt,
- Valid: true,
- },
- IncomeType: pgtype.Int4{
- Int32: data.IncomeType,
- Valid: true,
- },
- IncomeBank: pgtype.Int4{
- Int32: data.IncomeBank,
- Valid: true,
- },
- Remark: pgtype.Text{
- String: data.Remark,
- Valid: true,
- },
- Status: pgtype.Int2{
- Int16: data.Status,
- Valid: true,
- },
- UpdatedUserID: pgtype.Int4{
- Int32: authUser.ID,
- Valid: true,
- },
- }
- _, err := db.Engine.UpdateIncome(ctx, arg)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
- tpl.JSONOK(w, "更新成功")
- } else {
- arg := &db.CreateIncomeParams{
- ProjectID: data.ProjectID,
- BudgetID: data.BudgetID,
- Amount: data.AmountF,
- IncomeAt: data.IncomeAt,
- IncomeType: data.IncomeType,
- IncomeBank: data.IncomeBank,
- Remark: data.Remark,
- Status: data.Status,
- CreatedUserID: authUser.ID,
- }
- _, err := db.Engine.CreateIncome(ctx, arg)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
- tpl.JSONOK(w, "添加成功")
- }
-}
-
-func validForm(r *http.Request) (form.IncomeForm, error) {
- var err error
- data := form.IncomeForm{}
- data.ID = convertor.ConvertInt[int64](r.PostFormValue("ID"), 0)
-
- data.ProjectID, err = strconv.ParseInt(r.PostFormValue("ProjectID"), 10, 64)
- if err != nil || data.ProjectID == 0 {
- return data, errors.New("项目不能为空")
- }
-
- data.BudgetID, err = strconv.ParseInt(r.PostFormValue("BudgetID"), 10, 64)
- if err != nil {
- data.BudgetID = 0
- }
-
- if err := data.AmountF.Scan(r.PostFormValue("Amount")); err != nil {
- return data, errors.New("报销金额格式错误")
- }
-
- data.IncomeAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("IncomeAt"), time.Local)
- if err != nil {
- return data, errors.New("回款时间格式错误")
- }
-
- incomeType, err := strconv.ParseInt(r.PostFormValue("IncomeType"), 10, 64)
- if err != nil {
- return data, errors.New("收入类型数据错误")
- }
- data.IncomeType = int32(incomeType)
-
- incomeBank, err := strconv.ParseInt(r.PostFormValue("IncomeBank"), 10, 64)
- if err != nil {
- return data, errors.New("收入银行数据错误")
- }
- data.IncomeBank = int32(incomeBank)
-
- data.Remark = r.PostFormValue("Remark")
- data.Status = convertor.ConvertInt[int16](r.PostFormValue("Status"), 9999)
- return data, nil
-}
diff --git a/internal/router/manage/oauth/oauth.go b/internal/router/manage/oauth/oauth.go
deleted file mode 100644
index e95d948..0000000
--- a/internal/router/manage/oauth/oauth.go
+++ /dev/null
@@ -1,142 +0,0 @@
-package oauth
-
-import (
- "encoding/json"
- "net/http"
- "strings"
- "time"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
- "management/internal/pkg/crypto"
- captchaservice "management/internal/service/captcha"
- systemservice "management/internal/service/system"
- "management/internal/tpl"
-
- "github.com/zhang2092/browser"
-)
-
-func Login(w http.ResponseWriter, r *http.Request) {
- // ctx := r.Context()
- // var user dto.AuthorizeUser
- // u := session.GetBytes(ctx, authglobal.StoreName)
- // if err := json.Unmarshal(u, &user); err == nil {
- // // 判断租户是否一致, 一致则刷新令牌,跳转到首页
- // if err := session.RenewToken(ctx); err == nil {
- // session.Put(ctx, authglobal.StoreName, u)
- // http.Redirect(w, r, "/home.html", http.StatusFound)
- // return
- // }
- // }
-
- // session.Destroy(ctx)
- tpl.HTML(w, r, "oauth/login.tmpl", nil)
-}
-
-func PostLogin(w http.ResponseWriter, r *http.Request) {
- email := strings.TrimSpace(r.PostFormValue("email"))
- password := strings.TrimSpace(r.PostFormValue("password"))
- captchaID := strings.TrimSpace(r.PostFormValue("captcha_id"))
- captcha := strings.TrimSpace(r.PostFormValue("captcha"))
- if len(email) == 0 {
- tpl.JSON(w, tpl.Response{Success: false, Message: "请填写邮箱"})
- return
- }
- if len(password) == 0 {
- tpl.JSON(w, tpl.Response{Success: false, Message: "请填写密码"})
- return
- }
- if len(captcha) == 0 {
- tpl.JSON(w, tpl.Response{Success: false, Message: "请填写验证码"})
- return
- }
- if !captchaservice.Verify(captchaID, captcha, true) {
- tpl.JSON(w, tpl.Response{Success: false, Message: "验证码错误"})
- return
- }
-
- br, err := browser.NewBrowser(r.Header.Get("User-Agent"))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: "平台信息获取错误"})
- return
- }
-
- ctx := r.Context()
- log := &db.CreateSysUserLoginLogParams{
- CreatedAt: time.Now(),
- Email: email,
- IsSuccess: false,
- RefererUrl: r.Header.Get("Referer"),
- Url: r.URL.RequestURI(),
- Os: br.Platform().Name(),
- Ip: r.RemoteAddr,
- Browser: br.Name(),
- }
-
- user, err := systemservice.GetSysUserByEmail(ctx, email)
- if err != nil {
- log.Message = err.Error()
- _ = systemservice.CreateSysUserLoginLog(ctx, log)
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
- log.UserUuid = user.Uuid
- log.Username = user.Username
-
- err = crypto.BcryptComparePassword(user.HashedPassword, password+user.Salt)
- if err != nil {
- log.Message = "compare password failed"
- _ = systemservice.CreateSysUserLoginLog(ctx, log)
- tpl.JSON(w, tpl.Response{Success: false, Message: "compare password failed"})
- return
- }
-
- // 登陆成功
-
- if user.RoleID == 0 {
- log.Message = "账号没有配置角色, 请联系管理员"
- _ = systemservice.CreateSysUserLoginLog(ctx, log)
- tpl.JSON(w, tpl.Response{Success: false, Message: "账号没有配置角色, 请联系管理员"})
- return
- }
-
- sysRole, err := systemservice.GetSysRole(ctx, user.RoleID)
- if err != nil {
- log.Message = "账号配置的角色错误, 请联系管理员"
- _ = systemservice.CreateSysUserLoginLog(ctx, log)
- tpl.JSON(w, tpl.Response{Success: false, Message: "账号配置的角色错误, 请联系管理员"})
- return
- }
-
- auth := dto.AuthorizeUser{
- ID: user.ID,
- Uuid: user.Uuid,
- Email: user.Email,
- Username: user.Username,
- RoleID: sysRole.ID,
- RoleName: sysRole.Name,
- OS: log.Os,
- IP: log.Ip,
- Browser: log.Browser,
- }
-
- _, err = json.Marshal(auth)
- if err != nil {
- log.Message = err.Error()
- _ = systemservice.CreateSysUserLoginLog(ctx, log)
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- // session.Put(ctx, authglobal.StoreName, b)
-
- log.IsSuccess = true
- log.Message = "登陆成功"
- _ = systemservice.CreateSysUserLoginLog(ctx, log)
- tpl.JSONOK(w, "login successful")
-}
-
-func Logout(w http.ResponseWriter, r *http.Request) {
- // session.Destroy(r.Context())
- http.Redirect(w, r, "/", http.StatusFound)
-}
diff --git a/internal/router/manage/project/project.go b/internal/router/manage/project/project.go
deleted file mode 100644
index db8de18..0000000
--- a/internal/router/manage/project/project.go
+++ /dev/null
@@ -1,738 +0,0 @@
-package project
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "strconv"
- "strings"
- "time"
-
- "management/internal/db/model/dto"
- formDto "management/internal/db/model/form"
- "management/internal/db/model/view"
- db "management/internal/db/sqlc"
- "management/internal/global"
- "management/internal/global/html"
- "management/internal/middleware/manage/auth"
- "management/internal/pkg/convertor"
- "management/internal/pkg/snowflake"
- "management/internal/router/manage/util"
- projectservice "management/internal/service/project"
- "management/internal/tpl"
-
- "github.com/jackc/pgx/v5/pgtype"
-)
-
-func List(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "project/list.tmpl", map[string]any{
- "Statuses": html.NewSelectControls(global.ProjectStatuses, 0),
- })
-}
-
-func PostList(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- title := strings.TrimSpace(r.PostFormValue("title"))
- var search string
- if len(title) > 0 {
- search = "%" + title + "%"
- if strings.HasSuffix(title, ":") {
- search = title[:len(title)-1] + "%"
- }
- }
- arg := &db.ListProjectConditionParam{
- IsTitle: len(search) > 0,
- Title: search,
- Status: util.ConvertInt16(r.PostFormValue("status"), 9999),
- PageID: util.ConvertInt32(r.PostFormValue("page"), 1),
- PageSize: util.ConvertInt32(r.PostFormValue("rows"), 10),
- }
- arg.TimeBegin, arg.TimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd"))
- res, total, err := db.Engine.ListProjectCondition(ctx, arg)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: total,
- Data: res,
- }
- tpl.JSON(w, data)
-}
-
-func Add(w http.ResponseWriter, r *http.Request) {
- authUser := auth.AuthUser(r.Context())
- tpl.HTML(w, r, "project/edit.tmpl", map[string]any{
- "Item": &formDto.ProjectForm{
- ApplyUserID: authUser.ID,
- ProjectFiles: &formDto.ProjectFileForm{
- ProjectFileItems: []*formDto.ProjectFileItemForm{},
- },
- },
- "Statuses": html.NewSelectControls(global.ProjectStatuses, 0),
- })
-}
-
-func Edit(w http.ResponseWriter, r *http.Request) {
- form := &formDto.ProjectForm{}
- id := convertor.ConvertInt[int64](r.URL.Query().Get("id"), 0)
- if id > 0 {
- ctx := r.Context()
- if po, err := db.Engine.GetProject(ctx, id); err == nil {
- pfs, err := db.Engine.ListProjectFiles(ctx, po.ID)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- form = form.ToForm(po, pfs)
- if form.ApplyUserID == 0 {
- authUser := auth.AuthUser(ctx)
- form.ApplyUserID = authUser.ID
- }
- if c, err := db.Engine.GetCustomer(ctx, po.CustomerID); err == nil {
- form.CustomerName = c.Name
- }
- // if u, err := db.Engine.GetSysUser(ctx, po.ManagerID); err == nil {
- // form.ManagerName = u.Username
- // }
-
- // if len(po.Members) > 0 {
- // arr := strings.Split(po.Members, ",")
- // if len(arr) > 0 {
- // var ids []int32
- // for _, v := range arr {
- // ids = append(ids, convertor.ConvertInt[int32](v, 0))
- // }
-
- // if rows, err := db.Engine.ListSysUserByIds(ctx, ids); err == nil && len(rows) > 0 {
- // log.Println("rows: ", rows)
- // var names []string
- // for _, v := range rows {
- // names = append(names, v.Username)
- // }
- // form.MembersName = strings.Join(names, ",")
- // }
- // }
- // }
-
- // if u, err := db.Engine.GetSysUser(ctx, po.ApplyUserID); err == nil {
- // form.ApplyUserName = u.Username
- // }
- if u, err := db.Engine.GetSysUser(ctx, po.CreatedUserID); err == nil {
- form.CreatedName = u.Username
- }
- if u, err := db.Engine.GetSysUser(ctx, po.UpdatedUserID); err == nil {
- form.UpdatedName = u.Username
- }
- }
- }
- tpl.HTML(w, r, "project/edit.tmpl", map[string]any{
- "Item": form,
- "Statuses": html.NewSelectControls(global.ProjectStatuses, form.Status),
- })
-}
-
-func Save(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- form, err := validForm(r)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
-
- authUser := auth.AuthUser(ctx)
- if form.ID > 0 {
- p := &db.UpdateProjectParams{
- ID: form.ID,
- Name: pgtype.Text{
- String: form.Name,
- Valid: true,
- },
- StartAt: pgtype.Timestamptz{
- Time: form.StartAt,
- Valid: true,
- },
- EndAt: pgtype.Timestamptz{
- Time: form.EndAt,
- Valid: true,
- },
- CustomerID: pgtype.Int8{
- Int64: form.CustomerID,
- Valid: true,
- },
- TotalMoney: form.TotalMoneyF,
- Description: pgtype.Text{
- String: form.Description,
- Valid: true,
- },
- ApplyAt: pgtype.Timestamptz{
- Time: form.ApplyAt,
- Valid: true,
- },
- ApplyUserID: pgtype.Int4{
- Int32: form.ApplyUserID,
- Valid: true,
- },
- ManagerID: pgtype.Int4{
- Int32: form.ManagerID,
- Valid: true,
- },
- Members: pgtype.Text{
- String: form.Members,
- Valid: true,
- },
- Status: pgtype.Int2{
- Int16: form.Status,
- Valid: true,
- },
- UpdatedUserID: pgtype.Int4{
- Int32: authUser.ID,
- Valid: true,
- },
- }
- cpfs := []*db.CreateProjectFileParams{}
- for _, pfile := range form.ProjectFiles.ProjectFileItems {
- cpfs = append(cpfs, &db.CreateProjectFileParams{
- ID: snowflake.GetId(),
- Name: pfile.Name,
- Path: pfile.Path,
- ProjectID: form.ID,
- CreatedUserID: authUser.ID,
- })
- }
- err := projectservice.UpdateProject(ctx, p, cpfs)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
- tpl.JSONOK(w, "更新成功")
- } else {
- p := &db.CreateProjectParams{
- ID: snowflake.GetId(),
- Name: form.Name,
- StartAt: form.StartAt,
- EndAt: form.EndAt,
- CustomerID: form.CustomerID,
- TotalMoney: form.TotalMoneyF,
- Description: form.Description,
- ApplyAt: form.ApplyAt,
- ApplyUserID: form.ApplyUserID,
- ManagerID: form.ManagerID,
- Members: form.Members,
- Status: form.Status,
- CreatedUserID: authUser.ID,
- }
- cpfs := []*db.CreateProjectFileParams{}
- for _, pfile := range form.ProjectFiles.ProjectFileItems {
- cpfs = append(cpfs, &db.CreateProjectFileParams{
- ID: snowflake.GetId(),
- Name: pfile.Name,
- Path: pfile.Path,
- ProjectID: p.ID,
- CreatedUserID: authUser.ID,
- })
- }
- err := projectservice.CreateProject(ctx, p, cpfs)
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
- tpl.JSONOK(w, "添加成功")
- }
-}
-
-func XmSelect(w http.ResponseWriter, r *http.Request) {
- all, err := db.Engine.AllProjects(r.Context())
- if err != nil {
- tpl.JSONERR(w, err.Error())
- return
- }
-
- var res []*dto.XmSelectStrDto
- for _, v := range all {
- res = append(res, &dto.XmSelectStrDto{
- Name: v.Name,
- Value: strconv.FormatInt(v.ID, 10),
- })
- }
- tpl.JSON(w, res)
-}
-
-func Dashboard(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "project/dashboard.tmpl", map[string]any{
- "Projects": projectservice.AllProjects(r.Context()),
- })
-}
-
-func PostDashboard(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- t := r.PostFormValue("type")
- if t == "project" {
- var projectIncome float64
- var projectExpense float64
- projectID := convertor.ConvertInt[int64](r.PostFormValue("projectID"), 0)
- if projectID == 0 {
- si, _ := db.Engine.SumIncome(ctx)
- projectIncome = convertor.NumericToFloat64(si)
- se, _ := db.Engine.SumExpense(ctx)
- projectExpense = convertor.NumericToFloat64(se)
- } else {
- pi, _ := db.Engine.SumIncomeByProjectID(ctx, projectID)
- projectIncome = convertor.NumericToFloat64(pi)
- pe, _ := db.Engine.SumExpenseByProjectID(ctx, projectID)
- projectExpense = convertor.NumericToFloat64(pe)
- }
-
- projectProfit := projectIncome - projectExpense
- var projectProfitRate float64 = 0
- if projectExpense > 0 {
- projectProfitRate = projectProfit / projectExpense
- }
-
- res := &view.DashboardProject{
- ProjectIncome: projectIncome,
- ProjectExpense: projectExpense,
- ProjectProfit: projectProfit,
- ProjectProfitRate: fmt.Sprintf("%0.2f%%", projectProfitRate*100),
- IncomeExpenseEcharts: incomeExpenseEcharts(ctx, projectID),
- IncomeEcharts: incomeEcharts(ctx, projectID),
- ExpenseEcharts: expenseEcharts(ctx, projectID),
- }
- tpl.JSON(w, tpl.Response{Success: true, Message: "ok", Data: res})
- return
- } else if t == "budget" {
- }
- tpl.JSONERR(w, "failed to valid type")
-}
-
-func validForm(r *http.Request) (formDto.ProjectForm, error) {
- // data := &form.ProjectForm{}
- // if err := form.BindForm(r, data); err != nil {
- // return data, err
- // }
-
- // if err := data.TotalMoneyF.Scan(data.TotalMoney); err != nil {
- // return data, errors.New("总金额格式错误")
- // }
-
- // if len(data.Members) > 0 {
- // membersSplit := strings.SplitSeq(data.Members, ",")
- // for v := range membersSplit {
- // m := convertor.ConvertInt[int32](v, 0)
- // if m == 0 {
- // return data, errors.New("项目成员数据错误")
- // }
- // }
- // }
-
- // data.ProjectFiles = &formDto.ProjectFileForm{
- // ProjectFileItems: []*formDto.ProjectFileItemForm{},
- // }
- // if len(data.Paths) > 0 {
- // fnsSplit := strings.SplitSeq(data.Paths, ",")
- // for v := range fnsSplit {
- // if len(v) > 0 {
- // read := strings.Split(v, "|")
- // if len(read) != 2 {
- // return data, errors.New("文件路径数据错误")
- // }
- // pff := &formDto.ProjectFileItemForm{
- // Name: read[0],
- // Path: read[1],
- // Combination: v,
- // }
- // data.ProjectFiles.ProjectFileItems = append(data.ProjectFiles.ProjectFileItems, pff)
- // }
- // }
- // }
-
- // return data, nil
-
- var err error
- form := formDto.ProjectForm{}
-
- form.ID = convertor.ConvertInt[int64](r.PostFormValue("ID"), 0)
- form.CustomerID, err = strconv.ParseInt(r.PostFormValue("CustomerID"), 10, 64)
- if err != nil || form.CustomerID == 0 {
- return form, errors.New("客户不能为空")
- }
-
- form.Name = r.PostFormValue("Name")
- if len(form.Name) == 0 {
- return form, errors.New("名称不能为空")
- }
- form.StartAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("StartAt"), time.Local)
- if err != nil {
- return form, errors.New("开始时间格式错误")
- }
- form.EndAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("EndAt"), time.Local)
- if err != nil {
- return form, errors.New("结束时间格式错误")
- }
-
- if err := form.TotalMoneyF.Scan(r.PostFormValue("TotalMoney")); err != nil {
- return form, errors.New("总金额格式错误")
- }
-
- form.Description = r.PostFormValue("Description")
- form.ApplyAt, err = time.ParseInLocation("2006-01-02", r.PostFormValue("ApplyAt"), time.Local)
- if err != nil {
- return form, errors.New("申请时间格式错误")
- }
- form.ApplyUserID = convertor.ConvertInt[int32](r.PostFormValue("ApplyUserID"), 0)
- if form.ApplyUserID == 0 {
- return form, errors.New("申请人不能为空")
- }
-
- form.ManagerID = convertor.ConvertInt[int32](r.PostFormValue("ManagerID"), 0)
- if form.ManagerID == 0 {
- return form, errors.New("项目经理不能为空")
- }
-
- form.Members = r.PostFormValue("Members")
- if len(form.Members) > 0 {
- membersSplit := strings.SplitSeq(form.Members, ",")
- for v := range membersSplit {
- m := convertor.ConvertInt[int32](v, 0)
- if m == 0 {
- return form, errors.New("项目成员数据错误")
- }
- }
- }
-
- form.Status = convertor.ConvertInt[int16](r.PostFormValue("Status"), 9999)
-
- form.ProjectFiles = &formDto.ProjectFileForm{
- ProjectFileItems: []*formDto.ProjectFileItemForm{},
- }
- fns := r.PostFormValue("Paths")
- if len(fns) > 0 {
- fnsSplit := strings.SplitSeq(fns, ",")
- for v := range fnsSplit {
- if len(v) > 0 {
- read := strings.Split(v, "|")
- if len(read) != 2 {
- return form, errors.New("文件路径数据错误")
- }
- pff := &formDto.ProjectFileItemForm{
- Name: read[0],
- Path: read[1],
- Combination: v,
- }
- form.ProjectFiles.ProjectFileItems = append(form.ProjectFiles.ProjectFileItems, pff)
- }
- }
- }
- return form, nil
-}
-
-func incomeExpenseEcharts(ctx context.Context, projectId int64) view.EchartsOption {
- var name []string
- var income []float64
- var expense []float64
-
- if projectId == 0 {
- rows, err := db.Engine.StatisticsProjects(ctx)
- if err != nil || len(rows) == 0 {
- return view.EchartsOption{}
- }
-
- for _, row := range rows {
- name = append(name, row.Name)
- income = append(income, convertor.NumericToFloat64(row.Income))
- expense = append(expense, convertor.NumericToFloat64(row.Expense))
- }
- } else {
- row, err := db.Engine.StatisticsProjectItem(ctx, projectId)
- if err != nil || row == nil {
- return view.EchartsOption{}
- }
- name = append(name, row.Name)
- income = append(income, convertor.NumericToFloat64(row.Income))
- expense = append(expense, convertor.NumericToFloat64(row.Expense))
- }
-
- return view.EchartsOption{
- Title: view.Title{
- Text: "项目收支情况",
- Left: "center",
- Top: 2,
- FontSize: 15,
- TextStyle: view.TextStyle{
- Color: "#666666",
- FontWeight: "normal",
- },
- },
- Color: []string{"#fed46b", "#2194ff"},
- ToolTip: view.ToolTip{
- Trigger: "axis",
- AxisPointer: view.AxisPointer{
- Type: "shadow",
- },
- },
- Grid: view.Grid{
- Left: "3%",
- Right: "4%",
- Bottom: "10%",
- ContainLabel: true,
- },
- Legend: view.Legend{
- Left: "center",
- Top: "bottom",
- Data: []string{"支出金额", "收入金额"},
- },
- XAxis: []view.XAxis{
- {
- Type: "category",
- Data: name,
- AxisTick: view.AxisTick{
- AlignWithLabel: true,
- },
- },
- },
- YAxis: []view.YAxis{
- {
- Type: "value",
- Name: "单位:元",
- },
- },
- BarMaxWidth: "30",
- Label: view.Label{
- Show: true,
- Position: "top",
- },
- Series: []view.Series{
- {
- Name: "支出金额",
- Type: "bar",
- Data: expense,
- ItemStyle: view.ItemStyle{
- Normal: view.Normal{
- Color: "#f89588",
- },
- },
- },
- {
- Name: "收入金额",
- Type: "bar",
- Data: income,
- ItemStyle: view.ItemStyle{
- Normal: view.Normal{
- Color: "#76da91",
- },
- },
- },
- },
- }
-}
-
-func incomeEcharts(ctx context.Context, projectId int64) view.EchartsOption {
- var name []string
- data := []view.DataItem{}
-
- if projectId == 0 {
- rows, err := db.Engine.StatisticsIncome(ctx)
- if err != nil || len(rows) == 0 {
- return view.EchartsOption{}
- }
-
- for _, row := range rows {
- name = append(name, row.IncomeTypeName)
- data = append(data, view.DataItem{
- Name: row.IncomeTypeName,
- Value: convertor.NumericToFloat64(row.TotalAmount),
- })
- }
- } else {
- rows, err := db.Engine.StatisticsIncomeByProjectID(ctx, projectId)
- if err != nil || len(rows) == 0 {
- return view.EchartsOption{}
- }
-
- for _, row := range rows {
- name = append(name, row.IncomeTypeName)
- data = append(data, view.DataItem{
- Name: row.IncomeTypeName,
- Value: convertor.NumericToFloat64(row.TotalAmount),
- })
- }
- }
-
- return view.EchartsOption{
- Title: view.Title{
- Text: "收入分布",
- Left: "center",
- Orient: "vertical",
- FontSize: 15,
- TextStyle: view.TextStyle{
- Color: "#666666",
- FontWeight: "normal",
- },
- },
- ToolTip: view.ToolTip{
- Trigger: "item",
- },
- Legend: view.Legend{
- Left: "center",
- Top: "bottom",
- Data: name,
- },
- Color: []string{"#63b2ee", "#76da91", "#f8cb7f", "#f89588", "#7cd6cf", "#9192ab", "#7898e1", "#efa666", "#eddd86", "#9987ce", "#63b2ee", "#76da91"},
- Series: []view.Series{
- {
- Type: "pie",
- Radius: "50%",
- Data: data,
- Label: view.Label{
- Show: true,
- TextStyle: view.TextStyle{
- Color: "#666666",
- },
- Normal: view.LableNormal{
- Formatter: "{c} ({d}%)",
- TextStyle: view.TextStyle{
- Color: "#666666",
- FontWeight: "normal",
- },
- },
- },
- },
- },
- }
-}
-
-func expenseEcharts(ctx context.Context, projectId int64) view.EchartsOption {
- var name []string
- data := []view.DataItem{}
-
- if projectId == 0 {
- rows, err := db.Engine.StatisticsExpense(ctx)
- if err != nil || len(rows) == 0 {
- return view.EchartsOption{}
- }
-
- for _, row := range rows {
- name = append(name, row.ExpensesTypeName)
- data = append(data, view.DataItem{
- Name: row.ExpensesTypeName,
- Value: convertor.NumericToFloat64(row.TotalAmount),
- })
- }
- } else {
- rows, err := db.Engine.StatisticsExpenseByProjectID(ctx, projectId)
- if err != nil || len(rows) == 0 {
- return view.EchartsOption{}
- }
-
- for _, row := range rows {
- name = append(name, row.ExpensesTypeName)
- data = append(data, view.DataItem{
- Name: row.ExpensesTypeName,
- Value: convertor.NumericToFloat64(row.TotalAmount),
- })
- }
- }
-
- return view.EchartsOption{
- Title: view.Title{
- Text: "支出分布",
- Left: "center",
- Orient: "vertical",
- FontSize: 15,
- TextStyle: view.TextStyle{
- Color: "#666666",
- FontWeight: "normal",
- },
- },
- ToolTip: view.ToolTip{
- Trigger: "item",
- },
- Legend: view.Legend{
- Left: "center",
- Top: "bottom",
- Data: name,
- },
- Color: []string{"#63b2ee", "#76da91", "#f8cb7f", "#f89588", "#7cd6cf", "#9192ab", "#7898e1", "#efa666", "#eddd86", "#9987ce", "#63b2ee", "#76da91"},
- Series: []view.Series{
- {
- Type: "pie",
- Radius: "50%",
- Data: data,
- Label: view.Label{
- Show: true,
- TextStyle: view.TextStyle{
- Color: "#666666",
- },
- Normal: view.LableNormal{
- Formatter: "{c} ({d}%)",
- TextStyle: view.TextStyle{
- Color: "#666666",
- FontWeight: "normal",
- },
- },
- },
- },
- },
- }
-
- // return view.EchartsOption{
- // Title: view.Title{
- // Text: "支出分布",
- // Left: "center",
- // Top: 2,
- // FontSize: 15,
- // TextStyle: view.TextStyle{
- // Color: "#666666",
- // FontWeight: "normal",
- // },
- // },
- // Color: []string{"#fed46b", "#2194ff"},
- // ToolTip: view.ToolTip{
- // Trigger: "axis",
- // AxisPointer: view.AxisPointer{
- // Type: "shadow",
- // },
- // },
- // Grid: view.Grid{
- // Left: "3%",
- // Right: "4%",
- // Bottom: "10%",
- // ContainLabel: true,
- // },
- // XAxis: []view.XAxis{
- // {
- // Type: "category",
- // Data: name,
- // AxisTick: view.AxisTick{
- // AlignWithLabel: true,
- // },
- // },
- // },
- // YAxis: []view.YAxis{
- // {
- // Type: "value",
- // Name: "单位:元",
- // },
- // },
- // BarMaxWidth: "30",
- // Label: view.Label{
- // Show: true,
- // Position: "top",
- // },
- // Series: []view.Series{
- // {
- // Type: "bar",
- // Data: expense,
- // ItemStyle: view.ItemStyle{
- // Normal: view.Normal{
- // Color: "#f89588",
- // },
- // },
- // },
- // },
- // }
-}
diff --git a/internal/router/manage/router.go b/internal/router/manage/router.go
deleted file mode 100644
index 1c6fcbf..0000000
--- a/internal/router/manage/router.go
+++ /dev/null
@@ -1,226 +0,0 @@
-package router
-
-import (
- "net/http"
-
- "management/internal/middleware/manage/audit"
- "management/internal/middleware/manage/auth"
- "management/internal/middleware/manage/nosurf"
-
- budgethandler "management/internal/router/manage/budget"
- cachehandler "management/internal/router/manage/cache"
- categoryhandler "management/internal/router/manage/category"
- commonhandler "management/internal/router/manage/common"
- customerhandler "management/internal/router/manage/customer"
- expensehandler "management/internal/router/manage/expense"
- incomehandler "management/internal/router/manage/income"
- oauthhandler "management/internal/router/manage/oauth"
- projecthandler "management/internal/router/manage/project"
- systemhandler "management/internal/router/manage/system"
-
- "github.com/go-chi/chi/v5"
- "github.com/go-chi/chi/v5/middleware"
-)
-
-func NewRouter() *chi.Mux {
- r := chi.NewRouter()
-
- r.Use(middleware.RequestID)
- r.Use(middleware.RealIP)
- // r.Use(middleware.Logger)
- r.Use(middleware.Recoverer)
-
- staticServer := http.FileServer(http.Dir("./web/statics/"))
- r.Handle("/statics/*", http.StripPrefix("/statics", staticServer))
-
- uploadServer := http.FileServer(http.Dir("./upload/"))
- r.Handle("/upload/*", http.StripPrefix("/upload", uploadServer))
-
- r.Group(func(r chi.Router) {
- r.Use(nosurf.NoSurf) // CSRF
- // r.Use(session.LoadSession) // Session
-
- r.Get("/captcha", commonhandler.Captcha)
-
- r.Get("/", oauthhandler.Login)
- r.Post("/login", oauthhandler.PostLogin)
- r.Get("/logout", oauthhandler.Logout)
-
- r.With(auth.Authorize, audit.Audit).Post("/upload/img", commonhandler.UploadImg)
- r.With(auth.Authorize, audit.Audit).Post("/upload/file", commonhandler.UploadFile)
- r.With(auth.Authorize, audit.Audit).Post("/upload/mutilfile", commonhandler.UploadMutilFiles)
-
- r.With(auth.Authorize, audit.Audit).Get("/home.html", Home)
-
- configHandler := systemhandler.NewSysConfigHandler()
- r.With(auth.Authorize).Get("/pear.json", configHandler.Pear)
-
- r.Route("/system", func(r chi.Router) {
- r.Use(auth.Authorize)
-
- r.Route("/config", func(r chi.Router) {
- r.Use(audit.Audit)
- r.Get("/list", configHandler.List)
- r.Post("/list", configHandler.PostList)
- r.Get("/add", configHandler.Add)
- r.Get("/edit", configHandler.Edit)
- r.Post("/save", configHandler.Save)
- r.Post("/reset_pear", configHandler.ResetPear)
- r.Post("/refresh", configHandler.Refresh)
- })
-
- r.Route("/department", func(r chi.Router) {
- r.Use(audit.Audit)
- departHandler := systemhandler.NewSysDepartmentHandler()
- r.Get("/list", departHandler.List)
- r.Post("/list", departHandler.PostList)
- r.Get("/add", departHandler.Add)
- r.Get("/add_children", departHandler.AddChildren)
- r.Get("/edit", departHandler.Edit)
- r.Post("/save", departHandler.Save)
- r.Post("/dtree", departHandler.DTree)
- r.Post("/refresh", departHandler.Refresh)
- r.Post("/rebuild_parent_path", departHandler.RebuildParentPath)
- })
-
- r.Route("/user", func(r chi.Router) {
- r.Use(audit.Audit)
- userHandler := systemhandler.NewSysUserHandler()
- r.Get("/list", userHandler.List)
- r.Post("/list", userHandler.PostList)
- r.Get("/add", userHandler.Add)
- r.Get("/edit", userHandler.Edit)
- r.Post("/save", userHandler.Save)
- r.Get("/profile", userHandler.Profile)
- r.Post("/xmselect", userHandler.XmSelect)
- })
-
- r.Route("/login_log", func(r chi.Router) {
- // r.Use(audit.Audit)
- userLoginLogHandler := systemhandler.NewSysUserLoginLogHandler()
- r.Get("/list", userLoginLogHandler.List)
- r.Post("/list", userLoginLogHandler.PostList)
- })
-
- r.Route("/audit_log", func(r chi.Router) {
- // r.Use(audit.Audit)
- userAuditLogHandler := systemhandler.NewSysAuditLogHandler()
- r.Get("/list", userAuditLogHandler.List)
- r.Post("/list", userAuditLogHandler.PostList)
- })
-
- r.Route("/role", func(r chi.Router) {
- r.Use(audit.Audit)
- roleHandler := systemhandler.NewSysRoleHandler()
- r.Get("/list", roleHandler.List)
- r.Post("/list", roleHandler.PostList)
- r.Get("/add", roleHandler.Add)
- r.Get("/edit", roleHandler.Edit)
- r.Post("/save", roleHandler.Save)
- r.Post("/dtree", roleHandler.DTree)
- r.Post("/refresh", roleHandler.Refresh)
- r.Post("/rebuild_parent_path", roleHandler.RebuildParentPath)
- r.Post("/refresh_role_menus", roleHandler.RefreshRoleMenus)
- r.Post("/xm_select", roleHandler.XmSelect)
- r.Get("/set_menu", roleHandler.SetMenu)
- r.Post("/set_menu", roleHandler.PostSetMenu)
- })
-
- menuHandler := systemhandler.NewSysMenuHandler()
- r.Get("/menus", menuHandler.UserMenus)
- r.Route("/menu", func(r chi.Router) {
- r.Use(audit.Audit)
- r.Get("/tree", menuHandler.Tree)
- r.Get("/list", menuHandler.List)
- r.Post("/list", menuHandler.PostList)
- r.Get("/add", menuHandler.Add)
- r.Get("/add_children", menuHandler.AddChildren)
- r.Get("/edit", menuHandler.Edit)
- r.Post("/save", menuHandler.Save)
- r.Post("/xm_select_tree", menuHandler.XmSelectTree)
- r.Post("/refresh_cache", menuHandler.Refresh)
- })
-
- // 类别
- r.Route("/category", func(r chi.Router) {
- r.Use(audit.Audit)
- categoryHandler := categoryhandler.NewCategoryHandler()
- r.Get("/list", categoryHandler.List)
- r.Post("/list", categoryHandler.PostList)
- r.Get("/add", categoryHandler.Add)
- r.Get("/add_children", categoryHandler.AddChildren)
- r.Get("/edit", categoryHandler.Edit)
- r.Post("/save", categoryHandler.Save)
- r.Post("/dtree", categoryHandler.DTree)
- r.Post("/xmselect", categoryHandler.XmSelect)
- r.Post("/refresh", categoryHandler.Refresh)
- r.Post("/rebuild_parent_path", categoryHandler.RebuildParentPath)
- })
- })
-
- // 客户
- r.Route("/customer", func(r chi.Router) {
- r.Use(auth.Authorize)
- r.Get("/list", customerhandler.List)
- r.Post("/list", customerhandler.PostList)
- r.Get("/add", customerhandler.Add)
- r.Get("/edit", customerhandler.Edit)
- r.Post("/save", customerhandler.Save)
- r.Post("/xmselect", customerhandler.XmSelect)
- })
-
- // 项目
- r.Route("/project", func(r chi.Router) {
- r.Use(auth.Authorize)
- r.Get("/list", projecthandler.List)
- r.Post("/list", projecthandler.PostList)
- r.Get("/add", projecthandler.Add)
- r.Get("/edit", projecthandler.Edit)
- r.Post("/save", projecthandler.Save)
- r.Post("/xmselect", projecthandler.XmSelect)
- r.Get("/dashboard", projecthandler.Dashboard)
- r.Post("/dashboard", projecthandler.PostDashboard)
- })
-
- // 项目预算
- r.Route("/budget", func(r chi.Router) {
- r.Use(auth.Authorize)
- r.Get("/list", budgethandler.List)
- r.Post("/list", budgethandler.PostList)
- r.Get("/add", budgethandler.Add)
- r.Get("/edit", budgethandler.Edit)
- r.Post("/save", budgethandler.Save)
- r.Post("/xmselect", budgethandler.XmSelect)
- })
-
- // 回款单
- r.Route("/income", func(r chi.Router) {
- r.Use(auth.Authorize)
- r.Get("/list", incomehandler.List)
- r.Post("/list", incomehandler.PostList)
- r.Get("/add", incomehandler.Add)
- r.Get("/edit", incomehandler.Edit)
- r.Post("/save", incomehandler.Save)
- })
-
- // 费用报销单
- r.Route("/expense", func(r chi.Router) {
- r.Use(auth.Authorize)
- r.Get("/list", expensehandler.List)
- r.Post("/list", expensehandler.PostList)
- r.Get("/add", expensehandler.Add)
- r.Get("/edit", expensehandler.Edit)
- r.Post("/save", expensehandler.Save)
- })
-
- // 缓存
- r.Route("/cache", func(r chi.Router) {
- r.Use(auth.Authorize)
- r.Get("/list", cachehandler.List)
- r.Post("/list", cachehandler.PostList)
- r.Post("/refresh", cachehandler.Refresh)
- })
- })
-
- return r
-}
diff --git a/internal/router/manage/system/sys_audit_log.go b/internal/router/manage/system/sys_audit_log.go
deleted file mode 100644
index 841a736..0000000
--- a/internal/router/manage/system/sys_audit_log.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package system
-
-import (
- "net/http"
-
- "management/internal/db/model/dto"
- "management/internal/router/manage/util"
- systemservice "management/internal/service/system"
- "management/internal/tpl"
-)
-
-type SysAuditLogHandler struct{}
-
-func NewSysAuditLogHandler() *SysAuditLogHandler {
- return &SysAuditLogHandler{}
-}
-
-func (h *SysAuditLogHandler) List(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "audit_log/list.tmpl", nil)
-}
-
-func (h *SysAuditLogHandler) PostList(w http.ResponseWriter, r *http.Request) {
- var q dto.SearchDto
- q.SearchTimeBegin, q.SearchTimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("SearchTimeBegin"), r.PostFormValue("SearchTimeEnd"))
- q.SearchName = r.PostFormValue("SearchName")
- q.SearchKey = r.PostFormValue("SearchKey")
- q.Page = util.ConvertInt(r.PostFormValue("page"), 1)
- q.Rows = util.ConvertInt(r.PostFormValue("rows"), 10)
- ctx := r.Context()
- res, count, err := systemservice.ListSysAuditLog(ctx, q)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: count,
- Data: res,
- }
- tpl.JSON(w, data)
-}
diff --git a/internal/router/manage/system/sys_config.go b/internal/router/manage/system/sys_config.go
deleted file mode 100644
index 0449c1d..0000000
--- a/internal/router/manage/system/sys_config.go
+++ /dev/null
@@ -1,166 +0,0 @@
-package system
-
-import (
- "encoding/json"
- "net/http"
- "strings"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
- "management/internal/global/pearadmin"
- "management/internal/pkg/redis"
- "management/internal/router/manage/util"
- systemservice "management/internal/service/system"
- "management/internal/tpl"
-)
-
-type SysConfigHandler struct{}
-
-func NewSysConfigHandler() *SysConfigHandler {
- return &SysConfigHandler{}
-}
-
-func (h *SysConfigHandler) Pear(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- pear, err := systemservice.PearConfig(ctx)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- tpl.JSON(w, pear)
-}
-
-func (h *SysConfigHandler) List(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "config/list.tmpl", nil)
-}
-
-func (h *SysConfigHandler) PostList(w http.ResponseWriter, r *http.Request) {
- var q dto.SearchDto
- q.SearchKey = r.PostFormValue("SearchKey")
- q.Page = util.ConvertInt(r.PostFormValue("page"), 1)
- q.Rows = util.ConvertInt(r.PostFormValue("rows"), 10)
- ctx := r.Context()
- res, count, err := systemservice.ListSysConfigCondition(ctx, q)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: count,
- Data: res,
- }
- tpl.JSON(w, data)
-}
-
-type EditSysConfig struct {
- *db.SysConfig
- Result string
-}
-
-func (h *SysConfigHandler) Add(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "config/edit.tmpl", map[string]any{
- "Item": &db.SysConfig{},
- "Result": "",
- })
-}
-
-func (h *SysConfigHandler) Edit(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- id := util.DefaultInt(vars, "id", 0)
- vm := &EditSysConfig{}
- if id > 0 {
- ctx := r.Context()
- if conf, err := systemservice.GetSysConfig(ctx, int32(id)); err == nil {
- vm.SysConfig = conf
- vm.Result = string(conf.Value)
- }
- }
- tpl.HTML(w, r, "config/edit.tmpl", map[string]any{
- "Item": vm.SysConfig,
- "Result": vm.Result,
- })
-}
-
-func (h *SysConfigHandler) Save(w http.ResponseWriter, r *http.Request) {
- id := util.ConvertInt(r.PostFormValue("ID"), 0)
- key := r.PostFormValue("Key")
- value := r.PostFormValue("Value")
- if len(key) == 0 {
- tpl.JSON(w, tpl.Response{Success: false, Message: "Key不能为空"})
- return
- }
- if len(value) == 0 {
- tpl.JSON(w, tpl.Response{Success: false, Message: "Value不能为空"})
- return
- }
-
- ctx := r.Context()
- if id == 0 {
- arg := &db.CreateSysConfigParams{
- Key: key,
- Value: []byte(value),
- }
- err := systemservice.CreateSysConfig(ctx, arg)
- if err != nil {
- if db.IsUniqueViolation(err) {
- tpl.JSON(w, tpl.Response{Success: false, Message: "数据已存在"})
- return
- }
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "添加成功"})
- } else {
- res, err := systemservice.GetSysConfig(ctx, int32(id))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- arg := &db.UpdateSysConfigByKeyParams{
- Key: res.Key,
- Value: []byte(value),
- }
- err = systemservice.UpdateSysConfigByKey(ctx, arg)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "更新成功"})
- }
-}
-
-func (h *SysConfigHandler) ResetPear(w http.ResponseWriter, r *http.Request) {
- b, err := json.Marshal(pearadmin.PearJson)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- ctx := r.Context()
- err = systemservice.UpdateSysConfigByKey(ctx, &db.UpdateSysConfigByKeyParams{
- Key: pearadmin.PearKey,
- Value: b,
- })
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- tpl.JSON(w, tpl.Response{Success: true, Message: "重置成功"})
-}
-
-func (h *SysConfigHandler) Refresh(w http.ResponseWriter, r *http.Request) {
- key := r.FormValue("key")
- err := redis.Del(r.Context(), strings.ToLower(key))
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "刷新成功"})
-}
diff --git a/internal/router/manage/system/sys_department.go b/internal/router/manage/system/sys_department.go
deleted file mode 100644
index 0ecd412..0000000
--- a/internal/router/manage/system/sys_department.go
+++ /dev/null
@@ -1,177 +0,0 @@
-package system
-
-import (
- "fmt"
- "net/http"
- "time"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
- "management/internal/router/manage/util"
- systemservice "management/internal/service/system"
- "management/internal/tpl"
-)
-
-type SysDepartmentHandler struct{}
-
-func NewSysDepartmentHandler() *SysDepartmentHandler {
- return &SysDepartmentHandler{}
-}
-
-func (h *SysDepartmentHandler) List(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "department/list.tmpl", nil)
-}
-
-func (h *SysDepartmentHandler) PostList(w http.ResponseWriter, r *http.Request) {
- var q dto.SearchDto
- q.SearchStatus = util.ConvertInt(r.PostFormValue("SearchStatus"), 9999)
- q.SearchParentID = util.ConvertInt(r.PostFormValue("SearchParentID"), 0)
- q.SearchName = r.PostFormValue("SearchName")
- q.SearchKey = r.PostFormValue("SearchKey")
- q.Page = util.ConvertInt(r.PostFormValue("page"), 1)
- q.Rows = util.ConvertInt(r.PostFormValue("rows"), 10)
- res, count, err := systemservice.ListSysDepartmentCondition(r.Context(), q)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: count,
- Data: res,
- }
- tpl.JSON(w, data)
-}
-
-func (h *SysDepartmentHandler) Add(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "department/edit.tmpl", map[string]any{
- "Item": &db.SysDepartment{Sort: 6666},
- })
-}
-
-func (h *SysDepartmentHandler) AddChildren(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- parentID := util.DefaultInt(vars, "parentID", 0)
- vm := &db.SysDepartment{ParentID: int32(parentID), Sort: 6666}
- tpl.HTML(w, r, "department/edit.tmpl", map[string]any{
- "Item": vm,
- })
-}
-
-func (h *SysDepartmentHandler) Edit(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- id := util.DefaultInt(vars, "id", 0)
- vm := &db.SysDepartment{Sort: 6666}
- if id > 0 {
- vm, _ = systemservice.GetSysDepartment(r.Context(), int32(id))
- }
- tpl.HTML(w, r, "department/edit.tmpl", map[string]any{
- "Item": vm,
- })
-}
-
-func (h *SysDepartmentHandler) Save(w http.ResponseWriter, r *http.Request) {
- id := util.ConvertInt(r.PostFormValue("ID"), 0)
- ParentID := util.ConvertInt(r.PostFormValue("ParentID"), 0)
- name := r.PostFormValue("Name")
- sort := util.ConvertInt(r.PostFormValue("Sort"), 6666)
- status := util.ConvertInt(r.PostFormValue("Status"), 9999)
-
- ctx := r.Context()
- var parent *db.SysDepartment
- if ParentID > 0 {
- var err error
- parent, err = systemservice.GetSysDepartment(ctx, int32(ParentID))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: "父级节点错误"})
- return
- }
- }
-
- if id == 0 {
- arg := db.CreateSysDepartmentParams{
- Name: name,
- ParentID: int32(ParentID),
- ParentPath: fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID),
- Status: int32(status),
- Sort: int32(sort),
- CreatedAt: time.Now(),
- UpdatedAt: time.Now(),
- }
- _, err := systemservice.CreateSysDepartment(ctx, &arg)
- if err != nil {
- if db.IsUniqueViolation(err) {
- tpl.JSON(w, tpl.Response{Success: false, Message: "部门名称已存在"})
- return
- }
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "添加成功"})
- } else {
- res, err := systemservice.GetSysDepartment(ctx, int32(id))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- arg := &db.UpdateSysDepartmentParams{
- ID: res.ID,
- Name: name,
- ParentID: int32(ParentID),
- ParentPath: fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID),
- Status: int32(status),
- Sort: int32(sort),
- UpdatedAt: time.Now(),
- }
- _, err = systemservice.UpdateSysDepartment(ctx, arg)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "更新成功"})
- }
-}
-
-func (h *SysDepartmentHandler) DTree(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- res, err := systemservice.DTreeSysDepartment(ctx, 0)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- rsp := tpl.ResponseDtree{
- Status: tpl.ResponseDtreeStatus{
- Code: 200,
- Message: "OK",
- },
- Data: res,
- }
- tpl.JSON(w, rsp)
-}
-
-func (h *SysDepartmentHandler) Refresh(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- err := systemservice.RefreshSysDepartment(ctx)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "刷新成功"})
-}
-
-func (h *SysDepartmentHandler) RebuildParentPath(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- err := systemservice.RebuildSysDepartmentParentPath(ctx)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "重建成功"})
-}
diff --git a/internal/router/manage/system/sys_menu.go b/internal/router/manage/system/sys_menu.go
deleted file mode 100644
index bc07ccd..0000000
--- a/internal/router/manage/system/sys_menu.go
+++ /dev/null
@@ -1,223 +0,0 @@
-package system
-
-import (
- "net/http"
- "strconv"
- "strings"
- "time"
-
- db "management/internal/db/sqlc"
- "management/internal/router/manage/util"
- systemservice "management/internal/service/system"
- "management/internal/tpl"
-
- "github.com/google/uuid"
-)
-
-type SysMenuHandler struct{}
-
-func NewSysMenuHandler() *SysMenuHandler {
- return &SysMenuHandler{}
-}
-
-func (h *SysMenuHandler) Tree(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- vars := r.URL.Query()
- id := util.DefaultInt(vars, "id", 0)
- res, err := systemservice.ToTreeMenu(ctx, id, true)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- tpl.JSON(w, res)
-}
-
-func (h *SysMenuHandler) List(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "menu/list.tmpl", nil)
-}
-
-func (h *SysMenuHandler) PostList(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- res, err := systemservice.ListMenuTree(ctx)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: 0,
- Data: res,
- }
- tpl.JSON(w, data)
-}
-
-func (h *SysMenuHandler) Add(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "menu/edit.tmpl", map[string]any{
- "Item": &db.SysMenu{Style: "pear-btn-primary pear-btn-sm", Visible: true, Sort: 6666},
- })
-}
-
-func (h *SysMenuHandler) AddChildren(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- parentID := util.DefaultInt(vars, "parentID", 0)
- vm := &db.SysMenu{ParentID: int32(parentID), Style: "pear-btn-primary pear-btn-sm", Visible: true, Sort: 6666}
- ctx := r.Context()
- parent, err := systemservice.GetSysMenu(ctx, int32(parentID))
- if err == nil {
- if parent.Type == "node" {
- vm.Type = "menu"
- } else if parent.Type == "menu" {
- vm.Type = "btn"
- }
- }
- tpl.HTML(w, r, "menu/edit.tmpl", map[string]any{
- "Item": vm,
- })
-}
-
-func (h *SysMenuHandler) Edit(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- id := util.DefaultInt(vars, "id", 0)
- vm := &db.SysMenu{Style: "pear-btn-primary pear-btn-sm", Sort: 6666}
- if id > 0 {
- ctx := r.Context()
- vm, _ = systemservice.GetSysMenu(ctx, int32(id))
- }
- tpl.HTML(w, r, "menu/edit.tmpl", map[string]any{
- "Item": vm,
- })
-}
-
-func (h *SysMenuHandler) Save(w http.ResponseWriter, r *http.Request) {
- id := util.ConvertInt(r.PostFormValue("ID"), 0)
- name := r.PostFormValue("Name")
- dispalyName := r.PostFormValue("DisplayName")
- t := r.PostFormValue("Type")
- url := r.PostFormValue("Url")
- if len(url) == 0 {
- url = uuid.Must(uuid.NewRandom()).String()
- }
- avatar := r.PostFormValue("Avatar")
- style := r.PostFormValue("Style")
- parentID := util.ConvertInt(r.PostFormValue("ParentID"), 0)
- visible := util.ConvertBool(r.PostFormValue("Visible"), false)
- isList := util.ConvertBool(r.PostFormValue("IsList"), false)
- sort := util.ConvertInt(r.PostFormValue("Sort"), 6666)
- status := util.ConvertInt(r.PostFormValue("Status"), 9999)
-
- ctx := r.Context()
- if len(avatar) > 0 && !strings.Contains(avatar, "layui-icon ") {
- avatar = "layui-icon " + avatar
- }
-
- parentPath := ""
- if parentID > 0 {
- parent, err := systemservice.GetSysMenu(ctx, int32(parentID))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
- parentPath = parent.ParentPath + "," + strconv.Itoa(parentID) + ","
- parentPath = strings.ReplaceAll(parentPath, ",,", ",")
- }
-
- if id == 0 {
- arg := &db.CreateSysMenuParams{
- Name: name,
- DisplayName: dispalyName,
- Url: url,
- Type: t,
- ParentID: int32(parentID),
- ParentPath: parentPath,
- Avatar: avatar,
- Style: style,
- Visible: visible,
- IsList: isList,
- Status: int32(status),
- Sort: int32(sort),
- CreatedAt: time.Now(),
- UpdatedAt: time.Now(),
- }
- _, err := systemservice.CreateSysMenu(ctx, arg)
- if err != nil {
- if db.IsUniqueViolation(err) {
- tpl.JSON(w, tpl.Response{Success: false, Message: "菜单已存在"})
- return
- }
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "添加成功"})
- } else {
- res, err := systemservice.GetSysMenu(ctx, int32(id))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- arg := &db.UpdateSysMenuParams{
- ID: res.ID,
- Name: name,
- DisplayName: dispalyName,
- Url: url,
- Type: t,
- ParentID: int32(parentID),
- ParentPath: parentPath,
- Avatar: avatar,
- Style: style,
- Visible: visible,
- IsList: isList,
- Status: int32(status),
- Sort: int32(sort),
- UpdatedAt: time.Now(),
- }
- _, err = systemservice.UpdateSysMenu(ctx, arg)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "更新成功"})
- }
-}
-
-func (h *SysMenuHandler) UserMenus(w http.ResponseWriter, r *http.Request) {
- // ctx := r.Context()
- // b := session.GetBytes(ctx, auth.StoreName)
- // var u dto.AuthorizeUser
- // if err := json.Unmarshal(b, &u); err != nil {
- // http.Error(w, err.Error(), http.StatusInternalServerError)
- // return
- // }
- // menus, err := systemservice.RecursiveSysMenus(ctx, u.RoleID)
- // if err != nil {
- // tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- // return
- // }
-
- tpl.JSON(w, nil)
-}
-
-func (h *SysMenuHandler) XmSelectTree(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- res, err := systemservice.ToTreeMenu(ctx, 0, false)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- tpl.JSON(w, res)
-}
-
-func (h *SysMenuHandler) Refresh(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- err := systemservice.RefreshMenus(ctx)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "刷新成功"})
-}
diff --git a/internal/router/manage/system/sys_role.go b/internal/router/manage/system/sys_role.go
deleted file mode 100644
index ad99603..0000000
--- a/internal/router/manage/system/sys_role.go
+++ /dev/null
@@ -1,300 +0,0 @@
-package system
-
-import (
- "fmt"
- "net/http"
- "strings"
- "time"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
- "management/internal/pkg/convertor"
- "management/internal/router/manage/util"
- systemservice "management/internal/service/system"
- "management/internal/tpl"
-)
-
-type SysRoleHandler struct{}
-
-func NewSysRoleHandler() *SysRoleHandler {
- return &SysRoleHandler{}
-}
-
-func (h *SysRoleHandler) List(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "role/list.tmpl", nil)
-}
-
-func (h *SysRoleHandler) PostList(w http.ResponseWriter, r *http.Request) {
- var q dto.SearchDto
- q.SearchStatus = convertor.ConvertInt(r.PostFormValue("status"), 9999)
- q.SearchParentID = convertor.ConvertInt(r.PostFormValue("parentId"), 0)
- q.SearchName = r.PostFormValue("name")
- q.SearchID = convertor.ConvertInt[int64](r.PostFormValue("id"), 0)
- q.Page = convertor.ConvertInt(r.PostFormValue("page"), 1)
- q.Rows = convertor.ConvertInt(r.PostFormValue("rows"), 10)
- res, count, err := systemservice.ListSysRoleCondition(r.Context(), q)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: count,
- Data: res,
- }
- tpl.JSON(w, data)
-}
-
-func (h *SysRoleHandler) Add(w http.ResponseWriter, r *http.Request) {
- vm := &db.SysRole{Sort: 6666}
- tpl.HTML(w, r, "role/edit.tmpl", map[string]any{
- "Item": vm,
- })
-}
-
-func (h *SysRoleHandler) Edit(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- id := util.DefaultInt(vars, "id", 0)
- vm := &db.SysRole{Sort: 6666}
- if id > 0 {
- ctx := r.Context()
- vm, _ = systemservice.GetSysRole(ctx, int32(id))
- }
- tpl.HTML(w, r, "role/edit.tmpl", map[string]any{
- "Item": vm,
- })
-}
-
-func (h *SysRoleHandler) Save(w http.ResponseWriter, r *http.Request) {
- id := util.ConvertInt(r.PostFormValue("ID"), 0)
- name := r.PostFormValue("Name")
- parentID := util.ConvertInt(r.PostFormValue("ParentID"), 0)
- displayName := r.PostFormValue("DisplayName")
- sort := util.ConvertInt(r.PostFormValue("Sort"), 6666)
- status := util.ConvertInt(r.PostFormValue("Status"), 9999)
-
- ctx := r.Context()
- var parent *db.SysRole
- if parentID > 0 {
- var err error
- parent, err = systemservice.GetSysRole(ctx, int32(parentID))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: "父级节点错误"})
- return
- }
- } else {
- parent = &db.SysRole{
- ID: 0,
- ParentID: 0,
- ParentPath: ",0,",
- }
- }
-
- if id == 0 {
- arg := &db.CreateSysRoleParams{
- Name: name,
- DisplayName: displayName,
- Vip: false,
- ParentID: parent.ID,
- ParentPath: fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID),
- Status: int32(status),
- CreatedAt: time.Now(),
- UpdatedAt: time.Now(),
- }
- _, err := systemservice.CreateSysRole(ctx, arg)
- if err != nil {
- if db.IsUniqueViolation(err) {
- tpl.JSON(w, tpl.Response{Success: false, Message: "角色名称已存在"})
- return
- }
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "添加成功"})
- } else {
- res, err := systemservice.GetSysRole(ctx, int32(id))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
- arg := &db.UpdateSysRoleParams{
- ID: res.ID,
- DisplayName: displayName,
- Sort: int32(sort),
- Status: int32(status),
- ParentID: parent.ID,
- ParentPath: fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID),
- UpdatedAt: time.Now(),
- }
- _, err = systemservice.UpdateSysRole(ctx, arg)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "更新成功"})
- }
-}
-
-func (h *SysRoleHandler) XmSelect(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- res, err := systemservice.XmSelectSysRole(ctx, 0)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- tpl.JSON(w, res)
-}
-
-func (h *SysRoleHandler) SetMenu(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- id := util.DefaultInt(vars, "id", 0)
- vm := struct {
- Role *db.SysRole
- Menus []*dto.SetMenuDto
- }{}
- if id > 0 {
- ctx := r.Context()
- var err error
- vm.Role, err = systemservice.GetSysRole(ctx, int32(id))
- if err == nil {
- vm.Menus, _ = systemservice.SetMenuViewData(ctx, vm.Role.ID)
- }
- }
-
- tpl.HTML(w, r, "role/set_menu.tmpl", map[string]any{
- "Item": vm,
- })
-}
-
-func (h *SysRoleHandler) PostSetMenu(w http.ResponseWriter, r *http.Request) {
- id := util.ConvertInt(r.PostFormValue("ID"), 0)
- menus := r.PostFormValue("roleMenu")
-
- if id == 0 {
- tpl.JSON(w, tpl.Response{Success: false, Message: "角色异常, 请刷新重试"})
- return
- }
-
- if len(menus) == 0 {
- tpl.JSON(w, tpl.Response{Success: false, Message: "请选择菜单"})
- return
- }
-
- ctx := r.Context()
- _, err := systemservice.GetSysRole(ctx, int32(id))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- menuArr := strings.Split(menus, ",")
- if len(menuArr) == 0 {
- tpl.JSON(w, tpl.Response{Success: false, Message: "请选择菜单"})
- return
- }
-
- var menuList []*db.SysMenu
- for _, v := range menuArr {
- menuID := util.ConvertInt(v, 0)
- if menuID > 0 {
- menu, err := systemservice.GetSysMenu(ctx, int32(menuID))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- menuList = append(menuList, menu)
- }
- }
-
- if len(menuList) == 0 {
- tpl.JSON(w, tpl.Response{Success: false, Message: "请选择正确的菜单"})
- return
- }
-
- err = systemservice.SetMenu(ctx, int32(id), menuList)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "设置成功"})
-}
-
-func (h *SysRoleHandler) DTree(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- res, err := systemservice.DTreeSysRole(ctx, 0)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- rsp := tpl.ResponseDtree{
- Status: tpl.ResponseDtreeStatus{
- Code: 200,
- Message: "OK",
- },
- Data: res,
- }
- tpl.JSON(w, rsp)
-}
-
-func (h *SysRoleHandler) Refresh(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- err := systemservice.RefreshSysRole(ctx)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "刷新成功"})
-}
-
-func (h *SysRoleHandler) RebuildParentPath(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- err := systemservice.RebuildSysRoleParentPath(ctx)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "重建成功"})
-}
-
-func (h *SysRoleHandler) RefreshRoleMenus(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
-
- // 获取需要刷新的角色ID
- roleID := util.ConvertInt(r.PostFormValue("roleID"), 0)
- sysRole, err := systemservice.GetSysRole(ctx, int32(roleID))
- if err != nil || sysRole == nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- // 刷新角色菜单 (角色所拥有的菜单集合)
- _, err = systemservice.SetOwnerListMenuByRoleID(ctx, sysRole.ID)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- // 刷新角色菜单 (角色所拥有的菜单集合)
- _, err = systemservice.SetOwnerMapMenuByRoleID(ctx, sysRole.ID)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- // 刷新角色菜单树 (pear admin layui 使用的格式)
- _, err = systemservice.SetRecursiveSysMenus(ctx, sysRole.ID)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "刷新成功"})
-}
diff --git a/internal/router/manage/system/sys_user.go b/internal/router/manage/system/sys_user.go
deleted file mode 100644
index 5a60b23..0000000
--- a/internal/router/manage/system/sys_user.go
+++ /dev/null
@@ -1,213 +0,0 @@
-package system
-
-import (
- "net/http"
- "time"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
- "management/internal/middleware/manage/auth"
- "management/internal/pkg/crypto"
- "management/internal/pkg/rand"
- "management/internal/router/manage/util"
- systemservice "management/internal/service/system"
- "management/internal/tpl"
-
- "github.com/google/uuid"
-)
-
-type SysUserHandler struct{}
-
-func NewSysUserHandler() *SysUserHandler {
- return &SysUserHandler{}
-}
-
-func (h *SysUserHandler) List(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "user/list.tmpl", nil)
-}
-
-func (h *SysUserHandler) PostList(w http.ResponseWriter, r *http.Request) {
- var q dto.SearchDto
- q.SearchStatus = util.ConvertInt(r.PostFormValue("SearchStatus"), 9999)
- q.SearchName = r.PostFormValue("SearchName")
- q.SearchKey = r.PostFormValue("SearchKey")
- q.Page = util.ConvertInt(r.PostFormValue("page"), 1)
- q.Rows = util.ConvertInt(r.PostFormValue("rows"), 10)
- ctx := r.Context()
- res, count, err := systemservice.ListSysUserCondition(ctx, q)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: count,
- Data: res,
- }
- tpl.JSON(w, data)
-}
-
-func (h *SysUserHandler) Add(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "user/edit.tmpl", map[string]any{
- "Item": &db.SysUser{
- HashedPassword: nil,
- },
- })
-}
-
-func (h *SysUserHandler) Edit(w http.ResponseWriter, r *http.Request) {
- vars := r.URL.Query()
- id := util.DefaultInt(vars, "id", 0)
- sysUser := &db.SysUser{}
- if id > 0 {
- ctx := r.Context()
- if user, err := systemservice.GetSysUser(ctx, int32(id)); err == nil {
- user.HashedPassword = nil
- sysUser = user
- }
- }
- tpl.HTML(w, r, "user/edit.tmpl", map[string]any{
- "Item": sysUser,
- })
-}
-
-func (h *SysUserHandler) Profile(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
- user := auth.AuthUser(ctx)
- vm, _ := systemservice.GetSysUser(ctx, user.ID)
- tpl.HTML(w, r, "user/profile.tmpl", map[string]any{
- "Item": vm,
- })
-}
-
-func (h *SysUserHandler) Save(w http.ResponseWriter, r *http.Request) {
- id := util.ConvertInt(r.PostFormValue("ID"), 0)
- email := r.PostFormValue("Email")
- username := r.PostFormValue("Username")
- password := r.PostFormValue("Password")
- changePassword := r.PostFormValue("ChangePassword")
- gender := util.ConvertInt(r.PostFormValue("Gender"), 0)
- avatar := r.PostFormValue("File")
- status := util.ConvertInt(r.PostFormValue("Status"), 9999)
-
- ctx := r.Context()
- departmentID := util.ConvertInt(r.PostFormValue("DepartmentID"), 0)
- var department *db.SysDepartment
- var err error
- if departmentID > 0 {
- department, err = systemservice.GetSysDepartment(ctx, int32(departmentID))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: "部门数据错误"})
- return
- }
- }
- var role *db.SysRole
- roleID := util.ConvertInt(r.PostFormValue("RoleID"), 0)
- if roleID > 0 {
- role, err = systemservice.GetSysRole(ctx, int32(roleID))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: "角色数据错误"})
- return
- }
- }
-
- if id == 0 {
- salt, err := rand.String(10)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- hashedPassword, err := crypto.BcryptHashPassword(password + salt)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- initTime, err := time.ParseInLocation(time.DateTime, "0001-01-01 00:00:00", time.Local)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
- arg := &db.CreateSysUserParams{
- Uuid: uuid.Must(uuid.NewV7()),
- Email: email,
- Username: username,
- HashedPassword: hashedPassword,
- Salt: salt,
- Avatar: avatar,
- Gender: int32(gender),
- DepartmentID: department.ID,
- RoleID: role.ID,
- Status: int32(status),
- ChangePasswordAt: initTime,
- CreatedAt: time.Now(),
- UpdatedAt: time.Now(),
- }
- _, err = systemservice.CreateSysUser(ctx, arg)
- if err != nil {
- if db.IsUniqueViolation(err) {
- tpl.JSON(w, tpl.Response{Success: false, Message: "数据已存在"})
- return
- }
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "添加成功"})
- } else {
- res, err := systemservice.GetSysUser(ctx, int32(id))
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- arg := &db.UpdateSysUserParams{
- ID: res.ID,
- Username: username,
- HashedPassword: res.HashedPassword,
- Avatar: avatar,
- Gender: int32(gender),
- DepartmentID: department.ID,
- RoleID: role.ID,
- Status: int32(status),
- ChangePasswordAt: res.ChangePasswordAt,
- UpdatedAt: time.Now(),
- }
- if changePassword == "on" {
- hashedPassword, err := crypto.BcryptHashPassword(password + res.Salt)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
- arg.HashedPassword = hashedPassword
- arg.ChangePasswordAt = time.Now()
- }
- _, err = systemservice.UpdateSysUser(ctx, arg)
- if err != nil {
- tpl.JSON(w, tpl.Response{Success: false, Message: err.Error()})
- return
- }
-
- tpl.JSON(w, tpl.Response{Success: true, Message: "更新成功"})
- }
-}
-
-func (h *SysUserHandler) XmSelect(w http.ResponseWriter, r *http.Request) {
- all, err := db.Engine.ListSysUser(r.Context())
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- var res []*dto.XmSelectInt32Dto
- for _, v := range all {
- res = append(res, &dto.XmSelectInt32Dto{
- Name: v.Username,
- Value: v.ID,
- })
- }
- tpl.JSON(w, res)
-}
diff --git a/internal/router/manage/system/sys_user_login_log.go b/internal/router/manage/system/sys_user_login_log.go
deleted file mode 100644
index e6dacaf..0000000
--- a/internal/router/manage/system/sys_user_login_log.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package system
-
-import (
- "net/http"
-
- "management/internal/db/model/dto"
- "management/internal/router/manage/util"
- systemservice "management/internal/service/system"
- "management/internal/tpl"
-)
-
-type SysUserLoginLogHandler struct{}
-
-func NewSysUserLoginLogHandler() *SysUserLoginLogHandler {
- return &SysUserLoginLogHandler{}
-}
-
-func (h *SysUserLoginLogHandler) List(w http.ResponseWriter, r *http.Request) {
- tpl.HTML(w, r, "login_log/list.tmpl", nil)
-}
-
-func (h *SysUserLoginLogHandler) PostList(w http.ResponseWriter, r *http.Request) {
- var q dto.SearchDto
- q.SearchTimeBegin, q.SearchTimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("SearchTimeBegin"), r.PostFormValue("SearchTimeEnd"))
- q.SearchName = r.PostFormValue("SearchName")
- q.SearchKey = r.PostFormValue("SearchKey")
- q.Page = util.ConvertInt(r.PostFormValue("page"), 1)
- q.Rows = util.ConvertInt(r.PostFormValue("rows"), 10)
- ctx := r.Context()
- res, count, err := systemservice.ListSysUserLoginLog(ctx, q)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- data := tpl.ResponseList{
- Code: 0,
- Message: "ok",
- Count: count,
- Data: res,
- }
- tpl.JSON(w, data)
-}
diff --git a/internal/router/manage/util/util.go b/internal/router/manage/util/util.go
deleted file mode 100644
index 99ea2b3..0000000
--- a/internal/router/manage/util/util.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package util
-
-import (
- "net/url"
- "strconv"
- "time"
-
- "github.com/jackc/pgx/v5/pgtype"
-)
-
-func DefaultStartTimeAndEndTime(start string, end string) (string, string) {
- if len(start) == 0 {
- start = "2000-01-01 00:00:00"
- }
- if len(end) == 0 {
- end = time.Now().Add(time.Hour * 24).Format(time.DateTime)
- }
- return start, end
-}
-
-func DefaultString(values url.Values, key, defaultValue string) string {
- v := values.Get(key)
- if len(v) == 0 {
- return defaultValue
- }
-
- return v
-}
-
-func DefaultInt(values url.Values, key string, defaultValue int) int {
- v := values.Get(key)
- if len(v) == 0 {
- return defaultValue
- }
-
- i, err := strconv.Atoi(v)
- if err != nil {
- return defaultValue
- }
-
- return i
-}
-
-func ConvertInt16(value string, defaultValue int16) int16 {
- i, err := strconv.Atoi(value)
- if err != nil {
- return defaultValue
- }
-
- return int16(i)
-}
-
-func ConvertInt32(value string, defaultValue int32) int32 {
- i, err := strconv.Atoi(value)
- if err != nil {
- return defaultValue
- }
-
- return int32(i)
-}
-
-func ConvertBool(value string, defaultValue bool) bool {
- b, err := strconv.ParseBool(value)
- if err != nil {
- return defaultValue
- }
-
- return b
-}
-
-func ConvertInt[T int | int16 | int32 | int64](value string, defaultValue T) T {
- i, err := strconv.Atoi(value)
- if err != nil {
- return defaultValue
- }
- return T(i)
-}
-
-func PgtypeNumericToFloat64(num pgtype.Numeric) float64 {
- f1, _ := num.Float64Value()
- f2, _ := f1.Value()
- return f2.(float64)
-}
diff --git a/internal/service/aliyunoss/aliyunoss.go b/internal/service/aliyunoss/aliyunoss.go
deleted file mode 100644
index c2e695d..0000000
--- a/internal/service/aliyunoss/aliyunoss.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package aliyunoss
-
-import (
- "bytes"
- "errors"
- "fmt"
- "io"
- "mime/multipart"
- "time"
-
- "management/internal/config"
-
- "github.com/aliyun/aliyun-oss-go-sdk/oss"
- "github.com/h2non/filetype"
- gonanoid "github.com/matoous/go-nanoid/v2"
-)
-
-var engine *oss.Client
-
-var AllowImageMaxSize int64 = 10485760
-
-func Init() error {
- var err error
- engine, err = oss.New(config.File.AliyunUpload.Endpoint, config.File.AliyunUpload.AccessKeyID, config.File.AliyunUpload.AccessKeySecret, oss.Timeout(10, 120))
- if err != nil {
- return err
- }
- return err
-}
-
-func UploadImage(file *multipart.FileHeader) (string, error) {
- if file.Size > AllowImageMaxSize {
- return "", errors.New("failed to receive image too large")
- }
-
- fileOpen, err := file.Open()
- if err != nil {
- return "", errors.New("failed to image open")
- }
- defer func(fileOpen multipart.File) {
- _ = fileOpen.Close()
- }(fileOpen)
-
- fileBytes, err := io.ReadAll(fileOpen)
- if err != nil {
- return "", errors.New("failed to read image")
- }
-
- if !filetype.IsImage(fileBytes) {
- return "", errors.New("failed to no image type")
- }
-
- kind, err := filetype.Match(fileBytes)
- if err != nil || kind == filetype.Unknown {
- return "", errors.New("failed to get image type")
- }
-
- imgPath := GenerateFilename(kind.Extension)
- err = PutObject(imgPath, fileBytes)
- if err != nil {
- return "", err
- }
- return imgPath, nil
-}
-
-func GenerateFilename(extension string) string {
- id, _ := gonanoid.New()
- return fmt.Sprintf("upload/%s/%s/%s/%s.%s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02"), id, extension)
-}
-
-func PutObject(path string, stream []byte) error {
- bucket, err := engine.Bucket(config.File.AliyunUpload.Bucket)
- if err != nil {
- return errors.New("failed to get bucket")
- }
-
- err = bucket.PutObject(path, bytes.NewReader(stream))
- if err != nil {
- return errors.New("failed to upload to oss")
- }
- return nil
-}
diff --git a/internal/service/applet/applet.go b/internal/service/applet/applet.go
deleted file mode 100644
index 525e215..0000000
--- a/internal/service/applet/applet.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package applet
-
-import (
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "time"
-
- "management/internal/config"
- "management/internal/pkg/fetcher"
- "management/internal/pkg/redis"
-)
-
-// var appletLoginErrs = map[int]string{
-// -1: "系统繁忙",
-// 40029: "js_code无效",
-// 45011: "API调用太频繁,请稍候再试",
-// 40226: "高风险等级用户,小程序登录拦截",
-// }
-
-type AppletLoginResponse struct {
- OpenID string `json:"openid"`
- SessionKey string `json:"session_key"`
- UnionID string `json:"unionid"`
- ErrCode int `json:"errcode"`
- ErrMsg string `json:"errmsg"`
-}
-
-func AppletLogin(code string) (*AppletLoginResponse, error) {
- url := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
- config.File.Applet.AppID, config.File.Applet.AppSecret, code)
- response, status, err := fetcher.Get(url, time.Second*3)
- if err != nil {
- return nil, err
- }
-
- if status != 200 {
- return nil, errors.New("请求失败")
- }
-
- var res AppletLoginResponse
- err = json.Unmarshal(response, &res)
- if err != nil {
- return nil, err
- }
- return &res, nil
-}
-
-type accessTokenResponse struct {
- AccessToken string `json:"access_token"`
- ExpiresIn int `json:"expires_in"`
-}
-
-func GetAccessToken(ctx context.Context) (string, error) {
- key := "token:" + config.File.Applet.AppID
- token, err := redis.Get(ctx, key)
- if err == nil && len(token) > 0 {
- return token, nil
- }
-
- url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
- config.File.Applet.AppID, config.File.Applet.AppSecret)
- response, status, err := fetcher.Get(url, time.Second*3)
- if err != nil {
- return "", err
- }
-
- if status != 200 {
- return "", errors.New("获取access token失败")
- }
-
- var res accessTokenResponse
- err = json.Unmarshal(response, &res)
- if err != nil {
- return "", err
- }
-
- redis.Set(ctx, key, res.AccessToken, time.Duration(res.ExpiresIn-100)*time.Second)
- return res.AccessToken, nil
-}
diff --git a/internal/service/budget/budget.go b/internal/service/budget/budget.go
deleted file mode 100644
index 69e1703..0000000
--- a/internal/service/budget/budget.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package budget
-
-import (
- "context"
- "strconv"
-
- db "management/internal/db/sqlc"
- "management/internal/global"
-)
-
-func AllBudgets(ctx context.Context, projectId int64) []*global.DataDict {
- pp, err := db.Engine.ListBudgets(ctx, projectId)
- if err != nil || len(pp) == 0 {
- return nil
- }
-
- var res []*global.DataDict
- res = append(res, &global.DataDict{
- Name: "请选择",
- Value: "0",
- })
- for _, v := range pp {
- item := global.DataDict{
- Name: v.Name,
- Value: strconv.Itoa(int(v.ID)),
- }
- res = append(res, &item)
- }
-
- return res
-}
diff --git a/internal/service/captcha/captcha.go b/internal/service/captcha/captcha.go
deleted file mode 100644
index 295c3ef..0000000
--- a/internal/service/captcha/captcha.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package captcha
-
-import "github.com/mojocn/base64Captcha"
-
-var captchaStore base64Captcha.Store = base64Captcha.DefaultMemStore
-
-func Generate(height int, width int, length int, maxSkew float64, dotCount int) (id, b64s, answer string, err error) {
- driver := base64Captcha.NewDriverDigit(height, width, length, maxSkew, dotCount)
- // driver := base64Captcha.NewDriverString(config.File.Captcha.ImgHeight,
- // config.File.Captcha.ImgWidth,
- // 6, 1, keyLong, source, nil, nil, nil)
- cp := base64Captcha.NewCaptcha(driver, captchaStore)
- return cp.Generate()
-}
-
-func Verify(id, answer string, clear bool) bool {
- return captchaStore.Verify(id, answer, clear)
-}
diff --git a/internal/service/category/category.go b/internal/service/category/category.go
deleted file mode 100644
index 82bd69e..0000000
--- a/internal/service/category/category.go
+++ /dev/null
@@ -1,340 +0,0 @@
-package category
-
-import (
- "context"
- "encoding/json"
- "errors"
- "strconv"
- "time"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
- "management/internal/global"
- "management/internal/global/keys"
- "management/internal/pkg/redis"
-)
-
-func ListCategoriesCondition(ctx context.Context, q dto.SearchDto) ([]*db.Category, int64, error) {
- countArg := &db.CountCategoriesConditionParams{
- IsStatus: q.SearchStatus != 9999,
- Status: int16(q.SearchStatus),
- IsID: q.SearchID != 0,
- ID: int32(q.SearchID),
- IsParentID: q.SearchParentID != 0 && q.SearchParentID != 1,
- ParentID: int32(q.SearchParentID),
- Name: q.SearchName,
- }
-
- dataArg := &db.ListCategoriesConditionParams{
- IsStatus: q.SearchStatus != 9999,
- Status: int16(q.SearchStatus),
- IsID: q.SearchID != 0,
- ID: int32(q.SearchID),
- IsParentID: q.SearchParentID != 0 && q.SearchParentID != 1,
- ParentID: int32(q.SearchParentID),
- Name: q.SearchName,
- Skip: (int32(q.Page) - 1) * int32(q.Rows),
- Size: int32(q.Rows),
- }
-
- count, err := db.Engine.CountCategoriesCondition(ctx, countArg)
- if err != nil {
- return nil, 0, err
- }
-
- categories, err := db.Engine.ListCategoriesCondition(ctx, dataArg)
- if err != nil {
- return nil, 0, err
- }
-
- return categories, count, nil
-}
-
-func DTreeCategory(ctx context.Context, id int32) ([]*dto.DTreeDto, error) {
- all, err := db.Engine.AllCategories(ctx)
- if err != nil {
- return nil, err
- }
-
- return toDtree(id, all), nil
-}
-
-func XmSelectCategory(ctx context.Context, id int32) ([]*dto.XmSelectTreeDto, error) {
- all, err := db.Engine.AllCategories(ctx)
- if err != nil {
- return nil, err
- }
-
- return toXmSelectTree(id, all), nil
-}
-
-func GetParentCategorySelectLetter(ctx context.Context, letter string) ([]*global.DataDict, error) {
- all := AllCategories(ctx)
- if len(all) == 0 {
- return nil, errors.New("请刷新类别缓存")
- }
-
- var current *db.Category
- for _, v := range all {
- if v.Letter == letter {
- current = v
- break
- }
- }
- if current == nil {
- return nil, errors.New("未找到当前类别")
- }
-
- var res []*global.DataDict
- res = append(res, &global.DataDict{
- Name: "请选择",
- Value: "0",
- })
- for _, v := range all {
- if v.ParentID == current.ID {
- item := global.DataDict{
- Name: v.Name,
- Value: strconv.Itoa(int(v.ID)),
- }
- res = append(res, &item)
- }
- }
-
- return res, nil
-}
-
-func ListByParentID(ctx context.Context, parentID int32) ([]*db.Category, error) {
- all := AllCategories(ctx)
- if len(all) == 0 {
- return nil, errors.New("请刷新类别缓存")
- }
- var res []*db.Category
- for _, v := range all {
- if v.ParentID == parentID {
- res = append(res, v)
- }
- }
- return res, nil
-}
-
-func ListByLetter(ctx context.Context, letter string) ([]*db.Category, error) {
- all := AllCategories(ctx)
- if len(all) == 0 {
- return nil, errors.New("请刷新类别缓存")
- }
- var current *db.Category
- for _, v := range all {
- if v.Letter == letter {
- current = v
- break
- }
- }
- if current == nil {
- return nil, errors.New("未找到当前类别")
- }
-
- var res []*db.Category
- for _, v := range all {
- if v.ParentID == current.ID {
- res = append(res, v)
- }
- }
- return res, nil
-}
-
-func GetParentCategorySelect(ctx context.Context, id int32) ([]*global.DataDict, error) {
- all := AllCategories(ctx)
- if len(all) == 0 {
- return nil, errors.New("请刷新类别缓存")
- }
-
- var res []*global.DataDict
- res = append(res, &global.DataDict{
- Name: "请选择",
- Value: "0",
- })
- for _, v := range all {
- if v.ParentID == id {
- item := global.DataDict{
- Name: v.Name,
- Value: strconv.Itoa(int(v.ID)),
- }
- res = append(res, &item)
- }
- }
-
- return res, nil
-}
-
-func toDtree(parentId int32, data []*db.Category) []*dto.DTreeDto {
- var res []*dto.DTreeDto
- for _, v := range data {
- if v.ParentID == parentId {
- item := dto.DTreeDto{}
- item.ID = strconv.FormatInt(int64(v.ID), 10)
- item.Title = v.Name
- item.Last = !hasChildren(v.ID, data)
- item.ParentId = strconv.FormatInt(int64(v.ParentID), 10)
- item.Children = toDtree(v.ID, data)
- if v.ParentID == 0 {
- item.Spread = true
- }
- res = append(res, &item)
- }
- }
-
- return res
-}
-
-func toXmSelectTree(parentId int32, data []*db.Category) []*dto.XmSelectTreeDto {
- var res []*dto.XmSelectTreeDto
- for _, v := range data {
- if v.ParentID == parentId {
- item := dto.XmSelectTreeDto{
- Name: v.Name,
- Value: strconv.FormatInt(int64(v.ID), 10),
- Children: toXmSelectTree(v.ID, data),
- }
- res = append(res, &item)
- }
- }
-
- return res
-}
-
-func hasChildren(parentId int32, data []*db.Category) bool {
- if len(data) > 0 {
- for _, v := range data {
- if v.ParentID == parentId {
- return true
- }
- }
- }
-
- return false
-}
-
-func RefreshCategory(ctx context.Context) error {
- all, err := db.Engine.AllCategories(ctx)
- if err != nil {
- return err
- }
-
- b, err := json.Marshal(all)
- if err != nil {
- return err
- }
-
- redis.Del(ctx, keys.GetManageKey(ctx, keys.AllCategorySimple))
- key := keys.GetManageKey(ctx, keys.AllCategories)
- err = redis.Set(ctx, key, b, time.Hour*6)
- return err
-}
-
-func AllCategories(ctx context.Context) []*db.Category {
- var res []*db.Category
- key := keys.GetManageKey(ctx, keys.AllCategories)
- b, err := redis.GetBytes(ctx, key)
- if err == nil {
- if err := json.Unmarshal(b, &res); err == nil {
- return res
- }
- }
-
- res, err = db.Engine.AllCategories(ctx)
- if err == nil {
- if b, err = json.Marshal(res); err == nil {
- redis.Set(ctx, key, b, time.Hour*6)
- }
- }
-
- return res
-}
-
-type CategorySet struct {
- Title string `json:"title"`
- Data []*CategoryItem `json:"data"`
-}
-
-type CategoryItem struct {
- ID int32 `json:"id"`
- Name string `json:"name"`
- Icon string `json:"icon"`
- Description string `json:"description"`
- Url string `json:"url"`
-}
-
-func AllCategoriesItem(ctx context.Context) []*CategoryItem {
- var res []*CategoryItem
- key := keys.GetManageKey(ctx, keys.AllCategorySimple)
- b, err := redis.GetBytes(ctx, key)
- if err == nil {
- if err = json.Unmarshal(b, &res); err == nil {
- return res
- }
- }
- all, err := db.Engine.AllCategories(ctx)
- if err != nil {
- return nil
- }
- for _, v := range all {
- res = append(res, &CategoryItem{
- ID: v.ID,
- Name: v.Name,
- })
- }
- b, err = json.Marshal(res)
- if err == nil {
- redis.Set(ctx, key, b, time.Hour*6)
- }
- return res
-}
-
-func ListCategoriesByParentID(ctx context.Context, parentID int) ([]*CategorySet, error) {
- var res []*CategorySet
- key := keys.GetManageKey(ctx, keys.ListCategoriesByParentID, parentID)
- b, err := redis.GetBytes(ctx, key)
- if err == nil {
- if err = json.Unmarshal(b, &res); err == nil {
- return res, nil
- }
- }
-
- all, err := db.Engine.ListCategoriesByPath(ctx, "%,"+strconv.Itoa(parentID)+",%")
- if err != nil {
- return nil, err
- }
-
- root := findCategoryItem(parentID, all)
- for _, v := range root {
- children := findCategoryItem(int(v.ID), all)
- if len(children) > 0 {
- res = append(res, &CategorySet{
- Title: v.Name,
- Data: children,
- })
- }
- }
-
- b, err = json.Marshal(res)
- if err == nil {
- redis.Set(ctx, key, b, time.Hour*6)
- }
-
- return res, nil
-}
-
-func findCategoryItem(parentID int, all []*db.Category) []*CategoryItem {
- var res []*CategoryItem
- for _, v := range all {
- if v.ParentID == int32(parentID) {
- item := CategoryItem{}
- item.ID = v.ID
- item.Name = v.Name
- item.Icon = v.Icon
- item.Description = v.Description
- res = append(res, &item)
- }
- }
- return res
-}
diff --git a/internal/service/project/project.go b/internal/service/project/project.go
deleted file mode 100644
index ff460bb..0000000
--- a/internal/service/project/project.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package project
-
-import (
- "context"
- "strconv"
-
- db "management/internal/db/sqlc"
- "management/internal/global"
-)
-
-func CreateProject(ctx context.Context, p *db.CreateProjectParams, pf []*db.CreateProjectFileParams) error {
- return db.Engine.ExecTx(ctx, func(q *db.Queries) error {
- _, err := q.CreateProject(ctx, p)
- if err != nil {
- return err
- }
-
- for _, item := range pf {
- _, err = q.CreateProjectFile(ctx, item)
- if err != nil {
- return err
- }
- }
-
- return nil
- })
-}
-
-func UpdateProject(ctx context.Context, p *db.UpdateProjectParams, pf []*db.CreateProjectFileParams) error {
- return db.Engine.ExecTx(ctx, func(q *db.Queries) error {
- _, err := q.UpdateProject(ctx, p)
- if err != nil {
- return err
- }
-
- err = q.DeleteProjectFile(ctx, p.ID)
- if err != nil {
- return err
- }
-
- for _, item := range pf {
- _, err = q.CreateProjectFile(ctx, item)
- if err != nil {
- return err
- }
- }
-
- return nil
- })
-}
-
-func AllProjects(ctx context.Context) []*global.DataDict {
- pp, err := db.Engine.AllProjects(ctx)
- if err != nil || len(pp) == 0 {
- return nil
- }
-
- var res []*global.DataDict
- res = append(res, &global.DataDict{
- Name: "请选择",
- Value: "0",
- })
- for _, v := range pp {
- item := global.DataDict{
- Name: v.Name,
- Value: strconv.Itoa(int(v.ID)),
- }
- res = append(res, &item)
- }
-
- return res
-}
diff --git a/internal/service/system/auth.go b/internal/service/system/auth.go
deleted file mode 100644
index 9b140a3..0000000
--- a/internal/service/system/auth.go
+++ /dev/null
@@ -1 +0,0 @@
-package system
diff --git a/internal/service/system/sys_audit_log.go b/internal/service/system/sys_audit_log.go
deleted file mode 100644
index e49b3ff..0000000
--- a/internal/service/system/sys_audit_log.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package system
-
-import (
- "context"
- "strings"
- "time"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
-)
-
-func CreateSysAuditLog(ctx context.Context, arg *db.CreateSysAuditLogParams) error {
- return db.Engine.CreateSysAuditLog(ctx, arg)
-}
-
-func ListSysAuditLog(ctx context.Context, q dto.SearchDto) ([]*db.SysAuditLog, int64, error) {
- start, err := time.ParseInLocation(time.DateTime, q.SearchTimeBegin, time.Local)
- if err != nil {
- return nil, 0, err
- }
- end, err := time.ParseInLocation(time.DateTime, q.SearchTimeEnd, time.Local)
- if err != nil {
- return nil, 0, err
- }
-
- countArg := &db.CountSysAuditLogConditionParams{
- StartAt: start,
- EndAt: end,
- }
-
- dataArg := &db.ListSysAuditLogConditionParams{
- StartAt: start,
- EndAt: end,
- Skip: (int32(q.Page) - 1) * int32(q.Rows),
- Size: int32(q.Rows),
- }
-
- if len(q.SearchKey) > 0 {
- switch strings.ToLower(q.SearchName) {
- case "email":
- countArg.Email = q.SearchKey
- dataArg.Email = q.SearchKey
- case "username":
- countArg.Username = q.SearchKey
- dataArg.Username = q.SearchKey
- }
- }
- count, err := db.Engine.CountSysAuditLogCondition(ctx, countArg)
- if err != nil {
- return nil, 0, err
- }
-
- audits, err := db.Engine.ListSysAuditLogCondition(ctx, dataArg)
- if err != nil {
- return nil, 0, err
- }
-
- return audits, count, nil
-}
diff --git a/internal/service/system/sys_config.go b/internal/service/system/sys_config.go
deleted file mode 100644
index bfb2cf2..0000000
--- a/internal/service/system/sys_config.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package system
-
-import (
- "context"
- "encoding/json"
- "time"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
- "management/internal/global/keys"
- "management/internal/global/pearadmin"
- "management/internal/pkg/redis"
-)
-
-func CreateSysConfig(ctx context.Context, arg *db.CreateSysConfigParams) error {
- return db.Engine.CreateSysConfig(ctx, arg)
-}
-
-func UpdateSysConfigByKey(ctx context.Context, arg *db.UpdateSysConfigByKeyParams) error {
- return db.Engine.UpdateSysConfigByKey(ctx, arg)
-}
-
-func GetSysConfig(ctx context.Context, id int32) (*db.SysConfig, error) {
- return db.Engine.GetSysConfig(ctx, id)
-}
-
-func GetSysConfigByKey(ctx context.Context, key string) (*db.SysConfig, error) {
- return db.Engine.GetSysConfigByKey(ctx, key)
-}
-
-func PearConfig(ctx context.Context) (*dto.PearConfig, error) {
- // 判断redis是否存储
- key := keys.GetManageKey(ctx, keys.PearAdmin)
- b, err := redis.GetBytes(ctx, key)
- if err == nil {
- var res *dto.PearConfig
- if err := json.Unmarshal(b, &res); err == nil {
- return res, nil
- }
- }
-
- conf, err := db.Engine.GetSysConfigByKey(ctx, pearadmin.PearKey)
- if err != nil {
- return nil, err
- }
-
- var pear dto.PearConfig
- if err := json.Unmarshal(conf.Value, &pear); err != nil {
- return nil, err
- }
-
- _ = redis.Set(ctx, key, conf.Value, time.Hour*6)
- return &pear, nil
-}
-
-func ListSysConfigCondition(ctx context.Context, q dto.SearchDto) ([]*db.SysConfig, int64, error) {
- count, err := db.Engine.CountSysConfigCondition(ctx, q.SearchKey)
- if err != nil {
- return nil, 0, err
- }
-
- configs, err := db.Engine.ListSysConfigCondition(ctx, &db.ListSysConfigConditionParams{
- Key: q.SearchKey,
- Skip: (int32(q.Page) - 1) * int32(q.Rows),
- Size: int32(q.Rows),
- })
- if err != nil {
- return nil, 0, err
- }
-
- return configs, count, nil
-}
diff --git a/internal/service/system/sys_department.go b/internal/service/system/sys_department.go
deleted file mode 100644
index 95021eb..0000000
--- a/internal/service/system/sys_department.go
+++ /dev/null
@@ -1,232 +0,0 @@
-package system
-
-import (
- "context"
- "encoding/json"
- "strconv"
- "strings"
- "time"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
- "management/internal/global/keys"
- "management/internal/pkg/redis"
-)
-
-func CreateSysDepartment(ctx context.Context, arg *db.CreateSysDepartmentParams) (*db.SysDepartment, error) {
- return db.Engine.CreateSysDepartment(ctx, arg)
-}
-
-func UpdateSysDepartment(ctx context.Context, arg *db.UpdateSysDepartmentParams) (*db.SysDepartment, error) {
- return db.Engine.UpdateSysDepartment(ctx, arg)
-}
-
-func GetSysDepartment(ctx context.Context, id int32) (*db.SysDepartment, error) {
- return db.Engine.GetSysDepartment(ctx, id)
-}
-
-func AllCache(ctx context.Context) ([]*db.SysDepartment, error) {
- key := keys.GetManageKey(ctx, keys.AllDepartments)
- b, err := redis.GetBytes(ctx, key)
- if err == nil {
- var res []*db.SysDepartment
- if err := json.Unmarshal(b, &res); err == nil {
- return res, nil
- }
- }
-
- all, err := db.Engine.AllSysDepartment(ctx)
- if err != nil {
- return nil, err
- }
-
- b, err = json.Marshal(all)
- if err != nil {
- return nil, err
- }
-
- _ = redis.Set(ctx, key, b, time.Hour*6)
- return all, nil
-}
-
-func ListSysDepartmentCondition(ctx context.Context, q dto.SearchDto) ([]*db.SysDepartment, int64, error) {
- countArg := &db.CountSysDepartmentConditionParams{
- IsStatus: q.SearchStatus != 9999,
- Status: int32(q.SearchStatus),
- IsParentID: q.SearchParentID != 0,
- ParentID: int32(q.SearchParentID),
- }
-
- dataArg := &db.ListSysDepartmentConditionParams{
- IsStatus: q.SearchStatus != 9999,
- Status: int32(q.SearchStatus),
- IsParentID: q.SearchParentID != 0,
- ParentID: int32(q.SearchParentID),
- Skip: (int32(q.Page) - 1) * int32(q.Rows),
- Size: int32(q.Rows),
- }
-
- if len(q.SearchKey) > 0 {
- switch strings.ToLower(q.SearchName) {
- case "id":
- id, err := strconv.Atoi(q.SearchKey)
- if err == nil {
- countArg.IsID = true
- countArg.ID = int32(id)
-
- dataArg.IsID = true
- dataArg.ID = int32(id)
- }
- case "name":
- countArg.Name = q.SearchKey
- dataArg.Name = q.SearchKey
- }
- }
- count, err := db.Engine.CountSysDepartmentCondition(ctx, countArg)
- if err != nil {
- return nil, 0, err
- }
-
- departs, err := db.Engine.ListSysDepartmentCondition(ctx, dataArg)
- if err != nil {
- return nil, 0, err
- }
-
- return departs, count, nil
-}
-
-func ListTreeSysDepartment(ctx context.Context) ([]*db.SysDepartmentDto, error) {
- all, err := db.Engine.ListSysDepartment(ctx)
- if err != nil {
- return nil, err
- }
-
- return ToDtoTreeSysDepartment(0, all), nil
-}
-
-func DTreeSysDepartment(ctx context.Context, id int32) ([]*dto.DTreeDto, error) {
- all, err := db.Engine.AllSysDepartment(ctx)
- if err != nil {
- return nil, err
- }
-
- return toDtree(id, all), nil
-}
-
-func RebuildSysDepartmentParentPath(ctx context.Context) error {
- return db.Engine.SysDepartmentRebuildPath(ctx)
-}
-
-func toDtree(parentId int32, data []*db.SysDepartment) []*dto.DTreeDto {
- var res []*dto.DTreeDto
- for _, v := range data {
- if v.ParentID == parentId {
- item := dto.DTreeDto{}
- item.ID = strconv.FormatInt(int64(v.ID), 10)
- item.Title = v.Name
- item.Last = !hasChildren(v.ID, data)
- item.ParentId = strconv.FormatInt(int64(v.ParentID), 10)
- item.Children = toDtree(v.ID, data)
- res = append(res, &item)
- }
- }
-
- return res
-}
-
-func hasChildren(parentId int32, data []*db.SysDepartment) bool {
- if len(data) > 0 {
- for _, v := range data {
- if v.ParentID == parentId {
- return true
- }
- }
- }
-
- return false
-}
-
-func ToTreeSysDepartment(ctx context.Context, id int, isRoot bool) ([]*dto.TreeDto, error) {
- all, err := db.Engine.AllSysDepartment(ctx)
- if err != nil {
- return nil, err
- }
-
- if isRoot {
- root := getSysDepartmentRootParentId(int32(id), all)
- if root == nil {
- root = &dto.TreeDto{
- ID: 0,
- Title: "根节点",
- }
- }
-
- root.Children = toDtoTreeSysDepartment(int32(id), all)
- return []*dto.TreeDto{root}, nil
- }
-
- return toDtoTreeSysDepartment(int32(id), all), nil
-}
-
-func RefreshSysDepartment(ctx context.Context) error {
- all, err := db.Engine.AllSysDepartment(ctx)
- if err != nil {
- return err
- }
-
- b, err := json.Marshal(all)
- if err != nil {
- return err
- }
-
- key := keys.GetManageKey(ctx, keys.AllDepartments)
- err = redis.Set(ctx, key, b, time.Hour*6)
- return err
-}
-
-func getSysDepartmentRootParentId(parentId int32, data []*db.SysDepartment) *dto.TreeDto {
- for _, v := range data {
- if v.ID == parentId {
- return &dto.TreeDto{
- ID: int(v.ID),
- Title: v.Name,
- }
- }
- }
- return nil
-}
-
-func ToDtoTreeSysDepartment(parentId int32, data []*db.SysDepartment) []*db.SysDepartmentDto {
- var res []*db.SysDepartmentDto
- for _, v := range data {
- if v.ParentID == parentId {
- item := db.SysDepartmentDto{}
- item.ID = v.ID
- item.Name = v.Name
- item.ParentID = v.ParentID
- item.ParentPath = v.ParentPath
- item.Status = v.Status
- item.CreatedAt = v.CreatedAt
- item.UpdatedAt = v.UpdatedAt
- item.Children = ToDtoTreeSysDepartment(v.ID, data)
- res = append(res, &item)
- }
- }
-
- return res
-}
-
-func toDtoTreeSysDepartment(parentId int32, data []*db.SysDepartment) []*dto.TreeDto {
- var res []*dto.TreeDto
- for _, v := range data {
- if v.ParentID == parentId {
- item := dto.TreeDto{}
- item.ID = int(v.ID)
- item.Title = v.Name
- item.Children = toDtoTreeSysDepartment(v.ID, data)
- res = append(res, &item)
- }
- }
-
- return res
-}
diff --git a/internal/service/system/sys_menu.go b/internal/service/system/sys_menu.go
deleted file mode 100644
index 0058541..0000000
--- a/internal/service/system/sys_menu.go
+++ /dev/null
@@ -1,568 +0,0 @@
-package system
-
-import (
- "context"
- "encoding/json"
- "strconv"
- "strings"
- "time"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
- "management/internal/global/keys"
- "management/internal/pkg/redis"
-)
-
-func CreateSysMenu(ctx context.Context, arg *db.CreateSysMenuParams) (*db.SysMenu, error) {
- return db.Engine.CreateSysMenu(ctx, arg)
-}
-
-func UpdateSysMenu(ctx context.Context, arg *db.UpdateSysMenuParams) (*db.SysMenu, error) {
- return db.Engine.UpdateSysMenu(ctx, arg)
-}
-
-func GetSysMenu(ctx context.Context, id int32) (*db.SysMenu, error) {
- return db.Engine.GetSysMenu(ctx, id)
-}
-
-func GetSysMenuByUrl(ctx context.Context, url string) (*db.SysMenu, error) {
- return db.Engine.GetSysMenuByUrl(ctx, url)
-}
-
-func ListSysMenuByRoleID(ctx context.Context, roleID int32) ([]*db.SysMenu, error) {
- return db.Engine.ListSysMenuByRoleID(ctx, roleID)
-}
-
-func AllMenusCache(ctx context.Context) ([]*db.SysMenu, error) {
- key := keys.GetManageKey(ctx, keys.AllMenus)
- b, err := redis.GetBytes(ctx, key)
- if err == nil {
- var res []*db.SysMenu
- if err := json.Unmarshal(b, &res); err == nil {
- return res, nil
- }
- }
-
- all, err := db.Engine.AllSysMenu(ctx)
- if err != nil {
- return nil, err
- }
-
- b, err = json.Marshal(all)
- if err != nil {
- return nil, err
- }
-
- _ = redis.Set(ctx, key, b, time.Hour*6)
- return all, nil
-}
-
-func ListMenuTree(ctx context.Context) ([]*db.SysMenuDto, error) {
- all, err := AllMenusCache(ctx)
- if err != nil {
- return nil, err
- }
-
- return toTreeSysMenu(0, all), nil
-}
-
-func ListMenuByRoles(ctx context.Context, roles []*db.SysRole) ([]*db.SysMenu, error) {
- // 判断角色是否有vip
- var vip bool
- for _, item := range roles {
- if item.Vip {
- vip = true
- break
- }
- }
-
- var err error
- var userMenus []*db.SysMenu
- if vip {
- userMenus, err = AllMenusCache(ctx)
- if err != nil {
- return nil, err
- }
- } else {
- for _, item := range roles {
- ums, err := db.Engine.ListSysMenuByRoleID(ctx, item.ID)
- if err != nil {
- return nil, err
- }
- userMenus = append(userMenus, ums...)
- }
- }
-
- return userMenus, nil
-}
-
-func IListMenuByUserID(ctx context.Context, userID int32) ([]*db.SysMenu, error) {
- // 判断redis是否存储
- key := keys.GetManageKey(ctx, keys.AdminMenus, userID)
- b, err := redis.GetBytes(ctx, key)
- if err == nil {
- var res []*db.SysMenu
- if err := json.Unmarshal(b, &res); err == nil {
- return res, nil
- }
- }
-
- return SetListMenuByUserID(ctx, userID)
-}
-
-func SetListMenuByUserID(ctx context.Context, userID int32) ([]*db.SysMenu, error) {
- // 判断当前用户是否有vip角色
- role, err := db.Engine.GetSysRoleByUserID(ctx, userID)
- if err != nil {
- return nil, err
- }
-
- var e error
- var menus []*db.SysMenu
- if role.Vip {
- // vip 用户
- menus, e = db.Engine.AllSysMenu(ctx)
- if e != nil {
- return nil, err
- }
-
- } else {
- // not vip
- menus, e = db.Engine.AllSysMenu(ctx) // db.Engine.ListSysMenuByUserID(ctx, userID)
- if e != nil {
- return nil, err
- }
- }
-
- b, err := json.Marshal(menus)
- if err != nil {
- return nil, err
- }
-
- key := keys.GetManageKey(ctx, keys.AdminMenus, userID)
- _ = redis.Set(ctx, key, b, time.Hour*6)
- return menus, nil
-}
-
-func MapOwnerMenuByRoleID(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error) {
- // 判断redis是否存储
- key := keys.GetManageKey(ctx, keys.OwnerMenus, roleID)
- b, err := redis.GetBytes(ctx, key)
- if err == nil {
- var res map[string]*dto.OwnerMenuDto
- if err := json.Unmarshal(b, &res); err == nil {
- return res, nil
- }
- }
-
- return SetOwnerMapMenuByRoleID(ctx, roleID)
-}
-
-func ListOwnerMenuByRoleID(ctx context.Context, roleID int32) ([]*dto.OwnerMenuDto, error) {
- // 判断redis是否存储
- key := keys.GetManageKey(ctx, keys.OwnerMenus, roleID)
- b, err := redis.GetBytes(ctx, key)
- if err == nil {
- var res []*dto.OwnerMenuDto
- if err := json.Unmarshal(b, &res); err == nil {
- return res, nil
- }
- }
-
- return SetOwnerListMenuByRoleID(ctx, roleID)
-}
-
-func ownerMenusByRoleID(ctx context.Context, roleID int32) ([]*db.SysMenu, error) {
- // 判断当前用户是否有vip角色
- role, err := db.Engine.GetSysRole(ctx, roleID)
- if err != nil {
- return nil, err
- }
-
- var e error
- var menus []*db.SysMenu
- if role.Vip {
- // vip 用户
- menus, e = db.Engine.AllSysMenu(ctx)
- if e != nil {
- return nil, err
- }
-
- } else {
- // not vip
- menus, e = db.Engine.ListSysMenuByRoleID(ctx, roleID)
- if e != nil {
- return nil, err
- }
- }
-
- return menus, nil
-}
-
-func SetOwnerListMenuByRoleID(ctx context.Context, roleID int32) ([]*dto.OwnerMenuDto, error) {
- menus, err := ownerMenusByRoleID(ctx, roleID)
- if err != nil {
- return nil, err
- }
-
- var res []*dto.OwnerMenuDto
- for _, menu := range menus {
- res = append(res, &dto.OwnerMenuDto{
- ID: menu.ID,
- DisplayName: menu.DisplayName,
- Url: menu.Url,
- ParentID: menu.ParentID,
- Avatar: menu.Avatar,
- Style: menu.Style,
- IsList: menu.IsList,
- })
- }
-
- b, err := json.Marshal(res)
- if err != nil {
- return nil, err
- }
-
- key := keys.GetManageKey(ctx, keys.OwnerMenus, roleID)
- _ = redis.Set(ctx, key, b, time.Hour*6)
- return res, nil
-}
-
-func SetOwnerMapMenuByRoleID(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error) {
- result := make(map[string]*dto.OwnerMenuDto)
- menus, err := ownerMenusByRoleID(ctx, roleID)
- if err != nil {
- return result, err
- }
-
- for _, menu := range menus {
- result[menu.Url] = &dto.OwnerMenuDto{
- ID: menu.ID,
- DisplayName: menu.DisplayName,
- Url: menu.Url,
- ParentID: menu.ParentID,
- Avatar: menu.Avatar,
- Style: menu.Style,
- IsList: menu.IsList,
- }
- }
-
- b, err := json.Marshal(result)
- if err != nil {
- return nil, err
- }
-
- key := keys.GetManageKey(ctx, keys.OwnerMenus, roleID)
- _ = redis.Set(ctx, key, b, time.Hour*6)
- return result, nil
-}
-
-// RecursiveSysMenus 递归查询菜单 (pear layui 展示菜单的格式)
-func RecursiveSysMenus(ctx context.Context, roleID int32) ([]*dto.MenuUIDto, error) {
- // 判断redis是否存储
- key := keys.GetManageKey(ctx, keys.RecursiveMenus, roleID)
- b, err := redis.GetBytes(ctx, key)
- if err == nil {
- var res []*dto.MenuUIDto
- if err := json.Unmarshal(b, &res); err == nil {
- return res, nil
- }
- }
-
- return SetRecursiveSysMenus(ctx, roleID)
-}
-
-func SetRecursiveSysMenus(ctx context.Context, roleID int32) ([]*dto.MenuUIDto, error) {
- // 判断当前用户是否有vip角色
- role, err := db.Engine.GetSysRole(ctx, roleID)
- if err != nil {
- return nil, err
- }
-
- var menus []*db.SysMenu
- if role.Vip {
- // vip 用户
- all, err := db.Engine.RecursiveSysMenus(ctx)
- if err != nil {
- return nil, err
- }
- menus = convertToMenuUIDto(all)
-
- } else {
- // not vip
- all, err := db.Engine.RecursiveSysMenusByRoleID(ctx, roleID)
- if err != nil {
- return nil, err
- }
- menus = convertToMenuUIDto2(all)
- }
- menuList := uniqueSysMenus(menus)
- if len(menuList) == 0 {
- return nil, nil
- }
-
- tree := convertToUITree(menuList, 0)
- b, err := json.Marshal(tree)
- if err != nil {
- return nil, err
- }
-
- key := keys.GetManageKey(ctx, keys.RecursiveMenus, roleID)
- _ = redis.Set(ctx, key, b, time.Hour*6)
- return tree, nil
-}
-
-func convertToMenuUIDto(data []*db.RecursiveSysMenusRow) []*db.SysMenu {
- var res []*db.SysMenu
-
- for _, item := range data {
- temp := &db.SysMenu{
- ID: item.ID,
- Name: item.Name,
- DisplayName: item.DisplayName,
- Url: item.Url,
- Type: item.Type,
- ParentID: item.ParentID,
- ParentPath: item.ParentPath,
- Avatar: item.Avatar,
- Style: item.Style,
- Visible: item.Visible,
- IsList: item.IsList,
- Status: item.Status,
- Sort: item.Sort,
- CreatedAt: item.CreatedAt,
- UpdatedAt: item.UpdatedAt,
- }
- res = append(res, temp)
- }
-
- return res
-}
-
-func convertToMenuUIDto2(data []*db.RecursiveSysMenusByRoleIDRow) []*db.SysMenu {
- var res []*db.SysMenu
-
- for _, item := range data {
- temp := &db.SysMenu{
- ID: item.ID,
- Name: item.Name,
- DisplayName: item.DisplayName,
- Url: item.Url,
- Type: item.Type,
- ParentID: item.ParentID,
- ParentPath: item.ParentPath,
- Avatar: item.Avatar,
- Style: item.Style,
- Visible: item.Visible,
- IsList: item.IsList,
- Status: item.Status,
- Sort: item.Sort,
- CreatedAt: item.CreatedAt,
- UpdatedAt: item.UpdatedAt,
- }
- res = append(res, temp)
- }
-
- return res
-}
-
-func convertToUITree(data []*db.SysMenu, parentID int32) []*dto.MenuUIDto {
- var root []*dto.MenuUIDto
- for _, item := range data {
- if item.ParentID == parentID {
- if item.IsList {
- temp := &dto.MenuUIDto{
- ID: strings.ToLower(item.Url),
- Title: item.DisplayName,
- Icon: item.Avatar,
- Type: 1,
- OpenType: "_iframe",
- // OpenType: "_component",
- Href: item.Url,
- }
- root = append(root, temp)
- } else {
- temp := &dto.MenuUIDto{
- ID: strconv.Itoa(int(item.ID)),
- Title: item.DisplayName,
- Icon: item.Avatar,
- Type: 0,
- }
- temp.Children = convertToUITree(data, item.ID)
- root = append(root, temp)
- }
- }
- }
- return root
-}
-
-func uniqueSysMenus(sm []*db.SysMenu) []*db.SysMenu {
- res := make([]*db.SysMenu, 0) // 返回的新切片
- m1 := make(map[int32]byte) // 用来去重的临时map
- for _, v := range sm {
- if _, ok := m1[v.ID]; !ok {
- m1[v.ID] = 1
- res = append(res, v)
- }
- }
- return res
-}
-
-func ToTreeMenu(ctx context.Context, id int, hasRoot bool) ([]*dto.TreeDto, error) {
- all, err := AllMenusCache(ctx)
- if err != nil {
- return nil, err
- }
-
- if hasRoot {
- root := getSysMenuRootParentId(int32(id), all)
- if root == nil {
- root = &dto.TreeDto{
- ID: 0,
- Title: "根节点",
- }
- }
-
- root.Children = toDtoTreeSysMenu(int32(id), all)
- return []*dto.TreeDto{root}, nil
- }
-
- return toDtoTreeSysMenu(int32(id), all), nil
-}
-
-func RefreshMenus(ctx context.Context) error {
- key := keys.GetManageKey(ctx, keys.AllMenus)
- all, err := db.Engine.AllSysMenu(ctx)
- if err != nil {
- return err
- }
-
- b, err := json.Marshal(all)
- if err != nil {
- return err
- }
-
- err = redis.Set(ctx, key, b, time.Hour*6)
- return err
-}
-
-func getSysMenuRootParentId(parentId int32, data []*db.SysMenu) *dto.TreeDto {
- for _, v := range data {
- if v.ID == parentId {
- return &dto.TreeDto{
- ID: int(v.ID),
- Title: v.Name,
- }
- }
- }
- return nil
-}
-
-func toTreeSysMenu(parentId int32, data []*db.SysMenu) []*db.SysMenuDto {
- var res []*db.SysMenuDto
- for _, v := range data {
- if v.ParentID == parentId {
- item := db.SysMenuDto{}
- item.ID = v.ID
- item.Name = v.Name
- item.DisplayName = v.DisplayName
- item.Url = v.Url
- item.Type = v.Type
- item.ParentID = v.ParentID
- item.ParentPath = v.ParentPath
- item.Avatar = v.Avatar
- item.Style = v.Style
- item.Visible = v.Visible
- item.IsList = v.IsList
- item.Status = v.Status
- item.Sort = v.Sort
- item.CreatedAt = v.CreatedAt
- item.UpdatedAt = v.UpdatedAt
- item.Children = toTreeSysMenu(v.ID, data)
- res = append(res, &item)
- }
- }
-
- return res
-}
-
-func toDtoTreeSysMenu(parentId int32, data []*db.SysMenu) []*dto.TreeDto {
- var res []*dto.TreeDto
- for _, v := range data {
- if v.ParentID == parentId {
- item := dto.TreeDto{}
- item.ID = int(v.ID)
- item.Title = v.Name
- item.Children = toDtoTreeSysMenu(v.ID, data)
- res = append(res, &item)
- }
- }
-
- return res
-}
-
-func SetMenuViewData(ctx context.Context, roleID int32) ([]*dto.SetMenuDto, error) {
- // 获取该用户已经有的权限
- hs, err := db.Engine.ListSysMenuIDByRoleID(ctx, roleID)
- if err != nil {
- return nil, err
- }
-
- all, err := AllMenusCache(ctx)
- if err != nil {
- return nil, err
- }
-
- return toSetMenuTree(all, hs, 0), nil
-}
-
-func toSetMenuTree(data []*db.SysMenu, ids []int32, parentID int32) []*dto.SetMenuDto {
- var res []*dto.SetMenuDto
- for _, v := range data {
- if v.ParentID == parentID {
- isSelect := hasValueInArray(ids, v.ID)
- if v.IsList {
- item := dto.SetMenuDto{
- ID: v.ID,
- Name: v.DisplayName,
- Link: v.Type,
- IsList: v.IsList,
- IsSelect: isSelect,
- }
- item.Items = []*dto.SetMenuDto{
- {
- ID: v.ID,
- Name: "列表",
- Link: "btn",
- IsList: false,
- IsSelect: isSelect,
- Items: toSetMenuTree(data, ids, v.ID),
- },
- }
- item.Items = append(item.Items, toSetMenuTree(data, ids, v.ID)...)
- res = append(res, &item)
- } else {
- item := dto.SetMenuDto{
- ID: v.ID,
- Name: v.DisplayName,
- Link: v.Type,
- IsList: v.IsList,
- IsSelect: isSelect,
- Items: toSetMenuTree(data, ids, v.ID),
- }
- res = append(res, &item)
- }
- }
- }
-
- return res
-}
-
-func hasValueInArray(data []int32, id int32) bool {
- for _, v := range data {
- if id == v {
- return true
- }
- }
- return false
-}
diff --git a/internal/service/system/sys_role.go b/internal/service/system/sys_role.go
deleted file mode 100644
index 4f99ea1..0000000
--- a/internal/service/system/sys_role.go
+++ /dev/null
@@ -1,164 +0,0 @@
-package system
-
-import (
- "context"
- "encoding/json"
- "strconv"
- "time"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
- "management/internal/global/keys"
- "management/internal/pkg/redis"
-)
-
-func CreateSysRole(ctx context.Context, arg *db.CreateSysRoleParams) (*db.SysRole, error) {
- return db.Engine.CreateSysRole(ctx, arg)
-}
-
-func UpdateSysRole(ctx context.Context, arg *db.UpdateSysRoleParams) (*db.SysRole, error) {
- return db.Engine.UpdateSysRole(ctx, arg)
-}
-
-func GetSysRole(ctx context.Context, id int32) (*db.SysRole, error) {
- return db.Engine.GetSysRole(ctx, id)
-}
-
-func ListSysRoleCondition(ctx context.Context, q dto.SearchDto) ([]*db.SysRole, int64, error) {
- countArg := &db.CountSysRoleConditionParams{
- IsStatus: q.SearchStatus != 9999,
- Status: int32(q.SearchStatus),
- IsID: q.SearchID != 0,
- ID: int32(q.SearchID),
- IsParentID: q.SearchParentID != 0,
- ParentID: int32(q.SearchParentID),
- DisplayName: q.SearchName,
- }
-
- dataArg := &db.ListSysRoleConditionParams{
- IsStatus: q.SearchStatus != 9999,
- Status: int32(q.SearchStatus),
- IsID: q.SearchID != 0,
- ID: int32(q.SearchID),
- IsParentID: q.SearchParentID != 0,
- ParentID: int32(q.SearchParentID),
- DisplayName: q.SearchName,
- Skip: (int32(q.Page) - 1) * int32(q.Rows),
- Size: int32(q.Rows),
- }
- count, err := db.Engine.CountSysRoleCondition(ctx, countArg)
- if err != nil {
- return nil, 0, err
- }
-
- roles, err := db.Engine.ListSysRoleCondition(ctx, dataArg)
- if err != nil {
- return nil, 0, err
- }
-
- return roles, count, nil
-}
-
-func XmSelectSysRole(ctx context.Context, id int32) ([]*dto.XmSelectTreeDto, error) {
- all, err := db.Engine.AllSysRole(ctx)
- if err != nil {
- return nil, err
- }
-
- return toXmSelectTree(id, all), nil
-}
-
-func toXmSelectTree(parentId int32, data []*db.SysRole) []*dto.XmSelectTreeDto {
- var res []*dto.XmSelectTreeDto
- for _, v := range data {
- if v.ParentID == parentId {
- item := dto.XmSelectTreeDto{
- Name: v.Name,
- Value: strconv.FormatInt(int64(v.ID), 10),
- Children: toXmSelectTree(v.ID, data),
- }
- res = append(res, &item)
- }
- }
-
- return res
-}
-
-func SetMenu(ctx context.Context, roleID int32, menus []*db.SysMenu) error {
- return db.Engine.ExecTx(ctx, func(q *db.Queries) error {
- err := db.Engine.DeleteRoleMneuByRoleID(ctx, roleID)
- if err != nil {
- return err
- }
-
- for _, m := range menus {
- err := db.Engine.CreateRoleMenu(ctx, &db.CreateRoleMenuParams{
- RoleID: roleID,
- MenuID: m.ID,
- })
- if err != nil {
- return err
- }
- }
-
- return nil
- })
-}
-
-func DTreeSysRole(ctx context.Context, id int32) ([]*dto.DTreeDto, error) {
- all, err := db.Engine.AllSysRole(ctx)
- if err != nil {
- return nil, err
- }
-
- return toDtreeSysRole(id, all), nil
-}
-
-func RefreshSysRole(ctx context.Context) error {
- all, err := db.Engine.AllSysRole(ctx)
- if err != nil {
- return err
- }
-
- b, err := json.Marshal(all)
- if err != nil {
- return err
- }
-
- key := keys.GetManageKey(ctx, keys.AllRoles)
- err = redis.Set(ctx, key, b, time.Hour*6)
- return err
-}
-
-func RebuildSysRoleParentPath(ctx context.Context) error {
- return db.Engine.SysRoleRebuildPath(ctx)
-}
-
-func toDtreeSysRole(parentId int32, data []*db.SysRole) []*dto.DTreeDto {
- var res []*dto.DTreeDto
- for _, v := range data {
- if v.ParentID == parentId {
- item := dto.DTreeDto{}
- item.ID = strconv.FormatInt(int64(v.ID), 10)
- item.Title = v.DisplayName
- item.Last = !hasSysRoleChildren(v.ID, data)
- item.ParentId = strconv.FormatInt(int64(v.ParentID), 10)
- item.Children = toDtreeSysRole(v.ID, data)
- res = append(res, &item)
- }
- }
-
- return res
-}
-
-func hasSysRoleChildren(parentId int32, data []*db.SysRole) bool {
- if len(data) > 0 {
- for _, v := range data {
- if v.ParentID == parentId {
- return true
- }
- }
- }
-
- return false
-}
diff --git a/internal/service/system/sys_user.go b/internal/service/system/sys_user.go
deleted file mode 100644
index 7761ce0..0000000
--- a/internal/service/system/sys_user.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package system
-
-import (
- "context"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
-)
-
-func CreateSysUser(ctx context.Context, arg *db.CreateSysUserParams) (*db.SysUser, error) {
- return db.Engine.CreateSysUser(ctx, arg)
-}
-
-func UpdateSysUser(ctx context.Context, arg *db.UpdateSysUserParams) (*db.SysUser, error) {
- return db.Engine.UpdateSysUser(ctx, arg)
-}
-
-func GetSysUser(ctx context.Context, id int32) (*db.SysUser, error) {
- return db.Engine.GetSysUser(ctx, id)
-}
-
-func GetSysUserByEmail(ctx context.Context, email string) (*db.SysUser, error) {
- return db.Engine.GetSysUserByEmail(ctx, email)
-}
-
-func ListSysUserCondition(ctx context.Context, q dto.SearchDto) ([]*db.ListSysUserConditionRow, int64, error) {
- count, err := db.Engine.CountSysUserCondition(ctx, &db.CountSysUserConditionParams{
- IsStatus: q.SearchStatus != 9999,
- Status: int32(q.SearchStatus),
- Username: q.SearchKey,
- })
- if err != nil {
- return nil, 0, err
- }
-
- users, err := db.Engine.ListSysUserCondition(ctx, &db.ListSysUserConditionParams{
- IsStatus: q.SearchStatus != 9999,
- Status: int32(q.SearchStatus),
- Username: q.SearchKey,
- Skip: (int32(q.Page) - 1) * int32(q.Rows),
- Size: int32(q.Rows),
- })
- if err != nil {
- return nil, 0, err
- }
-
- return users, count, nil
-}
diff --git a/internal/service/system/sys_user_login_log.go b/internal/service/system/sys_user_login_log.go
deleted file mode 100644
index 70e8250..0000000
--- a/internal/service/system/sys_user_login_log.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package system
-
-import (
- "context"
- "strings"
- "time"
-
- "management/internal/db/model/dto"
- db "management/internal/db/sqlc"
-)
-
-func CreateSysUserLoginLog(ctx context.Context, arg *db.CreateSysUserLoginLogParams) error {
- return db.Engine.CreateSysUserLoginLog(ctx, arg)
-}
-
-func ListSysUserLoginLog(ctx context.Context, q dto.SearchDto) ([]*db.SysUserLoginLog, int64, error) {
- start, err := time.ParseInLocation(time.DateTime, q.SearchTimeBegin, time.Local)
- if err != nil {
- return nil, 0, err
- }
- end, err := time.ParseInLocation(time.DateTime, q.SearchTimeEnd, time.Local)
- if err != nil {
- return nil, 0, err
- }
-
- countArg := &db.CountSysUserLoginLogConditionParams{
- StartAt: start,
- EndAt: end,
- }
-
- dataArg := &db.ListSysUserLoginLogConditionParams{
- StartAt: start,
- EndAt: end,
- Skip: (int32(q.Page) - 1) * int32(q.Rows),
- Size: int32(q.Rows),
- }
-
- if len(q.SearchKey) > 0 {
- switch strings.ToLower(q.SearchName) {
- case "email":
- countArg.Email = q.SearchKey
- dataArg.Email = q.SearchKey
- case "username":
- countArg.Username = q.SearchKey
- dataArg.Username = q.SearchKey
- }
- }
- count, err := db.Engine.CountSysUserLoginLogCondition(ctx, countArg)
- if err != nil {
- return nil, 0, err
- }
-
- logs, err := db.Engine.ListSysUserLoginLogCondition(ctx, dataArg)
- if err != nil {
- return nil, 0, err
- }
-
- return logs, count, nil
-}
diff --git a/internal/service/tencentoss/tencentoss.go b/internal/service/tencentoss/tencentoss.go
deleted file mode 100644
index fbd3fad..0000000
--- a/internal/service/tencentoss/tencentoss.go
+++ /dev/null
@@ -1,162 +0,0 @@
-package tencentoss
-
-import (
- "bytes"
- "context"
- "errors"
- "fmt"
- "io"
- "io/fs"
- "mime/multipart"
- "net/http"
- "net/url"
- "os"
- "path"
-
- "management/internal/config"
- fileutil "management/internal/pkg/file"
-
- "github.com/h2non/filetype"
- "github.com/tencentyun/cos-go-sdk-v5"
-)
-
-var engine *cos.Client
-
-func Init() error {
- u, err := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", config.File.TencentUpload.Bucket, config.File.TencentUpload.Region))
- if err != nil {
- return err
- }
-
- b := &cos.BaseURL{BucketURL: u}
- engine = cos.NewClient(b, &http.Client{
- Transport: &cos.AuthorizationTransport{
- // 通过环境变量获取密钥
- // 环境变量 SECRETID 表示用户的 SecretId,登录访问管理控制台查看密钥,https://console.cloud.tencent.com/cam/capi
- SecretID: config.File.TencentUpload.AccessKeyID, // 用户的 SecretId,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
- // 环境变量 SECRETKEY 表示用户的 SecretKey,登录访问管理控制台查看密钥,https://console.cloud.tencent.com/cam/capi
- SecretKey: config.File.TencentUpload.AccessKeySecret, // 用户的 SecretKey,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
- },
- })
-
- return nil
-}
-
-func UploadFile(ctx context.Context, file *multipart.FileHeader, t fileutil.FileType) (string, error) {
- if file.Size > config.File.TencentUpload.AllowFileMaxSize {
- return "", errors.New("failed to receive file too large")
- }
-
- fileOpen, err := file.Open()
- if err != nil {
- return "", errors.New("failed to file open")
- }
- defer func(fileOpen multipart.File) {
- _ = fileOpen.Close()
- }(fileOpen)
-
- fileBytes, err := io.ReadAll(fileOpen)
- if err != nil {
- return "", errors.New("failed to read file")
- }
-
- if t == fileutil.IMG {
- // 判断是不是图片
- if !filetype.IsImage(fileBytes) {
- return "", fileutil.ErrUnsupported
- }
- }
-
- kind, err := filetype.Match(fileBytes)
- if err != nil || kind == filetype.Unknown {
- return "", errors.New("failed to get file type")
- }
-
- filename := fileutil.GenFilename(kind.Extension)
- imgPath := path.Join(fileutil.GetPath(), filename)
- _, err = engine.Object.Put(ctx, imgPath, bytes.NewReader(fileBytes), nil)
- if err != nil {
- return "", err
- }
-
- return imgPath, nil
-}
-
-func UploadFileOther(ctx context.Context, p string, t fileutil.FileType) (string, error) {
- file, err := os.Open(p)
- if err != nil {
- return "", err
- }
- defer func(file *os.File) {
- _ = file.Close()
- }(file)
-
- fileBytes, err := io.ReadAll(file)
- if err != nil {
- return "", errors.New("failed to read file")
- }
-
- if t == fileutil.IMG {
- // 判断是不是图片
- if !filetype.IsImage(fileBytes) {
- return "", fileutil.ErrUnsupported
- }
- }
-
- kind, err := filetype.Match(fileBytes)
- if err != nil || kind == filetype.Unknown {
- return "", errors.New("failed to get file type")
- }
-
- filename := fileutil.GenFilename(kind.Extension)
- imgPath := path.Join(fileutil.GetPath(), filename)
- _, err = engine.Object.Put(ctx, imgPath, bytes.NewReader(fileBytes), nil)
- if err != nil {
- return "", err
- }
-
- return imgPath, nil
-}
-
-func UploadFileByFS(ctx context.Context, file fs.File, t fileutil.FileType) (string, error) {
- fileBytes, err := io.ReadAll(file)
- if err != nil {
- return "", errors.New("failed to read file")
- }
-
- if t == fileutil.IMG {
- // 判断是不是图片
- if !filetype.IsImage(fileBytes) {
- return "", fileutil.ErrUnsupported
- }
- }
-
- kind, err := filetype.Match(fileBytes)
- if err != nil || kind == filetype.Unknown {
- return "", errors.New("failed to get file type")
- }
-
- filename := fileutil.GenFilename(kind.Extension)
- imgPath := path.Join(fileutil.GetPath(), filename)
- _, err = engine.Object.Put(ctx, imgPath, bytes.NewReader(fileBytes), nil)
- if err != nil {
- return "", err
- }
-
- return imgPath, nil
-}
-
-func DownloadFile(ctx context.Context, name string) ([]byte, error) {
- resp, err := engine.Object.Get(ctx, name, nil)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- bs, err := io.ReadAll(resp.Body)
- if err != nil {
- return nil, err
- }
-
- return bs, nil
-}
diff --git a/internal/tpl/html.go b/internal/tpl/html.go
deleted file mode 100644
index 7a5dcf9..0000000
--- a/internal/tpl/html.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package tpl
-
-import (
- "bytes"
- "net/http"
- "path/filepath"
- "strings"
-
- "management/internal/db/model/dto"
-)
-
-type TemplateConfig struct {
- Root string
- Extension string
- Layout string
- Partial string
-}
-
-type HtmlData struct {
- IsAuthenticated bool
- AuthorizeUser dto.AuthorizeUser
- AuthorizeMenus []*dto.OwnerMenuDto
- Data any
-}
-
-func HTML(w http.ResponseWriter, r *http.Request, tpl string, data map[string]any) {
- rndr.HTML(w, r, tpl, data)
-}
-
-func (r *render) HTML(w http.ResponseWriter, req *http.Request, tpl string, data map[string]any) {
- name := strings.ReplaceAll(tpl, "/", "_")
- t, ok := r.templates[name]
- if !ok {
- http.Error(w, "template is empty", http.StatusInternalServerError)
- return
- }
-
- hd := r.setDefaultData(req, data)
-
- buf := new(bytes.Buffer)
- err := t.ExecuteTemplate(buf, filepath.Base(tpl), hd)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- _, err = buf.WriteTo(w)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-}
diff --git a/internal/tpl/html_btn.go b/internal/tpl/html_btn.go
deleted file mode 100644
index 9ee3b97..0000000
--- a/internal/tpl/html_btn.go
+++ /dev/null
@@ -1,91 +0,0 @@
-package tpl
-
-import (
- "html/template"
- "path/filepath"
- "strings"
-
- "management/internal/db/model/dto"
-)
-
-func (r *render) btnFuncs() map[string]any {
- res := make(map[string]any, 3)
-
- res["genBtn"] = func(btns []*dto.OwnerMenuDto, actionNames ...string) template.HTML {
- if len(btns) == 0 {
- return template.HTML("")
- }
-
- var res string
- for _, action := range actionNames {
- for _, btn := range btns {
- btn.Style = strings.ReplaceAll(btn.Style, "pear", "layui")
- base := filepath.Base(btn.Url)
- if base == action {
- res += ``
- }
- }
- }
-
- return template.HTML(res)
- }
-
- res["genLink"] = func(btns []*dto.OwnerMenuDto, actionNames ...string) template.HTML {
- if len(btns) == 0 {
- return template.HTML("")
- }
-
- var res string
- for _, action := range actionNames {
- for _, btn := range btns {
- btn.Style = strings.ReplaceAll(btn.Style, "pear", "layui")
- base := filepath.Base(btn.Url)
- if base == action {
- res += ``
- }
- }
- }
-
- return template.HTML(res)
- }
-
- res["previewPicture"] = func(name string) template.HTML {
- var res string
- res += ``
-
- return template.HTML(res)
- }
-
- res["submitBtn"] = func(btns []*dto.OwnerMenuDto, actionNames ...string) template.HTML {
- if len(btns) == 0 {
- return template.HTML("")
- }
-
- var res string
- for _, action := range actionNames {
- for _, btn := range btns {
- btn.Style = strings.ReplaceAll(btn.Style, "pear", "layui")
- base := filepath.Base(btn.Url)
- if base == action {
- res += ``
- }
- }
- }
-
- return template.HTML(res)
- }
-
- return res
-}
diff --git a/internal/tpl/html_method.go b/internal/tpl/html_method.go
deleted file mode 100644
index 36accad..0000000
--- a/internal/tpl/html_method.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package tpl
-
-import (
- "html/template"
- "strings"
- "time"
-)
-
-func (r *render) Methods() map[string]any {
- res := make(map[string]any, 1)
-
- res["dateFormat"] = func(dt time.Time) template.HTML {
- return template.HTML(dt.Format(time.DateTime))
- }
-
- res["today"] = func() template.HTML {
- return template.HTML(time.Now().Format("2006-01-02"))
- }
-
- res["threeMonth"] = func() template.HTML {
- return template.HTML(time.Now().AddDate(0, 3, 0).Format("2006-01-02"))
- }
-
- res["yearBegin"] = func() template.HTML {
- dt := time.Now()
- t := dt.AddDate(0, -int(dt.Month())+1, -dt.Day()+1)
- return template.HTML(t.Format("2006-01-02") + " 00:00:00")
- }
-
- res["monthBegin"] = func() template.HTML {
- dt := time.Now()
- t := dt.AddDate(0, 0, -dt.Day()+1)
- return template.HTML(t.Format("2006-01-02") + " 00:00:00")
- }
-
- res["monthEnd"] = func() template.HTML {
- dt := time.Now()
- t := dt.AddDate(0, 0, -dt.Day()+1).AddDate(0, 1, -1)
- return template.HTML(t.Format("2006-01-02") + " 23:59:59")
- }
-
- res["trimSpace"] = func(s string) template.HTML {
- return template.HTML(strings.TrimSpace(s))
- }
-
- res["expandTags"] = func(s []string) template.HTML {
- if len(s) == 0 {
- return template.HTML("")
- }
- if len(s) == 1 && s[0] == "all" {
- return template.HTML("")
- }
- return template.HTML(strings.Join(s, ","))
- }
-
- return res
-}
diff --git a/internal/tpl/json.go b/internal/tpl/json.go
deleted file mode 100644
index 1570cff..0000000
--- a/internal/tpl/json.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package tpl
-
-import (
- "encoding/json"
- "net/http"
-)
-
-type Response struct {
- Success bool `json:"success"`
- Message string `json:"msg"`
- Data any `json:"data"`
-}
-
-type ResponseDtree struct {
- Status ResponseDtreeStatus `json:"status"`
- Data any `json:"data"`
-}
-
-type ResponseDtreeStatus struct {
- Code int `json:"code"`
- Message string `json:"message"`
-}
-
-type ResponseList struct {
- Code int `json:"code"`
- Message string `json:"msg"`
- Count int64 `json:"count"`
- Data any `json:"data"`
-}
-
-func JSON(w http.ResponseWriter, data any) {
- rndr.JSON(w, data)
-}
-
-func JSONF(w http.ResponseWriter, success bool, message string) {
- rndr.JSONF(w, success, message)
-}
-
-func JSONOK(w http.ResponseWriter, message string) {
- rndr.JSONOK(w, message)
-}
-
-func JSONERR(w http.ResponseWriter, message string) {
- rndr.JSONERR(w, message)
-}
-
-func (r *render) JSONF(w http.ResponseWriter, success bool, message string) {
- r.JSON(w, Response{Success: success, Message: message})
-}
-
-func (r *render) JSONOK(w http.ResponseWriter, message string) {
- r.JSON(w, Response{Success: true, Message: message})
-}
-
-func (r *render) JSONERR(w http.ResponseWriter, message string) {
- r.JSON(w, Response{Success: false, Message: message})
-}
-
-func (r *render) JSON(w http.ResponseWriter, data any) {
- v, err := json.Marshal(data)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- w.Header().Set("Content-Type", "application/json; charset=utf-8")
- w.WriteHeader(http.StatusOK)
- _, err = w.Write(v)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-}
diff --git a/internal/tpl/render.go b/internal/tpl/render.go
deleted file mode 100644
index c7fbb6a..0000000
--- a/internal/tpl/render.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package tpl
-
-import (
- "html/template"
- "net/http"
-
- "management/internal/pkg/session"
-)
-
-var rndr Renderer
-
-type Renderer interface {
- HTML(w http.ResponseWriter, req *http.Request, name string, data map[string]any)
- JSON(w http.ResponseWriter, data any)
- JSONF(w http.ResponseWriter, success bool, message string)
- JSONOK(w http.ResponseWriter, message string)
- JSONERR(w http.ResponseWriter, message string)
-}
-
-type render struct {
- session session.ISession
- config *TemplateConfig
- templates map[string]*template.Template
-}
-
-func New(session session.ISession) (Renderer, error) {
- render := &render{
- session: session,
- config: &TemplateConfig{
- Root: ".",
- Extension: ".tmpl",
- Layout: "base",
- Partial: "partial",
- },
- }
-
- templates, err := render.createTemplateCache()
- if err != nil {
- return nil, err
- }
-
- render.templates = templates
- return render, nil
-}
diff --git a/internal/tpl/util.go b/internal/tpl/util.go
deleted file mode 100644
index 068c88e..0000000
--- a/internal/tpl/util.go
+++ /dev/null
@@ -1,182 +0,0 @@
-package tpl
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "html/template"
- "io/fs"
- "net/http"
- "os"
- "path/filepath"
- "slices"
- "strings"
-
- "management/internal/db/model/dto"
- "management/internal/global/auth"
- systemservice "management/internal/service/system"
- templates "management/web/templates/manage"
-
- "github.com/justinas/nosurf"
-)
-
-func (r *render) setDefaultData(req *http.Request, data map[string]any) map[string]any {
- if data == nil {
- data = make(map[string]any)
- }
-
- ctx := req.Context()
- isAuth := r.session.Exists(ctx, auth.StoreName)
- data["IsAuthenticated"] = isAuth
- if isAuth {
- var authUser dto.AuthorizeUser
- u := r.session.GetBytes(ctx, auth.StoreName)
- _ = json.Unmarshal(u, &authUser)
-
- data["AuthorizeMenus"] = r.getCurrentPathBtns(ctx, authUser.RoleID, req.URL.Path)
- }
- token := nosurf.Token(req)
- data["CsrfToken"] = token
- data["CsrfTokenField"] = template.HTML(fmt.Sprintf(``, token))
-
- return data
-}
-
-func (r *render) getCurrentPathBtns(ctx context.Context, roleID int32, path string) []*dto.OwnerMenuDto {
- var res []*dto.OwnerMenuDto
-
- // 获取当前path的菜单
- menu, err := systemservice.GetSysMenuByUrl(ctx, path)
- if err != nil {
- return res
- }
-
- // 获取权限
- menus, err := systemservice.ListOwnerMenuByRoleID(ctx, roleID)
- if err != nil {
- return res
- }
-
- for _, item := range menus {
- if menu.IsList {
- if item.ParentID == menu.ID || item.ID == menu.ID {
- res = append(res, item)
- }
- } else {
- if item.ParentID == menu.ParentID {
- res = append(res, item)
- }
- }
- }
-
- return res
-}
-
-func (r *render) createTemplateCache() (map[string]*template.Template, error) {
- cache := make(map[string]*template.Template)
- pages, err := getFiles(r.config.Root, r.config.Extension)
- if err != nil {
- return nil, err
- }
-
- layoutAndPartial, err := r.getLayoutAndPartials()
- if err != nil {
- return nil, err
- }
-
- for _, page := range pages {
- if strings.HasPrefix(page, "base") || strings.HasSuffix(page, "partial") {
- continue
- }
-
- name := filepath.Base(page)
- pathArr := strings.Split(page, "/")
- dir := pathArr[len(pathArr)-2 : len(pathArr)-1]
- templateName := fmt.Sprintf("%s_%s", dir[0], name)
- ts := template.Must(template.New(templateName).Funcs(r.btnFuncs()).Funcs(r.Methods()).ParseFS(templates.TemplateFS, page))
- if err != nil {
- return nil, err
- }
-
- ts, err = ts.ParseFS(templates.TemplateFS, layoutAndPartial...)
- if err != nil {
- return nil, err
- }
-
- cache[templateName] = ts
- }
-
- return cache, nil
-}
-
-func (r *render) getLayoutAndPartials() ([]string, error) {
- layouts, err := getFiles(r.config.Layout, r.config.Extension)
- if err != nil {
- return nil, err
- }
-
- partials, err := getFiles(r.config.Partial, r.config.Extension)
- if err != nil {
- return nil, err
- }
-
- return slices.Concat(layouts, partials), nil
-}
-
-func getFiles(path string, stuffix string) ([]string, error) {
- files := make([]string, 0)
- b, err := pathExists(templates.TemplateFS, path)
- if err != nil {
- return nil, err
- }
-
- if !b {
- return files, nil
- }
-
- err = fs.WalkDir(templates.TemplateFS, path, func(path string, d fs.DirEntry, err error) error {
- if err != nil {
- return err
- }
- if d.IsDir() {
- return nil
- }
- if strings.HasSuffix(path, stuffix) {
- files = append(files, path)
- }
- return nil
- })
- // err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
- // if info == nil {
- // return err
- // }
- // if info.IsDir() {
- // return nil
- // }
- // // 将模板后缀的文件放到列表
- // if strings.HasSuffix(path, stuffix) {
- // files = append(files, path)
- // }
- // return nil
- // })
- return files, err
-}
-
-func pathExists(fs fs.FS, path string) (bool, error) {
- _, err := fs.Open(path)
- if err != nil {
- if os.IsNotExist(err) {
- return false, nil
- }
- return false, err
- }
- return true, err
-}
-
-func firstLower(s string) string {
- if len(s) == 0 {
- return s
- }
-
- return strings.ToLower(s[:1]) + s[1:]
-}
diff --git a/management b/management
index 028aeb2..de06472 100755
Binary files a/management and b/management differ
diff --git a/web/templates/manage/budget/edit.tmpl b/web/templates/manage/budget/edit.tmpl
index a9af92a..669f5e9 100644
--- a/web/templates/manage/budget/edit.tmpl
+++ b/web/templates/manage/budget/edit.tmpl
@@ -137,7 +137,7 @@