@liujitcn/kratos-uni-app-system 0.0.19 → 0.0.21
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/dist/index.mjs +1460 -7
- package/package.json +2 -2
- package/src/api/base/ai_message.ts +8 -5
- package/src/index.ts +18 -0
- package/src/locales/README.md +15 -0
- package/src/locales/en-US.json +91 -0
- package/src/locales/es-ES.json +91 -0
- package/src/locales/fr-FR.json +91 -0
- package/src/locales/ja-JP.json +91 -0
- package/src/locales/ko-KR.json +91 -0
- package/src/locales/zh-CN.json +91 -0
- package/src/locales/zh-TW.json +91 -0
- package/src/pages.ts +4 -4
- package/src/views/pages/my/my.vue +9 -7
- package/src/views/pagesMember/ai/components/SessionDrawer.vue +10 -6
- package/src/views/pagesMember/ai/components/WelcomePanel.vue +11 -7
- package/src/views/pagesMember/ai/index.vue +85 -66
- package/src/views/pagesMember/profile/profile.vue +22 -15
- package/src/views/pagesMember/settings/settings.vue +53 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { onLoad } from '@dcloudio/uni-app'
|
|
3
|
-
import { computed, nextTick, onBeforeUnmount, ref } from 'vue'
|
|
3
|
+
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'
|
|
4
4
|
import { defAiMessageService, StreamAiMessageByChunkedRequest } from '../../../api/base/ai_message'
|
|
5
5
|
import { defAiSessionService } from '../../../api/base/ai_session'
|
|
6
6
|
import { defAiToolService } from '../../../api/base/ai_tool'
|
|
@@ -13,7 +13,7 @@ import { formatSrc } from '@liujitcn/kratos-uni-app-core/utils/index'
|
|
|
13
13
|
import Composer from './components/Composer.vue'
|
|
14
14
|
import SessionDrawer from './components/SessionDrawer.vue'
|
|
15
15
|
import WelcomePanel from './components/WelcomePanel.vue'
|
|
16
|
-
import { navigateAppRoute } from '@liujitcn/kratos-uni-app-core'
|
|
16
|
+
import { navigateAppRoute, useI18n } from '@liujitcn/kratos-uni-app-core'
|
|
17
17
|
import {
|
|
18
18
|
type AiStreamEvent,
|
|
19
19
|
type AiStreamPayload,
|
|
@@ -56,11 +56,11 @@ type StreamTask = {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
const AI_TERMINAL = Terminal.TERMINAL_APP
|
|
59
|
-
const THINKING_MESSAGE_CONTENT = '正在回复'
|
|
60
59
|
const LOCAL_USER_MESSAGE_PREFIX = 'ai-user-local'
|
|
61
60
|
const PENDING_MESSAGE_ID = 'pending'
|
|
62
61
|
const MAX_ATTACHMENT_COUNT = 6
|
|
63
62
|
const STARTER_PROMPT_PAGE_SIZE = 4
|
|
63
|
+
const { locale, t } = useI18n()
|
|
64
64
|
|
|
65
65
|
const windowInfo = uni.getWindowInfo()
|
|
66
66
|
let safeAreaTop =
|
|
@@ -92,44 +92,45 @@ const runningStreamTaskMap = new Map<string, StreamTask>()
|
|
|
92
92
|
const pendingDeltaMap = new Map<string, AiStreamPayload>()
|
|
93
93
|
let pendingDeltaTimer = 0
|
|
94
94
|
|
|
95
|
-
const
|
|
95
|
+
const createStarterShortcuts = (): AiShortcut[] => [
|
|
96
96
|
{
|
|
97
97
|
key: 'summarize',
|
|
98
|
-
title: '
|
|
99
|
-
prompt: '
|
|
98
|
+
title: t('system.ai.prompt.summary'),
|
|
99
|
+
prompt: t('system.ai.prompt.summaryContent'),
|
|
100
100
|
action: undefined,
|
|
101
101
|
required_tools: [],
|
|
102
102
|
sort: 1,
|
|
103
|
-
group: '
|
|
103
|
+
group: t('system.ai.textAssistant'),
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
106
|
key: 'rewrite',
|
|
107
|
-
title: '
|
|
108
|
-
prompt: '
|
|
107
|
+
title: t('system.ai.prompt.optimize'),
|
|
108
|
+
prompt: t('system.ai.prompt.optimizeContent'),
|
|
109
109
|
action: undefined,
|
|
110
110
|
required_tools: [],
|
|
111
111
|
sort: 2,
|
|
112
|
-
group: '
|
|
112
|
+
group: t('system.ai.textAssistant'),
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
key: 'plan',
|
|
116
|
-
title: '
|
|
117
|
-
prompt: '
|
|
116
|
+
title: t('system.ai.prompt.plan'),
|
|
117
|
+
prompt: t('system.ai.prompt.planContent'),
|
|
118
118
|
action: undefined,
|
|
119
119
|
required_tools: [],
|
|
120
120
|
sort: 3,
|
|
121
|
-
group: '
|
|
121
|
+
group: t('system.ai.efficiencyAssistant'),
|
|
122
122
|
},
|
|
123
123
|
{
|
|
124
124
|
key: 'ideas',
|
|
125
|
-
title: '
|
|
126
|
-
prompt: '
|
|
125
|
+
title: t('system.ai.prompt.idea'),
|
|
126
|
+
prompt: t('system.ai.prompt.ideaContent'),
|
|
127
127
|
action: undefined,
|
|
128
128
|
required_tools: [],
|
|
129
129
|
sort: 4,
|
|
130
|
-
group: '
|
|
130
|
+
group: t('system.ai.efficiencyAssistant'),
|
|
131
131
|
},
|
|
132
|
-
]
|
|
132
|
+
]
|
|
133
|
+
const starterShortcuts = ref<AiShortcut[]>(createStarterShortcuts())
|
|
133
134
|
|
|
134
135
|
const filteredSessions = computed(() => {
|
|
135
136
|
const keyword = sessionKeyword.value.trim()
|
|
@@ -158,27 +159,29 @@ const starterPrompts = computed(() => {
|
|
|
158
159
|
const aiGreetingPeriod = computed(() => {
|
|
159
160
|
const hour = new Date().getHours()
|
|
160
161
|
if (hour < 11) {
|
|
161
|
-
return '
|
|
162
|
+
return t('system.ai.period.morning')
|
|
162
163
|
}
|
|
163
164
|
if (hour < 14) {
|
|
164
|
-
return '
|
|
165
|
+
return t('system.ai.period.noon')
|
|
165
166
|
}
|
|
166
167
|
if (hour < 18) {
|
|
167
|
-
return '
|
|
168
|
+
return t('system.ai.period.afternoon')
|
|
168
169
|
}
|
|
169
|
-
return '
|
|
170
|
+
return t('system.ai.period.evening')
|
|
170
171
|
})
|
|
171
|
-
const aiGreetingMessage = computed(
|
|
172
|
-
(
|
|
172
|
+
const aiGreetingMessage = computed(() =>
|
|
173
|
+
t('system.ai.greeting', { period: aiGreetingPeriod.value }),
|
|
173
174
|
)
|
|
174
175
|
const composerPlaceholder = computed(() => {
|
|
175
176
|
if (isRecording.value) {
|
|
176
|
-
return '
|
|
177
|
+
return t('system.ai.recording')
|
|
177
178
|
}
|
|
178
179
|
if (uploadingAttachment.value) {
|
|
179
|
-
return '
|
|
180
|
+
return t('system.ai.attachmentUploading')
|
|
180
181
|
}
|
|
181
|
-
return hasMessages.value
|
|
182
|
+
return hasMessages.value
|
|
183
|
+
? t('system.ai.placeholder.continue')
|
|
184
|
+
: t('system.ai.placeholder.default')
|
|
182
185
|
})
|
|
183
186
|
const isSubmitDisabled = computed(
|
|
184
187
|
() =>
|
|
@@ -193,6 +196,11 @@ onLoad(() => {
|
|
|
193
196
|
void ensureSessionsLoaded()
|
|
194
197
|
})
|
|
195
198
|
|
|
199
|
+
watch(locale, () => {
|
|
200
|
+
starterShortcuts.value = createStarterShortcuts()
|
|
201
|
+
void loadAiShortcuts()
|
|
202
|
+
})
|
|
203
|
+
|
|
196
204
|
onBeforeUnmount(() => {
|
|
197
205
|
cancelAllStreamTasks()
|
|
198
206
|
clearPendingDelta()
|
|
@@ -224,16 +232,18 @@ const createSession = async () => {
|
|
|
224
232
|
sessionKeyword.value = ''
|
|
225
233
|
showSessionDrawer.value = false
|
|
226
234
|
} catch (error) {
|
|
227
|
-
showError(error, '
|
|
235
|
+
showError(error, t('system.ai.createSessionFailed'))
|
|
228
236
|
}
|
|
229
237
|
}
|
|
230
238
|
|
|
231
239
|
const deleteSession = async (sessionID: string) => {
|
|
232
240
|
const session = sessions.value.find((item) => item.id === sessionID)
|
|
233
241
|
const result = await uni.showModal({
|
|
234
|
-
title: '
|
|
235
|
-
content:
|
|
236
|
-
|
|
242
|
+
title: t('system.ai.deleteSession'),
|
|
243
|
+
content: t('system.ai.deleteSessionConfirm', {
|
|
244
|
+
title: session?.title || t('system.ai.currentSession'),
|
|
245
|
+
}),
|
|
246
|
+
confirmText: t('common.action.delete'),
|
|
237
247
|
confirmColor: '#cf4444',
|
|
238
248
|
})
|
|
239
249
|
if (!result.confirm) {
|
|
@@ -249,13 +259,13 @@ const deleteSession = async (sessionID: string) => {
|
|
|
249
259
|
await ensureActiveSession()
|
|
250
260
|
}
|
|
251
261
|
} catch (error) {
|
|
252
|
-
showError(error, '
|
|
262
|
+
showError(error, t('system.ai.deleteSessionFailed'))
|
|
253
263
|
}
|
|
254
264
|
}
|
|
255
265
|
|
|
256
266
|
const handleSessionAction = (session: AiSession) => {
|
|
257
267
|
uni.showActionSheet({
|
|
258
|
-
itemList: ['
|
|
268
|
+
itemList: [t('system.ai.deleteSession')],
|
|
259
269
|
success: ({ tapIndex }) => {
|
|
260
270
|
if (tapIndex === 0) {
|
|
261
271
|
void deleteSession(session.id)
|
|
@@ -267,7 +277,7 @@ const handleSessionAction = (session: AiSession) => {
|
|
|
267
277
|
const copyMessage = (item: ChatMessageItem) => {
|
|
268
278
|
uni.setClipboardData({
|
|
269
279
|
data: item.content,
|
|
270
|
-
success: () => uni.showToast({ icon: 'none', title: '
|
|
280
|
+
success: () => uni.showToast({ icon: 'none', title: t('system.ai.copySuccess') }),
|
|
271
281
|
})
|
|
272
282
|
}
|
|
273
283
|
|
|
@@ -287,7 +297,7 @@ const deleteMessage = async (item: ChatMessageItem) => {
|
|
|
287
297
|
(message) => message.messageID !== item.messageID,
|
|
288
298
|
)
|
|
289
299
|
} catch (error) {
|
|
290
|
-
showError(error, '
|
|
300
|
+
showError(error, t('system.ai.deleteMessageFailed'))
|
|
291
301
|
}
|
|
292
302
|
}
|
|
293
303
|
|
|
@@ -306,14 +316,17 @@ const regenerateMessage = async (item: ChatMessageItem) => {
|
|
|
306
316
|
upsertSession(normalizeSession(response.session))
|
|
307
317
|
}
|
|
308
318
|
} catch (error) {
|
|
309
|
-
showError(error, '
|
|
319
|
+
showError(error, t('system.ai.regenerateFailed'))
|
|
310
320
|
} finally {
|
|
311
321
|
setSessionSending(activeSessionID.value, false)
|
|
312
322
|
}
|
|
313
323
|
}
|
|
314
324
|
|
|
315
325
|
const handleMessageAction = (item: ChatMessageItem) => {
|
|
316
|
-
const itemList =
|
|
326
|
+
const itemList =
|
|
327
|
+
item.role === 'ai'
|
|
328
|
+
? [t('system.ai.action.copy'), t('common.action.delete'), t('system.ai.action.regenerate')]
|
|
329
|
+
: [t('system.ai.action.copy'), t('common.action.delete')]
|
|
317
330
|
uni.showActionSheet({
|
|
318
331
|
itemList,
|
|
319
332
|
success: ({ tapIndex }) => {
|
|
@@ -341,7 +354,7 @@ const handleSend = async () => {
|
|
|
341
354
|
if (isSubmitDisabled.value) {
|
|
342
355
|
return
|
|
343
356
|
}
|
|
344
|
-
const text = inputText.value.trim() || '
|
|
357
|
+
const text = inputText.value.trim() || t('system.ai.attachmentAnswer')
|
|
345
358
|
inputText.value = ''
|
|
346
359
|
const attachments = [...selectedAttachments.value]
|
|
347
360
|
selectedAttachments.value = []
|
|
@@ -369,7 +382,7 @@ const handleToggleRecord = () => {
|
|
|
369
382
|
isRecording.value = !isRecording.value
|
|
370
383
|
uni.showToast({
|
|
371
384
|
icon: 'none',
|
|
372
|
-
title: isRecording.value ? '
|
|
385
|
+
title: isRecording.value ? t('system.ai.recognizing') : t('system.ai.speechStopped'),
|
|
373
386
|
})
|
|
374
387
|
}
|
|
375
388
|
|
|
@@ -378,7 +391,10 @@ const handleAttachment = () => {
|
|
|
378
391
|
return
|
|
379
392
|
}
|
|
380
393
|
if (selectedAttachments.value.length >= MAX_ATTACHMENT_COUNT) {
|
|
381
|
-
uni.showToast({
|
|
394
|
+
uni.showToast({
|
|
395
|
+
icon: 'none',
|
|
396
|
+
title: t('system.ai.attachmentLimit', { count: MAX_ATTACHMENT_COUNT }),
|
|
397
|
+
})
|
|
382
398
|
return
|
|
383
399
|
}
|
|
384
400
|
|
|
@@ -396,7 +412,9 @@ const handleAttachment = () => {
|
|
|
396
412
|
: []
|
|
397
413
|
const files: AttachmentUpload[] = paths.map((path: string, index: number) => ({
|
|
398
414
|
path,
|
|
399
|
-
name:
|
|
415
|
+
name:
|
|
416
|
+
(tempFiles[index] as { name?: string } | undefined)?.name ||
|
|
417
|
+
t('system.ai.imageName', { index: index + 1 }),
|
|
400
418
|
size: Number((tempFiles[index] as { size?: number } | undefined)?.size || 0),
|
|
401
419
|
}))
|
|
402
420
|
uploadingAttachment.value = true
|
|
@@ -414,7 +432,7 @@ const handleAttachment = () => {
|
|
|
414
432
|
MAX_ATTACHMENT_COUNT,
|
|
415
433
|
)
|
|
416
434
|
} catch (error) {
|
|
417
|
-
showError(error, '
|
|
435
|
+
showError(error, t('system.ai.uploadFailed'))
|
|
418
436
|
} finally {
|
|
419
437
|
uploadingAttachment.value = false
|
|
420
438
|
}
|
|
@@ -451,7 +469,7 @@ async function loadAiShortcuts() {
|
|
|
451
469
|
starterPromptGroupIndex.value = 0
|
|
452
470
|
}
|
|
453
471
|
} catch (error) {
|
|
454
|
-
showError(error, '
|
|
472
|
+
showError(error, t('system.ai.loadShortcutsFailed'))
|
|
455
473
|
} finally {
|
|
456
474
|
loadingShortcuts.value = false
|
|
457
475
|
}
|
|
@@ -507,7 +525,7 @@ async function runAiTask(
|
|
|
507
525
|
await chunkedTask.promise
|
|
508
526
|
parser.flush()
|
|
509
527
|
if (!task.finished && !task.aborted) {
|
|
510
|
-
throw new Error('
|
|
528
|
+
throw new Error(t('system.ai.responseIncomplete'))
|
|
511
529
|
}
|
|
512
530
|
// #endif
|
|
513
531
|
|
|
@@ -532,7 +550,7 @@ async function runAiTask(
|
|
|
532
550
|
signal: controller.signal,
|
|
533
551
|
})
|
|
534
552
|
if (!response.body) {
|
|
535
|
-
throw new Error('
|
|
553
|
+
throw new Error(t('system.ai.streamEmpty'))
|
|
536
554
|
}
|
|
537
555
|
await readAiEventStream(
|
|
538
556
|
response.body,
|
|
@@ -540,7 +558,7 @@ async function runAiTask(
|
|
|
540
558
|
controller.signal,
|
|
541
559
|
)
|
|
542
560
|
if (!task.finished && !task.aborted) {
|
|
543
|
-
throw new Error('
|
|
561
|
+
throw new Error(t('system.ai.responseIncomplete'))
|
|
544
562
|
}
|
|
545
563
|
handledByStream = true
|
|
546
564
|
}
|
|
@@ -550,7 +568,7 @@ async function runAiTask(
|
|
|
550
568
|
const response = await defAiMessageService.SendAiMessage(request)
|
|
551
569
|
const nextMessages = normalizeNonStreamMessages(response)
|
|
552
570
|
if (!nextMessages.length) {
|
|
553
|
-
throw new Error('
|
|
571
|
+
throw new Error(t('system.ai.responseEmpty'))
|
|
554
572
|
}
|
|
555
573
|
const success = hasSuccessfulAiMessages(nextMessages)
|
|
556
574
|
messages.value[sessionID] = replacePendingMessages(
|
|
@@ -570,7 +588,7 @@ async function runAiTask(
|
|
|
570
588
|
}
|
|
571
589
|
messages.value[sessionID] = markThinkingMessageFailed(messages.value[sessionID] ?? [])
|
|
572
590
|
scrollChatToBottom()
|
|
573
|
-
showError(error, '
|
|
591
|
+
showError(error, t('system.ai.requestFailed'))
|
|
574
592
|
} finally {
|
|
575
593
|
if (task && runningStreamTaskMap.get(sessionID) === task) {
|
|
576
594
|
runningStreamTaskMap.delete(sessionID)
|
|
@@ -721,7 +739,7 @@ function normalizeNonStreamMessages(response: unknown) {
|
|
|
721
739
|
}
|
|
722
740
|
const errorEvent = [...events].reverse().find((item) => item.event === 'error')
|
|
723
741
|
if (errorEvent) {
|
|
724
|
-
throw new Error('
|
|
742
|
+
throw new Error(t('system.ai.requestFailed'))
|
|
725
743
|
}
|
|
726
744
|
return []
|
|
727
745
|
}
|
|
@@ -781,7 +799,7 @@ async function ensureSessionsLoaded() {
|
|
|
781
799
|
await loadMessages(sessionID)
|
|
782
800
|
}
|
|
783
801
|
} catch (error) {
|
|
784
|
-
showError(error, '
|
|
802
|
+
showError(error, t('system.ai.loadSessionsFailed'))
|
|
785
803
|
} finally {
|
|
786
804
|
loadingSessions.value = false
|
|
787
805
|
}
|
|
@@ -805,7 +823,7 @@ async function ensureActiveSession() {
|
|
|
805
823
|
|
|
806
824
|
async function createRemoteSession() {
|
|
807
825
|
const response = await defAiSessionService.CreateAiSession({
|
|
808
|
-
title: '
|
|
826
|
+
title: t('system.ai.newSession'),
|
|
809
827
|
terminal: AI_TERMINAL,
|
|
810
828
|
})
|
|
811
829
|
const session = response.session ? normalizeSession(response.session) : undefined
|
|
@@ -835,7 +853,7 @@ async function loadMessages(sessionID: string) {
|
|
|
835
853
|
if (loadingSessionID.value === sessionID) {
|
|
836
854
|
messages.value[sessionID] = []
|
|
837
855
|
}
|
|
838
|
-
showError(error, '
|
|
856
|
+
showError(error, t('system.ai.loadMessagesFailed'))
|
|
839
857
|
} finally {
|
|
840
858
|
if (loadingSessionID.value === sessionID) {
|
|
841
859
|
loadingSessionID.value = ''
|
|
@@ -846,7 +864,7 @@ async function loadMessages(sessionID: string) {
|
|
|
846
864
|
function normalizeSession(session?: Partial<AiSession> | null): AiSession {
|
|
847
865
|
return {
|
|
848
866
|
id: String(session?.id ?? ''),
|
|
849
|
-
title: String(session?.title ?? '
|
|
867
|
+
title: String(session?.title ?? t('system.ai.newSession')),
|
|
850
868
|
summary: String(session?.summary ?? ''),
|
|
851
869
|
updated_at: session?.updated_at,
|
|
852
870
|
terminal: Number(session?.terminal ?? AI_TERMINAL),
|
|
@@ -969,7 +987,7 @@ function createThinkingMessage(options?: { sessionID?: string; messageID?: strin
|
|
|
969
987
|
input_content: undefined,
|
|
970
988
|
output_content: {
|
|
971
989
|
kind: 'text',
|
|
972
|
-
content:
|
|
990
|
+
content: t('system.ai.thinking'),
|
|
973
991
|
reply_source: '',
|
|
974
992
|
model: '',
|
|
975
993
|
fallback: false,
|
|
@@ -1030,7 +1048,7 @@ function appendStreamingDelta(current: ChatMessageItem[], payload: AiStreamPaylo
|
|
|
1030
1048
|
if (item.streamKey !== streamKey || item.role === 'user') {
|
|
1031
1049
|
return item
|
|
1032
1050
|
}
|
|
1033
|
-
const baseContent = item.content ===
|
|
1051
|
+
const baseContent = item.content === t('system.ai.thinking') ? '' : item.content
|
|
1034
1052
|
return {
|
|
1035
1053
|
...item,
|
|
1036
1054
|
content: `${baseContent}${payload.delta}`,
|
|
@@ -1047,8 +1065,7 @@ function markThinkingMessageFailed(current: ChatMessageItem[]) {
|
|
|
1047
1065
|
return {
|
|
1048
1066
|
...item,
|
|
1049
1067
|
status: AiMessageStatus.FAILED_AMS,
|
|
1050
|
-
content:
|
|
1051
|
-
item.role === 'ai' ? '这次回复没有成功返回,你可以直接重试刚才的问题。' : item.content,
|
|
1068
|
+
content: item.role === 'ai' ? t('system.ai.failedResponse') : item.content,
|
|
1052
1069
|
}
|
|
1053
1070
|
})
|
|
1054
1071
|
}
|
|
@@ -1062,7 +1079,7 @@ function markStreamingError(current: ChatMessageItem[], payload: AiStreamPayload
|
|
|
1062
1079
|
return {
|
|
1063
1080
|
...item,
|
|
1064
1081
|
status: AiMessageStatus.FAILED_AMS,
|
|
1065
|
-
content: '
|
|
1082
|
+
content: t('system.ai.failedResponse'),
|
|
1066
1083
|
}
|
|
1067
1084
|
})
|
|
1068
1085
|
}
|
|
@@ -1075,7 +1092,7 @@ function sortMessages(list: ChatMessageItem[]) {
|
|
|
1075
1092
|
if (left.role !== right.role) {
|
|
1076
1093
|
return left.role === 'user' ? -1 : 1
|
|
1077
1094
|
}
|
|
1078
|
-
return left.messageID.localeCompare(right.messageID,
|
|
1095
|
+
return left.messageID.localeCompare(right.messageID, locale.value, { numeric: true })
|
|
1079
1096
|
}
|
|
1080
1097
|
return leftTime - rightTime
|
|
1081
1098
|
})
|
|
@@ -1127,7 +1144,7 @@ function isImageAttachment(attachment: AiAttachment) {
|
|
|
1127
1144
|
|
|
1128
1145
|
function formatAttachmentMeta(attachment: AiAttachment) {
|
|
1129
1146
|
if (!attachment.size) {
|
|
1130
|
-
return '
|
|
1147
|
+
return t('system.ai.attachment')
|
|
1131
1148
|
}
|
|
1132
1149
|
return `${Math.max(1, Math.round(attachment.size / 1024))} KB`
|
|
1133
1150
|
}
|
|
@@ -1151,7 +1168,7 @@ function showError(error: unknown, fallback: string) {
|
|
|
1151
1168
|
<button class="nav-back-button" hover-class="none" @tap="navigateBack">
|
|
1152
1169
|
<uni-icons type="left" size="24" color="#111" />
|
|
1153
1170
|
</button>
|
|
1154
|
-
<view class="ai-navbar__title">
|
|
1171
|
+
<view class="ai-navbar__title">{{ t('system.ai.chatTitle') }}</view>
|
|
1155
1172
|
<button class="nav-menu-button" hover-class="none" @tap="toggleSessionDrawer">
|
|
1156
1173
|
<uni-icons type="bars" size="24" color="#111" />
|
|
1157
1174
|
</button>
|
|
@@ -1192,7 +1209,7 @@ function showError(error: unknown, fallback: string) {
|
|
|
1192
1209
|
@longpress="handleMessageAction(item)"
|
|
1193
1210
|
>
|
|
1194
1211
|
<view v-if="item.role === 'ai' && item.model" class="reply-meta">
|
|
1195
|
-
<text class="reply-tag"
|
|
1212
|
+
<text class="reply-tag">{{ t('system.ai.modelReply') }}</text>
|
|
1196
1213
|
<text class="reply-model">{{ item.model }}</text>
|
|
1197
1214
|
</view>
|
|
1198
1215
|
<view class="bubble-content">{{ item.content }}</view>
|
|
@@ -1204,7 +1221,9 @@ function showError(error: unknown, fallback: string) {
|
|
|
1204
1221
|
@tap="previewAttachment(attachment, item.attachments)"
|
|
1205
1222
|
>
|
|
1206
1223
|
<view class="attachment-icon">{{
|
|
1207
|
-
isImageAttachment(attachment)
|
|
1224
|
+
isImageAttachment(attachment)
|
|
1225
|
+
? t('system.ai.imageAttachment')
|
|
1226
|
+
: t('system.ai.attachment')
|
|
1208
1227
|
}}</view>
|
|
1209
1228
|
<view class="attachment-info">
|
|
1210
1229
|
<view class="attachment-name">{{ attachment.name }}</view>
|
|
@@ -1212,14 +1231,14 @@ function showError(error: unknown, fallback: string) {
|
|
|
1212
1231
|
</view>
|
|
1213
1232
|
</view>
|
|
1214
1233
|
</view>
|
|
1215
|
-
<view v-if="item.tools.length" class="tool-row"
|
|
1216
|
-
|
|
1217
|
-
>
|
|
1234
|
+
<view v-if="item.tools.length" class="tool-row">{{
|
|
1235
|
+
t('system.ai.toolCalled', { tools: formatTools(item.tools) })
|
|
1236
|
+
}}</view>
|
|
1218
1237
|
</view>
|
|
1219
1238
|
</view>
|
|
1220
1239
|
<view id="chat-bottom" class="chat-bottom"></view>
|
|
1221
1240
|
</view>
|
|
1222
|
-
<view v-if="loadingSessionID" class="loading-session"
|
|
1241
|
+
<view v-if="loadingSessionID" class="loading-session">{{ t('system.ai.loadMessages') }}</view>
|
|
1223
1242
|
</scroll-view>
|
|
1224
1243
|
|
|
1225
1244
|
<Composer
|
|
@@ -11,8 +11,10 @@ import { uploadFile } from '@liujitcn/kratos-uni-app-core/utils/file'
|
|
|
11
11
|
import { navigateToLogin } from '@liujitcn/kratos-uni-app-core/utils/navigation'
|
|
12
12
|
import defaultAvatar from '@liujitcn/kratos-uni-app-core/static/images/avatar.png'
|
|
13
13
|
import navigatorBackground from '@liujitcn/kratos-uni-app-core/static/images/navigator_bg.png'
|
|
14
|
+
import { useI18n } from '@liujitcn/kratos-uni-app-core'
|
|
14
15
|
|
|
15
16
|
const userStore = useUserStore()
|
|
17
|
+
const { t } = useI18n()
|
|
16
18
|
|
|
17
19
|
// 获取屏幕边界到安全区域距离
|
|
18
20
|
const { safeAreaInsets } = uni.getSystemInfoSync()
|
|
@@ -75,7 +77,7 @@ const onAvatarChange = async () => {
|
|
|
75
77
|
const { path, size } = res.tempFiles[0]
|
|
76
78
|
if (size > imgMaxSize.value) {
|
|
77
79
|
await uni.showToast({
|
|
78
|
-
title: '
|
|
80
|
+
title: t('system.profile.photoLimit'),
|
|
79
81
|
icon: 'none',
|
|
80
82
|
duration: 1500,
|
|
81
83
|
})
|
|
@@ -99,7 +101,7 @@ const onAvatarChange = async () => {
|
|
|
99
101
|
const { tempFilePath, size } = res.tempFiles[0]
|
|
100
102
|
if (size > imgMaxSize.value) {
|
|
101
103
|
await uni.showToast({
|
|
102
|
-
title: '
|
|
104
|
+
title: t('system.profile.photoLimit'),
|
|
103
105
|
icon: 'none',
|
|
104
106
|
duration: 1500,
|
|
105
107
|
})
|
|
@@ -123,9 +125,9 @@ const uploadAvatar = async (file: string) => {
|
|
|
123
125
|
userInfo.value.avatar = fileInfo.url
|
|
124
126
|
await defAuthService.UpdateUserProfile(userInfo.value)
|
|
125
127
|
syncUserStoreProfile(userInfo.value)
|
|
126
|
-
await uni.showToast({ icon: 'success', title: '
|
|
128
|
+
await uni.showToast({ icon: 'success', title: t('system.profile.updateSuccess') })
|
|
127
129
|
} catch {
|
|
128
|
-
await uni.showToast({ icon: 'error', title: '
|
|
130
|
+
await uni.showToast({ icon: 'error', title: t('system.profile.avatarUploadFailed') })
|
|
129
131
|
}
|
|
130
132
|
}
|
|
131
133
|
|
|
@@ -146,7 +148,7 @@ const onGetPhoneNumber: UniHelper.ButtonOnGetphonenumber = async (e) => {
|
|
|
146
148
|
const res = await defAuthService.BindUserPhone({ code: e.detail.code || '' })
|
|
147
149
|
userInfo.value.phone = res.phone
|
|
148
150
|
syncUserStoreProfile(userInfo.value)
|
|
149
|
-
await uni.showToast({ icon: 'success', title: '
|
|
151
|
+
await uni.showToast({ icon: 'success', title: t('system.profile.phoneAuthorizationSuccess') })
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
// #endif
|
|
@@ -168,7 +170,7 @@ const onSubmit = async () => {
|
|
|
168
170
|
})
|
|
169
171
|
// 更新Store昵称
|
|
170
172
|
syncUserStoreProfile(userInfo.value)
|
|
171
|
-
await uni.showToast({ icon: 'success', title: '
|
|
173
|
+
await uni.showToast({ icon: 'success', title: t('system.profile.saveSuccess') })
|
|
172
174
|
setTimeout(() => {
|
|
173
175
|
uni.navigateBack()
|
|
174
176
|
}, 400)
|
|
@@ -180,7 +182,7 @@ const onSubmit = async () => {
|
|
|
180
182
|
<!-- 导航栏 -->
|
|
181
183
|
<view class="navbar" :style="{ paddingTop: safeAreaInsets?.top + 'px' }">
|
|
182
184
|
<navigator open-type="navigateBack" class="back icon-left" hover-class="none"></navigator>
|
|
183
|
-
<view class="title"
|
|
185
|
+
<view class="title">{{ t('system.profile.title') }}</view>
|
|
184
186
|
</view>
|
|
185
187
|
<view class="avatar">
|
|
186
188
|
<view @tap="onAvatarChange" class="avatar-content">
|
|
@@ -191,7 +193,7 @@ const onSubmit = async () => {
|
|
|
191
193
|
mode="aspectFill"
|
|
192
194
|
/>
|
|
193
195
|
<image v-else class="image" :src="defaultAvatar" mode="aspectFill"></image>
|
|
194
|
-
<text class="text"
|
|
196
|
+
<text class="text">{{ t('system.profile.avatarChange') }}</text>
|
|
195
197
|
</view>
|
|
196
198
|
</view>
|
|
197
199
|
<!-- 表单 -->
|
|
@@ -199,13 +201,13 @@ const onSubmit = async () => {
|
|
|
199
201
|
<!-- 表单内容 -->
|
|
200
202
|
<view class="form-content">
|
|
201
203
|
<view class="form-item" v-if="userInfo?.user_name">
|
|
202
|
-
<text class="label"
|
|
204
|
+
<text class="label">{{ t('system.profile.account') }}</text>
|
|
203
205
|
<text class="account placeholder">{{ userInfo?.user_name }}</text>
|
|
204
206
|
</view>
|
|
205
207
|
<!-- #ifdef MP-WEIXIN -->
|
|
206
208
|
<!-- 手机号 -->
|
|
207
209
|
<view class="form-item">
|
|
208
|
-
<text class="label"
|
|
210
|
+
<text class="label">{{ t('system.profile.mobile') }}</text>
|
|
209
211
|
<view class="input">
|
|
210
212
|
<text v-if="userInfo.phone" class="account">{{ userInfo.phone }}</text>
|
|
211
213
|
<button
|
|
@@ -214,17 +216,22 @@ const onSubmit = async () => {
|
|
|
214
216
|
open-type="getPhoneNumber"
|
|
215
217
|
@getphonenumber="onGetPhoneNumber"
|
|
216
218
|
>
|
|
217
|
-
|
|
219
|
+
{{ t('system.profile.phoneAuthorization') }}
|
|
218
220
|
</button>
|
|
219
221
|
</view>
|
|
220
222
|
</view>
|
|
221
223
|
<!-- #endif -->
|
|
222
224
|
<view class="form-item">
|
|
223
|
-
<text class="label"
|
|
224
|
-
<input
|
|
225
|
+
<text class="label">{{ t('system.profile.nickName') }}</text>
|
|
226
|
+
<input
|
|
227
|
+
class="input"
|
|
228
|
+
type="text"
|
|
229
|
+
:placeholder="t('system.profile.nickNamePlaceholder')"
|
|
230
|
+
v-model="userInfo.nick_name"
|
|
231
|
+
/>
|
|
225
232
|
</view>
|
|
226
233
|
<view class="form-item">
|
|
227
|
-
<text class="label"
|
|
234
|
+
<text class="label">{{ t('system.profile.gender') }}</text>
|
|
228
235
|
<radio-group @change="onGenderChange">
|
|
229
236
|
<label class="radio" v-for="(item, index) in genderList" :key="index">
|
|
230
237
|
<radio
|
|
@@ -238,7 +245,7 @@ const onSubmit = async () => {
|
|
|
238
245
|
</view>
|
|
239
246
|
</view>
|
|
240
247
|
<!-- 提交按钮 -->
|
|
241
|
-
<button @tap="onSubmit" class="form-button"
|
|
248
|
+
<button @tap="onSubmit" class="form-button">{{ t('common.action.save') }}</button>
|
|
242
249
|
</view>
|
|
243
250
|
</view>
|
|
244
251
|
</template>
|