diff --git a/api/tenant/v1/agreement.go b/api/tenant/v1/agreement.go
index 3bf893d..662f94d 100644
--- a/api/tenant/v1/agreement.go
+++ b/api/tenant/v1/agreement.go
@@ -35,7 +35,7 @@ type TenantAgreementAcceptRes struct{}
// --- 公开端点(登录/注册页面使用,无需认证) ---
type AgreementCurrentListReq struct {
- g.Meta `path:"/agreements/current" method:"get" mime:"json" tags:"公开-用户协议" summary:"所有当前生效的协议列表" group:"public" middleware:"-"`
+ g.Meta `path:"/agreements/current" method:"get" mime:"json" tags:"公开-用户协议" summary:"所有当前生效的协议列表" middleware:"-"`
}
type PublicAgreementItem struct {
@@ -52,7 +52,7 @@ type AgreementCurrentListRes struct {
}
type AgreementCurrentGetReq struct {
- g.Meta `path:"/agreements/current/{code}" method:"get" mime:"json" tags:"公开-用户协议" summary:"按标识码获取当前协议详情" group:"public" middleware:"-"`
+ g.Meta `path:"/agreements/current/{code}" method:"get" mime:"json" tags:"公开-用户协议" summary:"按标识码获取当前协议详情" middleware:"-"`
Code string `json:"code" in:"path" v:"required|length:1,50"`
}
diff --git a/internal/middleware/tenant_auth.go b/internal/middleware/tenant_auth.go
index bc4d0fc..4138408 100644
--- a/internal/middleware/tenant_auth.go
+++ b/internal/middleware/tenant_auth.go
@@ -1,6 +1,8 @@
package middleware
import (
+ "strings"
+
"github.com/gogf/gf/v2/net/ghttp"
"github.com/qianfree/team-api/internal/dao"
@@ -21,6 +23,12 @@ var tenantPublicPaths = map[string]bool{
"/api/tenant/email/reset-password": true,
"/api/tenant/members/join": true,
"/api/tenant/members/invite-info": true,
+ "/api/tenant/agreements/current": true,
+}
+
+// tenantPublicPrefixes lists path prefixes that skip JWT auth (for dynamic routes like /current/{code}).
+var tenantPublicPrefixes = []string{
+ "/api/tenant/agreements/current/",
}
// TenantAuth is JWT authentication middleware for tenant console.
@@ -31,6 +39,12 @@ func TenantAuth(r *ghttp.Request) {
r.Middleware.Next()
return
}
+ for _, prefix := range tenantPublicPrefixes {
+ if strings.HasPrefix(r.URL.Path, prefix) {
+ r.Middleware.Next()
+ return
+ }
+ }
tokenStr := extractBearerToken(r)
if tokenStr == "" {
diff --git a/web/admin/src/views/system/SettingsPage.vue b/web/admin/src/views/system/SettingsPage.vue
index 37d6e60..dcc864a 100644
--- a/web/admin/src/views/system/SettingsPage.vue
+++ b/web/admin/src/views/system/SettingsPage.vue
@@ -14,6 +14,7 @@ import ContentFilterTab from './settings/ContentFilterTab.vue'
import ChannelTab from './settings/ChannelTab.vue'
import StorageTab from './settings/StorageTab.vue'
import DataGovernanceTab from './settings/DataGovernanceTab.vue'
+import AgreementTab from './settings/AgreementTab.vue'
interface SettingCategory {
key: string
@@ -34,6 +35,7 @@ const categoryMap: Record = {
channel: ChannelTab,
storage: StorageTab,
data_governance: DataGovernanceTab,
+ agreement: AgreementTab,
}
const categories = ref([])
diff --git a/web/tenant/src/router/tenant.ts b/web/tenant/src/router/tenant.ts
index 42a90ad..8de8845 100644
--- a/web/tenant/src/router/tenant.ts
+++ b/web/tenant/src/router/tenant.ts
@@ -32,12 +32,6 @@ const tenantRoutes: RouteRecordRaw[] = [
component: () => import('@/views/auth/ForgotPasswordPage.vue'),
meta: { requiresAuth: false, title: '找回密码' },
},
- {
- path: '/tenant/agreement/:code',
- name: 'TenantAgreement',
- component: () => import('@/views/auth/AgreementPage.vue'),
- meta: { requiresAuth: false, title: '协议详情' },
- },
{
path: '/tenant/join',
name: 'TenantJoin',
diff --git a/web/tenant/src/utils/request.ts b/web/tenant/src/utils/request.ts
index 5e8e938..a67cf17 100644
--- a/web/tenant/src/utils/request.ts
+++ b/web/tenant/src/utils/request.ts
@@ -104,7 +104,7 @@ async function doRefresh(): Promise {
return newTokens
}
-const PUBLIC_PATHS = ['/settings/', '/captcha', '/captcha/', '/auth/login', '/auth/register']
+const PUBLIC_PATHS = ['/settings/', '/captcha', '/captcha/', '/auth/login', '/auth/register', '/agreements/']
function isPublicPath(url?: string): boolean {
if (!url) return false
diff --git a/web/tenant/src/views/auth/AgreementPage.vue b/web/tenant/src/views/auth/AgreementPage.vue
deleted file mode 100644
index b5e0ec9..0000000
--- a/web/tenant/src/views/auth/AgreementPage.vue
+++ /dev/null
@@ -1,108 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{ title }}
-
版本 {{ version }}
-
-
-
-
-
-
-
-
- 返回登录
-
-
-
-
-
-
-
diff --git a/web/tenant/src/views/auth/LoginPage.vue b/web/tenant/src/views/auth/LoginPage.vue
index b5fd48d..ac7018d 100644
--- a/web/tenant/src/views/auth/LoginPage.vue
+++ b/web/tenant/src/views/auth/LoginPage.vue
@@ -10,6 +10,7 @@ import Icon from '@/components/common/Icon.vue'
import SlideCaptcha from '@/components/common/SlideCaptcha.vue'
import Turnstile from '@/components/common/Turnstile.vue'
import AgreementAcceptModal from '@/components/common/AgreementAcceptModal.vue'
+import AgreementViewModal from '@/components/common/AgreementViewModal.vue'
const router = useRouter()
const route = useRoute()
@@ -46,6 +47,15 @@ const accountInput = ref(null)
// Pending agreements
const showAgreements = ref(false)
+// Agreement view modal
+const showAgreementModal = ref(false)
+const agreementModalCode = ref('')
+
+function openAgreement(code: string) {
+ agreementModalCode.value = code
+ showAgreementModal.value = true
+}
+
function proceedAfterLogin() {
const pending = authStore.pendingAgreements
if (pending.length > 0) {
@@ -360,6 +370,11 @@ async function handleOAuthLogin(provider: string) {
{{ loading ? '登录中...' : '登录' }}
+
+
+ ·
+
+
@@ -452,6 +467,11 @@ async function handleOAuthLogin(provider: string) {
{{ loading ? '登录中...' : '登录' }}
+
+
+ ·
+
+
@@ -494,11 +514,6 @@ async function handleOAuthLogin(provider: string) {
立即创建
-
- 服务条款
- ·
- 隐私政策
-
@@ -507,6 +522,12 @@ async function handleOAuthLogin(provider: string) {
:agreements="authStore.pendingAgreements"
@accepted="onAgreementsAccepted"
/>
+
+