feat: 迁移商务旗下渠道查询和抽屉
This commit is contained in:
@@ -75,6 +75,8 @@ func TestBusinessHTTPListWithSystemOnlyAndCompleteDatabase(t *testing.T) {
|
||||
c.Next()
|
||||
})
|
||||
router.RegisterBusiness(engine.Group(""), handler.NewBusiness(prefs, accounts, bindings))
|
||||
promotes := handler.NewBusinessPromote(businessservice.NewBusinessPromoteService(businessbiz.NewBusinessPromoteUsecase(businessdata.NewBusinessPromoteRepo(provider), accountUsecase)))
|
||||
engine.GET("/sw/business/:userId/promotes", promotes.List)
|
||||
server := httptest.NewServer(engine)
|
||||
defer server.Close()
|
||||
requestList := func() map[string]any {
|
||||
@@ -106,10 +108,10 @@ func TestBusinessHTTPListWithSystemOnlyAndCompleteDatabase(t *testing.T) {
|
||||
if rows[2].(map[string]any)["promoteCount"] != float64(0) {
|
||||
t.Fatal("无绑定账号的直属渠道应明确为零")
|
||||
}
|
||||
if err := db.Exec("CREATE TABLE tab_promote(id INTEGER,source_db TEXT,busier_id INTEGER,promote_level INTEGER)").Error; err != nil {
|
||||
if err := db.Exec("CREATE TABLE tab_promote(id INTEGER,source_db TEXT,busier_id INTEGER,promote_level INTEGER,account TEXT)").Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.Exec("INSERT INTO tab_promote VALUES(1,'lx',9,1),(2,'lx',9,2),(1,'hw',9,1)").Error; err != nil {
|
||||
if err := db.Exec("INSERT INTO tab_promote VALUES(1,'lx',9,1,'测试渠道'),(2,'lx',9,2,'下级渠道'),(1,'hw',9,1,'其他平台')").Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
data = requestList()
|
||||
@@ -137,6 +139,10 @@ func TestBusinessHTTPListWithSystemOnlyAndCompleteDatabase(t *testing.T) {
|
||||
return value
|
||||
}
|
||||
created := call("POST", "/sw/business", `{"userName":"http_child","realName":"接口测试","password":"abc123"}`, "")["data"].(map[string]any)
|
||||
channels := call("GET", "/sw/business/2/promotes", "", "")["data"].(map[string]any)
|
||||
if channels["total"] != float64(1) || channels["rows"].([]any)[0].(map[string]any)["promoteName"] != "测试渠道" {
|
||||
t.Fatalf("HTTP 旗下渠道范围错误: %+v", channels)
|
||||
}
|
||||
if created["userId"] != float64(4) || created["level"] != float64(1) || created["authorityId"] != float64(901) {
|
||||
t.Fatalf("HTTP 新增层级或角色不正确: %+v", created)
|
||||
}
|
||||
|
||||
Generated
+7
-2
@@ -82,11 +82,15 @@ func wireApp(configServer *config.Server, store *config.Store, logger *slog.Logg
|
||||
auditRecorderUsecase := system2.NewAuditRecorderUsecase(auditRecordRepo)
|
||||
auditRecorder := system3.NewAuditRecorder(auditRecorderUsecase)
|
||||
registry := taskRegistry()
|
||||
businessPromoteRepo := business.NewBusinessPromoteRepo(dataData)
|
||||
accountRepo := business.NewAccountRepo(dataData)
|
||||
accountUsecase := business2.NewAccountUsecase(accountRepo)
|
||||
businessPromoteUsecase := business2.NewBusinessPromoteUsecase(businessPromoteRepo, accountUsecase)
|
||||
businessPromoteService := business3.NewBusinessPromoteService(businessPromoteUsecase)
|
||||
businessPromote := handler.NewBusinessPromote(businessPromoteService)
|
||||
userPreferenceRepo := business.NewUserPreferenceRepo(dataData)
|
||||
userPreferenceUsecase := business2.NewUserPreferenceUsecase(userPreferenceRepo)
|
||||
userPreferenceService := business3.NewUserPreferenceService(userPreferenceUsecase)
|
||||
accountRepo := business.NewAccountRepo(dataData)
|
||||
accountUsecase := business2.NewAccountUsecase(accountRepo)
|
||||
accountService := business3.NewAccountService(accountUsecase)
|
||||
bindingRepo := business.NewBindingRepo(dataData)
|
||||
platformAccountRepo := business.NewPlatformAccountRepo(dataData)
|
||||
@@ -197,6 +201,7 @@ func wireApp(configServer *config.Server, store *config.Store, logger *slog.Logg
|
||||
integrationConfigService := integration2.NewIntegrationConfigService(integrationConfigUsecase)
|
||||
integrationConfig := handler.NewIntegrationConfig(integrationConfigService)
|
||||
set := &handler.Set{
|
||||
BusinessPromote: businessPromote,
|
||||
Business: handlerBusiness,
|
||||
BusinessPassword: businessPassword,
|
||||
SMS: handlerSMS,
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
"rejectedUnbind": 0,
|
||||
"pendingUnbind": 0,
|
||||
"rejectedDetail": 1,
|
||||
"rejectedChannelsDisabled": true,
|
||||
"pendingChannelsDisabled": true,
|
||||
"channelFilters": true,
|
||||
"rejectDrawerInViewport": true,
|
||||
"bindingCalls": 1,
|
||||
"pageErrors": []
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"scope": "既有 sw7 系统库;渠道表尚未接入。完整数据与跨平台范围通过隔离数据库 HTTP/仓储测试。",
|
||||
"checks": [
|
||||
{
|
||||
"path": "/sw/business/10001/promotes",
|
||||
"code": 0,
|
||||
"available": true,
|
||||
"total": 0,
|
||||
"rows": 0,
|
||||
"elapsed_ms": 14
|
||||
},
|
||||
{
|
||||
"path": "/sw/business/10007/promotes",
|
||||
"code": 0,
|
||||
"available": false,
|
||||
"total": 0,
|
||||
"rows": 0,
|
||||
"elapsed_ms": 15
|
||||
},
|
||||
{
|
||||
"path": "/sw/business/10007/promotes?sourceDb=hw&platformBusierId=14",
|
||||
"code": 0,
|
||||
"available": false,
|
||||
"total": 0,
|
||||
"rows": 0,
|
||||
"elapsed_ms": 33
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -47,10 +47,11 @@
|
||||
- 已落地商务用户七个扩展字段的存取及增量补列;登录和既有会话同时检查商务审核状态。
|
||||
- 已落地全局偏好 GET/PUT、当前用户隔离、缺省开启、显式关闭及幂等写入;Kra 顶栏增加统计口径入口。
|
||||
- 已落地商务列表、查询资料、新增子商务、部分编辑和审核状态,以及 Kra 风格 `BusinessList` 页面。层级及角色由服务端按原角色 ID 映射分配;账号、角色、偏好在同一事务创建。列表按平台与商务组合键统计直属一级渠道和已通过绑定。
|
||||
- 商务画像、旗下渠道明细、导出等功能仍在后续范围内;当前不将整个商务菜单标为完成。
|
||||
- 商务画像及其关联报表仍在后续范围内;后端导出等接口另按源码核对,不能据此给旧页面增加不存在的按钮。当前不将整个商务菜单标为完成。
|
||||
- 已接入绑定列表、指定商务已通过绑定详情、提交绑定及解绑四个接口,页面增加游戏 SDK 绑定页签与详情抽屉。绑定流程保持三级限制、平台验密、OA 待审核及驳回重提规则;新增键锁表 `sys_business_binding_locks`,串行处理同一平台商务的并发绑定。
|
||||
- 已恢复旧登录页的图片、文案、布局及记住账号功能,系统名称统一为“遨游龙翔游戏平台”。找回密码四个匿名接口位于 `/sw/auth/forgot-password/`,保留账号/手机号检查、60 秒发码限制、两分钟验证码、十分钟凭证、6–15 位密码及失败五次吊销等规则。
|
||||
- 找回密码采用同库事务保存验证码摘要和一次性凭证,并原子执行改密/消费凭证;新增 `sys_business_password_codes`、`sys_business_password_resets`。更新密码版本使旧 JWT 失效。短信复用 Kra 集成配置,`SW_PASSWORD_RESET_SMS_PROVIDER` 默认 `tencent`,也支持 `aliyun`;模板和通道凭据在对应集成配置中维护。
|
||||
- 旗下渠道接口 `/sw/business/:userId/promotes` 和两处抽屉入口已接入:先校验商务可见范围,再按已通过绑定的 `(source_db, platform_busier_id)` 查询直属一级渠道;按渠道 ID、平台稳定分页。实际 sw7 请求与隔离完整数据 HTTP/仓储测试均通过,浏览器确认绑定入口同时携带平台和平台商务 ID,未通过绑定禁用该入口。
|
||||
- 平台数据源通过 Kra 的 `data.database_list` 复用连接,别名为 `lx` / `hw` / `yq`。旧密码算法支持三种格式,兼容盐通过环境变量 `SW_SDK_AUTH_CODE`、`SW_SDK_MIGRATE_AUTH_CODE` 提供,取值应与旧 `XiguPasswordUtils` 对应常量一致;`SW_SDK_TABLE_PREFIX` 缺省为 `sys_`。真实连接凭据和盐不写进新仓库。完整平台库验密仍需部署配置后联调。
|
||||
- 已生成 `source-inventory.json`:现有 SQL 的 63 个接口契约、279 个变更源文件及额外找回密码控制器。此清单是范围索引,不代表已完成实现。
|
||||
- 已执行 `make generate`、相关 Go 测试、变更前端 ESLint 和生产构建。构建存在原 `arcdash` 依赖的 BigInt 浏览器目标警告。
|
||||
|
||||
@@ -11,15 +11,15 @@
|
||||
| 商务列表没有编辑按钮;操作列为画像 | 已移除错误增加的编辑入口;画像待报表与画像用例迁移,不能视为完成 |
|
||||
| 第二个页签名为“绑定列表”,仅 `level=3` 显示 | 已对齐;超管、一级、二级均隐藏且不会加载绑定列表 |
|
||||
| 商务列表筛选:商务名称、商务账号、等级、状态 | 已实现 |
|
||||
| 添加子商务:账号、密码、姓名、手机号、QQ;展示等级/所属商务 | 已实现主要字段,所属商务展示继续核对;已移除原页面没有的邮箱和编辑审核表单 |
|
||||
| 添加子商务:账号、密码、姓名、手机号、QQ;展示等级/所属商务 | 已实现;已移除原页面没有的邮箱和编辑审核表单 |
|
||||
| SDK商务数量可点击,零数量也能打开详情 | 已对齐 |
|
||||
| SDK商务绑定详情是只读抽屉,上级可以查看;列为平台、ID、游戏商务账号、审核状态、绑定日期 | 已对齐基础列表与字段;平台点击进入画像待实现 |
|
||||
| 商务列表列名“旗下渠道数” | 已对齐;点击进入旗下渠道抽屉待实现 |
|
||||
| 商务列表列名“旗下渠道数”,点击进入旗下渠道抽屉 | 已对齐,抽屉显示序号、渠道名称、所属平台及分页 |
|
||||
| 注册日期、绑定日期显示年月日 | 已对齐 |
|
||||
| 绑定状态正常:画像、解绑;驳回:查看驳回;待审核:无操作 | 解绑/查看驳回/待审核无操作已对齐;画像待实现 |
|
||||
| 查看驳回打开审核详情,展示申请商务、平台、账号、状态、申请/审核时间、审核人和审核意见 | 已实现 |
|
||||
| 添加绑定、解除绑定确认使用右侧抽屉 | 已对齐 |
|
||||
| 绑定列表点击旗下渠道数时,仅正常状态可查看并携带平台/平台商务筛选 | 待实现 |
|
||||
| 绑定列表点击旗下渠道数时,仅正常状态可查看并携带平台/平台商务筛选 | 已实现并通过浏览器参数核对 |
|
||||
| 全局偏好变化刷新商务/绑定数据 | 已接入 Kra 页面刷新机制 |
|
||||
|
||||
“仅三级可见”是旧页面页签规则。旧 Java 绑定查询接口仍支持超管全量、一级/二级查询下级,SDK 详情接口允许上级查看下级;这些接口的数据范围不能因页签隐藏而一并误删。
|
||||
@@ -30,7 +30,8 @@
|
||||
|
||||
- `business-page-parity-2026-11-03.json`:真实 Chrome 渲染、受控身份/业务数据,检查四个等级的页签和按钮,以及三种审核状态的行操作;无页面运行时错误。
|
||||
- `http-business-bindings-2026-11-03.json`:真实运行实例及已有 sw7 测试数据的 HTTP 验证。
|
||||
- 画像、旗下渠道抽屉等未完成项没有用占位响应或假数据冒充已迁移功能。
|
||||
- 旗下渠道已通过仓储与实际 HTTP 回归,覆盖已通过绑定、直属一级、跨平台同号和稳定分页;sw7 缺渠道数据时明确返回 `available=false`。
|
||||
- 画像等未完成项没有用占位响应或假数据冒充已迁移功能。
|
||||
|
||||
## 其他页面
|
||||
|
||||
|
||||
+1
-1
@@ -11,4 +11,4 @@ import (
|
||||
)
|
||||
|
||||
// ProviderSet is biz providers.
|
||||
var ProviderSet = wire.NewSet(system.ProviderSet, payment.ProviderSet, integration.ProviderSet, task.ProviderSet, business.NewUserPreferenceUsecase, business.NewAccountUsecase, business.NewBindingUsecase, business.NewPasswordResetUsecase)
|
||||
var ProviderSet = wire.NewSet(system.ProviderSet, payment.ProviderSet, integration.ProviderSet, task.ProviderSet, business.NewUserPreferenceUsecase, business.NewAccountUsecase, business.NewBindingUsecase, business.NewPasswordResetUsecase, business.NewBusinessPromoteUsecase)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package business
|
||||
|
||||
import "context"
|
||||
|
||||
type BusinessPromote struct {
|
||||
ID uint64
|
||||
Account, SourceDB string
|
||||
BusierID uint64
|
||||
}
|
||||
type BusinessPromoteFilter struct {
|
||||
UserID uint
|
||||
SourceDB string
|
||||
BusierID uint64
|
||||
}
|
||||
type BusinessPromotePage struct {
|
||||
Rows []*BusinessPromote
|
||||
Total int64
|
||||
Available bool
|
||||
}
|
||||
type BusinessPromoteRepo interface {
|
||||
ListDirect(context.Context, BusinessPromoteFilter, ...ListOption) (*BusinessPromotePage, error)
|
||||
}
|
||||
type BusinessPromoteUsecase struct {
|
||||
repo BusinessPromoteRepo
|
||||
accounts *AccountUsecase
|
||||
}
|
||||
|
||||
func NewBusinessPromoteUsecase(repo BusinessPromoteRepo, accounts *AccountUsecase) *BusinessPromoteUsecase {
|
||||
return &BusinessPromoteUsecase{repo: repo, accounts: accounts}
|
||||
}
|
||||
func (uc *BusinessPromoteUsecase) List(ctx context.Context, filter BusinessPromoteFilter, options ...ListOption) (*BusinessPromotePage, error) {
|
||||
if _, err := uc.accounts.Find(ctx, filter.UserID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return uc.repo.ListDirect(ctx, filter, options...)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package business
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type directPromoteRepoFake struct{ calls int }
|
||||
|
||||
func (r *directPromoteRepoFake) ListDirect(context.Context, BusinessPromoteFilter, ...ListOption) (*BusinessPromotePage, error) {
|
||||
r.calls++
|
||||
return &BusinessPromotePage{Available: true}, nil
|
||||
}
|
||||
func TestDirectPromotesCheckUserScopeBeforeReadingChannels(t *testing.T) {
|
||||
a := &accountRepoFake{accounts: map[uint]*Account{12: {ID: 12, Level: 1, IDPath: "0"}, 13: {ID: 13, Level: 2, IDPath: "0,12"}, 99: {ID: 99, Level: 2, IDPath: "0,123"}}}
|
||||
r := &directPromoteRepoFake{}
|
||||
uc := NewBusinessPromoteUsecase(r, NewAccountUsecase(a))
|
||||
if _, err := uc.List(accountContext(12, 901), BusinessPromoteFilter{UserID: 99}); err != ErrAccountScope || r.calls != 0 {
|
||||
t.Fatal("越权请求触达了渠道仓储")
|
||||
}
|
||||
if _, err := uc.List(accountContext(12, 901), BusinessPromoteFilter{UserID: 13}); err != nil || r.calls != 1 {
|
||||
t.Fatal("下级渠道查询未执行")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package business
|
||||
|
||||
import (
|
||||
"context"
|
||||
"gorm.io/gorm"
|
||||
"kra/internal/biz/business"
|
||||
)
|
||||
|
||||
type businessPromoteRepo struct{ data Provider }
|
||||
|
||||
func NewBusinessPromoteRepo(data Provider) business.BusinessPromoteRepo {
|
||||
return &businessPromoteRepo{data: data}
|
||||
}
|
||||
|
||||
type directPromotePO struct {
|
||||
ID uint64
|
||||
Account string
|
||||
SourceDB string `gorm:"column:source_db"`
|
||||
BusierID uint64
|
||||
}
|
||||
|
||||
func (r *businessPromoteRepo) ListDirect(ctx context.Context, filter business.BusinessPromoteFilter, options ...business.ListOption) (*business.BusinessPromotePage, error) {
|
||||
page := &business.BusinessPromotePage{Rows: []*business.BusinessPromote{}, Available: true}
|
||||
db := r.data.DB().WithContext(ctx)
|
||||
bindings := func() *gorm.DB {
|
||||
q := db.Table("sys_user_bind_platform b").Where("b.user_id = ? AND b.status = ?", filter.UserID, "0")
|
||||
if filter.SourceDB != "" {
|
||||
q = q.Where("b.source_db = ?", filter.SourceDB)
|
||||
}
|
||||
if filter.BusierID != 0 {
|
||||
q = q.Where("b.platform_busier_id = ?", filter.BusierID)
|
||||
}
|
||||
return q
|
||||
}
|
||||
var count int64
|
||||
if err := bindings().Count(&count).Error; err != nil {
|
||||
return nil, business.ErrStorage
|
||||
}
|
||||
if count == 0 {
|
||||
return page, nil
|
||||
}
|
||||
available, err := businessTableAvailable(db, "tab_promote")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !available {
|
||||
page.Available = false
|
||||
return page, nil
|
||||
}
|
||||
q := db.Table("tab_promote p").Where("p.promote_level = ?", 1).Where("EXISTS (?)", bindings().Select("1").Where("b.source_db = p.source_db AND b.platform_busier_id = p.busier_id"))
|
||||
if err := q.Count(&page.Total).Error; err != nil {
|
||||
return nil, business.ErrStorage
|
||||
}
|
||||
o := business.NewListOptions(options...)
|
||||
var pos []directPromotePO
|
||||
if err := q.Select("p.id,p.account,p.source_db,p.busier_id").Order("p.id DESC,p.source_db ASC").Offset(o.Offset).Limit(o.Limit).Scan(&pos).Error; err != nil {
|
||||
return nil, business.ErrStorage
|
||||
}
|
||||
for _, po := range pos {
|
||||
page.Rows = append(page.Rows, &business.BusinessPromote{ID: po.ID, Account: po.Account, SourceDB: po.SourceDB, BusierID: po.BusierID})
|
||||
}
|
||||
return page, nil
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package business
|
||||
|
||||
import (
|
||||
"context"
|
||||
"kra/internal/biz/business"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDirectPromotesUseApprovedBindingPairsAndStablePaging(t *testing.T) {
|
||||
db := prepareAccounts(t)
|
||||
for _, sql := range []string{
|
||||
"ALTER TABLE tab_promote ADD COLUMN account TEXT",
|
||||
"INSERT INTO sys_user_bind_platform(user_id,source_db,platform_busier_id,status) VALUES(7,'lx',10,'0'),(7,'hw',10,'0'),(7,'yq',10,'3'),(8,'lx',20,'0')",
|
||||
"INSERT INTO tab_promote(id,source_db,busier_id,promote_level,account) VALUES(1,'lx',10,1,'a'),(2,'lx',10,2,'sub'),(1,'hw',10,1,'b'),(3,'yq',10,1,'pending'),(4,'lx',20,1,'other'),(5,'lx',10,1,'c')",
|
||||
} {
|
||||
if err := db.Exec(sql).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
r := NewBusinessPromoteRepo(testData{db})
|
||||
ctx := context.Background()
|
||||
page, err := r.ListDirect(ctx, business.BusinessPromoteFilter{UserID: 7})
|
||||
if err != nil || !page.Available || page.Total != 3 || len(page.Rows) != 3 {
|
||||
t.Fatalf("直属渠道范围错误: %+v %v", page, err)
|
||||
}
|
||||
if page.Rows[0].ID != 5 || page.Rows[1].SourceDB != "hw" {
|
||||
t.Fatal("同号跨平台分页未使用稳定排序")
|
||||
}
|
||||
page, err = r.ListDirect(ctx, business.BusinessPromoteFilter{UserID: 7, SourceDB: "hw", BusierID: 10})
|
||||
if err != nil || page.Total != 1 || page.Rows[0].Account != "b" {
|
||||
t.Fatal("平台与商务筛选未同时生效")
|
||||
}
|
||||
page, err = r.ListDirect(ctx, business.BusinessPromoteFilter{UserID: 7}, business.ListOffset(1), business.ListLimit(1))
|
||||
if err != nil || page.Total != 3 || len(page.Rows) != 1 || page.Rows[0].SourceDB != "hw" {
|
||||
t.Fatal("分页或总数不正确")
|
||||
}
|
||||
if err := db.Exec("DROP TABLE tab_promote").Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
page, err = r.ListDirect(ctx, business.BusinessPromoteFilter{UserID: 7})
|
||||
if err != nil || page.Available {
|
||||
t.Fatal("未接入的渠道数据不能返回正常空列表")
|
||||
}
|
||||
page, err = r.ListDirect(ctx, business.BusinessPromoteFilter{UserID: 999})
|
||||
if err != nil || !page.Available || page.Total != 0 {
|
||||
t.Fatal("无绑定用户的直属渠道应为确定的空集合")
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ var ProviderSet = wire.NewSet(
|
||||
databusiness.NewBindingRepo,
|
||||
databusiness.NewPlatformAccountRepo,
|
||||
databusiness.NewPasswordResetRepo,
|
||||
databusiness.NewBusinessPromoteRepo,
|
||||
NewIntegrationRuntime,
|
||||
wire.Bind(new(datasystem.Provider), new(*Data)),
|
||||
wire.Bind(new(datasystem.DatabaseProvider), new(*Data)),
|
||||
|
||||
@@ -33,8 +33,8 @@ func TestCatalogContainsBuiltInModulesInDependencyOrder(t *testing.T) {
|
||||
menus += len(definition.Surface.Menus)
|
||||
apis += len(definition.Surface.APIs)
|
||||
}
|
||||
if menus != 6 || apis != 28 {
|
||||
t.Fatalf("admin surface = %d menus/%d APIs, want 6/28", menus, apis)
|
||||
if menus != 6 || apis != 29 {
|
||||
t.Fatalf("admin surface = %d menus/%d APIs, want 6/29", menus, apis)
|
||||
}
|
||||
if got := catalog.DefaultTimedTasks(); len(got) != 2 {
|
||||
t.Fatalf("default timed tasks = %d, want 2", len(got))
|
||||
|
||||
@@ -41,6 +41,7 @@ type routeValue struct {
|
||||
// Gin router files still bind handlers; tests keep those registrations aligned
|
||||
// with this catalog while public, audit and API metadata live only here.
|
||||
var routes = map[string]routeValue{
|
||||
"GET /sw/business/:userId/promotes": {group: "商务管理", description: "查询商务旗下直属一级渠道"},
|
||||
"POST /sw/auth/forgot-password/check": {group: "商务登录", description: "校验找回密码账号", public: true},
|
||||
"POST /sw/auth/forgot-password/send-code": {group: "商务登录", description: "发送找回密码验证码", public: true},
|
||||
"POST /sw/auth/forgot-password/verify-code": {group: "商务登录", description: "验证短信并签发重置凭证", public: true},
|
||||
|
||||
@@ -26,8 +26,9 @@ func NewGinEngine(runtime *config.Store, access *systemservice.AccessControlServ
|
||||
|
||||
func emptyHandlers() *handler.Set {
|
||||
return &handler.Set{
|
||||
Business: &handler.Business{},
|
||||
Authority: &handler.Authority{}, Menu: &handler.Menu{}, API: &handler.API{},
|
||||
BusinessPromote: &handler.BusinessPromote{},
|
||||
Business: &handler.Business{},
|
||||
Authority: &handler.Authority{}, Menu: &handler.Menu{}, API: &handler.API{},
|
||||
Permission: &handler.Permission{}, Organization: &handler.Organization{},
|
||||
Announcement: &handler.Announcement{}, Email: &handler.Email{}, Payment: &handler.Payment{}, Task: &handler.Task{},
|
||||
Media: &handler.Media{}, Audit: &handler.Audit{}, Export: &handler.Export{},
|
||||
@@ -98,7 +99,7 @@ func TestGinStartupLogsEveryRegisteredRoute(t *testing.T) {
|
||||
if got, want := strings.Count(text, `"msg":"router registered"`), len(engine.Routes()); got != want {
|
||||
t.Fatalf("registered route log count = %d, want %d", got, want)
|
||||
}
|
||||
if !strings.Contains(text, `"msg":"router register success"`) || !strings.Contains(text, `"route_count":211`) {
|
||||
if !strings.Contains(text, `"msg":"router register success"`) || !strings.Contains(text, `"route_count":212`) {
|
||||
t.Fatalf("startup route summary is missing: %s", text)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-kratos/kratos/v3/errors"
|
||||
"kra/internal/service/business"
|
||||
"kra/internal/service/dto"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type BusinessPromote struct {
|
||||
service *business.BusinessPromoteService
|
||||
}
|
||||
|
||||
func NewBusinessPromote(service *business.BusinessPromoteService) *BusinessPromote {
|
||||
return &BusinessPromote{service: service}
|
||||
}
|
||||
func (h *BusinessPromote) List(c *gin.Context) {
|
||||
id, err := strconv.ParseUint(c.Param("userId"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
Fail(c, "商务用户 ID 不正确")
|
||||
return
|
||||
}
|
||||
var req dto.BusinessPromoteQuery
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
Fail(c, "查询参数格式错误")
|
||||
return
|
||||
}
|
||||
value, err := h.service.List(c.Request.Context(), uint(id), &req)
|
||||
if err != nil {
|
||||
Fail(c, errors.FromError(err).Message)
|
||||
return
|
||||
}
|
||||
OKWithData(c, value)
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import "github.com/google/wire"
|
||||
var ProviderSet = wire.NewSet(
|
||||
NewBusiness,
|
||||
NewBusinessPassword,
|
||||
NewBusinessPromote,
|
||||
NewAuthority, NewMenu, NewAPI, NewPermission, NewOrganization,
|
||||
NewAnnouncement, NewEmail, NewPayment, NewTask, NewMedia, NewAudit,
|
||||
NewExport, NewVersion, NewDictionary, NewParameter, NewAPIToken,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package handler
|
||||
|
||||
type Set struct {
|
||||
BusinessPromote *BusinessPromote
|
||||
Business *Business
|
||||
BusinessPassword *BusinessPassword
|
||||
SMS *SMS
|
||||
|
||||
@@ -20,6 +20,7 @@ func (r *Routes) RegisterRoutes(public, private *gin.RouterGroup, engine *gin.En
|
||||
return
|
||||
}
|
||||
registrations := []func(){
|
||||
func() { private.GET("/sw/business/:userId/promotes", r.handlers.BusinessPromote.List) },
|
||||
func() { RegisterBusiness(private, r.handlers.Business) },
|
||||
func() { RegisterBusinessPassword(public, r.handlers.BusinessPassword) },
|
||||
func() { RegisterPublic(public, engine, r.handlers.Public) },
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package business
|
||||
|
||||
import (
|
||||
"context"
|
||||
"kra/internal/biz/business"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
type BusinessPromoteUsecase interface {
|
||||
List(context.Context, business.BusinessPromoteFilter, ...business.ListOption) (*business.BusinessPromotePage, error)
|
||||
}
|
||||
type BusinessPromoteService struct{ uc BusinessPromoteUsecase }
|
||||
|
||||
func NewBusinessPromoteService(uc *business.BusinessPromoteUsecase) *BusinessPromoteService {
|
||||
return &BusinessPromoteService{uc: uc}
|
||||
}
|
||||
func (s *BusinessPromoteService) List(ctx context.Context, id uint, req *dto.BusinessPromoteQuery) (*dto.BusinessPromotePage, error) {
|
||||
if req == nil || id == 0 {
|
||||
return nil, business.ErrAccountInput
|
||||
}
|
||||
filter := business.BusinessPromoteFilter{UserID: id, BusierID: req.PlatformBusierID}
|
||||
if req.SourceDB != "" {
|
||||
source, err := business.NormalizePlatform(req.SourceDB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filter.SourceDB = source
|
||||
}
|
||||
page, size := req.Page, req.PageSize
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if size < 1 {
|
||||
size = 10
|
||||
}
|
||||
if size > 500 {
|
||||
size = 500
|
||||
}
|
||||
if page > int(^uint(0)>>1)/size {
|
||||
return nil, business.ErrAccountInput
|
||||
}
|
||||
result, err := s.uc.List(ctx, filter, business.ListOffset((page-1)*size), business.ListLimit(size))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := &dto.BusinessPromotePage{Rows: make([]*dto.BusinessPromoteResponse, 0, len(result.Rows)), Total: result.Total, Available: result.Available}
|
||||
for _, row := range result.Rows {
|
||||
out.Rows = append(out.Rows, &dto.BusinessPromoteResponse{PromoteID: row.ID, PromoteName: row.Account, SourceDB: row.SourceDB, PlatformName: business.PlatformName(row.SourceDB), PlatformBusierID: row.BusierID})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package dto
|
||||
|
||||
type BusinessPromoteQuery struct {
|
||||
Page int `form:"pageNum"`
|
||||
PageSize int `form:"pageSize"`
|
||||
SourceDB string `form:"sourceDb"`
|
||||
PlatformBusierID uint64 `form:"platformBusierId"`
|
||||
}
|
||||
type BusinessPromoteResponse struct {
|
||||
PromoteID uint64 `json:"promoteId"`
|
||||
PromoteName string `json:"promoteName"`
|
||||
SourceDB string `json:"sourceDb"`
|
||||
PlatformName string `json:"platformName"`
|
||||
PlatformBusierID uint64 `json:"platformBusierId"`
|
||||
}
|
||||
type BusinessPromotePage struct {
|
||||
Rows []*BusinessPromoteResponse `json:"rows"`
|
||||
Total int64 `json:"total"`
|
||||
Available bool `json:"available"`
|
||||
}
|
||||
@@ -16,6 +16,7 @@ var ProviderSet = wire.NewSet(
|
||||
businessservice.NewAccountService,
|
||||
businessservice.NewBindingService,
|
||||
businessservice.NewPasswordResetService,
|
||||
businessservice.NewBusinessPromoteService,
|
||||
systemservice.ProviderSet,
|
||||
paymentservice.ProviderSet,
|
||||
integrationservice.ProviderSet,
|
||||
|
||||
@@ -34,6 +34,8 @@ def main():
|
||||
data = body.get("data")
|
||||
if isinstance(data, dict) and "rows" in data:
|
||||
item.update(total=data.get("total"), rows=len(data["rows"]))
|
||||
if "available" in data:
|
||||
item["available"] = data["available"]
|
||||
results.append(item)
|
||||
print(json.dumps(item, ensure_ascii=False), flush=True)
|
||||
return data if item["passed"] else None
|
||||
@@ -51,6 +53,7 @@ def main():
|
||||
request("GET", "/sw/business/list?" + urllib.parse.urlencode({"userName": account["userName"]}))
|
||||
bound = next((row for row in first["rows"] if row["bindCount"] > 0), account)
|
||||
request("GET", f"/sw/business/{bound['userId']}/bindPlatform")
|
||||
request("GET", f"/sw/business/{bound['userId']}/promotes")
|
||||
request("GET", "/sw/user/preference")
|
||||
request("GET", "/sw/business/bindPlatform?pageNum=1&pageSize=10")
|
||||
request("GET", "/sw/business/bindPlatform?sourceDb=lx,hw&status=0&pageSize=2")
|
||||
|
||||
@@ -13,13 +13,14 @@ const { chromium } = require(process.env.SW_PLAYWRIGHT_MODULE || 'playwright');
|
||||
const page = await context.newPage();
|
||||
const pageErrors=[];
|
||||
page.on('pageerror',e=>pageErrors.push(e.message));
|
||||
let bindingCalls=0;
|
||||
let bindingCalls=0; const channelCalls=[];
|
||||
await page.route('http://127.0.0.1:8080/api/**', async route => {
|
||||
const request=route.request();
|
||||
const uri=new URL(request.url());
|
||||
const apiPath=uri.pathname.slice(4);
|
||||
let body;
|
||||
if(apiPath==='/sw/business/list') body={code:0,msg:'成功',data:{rows:[{userId:79999,userName:'展示测试商务',level:2,parentUserName:'上级商务',realName:'测试姓名',phoneNumber:'',bindCount:0,promoteCount:0,createTime:'2026-11-03 10:00:00',status:'0',authorityId:902}],total:1}};
|
||||
else if(/^\/sw\/business\/\d+\/promotes$/.test(apiPath)) { channelCalls.push(Object.fromEntries(uri.searchParams)); body={code:0,msg:'成功',data:{rows:[{promoteId:1,promoteName:'渠道测试',sourceDb:'lx',platformName:'龙翔'}],total:1,available:true}}; }
|
||||
else if(apiPath==='/sw/business/bindPlatform') {
|
||||
bindingCalls++;
|
||||
body={code:0,msg:'成功',data:{total:3,rows:['0','2','3'].map((status,i)=>({userId:70000+level,sourceDb:'lx',platformName:'龙翔',platformBusierId:10+i,platformBusierAccount:['正常账号','驳回账号','待审账号'][i],bindUserName:'测试商务',promoteCount:status==='0'?2:0,status,createTime:'2026-11-03 10:00:00',reviewTime:'2026-11-03 11:00:00',reviewAccount:'测试审核人',rejectReason:status==='2'?'测试驳回原因':null}))}};
|
||||
@@ -41,7 +42,7 @@ const { chromium } = require(process.env.SW_PLAYWRIGHT_MODULE || 'playwright');
|
||||
if(tabs!==(level===3?1:0)||editButtons!==0) throw new Error('页面权限或编辑入口不一致 level='+level);
|
||||
const result={level,bindingTab:tabs===1,editButtons,passed:true};
|
||||
if(level===1 || level===2) {
|
||||
await page.getByRole('row').filter({hasText:'展示测试商务'}).getByRole('button',{name:'0',exact:true}).click();
|
||||
await page.getByRole('row').filter({hasText:'展示测试商务'}).getByRole('button',{name:'查看SDK商务绑定详情',exact:true}).click();
|
||||
await page.getByRole('dialog',{name:'SDK商务绑定详情'}).waitFor();
|
||||
result.sdkDetailReadonly=(await page.getByRole('dialog',{name:'SDK商务绑定详情'}).getByRole('button',{name:'解绑',exact:true}).count())===0;
|
||||
if(!result.sdkDetailReadonly)throw new Error('SDK 详情出现写操作');
|
||||
@@ -58,6 +59,15 @@ const { chromium } = require(process.env.SW_PLAYWRIGHT_MODULE || 'playwright');
|
||||
result.pendingUnbind=await pending.getByRole('button',{name:'解绑',exact:true}).count();
|
||||
result.rejectedDetail=await rejected.getByRole('button',{name:'查看驳回',exact:true}).count();
|
||||
if(result.normalUnbind!==1||result.rejectedUnbind||result.pendingUnbind||result.rejectedDetail!==1)throw new Error('绑定状态操作不一致');
|
||||
result.rejectedChannelsDisabled=await rejected.getByRole('button',{name:'查看旗下渠道',exact:true}).isDisabled();
|
||||
result.pendingChannelsDisabled=await pending.getByRole('button',{name:'查看旗下渠道',exact:true}).isDisabled();
|
||||
if(!result.rejectedChannelsDisabled || !result.pendingChannelsDisabled)throw new Error('未通过绑定仍可查看渠道');
|
||||
await normal.getByRole('button',{name:'查看旗下渠道',exact:true}).click();
|
||||
await page.getByText('渠道测试',{exact:true}).waitFor();
|
||||
const channelQuery=channelCalls.at(-1);
|
||||
if(channelQuery.sourceDb!=='lx'||channelQuery.platformBusierId!=='10')throw new Error('旗下渠道未携带平台和商务筛选');
|
||||
result.channelFilters=true;
|
||||
await page.getByRole('dialog',{name:'旗下渠道',exact:true}).getByRole('button',{name:'关闭此对话框',exact:true}).click();
|
||||
await rejected.getByRole('button',{name:'查看驳回',exact:true}).click();
|
||||
await page.getByText('测试驳回原因',{exact:true}).waitFor();
|
||||
const panel=await page.getByRole('dialog',{name:'审核详情',exact:true}).elementHandle();
|
||||
|
||||
@@ -12,3 +12,4 @@ export const listBusinessBindings = (params) => service({ url: '/sw/business/bin
|
||||
export const listUserBindings = (id) => service({ url: `/sw/business/${id}/bindPlatform`, method: 'get' })
|
||||
export const bindPlatform = (data) => service({ url: '/sw/business/bindPlatform', method: 'post', data })
|
||||
export const unbindPlatform = (data) => service({ url: '/sw/business/bindPlatform', method: 'delete', data })
|
||||
export const listBusinessChannels = (id, params) => service({ url: `/sw/business/${id}/promotes`, method: 'get', params })
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
"/src/view/superAdmin/user/user.vue": "User",
|
||||
"/src/view/sw/BusinessList.vue": "SwBusinessList",
|
||||
"/src/view/sw/components/BusinessBindings.vue": "SwBusinessBindings",
|
||||
"/src/view/sw/components/BusinessChannels.vue": "SwBusinessChannels",
|
||||
"/src/view/system/security/forceChangePassword.vue": "ForceChangePassword",
|
||||
"/src/view/system/security/index.vue": "SecurityConfig",
|
||||
"/src/view/system/state.vue": "State",
|
||||
|
||||
@@ -29,11 +29,11 @@
|
||||
<el-table-column prop="parentUserName" label="上级商务" min-width="140" />
|
||||
<el-table-column prop="realName" label="姓名" min-width="100" />
|
||||
<el-table-column prop="phoneNumber" label="手机号" min-width="130" />
|
||||
<el-table-column prop="bindCount" label="SDK商务" width="120"><template #default="{ row }"><el-button link type="primary" @click="showBindings(row)">{{ row.bindCount }}</el-button></template></el-table-column>
|
||||
<el-table-column prop="bindCount" label="SDK商务" width="120"><template #default="{ row }"><el-button link type="primary" aria-label="查看SDK商务绑定详情" @click="showBindings(row)">{{ row.bindCount }}</el-button></template></el-table-column>
|
||||
<el-table-column prop="promoteCount" label="旗下渠道数" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tooltip v-if="row.promoteCount === null" content="当前数据库尚未接入渠道数据,商务资料和绑定数仍可查看。"><span class="text-gray-400">未接入</span></el-tooltip>
|
||||
<span v-else>{{ row.promoteCount }}</span>
|
||||
<el-button v-else type="primary" link aria-label="查看旗下渠道" @click="showChannels(row)">{{ row.promoteCount }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="注册时间" min-width="130"><template #default="{ row }">{{ row.createTime?.slice(0, 10) }}</template></el-table-column>
|
||||
@@ -43,6 +43,7 @@
|
||||
<el-pagination v-model:current-page="query.pageNum" v-model:page-size="query.pageSize" :total="total" :page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" @size-change="search" @current-change="load" />
|
||||
</div>
|
||||
</div>
|
||||
<el-drawer append-to-body v-model="channelsDrawer" title="旗下渠道" size="520px" destroy-on-close><business-channels :user-id="channelUserId" /></el-drawer>
|
||||
<el-drawer append-to-body v-model="bindingsDrawer" title="SDK商务绑定详情" size="85%" destroy-on-close><business-bindings :user-id="bindingUserId" /></el-drawer>
|
||||
<el-drawer append-to-body v-model="drawer" title="添加子商务" :size="480" destroy-on-close>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
|
||||
@@ -52,6 +53,7 @@
|
||||
<el-form-item label="手机号"><el-input v-model="form.phoneNumber" maxlength="11" /></el-form-item>
|
||||
<el-form-item label="QQ"><el-input v-model="form.qqNumber" maxlength="20" /></el-form-item>
|
||||
<el-form-item label="商务等级"><span>{{ childLevel }}</span></el-form-item>
|
||||
<el-form-item label="所属商务"><span>{{ user.userInfo.nickName || user.userInfo.userName }}</span></el-form-item>
|
||||
</el-form>
|
||||
<template #footer><el-button @click="drawer = false">取消</el-button><el-button type="primary" :loading="saving" @click="save">确定</el-button></template>
|
||||
</el-drawer>
|
||||
@@ -65,12 +67,16 @@ import { useUserStore } from '@/pinia/modules/user'
|
||||
import { useBtnAuth } from '@/utils/btnAuth'
|
||||
import { listBusiness, createBusiness } from '@/api/business'
|
||||
import BusinessBindings from './components/BusinessBindings.vue'
|
||||
import BusinessChannels from './components/BusinessChannels.vue'
|
||||
|
||||
defineOptions({ name: 'SwBusinessList' })
|
||||
const user = useUserStore()
|
||||
const activeTab = ref('accounts')
|
||||
const bindingsDrawer = ref(false)
|
||||
const bindingUserId = ref(0)
|
||||
const channelsDrawer = ref(false)
|
||||
const channelUserId = ref(0)
|
||||
const showChannels = (row) => { channelUserId.value = row.userId; channelsDrawer.value = true }
|
||||
const showBindings = (row) => { bindingUserId.value = row.userId; bindingsDrawer.value = true }
|
||||
const buttons = useBtnAuth()
|
||||
const levels = { 1: '一级商务', 2: '二级商务', 3: '三级商务' }
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<el-table-column v-if="userId" prop="platformBusierId" label="ID" min-width="90" />
|
||||
<el-table-column prop="platformBusierAccount" label="游戏商务账号" min-width="140" />
|
||||
<el-table-column v-if="!userId" prop="bindUserName" label="绑定商务" min-width="140" />
|
||||
<el-table-column v-if="!userId" label="旗下渠道数" min-width="110"><template #default="{ row }"><span :class="{ 'text-gray-400': row.promoteCount === null }">{{ row.promoteCount === null ? '未接入' : row.promoteCount }}</span></template></el-table-column>
|
||||
<el-table-column v-if="!userId" label="旗下渠道数" min-width="110"><template #default="{ row }"><span v-if="row.promoteCount === null" class="text-gray-400">未接入</span><el-button v-else type="primary" link aria-label="查看旗下渠道" :disabled="row.status !== '0'" @click="showChannels(row)">{{ row.promoteCount }}</el-button></template></el-table-column>
|
||||
<el-table-column label="审核状态" width="110"><template #default="{ row }"><el-tag :type="row.status === '0' ? 'success' : row.status === '2' ? 'danger' : 'warning'">{{ statuses[row.status] || row.status }}</el-tag></template></el-table-column>
|
||||
<el-table-column prop="createTime" label="绑定时间" min-width="130"><template #default="{ row }">{{ row.createTime?.slice(0, 10) }}</template></el-table-column>
|
||||
<el-table-column v-if="!userId" label="操作" width="110" fixed="right">
|
||||
@@ -28,6 +28,7 @@
|
||||
</el-table>
|
||||
<div v-if="!userId" class="kra-pagination"><el-pagination v-model:current-page="query.pageNum" v-model:page-size="query.pageSize" :total="total" :page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" @size-change="search" @current-change="load" /></div>
|
||||
</div>
|
||||
<el-drawer append-to-body v-model="channelsDrawer" title="旗下渠道" size="520px" destroy-on-close><business-channels v-if="selectedChannel" :user-id="selectedChannel.userId" :source-db="selectedChannel.sourceDb" :platform-busier-id="selectedChannel.platformBusierId" /></el-drawer>
|
||||
<el-drawer append-to-body v-model="dialog" title="绑定游戏商务" size="460px" destroy-on-close>
|
||||
<el-alert title="验证成功后提交 OA 审核,审核通过后可查看对应渠道数据。" type="info" :closable="false" class="mb-4" />
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
|
||||
@@ -64,6 +65,7 @@ import { ElMessage } from 'element-plus'
|
||||
import { useUserStore } from '@/pinia/modules/user'
|
||||
import { useBtnAuth } from '@/utils/btnAuth'
|
||||
import { listBusinessBindings, listUserBindings, bindPlatform, unbindPlatform } from '@/api/business'
|
||||
import BusinessChannels from './BusinessChannels.vue'
|
||||
|
||||
defineOptions({ name: 'SwBusinessBindings' })
|
||||
const props = defineProps({ userId: { type: Number, default: 0 } })
|
||||
@@ -81,6 +83,9 @@ const dialog = ref(false)
|
||||
const rejectDrawer = ref(false)
|
||||
const unbindDrawer = ref(false)
|
||||
const selectedRow = ref(null)
|
||||
const channelsDrawer = ref(false)
|
||||
const selectedChannel = ref(null)
|
||||
const showChannels = (row) => { selectedChannel.value = row; channelsDrawer.value = true }
|
||||
const showReject = (row) => { selectedRow.value = row; rejectDrawer.value = true }
|
||||
const saving = ref(false)
|
||||
const formRef = ref()
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-empty v-if="!available" description="当前数据库尚未接入渠道数据" />
|
||||
<template v-else>
|
||||
<el-table :data="rows" :row-key="(row) => `${row.sourceDb}:${row.promoteId}`">
|
||||
<el-table-column type="index" label="序号" width="70" />
|
||||
<el-table-column prop="promoteName" label="渠道名称" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="platformName" label="所属平台" min-width="110" />
|
||||
</el-table>
|
||||
<div v-if="total" class="kra-pagination"><el-pagination v-model:current-page="page" :page-size="10" :total="total" layout="total, prev, pager, next" @current-change="load" /></div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { listBusinessChannels } from '@/api/business'
|
||||
|
||||
defineOptions({ name: 'SwBusinessChannels' })
|
||||
const props = defineProps({ userId: { type: Number, required: true }, sourceDb: { type: String, default: '' }, platformBusierId: { type: Number, default: 0 } })
|
||||
const page = ref(1)
|
||||
const rows = ref([])
|
||||
const total = ref(0)
|
||||
const available = ref(true)
|
||||
const loading = ref(false)
|
||||
const load = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await listBusinessChannels(props.userId, { pageNum: page.value, pageSize: 10, sourceDb: props.sourceDb || undefined, platformBusierId: props.platformBusierId || undefined })
|
||||
if (res.code === 0) { rows.value = res.data.rows; total.value = res.data.total; available.value = res.data.available !== false }
|
||||
} finally { loading.value = false }
|
||||
}
|
||||
watch(() => [props.userId, props.sourceDb, props.platformBusierId], () => { page.value = 1; load() }, { immediate: true })
|
||||
</script>
|
||||
Reference in New Issue
Block a user