@oj-module/cli 0.2.53 → 0.2.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/devkit/SKILL.md +4 -4
- package/devkit/manual.md +79 -65
- package/package.json +2 -2
- package/shell-dist/assets/{index-e_Mp2mb5.js → index-CImwskAz.js} +24 -11
- package/shell-dist/assets/runtime.js +7 -4
- package/shell-dist/index.html +3 -3
- package/shell-dist/versions.json +3 -3
- package/src/__tests__/layout.test.ts +30 -1
- package/src/__tests__/templates-schema-columns.test.ts +99 -0
- package/src/__tests__/templates-tenant-scope.test.ts +3 -2
- package/src/alias-paths.ts +11 -12
- package/src/builtin.ts +10 -3
- package/src/config.ts +9 -0
- package/src/contract/__tests__/client-path.test.ts +30 -0
- package/src/contract/__tests__/emit-client.test.ts +20 -2
- package/src/contract/__tests__/handler-scan.test.ts +23 -0
- package/src/contract/__tests__/market-client.integration.test.ts +2 -2
- package/src/contract/__tests__/run-api.test.ts +2 -2
- package/src/contract/check.ts +11 -7
- package/src/contract/client-path.ts +30 -0
- package/src/contract/emit-client.ts +27 -6
- package/src/contract/handler-scan.ts +40 -3
- package/src/contract/run.ts +15 -5
- package/src/init.ts +29 -3
- package/src/layout.ts +72 -16
- package/src/lifecycle/__tests__/manifest-contract.test.ts +2 -2
- package/src/market/__tests__/bootstrap.test.ts +1 -1
- package/src/site.ts +1 -1
- package/templates/README.md +49 -43
- package/templates/init.include.yaml +31 -19
- package/templates/openapi.json +1488 -120
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/users.ts +27 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/oplog.ts +4 -2
- package/templates/src/{_platform/api → app/api/_platform}/contacts/api.ts +29 -1
- package/templates/src/{_platform/api → app/api/_platform}/contacts/detail/api.ts +25 -1
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.mysql.sql +7 -0
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.pg.sql +4 -0
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.sql +8 -0
- package/templates/src/{_platform/api → app/api/_platform}/schema.yaml +5 -0
- package/templates/src/{_platform/api → app/api/_platform}/solutions/api.ts +60 -1
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/replay.ts +9 -3
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/tenant-admin.ts +18 -27
- package/templates/src/{auth/api → app/api/auth}/api.ts +59 -0
- package/templates/src/{auth/api → app/api/auth}/ldap-login/api.ts +37 -1
- package/templates/src/{auth/api → app/api/auth}/wecom/api.ts +23 -0
- package/templates/src/{notification/api → app/api/notification}/api.ts +17 -0
- package/templates/src/{notification/api → app/api/notification}/del/api.ts +2 -0
- package/templates/src/{system/api → app/api/system}/oplog/api.ts +5 -3
- package/templates/src/{system/api → app/api/system}/roles/api.ts +3 -0
- package/templates/src/{system/api → app/api/system}/roles/bindings/api.ts +3 -0
- package/templates/src/{system/api → app/api/system}/settings/api.ts +3 -0
- package/templates/src/{system/api → app/api/system}/users/forbidden/api.ts +3 -0
- package/templates/src/{system/api → app/api/system}/users/password/api.ts +3 -0
- package/templates/src/{system/api → app/api/system}/users/roles/api.ts +3 -0
- package/templates/src/app/api/web/get-async-routes/api.ts +23 -0
- package/templates/src/app/api/web/hello/api.ts +22 -0
- package/templates/src/{web/api → app/api/web}/user-info/api.ts +21 -1
- package/templates/src/{_platform/web → app/web/_platform}/__client/api.schemas.ts +99 -35
- package/templates/src/{_platform/web/__client/api.ts → app/web/_platform/__client/index.ts} +108 -61
- package/templates/src/{auth/web → app/web/auth}/__client/api.schemas.ts +133 -13
- package/templates/src/{auth/web/__client/api.ts → app/web/auth/__client/index.ts} +134 -33
- package/templates/src/app/web/entry.ts +77 -0
- package/templates/src/{home/web/__client/api.ts → app/web/home/__client/index.ts} +5 -2
- package/templates/src/app/web/home/routes.ts +41 -0
- package/templates/src/app/web/login/routes.ts +71 -0
- package/templates/src/{notification/web → app/web/notification}/__client/api.schemas.ts +14 -0
- package/templates/src/{notification/web/__client/api.ts → app/web/notification/__client/index.ts} +67 -20
- package/templates/src/{notification/web → app/web/notification}/pages/center/index.tsx +1 -1
- package/templates/src/app/web/notification/routes.ts +70 -0
- package/templates/src/{personal-center/web/__client/api.ts → app/web/personal-center/__client/index.ts} +5 -2
- package/templates/src/{personal-center/web → app/web/personal-center}/pages/my-profile/index.tsx +1 -1
- package/templates/src/app/web/personal-center/routes.ts +49 -0
- package/templates/src/{system/web → app/web/system}/__client/api.schemas.ts +29 -22
- package/templates/src/{system/web/__client/api.ts → app/web/system/__client/index.ts} +103 -58
- package/templates/src/{system/web → app/web/system}/locales/en-US.json +2 -3
- package/templates/src/{system/web → app/web/system}/locales/zh-CN.json +2 -3
- package/templates/src/{system/web → app/web/system}/pages/departments/index.tsx +2 -2
- package/templates/src/{system/web → app/web/system}/pages/login-methods/index.tsx +1 -1
- package/templates/src/{system/web → app/web/system}/pages/oplog/index.tsx +44 -19
- package/templates/src/{system/web → app/web/system}/pages/roles/index.tsx +5 -3
- package/templates/src/app/web/system/pages/roles/visible-roles.ts +14 -0
- package/templates/src/{system/web → app/web/system}/pages/settings/index.tsx +2 -2
- package/templates/src/app/web/system/pages/users/can-manage.ts +21 -0
- package/templates/src/{system/web → app/web/system}/pages/users/index.tsx +23 -15
- package/templates/src/{system/web → app/web/system}/pages/users/roles.tsx +1 -1
- package/templates/src/{system/web → app/web/system}/pages/wecom/index.tsx +12 -3
- package/templates/src/{system/web/entry.ts → app/web/system/routes.ts} +25 -36
- package/templates/src/app/web/web/__client/api.schemas.ts +36 -0
- package/templates/src/{web/web/__client/api.ts → app/web/web/__client/index.ts} +38 -11
- package/templates/src/oj-market/web/api/defaultClient.ts +1 -1
- package/templates/tests/auth-ldap.spec.ts +2 -2
- package/templates/tests/auth-session.spec.ts +3 -3
- package/templates/tests/auth-throttle.spec.ts +1 -1
- package/templates/tests/fixture.ts +6 -4
- package/templates/tests/guard.spec.ts +1 -1
- package/templates/tests/lifecycle/atomic-state.spec.ts +3 -3
- package/templates/tests/lifecycle/bootstrap.spec.ts +3 -3
- package/templates/tests/lifecycle/deploy-smoke.spec.ts +8 -8
- package/templates/tests/lifecycle/installer.spec.ts +10 -10
- package/templates/tests/lifecycle/market-api.spec.ts +14 -14
- package/templates/tests/lifecycle/migrate.spec.ts +6 -6
- package/templates/tests/lifecycle/preflight.spec.ts +3 -3
- package/templates/tests/lifecycle/register.spec.ts +1 -1
- package/templates/tests/lifecycle/semver.spec.ts +1 -1
- package/templates/tests/lifecycle/sha384.spec.ts +1 -1
- package/templates/tests/lifecycle/solutions-api.spec.ts +1 -1
- package/templates/tests/lifecycle/source-seq.spec.ts +1 -1
- package/templates/tests/lifecycle/steps-fs.spec.ts +9 -9
- package/templates/tests/lifecycle/text-edit.spec.ts +1 -1
- package/templates/tests/lifecycle/tgz-guard.spec.ts +2 -2
- package/templates/tests/lifecycle/trust.spec.ts +5 -5
- package/templates/tests/lifecycle/uninstall.spec.ts +7 -7
- package/templates/tests/lifecycle/verify-checks.spec.ts +5 -5
- package/templates/tests/lifecycle/verify-report.spec.ts +4 -4
- package/templates/tests/org-departments.spec.ts +10 -6
- package/templates/tests/org-read.spec.ts +7 -7
- package/templates/tests/query-utils.spec.ts +1 -1
- package/templates/tests/rbac-audit.spec.ts +1 -1
- package/templates/tests/rbac-contacts.spec.ts +2 -2
- package/templates/tests/rbac-guard.spec.ts +1 -1
- package/templates/tests/rbac-roles.spec.ts +10 -2
- package/templates/tests/rbac-seed.spec.ts +1 -1
- package/templates/tests/rbac-settings.spec.ts +77 -7
- package/templates/tests/rbac-solution-perms.spec.ts +1 -1
- package/templates/tests/rbac-tables.spec.ts +29 -0
- package/templates/tests/rbac-users.spec.ts +55 -3
- package/templates/tests/roles-page.spec.ts +40 -0
- package/templates/tests/seed-role-accounts.spec.ts +1 -1
- package/templates/tests/tenant-access-cache.spec.ts +1 -1
- package/templates/tests/tenant-forgery.spec.ts +5 -5
- package/templates/tests/tenant-isolation.spec.ts +5 -4
- package/templates/tests/username-namespace.spec.ts +3 -3
- package/templates/tests/users-page.spec.ts +39 -0
- package/templates/tests/wecom-admin.spec.ts +6 -6
- package/templates/tests/wecom-client-timeout.spec.ts +1 -1
- package/templates/tests/wecom-connector.spec.ts +9 -9
- package/templates/tests/wecom-corp.spec.ts +9 -9
- package/templates/tests/wecom-crypt.spec.ts +1 -1
- package/templates/tests/wecom-endpoints.spec.ts +2 -2
- package/templates/tests/wecom-landing.spec.ts +1 -1
- package/templates/tests/wecom-org-sync.spec.ts +7 -7
- package/templates/tests/wecom-sync.spec.ts +3 -3
- package/templates/tsconfig.paths.json +11 -11
- package/templates/vitest.config.ts +2 -2
- package/templates/web.config.ts +24 -15
- package/vendor/host-versions.json +3 -3
- package/templates/src/home/web/entry.ts +0 -49
- package/templates/src/login/web/entry.ts +0 -79
- package/templates/src/notification/web/entry.ts +0 -84
- package/templates/src/personal-center/web/entry.ts +0 -60
- package/templates/src/web/api/get-async-routes/api.ts +0 -8
- package/templates/src/web/api/hello/api.ts +0 -10
- package/templates/src/web/web/__client/api.schemas.ts +0 -8
- package/templates/src/{_platform/api → app/api/_platform}/README.md +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/atomic.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/history.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/installer.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/limits.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/lock.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/semver.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/sha384.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/source-seq.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/state.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/deploy-web.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/download.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/extract.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/migrate.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/preflight.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/register.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/reload.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/smoke.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/verify.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/tasks.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/text-edit.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/tgz-guard.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/trust.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/types.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/uninstall.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/verify-checks.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/verify-report.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/respond.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/contacts.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/org-read.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/org.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/roles.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/settings.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/solution-perms.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/access.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/audit.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/guard.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/query.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/rate.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/site-facade.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/fixtures/l1-test-user.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/manifest.yaml +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/market/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/market/bootstrap.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/market/index-source.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0002__add_users_avatar_base64.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0002__add_users_avatar_base64.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0003__users_source_display_name.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0003__users_source_display_name.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0005__users_must_change.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0005__users_must_change.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0006__users_is_forbidden.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0006__users_is_forbidden.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0007__users_email.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0011__sys_setting_group_label.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0011__sys_setting_group_label.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0013__users_profile.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/departments/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/is-member/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/members/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/picker/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/resolve/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/tree/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/user/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/seed.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/seed.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/seed.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/ldap-login.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/ldap.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/login-throttle.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/session.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/admin.ts +1 -1
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/client.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/config.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/contacts.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/crypt.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/events.ts +1 -1
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/login.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/payload.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/store.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/sync.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/manifest.yaml +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.mysql.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.pg.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.mysql.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.pg.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.mysql.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.pg.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/schema.yaml +0 -0
- package/templates/src/{auth/api → app/api/auth}/wecom/admin/api.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/wecom/admin/tenant-admin/api.ts +1 -1
- package/templates/src/{auth/api → app/api/auth}/wecom/admin/tenant-admin/password/api.ts +1 -1
- /package/templates/src/{auth/api → app/api/auth}/wecom/sync/api.ts +0 -0
- /package/templates/src/{home/api → app/api/home}/line/api.ts +0 -0
- /package/templates/src/{home/api → app/api/home}/manifest.yaml +0 -0
- /package/templates/src/{home/api → app/api/home}/migrations/0001__create_home_tables.sql +0 -0
- /package/templates/src/{home/api → app/api/home}/migrations/0002__tenant.mysql.sql +0 -0
- /package/templates/src/{home/api → app/api/home}/migrations/0002__tenant.sql +0 -0
- /package/templates/src/{home/api → app/api/home}/pie/api.ts +0 -0
- /package/templates/src/{home/api → app/api/home}/schema.yaml +0 -0
- /package/templates/src/{home/api → app/api/home}/seed.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/_shared/notify.ts +0 -0
- /package/templates/src/{notification/api → app/api/notification}/manifest.yaml +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0001__create_notifications.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0002__notifications_user.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0003__notifications_broadcast.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0004__notifications_broadcast_hidden.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0005__tenant.mysql.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0005__tenant.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/schema.yaml +0 -0
- /package/templates/src/{notification/api → app/api/notification}/seed.sql +0 -0
- /package/templates/src/{personal-center/api → app/api/personal-center}/manifest.yaml +0 -0
- /package/templates/src/{personal-center/api → app/api/personal-center}/profile/api.ts +0 -0
- /package/templates/src/{personal-center/api → app/api/personal-center}/upload/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/departments/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/departments/detach/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/departments/members/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/departments/move/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/login-methods/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/manifest.yaml +0 -0
- /package/templates/src/{system/api → app/api/system}/permissions/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/profile/api.ts +0 -0
- /package/templates/src/{web/api → app/api/web}/manifest.yaml +0 -0
- /package/templates/src/{home/web → app/web/home}/__client/api.schemas.ts +0 -0
- /package/templates/src/{home/web → app/web/home}/locales/en-US.json +0 -0
- /package/templates/src/{home/web → app/web/home}/locales/zh-CN.json +0 -0
- /package/templates/src/{home/web → app/web/home}/pages/components/bar-chart.tsx +0 -0
- /package/templates/src/{home/web → app/web/home}/pages/components/card-list.tsx +0 -0
- /package/templates/src/{home/web → app/web/home}/pages/components/line-chart.tsx +0 -0
- /package/templates/src/{home/web → app/web/home}/pages/components/pie-chart.tsx +0 -0
- /package/templates/src/{home/web → app/web/home}/pages/index.tsx +0 -0
- /package/templates/src/{login/web → app/web/login}/auth-provider.ts +0 -0
- /package/templates/src/{login/web → app/web/login}/locales/en-US.json +0 -0
- /package/templates/src/{login/web → app/web/login}/locales/zh-CN.json +0 -0
- /package/templates/src/{login/web → app/web/login}/pages/change-password.tsx +0 -0
- /package/templates/src/{login/web → app/web/login}/pages/login.tsx +0 -0
- /package/templates/src/{login/web → app/web/login}/wecom.ts +0 -0
- /package/templates/src/{notification/web → app/web/notification}/locales/en-US.json +0 -0
- /package/templates/src/{notification/web → app/web/notification}/locales/zh-CN.json +0 -0
- /package/templates/src/{personal-center/web → app/web/personal-center}/__client/api.schemas.ts +0 -0
- /package/templates/src/{personal-center/web → app/web/personal-center}/locales/en-US.json +0 -0
- /package/templates/src/{personal-center/web → app/web/personal-center}/locales/zh-CN.json +0 -0
- /package/templates/src/{system/web → app/web/system}/pages/departments/sync-bar.tsx +0 -0
- /package/templates/src/{system/web → app/web/system}/pages/departments/tree.ts +0 -0
- /package/templates/src/{system/web → app/web/system}/pages/errors.ts +0 -0
- /package/templates/src/{system/web → app/web/system}/pages/forbidden.tsx +0 -0
|
@@ -17,6 +17,9 @@ export const API_PREFIX = "/system";
|
|
|
17
17
|
/** 认领身份前缀(契约 apiPrefix,字面等于模块目录名):跨模块认领护栏对比基准 */
|
|
18
18
|
export const MODULE_PREFIX = "/system";
|
|
19
19
|
|
|
20
|
+
/** 认领方模块(web.config clientOwners 指定):跨模块认领护栏对比基准 */
|
|
21
|
+
export const MODULE_OWNER = "/app";
|
|
22
|
+
|
|
20
23
|
/**
|
|
21
24
|
* 模块 entry 的 onInit 里一行创建(构造即 install):完成 apiPrefix 登记 +
|
|
22
25
|
* scoped request 绑定,返回绑好前缀的端点函数集合。一模块一 client;
|
|
@@ -28,12 +31,12 @@ export function createSystemClient(ctx: ModuleContext) {
|
|
|
28
31
|
// 单槽、卸载互相耦合;跨模块需求应由本模块创建后经 provider 暴露。
|
|
29
32
|
// 注意对比基准是 MODULE_PREFIX(目录名)而非 API_PREFIX——D-M8 映射时线上前缀
|
|
30
33
|
// 属于别的命名空间,认领身份仍按目录名。
|
|
31
|
-
if (import.meta.env.DEV && ctx.module.name !==
|
|
32
|
-
console.warn(`[ojm-api] 模块 "${ctx.module.name}" 正在认领 ${MODULE_PREFIX} 的 client——跨模块认领会共享 request 单槽、卸载互相耦合;应由 "${
|
|
34
|
+
if (import.meta.env.DEV && ctx.module.name !== MODULE_OWNER.slice(1)) {
|
|
35
|
+
console.warn(`[ojm-api] 模块 "${ctx.module.name}" 正在认领 ${MODULE_PREFIX} 的 client——跨模块认领会共享 request 单槽、卸载互相耦合;应由 "${MODULE_OWNER.slice(1)}" 模块在自身 onInit 创建,跨模块需求经 provider 暴露。`);
|
|
33
36
|
}
|
|
34
37
|
ctx.register.apiPrefix(API_PREFIX);
|
|
35
38
|
bindRequest(ctx.utils.request);
|
|
36
|
-
return { systemDepartmentsGet, systemDepartmentsPost, systemDepartmentsPut, systemDepartmentsDelete,
|
|
39
|
+
return { systemDepartmentsGet, systemDepartmentsPost, systemDepartmentsPut, systemDepartmentsDelete, systemDepartmentsDetachPost, systemDepartmentsMembersGet, systemDepartmentsMembersPost, systemDepartmentsMembersPut, systemDepartmentsMembersDelete, systemDepartmentsMovePut, systemLoginMethodsGet, systemOplogGet, systemOplogPost, systemPermissionsGet, systemRolesGet, systemRolesPost, systemRolesDelete, systemRolesBindingsPut, systemSettingsGet, systemSettingsPut, systemUsersGet, systemUsersPost, systemUsersDelete, systemUsersForbiddenPut, systemUsersPasswordPut, systemUsersProfilePut, systemUsersRolesPut };
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
/**
|
|
@@ -160,31 +163,6 @@ export async function systemDepartmentsDelete(query: SystemDepartmentsDeleteQuer
|
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
|
|
163
|
-
export type SystemDepartmentsMovePutQuery = z.input<(typeof schemas)["systemDepartmentsMovePut"]["query"]>;
|
|
164
|
-
export type SystemDepartmentsMovePutBody = z.input<(typeof schemas)["systemDepartmentsMovePut"]["body"]>;
|
|
165
|
-
export type SystemDepartmentsMovePutData = z.infer<(typeof schemas)["systemDepartmentsMovePut"]["data"]>;
|
|
166
|
-
|
|
167
|
-
export async function systemDepartmentsMovePut(input: { query: SystemDepartmentsMovePutQuery, body: SystemDepartmentsMovePutBody }): Promise<SystemDepartmentsMovePutData> {
|
|
168
|
-
const client = ensureReq();
|
|
169
|
-
try {
|
|
170
|
-
const env = await client.put(`system/departments/move`, { searchParams: input.query as Record<string, string | number | boolean>, json: input.body }).json<OjEnvelope<SystemDepartmentsMovePutData>>();
|
|
171
|
-
// 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
|
|
172
|
-
if (typeof env.code === "number" && env.code !== 0)
|
|
173
|
-
throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
|
|
174
|
-
const data = env.data as SystemDepartmentsMovePutData;
|
|
175
|
-
if (import.meta.env.DEV) {
|
|
176
|
-
const { schemas } = await import("./api.schemas");
|
|
177
|
-
const r = schemas["systemDepartmentsMovePut"].data.safeParse(data);
|
|
178
|
-
if (!r.success)
|
|
179
|
-
throw new ContractApiError(-1, `[契约违例] systemDepartmentsMovePut 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
180
|
-
}
|
|
181
|
-
return data;
|
|
182
|
-
}
|
|
183
|
-
catch (e) {
|
|
184
|
-
throw await toApiError(e);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
166
|
export type SystemDepartmentsDetachPostQuery = z.input<(typeof schemas)["systemDepartmentsDetachPost"]["query"]>;
|
|
189
167
|
export type SystemDepartmentsDetachPostData = z.infer<(typeof schemas)["systemDepartmentsDetachPost"]["data"]>;
|
|
190
168
|
|
|
@@ -307,6 +285,31 @@ export async function systemDepartmentsMembersDelete(query: SystemDepartmentsMem
|
|
|
307
285
|
}
|
|
308
286
|
}
|
|
309
287
|
|
|
288
|
+
export type SystemDepartmentsMovePutQuery = z.input<(typeof schemas)["systemDepartmentsMovePut"]["query"]>;
|
|
289
|
+
export type SystemDepartmentsMovePutBody = z.input<(typeof schemas)["systemDepartmentsMovePut"]["body"]>;
|
|
290
|
+
export type SystemDepartmentsMovePutData = z.infer<(typeof schemas)["systemDepartmentsMovePut"]["data"]>;
|
|
291
|
+
|
|
292
|
+
export async function systemDepartmentsMovePut(input: { query: SystemDepartmentsMovePutQuery, body: SystemDepartmentsMovePutBody }): Promise<SystemDepartmentsMovePutData> {
|
|
293
|
+
const client = ensureReq();
|
|
294
|
+
try {
|
|
295
|
+
const env = await client.put(`system/departments/move`, { searchParams: input.query as Record<string, string | number | boolean>, json: input.body }).json<OjEnvelope<SystemDepartmentsMovePutData>>();
|
|
296
|
+
// 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
|
|
297
|
+
if (typeof env.code === "number" && env.code !== 0)
|
|
298
|
+
throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
|
|
299
|
+
const data = env.data as SystemDepartmentsMovePutData;
|
|
300
|
+
if (import.meta.env.DEV) {
|
|
301
|
+
const { schemas } = await import("./api.schemas");
|
|
302
|
+
const r = schemas["systemDepartmentsMovePut"].data.safeParse(data);
|
|
303
|
+
if (!r.success)
|
|
304
|
+
throw new ContractApiError(-1, `[契约违例] systemDepartmentsMovePut 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
305
|
+
}
|
|
306
|
+
return data;
|
|
307
|
+
}
|
|
308
|
+
catch (e) {
|
|
309
|
+
throw await toApiError(e);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
310
313
|
export type SystemLoginMethodsGetData = z.infer<(typeof schemas)["systemLoginMethodsGet"]["data"]>;
|
|
311
314
|
|
|
312
315
|
export async function systemLoginMethodsGet(): Promise<SystemLoginMethodsGetData> {
|
|
@@ -449,15 +452,22 @@ export async function systemRolesPost(body: SystemRolesPostBody): Promise<System
|
|
|
449
452
|
}
|
|
450
453
|
|
|
451
454
|
export type SystemRolesDeleteQuery = z.input<(typeof schemas)["systemRolesDelete"]["query"]>;
|
|
455
|
+
export type SystemRolesDeleteData = z.infer<(typeof schemas)["systemRolesDelete"]["data"]>;
|
|
452
456
|
|
|
453
|
-
export async function systemRolesDelete(query: SystemRolesDeleteQuery): Promise<
|
|
457
|
+
export async function systemRolesDelete(query: SystemRolesDeleteQuery): Promise<SystemRolesDeleteData> {
|
|
454
458
|
const client = ensureReq();
|
|
455
459
|
try {
|
|
456
|
-
const env = await client.delete(`system/roles`, { searchParams: query as Record<string, string | number | boolean> }).json<OjEnvelope<
|
|
460
|
+
const env = await client.delete(`system/roles`, { searchParams: query as Record<string, string | number | boolean> }).json<OjEnvelope<SystemRolesDeleteData>>();
|
|
457
461
|
// 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
|
|
458
462
|
if (typeof env.code === "number" && env.code !== 0)
|
|
459
463
|
throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
|
|
460
|
-
const data = env.data as
|
|
464
|
+
const data = env.data as SystemRolesDeleteData;
|
|
465
|
+
if (import.meta.env.DEV) {
|
|
466
|
+
const { schemas } = await import("./api.schemas");
|
|
467
|
+
const r = schemas["systemRolesDelete"].data.safeParse(data);
|
|
468
|
+
if (!r.success)
|
|
469
|
+
throw new ContractApiError(-1, `[契约违例] systemRolesDelete 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
470
|
+
}
|
|
461
471
|
return data;
|
|
462
472
|
}
|
|
463
473
|
catch (e) {
|
|
@@ -467,15 +477,22 @@ export async function systemRolesDelete(query: SystemRolesDeleteQuery): Promise<
|
|
|
467
477
|
|
|
468
478
|
export type SystemRolesBindingsPutQuery = z.input<(typeof schemas)["systemRolesBindingsPut"]["query"]>;
|
|
469
479
|
export type SystemRolesBindingsPutBody = z.input<(typeof schemas)["systemRolesBindingsPut"]["body"]>;
|
|
480
|
+
export type SystemRolesBindingsPutData = z.infer<(typeof schemas)["systemRolesBindingsPut"]["data"]>;
|
|
470
481
|
|
|
471
|
-
export async function systemRolesBindingsPut(input: { query: SystemRolesBindingsPutQuery, body: SystemRolesBindingsPutBody }): Promise<
|
|
482
|
+
export async function systemRolesBindingsPut(input: { query: SystemRolesBindingsPutQuery, body: SystemRolesBindingsPutBody }): Promise<SystemRolesBindingsPutData> {
|
|
472
483
|
const client = ensureReq();
|
|
473
484
|
try {
|
|
474
|
-
const env = await client.put(`system/roles/bindings`, { searchParams: input.query as Record<string, string | number | boolean>, json: input.body }).json<OjEnvelope<
|
|
485
|
+
const env = await client.put(`system/roles/bindings`, { searchParams: input.query as Record<string, string | number | boolean>, json: input.body }).json<OjEnvelope<SystemRolesBindingsPutData>>();
|
|
475
486
|
// 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
|
|
476
487
|
if (typeof env.code === "number" && env.code !== 0)
|
|
477
488
|
throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
|
|
478
|
-
const data = env.data as
|
|
489
|
+
const data = env.data as SystemRolesBindingsPutData;
|
|
490
|
+
if (import.meta.env.DEV) {
|
|
491
|
+
const { schemas } = await import("./api.schemas");
|
|
492
|
+
const r = schemas["systemRolesBindingsPut"].data.safeParse(data);
|
|
493
|
+
if (!r.success)
|
|
494
|
+
throw new ContractApiError(-1, `[契约违例] systemRolesBindingsPut 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
495
|
+
}
|
|
479
496
|
return data;
|
|
480
497
|
}
|
|
481
498
|
catch (e) {
|
|
@@ -507,15 +524,22 @@ export async function systemSettingsGet(): Promise<SystemSettingsGetData> {
|
|
|
507
524
|
}
|
|
508
525
|
|
|
509
526
|
export type SystemSettingsPutBody = z.input<(typeof schemas)["systemSettingsPut"]["body"]>;
|
|
527
|
+
export type SystemSettingsPutData = z.infer<(typeof schemas)["systemSettingsPut"]["data"]>;
|
|
510
528
|
|
|
511
|
-
export async function systemSettingsPut(body: SystemSettingsPutBody): Promise<
|
|
529
|
+
export async function systemSettingsPut(body: SystemSettingsPutBody): Promise<SystemSettingsPutData> {
|
|
512
530
|
const client = ensureReq();
|
|
513
531
|
try {
|
|
514
|
-
const env = await client.put(`system/settings`, { json: body }).json<OjEnvelope<
|
|
532
|
+
const env = await client.put(`system/settings`, { json: body }).json<OjEnvelope<SystemSettingsPutData>>();
|
|
515
533
|
// 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
|
|
516
534
|
if (typeof env.code === "number" && env.code !== 0)
|
|
517
535
|
throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
|
|
518
|
-
const data = env.data as
|
|
536
|
+
const data = env.data as SystemSettingsPutData;
|
|
537
|
+
if (import.meta.env.DEV) {
|
|
538
|
+
const { schemas } = await import("./api.schemas");
|
|
539
|
+
const r = schemas["systemSettingsPut"].data.safeParse(data);
|
|
540
|
+
if (!r.success)
|
|
541
|
+
throw new ContractApiError(-1, `[契约违例] systemSettingsPut 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
542
|
+
}
|
|
519
543
|
return data;
|
|
520
544
|
}
|
|
521
545
|
catch (e) {
|
|
@@ -594,23 +618,23 @@ export async function systemUsersDelete(query: SystemUsersDeleteQuery): Promise<
|
|
|
594
618
|
}
|
|
595
619
|
}
|
|
596
620
|
|
|
597
|
-
export type
|
|
598
|
-
export type
|
|
599
|
-
export type
|
|
621
|
+
export type SystemUsersForbiddenPutQuery = z.input<(typeof schemas)["systemUsersForbiddenPut"]["query"]>;
|
|
622
|
+
export type SystemUsersForbiddenPutBody = z.input<(typeof schemas)["systemUsersForbiddenPut"]["body"]>;
|
|
623
|
+
export type SystemUsersForbiddenPutData = z.infer<(typeof schemas)["systemUsersForbiddenPut"]["data"]>;
|
|
600
624
|
|
|
601
|
-
export async function
|
|
625
|
+
export async function systemUsersForbiddenPut(input: { query: SystemUsersForbiddenPutQuery, body: SystemUsersForbiddenPutBody }): Promise<SystemUsersForbiddenPutData> {
|
|
602
626
|
const client = ensureReq();
|
|
603
627
|
try {
|
|
604
|
-
const env = await client.put(`system/users/
|
|
628
|
+
const env = await client.put(`system/users/forbidden`, { searchParams: input.query as Record<string, string | number | boolean>, json: input.body }).json<OjEnvelope<SystemUsersForbiddenPutData>>();
|
|
605
629
|
// 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
|
|
606
630
|
if (typeof env.code === "number" && env.code !== 0)
|
|
607
631
|
throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
|
|
608
|
-
const data = env.data as
|
|
632
|
+
const data = env.data as SystemUsersForbiddenPutData;
|
|
609
633
|
if (import.meta.env.DEV) {
|
|
610
634
|
const { schemas } = await import("./api.schemas");
|
|
611
|
-
const r = schemas["
|
|
635
|
+
const r = schemas["systemUsersForbiddenPut"].data.safeParse(data);
|
|
612
636
|
if (!r.success)
|
|
613
|
-
throw new ContractApiError(-1, `[契约违例]
|
|
637
|
+
throw new ContractApiError(-1, `[契约违例] systemUsersForbiddenPut 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
614
638
|
}
|
|
615
639
|
return data;
|
|
616
640
|
}
|
|
@@ -619,17 +643,24 @@ export async function systemUsersProfilePut(input: { query: SystemUsersProfilePu
|
|
|
619
643
|
}
|
|
620
644
|
}
|
|
621
645
|
|
|
622
|
-
export type
|
|
623
|
-
export type
|
|
646
|
+
export type SystemUsersPasswordPutQuery = z.input<(typeof schemas)["systemUsersPasswordPut"]["query"]>;
|
|
647
|
+
export type SystemUsersPasswordPutBody = z.input<(typeof schemas)["systemUsersPasswordPut"]["body"]>;
|
|
648
|
+
export type SystemUsersPasswordPutData = z.infer<(typeof schemas)["systemUsersPasswordPut"]["data"]>;
|
|
624
649
|
|
|
625
|
-
export async function
|
|
650
|
+
export async function systemUsersPasswordPut(input: { query: SystemUsersPasswordPutQuery, body: SystemUsersPasswordPutBody }): Promise<SystemUsersPasswordPutData> {
|
|
626
651
|
const client = ensureReq();
|
|
627
652
|
try {
|
|
628
|
-
const env = await client.put(`system/users/
|
|
653
|
+
const env = await client.put(`system/users/password`, { searchParams: input.query as Record<string, string | number | boolean>, json: input.body }).json<OjEnvelope<SystemUsersPasswordPutData>>();
|
|
629
654
|
// 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
|
|
630
655
|
if (typeof env.code === "number" && env.code !== 0)
|
|
631
656
|
throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
|
|
632
|
-
const data = env.data as
|
|
657
|
+
const data = env.data as SystemUsersPasswordPutData;
|
|
658
|
+
if (import.meta.env.DEV) {
|
|
659
|
+
const { schemas } = await import("./api.schemas");
|
|
660
|
+
const r = schemas["systemUsersPasswordPut"].data.safeParse(data);
|
|
661
|
+
if (!r.success)
|
|
662
|
+
throw new ContractApiError(-1, `[契约违例] systemUsersPasswordPut 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
663
|
+
}
|
|
633
664
|
return data;
|
|
634
665
|
}
|
|
635
666
|
catch (e) {
|
|
@@ -637,17 +668,24 @@ export async function systemUsersForbiddenPut(input: { query: SystemUsersForbidd
|
|
|
637
668
|
}
|
|
638
669
|
}
|
|
639
670
|
|
|
640
|
-
export type
|
|
641
|
-
export type
|
|
671
|
+
export type SystemUsersProfilePutQuery = z.input<(typeof schemas)["systemUsersProfilePut"]["query"]>;
|
|
672
|
+
export type SystemUsersProfilePutBody = z.input<(typeof schemas)["systemUsersProfilePut"]["body"]>;
|
|
673
|
+
export type SystemUsersProfilePutData = z.infer<(typeof schemas)["systemUsersProfilePut"]["data"]>;
|
|
642
674
|
|
|
643
|
-
export async function
|
|
675
|
+
export async function systemUsersProfilePut(input: { query: SystemUsersProfilePutQuery, body: SystemUsersProfilePutBody }): Promise<SystemUsersProfilePutData> {
|
|
644
676
|
const client = ensureReq();
|
|
645
677
|
try {
|
|
646
|
-
const env = await client.put(`system/users/
|
|
678
|
+
const env = await client.put(`system/users/profile`, { searchParams: input.query as Record<string, string | number | boolean>, json: input.body }).json<OjEnvelope<SystemUsersProfilePutData>>();
|
|
647
679
|
// 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
|
|
648
680
|
if (typeof env.code === "number" && env.code !== 0)
|
|
649
681
|
throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
|
|
650
|
-
const data = env.data as
|
|
682
|
+
const data = env.data as SystemUsersProfilePutData;
|
|
683
|
+
if (import.meta.env.DEV) {
|
|
684
|
+
const { schemas } = await import("./api.schemas");
|
|
685
|
+
const r = schemas["systemUsersProfilePut"].data.safeParse(data);
|
|
686
|
+
if (!r.success)
|
|
687
|
+
throw new ContractApiError(-1, `[契约违例] systemUsersProfilePut 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
688
|
+
}
|
|
651
689
|
return data;
|
|
652
690
|
}
|
|
653
691
|
catch (e) {
|
|
@@ -657,15 +695,22 @@ export async function systemUsersPasswordPut(input: { query: SystemUsersPassword
|
|
|
657
695
|
|
|
658
696
|
export type SystemUsersRolesPutQuery = z.input<(typeof schemas)["systemUsersRolesPut"]["query"]>;
|
|
659
697
|
export type SystemUsersRolesPutBody = z.input<(typeof schemas)["systemUsersRolesPut"]["body"]>;
|
|
698
|
+
export type SystemUsersRolesPutData = z.infer<(typeof schemas)["systemUsersRolesPut"]["data"]>;
|
|
660
699
|
|
|
661
|
-
export async function systemUsersRolesPut(input: { query: SystemUsersRolesPutQuery, body: SystemUsersRolesPutBody }): Promise<
|
|
700
|
+
export async function systemUsersRolesPut(input: { query: SystemUsersRolesPutQuery, body: SystemUsersRolesPutBody }): Promise<SystemUsersRolesPutData> {
|
|
662
701
|
const client = ensureReq();
|
|
663
702
|
try {
|
|
664
|
-
const env = await client.put(`system/users/roles`, { searchParams: input.query as Record<string, string | number | boolean>, json: input.body }).json<OjEnvelope<
|
|
703
|
+
const env = await client.put(`system/users/roles`, { searchParams: input.query as Record<string, string | number | boolean>, json: input.body }).json<OjEnvelope<SystemUsersRolesPutData>>();
|
|
665
704
|
// 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
|
|
666
705
|
if (typeof env.code === "number" && env.code !== 0)
|
|
667
706
|
throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
|
|
668
|
-
const data = env.data as
|
|
707
|
+
const data = env.data as SystemUsersRolesPutData;
|
|
708
|
+
if (import.meta.env.DEV) {
|
|
709
|
+
const { schemas } = await import("./api.schemas");
|
|
710
|
+
const r = schemas["systemUsersRolesPut"].data.safeParse(data);
|
|
711
|
+
if (!r.success)
|
|
712
|
+
throw new ContractApiError(-1, `[契约违例] systemUsersRolesPut 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
713
|
+
}
|
|
669
714
|
return data;
|
|
670
715
|
}
|
|
671
716
|
catch (e) {
|
|
@@ -99,10 +99,9 @@
|
|
|
99
99
|
},
|
|
100
100
|
"oplog": {
|
|
101
101
|
"filterAction": "Action",
|
|
102
|
-
"filterUsername": "Username (
|
|
102
|
+
"filterUsername": "Username (contains)",
|
|
103
103
|
"filterModule": "Module",
|
|
104
|
-
"
|
|
105
|
-
"truncated": "Results truncated by limit; narrow your filters",
|
|
104
|
+
"total": "{{total}} total",
|
|
106
105
|
"columns": {
|
|
107
106
|
"time": "Time",
|
|
108
107
|
"username": "Username",
|
|
@@ -99,10 +99,9 @@
|
|
|
99
99
|
},
|
|
100
100
|
"oplog": {
|
|
101
101
|
"filterAction": "操作 (action)",
|
|
102
|
-
"filterUsername": "
|
|
102
|
+
"filterUsername": "用户名(包含匹配)",
|
|
103
103
|
"filterModule": "模块",
|
|
104
|
-
"
|
|
105
|
-
"truncated": "结果已按上限截断,请缩小过滤范围",
|
|
104
|
+
"total": "共 {{total}} 条",
|
|
106
105
|
"columns": {
|
|
107
106
|
"time": "时间",
|
|
108
107
|
"username": "用户名",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SystemDepartmentsGetData, SystemDepartmentsMembersGetData } from "../../__client
|
|
1
|
+
import type { SystemDepartmentsGetData, SystemDepartmentsMembersGetData } from "../../__client";
|
|
2
2
|
|
|
3
3
|
import { PlusOutlined } from "@ant-design/icons";
|
|
4
4
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
systemDepartmentsPost,
|
|
33
33
|
systemDepartmentsPut,
|
|
34
34
|
systemUsersGet,
|
|
35
|
-
} from "../../__client
|
|
35
|
+
} from "../../__client";
|
|
36
36
|
import { explainError, isForbidden } from "../errors";
|
|
37
37
|
import { ForbiddenPanel } from "../forbidden";
|
|
38
38
|
import { WecomSyncBar } from "./sync-bar";
|
|
@@ -2,7 +2,7 @@ import { useQuery } from "@tanstack/react-query";
|
|
|
2
2
|
import { Card, Descriptions, Tag } from "antd";
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
4
|
|
|
5
|
-
import { systemLoginMethodsGet } from "../../__client
|
|
5
|
+
import { systemLoginMethodsGet } from "../../__client";
|
|
6
6
|
|
|
7
7
|
const METHOD_KEY: Record<string, string> = {
|
|
8
8
|
local: "system:loginMethodsPage.methodLocal",
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useQuery } from "@tanstack/react-query";
|
|
2
|
-
import {
|
|
2
|
+
import { Button, Form, Input, Space, Table, Tooltip } from "antd";
|
|
3
3
|
import dayjs from "dayjs";
|
|
4
4
|
import { useState } from "react";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
6
|
|
|
7
|
-
import { systemOplogGet } from "../../__client
|
|
7
|
+
import { systemOplogGet } from "../../__client";
|
|
8
8
|
import { isForbidden } from "../errors";
|
|
9
9
|
import { ForbiddenPanel } from "../forbidden";
|
|
10
10
|
|
|
@@ -12,20 +12,26 @@ interface OplogFilters {
|
|
|
12
12
|
action?: string
|
|
13
13
|
username?: string
|
|
14
14
|
module?: string
|
|
15
|
-
limit?: number
|
|
16
15
|
}
|
|
17
16
|
|
|
17
|
+
const DEFAULT_PAGE_SIZE = 20;
|
|
18
|
+
const PAGE_SIZE_OPTIONS = [20, 50, 100];
|
|
19
|
+
|
|
18
20
|
/**
|
|
19
|
-
* 操作日志(AC1-29/D13):action 精确 / username
|
|
20
|
-
*
|
|
21
|
+
* 操作日志(AC1-29/D13):action 精确 / username 包含 / module 精确。
|
|
22
|
+
*
|
|
23
|
+
* 分页交给服务端:`page` + `limit`(每页条数,钳 200),响应带 `total`,页面按 total 出页码。
|
|
24
|
+
* 不再有「结果被截断」的横幅——记录再多也能通过页码翻到,不必靠缩小过滤范围。
|
|
21
25
|
*/
|
|
22
26
|
export default function OplogPage() {
|
|
23
27
|
const { t } = useTranslation();
|
|
24
28
|
const [filters, setFilters] = useState<OplogFilters>({});
|
|
29
|
+
const [page, setPage] = useState(1);
|
|
30
|
+
const [size, setSize] = useState(DEFAULT_PAGE_SIZE);
|
|
25
31
|
|
|
26
32
|
const query = useQuery({
|
|
27
|
-
queryKey: ["system", "oplog", filters],
|
|
28
|
-
queryFn: () => systemOplogGet(filters),
|
|
33
|
+
queryKey: ["system", "oplog", filters, page, size],
|
|
34
|
+
queryFn: () => systemOplogGet({ ...filters, page, limit: size }),
|
|
29
35
|
});
|
|
30
36
|
|
|
31
37
|
if (query.error && isForbidden(query.error))
|
|
@@ -50,12 +56,14 @@ export default function OplogPage() {
|
|
|
50
56
|
<Space direction="vertical" style={{ width: "100%", paddingTop: 16 }}>
|
|
51
57
|
<Form
|
|
52
58
|
layout="inline"
|
|
53
|
-
onFinish={values =>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
onFinish={(values) => {
|
|
60
|
+
setFilters({
|
|
61
|
+
action: values.action || undefined,
|
|
62
|
+
username: values.username || undefined,
|
|
63
|
+
module: values.module || undefined,
|
|
64
|
+
});
|
|
65
|
+
setPage(1);
|
|
66
|
+
}}
|
|
59
67
|
>
|
|
60
68
|
<Form.Item name="action" label={t("system:oplog.filterAction")}>
|
|
61
69
|
<Input allowClear />
|
|
@@ -66,25 +74,42 @@ export default function OplogPage() {
|
|
|
66
74
|
<Form.Item name="module" label={t("system:oplog.filterModule")}>
|
|
67
75
|
<Input allowClear />
|
|
68
76
|
</Form.Item>
|
|
69
|
-
<Form.Item name="limit" label={t("system:oplog.filterLimit")} initialValue={50}>
|
|
70
|
-
<InputNumber min={1} max={200} />
|
|
71
|
-
</Form.Item>
|
|
72
77
|
<Form.Item>
|
|
73
78
|
<Space>
|
|
74
79
|
<Button type="primary" htmlType="submit">{t("system:common.search")}</Button>
|
|
75
|
-
<Button
|
|
80
|
+
<Button
|
|
81
|
+
onClick={() => {
|
|
82
|
+
setFilters({});
|
|
83
|
+
setPage(1);
|
|
84
|
+
}}
|
|
85
|
+
>
|
|
76
86
|
{t("system:common.reset")}
|
|
77
87
|
</Button>
|
|
78
88
|
</Space>
|
|
79
89
|
</Form.Item>
|
|
80
90
|
</Form>
|
|
81
|
-
{query.data?.truncated ? <Alert type="warning" showIcon message={t("system:oplog.truncated")} /> : null}
|
|
82
91
|
<Table
|
|
83
92
|
rowKey="id"
|
|
84
93
|
loading={query.isLoading}
|
|
85
94
|
dataSource={query.data?.list ?? []}
|
|
86
95
|
columns={columns}
|
|
87
|
-
pagination={{
|
|
96
|
+
pagination={{
|
|
97
|
+
current: page,
|
|
98
|
+
pageSize: size,
|
|
99
|
+
total: query.data?.total ?? 0,
|
|
100
|
+
showSizeChanger: true,
|
|
101
|
+
pageSizeOptions: PAGE_SIZE_OPTIONS,
|
|
102
|
+
showTotal: total => t("system:oplog.total", { total }),
|
|
103
|
+
onChange: (nextPage, nextSize) => {
|
|
104
|
+
// 改每页条数后原页码可能越界:统一回第 1 页
|
|
105
|
+
if (nextSize !== size) {
|
|
106
|
+
setSize(nextSize);
|
|
107
|
+
setPage(1);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
setPage(nextPage);
|
|
111
|
+
},
|
|
112
|
+
}}
|
|
88
113
|
/>
|
|
89
114
|
</Space>
|
|
90
115
|
);
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import type { SystemPermissionsGetData, SystemRolesGetData } from "../../__client
|
|
1
|
+
import type { SystemPermissionsGetData, SystemRolesGetData } from "../../__client";
|
|
2
2
|
|
|
3
3
|
import { useQuery } from "@tanstack/react-query";
|
|
4
4
|
import { Alert, Space, Table, Tabs, Tag } from "antd";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
6
|
|
|
7
|
-
import { systemPermissionsGet, systemRolesGet } from "../../__client
|
|
7
|
+
import { systemPermissionsGet, systemRolesGet } from "../../__client";
|
|
8
8
|
import { isForbidden } from "../errors";
|
|
9
9
|
import { ForbiddenPanel } from "../forbidden";
|
|
10
|
+
import { visibleRoles } from "./visible-roles";
|
|
10
11
|
|
|
11
12
|
type RoleRow = SystemRolesGetData[number];
|
|
12
13
|
type PermRow = SystemPermissionsGetData[number];
|
|
@@ -19,6 +20,7 @@ export default function RolesPage() {
|
|
|
19
20
|
const { t } = useTranslation();
|
|
20
21
|
const rolesQuery = useQuery({ queryKey: ["system", "roles"], queryFn: systemRolesGet });
|
|
21
22
|
const permsQuery = useQuery({ queryKey: ["system", "permissions"], queryFn: systemPermissionsGet });
|
|
23
|
+
const rows = visibleRoles(rolesQuery.data ?? []);
|
|
22
24
|
|
|
23
25
|
if ((rolesQuery.error && isForbidden(rolesQuery.error)) || (permsQuery.error && isForbidden(permsQuery.error)))
|
|
24
26
|
return <ForbiddenPanel t={t} error={rolesQuery.error ?? permsQuery.error} />;
|
|
@@ -75,7 +77,7 @@ export default function RolesPage() {
|
|
|
75
77
|
children: (
|
|
76
78
|
<>
|
|
77
79
|
<Alert style={{ marginBottom: 12 }} type="info" showIcon message={t("system:rolesPage.readonlyHint")} />
|
|
78
|
-
<Table rowKey="name" loading={rolesQuery.isLoading} dataSource={
|
|
80
|
+
<Table rowKey="name" loading={rolesQuery.isLoading} dataSource={rows} columns={roleColumns} pagination={{ hideOnSinglePage: true }} />
|
|
79
81
|
</>
|
|
80
82
|
),
|
|
81
83
|
},
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 角色展示页的可见范围(纯函数,便于用例直接钉住,不必起 React)。
|
|
3
|
+
*
|
|
4
|
+
* superadmin 是平台级角色(跨租户),不属于「站点可分配的角色目录」;列在角色页只会让人
|
|
5
|
+
* 误以为能改它的绑定,故展示层隐去。
|
|
6
|
+
*
|
|
7
|
+
* **只在这一层过滤**:后端 listRoles() 必须原样返回 superadmin——成员资格页
|
|
8
|
+
* (users/roles.tsx)还要拿它作为可授予项(仅 superadmin 可勾选,见那里的 disabled 逻辑)。
|
|
9
|
+
*/
|
|
10
|
+
export const HIDDEN_ROLE = "superadmin";
|
|
11
|
+
|
|
12
|
+
export function visibleRoles<T extends { name: string }>(roles: readonly T[]): T[] {
|
|
13
|
+
return roles.filter(r => r.name !== HIDDEN_ROLE);
|
|
14
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { TFunction } from "i18next";
|
|
2
2
|
|
|
3
|
-
import type { SystemSettingsGetData } from "../../__client
|
|
3
|
+
import type { SystemSettingsGetData } from "../../__client";
|
|
4
4
|
|
|
5
5
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
6
6
|
import { App, Button, Card, Input, Space, Switch, Tooltip } from "antd";
|
|
7
7
|
import { useState } from "react";
|
|
8
8
|
import { useTranslation } from "react-i18next";
|
|
9
9
|
|
|
10
|
-
import { systemSettingsGet, systemSettingsPut } from "../../__client
|
|
10
|
+
import { systemSettingsGet, systemSettingsPut } from "../../__client";
|
|
11
11
|
import { explainError, isForbidden } from "../errors";
|
|
12
12
|
import { ForbiddenPanel } from "../forbidden";
|
|
13
13
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /system/users 行级操作门禁:只有 superadmin 能改 superadmin 账号。
|
|
3
|
+
*
|
|
4
|
+
* 与后端 `domain/users.ts::assertCanManageTarget` 同一条红线(只有 superadmin 能改
|
|
5
|
+
* superadmin 的口令/状态/资料/角色)。前端这层只为「不给会 403 的按钮」——灰色可点却不
|
|
6
|
+
* 生效比报错更糟——真正的防线在服务端:admin 直打接口同样会被 403 挡住。
|
|
7
|
+
*
|
|
8
|
+
* 单独成文件是为了可测:vitest 跑在 node 环境,没有 jsdom,整页 render 不了。
|
|
9
|
+
*/
|
|
10
|
+
export const PLATFORM_ROLE = "superadmin";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param myRoles 当前登录者的角色
|
|
14
|
+
* @param targetRoles 行上用户的角色
|
|
15
|
+
* @returns 是否允许对目标账号执行管理操作(改密/启停/改资料/成员资格)
|
|
16
|
+
*/
|
|
17
|
+
export function canManageUser(myRoles: readonly string[], targetRoles: readonly string[]): boolean {
|
|
18
|
+
if (!targetRoles.includes(PLATFORM_ROLE))
|
|
19
|
+
return true;
|
|
20
|
+
return myRoles.includes(PLATFORM_ROLE);
|
|
21
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SystemUsersGetData } from "../../__client
|
|
1
|
+
import type { SystemUsersGetData } from "../../__client";
|
|
2
2
|
|
|
3
3
|
import { PlusOutlined } from "@ant-design/icons";
|
|
4
4
|
import { useUserStore } from "@oj-module/runtime";
|
|
@@ -9,16 +9,19 @@ import { useTranslation } from "react-i18next";
|
|
|
9
9
|
|
|
10
10
|
import { useNavigate } from "react-router";
|
|
11
11
|
|
|
12
|
-
import { systemDepartmentsGet, systemUsersForbiddenPut, systemUsersGet, systemUsersPasswordPut, systemUsersPost } from "../../__client
|
|
12
|
+
import { systemDepartmentsGet, systemUsersForbiddenPut, systemUsersGet, systemUsersPasswordPut, systemUsersPost } from "../../__client";
|
|
13
13
|
import { buildTreeData, subtreeIds } from "../departments/tree";
|
|
14
14
|
import { explainError, isForbidden } from "../errors";
|
|
15
15
|
import { ForbiddenPanel } from "../forbidden";
|
|
16
|
+
import { canManageUser } from "./can-manage";
|
|
16
17
|
|
|
17
18
|
type UserRow = SystemUsersGetData[number];
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* 用户管理(C1):GET /system/users 列表 + 建号 / 禁用切换 / 重置口令。
|
|
21
22
|
* 本人行禁用一切自操作(后端 assertNotSelf 400 兜底,前端不给会失败的按钮,R3);
|
|
23
|
+
* superadmin 行也禁用一切操作,除非当前登录者是 superadmin(红线:只有 superadmin 能改
|
|
24
|
+
* superadmin——后端 assertCanManageTarget 403 兜底,前端把按钮置灰);
|
|
22
25
|
* 成员资格入口:superadmin 与 **本租户 admin** 均可见(授予 admin 已下放到租户内,
|
|
23
26
|
* 但授予 superadmin 仍只许 superadmin——见 domain/users.ts::assertMembershipAllowed)。
|
|
24
27
|
* 部门列标出主部门,顶部可按部门筛选(含子部门)——筛选在前端做,名单本来就是一页全量。
|
|
@@ -117,8 +120,10 @@ export default function UsersPage() {
|
|
|
117
120
|
title={t("system:users.forbidden")}
|
|
118
121
|
description={`${row.username} → ${forbidden ? "false" : "true"}`}
|
|
119
122
|
onConfirm={() => forbiddenMut.mutate({ uid: row.id, forbidden: !forbidden })}
|
|
123
|
+
// 置灰的 Switch 不会触发 Popconfirm,这里只是把「为什么点不了」挡在确认框之前
|
|
124
|
+
disabled={String(row.id) === me || !canManageUser(myRoles, row.roles)}
|
|
120
125
|
>
|
|
121
|
-
<Switch size="small" checked={forbidden} disabled={String(row.id) === me} />
|
|
126
|
+
<Switch size="small" checked={forbidden} disabled={String(row.id) === me || !canManageUser(myRoles, row.roles)} />
|
|
122
127
|
</Popconfirm>
|
|
123
128
|
{row.must_change ? <Tag color="orange">{t("system:users.firstLoginHint")}</Tag> : null}
|
|
124
129
|
</Space>
|
|
@@ -127,20 +132,23 @@ export default function UsersPage() {
|
|
|
127
132
|
{
|
|
128
133
|
title: t("system:users.columns.actions"),
|
|
129
134
|
key: "actions",
|
|
130
|
-
render: (_: unknown, row: UserRow) =>
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
render: (_: unknown, row: UserRow) => {
|
|
136
|
+
const manageable = canManageUser(myRoles, row.roles);
|
|
137
|
+
return (
|
|
138
|
+
<Space>
|
|
139
|
+
<Button size="small" disabled={String(row.id) === me || !manageable} onClick={() => setPwdTarget(row)}>
|
|
140
|
+
{t("system:users.resetPwd")}
|
|
141
|
+
</Button>
|
|
135
142
|
{canManageMembership
|
|
136
143
|
? (
|
|
137
|
-
<Button size="small" type="link" onClick={() => navigate(`/system/users/${row.id}/roles`)}>
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
+
<Button size="small" type="link" disabled={!manageable} onClick={() => navigate(`/system/users/${row.id}/roles`)}>
|
|
145
|
+
{t("system:users.membership")}
|
|
146
|
+
</Button>
|
|
147
|
+
)
|
|
148
|
+
: null}
|
|
149
|
+
</Space>
|
|
150
|
+
);
|
|
151
|
+
},
|
|
144
152
|
},
|
|
145
153
|
];
|
|
146
154
|
|
|
@@ -6,7 +6,7 @@ import { useTranslation } from "react-i18next";
|
|
|
6
6
|
|
|
7
7
|
import { useNavigate, useParams } from "react-router";
|
|
8
8
|
|
|
9
|
-
import { systemRolesGet, systemUsersGet, systemUsersRolesPut } from "../../__client
|
|
9
|
+
import { systemRolesGet, systemUsersGet, systemUsersRolesPut } from "../../__client";
|
|
10
10
|
import { explainError, isForbidden } from "../errors";
|
|
11
11
|
import { ForbiddenPanel } from "../forbidden";
|
|
12
12
|
|