@liujitcn/kratos-taro-app-system 0.1.4 → 0.1.11

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/README.md CHANGED
@@ -54,3 +54,6 @@ pnpm test
54
54
  pnpm build:h5
55
55
  pnpm build:mp-weixin
56
56
  ```
57
+
58
+ AI 共用 RPC 同步人工确认消息类型;应用端会话仅开放读取工具,写操作确认由管理端完成。
59
+ AI 仅对最新且已结束的助手消息提供重新生成入口,历史消息仍可复制或删除。
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "type": "git",
8
8
  "url": "git@github.com:liujitcn/kratos-admin.git"
9
9
  },
10
- "version": "0.1.4",
10
+ "version": "0.1.11",
11
11
  "type": "module",
12
12
  "files": [
13
13
  "dist",
@@ -39,8 +39,8 @@
39
39
  "@tarojs/components": "4.2.1",
40
40
  "@tarojs/taro": "4.2.1",
41
41
  "react": "18.3.1",
42
- "@liujitcn/kratos-taro-app-ui": "^0.1.4",
43
- "@liujitcn/kratos-taro-app-core": "^0.1.4"
42
+ "@liujitcn/kratos-taro-app-core": "^0.1.11",
43
+ "@liujitcn/kratos-taro-app-ui": "^0.1.11"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "pnpm run build:entries && pnpm pack --pack-destination ../../../dist/npm",
@@ -11,6 +11,7 @@ import Taro from '@tarojs/taro'
11
11
  import type { ListAiMessageRequest, ListAiMessageResponse } from '../../../rpc/base/v1/ai_session'
12
12
  import type {
13
13
  AiMessageService,
14
+ DecideAiToolApprovalRequest,
14
15
  DeleteAiMessageRequest,
15
16
  DeleteAiMessageResponse,
16
17
  RegenerateAiMessageRequest,
@@ -202,6 +203,15 @@ export function StreamAiMessageByChunkedRequest(
202
203
 
203
204
  /** AI 助手消息服务。 */
204
205
  export class AiMessageServiceImpl implements AiMessageService {
206
+ /** 共用契约的审批入口;移动端会话由服务端拒绝写入审批。 */
207
+ DecideAiToolApproval(request: DecideAiToolApprovalRequest): Promise<SendAiMessageResponse> {
208
+ return http<SendAiMessageResponse>({
209
+ url: `${AI_SESSION_URL}/${request.session_id}/message/${request.message_id}/approval`,
210
+ method: 'POST',
211
+ data: request,
212
+ })
213
+ }
214
+
205
215
  /** 查询 AI 助手消息列表。 */
206
216
  ListAiMessage(request: ListAiMessageRequest): Promise<ListAiMessageResponse> {
207
217
  return http<ListAiMessageResponse>({
@@ -9,7 +9,7 @@ import type {
9
9
  MarkAllNotificationReadRequest,
10
10
  MarkNotificationReadRequest,
11
11
  MarkNotificationUnreadRequest,
12
- Notification,
12
+ NotificationDetail,
13
13
  NotificationService,
14
14
  NotificationSummary,
15
15
  PageNotificationRequest,
@@ -58,7 +58,7 @@ export class NotificationServiceImpl implements NotificationService {
58
58
  }))
59
59
  }
60
60
  /** 查询消息详情。 */
61
- GetNotification(request: GetNotificationRequest): Promise<Notification> {
61
+ GetNotification(request: GetNotificationRequest): Promise<NotificationDetail> {
62
62
  return http({ url: `${NOTIFICATION_URL}/${request.id}`, method: 'GET', authMode: 'required' })
63
63
  }
64
64
  /** 查询未读汇总。 */
@@ -1,12 +1,24 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: base/v1/ai_message.proto
6
6
 
7
7
  /* eslint-disable */
8
8
  import type { AiAttachment, AiMessage, AiSession } from "./ai_session";
9
9
 
10
+ /** AI 工具人工确认请求,实际工具和参数由服务端冻结。 */
11
+ export interface DecideAiToolApprovalRequest {
12
+ /** 会话ID */
13
+ session_id: string;
14
+ /** 消息ID */
15
+ message_id: string;
16
+ /** 一次性审批编号 */
17
+ approval_id: string;
18
+ /** 是否确认执行 */
19
+ approved: boolean;
20
+ }
21
+
10
22
  /** AI 助手消息更新请求 */
11
23
  export interface UpdateAiMessageRequest {
12
24
  /** 会话ID */
@@ -93,6 +105,8 @@ export interface AiAction {
93
105
 
94
106
  /** Base AI 助手消息服务 */
95
107
  export interface AiMessageService {
108
+ /** 确认或拒绝当前用户的待执行工具调用。 */
109
+ DecideAiToolApproval(request: DecideAiToolApprovalRequest): Promise<SendAiMessageResponse>;
96
110
  /** 更新 AI 助手消息并重新生成输出 */
97
111
  UpdateAiMessage(request: UpdateAiMessageRequest): Promise<SendAiMessageResponse>;
98
112
  /** 删除 AI 助手消息 */
@@ -1,12 +1,12 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: base/v1/ai_session.proto
6
6
 
7
7
  /* eslint-disable */
8
8
  import type { Timestamp } from "../../google/protobuf/timestamp";
9
- import type { AiToolCall, Terminal } from "./ai_tool";
9
+ import type { AiToolApproval, AiToolCall, Terminal } from "./ai_tool";
10
10
 
11
11
  /** AI 助手消息状态。 */
12
12
  export enum AiMessageStatus {
@@ -18,6 +18,8 @@ export enum AiMessageStatus {
18
18
  AI_MESSAGE_STATUS_SUCCESS = 2,
19
19
  /** AI_MESSAGE_STATUS_FAILED - 失败。 */
20
20
  AI_MESSAGE_STATUS_FAILED = 3,
21
+ /** AI_MESSAGE_STATUS_WAITING_APPROVAL - 等待用户确认工具调用。 */
22
+ AI_MESSAGE_STATUS_WAITING_APPROVAL = 4,
21
23
  }
22
24
 
23
25
  /** AI 助手消息列表查询条件 */
@@ -184,6 +186,8 @@ export interface AiOutputContent {
184
186
  step: string;
185
187
  /** 移动端结构化内容JSON */
186
188
  blocks_json: string;
189
+ /** 待执行工具的人工确认信息 */
190
+ approval: AiToolApproval | undefined;
187
191
  }
188
192
 
189
193
  /** AI 助手 Token 统计 */
@@ -1,10 +1,11 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: base/v1/ai_tool.proto
6
6
 
7
7
  /* eslint-disable */
8
+ import type { Timestamp } from "../../google/protobuf/timestamp";
8
9
 
9
10
  /** 终端类型。 */
10
11
  export enum Terminal {
@@ -16,6 +17,26 @@ export enum Terminal {
16
17
  TERMINAL_ADMIN = 2,
17
18
  }
18
19
 
20
+ /** AI 工具人工确认信息。 */
21
+ export interface AiToolApproval {
22
+ /** 一次性审批编号 */
23
+ id: string;
24
+ /** 待确认的工具和冻结参数 */
25
+ calls: AiApprovalTool[];
26
+ /** 确认截止时间 */
27
+ expires_at: Timestamp | undefined;
28
+ }
29
+
30
+ /** AI 待确认工具调用。 */
31
+ export interface AiApprovalTool {
32
+ /** 工具名称 */
33
+ name: string;
34
+ /** 操作说明 */
35
+ title: string;
36
+ /** 待执行的冻结参数JSON */
37
+ arguments: string;
38
+ }
39
+
19
40
  /** AI 助手快捷入口列表查询条件 */
20
41
  export interface ListAiShortcutRequest {
21
42
  /** 终端类型:枚举【Terminal】 */
@@ -1,6 +1,6 @@
1
1
  // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
2
  // versions:
3
- // protoc-gen-ts_proto v2.7.7
3
+ // protoc-gen-ts_proto v2.12.1
4
4
  // protoc unknown
5
5
  // source: base/v1/notification.proto
6
6
 
@@ -274,8 +274,36 @@ export interface DeleteNotificationRequest {
274
274
  id: number;
275
275
  }
276
276
 
277
- /** 当前用户消息。 */
277
+ /** 当前用户消息列表项。 */
278
278
  export interface Notification {
279
+ /** 投递ID */
280
+ id: number;
281
+ /** 分类名称 */
282
+ category_name: string;
283
+ /** 分类图标 */
284
+ category_icon: string;
285
+ /** 分类颜色 */
286
+ category_color: string;
287
+ /** 消息标题 */
288
+ title: string;
289
+ /** 动作目标 */
290
+ action_target: string;
291
+ /** 动作参数JSON */
292
+ action_params: string;
293
+ /** 接收时间 */
294
+ received_at: string;
295
+ /** 已读时间 */
296
+ read_at: string;
297
+ /** 归档时间 */
298
+ archived_at: string;
299
+ /** 是否允许归档 */
300
+ allow_archive: boolean;
301
+ /** 是否允许删除 */
302
+ allow_delete: boolean;
303
+ }
304
+
305
+ /** 消息详情。 */
306
+ export interface NotificationDetail {
279
307
  /** 投递ID */
280
308
  id: number;
281
309
  /** 租户ID */
@@ -304,8 +332,6 @@ export interface Notification {
304
332
  action_target: string;
305
333
  /** 动作参数JSON */
306
334
  action_params: string;
307
- /** 发送者名称 */
308
- sender_name: string;
309
335
  /** 接收时间 */
310
336
  received_at: string;
311
337
  /** 已读时间 */
@@ -329,7 +355,7 @@ export interface NotificationService {
329
355
  /** 查询当前用户未读汇总。 */
330
356
  GetNotificationSummary(request: GetNotificationSummaryRequest): Promise<NotificationSummary>;
331
357
  /** 查询当前用户消息详情。 */
332
- GetNotification(request: GetNotificationRequest): Promise<Notification>;
358
+ GetNotification(request: GetNotificationRequest): Promise<NotificationDetail>;
333
359
  /** 标记消息为已读。 */
334
360
  MarkNotificationRead(request: MarkNotificationReadRequest): Promise<Empty>;
335
361
  /** 标记消息为未读。 */
@@ -24,7 +24,7 @@
24
24
  padding: 20px 40px calc(40px + env(safe-area-inset-bottom));
25
25
  overflow: hidden;
26
26
  background: var(--kratos-color-surface-solid, #070d18);
27
- border-radius: 40px 40px 0 0;
27
+ border-radius: var(--kratos-page-radius) var(--kratos-page-radius) 0 0;
28
28
  box-sizing: border-box;
29
29
  }
30
30
 
@@ -34,7 +34,7 @@
34
34
  height: 8px;
35
35
  margin: 0 auto 20px;
36
36
  background: var(--kratos-color-track, rgba(255, 255, 255, 0.06));
37
- border-radius: 4px;
37
+ border-radius: var(--kratos-page-radius);
38
38
  }
39
39
 
40
40
  .knowledge-picker__head {
@@ -28,7 +28,7 @@
28
28
  background: var(--kratos-color-surface-solid, #070d18);
29
29
  border: 1PX solid var(--kratos-color-border-accent, rgba(120, 230, 215, 0.16));
30
30
  border-bottom: 0;
31
- border-radius: 32px 32px 0 0;
31
+ border-radius: var(--kratos-page-radius) var(--kratos-page-radius) 0 0;
32
32
  box-shadow: 0 -24px 80px rgba(15, 23, 42, 0.16);
33
33
  box-sizing: border-box;
34
34
  }
@@ -39,7 +39,7 @@
39
39
  height: 8px;
40
40
  margin: 16px auto 8px;
41
41
  background: var(--kratos-color-track, rgba(255, 255, 255, 0.06));
42
- border-radius: 4px;
42
+ border-radius: var(--kratos-page-radius);
43
43
  }
44
44
 
45
45
  .model-picker__head {
@@ -101,7 +101,7 @@
101
101
  margin-bottom: 12px;
102
102
  border: 1PX solid var(--kratos-color-border, rgba(255, 255, 255, 0.08));
103
103
  background: var(--kratos-color-surface, rgba(255, 255, 255, 0.035));
104
- border-radius: 20px;
104
+ border-radius: var(--kratos-page-radius);
105
105
  box-sizing: border-box;
106
106
  }
107
107
 
@@ -65,7 +65,7 @@
65
65
  width: 112px;
66
66
  height: 52px;
67
67
  border: 1PX solid var(--kratos-color-primary-edge, rgba(40, 240, 212, 0.3));
68
- border-radius: 12px;
68
+ border-radius: var(--kratos-page-radius);
69
69
  color: var(--kratos-color-primary, #28f0d4);
70
70
  font-size: 24px;
71
71
  line-height: 50px;
@@ -81,7 +81,7 @@
81
81
  padding: 0 18px;
82
82
  margin-bottom: 18px;
83
83
  border: 1PX solid var(--kratos-color-border, rgba(255, 255, 255, 0.08));
84
- border-radius: 12px;
84
+ border-radius: var(--kratos-page-radius);
85
85
  background: var(--kratos-color-surface-2, rgba(255, 255, 255, 0.06));
86
86
  box-sizing: border-box;
87
87
  }
@@ -101,7 +101,7 @@
101
101
  gap: 12px;
102
102
  padding: 22px 16px 22px 22px;
103
103
  border: 1PX solid var(--kratos-color-border, rgba(255, 255, 255, 0.08));
104
- border-radius: 14px;
104
+ border-radius: var(--kratos-page-radius);
105
105
  background: var(--kratos-color-surface, rgba(255, 255, 255, 0.035));
106
106
  }
107
107
 
@@ -185,7 +185,7 @@
185
185
  min-width: 350px;
186
186
  height: 96px;
187
187
  padding: 0 34px 0 78px;
188
- border-radius: 18px;
188
+ border-radius: var(--kratos-page-radius);
189
189
  font-size: 30px;
190
190
  line-height: 96px;
191
191
  }
@@ -196,7 +196,7 @@
196
196
  min-height: 96px;
197
197
  margin-top: 30px;
198
198
  padding: 24px 28px;
199
- border-radius: 18px;
199
+ border-radius: var(--kratos-page-radius);
200
200
  font-size: 29px;
201
201
  line-height: 44px;
202
202
  }
@@ -205,7 +205,7 @@
205
205
  margin-top: 34px;
206
206
  padding: 30px 28px 24px;
207
207
  border: 1PX solid var(--kratos-color-border-accent, rgba(120, 230, 215, 0.16));
208
- border-radius: 16px;
208
+ border-radius: var(--kratos-page-radius);
209
209
  background: var(--kratos-color-surface, #fff);
210
210
  box-shadow: var(--kratos-glow-soft, none);
211
211
  box-sizing: border-box;
@@ -265,7 +265,7 @@
265
265
  width: 36px;
266
266
  height: 36px;
267
267
  margin-right: 24px;
268
- border-radius: 8px;
268
+ border-radius: var(--kratos-page-radius);
269
269
  color: var(--kratos-color-primary, #28f0d4);
270
270
  font-size: 24px;
271
271
  font-weight: 700;
@@ -14,7 +14,7 @@
14
14
  flex-shrink: 0;
15
15
  width: 100%;
16
16
  margin-bottom: var(--kratos-tab-bar-space, calc(104px + env(safe-area-inset-bottom)));
17
- padding: 14px 24px calc(18px + env(safe-area-inset-bottom));
17
+ padding: 14px 24px 18px;
18
18
  overflow: hidden;
19
19
  background: var(--kratos-color-surface, #fff);
20
20
  border-top: 1PX solid var(--kratos-color-border-accent, rgba(0, 150, 134, 0.28));
@@ -32,7 +32,7 @@
32
32
  color: var(--kratos-color-text, #102232);
33
33
  background: var(--kratos-color-surface, #fff);
34
34
  border: 1PX solid var(--kratos-color-border-accent, rgba(0, 150, 134, 0.28));
35
- border-radius: 28px;
35
+ border-radius: var(--kratos-page-radius);
36
36
  box-sizing: border-box;
37
37
  }
38
38
 
@@ -65,7 +65,7 @@
65
65
  min-height: 124px;
66
66
  padding: 22px 18px;
67
67
  border: 1PX solid var(--kratos-color-border, #e3eaf2);
68
- border-radius: 24px;
68
+ border-radius: var(--kratos-page-radius);
69
69
  background: var(--kratos-color-surface, #fff);
70
70
  box-sizing: border-box;
71
71
  }
@@ -95,7 +95,7 @@
95
95
  min-height: 72px;
96
96
  padding: 0 12px 0 28px;
97
97
  border: 1PX solid var(--kratos-color-border, #e3eaf2);
98
- border-radius: 38px;
98
+ border-radius: var(--kratos-page-radius);
99
99
  background: var(--kratos-color-surface-2, #eef4fa);
100
100
  box-shadow: none;
101
101
  box-sizing: border-box;
@@ -116,7 +116,7 @@
116
116
  white-space: nowrap;
117
117
  padding: 6px 12px;
118
118
  border: 1PX solid var(--kratos-color-primary-edge, rgba(0, 150, 134, 0.3));
119
- border-radius: 8px;
119
+ border-radius: var(--kratos-page-radius);
120
120
  color: var(--kratos-color-primary, #039e8c);
121
121
  font-size: 20px;
122
122
  line-height: 28px;
@@ -35,7 +35,7 @@ page {
35
35
  .bubble {
36
36
  max-width: 86%;
37
37
  padding: 20px 24px;
38
- border-radius: 18px;
38
+ border-radius: var(--kratos-page-radius);
39
39
  box-sizing: border-box;
40
40
  word-break: break-word;
41
41
  }
@@ -43,14 +43,12 @@ page {
43
43
  .user-bubble {
44
44
  color: var(--kratos-color-on-primary);
45
45
  background: linear-gradient(135deg, var(--kratos-color-primary-deep) 0%, var(--kratos-color-primary) 100%);
46
- border-bottom-right-radius: 6px;
47
46
  box-shadow: var(--kratos-glow);
48
47
  }
49
48
  .ai-bubble {
50
49
  color: var(--kratos-color-text);
51
50
  background: var(--kratos-color-surface);
52
51
  border: 1PX solid var(--kratos-color-border);
53
- border-bottom-left-radius: 6px;
54
52
  }
55
53
  .bubble.is-streaming { opacity: 0.72; }
56
54
  .bubble-content { white-space: pre-wrap; font-size: 28px; line-height: 1.65; }
@@ -76,7 +74,7 @@ page {
76
74
  padding: 12px;
77
75
  margin-top: 8px;
78
76
  border: 1PX solid var(--kratos-color-border);
79
- border-radius: 12px;
77
+ border-radius: var(--kratos-page-radius);
80
78
  background: var(--kratos-color-surface-2);
81
79
  box-sizing: border-box;
82
80
  }
@@ -86,7 +84,7 @@ page {
86
84
  width: 48px;
87
85
  height: 48px;
88
86
  border: 1PX solid var(--kratos-color-primary-edge);
89
- border-radius: 10px;
87
+ border-radius: var(--kratos-page-radius);
90
88
  color: var(--kratos-color-primary);
91
89
  font-size: 20px;
92
90
  line-height: 46px;
@@ -626,9 +626,17 @@ export default function AiPage() {
626
626
  }
627
627
  }
628
628
 
629
+ const canRegenerateMessage = (item: ChatMessageItem) => {
630
+ const current = messagesRef.current[activeSessionIDRef.current] ?? []
631
+ return item.role === 'ai' && !item.localOnly && !isSessionSending(activeSessionIDRef.current)
632
+ && item.status !== AiMessageStatus.AI_MESSAGE_STATUS_GENERATING
633
+ && item.status !== AiMessageStatus.AI_MESSAGE_STATUS_WAITING_APPROVAL
634
+ && current[current.length - 1]?.messageID === item.messageID
635
+ }
636
+
629
637
  const regenerateMessage = async (item: ChatMessageItem) => {
630
638
  const sessionID = activeSessionIDRef.current
631
- if (item.role !== 'ai' || item.localOnly || isSessionSending(sessionID)) return
639
+ if (!canRegenerateMessage(item)) return
632
640
  setSessionSending(sessionID, true)
633
641
  try {
634
642
  const response = await defAiMessageService.RegenerateAiMessage({ session_id: sessionID, message_id: item.messageID })
@@ -643,7 +651,7 @@ export default function AiPage() {
643
651
 
644
652
  const handleMessageAction = async (item: ChatMessageItem) => {
645
653
  try {
646
- const itemList = item.role === 'ai'
654
+ const itemList = canRegenerateMessage(item)
647
655
  ? [t('system.ai.action.copy'), t('common.action.delete'), t('system.ai.action.regenerate')]
648
656
  : [t('system.ai.action.copy'), t('common.action.delete')]
649
657
  const { tapIndex } = await Taro.showActionSheet({ itemList })
@@ -889,6 +897,7 @@ function mapMessageItem(message: AiMessage, role: ChatRole): ChatMessageItem {
889
897
  flow: message.output_content?.flow ?? '',
890
898
  step: message.output_content?.step ?? '',
891
899
  blocks_json: message.output_content?.blocks_json ?? '',
900
+ approval: message.output_content?.approval,
892
901
  }
893
902
  const status = Number(message.status ?? AiMessageStatus.AI_MESSAGE_STATUS_SUCCESS)
894
903
  return {
@@ -949,7 +958,7 @@ function createThinkingMessage(options?: { sessionID?: string; messageID?: strin
949
958
  input_content: undefined,
950
959
  output_content: {
951
960
  kind: 'text', content: t('system.ai.thinking'), reply_source: '', model: '', fallback: false,
952
- fallback_reason: '', flow: '', step: '', blocks_json: '',
961
+ fallback_reason: '', flow: '', step: '', blocks_json: '', approval: undefined,
953
962
  },
954
963
  attachments: [],
955
964
  created_at: { seconds: Math.floor(now / 1000), nanos: (now % 1000) * 1_000_000 },
@@ -4,7 +4,7 @@ import { useState } from 'react'
4
4
  import { KratosNavBar, t, useThemeStore } from '@liujitcn/kratos-taro-app-core'
5
5
  import { UniIcon } from '@liujitcn/kratos-taro-app-ui'
6
6
  import { defNotificationService } from '../../../api/base/v1/notification'
7
- import type { Notification } from '../../../rpc/base/v1/notification'
7
+ import type { NotificationDetail } from '../../../rpc/base/v1/notification'
8
8
  import { MessageContentFormat } from '../../../rpc/base/v1/notification'
9
9
  import { resolvePersistedMessage } from '../../../utils/persisted-message'
10
10
  import { resolveMessageCategoryIcon } from './icons'
@@ -13,7 +13,7 @@ import './message.scss'
13
13
  /** MessageDetailPage 展示站内信详情与通知操作。 */
14
14
  export default function MessageDetailPage() {
15
15
  const themeStore = useThemeStore()
16
- const [detail, setDetail] = useState<Notification>()
16
+ const [detail, setDetail] = useState<NotificationDetail>()
17
17
 
18
18
  useLoad((options) => {
19
19
  const id = Number(options?.id)
@@ -45,7 +45,6 @@ export default function MessageDetailPage() {
45
45
  />
46
46
  <Text>{detail.category_name}</Text>
47
47
  </View>
48
- <Text>{resolvePersistedMessage(detail.sender_name)}</Text>
49
48
  <Text>{detail.received_at}</Text>
50
49
  </View>
51
50
  {detail.content_format === MessageContentFormat.MESSAGE_CONTENT_FORMAT_RICH_TEXT ? (
@@ -27,7 +27,7 @@
27
27
  margin-top: 24px;
28
28
  padding: 0 24px;
29
29
  border: 1PX solid var(--kratos-color-border);
30
- border-radius: 16px;
30
+ border-radius: var(--kratos-page-radius);
31
31
  background: var(--kratos-color-surface-2);
32
32
  color: var(--kratos-color-text);
33
33
  font-size: 26px;
@@ -93,7 +93,7 @@
93
93
  display: block;
94
94
  padding: 28px;
95
95
  border: 1PX solid var(--kratos-color-border);
96
- border-radius: 20px;
96
+ border-radius: var(--kratos-page-radius);
97
97
  background: var(--kratos-color-surface);
98
98
  color: var(--kratos-color-text);
99
99
  font-size: 30px;
@@ -34,7 +34,7 @@
34
34
  .profile-av-img {
35
35
  width: 100%;
36
36
  height: 100%;
37
- border-radius: 22px;
37
+ border-radius: var(--kratos-page-radius);
38
38
  }
39
39
 
40
40
  /* 表单卡 */
@@ -83,7 +83,7 @@
83
83
  margin: 0;
84
84
  padding: 0 24px;
85
85
  border: 1PX solid var(--kratos-color-border-accent);
86
- border-radius: 999px;
86
+ border-radius: var(--kratos-page-radius);
87
87
  background: var(--kratos-color-primary-soft);
88
88
  color: var(--kratos-color-primary);
89
89
  font-size: 24px;
@@ -19,7 +19,7 @@
19
19
  max-height: calc(100vh - 64px);
20
20
  overflow-y: auto;
21
21
  background: var(--kratos-color-surface-solid);
22
- border-radius: 16px;
22
+ border-radius: var(--kratos-page-radius);
23
23
  box-shadow: 0 20px 64px rgb(0 0 0 / 20%);
24
24
  }
25
25
 
@@ -82,7 +82,7 @@
82
82
  color: var(--kratos-color-text);
83
83
  font-size: 30px;
84
84
  border: 1PX solid var(--kratos-color-border);
85
- border-radius: 8px;
85
+ border-radius: var(--kratos-page-radius);
86
86
  background: var(--kratos-color-surface-2);
87
87
  }
88
88
 
@@ -90,7 +90,7 @@
90
90
  margin-top: 20px;
91
91
  padding: 18px 20px;
92
92
  border: 1PX solid var(--kratos-color-border);
93
- border-radius: 10px;
93
+ border-radius: var(--kratos-page-radius);
94
94
  background: var(--kratos-color-surface-2);
95
95
  }
96
96
 
@@ -100,7 +100,7 @@
100
100
  .change-password-strength__label--medium { color: var(--kratos-color-warning); }
101
101
  .change-password-strength__label--high { color: var(--kratos-color-primary); }
102
102
  .change-password-strength__bars { display: flex; gap: 10px; margin-top: 14px; }
103
- .change-password-strength__bar { flex: 1; height: 10px; border-radius: 6px; background: var(--kratos-color-border); }
103
+ .change-password-strength__bar { flex: 1; height: 10px; border-radius: var(--kratos-page-radius); background: var(--kratos-color-border); }
104
104
  .change-password-strength__bar--low { background: var(--kratos-color-danger); }
105
105
  .change-password-strength__bar--medium { background: var(--kratos-color-warning); }
106
106
  .change-password-strength__bar--high { background: var(--kratos-color-primary); }
@@ -109,7 +109,7 @@
109
109
  .change-password-dialog__error { margin-top: 12px; color: var(--kratos-color-text-muted); font-size: 24px; line-height: 1.5; }
110
110
  .change-password-dialog__error { color: var(--kratos-color-danger); }
111
111
  .change-password-dialog__footer { display: flex; justify-content: flex-end; gap: 20px; padding: 0 32px 32px; }
112
- .change-password-dialog__button { min-width: 160px; height: 72px; margin: 0; padding: 0 24px; font-size: 28px; line-height: 72px; border: 0; border-radius: 8px; }
112
+ .change-password-dialog__button { min-width: 160px; height: 72px; margin: 0; padding: 0 24px; font-size: 28px; line-height: 72px; border: 0; border-radius: var(--kratos-page-radius); }
113
113
  .change-password-dialog__button::after { border: 0; }
114
114
  .change-password-dialog__button--cancel { color: var(--kratos-color-text-muted); background: var(--kratos-color-track); }
115
115
  .change-password-dialog__button--confirm { color: var(--kratos-color-on-primary); background: var(--kratos-color-primary); }
@@ -16,7 +16,7 @@
16
16
  width: 100%;
17
17
  max-width: 680px;
18
18
  overflow: hidden;
19
- border-radius: 16px;
19
+ border-radius: var(--kratos-page-radius);
20
20
  background-color: var(--kratos-color-surface-solid);
21
21
  box-shadow: 0 20px 64px rgba(0, 0, 0, 0.2);
22
22
  }
@@ -64,7 +64,7 @@
64
64
  font-size: 30px;
65
65
  border: 1PX solid var(--kratos-color-border);
66
66
  background-color: var(--kratos-color-surface-2);
67
- border-radius: 8px;
67
+ border-radius: var(--kratos-page-radius);
68
68
  box-sizing: border-box;
69
69
  }
70
70
 
@@ -102,7 +102,7 @@
102
102
  font-size: 28px;
103
103
  line-height: 72px;
104
104
  border: 0;
105
- border-radius: 8px;
105
+ border-radius: var(--kratos-page-radius);
106
106
  }
107
107
 
108
108
  .mfa-bind-dialog__button--cancel {