Skip to content

Commit 370c803

Browse files
committed
feat: user setting add search functionality
Signed-off-by: Bob Du <[email protected]>
1 parent 8af1a8d commit 370c803

File tree

8 files changed

+137
-55
lines changed

8 files changed

+137
-55
lines changed

service/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,8 @@ router.get('/users', rootAuth, async (req, res) => {
482482
try {
483483
const page = +req.query.page
484484
const size = +req.query.size
485-
const data = await getUsers(page, size)
485+
const search = req.query.search as string | undefined
486+
const data = await getUsers(page, size, search)
486487
res.send({ status: 'Success', message: '获取成功 | Get successfully', data })
487488
}
488489
catch (error) {

service/src/storage/mongo.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { WithId } from 'mongodb'
1+
import type { Filter, WithId } from 'mongodb'
22
import type {
33
AdvancedConfig,
44
BuiltInPrompt,
@@ -502,8 +502,11 @@ export async function getUser(email: string): Promise<UserInfo> {
502502
return userInfo
503503
}
504504

505-
export async function getUsers(page: number, size: number): Promise<{ users: UserInfo[], total: number }> {
506-
const query = { status: { $ne: Status.Deleted } }
505+
export async function getUsers(page: number, size: number, search?: string): Promise<{ users: UserInfo[], total: number }> {
506+
const query: Filter<UserInfo> = { status: { $ne: Status.Deleted } }
507+
if (search && search.trim()) {
508+
query.email = { $regex: search.trim(), $options: 'i' }
509+
}
507510
const cursor = userCol.find(query).sort({ createTime: -1 })
508511
const total = await userCol.countDocuments(query)
509512
const skip = (page - 1) * size

src/api/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,10 +244,10 @@ export function fetchUpdateUserMaxContextCount<T = any>(maxContextCount: number)
244244
})
245245
}
246246

247-
export function fetchGetUsers<T = any>(page: number, size: number) {
247+
export function fetchGetUsers<T = any>(page: number, size: number, search?: string) {
248248
return get<T>({
249249
url: '/users',
250-
data: { page, size },
250+
data: { page, size, search },
251251
})
252252
}
253253

src/components/common/Setting/User.vue

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,38 @@ const loading = ref(false)
1414
const show = ref(false)
1515
const handleSaving = ref(false)
1616
const userRef = ref(new UserInfo([UserRole.User]))
17+
const searchKeyword = ref('')
1718
1819
const users = ref([])
1920
2021
function createColumns(): DataTableColumns {
2122
return [
2223
{
23-
title: 'Email',
24+
title: t('setting.user.email'),
2425
key: 'email',
2526
resizable: true,
2627
width: 200,
2728
minWidth: 80,
2829
maxWidth: 200,
2930
},
3031
{
31-
title: 'Register Time',
32+
title: t('setting.user.registerTime'),
3233
key: 'createTime',
3334
resizable: true,
3435
width: 200,
3536
minWidth: 80,
3637
maxWidth: 200,
3738
},
3839
{
39-
title: 'Verify Time',
40+
title: t('setting.user.verifyTime'),
4041
key: 'verifyTime',
4142
resizable: true,
4243
width: 200,
4344
minWidth: 80,
4445
maxWidth: 200,
4546
},
4647
{
47-
title: 'Roles',
48+
title: t('setting.user.roles'),
4849
key: 'status',
4950
resizable: true,
5051
width: 200,
@@ -70,15 +71,15 @@ function createColumns(): DataTableColumns {
7071
},
7172
},
7273
{
73-
title: 'Status',
74+
title: t('setting.user.status'),
7475
key: 'status',
7576
width: 80,
7677
render(row: any) {
7778
return Status[row.status]
7879
},
7980
},
8081
{
81-
title: 'Remark',
82+
title: t('setting.user.remark'),
8283
key: 'remark',
8384
resizable: true,
8485
width: 200,
@@ -87,7 +88,7 @@ function createColumns(): DataTableColumns {
8788
},
8889
// switch off amt limit
8990
{
90-
title: 'Limit Enabled',
91+
title: t('setting.user.limitEnabled'),
9192
key: 'limit_switch',
9293
resizable: true,
9394
width: 100,
@@ -99,15 +100,15 @@ function createColumns(): DataTableColumns {
99100
},
100101
// 新增额度信息
101102
{
102-
title: 'Amounts',
103+
title: t('setting.user.amounts'),
103104
key: 'useAmount',
104105
resizable: true,
105106
width: 80,
106107
minWidth: 30,
107108
maxWidth: 100,
108109
},
109110
{
110-
title: 'Action',
111+
title: t('setting.user.action'),
111112
key: '_id',
112113
width: 220,
113114
fixed: 'right',
@@ -136,7 +137,7 @@ function createColumns(): DataTableColumns {
136137
},
137138
onClick: () => handleEditUser(row),
138139
},
139-
{ default: () => t('chat.editUser') },
140+
{ default: () => t('setting.user.editUser') },
140141
))
141142
}
142143
if (row.status === Status.PreVerify || row.status === Status.AdminVerify) {
@@ -147,7 +148,7 @@ function createColumns(): DataTableColumns {
147148
type: 'info',
148149
onClick: () => handleUpdateUserStatus(row._id, Status.Normal),
149150
},
150-
{ default: () => t('chat.verifiedUser') },
151+
{ default: () => t('setting.user.verifiedUser') },
151152
))
152153
}
153154
if (row.secretKey) {
@@ -158,7 +159,7 @@ function createColumns(): DataTableColumns {
158159
type: 'warning',
159160
onClick: () => handleDisable2FA(row._id),
160161
},
161-
{ default: () => t('chat.disable2FA') },
162+
{ default: () => t('setting.user.disable2FA') },
162163
))
163164
}
164165
return actions
@@ -175,7 +176,7 @@ const pagination = reactive ({
175176
pageCount: 1,
176177
itemCount: 1,
177178
prefix({ itemCount }: { itemCount: number | undefined }) {
178-
return `Total is ${itemCount}.`
179+
return `${t('setting.user.total')}: ${itemCount}`
179180
},
180181
showSizePicker: true,
181182
pageSizes: [25, 50, 100],
@@ -196,7 +197,7 @@ async function handleGetUsers(page: number) {
196197
users.value.length = 0
197198
loading.value = true
198199
const size = pagination.pageSize
199-
const data = (await fetchGetUsers(page, size)).data
200+
const data = (await fetchGetUsers(page, size, searchKeyword.value || undefined)).data
200201
data.users.forEach((user: never) => {
201202
users.value.push(user)
202203
})
@@ -206,11 +207,16 @@ async function handleGetUsers(page: number) {
206207
loading.value = false
207208
}
208209
210+
function handleSearch() {
211+
pagination.page = 1
212+
handleGetUsers(1)
213+
}
214+
209215
async function handleUpdateUserStatus(userId: string, status: Status) {
210216
if (status === Status.Deleted) {
211217
dialog.warning({
212-
title: t('chat.deleteUser'),
213-
content: t('chat.deleteUserConfirm'),
218+
title: t('setting.user.deleteUser'),
219+
content: t('setting.user.deleteUserConfirm'),
214220
positiveText: t('common.yes'),
215221
negativeText: t('common.no'),
216222
onPositiveClick: async () => {
@@ -229,8 +235,8 @@ async function handleUpdateUserStatus(userId: string, status: Status) {
229235
230236
async function handleDisable2FA(userId: string) {
231237
dialog.warning({
232-
title: t('chat.disable2FA'),
233-
content: t('chat.disable2FAConfirm'),
238+
title: t('setting.user.disable2FA'),
239+
content: t('setting.user.disable2FAConfirm'),
234240
positiveText: t('common.yes'),
235241
negativeText: t('common.no'),
236242
onPositiveClick: async () => {
@@ -273,9 +279,21 @@ onMounted(async () => {
273279
<div class="p-4 space-y-5 min-h-[200px]">
274280
<div class="space-y-6">
275281
<NSpace vertical :size="12">
276-
<NSpace>
277-
<NButton @click="handleNewUser()">
278-
New User
282+
<NSpace justify="space-between" align="center">
283+
<NSpace>
284+
<NInput
285+
v-model:value="searchKeyword"
286+
:placeholder="t('setting.user.searchUserPlaceholder')"
287+
clearable
288+
style="width: 280px"
289+
@keyup.enter="handleSearch"
290+
/>
291+
<NButton type="primary" @click="handleSearch">
292+
{{ t('setting.user.searchUser') }}
293+
</NButton>
294+
</NSpace>
295+
<NButton type="primary" @click="handleNewUser()">
296+
{{ t('setting.user.newUser') }}
279297
</NButton>
280298
</NSpace>
281299
<NDataTable

src/locales/en-US.json

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,9 @@
8585
"usagePrompt": "Prompt",
8686
"usageResponse": "Response",
8787
"usageTotal": "Total token cost",
88-
"deleteUser": "Delete User",
89-
"editUser": "Edit User",
90-
"deleteUserConfirm": "Are you sure to delete this user? After deletion, this email can never be registered or logged in again.",
91-
"verifiedUser": "Verified User",
9288
"deleteKey": "Delete Key",
9389
"editKeyButton": "Edit Key",
9490
"deleteKeyConfirm": "Are you sure to delete this key?",
95-
"disable2FA": "Disable 2FA",
96-
"disable2FAConfirm": "Are you sure to disable 2FA for this user?",
9791
"thinking": "Thinking",
9892
"reasoningProcess": "Reasoning Process",
9993
"noReasoningProcess": "No Reasoning Process",
@@ -224,7 +218,28 @@
224218
"info2FAStep3Tip2": "1. After logging in, use the two-step verification on the Two-Step Verification page to disable it.",
225219
"info2FAStep3Tip3": "2. Contact the administrator to disable two-step verification.",
226220
"maxContextCount": "Maximum number of messages included in the context window for default new sessions",
227-
"fastDelMsg": "Fast Delete Message"
221+
"fastDelMsg": "Fast Delete Message",
222+
"user": {
223+
"searchUser": "Search",
224+
"newUser": "New User",
225+
"searchUserPlaceholder": "Search by email",
226+
"editUser": "Edit User",
227+
"deleteUser": "Delete User",
228+
"deleteUserConfirm": "Are you sure to delete this user? After deletion, this email can never be registered or logged in again.",
229+
"verifiedUser": "Verified User",
230+
"disable2FA": "Disable 2FA",
231+
"disable2FAConfirm": "Are you sure to disable 2FA for this user?",
232+
"email": "Email",
233+
"registerTime": "Register Time",
234+
"verifyTime": "Verify Time",
235+
"roles": "Roles",
236+
"status": "Status",
237+
"remark": "Remark",
238+
"limitEnabled": "Limit Enabled",
239+
"amounts": "Amounts",
240+
"action": "Action",
241+
"total": "Total"
242+
}
228243
},
229244
"store": {
230245
"siderButton": "Prompt Store",

src/locales/ko-KR.json

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,9 @@
8585
"usagePrompt": "질문",
8686
"usageResponse": "답변",
8787
"usageTotal": "총 소비 token",
88-
"deleteUser": "Delete User",
89-
"editUser": "Edit User",
90-
"deleteUserConfirm": "Are you sure to delete this user? After deletion, this email can never be registered or logged in again.",
91-
"verifiedUser": "Verified User",
9288
"deleteKey": "Delete Key",
9389
"editKeyButton": "Edit Key",
9490
"deleteKeyConfirm": "Are you sure to delete this key?",
95-
"disable2FA": "Disable 2FA",
96-
"disable2FAConfirm": "Are you sure to disable 2FA for this user?",
9791
"thinking": "생각 중",
9892
"reasoningProcess": "추론 과정",
9993
"noReasoningProcess": "추론 과정 없음",
@@ -224,7 +218,28 @@
224218
"info2FAStep3Tip2": "1. After logging in, use the two-step verification on the Two-Step Verification page to disable it.",
225219
"info2FAStep3Tip3": "2. Contact the administrator to disable two-step verification.",
226220
"maxContextCount": "기본 새 세션의 컨텍스트 창에 포함된 최대 메시지 수",
227-
"fastDelMsg": "빠르게 메시지 삭제"
221+
"fastDelMsg": "빠르게 메시지 삭제",
222+
"user": {
223+
"searchUser": "검색",
224+
"newUser": "새 사용자",
225+
"searchUserPlaceholder": "이메일로 검색",
226+
"editUser": "사용자 편집",
227+
"deleteUser": "사용자 삭제",
228+
"deleteUserConfirm": "이 사용자를 삭제하시겠습니까? 삭제 후 이 이메일은 영원히 등록하거나 로그인할 수 없습니다.",
229+
"verifiedUser": "인증된 사용자",
230+
"disable2FA": "2FA 비활성화",
231+
"disable2FAConfirm": "이 사용자의 2FA를 비활성화하시겠습니까?",
232+
"email": "Email",
233+
"registerTime": "등록 시간",
234+
"verifyTime": "인증 시간",
235+
"roles": "역할",
236+
"status": "상태",
237+
"remark": "비고",
238+
"limitEnabled": "제한 활성화",
239+
"amounts": "금액",
240+
"action": "작업",
241+
"total": "총계"
242+
}
228243
},
229244
"store": {
230245
"siderButton": "프롬프트 스토어",

src/locales/zh-CN.json

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,9 @@
8585
"usagePrompt": "提问",
8686
"usageResponse": "回复",
8787
"usageTotal": "总消耗 token",
88-
"deleteUser": "删除用户",
89-
"editUser": "编辑用户",
90-
"deleteUserConfirm": "你确定要删除这个用户吗? 删除后这个邮箱永远无法注册登录",
91-
"verifiedUser": "通过验证",
9288
"deleteKey": "删除 Key",
9389
"editKeyButton": "编辑 Key",
9490
"deleteKeyConfirm": "你确定要删除这个 key 吗?",
95-
"disable2FA": "禁用 2FA",
96-
"disable2FAConfirm": "您确定要为此用户禁用两步验证吗??",
9791
"thinking": "思考中",
9892
"reasoningProcess": "推理过程",
9993
"noReasoningProcess": "无推理过程",
@@ -224,7 +218,28 @@
224218
"info2FAStep3Tip2": "1. 登录后,在 两步验证 页面使用两步验证码关闭。",
225219
"info2FAStep3Tip3": "2. 联系管理员来关闭两步验证。",
226220
"maxContextCount": "默认新会话的上下文窗口中包含的最大消息数量",
227-
"fastDelMsg": "快速删除消息"
221+
"fastDelMsg": "快速删除消息",
222+
"user": {
223+
"searchUser": "搜索",
224+
"newUser": "新建用户",
225+
"searchUserPlaceholder": "按邮箱搜索",
226+
"editUser": "编辑用户",
227+
"deleteUser": "删除用户",
228+
"deleteUserConfirm": "你确定要删除这个用户吗? 删除后这个邮箱永远无法注册登录",
229+
"verifiedUser": "通过验证",
230+
"disable2FA": "禁用 2FA",
231+
"disable2FAConfirm": "您确定要为此用户禁用两步验证吗?",
232+
"email": "Email",
233+
"registerTime": "注册时间",
234+
"verifyTime": "验证时间",
235+
"roles": "角色",
236+
"status": "状态",
237+
"remark": "备注",
238+
"limitEnabled": "限制启用",
239+
"amounts": "额度",
240+
"action": "操作",
241+
"total": "总计"
242+
}
228243
},
229244
"store": {
230245
"siderButton": "提示词商店",

0 commit comments

Comments
 (0)