feat: 订阅新增类型选择

This commit is contained in:
xuncha
2026-04-25 14:33:59 +08:00
committed by digua
parent 120eb93c23
commit ef2334b758
6 changed files with 110 additions and 7 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ export interface RemoteSession {
*/
export function fetchRemoteSessions(baseUrl: string, token?: string): Promise<RemoteSession[]> {
return new Promise<RemoteSession[]>((resolve, reject) => {
const url = normalizeBaseUrl(baseUrl) + '/sessions?format=chatlab'
const url = normalizeBaseUrl(baseUrl) + '/sessions?format=chatlab&limit=10000'
const request = net.request(url)
if (token) {
@@ -32,6 +32,11 @@ const selectedSessionIds = ref<Set<string>>(new Set())
const discovering = ref(false)
const discoveryError = ref('')
type SessionTypeSelection = 'private' | 'group' | 'other'
type SessionTypeFilter = 'all' | SessionTypeSelection
const activeSessionTypeFilter = ref<SessionTypeFilter>('all')
watch(
() => props.open,
async (val) => {
@@ -49,6 +54,7 @@ watch(
remoteSessions.value = []
selectedSessionIds.value = new Set()
discoveryError.value = ''
activeSessionTypeFilter.value = 'all'
if (isManageMode.value) {
await discoverSessions()
}
@@ -57,17 +63,71 @@ watch(
{ immediate: true }
)
const availableSessions = computed(() => remoteSessions.value.filter((s) => !props.subscribedRemoteIds?.has(s.id)))
const visibleRemoteSessions = computed(() => {
if (activeSessionTypeFilter.value === 'all') return remoteSessions.value
return remoteSessions.value.filter((session) => getSessionTypeSelection(session) === activeSessionTypeFilter.value)
})
const allSelected = computed(
() => availableSessions.value.length > 0 && selectedSessionIds.value.size === availableSessions.value.length
const visibleAvailableSessions = computed(() =>
visibleRemoteSessions.value.filter((s) => !props.subscribedRemoteIds?.has(s.id))
)
const allSelected = computed(
() =>
visibleAvailableSessions.value.length > 0 &&
visibleAvailableSessions.value.every((session) => selectedSessionIds.value.has(session.id))
)
const sessionTypeSelectionOptions = computed(() =>
(
[
{ value: 'all', label: t('settings.api.dataSources.discovery.typeAll') },
{ value: 'private', label: t('settings.api.dataSources.discovery.typePrivate') },
{ value: 'group', label: t('settings.api.dataSources.discovery.typeGroup') },
{ value: 'other', label: t('settings.api.dataSources.discovery.typeOther') },
] as Array<{ value: SessionTypeFilter; label: string }>
).map((option) => ({
...option,
count:
option.value === 'all'
? remoteSessions.value.length
: remoteSessions.value.filter((session) => getSessionTypeSelection(session) === option.value).length,
}))
)
function getSessionTypeSelection(session: RemoteSession): SessionTypeSelection {
const rawType = String(session.type || '')
.trim()
.toLowerCase()
const id = String(session.id || '')
.trim()
.toLowerCase()
if (rawType === 'group' || id.endsWith('@chatroom')) return 'group'
if (
rawType === 'channel' ||
rawType === 'official' ||
rawType === 'other' ||
id.startsWith('gh_') ||
id.includes('@openim') ||
(id.startsWith('weixin') && id !== 'weixin')
) {
return 'other'
}
return 'private'
}
function setSessionTypeFilter(type: SessionTypeFilter) {
activeSessionTypeFilter.value = type
}
function toggleSelectAll() {
const visibleIds = visibleAvailableSessions.value.map((s) => s.id)
if (allSelected.value) {
selectedSessionIds.value = new Set()
const next = new Set(selectedSessionIds.value)
for (const id of visibleIds) next.delete(id)
selectedSessionIds.value = next
} else {
selectedSessionIds.value = new Set(availableSessions.value.map((s) => s.id))
selectedSessionIds.value = new Set([...selectedSessionIds.value, ...visibleIds])
}
}
@@ -89,6 +149,7 @@ async function discoverSessions() {
discoveryError.value = ''
remoteSessions.value = []
selectedSessionIds.value = new Set()
activeSessionTypeFilter.value = 'all'
try {
remoteSessions.value = await store.fetchRemoteSessions(formData.value.baseUrl, formData.value.token)
} catch (err: any) {
@@ -226,9 +287,31 @@ function formatMessageCount(count?: number): string {
}}
</button>
</div>
<div class="mb-2 flex flex-wrap items-center gap-2">
<span class="text-xs text-gray-500 dark:text-gray-400">
{{ t('settings.api.dataSources.discovery.selectByType') }}
</span>
<div class="inline-flex rounded-lg bg-gray-100 p-0.5 dark:bg-gray-800">
<button
v-for="option in sessionTypeSelectionOptions"
:key="option.value"
type="button"
class="rounded-md px-2.5 py-1 text-xs transition-colors"
:class="
activeSessionTypeFilter === option.value
? 'bg-white text-blue-600 shadow-sm dark:bg-gray-700 dark:text-blue-300'
: 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-200'
"
:disabled="option.count === 0"
@click="setSessionTypeFilter(option.value)"
>
{{ option.label }} ({{ option.count }})
</button>
</div>
</div>
<div class="max-h-64 overflow-y-auto rounded-lg border border-gray-200 dark:border-gray-600">
<div
v-for="session in remoteSessions"
v-for="session in visibleRemoteSessions"
:key="session.id"
class="flex items-center gap-3 border-b border-gray-100 px-3 py-2 last:border-0"
:class="
+5
View File
@@ -511,6 +511,11 @@
"found": "Found {count} sessions",
"selectAll": "Select All",
"deselectAll": "Deselect All",
"selectByType": "Session type",
"typeAll": "All",
"typePrivate": "Private",
"typeGroup": "Group",
"typeOther": "Other",
"subscribe": "Subscribe {count} sessions",
"messages": "messages",
"error": "Failed to connect to remote server"
+5
View File
@@ -510,6 +510,11 @@
"found": "{count} 件のセッションが見つかりました",
"selectAll": "すべて選択",
"deselectAll": "選択解除",
"selectByType": "セッションタイプ",
"typeAll": "すべて",
"typePrivate": "個人チャット",
"typeGroup": "グループチャット",
"typeOther": "その他",
"subscribe": "{count} 件を購読",
"messages": "件のメッセージ",
"error": "リモートサーバーへの接続に失敗しました"
+5
View File
@@ -511,6 +511,11 @@
"found": "发现 {count} 个会话",
"selectAll": "全选",
"deselectAll": "取消全选",
"selectByType": "会话类型",
"typeAll": "全部",
"typePrivate": "私聊",
"typeGroup": "群聊",
"typeOther": "其他",
"subscribe": "订阅 {count} 个会话",
"messages": "条消息",
"error": "连接远程服务器失败"
+5
View File
@@ -510,6 +510,11 @@
"found": "發現 {count} 個會話",
"selectAll": "全選",
"deselectAll": "取消全選",
"selectByType": "會話類型",
"typeAll": "全部",
"typePrivate": "私訊",
"typeGroup": "群組",
"typeOther": "其他",
"subscribe": "訂閱 {count} 個會話",
"messages": "則訊息",
"error": "連線遠端伺服器失敗"