Skip to content

Commit

Permalink
feat: enhance user search functionality with pagination support
Browse files Browse the repository at this point in the history
- Updated SearchUsers function to include pagination parameters (startIdx and num) for improved user search results.
- Modified API response structure to return paginated data, including total user count and current page information.
- Adjusted UsersTable component to handle pagination and search parameters, ensuring a seamless user experience.
- Added internationalization support for new search functionality in the UI.
  • Loading branch information
Calcium-Ion committed Dec 31, 2024
1 parent be0b2f6 commit 014fb7e
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 58 deletions.
18 changes: 16 additions & 2 deletions controller/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,16 @@ func GetAllUsers(c *gin.Context) {
func SearchUsers(c *gin.Context) {
keyword := c.Query("keyword")
group := c.Query("group")
users, err := model.SearchUsers(keyword, group)
p, _ := strconv.Atoi(c.Query("p"))
pageSize, _ := strconv.Atoi(c.Query("page_size"))
if p < 1 {
p = 1
}
if pageSize < 0 {
pageSize = common.ItemsPerPage
}
startIdx := (p - 1) * pageSize
users, total, err := model.SearchUsers(keyword, group, startIdx, pageSize)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
Expand All @@ -285,7 +294,12 @@ func SearchUsers(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
"data": users,
"data": gin.H{
"items": users,
"total": total,
"page": p,
"page_size": pageSize,
},
})
return
}
Expand Down
60 changes: 45 additions & 15 deletions model/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,36 +115,66 @@ func GetAllUsers(startIdx int, num int) (users []*User, total int64, err error)
return users, total, nil
}

func SearchUsers(keyword string, group string) ([]*User, error) {
func SearchUsers(keyword string, group string, startIdx int, num int) ([]*User, int64, error) {
var users []*User
var total int64
var err error

// 开始事务
tx := DB.Begin()
if tx.Error != nil {
return nil, 0, tx.Error
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()

// 构建基础查询
query := tx.Unscoped().Model(&User{})

// 尝试将关键字转换为整数ID
keywordInt, err := strconv.Atoi(keyword)
if err == nil {
// 如果转换成功,按照ID和可选的组别搜索用户
query := DB.Unscoped().Omit("password").Where("id = ?", keywordInt)
if group != "" {
query = query.Where(groupCol+" = ?", group) // 使用反引号包围group
query = query.Where("id = ? AND "+groupCol+" = ?", keywordInt, group)
} else {
query = query.Where("id = ?", keywordInt)
}
err = query.Find(&users).Error
if err != nil || len(users) > 0 {
return users, err
} else {
// 如果不是ID搜索,则使用模糊匹配
likeCondition := "username LIKE ? OR email LIKE ? OR display_name LIKE ?"
if group != "" {
query = query.Where("("+likeCondition+") AND "+groupCol+" = ?",
"%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%", group)
} else {
query = query.Where(likeCondition,
"%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%")
}
}

err = nil
// 获取总数
err = query.Count(&total).Error
if err != nil {
tx.Rollback()
return nil, 0, err
}

query := DB.Unscoped().Omit("password")
likeCondition := "username LIKE ? OR email LIKE ? OR display_name LIKE ?"
if group != "" {
query = query.Where("("+likeCondition+") AND "+groupCol+" = ?", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%", group)
} else {
query = query.Where(likeCondition, "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%")
// 获取分页数据
err = query.Omit("password").Order("id desc").Limit(num).Offset(startIdx).Find(&users).Error
if err != nil {
tx.Rollback()
return nil, 0, err
}
err = query.Find(&users).Error

return users, err
// 提交事务
if err = tx.Commit().Error; err != nil {
return nil, 0, err
}

return users, total, nil
}

func GetUserById(id int, selectAll bool) (*User, error) {
Expand Down
70 changes: 30 additions & 40 deletions web/src/components/UsersTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -327,20 +327,22 @@ const UsersTable = () => {
}
};

const searchUsers = async (searchKeyword, searchGroup) => {
const searchUsers = async (startIdx, pageSize, searchKeyword, searchGroup) => {
if (searchKeyword === '' && searchGroup === '') {
// if keyword is blank, load files instead.
await loadUsers(activePage, pageSize);
return;
// if keyword is blank, load files instead.
await loadUsers(startIdx, pageSize);
return;
}
setSearching(true);
const res = await API.get(`/api/user/search?keyword=${searchKeyword}&group=${searchGroup}`);
const res = await API.get(`/api/user/search?keyword=${searchKeyword}&group=${searchGroup}&p=${startIdx}&page_size=${pageSize}`);
const { success, message, data } = res.data;
if (success) {
setUsers(data);
setActivePage(1);
const newPageData = data.items;
setActivePage(data.page);
setUserCount(data.total);
setUserFormat(newPageData);
} else {
showError(message);
showError(message);
}
setSearching(false);
};
Expand All @@ -349,30 +351,15 @@ const UsersTable = () => {
setSearchKeyword(value.trim());
};

const sortUser = (key) => {
if (users.length === 0) return;
setLoading(true);
let sortedUsers = [...users];
sortedUsers.sort((a, b) => {
return ('' + a[key]).localeCompare(b[key]);
});
if (sortedUsers[0].id === users[0].id) {
sortedUsers.reverse();
}
setUsers(sortedUsers);
setLoading(false);
};

const handlePageChange = (page) => {
setActivePage(page);
loadUsers(page, pageSize).then((r) => {});
if (searchKeyword === '' && searchGroup === '') {
loadUsers(page, pageSize).then();
} else {
searchUsers(page, pageSize, searchKeyword, searchGroup).then();
}
};

const pageData = users.slice(
(activePage - 1) * ITEMS_PER_PAGE,
activePage * ITEMS_PER_PAGE,
);

const closeAddUser = () => {
setShowAddUser(false);
};
Expand Down Expand Up @@ -438,29 +425,32 @@ const UsersTable = () => {
></EditUser>
<Form
onSubmit={() => {
searchUsers(searchKeyword, searchGroup);
searchUsers(activePage, pageSize, searchKeyword, searchGroup);
}}
labelPosition='left'
>
<div style={{ display: 'flex' }}>
<Space>
<Form.Input
label={t('搜索关键字')}
icon='search'
field='keyword'
iconPosition='left'
placeholder={t('搜索用户的 ID,用户名,显示名称,以及邮箱地址 ...')}
value={searchKeyword}
loading={searching}
onChange={(value) => handleKeywordChange(value)}
/>
<Tooltip content={t('支持搜索用户的 ID、用户名、显示名称和邮箱地址')}>
<Form.Input
label={t('搜索关键字')}
icon='search'
field='keyword'
iconPosition='left'
placeholder={t('搜索关键字')}
value={searchKeyword}
loading={searching}
onChange={(value) => handleKeywordChange(value)}
/>
</Tooltip>

<Form.Select
field='group'
label={t('分组')}
optionList={groupOptions}
onChange={(value) => {
setSearchGroup(value);
searchUsers(searchKeyword, value);
searchUsers(activePage, pageSize, searchKeyword, value);
}}
/>
<Button
Expand Down
4 changes: 3 additions & 1 deletion web/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1240,5 +1240,7 @@
"时间范围": "Time range",
"批量设置标签": "Batch set tag",
"请输入要设置的标签名称": "Please enter the tag name to be set",
"请输入标签名称": "Please enter the tag name"
"请输入标签名称": "Please enter the tag name",
"支持搜索用户的 ID、用户名、显示名称和邮箱地址": "Support searching for user ID, username, display name, and email address",
"已注销": "Logged out"
}

0 comments on commit 014fb7e

Please sign in to comment.