diff --git a/backend/__debug_bin3277441022 b/backend/__debug_bin2556343980 similarity index 81% rename from backend/__debug_bin3277441022 rename to backend/__debug_bin2556343980 index 26d1c22..a5ff30d 100755 Binary files a/backend/__debug_bin3277441022 and b/backend/__debug_bin2556343980 differ diff --git a/backend/database/migrations/20241212111730_alter_tenants.sql b/backend/database/migrations/20241212111730_alter_tenants.sql index 2512d58..84ce208 100644 --- a/backend/database/migrations/20241212111730_alter_tenants.sql +++ b/backend/database/migrations/20241212111730_alter_tenants.sql @@ -2,9 +2,11 @@ -- +goose StatementBegin -- add column bind_user_id to tenants ALTER TABLE tenants ADD COLUMN bind_user_id INT8 NOT NULL DEFAULT 0; +ALTER TABLE tenants ADD COLUMN bind_user_contact varchar(128) NOT NULL DEFAULT ''; -- +goose StatementEnd -- +goose Down -- +goose StatementBegin -DROP COLUMN bind_user_id FROM tenants; +ALTER TABLE tenants DROP COLUMN bind_user_id ; +ALTER TABLE tenants DROP COLUMN bind_user_contact ; -- +goose StatementEnd diff --git a/backend/database/models/qvyun/public/model/tenants.go b/backend/database/models/qvyun/public/model/tenants.go index b6bbccd..ea6a615 100644 --- a/backend/database/models/qvyun/public/model/tenants.go +++ b/backend/database/models/qvyun/public/model/tenants.go @@ -12,12 +12,13 @@ import ( ) type Tenants struct { - ID int64 `sql:"primary_key" json:"id"` - Name string `json:"name"` - Slug string `json:"slug"` - Description *string `json:"description"` - ExpireAt time.Time `json:"expire_at"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - BindUserID int64 `json:"bind_user_id"` + ID int64 `sql:"primary_key" json:"id"` + Name string `json:"name"` + Slug string `json:"slug"` + Description *string `json:"description"` + ExpireAt time.Time `json:"expire_at"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + BindUserID int64 `json:"bind_user_id"` + BindUserContact string `json:"bind_user_contact"` } diff --git a/backend/database/models/qvyun/public/table/tenants.go b/backend/database/models/qvyun/public/table/tenants.go index d185886..0d9ecab 100644 --- a/backend/database/models/qvyun/public/table/tenants.go +++ b/backend/database/models/qvyun/public/table/tenants.go @@ -17,14 +17,15 @@ type tenantsTable struct { postgres.Table // Columns - ID postgres.ColumnInteger - Name postgres.ColumnString - Slug postgres.ColumnString - Description postgres.ColumnString - ExpireAt postgres.ColumnTimestamp - CreatedAt postgres.ColumnTimestamp - UpdatedAt postgres.ColumnTimestamp - BindUserID postgres.ColumnInteger + ID postgres.ColumnInteger + Name postgres.ColumnString + Slug postgres.ColumnString + Description postgres.ColumnString + ExpireAt postgres.ColumnTimestamp + CreatedAt postgres.ColumnTimestamp + UpdatedAt postgres.ColumnTimestamp + BindUserID postgres.ColumnInteger + BindUserContact postgres.ColumnString AllColumns postgres.ColumnList MutableColumns postgres.ColumnList @@ -65,30 +66,32 @@ func newTenantsTable(schemaName, tableName, alias string) *TenantsTable { func newTenantsTableImpl(schemaName, tableName, alias string) tenantsTable { var ( - IDColumn = postgres.IntegerColumn("id") - NameColumn = postgres.StringColumn("name") - SlugColumn = postgres.StringColumn("slug") - DescriptionColumn = postgres.StringColumn("description") - ExpireAtColumn = postgres.TimestampColumn("expire_at") - CreatedAtColumn = postgres.TimestampColumn("created_at") - UpdatedAtColumn = postgres.TimestampColumn("updated_at") - BindUserIDColumn = postgres.IntegerColumn("bind_user_id") - allColumns = postgres.ColumnList{IDColumn, NameColumn, SlugColumn, DescriptionColumn, ExpireAtColumn, CreatedAtColumn, UpdatedAtColumn, BindUserIDColumn} - mutableColumns = postgres.ColumnList{NameColumn, SlugColumn, DescriptionColumn, ExpireAtColumn, CreatedAtColumn, UpdatedAtColumn, BindUserIDColumn} + IDColumn = postgres.IntegerColumn("id") + NameColumn = postgres.StringColumn("name") + SlugColumn = postgres.StringColumn("slug") + DescriptionColumn = postgres.StringColumn("description") + ExpireAtColumn = postgres.TimestampColumn("expire_at") + CreatedAtColumn = postgres.TimestampColumn("created_at") + UpdatedAtColumn = postgres.TimestampColumn("updated_at") + BindUserIDColumn = postgres.IntegerColumn("bind_user_id") + BindUserContactColumn = postgres.StringColumn("bind_user_contact") + allColumns = postgres.ColumnList{IDColumn, NameColumn, SlugColumn, DescriptionColumn, ExpireAtColumn, CreatedAtColumn, UpdatedAtColumn, BindUserIDColumn, BindUserContactColumn} + mutableColumns = postgres.ColumnList{NameColumn, SlugColumn, DescriptionColumn, ExpireAtColumn, CreatedAtColumn, UpdatedAtColumn, BindUserIDColumn, BindUserContactColumn} ) return tenantsTable{ Table: postgres.NewTable(schemaName, tableName, alias, allColumns...), //Columns - ID: IDColumn, - Name: NameColumn, - Slug: SlugColumn, - Description: DescriptionColumn, - ExpireAt: ExpireAtColumn, - CreatedAt: CreatedAtColumn, - UpdatedAt: UpdatedAtColumn, - BindUserID: BindUserIDColumn, + ID: IDColumn, + Name: NameColumn, + Slug: SlugColumn, + Description: DescriptionColumn, + ExpireAt: ExpireAtColumn, + CreatedAt: CreatedAtColumn, + UpdatedAt: UpdatedAtColumn, + BindUserID: BindUserIDColumn, + BindUserContact: BindUserContactColumn, AllColumns: allColumns, MutableColumns: mutableColumns, diff --git a/backend/modules/users/controller.go b/backend/modules/users/controller.go index c9eea0f..f38057f 100644 --- a/backend/modules/users/controller.go +++ b/backend/modules/users/controller.go @@ -54,6 +54,7 @@ func (c *Controller) Info(ctx fiber.Ctx) error { return errors.Wrapf(err, "get tenant: %d", claim.TenantID) } info.IsAdmin = tenant.BindUserID == claim.UserID + info.AdminContact = tenant.BindUserContact return ctx.JSON(info) } @@ -92,3 +93,26 @@ func (c *Controller) GetChargeCodes(ctx fiber.Ctx) error { return ctx.JSON(codes) } + +// BalanceHistory +func (c *Controller) BalanceHistory(ctx fiber.Ctx) error { + claim := fiber.Locals[*jwt.Claims](ctx, consts.CtxKeyClaim) + log.Debug(claim) + + histories, err := c.svc.GetBalanceHistory(ctx.Context(), claim.TenantID, claim.UserID) + if err != nil { + return errorx.Wrap(err) + } + + items := []BalanceHistory{} + for _, h := range histories { + items = append(items, BalanceHistory{ + Balance: h.Balance, + Type: h.Type, + Target: h.Target, + CreatedAt: h.CreatedAt, + }) + } + + return ctx.JSON(items) +} diff --git a/backend/modules/users/dto.go b/backend/modules/users/dto.go index e26b028..8671293 100644 --- a/backend/modules/users/dto.go +++ b/backend/modules/users/dto.go @@ -1,6 +1,20 @@ package users +import ( + "time" + + "backend/pkg/pg" +) + type UserInfo struct { - IsAdmin bool `json:"is_admin"` - Balance int64 `json:"balance"` + IsAdmin bool `json:"is_admin"` + AdminContact string `json:"admin_contact"` + Balance int64 `json:"balance"` +} + +type BalanceHistory struct { + Type pg.BalanceType `json:"type"` + Target pg.BalanceTarget `json:"target"` + Balance int64 `json:"balance"` + CreatedAt time.Time `json:"created_at"` } diff --git a/backend/modules/users/router.go b/backend/modules/users/router.go index 80f33bf..259cc5b 100755 --- a/backend/modules/users/router.go +++ b/backend/modules/users/router.go @@ -29,4 +29,5 @@ func (r *Router) Register(router fiber.Router) { group.Get("info", r.controller.Info) group.Patch("charge/:code", r.controller.Charge) group.Get("codes", r.controller.GetChargeCodes) + group.Get("balance-histories", r.controller.BalanceHistory) } diff --git a/backend/modules/users/service.go b/backend/modules/users/service.go index 841079e..13f128b 100644 --- a/backend/modules/users/service.go +++ b/backend/modules/users/service.go @@ -413,3 +413,28 @@ func (svc *Service) SetTenantBindUserID(ctx context.Context, tenantID, adminUser } return nil } + +// GetBalanceHistory +func (svc *Service) GetBalanceHistory(ctx context.Context, tenantID, userID int64) ([]model.UserBalanceHistories, error) { + log := svc.log.WithField("method", "GetBalanceHistory") + + tbl := table.UserBalanceHistories + stmt := tbl. + SELECT( + tbl.AllColumns, + ). + WHERE( + tbl.TenantID.EQ(Int64(tenantID)).AND(tbl.UserID.EQ(Int64(userID))), + ). + ORDER_BY( + tbl.CreatedAt.DESC(), + ). + LIMIT(20) + log.Debug(stmt.DebugSql()) + + var items []model.UserBalanceHistories + if err := stmt.QueryContext(ctx, db.FromContext(ctx, svc.db), &items); err != nil { + return nil, errors.Wrap(err, "failed to query balance history") + } + return items, nil +} diff --git a/backend/pkg/service/tenants/tenants.go b/backend/pkg/service/tenants/tenants.go index 3bdad97..8abcb21 100644 --- a/backend/pkg/service/tenants/tenants.go +++ b/backend/pkg/service/tenants/tenants.go @@ -31,6 +31,7 @@ func Command() atom.Option { return atom.Command( atom.Name("tenants"), atom.Short("租户相关操作"), + atom.Example("create Name --slug [slug] --contact [wechat_contact]"), atom.Command( atom.Name("create"), atom.Providers(defaultProviders().With( @@ -40,6 +41,7 @@ func Command() atom.Option { )), atom.Arguments(func(cmd *cobra.Command) { cmd.Flags().String("slug", "", "slug") + cmd.Flags().String("contact", "", "contact") }), atom.RunE(func(cmd *cobra.Command, args []string) error { return container.Container.Invoke(func(t *tenant.Create) error { diff --git a/frontend/src/components/BalanceHistory.vue b/frontend/src/components/BalanceHistory.vue new file mode 100644 index 0000000..2af8f0d --- /dev/null +++ b/frontend/src/components/BalanceHistory.vue @@ -0,0 +1,65 @@ + + + + \ No newline at end of file diff --git a/frontend/src/components/ChargeCode.vue b/frontend/src/components/ChargeCode.vue new file mode 100644 index 0000000..c9976b0 --- /dev/null +++ b/frontend/src/components/ChargeCode.vue @@ -0,0 +1,52 @@ + + + + \ No newline at end of file diff --git a/frontend/src/components/ChargeNoticeBar.vue b/frontend/src/components/ChargeNoticeBar.vue new file mode 100644 index 0000000..3363186 --- /dev/null +++ b/frontend/src/components/ChargeNoticeBar.vue @@ -0,0 +1,29 @@ + + + + \ No newline at end of file diff --git a/frontend/src/views/tabs/UserView.vue b/frontend/src/views/tabs/UserView.vue index 185efde..a5f4f57 100644 --- a/frontend/src/views/tabs/UserView.vue +++ b/frontend/src/views/tabs/UserView.vue @@ -1,6 +1,7 @@