Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
水玉婷
ai-wechat
Commits
de2d3fa6
Commit
de2d3fa6
authored
Feb 02, 2026
by
水玉婷
Browse files
feat:添加在线用户列表
parent
e3a28c68
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/router/index.js
View file @
de2d3fa6
...
...
@@ -14,6 +14,12 @@ const routes = [
component
:
()
=>
import
(
'
../views/History.vue
'
),
meta
:
{
requiresAuth
:
true
}
},
{
path
:
'
/user
'
,
name
:
'
User
'
,
component
:
()
=>
import
(
'
../views/User.vue
'
),
meta
:
{
requiresAuth
:
true
}
},
{
path
:
'
/login
'
,
name
:
'
Login
'
,
...
...
src/views/User.vue
0 → 100644
View file @
de2d3fa6
<
template
>
<div
class=
"user-list-container"
>
<!-- 用户列表头部 -->
<div
class=
"user-list-header"
>
<div
class=
"header-title"
>
<h3>
在线用户
</h3>
<span
class=
"user-count"
>
(
{{
userList
.
length
}}
)
</span>
</div>
<div
class=
"header-actions"
>
<a-button
type=
"text"
size=
"small"
@
click=
"refreshList"
class=
"refresh-button"
:loading=
"refreshing"
>
<template
#icon
>
<reload-outlined
/>
</
template
>
刷新
</a-button>
</div>
</div>
<!-- 搜索框 -->
<div
class=
"user-search"
>
<a-input-search
v-model:value=
"searchKeyword"
placeholder=
"搜索用户..."
size=
"small"
@
search=
"handleSearch"
class=
"search-input"
/>
</div>
<!-- 用户列表 -->
<div
class=
"user-list-content"
>
<div
v-for=
"user in filteredUsers"
:key=
"user.id"
:class=
"['user-item', { active: user.id === activeUserId }]"
@
click=
"handleUserClick(user)"
>
<div
class=
"user-info"
>
<span
class=
"name-text"
>
{{ user.cname }}
</span>
</div>
</div>
<!-- 空状态 -->
<div
v-if=
"filteredUsers.length === 0"
class=
"empty-state"
>
<div
class=
"empty-icon"
>
<user-outlined
/>
</div>
<p
class=
"empty-text"
>
暂无在线用户
</p>
</div>
</div>
</div>
</template>
<
script
setup
lang=
"ts"
>
import
{
ref
,
computed
,
onMounted
,
onUnmounted
}
from
'
vue
'
import
{
ReloadOutlined
,
UserOutlined
}
from
'
@ant-design/icons-vue
'
import
{
get
}
from
'
../utils/axios
'
// 用户接口定义
interface
User
{
id
:
string
cname
:
string
}
// Props
interface
Props
{
activeUserId
?:
string
autoRefresh
?:
boolean
refreshInterval
?:
number
}
const
props
=
withDefaults
(
defineProps
<
Props
>
(),
{
autoRefresh
:
true
,
refreshInterval
:
30000
// 30秒
})
// Emits
const
emit
=
defineEmits
<
{
'
user-click
'
:
[
user
:
User
]
'
refresh
'
:
[]
}
>
()
// 响应式数据
const
userList
=
ref
<
User
[]
>
([])
const
searchKeyword
=
ref
(
''
)
const
refreshing
=
ref
(
false
)
const
refreshTimer
=
ref
<
number
|
null
>
(
null
)
// 计算属性
const
filteredUsers
=
computed
(()
=>
{
return
userList
.
value
.
filter
(
user
=>
user
.
cname
.
toLowerCase
().
includes
(
searchKeyword
.
value
.
toLowerCase
())
)
})
// 方法
const
refreshList
=
async
()
=>
{
refreshing
.
value
=
true
try
{
// 模拟API调用
await
fetchUserList
()
emit
(
'
refresh
'
)
}
finally
{
refreshing
.
value
=
false
}
}
const
handleSearch
=
()
=>
{
// 搜索逻辑已通过计算属性处理
}
const
handleUserClick
=
(
user
:
User
)
=>
{
emit
(
'
user-click
'
,
user
)
}
// 获取用户列表
const
fetchUserList
=
async
()
=>
{
try
{
const
response
=
await
get
(
`
${
import
.
meta
.
env
.
VITE_SSE_PATH
}
/sse/list-user`
)
if
(
response
.
data
.
code
===
0
)
{
userList
.
value
=
response
.
data
.
data
||
[]
}
else
{
console
.
error
(
'
获取用户列表失败:
'
,
response
.
data
.
msg
)
}
}
catch
(
error
)
{
console
.
error
(
'
调用用户列表接口失败:
'
,
error
)
}
}
// 清理定时器
const
clearRefreshTimer
=
()
=>
{
if
(
refreshTimer
.
value
)
{
clearInterval
(
refreshTimer
.
value
)
refreshTimer
.
value
=
null
}
}
// 生命周期
onMounted
(()
=>
{
fetchUserList
()
// 自动刷新
if
(
props
.
autoRefresh
)
{
refreshTimer
.
value
=
setInterval
(
refreshList
,
props
.
refreshInterval
)
}
})
onUnmounted
(()
=>
{
clearRefreshTimer
()
})
</
script
>
<
style
lang=
"less"
scoped
>
@import './components/style.less';
.user-list-container {
background: @white;
border-radius: 8px;
height: 100%;
display: flex;
flex-direction: column;
}
.user-list-header {
padding: 16px;
border-bottom: 1px solid @gray-3;
display: flex;
justify-content: space-between;
align-items: center;
.header-title {
display: flex;
align-items: center;
gap: 8px;
h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
color: @gray-7;
}
.user-count {
color: @gray-5;
font-size: 14px;
}
}
.header-actions {
.ant-btn {
color: @gray-6;
&:hover {
color: @primary-color;
background: @blue-light-1;
}
}
}
}
.user-search {
padding: 12px 16px;
border-bottom: 1px solid @gray-3;
.search-input {
.ant-input {
border-radius: 20px;
}
}
}
.user-list-content {
flex: 1;
overflow-y: auto;
padding: 8px 0;
}
.user-item {
display: flex;
align-items: center;
padding: 12px 16px;
cursor: pointer;
transition: background-color 0.2s;
&:hover {
background: @blue-light-1;
}
&.active {
background: @blue-light-2;
border-left: 3px solid @primary-color;
}
.user-info {
.name-text {
font-weight: 500;
color: @gray-7;
font-size: 14px;
}
}
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 20px;
color: @gray-5;
.empty-icon {
font-size: 48px;
margin-bottom: 16px;
color: @gray-4;
}
.empty-text {
margin: 0;
font-size: 14px;
}
}
// 响应式设计
@media (max-width: 768px) {
.user-list-container {
border-radius: 0;
box-shadow: none;
}
.user-item {
padding: 10px 12px;
}
}
</
style
>
\ No newline at end of file
src/views/components/utils/contentTemplateService.ts
View file @
de2d3fa6
...
...
@@ -426,7 +426,7 @@ export class ContentTemplateService {
// 计算思考用时
const
thinkingTime
=
this
.
thinkingStartTime
?
Math
.
round
((
Date
.
now
()
-
this
.
thinkingStartTime
)
/
1000
)
:
0
;
// 对于历史数据,直接显示"已完成思考",不显示具体用时
const
thinkingTimeText
=
isHistoryData
?
'
已完成思考
'
:
(
thinkingTime
>
0
?
'
已完成思考
'
:
''
);
const
thinkingTimeText
=
isHistoryData
?
'
已完成思考
'
:
(
thinkingTime
>
0
?
'
已完成思考
'
:
'
已完成思考
'
);
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkContent
=
currentThinkContent
;
// 添加思考时长信息到内容块中,供前端模板使用
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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