Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
sdream-ai-fe
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
侯明涛
sdream-ai-fe
Commits
68a333d9
Commit
68a333d9
authored
Dec 01, 2025
by
Liu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: 权限分配逻辑&&history展示
parent
10a746a8
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
113 additions
and
62 deletions
+113
-62
src/components/ChatEditor/index.tsx
+3
-25
src/lib/utils.ts
+77
-0
src/pages/Chat/Chat.tsx
+33
-37
No files found.
src/components/ChatEditor/index.tsx
View file @
68a333d9
...
...
@@ -9,30 +9,7 @@ import { type WithAuthProps, withAuth } from '@/auth/withAuth'
import
{
useAppDispatch
,
useAppSelector
}
from
'@/store/hook'
import
{
fetchToolList
}
from
'@/api/home'
import
{
clearCurrentToolId
,
createConversation
,
setCurrentToolId
}
from
'@/store/conversationSlice'
function
getUserRolesFromRoute
():
string
[]
{
try
{
const
searchParams
=
new
URLSearchParams
(
window
.
location
.
search
)
const
rolesFromRepeatedKeys
=
searchParams
.
getAll
(
'userRoles'
).
filter
(
Boolean
)
if
(
rolesFromRepeatedKeys
.
length
)
return
Array
.
from
(
new
Set
(
rolesFromRepeatedKeys
))
const
commaSeparated
=
searchParams
.
get
(
'userRoles'
)
if
(
commaSeparated
)
{
const
roles
=
commaSeparated
.
split
(
','
)
.
map
(
role
=>
role
.
trim
())
.
filter
(
Boolean
)
if
(
roles
.
length
)
return
Array
.
from
(
new
Set
(
roles
))
}
return
[]
}
catch
{
return
[]
}
}
import
{
getUserRolesForApi
}
from
'@/lib/utils'
interface
ChatEditorProps
{
onChange
?:
(
value
:
string
)
=>
void
...
...
@@ -62,7 +39,8 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
// 获取工具列表
const
getToolList
=
async
()
=>
{
try
{
const
userRoles
=
getUserRolesFromRoute
()
// 使用统一的方法获取 userRoles(先同步路由到 localStorage,然后读取)
const
userRoles
=
getUserRolesForApi
()
const
res
=
await
fetchToolList
({
userRoles
})
if
(
res
?.
data
)
{
// 根据 toolId 去重,防止重复渲染
...
...
src/lib/utils.ts
View file @
68a333d9
...
...
@@ -6,3 +6,80 @@ import { twMerge } from 'tailwind-merge'
export
function
cn
(...
inputs
:
ClassValue
[])
{
return
twMerge
(
clsx
(
inputs
))
}
const
USER_ROLES_STORAGE_KEY
=
'__USER_ROLES__'
/**
* 从路由获取 userRoles 并存储到 localStorage
* @returns 返回获取到的 userRoles 数组
*/
export
function
getUserRolesFromRouteAndStore
():
string
[]
{
try
{
const
searchParams
=
new
URLSearchParams
(
window
.
location
.
search
)
const
rolesFromRepeatedKeys
=
searchParams
.
getAll
(
'userRoles'
).
filter
(
Boolean
)
let
userRoles
:
string
[]
=
[]
if
(
rolesFromRepeatedKeys
.
length
)
{
userRoles
=
Array
.
from
(
new
Set
(
rolesFromRepeatedKeys
))
}
else
{
const
commaSeparated
=
searchParams
.
get
(
'userRoles'
)
if
(
commaSeparated
)
{
const
roles
=
commaSeparated
.
split
(
','
)
.
map
(
role
=>
role
.
trim
())
.
filter
(
Boolean
)
if
(
roles
.
length
)
{
userRoles
=
Array
.
from
(
new
Set
(
roles
))
}
}
}
// 如果获取到了 userRoles,存储到 localStorage
if
(
userRoles
.
length
>
0
)
{
try
{
localStorage
.
setItem
(
USER_ROLES_STORAGE_KEY
,
JSON
.
stringify
(
userRoles
))
}
catch
(
error
)
{
console
.
error
(
'存储 userRoles 到 localStorage 失败:'
,
error
)
}
}
return
userRoles
}
catch
{
return
[]
}
}
/**
* 从 localStorage 读取 userRoles
* @returns 返回 userRoles 数组,如果没有则返回空数组
*/
export
function
getUserRolesFromStorage
():
string
[]
{
try
{
const
stored
=
localStorage
.
getItem
(
USER_ROLES_STORAGE_KEY
)
if
(
stored
)
{
const
userRoles
=
JSON
.
parse
(
stored
)
if
(
Array
.
isArray
(
userRoles
)
&&
userRoles
.
length
>
0
)
{
return
userRoles
}
}
}
catch
(
error
)
{
console
.
error
(
'从 localStorage 读取 userRoles 失败:'
,
error
)
}
return
[]
}
/**
* 获取 userRoles(先同步路由到 localStorage,然后读取)
* 这是推荐的统一方法,确保调用 fetchToolList 时能获取到正确的 userRoles
* @returns 返回 userRoles 数组,如果没有则返回空数组
*/
export
function
getUserRolesForApi
():
string
[]
{
// 先同步路由中的 userRoles 到 localStorage(如果路由中有的话)
getUserRolesFromRouteAndStore
()
// 然后从 localStorage 读取(localStorage.setItem 是同步的,所以可以立即读取)
return
getUserRolesFromStorage
()
}
src/pages/Chat/Chat.tsx
View file @
68a333d9
...
...
@@ -14,6 +14,7 @@ import { fetchUserQaRecordPage } from '@/api/conversation'
import
{
fetchCheckTokenApi
,
fetchStreamResponse
}
from
'@/api/chat'
import
{
fetchToolList
}
from
'@/api/home'
import
{
clearCurrentToolId
,
clearShouldSendQuestion
,
fetchConversations
,
setCurrentToolId
}
from
'@/store/conversationSlice'
import
{
getUserRolesForApi
}
from
'@/lib/utils'
import
type
{
RootState
}
from
'@/store'
import
{
useAppDispatch
,
useAppSelector
}
from
'@/store/hook'
import
ScrollBtoIcon
from
'@/assets/svg/scrollBto.svg?react'
...
...
@@ -25,7 +26,7 @@ export const Chat: React.FC = () => {
const
[
isLoading
,
setIsLoading
]
=
useState
(
false
)
const
[
allItems
,
setAllItems
]
=
useState
<
ChatRecord
[]
>
([])
const
dispatch
=
useAppDispatch
()
const
{
shouldSendQuestion
,
currentToolId
}
=
useAppSelector
((
state
:
RootState
)
=>
state
.
conversation
)
const
{
shouldSendQuestion
,
currentToolId
,
conversations
}
=
useAppSelector
((
state
:
RootState
)
=>
state
.
conversation
)
const
scrollableRef
=
useRef
<
HTMLDivElement
|
any
>
(
null
)
const
position
=
useScroll
(
scrollableRef
)
const
currentIdRef
=
useRef
<
string
|
undefined
>
(
id
)
...
...
@@ -228,43 +229,59 @@ export const Chat: React.FC = () => {
return
item
})
setAllItems
(
processedMessages
)
// 优先从 qaRecords 中查找 toolId(这是实际使用的)
const
latestToolId
=
[...
qaRecords
].
reverse
().
find
(
item
=>
Boolean
(
item
.
toolId
))?.
toolId
?.
trim
?.()
const
hasQaRecords
=
qaRecords
.
length
>
0
// 如果 qaRecords 中没有 toolId,尝试从 conversations 中查找当前会话的 toolId(会话级别)
const
conversationToolId
=
latestToolId
||
(
conversations
.
find
(
conv
=>
conv
.
conversationId
===
conversationId
)?.
toolId
?.
trim
?.())
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] 从历史记录获取 toolId:'
,
{
conversationId
,
latestToolId
,
latestToolIdFromQaRecords
:
latestToolId
,
conversationToolId
,
hasQaRecords
,
currentToolIdInRedux
:
currentToolId
,
})
// 优化:如果 Redux 中已有 toolId 且与历史记录中的一致,则不重复设置
// 这样可以避免覆盖 HistoryBarList 中设置的值
if
(
hasQaRecords
)
{
if
(
latestToolId
)
{
// 只有当 Redux 中的 toolId 与历史记录中的不一致时,才更新
if
(
currentToolId
!==
latestToolId
)
{
// 确定最终使用的 toolId:优先使用 qaRecords 中的,其次使用 conversation 中的
const
finalToolId
=
latestToolId
||
conversationToolId
||
undefined
if
(
hasQaRecords
||
conversationToolId
)
{
if
(
finalToolId
)
{
// 只有当 Redux 中的 toolId 与最终确定的 toolId 不一致时,才更新
if
(
currentToolId
!==
finalToolId
)
{
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] 更新 toolId (不一致):'
,
{
from
:
currentToolId
,
to
:
latestToolId
,
to
:
finalToolId
,
source
:
latestToolId
?
'qaRecords'
:
'conversation'
,
})
dispatch
(
setCurrentToolId
(
latest
ToolId
))
dispatch
(
setCurrentToolId
(
final
ToolId
))
}
else
{
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] toolId 已一致,无需更新:'
,
latest
ToolId
)
console
.
log
(
'[Chat] toolId 已一致,无需更新:'
,
final
ToolId
)
}
}
else
{
// 如果
历史记录中没有 toolId,但 Redux 中有,需要清除
// 如果
qaRecords 和 conversation 中都没有 toolId,清除 Redux 中的 toolId
if
(
currentToolId
)
{
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] 清除 toolId (
历史记录中
没有)'
)
console
.
log
(
'[Chat] 清除 toolId (
qaRecords 和 conversation 中都
没有)'
)
dispatch
(
clearCurrentToolId
())
}
}
}
else
{
// 如果没有 qaRecords 且没有 conversation,清除 toolId
if
(
currentToolId
)
{
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] 清除 toolId (没有历史记录)'
)
dispatch
(
clearCurrentToolId
())
}
}
}
catch
{
// 错误处理
...
...
@@ -272,7 +289,7 @@ export const Chat: React.FC = () => {
finally
{
setIsLoading
(
false
)
}
},
[
dispatch
,
currentToolId
])
},
[
dispatch
,
currentToolId
,
conversations
])
/** 点击滚动到底部 */
const
scrollToBottom
=
()
=>
{
...
...
@@ -316,29 +333,8 @@ export const Chat: React.FC = () => {
const
getToolNameFromToolId
=
async
()
=>
{
if
(
currentToolId
)
{
try
{
const
userRoles
:
string
[]
=
[]
try
{
const
searchParams
=
new
URLSearchParams
(
window
.
location
.
search
)
const
rolesFromRepeatedKeys
=
searchParams
.
getAll
(
'userRoles'
).
filter
(
Boolean
)
if
(
rolesFromRepeatedKeys
.
length
)
{
userRoles
.
push
(...
Array
.
from
(
new
Set
(
rolesFromRepeatedKeys
)))
}
else
{
const
commaSeparated
=
searchParams
.
get
(
'userRoles'
)
if
(
commaSeparated
)
{
const
roles
=
commaSeparated
.
split
(
','
)
.
map
(
role
=>
role
.
trim
())
.
filter
(
Boolean
)
if
(
roles
.
length
)
{
userRoles
.
push
(...
Array
.
from
(
new
Set
(
roles
)))
}
}
}
}
catch
{
// 忽略错误
}
// 使用统一的方法获取 userRoles(先同步路由到 localStorage,然后读取)
const
userRoles
=
getUserRolesForApi
()
const
res
=
await
fetchToolList
({
userRoles
})
if
(
res
?.
data
)
{
const
tool
=
res
.
data
.
find
((
t
:
any
)
=>
t
.
toolId
===
currentToolId
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment