+
+
+
+ 共 {{ sortedAccounts.length }} 条记录
+
+
+ 每页显示
+
+ 条
+
+
+
+
+
+
+
+
+
+
+ ...
+
+
+
+
+
+ ...
+
+
+
+
+
+
+
+
+
{
+ const saved = localStorage.getItem(PAGE_SIZE_STORAGE_KEY)
+ if (saved) {
+ const parsedSize = parseInt(saved, 10)
+ if ([10, 20, 50, 100].includes(parsedSize)) {
+ return parsedSize
+ }
+ }
+ return 10
+}
+const pageSizeOptions = [10, 20, 50, 100]
+const pageSize = ref(getInitialPageSize())
+const currentPage = ref(1)
// 缓存状态标志
const apiKeysLoaded = ref(false)
@@ -1265,9 +1393,78 @@ const newAccountPlatform = ref(null) // 跟踪新建账户选择的平台
const showEditAccountModal = ref(false)
const editingAccount = ref(null)
+const collectAccountSearchableStrings = (account) => {
+ const values = new Set()
+
+ const baseFields = [
+ account?.name,
+ account?.email,
+ account?.accountName,
+ account?.owner,
+ account?.ownerName,
+ account?.ownerDisplayName,
+ account?.displayName,
+ account?.username,
+ account?.identifier,
+ account?.alias,
+ account?.title,
+ account?.label
+ ]
+
+ baseFields.forEach((field) => {
+ if (typeof field === 'string') {
+ const trimmed = field.trim()
+ if (trimmed) {
+ values.add(trimmed)
+ }
+ }
+ })
+
+ if (Array.isArray(account?.groupInfos)) {
+ account.groupInfos.forEach((group) => {
+ if (group && typeof group.name === 'string') {
+ const trimmed = group.name.trim()
+ if (trimmed) {
+ values.add(trimmed)
+ }
+ }
+ })
+ }
+
+ Object.entries(account || {}).forEach(([key, value]) => {
+ if (typeof value === 'string') {
+ const lowerKey = key.toLowerCase()
+ if (lowerKey.includes('name') || lowerKey.includes('email')) {
+ const trimmed = value.trim()
+ if (trimmed) {
+ values.add(trimmed)
+ }
+ }
+ }
+ })
+
+ return Array.from(values)
+}
+
+const accountMatchesKeyword = (account, normalizedKeyword) => {
+ if (!normalizedKeyword) return true
+ return collectAccountSearchableStrings(account).some((value) =>
+ value.toLowerCase().includes(normalizedKeyword)
+ )
+}
+
// 计算排序后的账户列表
const sortedAccounts = computed(() => {
- const sourceAccounts = accounts.value
+ let sourceAccounts = accounts.value
+
+ const keyword = searchKeyword.value.trim()
+ if (keyword) {
+ const normalizedKeyword = keyword.toLowerCase()
+ sourceAccounts = sourceAccounts.filter((account) =>
+ accountMatchesKeyword(account, normalizedKeyword)
+ )
+ }
+
if (!accountsSortBy.value) return sourceAccounts
const sorted = [...sourceAccounts].sort((a, b) => {
@@ -1306,6 +1503,68 @@ const sortedAccounts = computed(() => {
return sorted
})
+const totalPages = computed(() => {
+ const total = sortedAccounts.value.length
+ return Math.ceil(total / pageSize.value) || 0
+})
+
+const pageNumbers = computed(() => {
+ const total = totalPages.value
+ const current = currentPage.value
+ const pages = []
+
+ if (total <= 7) {
+ for (let i = 1; i <= total; i++) {
+ pages.push(i)
+ }
+ } else {
+ let start = Math.max(1, current - 2)
+ let end = Math.min(total, current + 2)
+
+ if (current <= 3) {
+ end = 5
+ } else if (current >= total - 2) {
+ start = total - 4
+ }
+
+ for (let i = start; i <= end; i++) {
+ pages.push(i)
+ }
+ }
+
+ return pages
+})
+
+const shouldShowFirstPage = computed(() => {
+ const pages = pageNumbers.value
+ if (pages.length === 0) return false
+ return pages[0] > 1
+})
+
+const shouldShowLastPage = computed(() => {
+ const pages = pageNumbers.value
+ if (pages.length === 0) return false
+ return pages[pages.length - 1] < totalPages.value
+})
+
+const showLeadingEllipsis = computed(() => {
+ const pages = pageNumbers.value
+ if (pages.length === 0) return false
+ return shouldShowFirstPage.value && pages[0] > 2
+})
+
+const showTrailingEllipsis = computed(() => {
+ const pages = pageNumbers.value
+ if (pages.length === 0) return false
+ return shouldShowLastPage.value && pages[pages.length - 1] < totalPages.value - 1
+})
+
+const paginatedAccounts = computed(() => {
+ const start = (currentPage.value - 1) * pageSize.value
+ const end = start + pageSize.value
+ return sortedAccounts.value.slice(start, end)
+})
+
// 加载账户列表
const loadAccounts = async (forceReload = false) => {
accountsLoading.value = true
@@ -1628,6 +1887,11 @@ const formatLastUsed = (dateString) => {
return date.toLocaleDateString('zh-CN')
}
+const clearSearch = () => {
+ searchKeyword.value = ''
+ currentPage.value = 1
+}
+
// 加载API Keys列表(缓存版本)
const loadApiKeys = async (forceReload = false) => {
if (!forceReload && apiKeysLoaded.value) {
@@ -1672,11 +1936,13 @@ const clearCache = () => {
// 按平台筛选账户
const filterByPlatform = () => {
+ currentPage.value = 1
loadAccounts()
}
// 按分组筛选账户
const filterByGroup = () => {
+ currentPage.value = 1
loadAccounts()
}
@@ -2405,6 +2671,23 @@ const calculateDailyCost = (account) => {
// await toggleSchedulable(account)
// }
+watch(searchKeyword, () => {
+ currentPage.value = 1
+})
+
+watch(pageSize, (newSize) => {
+ localStorage.setItem(PAGE_SIZE_STORAGE_KEY, newSize.toString())
+})
+
+watch(
+ () => sortedAccounts.value.length,
+ () => {
+ if (currentPage.value > totalPages.value) {
+ currentPage.value = totalPages.value || 1
+ }
+ }
+)
+
// 监听排序选择变化
watch(accountSortBy, (newVal) => {
const fieldMap = {
diff --git a/web/admin-spa/src/views/ApiKeysView.vue b/web/admin-spa/src/views/ApiKeysView.vue
index 36ad6642..dad79779 100644
--- a/web/admin-spa/src/views/ApiKeysView.vue
+++ b/web/admin-spa/src/views/ApiKeysView.vue
@@ -125,7 +125,7 @@
|