chore: sync local changes
这个提交包含在:
父节点
f36d657bba
当前提交
6eeea6f268
@ -41,7 +41,7 @@ export interface Statistics {
|
||||
|
||||
export interface ServiceRequest {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
platform: string
|
||||
serviceType: string
|
||||
status: 'PENDING' | 'APPROVED' | 'REJECTED'
|
||||
@ -69,7 +69,7 @@ export interface AppItem {
|
||||
|
||||
export interface FeatureServiceItem {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
platform: string
|
||||
serviceType: string
|
||||
enabled: boolean
|
||||
@ -148,7 +148,7 @@ export interface PushDeviceInfo {
|
||||
|
||||
export interface PushDiagnostics {
|
||||
tokenType: 'PUSH' | 'IM' | 'UNKNOWN'
|
||||
appId?: string
|
||||
appKey?: string
|
||||
userId?: string
|
||||
online: boolean
|
||||
lastSeenAt: number
|
||||
@ -160,7 +160,7 @@ export interface PushDiagnostics {
|
||||
|
||||
export interface PushDeviceLog {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
userId: string
|
||||
vendor: string
|
||||
tokenPreview: string
|
||||
@ -182,7 +182,7 @@ export interface PushDeviceLogPage {
|
||||
}
|
||||
|
||||
export interface PushTestResult {
|
||||
appId: string
|
||||
appKey: string
|
||||
userId: string
|
||||
sent: boolean
|
||||
targetCount: number
|
||||
@ -248,12 +248,12 @@ export const opsApi = {
|
||||
deleteSensitiveWord: (id: string) =>
|
||||
client.delete(`/ops/risk/sensitive-words/${id}`),
|
||||
|
||||
searchPushByToken: (token: string, appId = '') =>
|
||||
client.get<{ data: PushDiagnostics }>('/ops/push/search', { params: { token, appId } }),
|
||||
searchPushByToken: (token: string, appKey = '') =>
|
||||
client.get<{ data: PushDiagnostics }>('/ops/push/search', { params: { token, appKey } }),
|
||||
|
||||
listPushDeviceLogs: (appId: string, userId: string, page = 0, size = 20) =>
|
||||
client.get<{ data: PushDeviceLogPage }>('/ops/push/device-logs', { params: { appId, userId, page, size } }),
|
||||
listPushDeviceLogs: (appKey: string, userId: string, page = 0, size = 20) =>
|
||||
client.get<{ data: PushDeviceLogPage }>('/ops/push/device-logs', { params: { appKey, userId, page, size } }),
|
||||
|
||||
sendPushTestOffline: (payload: { appId: string; userId: string; title: string; body: string; payload?: string }) =>
|
||||
sendPushTestOffline: (payload: { appKey: string; userId: string; title: string; body: string; payload?: string }) =>
|
||||
client.post<{ data: PushTestResult }>('/ops/push/test-offline', payload),
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
{{ diagnostics.online ? '用户在线' : '用户离线' }}
|
||||
</el-tag>
|
||||
<el-button
|
||||
v-if="diagnostics?.appId && diagnostics?.userId"
|
||||
v-if="diagnostics?.appKey && diagnostics?.userId"
|
||||
type="primary"
|
||||
:disabled="!diagnostics.deliverableDevices?.length"
|
||||
:loading="testLoading"
|
||||
@ -32,7 +32,7 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="AppId">
|
||||
<el-input v-model="form.appId" placeholder="可选;push token 无法解析 AppId 时使用" clearable />
|
||||
<el-input v-model="form.appKey" placeholder="可选;push token 无法解析 AppId 时使用" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="loading" @click="search">查询</el-button>
|
||||
@ -101,7 +101,7 @@
|
||||
<template #header>
|
||||
<div class="header-row">
|
||||
<span>历史登录设备日志</span>
|
||||
<el-button :disabled="!diagnostics.appId || !diagnostics.userId" :loading="logsLoading" @click="loadLogs">
|
||||
<el-button :disabled="!diagnostics.appKey || !diagnostics.userId" :loading="logsLoading" @click="loadLogs">
|
||||
刷新
|
||||
</el-button>
|
||||
</div>
|
||||
@ -141,7 +141,7 @@ import { reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { opsApi, type PushDeviceInfo, type PushDeviceLog, type PushDiagnostics } from '@/api/ops'
|
||||
|
||||
const form = reactive({ token: '', appId: '' })
|
||||
const form = reactive({ token: '', appKey: '' })
|
||||
const loading = ref(false)
|
||||
const logsLoading = ref(false)
|
||||
const testLoading = ref(false)
|
||||
@ -158,12 +158,12 @@ async function search() {
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await opsApi.searchPushByToken(form.token.trim(), form.appId.trim())
|
||||
const res = await opsApi.searchPushByToken(form.token.trim(), form.appKey.trim())
|
||||
diagnostics.value = res.data.data
|
||||
logs.value = []
|
||||
logTotal.value = 0
|
||||
logPage.value = 0
|
||||
if (diagnostics.value.appId && diagnostics.value.userId) {
|
||||
if (diagnostics.value.appKey && diagnostics.value.userId) {
|
||||
await loadLogs()
|
||||
}
|
||||
} finally {
|
||||
@ -172,11 +172,11 @@ async function search() {
|
||||
}
|
||||
|
||||
async function loadLogs() {
|
||||
if (!diagnostics.value?.appId || !diagnostics.value?.userId) return
|
||||
if (!diagnostics.value?.appKey || !diagnostics.value?.userId) return
|
||||
logsLoading.value = true
|
||||
try {
|
||||
const res = await opsApi.listPushDeviceLogs(
|
||||
diagnostics.value.appId,
|
||||
diagnostics.value.appKey,
|
||||
diagnostics.value.userId,
|
||||
logPage.value,
|
||||
logSize,
|
||||
@ -194,11 +194,11 @@ function changeLogPage(page: number) {
|
||||
}
|
||||
|
||||
async function sendTestOffline() {
|
||||
if (!diagnostics.value?.appId || !diagnostics.value?.userId) return
|
||||
if (!diagnostics.value?.appKey || !diagnostics.value?.userId) return
|
||||
testLoading.value = true
|
||||
try {
|
||||
const res = await opsApi.sendPushTestOffline({
|
||||
appId: diagnostics.value.appId,
|
||||
appKey: diagnostics.value.appKey,
|
||||
userId: diagnostics.value.userId,
|
||||
title: 'XuqmGroup Push 测试',
|
||||
body: `离线推送测试 ${new Date().toLocaleString('zh-CN')}`,
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
</div>
|
||||
|
||||
<el-table :data="requests" v-loading="loading">
|
||||
<el-table-column prop="appId" label="AppID" width="180" />
|
||||
<el-table-column prop="appKey" label="AppID" width="180" />
|
||||
<el-table-column prop="platform" label="平台" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag size="small">{{ row.platform }}</el-tag>
|
||||
|
||||
@ -25,7 +25,7 @@ export interface CreateAppRequest {
|
||||
|
||||
export interface FeatureService {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
platform: 'ANDROID' | 'IOS' | 'HARMONY'
|
||||
serviceType: 'IM' | 'PUSH' | 'UPDATE'
|
||||
enabled: boolean
|
||||
@ -121,11 +121,11 @@ export const appApi = {
|
||||
|
||||
delete: (id: string) => client.delete(`/apps/${id}`),
|
||||
|
||||
getServices: (appId: string) =>
|
||||
client.get<{ data: FeatureService[] }>(`/apps/${appId}/services`),
|
||||
getServices: (appKey: string) =>
|
||||
client.get<{ data: FeatureService[] }>(`/apps/${appKey}/services`),
|
||||
|
||||
getService: async (appId: string, platform: string, serviceType: string) => {
|
||||
const res = await client.get<{ data: FeatureService[] }>(`/apps/${appId}/services`)
|
||||
getService: async (appKey: string, platform: string, serviceType: string) => {
|
||||
const res = await client.get<{ data: FeatureService[] }>(`/apps/${appKey}/services`)
|
||||
const service = res.data.data.find(item => item.platform === platform && item.serviceType === serviceType)
|
||||
if (!service) {
|
||||
throw new Error('服务不存在')
|
||||
@ -136,29 +136,29 @@ export const appApi = {
|
||||
} as typeof res & { data: { data: FeatureService } }
|
||||
},
|
||||
|
||||
toggleService: (appId: string, platform: string, serviceType: string, enable: boolean) =>
|
||||
client.post<{ data: FeatureService }>(`/apps/${appId}/services/toggle`, null, {
|
||||
toggleService: (appKey: string, platform: string, serviceType: string, enable: boolean) =>
|
||||
client.post<{ data: FeatureService }>(`/apps/${appKey}/services/toggle`, null, {
|
||||
params: { platform, serviceType, enable },
|
||||
}),
|
||||
|
||||
updateServiceConfig: (
|
||||
appId: string,
|
||||
appKey: string,
|
||||
platform: string,
|
||||
serviceType: string,
|
||||
config: Partial<ImServiceConfig> & Partial<UpdateServiceConfig> & Partial<PushServiceConfig> | Record<string, unknown>,
|
||||
) =>
|
||||
client.put<{ data: FeatureService }>(`/apps/${appId}/services/config`, config, {
|
||||
client.put<{ data: FeatureService }>(`/apps/${appKey}/services/config`, config, {
|
||||
params: { platform, serviceType },
|
||||
}),
|
||||
|
||||
requestSecretVerify: (appId: string, purpose: 'REVEAL_SECRET' | 'RESET_SECRET') =>
|
||||
client.post<{ data: null }>(`/apps/${appId}/request-secret-verify`, null, {
|
||||
requestSecretVerify: (appKey: string, purpose: 'REVEAL_SECRET' | 'RESET_SECRET') =>
|
||||
client.post<{ data: null }>(`/apps/${appKey}/request-secret-verify`, null, {
|
||||
params: { purpose },
|
||||
}),
|
||||
|
||||
revealSecret: (appId: string, code: string) =>
|
||||
client.post<{ data: { appSecret: string } }>(`/apps/${appId}/reveal-secret`, { code }),
|
||||
revealSecret: (appKey: string, code: string) =>
|
||||
client.post<{ data: { appSecret: string } }>(`/apps/${appKey}/reveal-secret`, { code }),
|
||||
|
||||
resetSecret: (appId: string, code: string) =>
|
||||
client.post<{ data: { appSecret: string } }>(`/apps/${appId}/reset-secret`, { code }),
|
||||
resetSecret: (appKey: string, code: string) =>
|
||||
client.post<{ data: { appSecret: string } }>(`/apps/${appKey}/reset-secret`, { code }),
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ imClient.interceptors.response.use(
|
||||
|
||||
export interface ImUser {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
userId: string
|
||||
nickname: string
|
||||
avatar?: string
|
||||
@ -79,7 +79,7 @@ export interface ImUser {
|
||||
|
||||
export interface ImProfile {
|
||||
id?: string
|
||||
appId?: string
|
||||
appKey?: string
|
||||
userId: string
|
||||
nickname?: string | null
|
||||
avatar?: string | null
|
||||
@ -90,7 +90,7 @@ export interface ImProfile {
|
||||
|
||||
export interface ImGroup {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
name: string
|
||||
creatorId: string
|
||||
groupType?: string | null
|
||||
@ -102,7 +102,7 @@ export interface ImGroup {
|
||||
|
||||
export interface ImMessage {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
fromUserId: string
|
||||
toId: string
|
||||
chatType: 'SINGLE' | 'GROUP'
|
||||
@ -131,7 +131,7 @@ export interface ImStats {
|
||||
|
||||
export interface OperationLog {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
operatorId: string
|
||||
action: string
|
||||
resourceType: string
|
||||
@ -142,7 +142,7 @@ export interface OperationLog {
|
||||
|
||||
export interface KeywordFilter {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
pattern: string
|
||||
replacement?: string | null
|
||||
action: 'REPLACE' | 'BLOCK'
|
||||
@ -152,7 +152,7 @@ export interface KeywordFilter {
|
||||
|
||||
export interface GlobalMute {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
enabled: boolean
|
||||
createdAt: number
|
||||
updatedAt: number
|
||||
@ -160,7 +160,7 @@ export interface GlobalMute {
|
||||
|
||||
export interface WebhookConfig {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
url: string
|
||||
secret?: string | null
|
||||
enabled: boolean
|
||||
@ -177,7 +177,7 @@ export interface WebhookConfigForm {
|
||||
|
||||
export interface WebhookDelivery {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
callbackId: string
|
||||
callbackEvent: string
|
||||
url: string
|
||||
@ -191,7 +191,7 @@ export interface WebhookDelivery {
|
||||
|
||||
export interface WebhookAlert {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
webhookId: string
|
||||
webhookUrl: string
|
||||
alertType: string
|
||||
@ -203,7 +203,7 @@ export interface WebhookAlert {
|
||||
|
||||
export interface GroupJoinRequest {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
groupId: string
|
||||
requesterId: string
|
||||
remark?: string | null
|
||||
@ -213,192 +213,192 @@ export interface GroupJoinRequest {
|
||||
}
|
||||
|
||||
export const imAdminApi = {
|
||||
listUsers(appId: string, page = 0, size = 20) {
|
||||
listUsers(appKey: string, page = 0, size = 20) {
|
||||
return imClient.get<{ data: PagedResult<ImUser> }>(
|
||||
'/api/im/admin/users', { params: { appId, page, size } },
|
||||
'/api/im/admin/users', { params: { appKey, page, size } },
|
||||
)
|
||||
},
|
||||
|
||||
updateUserStatus(appId: string, userId: string, status: 'ACTIVE' | 'BANNED') {
|
||||
return imClient.put(`/api/im/admin/users/${encodeURIComponent(userId)}/status`, { status }, { params: { appId } })
|
||||
updateUserStatus(appKey: string, userId: string, status: 'ACTIVE' | 'BANNED') {
|
||||
return imClient.put(`/api/im/admin/users/${encodeURIComponent(userId)}/status`, { status }, { params: { appKey } })
|
||||
},
|
||||
|
||||
listGroups(appId: string) {
|
||||
return imClient.get<{ data: ImGroup[] }>('/api/im/admin/groups', { params: { appId } })
|
||||
listGroups(appKey: string) {
|
||||
return imClient.get<{ data: ImGroup[] }>('/api/im/admin/groups', { params: { appKey } })
|
||||
},
|
||||
|
||||
getStats(appId: string) {
|
||||
return imClient.get<{ data: ImStats }>('/api/im/admin/stats', { params: { appId } })
|
||||
getStats(appKey: string) {
|
||||
return imClient.get<{ data: ImStats }>('/api/im/admin/stats', { params: { appKey } })
|
||||
},
|
||||
|
||||
getOperationLogs(appId: string, page = 0, size = 20) {
|
||||
getOperationLogs(appKey: string, page = 0, size = 20) {
|
||||
return imClient.get<{ data: PagedResult<OperationLog> }>('/api/im/admin/operation-logs', {
|
||||
params: { appId, page, size },
|
||||
params: { appKey, page, size },
|
||||
})
|
||||
},
|
||||
|
||||
listWebhooks(appId: string) {
|
||||
listWebhooks(appKey: string) {
|
||||
return imClient.get<{ data: WebhookConfig[] }>('/api/im/admin/webhooks', {
|
||||
params: { appId },
|
||||
params: { appKey },
|
||||
})
|
||||
},
|
||||
|
||||
createWebhook(appId: string, form: WebhookConfigForm) {
|
||||
createWebhook(appKey: string, form: WebhookConfigForm) {
|
||||
return imClient.post<{ data: WebhookConfig }>('/api/im/admin/webhooks', form, {
|
||||
params: { appId },
|
||||
params: { appKey },
|
||||
})
|
||||
},
|
||||
|
||||
updateUser(
|
||||
appId: string,
|
||||
appKey: string,
|
||||
userId: string,
|
||||
form: { nickname?: string; avatar?: string; gender?: string; status?: string },
|
||||
) {
|
||||
return imClient.put<{ data: ImUser }>(
|
||||
`/api/im/admin/users/${encodeURIComponent(userId)}`,
|
||||
form,
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
updateWebhook(appId: string, webhookId: string, form: WebhookConfigForm) {
|
||||
updateWebhook(appKey: string, webhookId: string, form: WebhookConfigForm) {
|
||||
return imClient.put<{ data: WebhookConfig }>(`/api/im/admin/webhooks/${encodeURIComponent(webhookId)}`, form, {
|
||||
params: { appId },
|
||||
params: { appKey },
|
||||
})
|
||||
},
|
||||
|
||||
deleteWebhook(appId: string, webhookId: string) {
|
||||
deleteWebhook(appKey: string, webhookId: string) {
|
||||
return imClient.delete<{ data: null }>(`/api/im/admin/webhooks/${encodeURIComponent(webhookId)}`, {
|
||||
params: { appId },
|
||||
params: { appKey },
|
||||
})
|
||||
},
|
||||
|
||||
listKeywordFilters(appId: string) {
|
||||
listKeywordFilters(appKey: string) {
|
||||
return imClient.get<{ data: KeywordFilter[] }>('/api/im/admin/keyword-filters', {
|
||||
params: { appId },
|
||||
params: { appKey },
|
||||
})
|
||||
},
|
||||
|
||||
createKeywordFilter(
|
||||
appId: string,
|
||||
appKey: string,
|
||||
form: { pattern: string; replacement?: string; action: 'REPLACE' | 'BLOCK'; enabled: boolean },
|
||||
) {
|
||||
return imClient.post<{ data: KeywordFilter }>('/api/im/admin/keyword-filters', form, {
|
||||
params: { appId },
|
||||
params: { appKey },
|
||||
})
|
||||
},
|
||||
|
||||
updateKeywordFilter(
|
||||
appId: string,
|
||||
appKey: string,
|
||||
filterId: string,
|
||||
form: { pattern: string; replacement?: string; action: 'REPLACE' | 'BLOCK'; enabled: boolean },
|
||||
) {
|
||||
return imClient.put<{ data: KeywordFilter }>(`/api/im/admin/keyword-filters/${encodeURIComponent(filterId)}`, form, {
|
||||
params: { appId },
|
||||
params: { appKey },
|
||||
})
|
||||
},
|
||||
|
||||
deleteKeywordFilter(appId: string, filterId: string) {
|
||||
deleteKeywordFilter(appKey: string, filterId: string) {
|
||||
return imClient.delete<{ data: null }>(`/api/im/admin/keyword-filters/${encodeURIComponent(filterId)}`, {
|
||||
params: { appId },
|
||||
params: { appKey },
|
||||
})
|
||||
},
|
||||
|
||||
getGlobalMute(appId: string) {
|
||||
getGlobalMute(appKey: string) {
|
||||
return imClient.get<{ data: GlobalMute }>('/api/im/admin/global-mute', {
|
||||
params: { appId },
|
||||
params: { appKey },
|
||||
})
|
||||
},
|
||||
|
||||
setGlobalMute(appId: string, enabled: boolean) {
|
||||
setGlobalMute(appKey: string, enabled: boolean) {
|
||||
return imClient.put<{ data: GlobalMute }>('/api/im/admin/global-mute', null, {
|
||||
params: { appId, enabled },
|
||||
params: { appKey, enabled },
|
||||
})
|
||||
},
|
||||
|
||||
listGroupMembers(appId: string, groupId: string) {
|
||||
listGroupMembers(appKey: string, groupId: string) {
|
||||
return imClient.get<{ data: ImUser[] }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/members`,
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
searchGroupMembers(appId: string, groupId: string, keyword: string, size = 20) {
|
||||
searchGroupMembers(appKey: string, groupId: string, keyword: string, size = 20) {
|
||||
return imClient.get<{ data: ImUser[] }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/members/search`,
|
||||
{ params: { appId, keyword, size } },
|
||||
{ params: { appKey, keyword, size } },
|
||||
)
|
||||
},
|
||||
|
||||
addGroupMember(appId: string, groupId: string, userId: string) {
|
||||
addGroupMember(appKey: string, groupId: string, userId: string) {
|
||||
return imClient.post<{ data: ImGroup }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/members`,
|
||||
{ userId },
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
removeGroupMember(appId: string, groupId: string, userId: string) {
|
||||
removeGroupMember(appKey: string, groupId: string, userId: string) {
|
||||
return imClient.delete<{ data: ImGroup }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/members/${encodeURIComponent(userId)}`,
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
setGroupRole(appId: string, groupId: string, userId: string, role: 'ADMIN' | 'MEMBER') {
|
||||
setGroupRole(appKey: string, groupId: string, userId: string, role: 'ADMIN' | 'MEMBER') {
|
||||
return imClient.post<{ data: ImGroup }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/roles`,
|
||||
{ userId, role },
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
muteGroupMember(appId: string, groupId: string, userId: string, minutes: number) {
|
||||
muteGroupMember(appKey: string, groupId: string, userId: string, minutes: number) {
|
||||
return imClient.post<{ data: ImGroup }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/mute`,
|
||||
{ userId, minutes },
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
listGroupJoinRequests(appId: string, groupId: string) {
|
||||
listGroupJoinRequests(appKey: string, groupId: string) {
|
||||
return imClient.get<{ data: GroupJoinRequest[] }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/join-requests`,
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
sendGroupJoinRequest(appId: string, groupId: string, remark?: string) {
|
||||
sendGroupJoinRequest(appKey: string, groupId: string, remark?: string) {
|
||||
return imClient.post<{ data: GroupJoinRequest }>(
|
||||
`/api/im/groups/${encodeURIComponent(groupId)}/join-requests`,
|
||||
null,
|
||||
{
|
||||
params: {
|
||||
appId,
|
||||
appKey,
|
||||
...(remark ? { remark } : {}),
|
||||
},
|
||||
},
|
||||
)
|
||||
},
|
||||
|
||||
acceptGroupJoinRequest(appId: string, groupId: string, requestId: string) {
|
||||
acceptGroupJoinRequest(appKey: string, groupId: string, requestId: string) {
|
||||
return imClient.post<{ data: GroupJoinRequest }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/join-requests/${encodeURIComponent(requestId)}/accept`,
|
||||
null,
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
rejectGroupJoinRequest(appId: string, groupId: string, requestId: string) {
|
||||
rejectGroupJoinRequest(appKey: string, groupId: string, requestId: string) {
|
||||
return imClient.post<{ data: GroupJoinRequest }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/join-requests/${encodeURIComponent(requestId)}/reject`,
|
||||
null,
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
getMessages(
|
||||
appId: string,
|
||||
appKey: string,
|
||||
userA: string,
|
||||
userB: string,
|
||||
page = 0,
|
||||
@ -412,7 +412,7 @@ export const imAdminApi = {
|
||||
) {
|
||||
return imClient.get<{ data: PagedResult<ImMessage> }>('/api/im/admin/messages', {
|
||||
params: {
|
||||
appId,
|
||||
appKey,
|
||||
userA,
|
||||
userB,
|
||||
page,
|
||||
@ -425,20 +425,20 @@ export const imAdminApi = {
|
||||
})
|
||||
},
|
||||
|
||||
revokeMessage(appId: string, messageId: string) {
|
||||
revokeMessage(appKey: string, messageId: string) {
|
||||
return imClient.post<{ data: ImMessage }>(
|
||||
`/api/im/admin/messages/${encodeURIComponent(messageId)}/revoke`,
|
||||
{},
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
dismissGroup(appId: string, groupId: string) {
|
||||
return imClient.delete<{ data: null }>(`/api/im/admin/groups/${encodeURIComponent(groupId)}`, { params: { appId } })
|
||||
dismissGroup(appKey: string, groupId: string) {
|
||||
return imClient.delete<{ data: null }>(`/api/im/admin/groups/${encodeURIComponent(groupId)}`, { params: { appKey } })
|
||||
},
|
||||
|
||||
registerUser(
|
||||
appId: string,
|
||||
appKey: string,
|
||||
userId: string,
|
||||
nickname?: string,
|
||||
avatar?: string,
|
||||
@ -454,12 +454,12 @@ export const imAdminApi = {
|
||||
...(gender ? { gender } : {}),
|
||||
...(status ? { status } : {}),
|
||||
},
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
createGroup(
|
||||
appId: string,
|
||||
appKey: string,
|
||||
name: string,
|
||||
creatorId: string,
|
||||
memberIds: string[],
|
||||
@ -475,31 +475,31 @@ export const imAdminApi = {
|
||||
...(groupType ? { groupType } : {}),
|
||||
...(announcement ? { announcement } : {}),
|
||||
},
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
updateGroup(
|
||||
appId: string,
|
||||
appKey: string,
|
||||
groupId: string,
|
||||
form: { name?: string; groupType?: string; announcement?: string },
|
||||
) {
|
||||
return imClient.put<{ data: ImGroup }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}`,
|
||||
form,
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
searchUsers(appId: string, keyword: string, size = 20) {
|
||||
searchUsers(appKey: string, keyword: string, size = 20) {
|
||||
return imClient.get<{ data: ImUser[] }>(
|
||||
'/api/im/admin/users/search',
|
||||
{ params: { appId, keyword, size } },
|
||||
{ params: { appKey, keyword, size } },
|
||||
)
|
||||
},
|
||||
|
||||
searchMessages(
|
||||
appId: string,
|
||||
appKey: string,
|
||||
filters: {
|
||||
keyword?: string
|
||||
chatType?: string
|
||||
@ -512,7 +512,7 @@ export const imAdminApi = {
|
||||
) {
|
||||
return imClient.get<{ data: PagedResult<ImMessage> }>('/api/im/admin/messages/search', {
|
||||
params: {
|
||||
appId,
|
||||
appKey,
|
||||
...(filters.keyword ? { keyword: filters.keyword } : {}),
|
||||
...(filters.chatType ? { chatType: filters.chatType } : {}),
|
||||
...(filters.msgType ? { msgType: filters.msgType } : {}),
|
||||
@ -524,20 +524,20 @@ export const imAdminApi = {
|
||||
})
|
||||
},
|
||||
|
||||
getProfile(appId: string, userId: string) {
|
||||
getProfile(appKey: string, userId: string) {
|
||||
return imClient.get<{ data: ImProfile }>(
|
||||
`/api/im/accounts/${encodeURIComponent(userId)}`,
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
updateProfile(appId: string, userId: string, nickname?: string, avatar?: string, gender?: string) {
|
||||
updateProfile(appKey: string, userId: string, nickname?: string, avatar?: string, gender?: string) {
|
||||
return imClient.put<{ data: ImProfile }>(
|
||||
`/api/im/accounts/${encodeURIComponent(userId)}`,
|
||||
{},
|
||||
{
|
||||
params: {
|
||||
appId,
|
||||
appKey,
|
||||
...(nickname ? { nickname } : {}),
|
||||
...(avatar ? { avatar } : {}),
|
||||
...(gender ? { gender } : {}),
|
||||
@ -546,39 +546,39 @@ export const imAdminApi = {
|
||||
)
|
||||
},
|
||||
|
||||
transferGroupOwner(appId: string, groupId: string, newOwnerId: string) {
|
||||
transferGroupOwner(appKey: string, groupId: string, newOwnerId: string) {
|
||||
return imClient.post<{ data: ImGroup }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/owner`,
|
||||
{ newOwnerId },
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
updateGroupAttributes(appId: string, groupId: string, attributes: Record<string, unknown>) {
|
||||
updateGroupAttributes(appKey: string, groupId: string, attributes: Record<string, unknown>) {
|
||||
return imClient.put<{ data: ImGroup }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/attributes`,
|
||||
{ attributes },
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
removeGroupAttributes(appId: string, groupId: string, keys: string[]) {
|
||||
removeGroupAttributes(appKey: string, groupId: string, keys: string[]) {
|
||||
return imClient.post<{ data: ImGroup }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/attributes/delete`,
|
||||
{ keys },
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
getGroupReadReceipts(appId: string, groupId: string, messageIds?: string[]) {
|
||||
getGroupReadReceipts(appKey: string, groupId: string, messageIds?: string[]) {
|
||||
return imClient.post<{ data: Array<{ messageId: string; readCount: number; readUserIds: string[] }> }>(
|
||||
`/api/im/admin/groups/${encodeURIComponent(groupId)}/read-receipts`,
|
||||
{ messageIds },
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
queryUserState(appId: string, userIds: string[]) {
|
||||
queryUserState(appKey: string, userIds: string[]) {
|
||||
return imClient.get<{ data: Record<string, { online: boolean; lastSeenAt: number }> }>(
|
||||
'/api/im/admin/users/state',
|
||||
{ params: { userIds: userIds.join(',') } },
|
||||
@ -586,32 +586,32 @@ export const imAdminApi = {
|
||||
},
|
||||
|
||||
listWebhookDeliveries(
|
||||
appId: string,
|
||||
appKey: string,
|
||||
params: { callbackEvent?: string; success?: boolean; page?: number; size?: number } = {},
|
||||
) {
|
||||
return imClient.get<{ data: PagedResult<WebhookDelivery> }>('/api/im/admin/webhook-deliveries', {
|
||||
params: { appId, ...params },
|
||||
params: { appKey, ...params },
|
||||
})
|
||||
},
|
||||
|
||||
listWebhookAlerts(
|
||||
appId: string,
|
||||
appKey: string,
|
||||
params: { acknowledged?: boolean; page?: number; size?: number } = {},
|
||||
) {
|
||||
return imClient.get<{ data: PagedResult<WebhookAlert> }>('/api/im/admin/webhook-alerts', {
|
||||
params: { appId, ...params },
|
||||
params: { appKey, ...params },
|
||||
})
|
||||
},
|
||||
|
||||
acknowledgeWebhookAlert(appId: string, alertId: string) {
|
||||
acknowledgeWebhookAlert(appKey: string, alertId: string) {
|
||||
return imClient.post<{ data: WebhookAlert }>(
|
||||
`/api/im/admin/webhook-alerts/${encodeURIComponent(alertId)}/acknowledge`,
|
||||
null,
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
getWebhookHealth(appId: string, webhookId: string) {
|
||||
getWebhookHealth(appKey: string, webhookId: string) {
|
||||
return imClient.get<{
|
||||
data: {
|
||||
webhookId: string
|
||||
@ -621,6 +621,6 @@ export const imAdminApi = {
|
||||
lastFailureAt: number | null
|
||||
unacknowledgedAlerts: number
|
||||
}
|
||||
}>(`/api/im/admin/webhooks/${encodeURIComponent(webhookId)}/health`, { params: { appId } })
|
||||
}>(`/api/im/admin/webhooks/${encodeURIComponent(webhookId)}/health`, { params: { appKey } })
|
||||
},
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ export interface DeviceInfo {
|
||||
|
||||
export interface UserPushStatus {
|
||||
tokenType: string
|
||||
appId: string
|
||||
appKey: string
|
||||
userId: string
|
||||
online: boolean
|
||||
lastSeenAt: number
|
||||
@ -29,7 +29,7 @@ export interface UserPushStatus {
|
||||
|
||||
export interface DeviceLoginLog {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
userId: string
|
||||
vendor: string
|
||||
deviceId: string | null
|
||||
@ -48,7 +48,7 @@ export interface PagedLogs {
|
||||
}
|
||||
|
||||
export interface TestPushResult {
|
||||
appId: string
|
||||
appKey: string
|
||||
userId: string
|
||||
sent: boolean
|
||||
targetCount: number
|
||||
@ -56,21 +56,21 @@ export interface TestPushResult {
|
||||
}
|
||||
|
||||
export const pushAdminApi = {
|
||||
getUserStatus(appId: string, userId: string) {
|
||||
getUserStatus(appKey: string, userId: string) {
|
||||
return client.get<{ data: UserPushStatus }>('/push/admin/user-status', {
|
||||
params: { appId, userId },
|
||||
params: { appKey, userId },
|
||||
})
|
||||
},
|
||||
|
||||
getDeviceLogs(appId: string, userId: string, page = 0, size = 20) {
|
||||
getDeviceLogs(appKey: string, userId: string, page = 0, size = 20) {
|
||||
return client.get<{ data: PagedLogs }>('/push/admin/device-logs', {
|
||||
params: { appId, userId, page, size },
|
||||
params: { appKey, userId, page, size },
|
||||
})
|
||||
},
|
||||
|
||||
testOffline(appId: string, userId: string, title: string, body: string, payload?: string) {
|
||||
testOffline(appKey: string, userId: string, title: string, body: string, payload?: string) {
|
||||
return client.post<{ data: TestPushResult }>('/push/admin/test-offline', {
|
||||
appId,
|
||||
appKey,
|
||||
userId,
|
||||
title,
|
||||
body,
|
||||
|
||||
@ -87,14 +87,14 @@ export type GraySelectionSource = 'LOCAL' | 'CALLBACK'
|
||||
|
||||
export interface PublishConfig {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
configJson?: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
export interface OperationLog {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
resourceType: string
|
||||
resourceId: string
|
||||
action: string
|
||||
@ -119,7 +119,7 @@ export interface GrayMemberGroup {
|
||||
|
||||
export interface StoreConfig {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
storeType: StoreType
|
||||
configJson?: string
|
||||
enabled: boolean
|
||||
@ -128,7 +128,7 @@ export interface StoreConfig {
|
||||
|
||||
export interface AppVersion {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
platform: 'ANDROID' | 'IOS' | 'HARMONY'
|
||||
versionName: string
|
||||
versionCode: number
|
||||
@ -164,7 +164,7 @@ export interface AppPackageInspectResult {
|
||||
|
||||
export interface RnBundle {
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
moduleId: string
|
||||
platform: 'ANDROID' | 'IOS' | 'HARMONY'
|
||||
version: string
|
||||
@ -221,9 +221,9 @@ export interface UnifiedReleaseManifest {
|
||||
}
|
||||
|
||||
export const updateAdminApi = {
|
||||
listAppVersions(appId: string, platform: 'ANDROID' | 'IOS' | 'HARMONY') {
|
||||
listAppVersions(appKey: string, platform: 'ANDROID' | 'IOS' | 'HARMONY') {
|
||||
return updateClient.get<{ data: AppVersion[] }>('/api/v1/updates/app/list', {
|
||||
params: { appId, platform },
|
||||
params: { appKey, platform },
|
||||
})
|
||||
},
|
||||
|
||||
@ -255,9 +255,9 @@ export const updateAdminApi = {
|
||||
})
|
||||
},
|
||||
|
||||
listRnBundles(appId: string, moduleId?: string, platform?: string) {
|
||||
listRnBundles(appKey: string, moduleId?: string, platform?: string) {
|
||||
return updateClient.get<{ data: RnBundle[] }>('/api/v1/rn/list', {
|
||||
params: { appId, ...(moduleId && { moduleId }), ...(platform && { platform }) },
|
||||
params: { appKey, ...(moduleId && { moduleId }), ...(platform && { platform }) },
|
||||
})
|
||||
},
|
||||
|
||||
@ -293,20 +293,20 @@ export const updateAdminApi = {
|
||||
|
||||
// ── Store config ────────────────────────────────────────────────────────
|
||||
|
||||
getStoreConfigs(appId: string) {
|
||||
return updateClient.get<{ data: StoreConfig[] }>('/api/v1/updates/store/configs', { params: { appId } })
|
||||
getStoreConfigs(appKey: string) {
|
||||
return updateClient.get<{ data: StoreConfig[] }>('/api/v1/updates/store/configs', { params: { appKey } })
|
||||
},
|
||||
|
||||
saveStoreConfig(appId: string, storeType: StoreType, configJson: string, enabled: boolean) {
|
||||
saveStoreConfig(appKey: string, storeType: StoreType, configJson: string, enabled: boolean) {
|
||||
return updateClient.put<{ data: StoreConfig }>(
|
||||
`/api/v1/updates/store/configs/${storeType}`,
|
||||
{ configJson, enabled },
|
||||
{ params: { appId } },
|
||||
{ params: { appKey } },
|
||||
)
|
||||
},
|
||||
|
||||
deleteStoreConfig(appId: string, storeType: StoreType) {
|
||||
return updateClient.delete(`/api/v1/updates/store/configs/${storeType}`, { params: { appId } })
|
||||
deleteStoreConfig(appKey: string, storeType: StoreType) {
|
||||
return updateClient.delete(`/api/v1/updates/store/configs/${storeType}`, { params: { appKey } })
|
||||
},
|
||||
|
||||
executeSubmitToStores(
|
||||
@ -329,29 +329,29 @@ export const updateAdminApi = {
|
||||
)
|
||||
},
|
||||
|
||||
getPublishConfig(appId: string) {
|
||||
return updateClient.get<{ data: PublishConfig }>('/api/v1/updates/publish/config', { params: { appId } })
|
||||
getPublishConfig(appKey: string) {
|
||||
return updateClient.get<{ data: PublishConfig }>('/api/v1/updates/publish/config', { params: { appKey } })
|
||||
},
|
||||
|
||||
savePublishConfig(appId: string, config: Record<string, unknown>) {
|
||||
return updateClient.put<{ data: PublishConfig }>('/api/v1/updates/publish/config', config, { params: { appId } })
|
||||
savePublishConfig(appKey: string, config: Record<string, unknown>) {
|
||||
return updateClient.put<{ data: PublishConfig }>('/api/v1/updates/publish/config', config, { params: { appKey } })
|
||||
},
|
||||
|
||||
listOperationLogs(appId: string, limit = 100) {
|
||||
listOperationLogs(appKey: string, limit = 100) {
|
||||
return updateClient.get<{ data: OperationLog[] }>('/api/v1/updates/ops/logs', {
|
||||
params: { appId, limit },
|
||||
params: { appKey, limit },
|
||||
})
|
||||
},
|
||||
|
||||
listGrayMembers(appId: string, keyword?: string, groupName?: string) {
|
||||
listGrayMembers(appKey: string, keyword?: string, groupName?: string) {
|
||||
return updateClient.get<{ data: GrayMemberGroup[] }>('/api/v1/updates/gray/members', {
|
||||
params: { appId, ...(keyword && { keyword }), ...(groupName && { groupName }) },
|
||||
params: { appKey, ...(keyword && { keyword }), ...(groupName && { groupName }) },
|
||||
})
|
||||
},
|
||||
|
||||
syncGrayMembers(appId: string) {
|
||||
syncGrayMembers(appKey: string) {
|
||||
return updateClient.post<{ data: GrayMemberGroup[] }>('/api/v1/updates/gray/members/sync', null, {
|
||||
params: { appId },
|
||||
params: { appKey },
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
@ -50,47 +50,47 @@ const router = createRouter({
|
||||
component: () => import('@/views/apps/AppDetailView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'apps/:appId/im-config',
|
||||
path: 'apps/:appKey/im-config',
|
||||
component: () => import('@/views/im/ImConfigView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'apps/:appId/push-config',
|
||||
path: 'apps/:appKey/push-config',
|
||||
component: () => import('@/views/push/PushConfigView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'apps/:appId/push-management',
|
||||
path: 'apps/:appKey/push-management',
|
||||
component: () => import('@/views/push/PushManagementView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'apps/:appId/im-webhooks',
|
||||
path: 'apps/:appKey/im-webhooks',
|
||||
component: () => import('@/views/im/ImWebhookView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'apps/:appId/im-webhooks/:webhookId/deliveries',
|
||||
path: 'apps/:appKey/im-webhooks/:webhookId/deliveries',
|
||||
component: () => import('@/views/im/WebhookDeliveryLogView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'apps/:appId/im-webhook-alerts',
|
||||
path: 'apps/:appKey/im-webhook-alerts',
|
||||
component: () => import('@/views/im/WebhookAlertView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'apps/:appId/im',
|
||||
path: 'apps/:appKey/im',
|
||||
component: () => import('@/views/im/ImManagementView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'apps/:appId/update',
|
||||
path: 'apps/:appKey/update',
|
||||
component: () => import('@/views/update/VersionManagementView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'services/im/:appId?',
|
||||
path: 'services/im/:appKey?',
|
||||
component: () => import('@/views/im/ImManagementView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'services/push/:appId?',
|
||||
path: 'services/push/:appKey?',
|
||||
component: () => import('@/views/push/PushManagementView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'services/update/:appId?',
|
||||
path: 'services/update/:appKey?',
|
||||
component: () => import('@/views/update/VersionManagementView.vue'),
|
||||
},
|
||||
{
|
||||
|
||||
@ -24,10 +24,10 @@
|
||||
</div>
|
||||
<div style="margin-top:10px;display:flex;gap:8px;flex-wrap:wrap">
|
||||
<!-- 服务配置页使用的是租户应用主键 app.id;IM 管理页才带 appKey。 -->
|
||||
<el-button size="small" @click="$router.push({ path: `/apps/${route.params.appId}/im`, query: { appKey: app.appKey } })">
|
||||
<el-button size="small" @click="$router.push({ path: `/apps/${route.params.appKey}/im`, query: { appKey: app.appKey } })">
|
||||
即时通讯管理 →
|
||||
</el-button>
|
||||
<el-button size="small" @click="$router.push(`/apps/${route.params.appId}`)">
|
||||
<el-button size="small" @click="$router.push(`/apps/${route.params.appKey}`)">
|
||||
返回详情
|
||||
</el-button>
|
||||
</div>
|
||||
@ -243,7 +243,7 @@ function normalizeFriendRequestMode(
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
const id = route.params.appId as string
|
||||
const id = route.params.appKey as string
|
||||
const [appRes, svcRes] = await Promise.all([
|
||||
appApi.get(id),
|
||||
appApi.getServices(id),
|
||||
@ -265,7 +265,7 @@ async function onToggleImService(enable: boolean) {
|
||||
confirmButtonText: '确认关闭',
|
||||
cancelButtonText: '取消',
|
||||
})
|
||||
await appApi.toggleService(route.params.appId as string, imServicePlatform(), 'IM', false)
|
||||
await appApi.toggleService(route.params.appKey as string, imServicePlatform(), 'IM', false)
|
||||
ElMessage.success('已关闭')
|
||||
loadData()
|
||||
}
|
||||
@ -275,7 +275,7 @@ async function onToggleImConfig(patch: Partial<ImServiceConfig>) {
|
||||
...imConfig.value,
|
||||
...patch,
|
||||
}
|
||||
await appApi.updateServiceConfig(route.params.appId as string, imServicePlatform(), 'IM', nextConfig)
|
||||
await appApi.updateServiceConfig(route.params.appKey as string, imServicePlatform(), 'IM', nextConfig)
|
||||
ElMessage.success('IM 配置已更新')
|
||||
loadData()
|
||||
}
|
||||
|
||||
@ -699,8 +699,8 @@
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="调用方式">POST 到你配置的回调地址,`Content-Type: application/json`。</el-descriptions-item>
|
||||
<el-descriptions-item label="请求头">`X-App-Id`、`X-App-Timestamp`、`X-App-Nonce`、`X-App-Signature`。</el-descriptions-item>
|
||||
<el-descriptions-item label="请求体">统一 envelope:`callbackId`、`callbackType`、`callbackEvent`、`requestTime`、`payload`、`appId`。</el-descriptions-item>
|
||||
<el-descriptions-item label="签名">`HMAC-SHA256(appSecret, appId + '\\n' + timestamp + '\\n' + nonce + '\\n' + sha256(body))`。</el-descriptions-item>
|
||||
<el-descriptions-item label="请求体">统一 envelope:`callbackId`、`callbackType`、`callbackEvent`、`requestTime`、`payload`、`appKey`。</el-descriptions-item>
|
||||
<el-descriptions-item label="签名">`HMAC-SHA256(appSecret, appKey + '\\n' + timestamp + '\\n' + nonce + '\\n' + sha256(body))`。</el-descriptions-item>
|
||||
<el-descriptions-item label="失败处理">回调发送失败只记录日志,不会中断消息发送、撤回等主流程。</el-descriptions-item>
|
||||
<el-descriptions-item label="幂等建议">接收方建议按 `callbackId` 去重。</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
@ -779,7 +779,7 @@ const appKey = computed(() => {
|
||||
if (typeof queryAppKey === 'string' && queryAppKey.trim()) {
|
||||
return queryAppKey.trim()
|
||||
}
|
||||
return String(route.params['appId'] ?? '')
|
||||
return String(route.params['appKey'] ?? '')
|
||||
})
|
||||
|
||||
const genderLabel: Record<string, string> = {
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="调用方式">服务端以 `POST` 方式推送到你配置的回调地址。</el-descriptions-item>
|
||||
<el-descriptions-item label="签名头">`X-App-Id`、`X-App-Timestamp`、`X-App-Nonce`、`X-App-Signature`。</el-descriptions-item>
|
||||
<el-descriptions-item label="验签公式">`HMAC-SHA256(appSecret, appId + '\\n' + timestamp + '\\n' + nonce + '\\n' + sha256(body))`。</el-descriptions-item>
|
||||
<el-descriptions-item label="验签公式">`HMAC-SHA256(appSecret, appKey + '\\n' + timestamp + '\\n' + nonce + '\\n' + sha256(body))`。</el-descriptions-item>
|
||||
<el-descriptions-item label="幂等建议">接收方建议按 `callbackId` 去重。</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-table :data="webhookEvents" border stripe style="margin-top:16px">
|
||||
@ -44,7 +44,7 @@
|
||||
<template #header>
|
||||
<div class="toolbar toolbar-space-between">
|
||||
<span>回调地址</span>
|
||||
<el-button link type="primary" @click="$router.push({ path: `/apps/${appId}/im-webhook-alerts` })">
|
||||
<el-button link type="primary" @click="$router.push({ path: `/apps/${appKey}/im-webhook-alerts` })">
|
||||
查看告警
|
||||
</el-button>
|
||||
</div>
|
||||
@ -86,7 +86,7 @@
|
||||
<el-table-column label="操作" width="220" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" size="small" @click="openEditWebhookDialog(row)">编辑</el-button>
|
||||
<el-button link type="info" size="small" @click="$router.push({ path: `/apps/${appId}/im-webhooks/${row.id}/deliveries` })">日志</el-button>
|
||||
<el-button link type="info" size="small" @click="$router.push({ path: `/apps/${appKey}/im-webhooks/${row.id}/deliveries` })">日志</el-button>
|
||||
<el-button link type="danger" size="small" @click="deleteWebhook(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -139,7 +139,7 @@ const webhookForm = ref<WebhookConfigForm & { enabled: boolean }>({
|
||||
enabled: true,
|
||||
})
|
||||
|
||||
const appId = computed(() => route.params.appId as string)
|
||||
const appKey = computed(() => route.params.appKey as string)
|
||||
|
||||
const webhookEvents = [
|
||||
{ event: 'message.sent', payload: 'ImMessageEntity', description: '消息发送成功后触发。' },
|
||||
@ -157,14 +157,14 @@ const webhookEvents = [
|
||||
]
|
||||
|
||||
async function loadApp() {
|
||||
const res = await appApi.get(appId.value)
|
||||
const res = await appApi.get(appKey.value)
|
||||
app.value = res.data.data
|
||||
}
|
||||
|
||||
async function loadWebhooks() {
|
||||
loadingWebhooks.value = true
|
||||
try {
|
||||
const res = await imAdminApi.listWebhooks(appId.value)
|
||||
const res = await imAdminApi.listWebhooks(appKey.value)
|
||||
webhooks.value = res.data.data
|
||||
} finally {
|
||||
loadingWebhooks.value = false
|
||||
@ -208,9 +208,9 @@ async function submitWebhookForm() {
|
||||
payload.secret = secret
|
||||
}
|
||||
if (editingWebhookId.value) {
|
||||
await imAdminApi.updateWebhook(appId.value, editingWebhookId.value, payload)
|
||||
await imAdminApi.updateWebhook(appKey.value, editingWebhookId.value, payload)
|
||||
} else {
|
||||
await imAdminApi.createWebhook(appId.value, payload)
|
||||
await imAdminApi.createWebhook(appKey.value, payload)
|
||||
}
|
||||
ElMessage.success('回调配置已保存')
|
||||
showWebhookDialog.value = false
|
||||
@ -226,7 +226,7 @@ async function deleteWebhook(row: WebhookConfig) {
|
||||
confirmButtonText: '确认删除',
|
||||
cancelButtonText: '取消',
|
||||
})
|
||||
await imAdminApi.deleteWebhook(appId.value, row.id)
|
||||
await imAdminApi.deleteWebhook(appKey.value, row.id)
|
||||
ElMessage.success('已删除')
|
||||
await loadWebhooks()
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ import { imAdminApi, type WebhookAlert } from '@/api/im'
|
||||
|
||||
const route = useRoute()
|
||||
const app = ref<App | null>(null)
|
||||
const appId = computed(() => route.params.appId as string)
|
||||
const appKey = computed(() => route.params.appKey as string)
|
||||
|
||||
const alerts = ref<WebhookAlert[]>([])
|
||||
const loading = ref(false)
|
||||
@ -89,7 +89,7 @@ const filterAcknowledged = ref<boolean | ''>('')
|
||||
const unacknowledgedCount = ref(0)
|
||||
|
||||
async function loadApp() {
|
||||
const res = await appApi.get(appId.value)
|
||||
const res = await appApi.get(appKey.value)
|
||||
app.value = res.data.data
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ async function loadAlerts() {
|
||||
try {
|
||||
const params: Record<string, unknown> = { page: page.value - 1, size: size.value }
|
||||
if (filterAcknowledged.value !== '') params.acknowledged = filterAcknowledged.value
|
||||
const res = await imAdminApi.listWebhookAlerts(appId.value, params)
|
||||
const res = await imAdminApi.listWebhookAlerts(appKey.value, params)
|
||||
alerts.value = res.data.data.content
|
||||
total.value = res.data.data.totalElements
|
||||
} finally {
|
||||
@ -107,12 +107,12 @@ async function loadAlerts() {
|
||||
}
|
||||
|
||||
async function loadUnacknowledgedCount() {
|
||||
const res = await imAdminApi.listWebhookAlerts(appId.value, { acknowledged: false, size: 1 })
|
||||
const res = await imAdminApi.listWebhookAlerts(appKey.value, { acknowledged: false, size: 1 })
|
||||
unacknowledgedCount.value = Number(res.data.data.totalElements)
|
||||
}
|
||||
|
||||
async function acknowledge(row: WebhookAlert) {
|
||||
await imAdminApi.acknowledgeWebhookAlert(appId.value, row.id)
|
||||
await imAdminApi.acknowledgeWebhookAlert(appKey.value, row.id)
|
||||
ElMessage.success('已确认')
|
||||
await loadAlerts()
|
||||
await loadUnacknowledgedCount()
|
||||
|
||||
@ -66,7 +66,7 @@ import { imAdminApi, type WebhookDelivery } from '@/api/im'
|
||||
|
||||
const route = useRoute()
|
||||
const app = ref<App | null>(null)
|
||||
const appId = computed(() => route.params.appId as string)
|
||||
const appKey = computed(() => route.params.appKey as string)
|
||||
const webhookId = computed(() => route.params.webhookId as string)
|
||||
const webhookUrl = ref('')
|
||||
|
||||
@ -79,12 +79,12 @@ const filterEvent = ref('')
|
||||
const filterSuccess = ref<boolean | ''>('')
|
||||
|
||||
async function loadApp() {
|
||||
const res = await appApi.get(appId.value)
|
||||
const res = await appApi.get(appKey.value)
|
||||
app.value = res.data.data
|
||||
}
|
||||
|
||||
async function loadWebhook() {
|
||||
const res = await imAdminApi.listWebhooks(appId.value)
|
||||
const res = await imAdminApi.listWebhooks(appKey.value)
|
||||
const wh = res.data.data.find((w) => w.id === webhookId.value)
|
||||
if (wh) webhookUrl.value = wh.url
|
||||
}
|
||||
@ -95,7 +95,7 @@ async function loadDeliveries() {
|
||||
const params: Record<string, unknown> = { page: page.value - 1, size: size.value }
|
||||
if (filterEvent.value) params.callbackEvent = filterEvent.value
|
||||
if (filterSuccess.value !== '') params.success = filterSuccess.value
|
||||
const res = await imAdminApi.listWebhookDeliveries(appId.value, params)
|
||||
const res = await imAdminApi.listWebhookDeliveries(appKey.value, params)
|
||||
deliveries.value = res.data.data.content
|
||||
total.value = res.data.data.totalElements
|
||||
} finally {
|
||||
|
||||
@ -321,7 +321,7 @@ const pushEnabled = computed(() => services.value.some(
|
||||
const servicePlatform = computed(() => selectedPlatform.value)
|
||||
|
||||
async function loadData() {
|
||||
const id = route.params.appId as string
|
||||
const id = route.params.appKey as string
|
||||
const [appRes, svcRes] = await Promise.all([
|
||||
appApi.get(id),
|
||||
appApi.getServices(id),
|
||||
|
||||
@ -2,14 +2,14 @@
|
||||
<div>
|
||||
<div v-if="isServicesPortal" class="portal-bar">
|
||||
<span class="portal-bar-title">离线推送管理</span>
|
||||
<el-select :model-value="appId" placeholder="选择应用" style="width:220px" @change="switchApp">
|
||||
<el-select :model-value="appKey" placeholder="选择应用" style="width:220px" @change="switchApp">
|
||||
<el-option v-for="a in portalApps" :key="a.appKey" :label="a.name" :value="a.appKey" />
|
||||
</el-select>
|
||||
</div>
|
||||
<el-page-header v-else @back="$router.back()" content="推送管理" style="margin-bottom:24px" />
|
||||
<el-empty v-if="isServicesPortal && !appId" description="请选择一个应用" style="margin-top:80px" />
|
||||
<el-empty v-if="isServicesPortal && !appKey" description="请选择一个应用" style="margin-top:80px" />
|
||||
|
||||
<template v-if="!isServicesPortal || appId">
|
||||
<template v-if="!isServicesPortal || appKey">
|
||||
<el-card style="margin-bottom:16px">
|
||||
<template #header>用户设备状态查询</template>
|
||||
<el-form inline @submit.prevent="queryUser">
|
||||
@ -156,7 +156,7 @@ import { pushAdminApi, type DeviceLoginLog, type TestPushResult, type UserPushSt
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const appId = route.params.appId as string
|
||||
const appKey = route.params.appKey as string
|
||||
const isServicesPortal = computed(() => route.path.startsWith('/services/'))
|
||||
const portalApps = ref<App[]>([])
|
||||
|
||||
@ -192,7 +192,7 @@ async function queryUser() {
|
||||
querying.value = true
|
||||
testResult.value = null
|
||||
try {
|
||||
const res = await pushAdminApi.getUserStatus(appId, uid)
|
||||
const res = await pushAdminApi.getUserStatus(appKey, uid)
|
||||
userStatus.value = res.data.data
|
||||
logsUserId.value = uid
|
||||
logsPage.value = 1
|
||||
@ -210,7 +210,7 @@ async function sendTestPush() {
|
||||
testResult.value = null
|
||||
try {
|
||||
const res = await pushAdminApi.testOffline(
|
||||
appId,
|
||||
appKey,
|
||||
userStatus.value.userId,
|
||||
testForm.title,
|
||||
testForm.body,
|
||||
@ -229,7 +229,7 @@ async function loadLogs() {
|
||||
if (!uid) return
|
||||
logsLoading.value = true
|
||||
try {
|
||||
const res = await pushAdminApi.getDeviceLogs(appId, uid, logsPage.value - 1, logsPageSize)
|
||||
const res = await pushAdminApi.getDeviceLogs(appKey, uid, logsPage.value - 1, logsPageSize)
|
||||
const d = res.data.data
|
||||
logs.value = d.content
|
||||
logsTotal.value = d.total
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="store-guide-page">
|
||||
<el-page-header @back="$router.back()" :content="`应用配置指引 — ${appId}`" />
|
||||
<el-page-header @back="$router.back()" :content="`应用配置指引 — ${appKey}`" />
|
||||
|
||||
<el-alert
|
||||
title="这里是应用商店配置的独立指引页。建议先完成凭据配置和市场跳转页,再回到版本管理页提交审核。Harmony 应用仅跳转应用市场,不做本地安装。"
|
||||
@ -72,7 +72,7 @@ import vivoGuideImage from '@/assets/update-store/vivo/01.png'
|
||||
import honorGuideImage from '@/assets/update-store/honor/01.png'
|
||||
|
||||
const route = useRoute()
|
||||
const appId = route.params.appId as string
|
||||
const appKey = route.params.appKey as string
|
||||
|
||||
interface StoreGuide {
|
||||
type: string
|
||||
|
||||
@ -2,14 +2,14 @@
|
||||
<div>
|
||||
<div v-if="isServicesPortal" class="portal-bar">
|
||||
<span class="portal-bar-title">版本管理</span>
|
||||
<el-select :model-value="appId" placeholder="选择应用" style="width:220px" @change="switchApp">
|
||||
<el-select :model-value="appKey" placeholder="选择应用" style="width:220px" @change="switchApp">
|
||||
<el-option v-for="a in portalApps" :key="a.id" :label="a.name" :value="a.id" />
|
||||
</el-select>
|
||||
</div>
|
||||
<el-page-header v-else @back="$router.back()" :content="`版本管理 — ${pageTitle}`" style="margin-bottom:20px" />
|
||||
<el-empty v-if="isServicesPortal && !appId" description="请选择一个应用" style="margin-top:80px" />
|
||||
<el-empty v-if="isServicesPortal && !appKey" description="请选择一个应用" style="margin-top:80px" />
|
||||
|
||||
<template v-if="!isServicesPortal || appId">
|
||||
<template v-if="!isServicesPortal || appKey">
|
||||
<el-card>
|
||||
<el-tabs v-model="activeTab">
|
||||
<!-- App Versions -->
|
||||
@ -649,11 +649,11 @@ import honorGuideImage from '@/assets/update-store/honor/01.png'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const appId = route.params.appId as string
|
||||
const appKey = route.params.appKey as string
|
||||
const isServicesPortal = computed(() => route.path.startsWith('/services/'))
|
||||
const portalApps = ref<App[]>([])
|
||||
const app = ref<App | null>(null)
|
||||
const pageTitle = computed(() => app.value?.name ?? appId)
|
||||
const pageTitle = computed(() => app.value?.name ?? appKey)
|
||||
const isMobile = ref(false)
|
||||
const dialogWidth = computed(() => (isMobile.value ? 'calc(100vw - 24px)' : '920px'))
|
||||
|
||||
@ -691,7 +691,7 @@ const rnInspectUploadProgress = ref(0)
|
||||
const rnBundleUploadProgress = ref(0)
|
||||
const operationLogs = ref<{
|
||||
id: string
|
||||
appId: string
|
||||
appKey: string
|
||||
resourceType: string
|
||||
resourceId: string
|
||||
action: string
|
||||
@ -762,7 +762,7 @@ const STORE_DEFS: StoreDef[] = [
|
||||
{ title: '打开自动发布接口', description: '下载公钥文件并准备私钥。' },
|
||||
{ title: '录入用户名和私钥', description: '这里保存的是服务端上传所需凭据。' },
|
||||
],
|
||||
jumpLinkHint: '小米应用商店详情页可从应用的商店公开链接或发布页面复制,通常包含 appId 或 package 信息。',
|
||||
jumpLinkHint: '小米应用商店详情页可从应用的商店公开链接或发布页面复制,通常包含 appKey 或 package 信息。',
|
||||
guideHint: '当前字段为 username / publicKey / privateKey,与后端服务一致。',
|
||||
guideImage: miGuideImage,
|
||||
},
|
||||
@ -918,7 +918,7 @@ async function toggleStore(type: StoreType, enabled: boolean) {
|
||||
const cfg = getStoreConfig(type)
|
||||
if (!cfg) return
|
||||
try {
|
||||
await updateAdminApi.saveStoreConfig(appId, type, cfg.configJson ?? '{}', enabled)
|
||||
await updateAdminApi.saveStoreConfig(appKey, type, cfg.configJson ?? '{}', enabled)
|
||||
await loadStoreConfigs()
|
||||
} catch {
|
||||
ElMessage.error('操作失败')
|
||||
@ -927,7 +927,7 @@ async function toggleStore(type: StoreType, enabled: boolean) {
|
||||
|
||||
async function loadStoreConfigs() {
|
||||
try {
|
||||
const res = await updateAdminApi.getStoreConfigs(appId)
|
||||
const res = await updateAdminApi.getStoreConfigs(appKey)
|
||||
storeConfigs.value = res.data.data
|
||||
} catch {
|
||||
storeConfigs.value = []
|
||||
@ -939,7 +939,7 @@ function switchApp(val: string) {
|
||||
}
|
||||
|
||||
async function loadApp() {
|
||||
const res = await appApi.get(appId)
|
||||
const res = await appApi.get(appKey)
|
||||
app.value = res.data.data
|
||||
}
|
||||
|
||||
@ -978,7 +978,7 @@ async function saveStoreConfig() {
|
||||
savingStoreConfig.value = true
|
||||
try {
|
||||
await updateAdminApi.saveStoreConfig(
|
||||
appId,
|
||||
appKey,
|
||||
currentStoreDef.value.type,
|
||||
JSON.stringify(storeConfigForm.value.values),
|
||||
storeConfigForm.value.enabled,
|
||||
@ -996,7 +996,7 @@ async function saveStoreConfig() {
|
||||
async function removeStoreConfig(type: StoreType) {
|
||||
await ElMessageBox.confirm('确认删除此应用商店凭据?', '提示', { type: 'warning' })
|
||||
try {
|
||||
await updateAdminApi.deleteStoreConfig(appId, type)
|
||||
await updateAdminApi.deleteStoreConfig(appKey, type)
|
||||
ElMessage.success('已删除')
|
||||
await loadStoreConfigs()
|
||||
} catch {
|
||||
@ -1036,7 +1036,7 @@ function parsePublishConfig(config?: string | null) {
|
||||
async function loadPublishConfig() {
|
||||
loadingPublishConfig.value = true
|
||||
try {
|
||||
const res = await updateAdminApi.getPublishConfig(appId)
|
||||
const res = await updateAdminApi.getPublishConfig(appKey)
|
||||
publishConfigForm.value = parsePublishConfig(res.data.data.configJson)
|
||||
if (publishConfigForm.value.grayMode === 'MEMBERS' && !hasAnyGrayCallback.value) {
|
||||
publishConfigForm.value.grayMode = 'PERCENT'
|
||||
@ -1068,7 +1068,7 @@ async function savePublishConfig() {
|
||||
if (payload.grayMode === 'MEMBERS' && !hasGrayDirectorySyncCallback.value) {
|
||||
payload.graySelectionSource = 'CALLBACK'
|
||||
}
|
||||
await updateAdminApi.savePublishConfig(appId, payload)
|
||||
await updateAdminApi.savePublishConfig(appKey, payload)
|
||||
ElMessage.success('发布配置已保存')
|
||||
} catch {
|
||||
ElMessage.error('保存失败')
|
||||
@ -1155,7 +1155,7 @@ async function loadGrayMembers() {
|
||||
if (!showGray.value || !hasGrayDirectorySyncCallback.value) return
|
||||
loadingGrayMembers.value = true
|
||||
try {
|
||||
const res = await updateAdminApi.listGrayMembers(appId, grayMemberKeyword.value || undefined, grayMemberGroupFilter.value || undefined)
|
||||
const res = await updateAdminApi.listGrayMembers(appKey, grayMemberKeyword.value || undefined, grayMemberGroupFilter.value || undefined)
|
||||
grayMembers.value = res.data.data
|
||||
} catch {
|
||||
grayMembers.value = []
|
||||
@ -1171,7 +1171,7 @@ async function syncGrayMembers() {
|
||||
}
|
||||
loadingGrayMembers.value = true
|
||||
try {
|
||||
const res = await updateAdminApi.syncGrayMembers(appId)
|
||||
const res = await updateAdminApi.syncGrayMembers(appKey)
|
||||
grayMembers.value = res.data.data
|
||||
ElMessage.success('成员已同步')
|
||||
} catch {
|
||||
@ -1345,7 +1345,7 @@ async function submitAppUpload() {
|
||||
appVersionUploadProgress.value = 0
|
||||
try {
|
||||
const fd = new FormData()
|
||||
fd.append('appId', appId)
|
||||
fd.append('appKey', appKey)
|
||||
fd.append('platform', f.platform)
|
||||
fd.append('versionName', f.versionName)
|
||||
fd.append('versionCode', String(f.versionCode))
|
||||
@ -1439,7 +1439,7 @@ async function submitRnUpload() {
|
||||
rnBundleUploadProgress.value = 0
|
||||
try {
|
||||
const fd = new FormData()
|
||||
fd.append('appId', appId)
|
||||
fd.append('appKey', appKey)
|
||||
fd.append('moduleId', f.moduleId)
|
||||
fd.append('platform', f.platform)
|
||||
fd.append('version', f.version)
|
||||
@ -1463,7 +1463,7 @@ async function submitRnUpload() {
|
||||
async function loadAppVersions() {
|
||||
loadingApp.value = true
|
||||
try {
|
||||
const res = await updateAdminApi.listAppVersions(appId, appPlatform.value)
|
||||
const res = await updateAdminApi.listAppVersions(appKey, appPlatform.value)
|
||||
appVersions.value = res.data.data
|
||||
} catch {
|
||||
ElMessage.error('加载失败')
|
||||
@ -1475,7 +1475,7 @@ async function loadAppVersions() {
|
||||
async function loadRnBundles() {
|
||||
loadingRn.value = true
|
||||
try {
|
||||
const res = await updateAdminApi.listRnBundles(appId, rnModuleFilter.value || undefined, rnPlatform.value || undefined)
|
||||
const res = await updateAdminApi.listRnBundles(appKey, rnModuleFilter.value || undefined, rnPlatform.value || undefined)
|
||||
rnBundles.value = res.data.data
|
||||
} catch {
|
||||
ElMessage.error('加载失败')
|
||||
@ -1654,7 +1654,7 @@ function updateViewport() {
|
||||
async function loadOperationLogs() {
|
||||
loadingOperationLogs.value = true
|
||||
try {
|
||||
const res = await updateAdminApi.listOperationLogs(appId, 100)
|
||||
const res = await updateAdminApi.listOperationLogs(appKey, 100)
|
||||
operationLogs.value = res.data.data
|
||||
} catch {
|
||||
operationLogs.value = []
|
||||
@ -1718,7 +1718,7 @@ onMounted(() => {
|
||||
window.addEventListener('resize', updateViewport)
|
||||
if (isServicesPortal.value) {
|
||||
appApi.list().then(res => { portalApps.value = res.data.data })
|
||||
if (!appId) return
|
||||
if (!appKey) return
|
||||
}
|
||||
loadApp()
|
||||
loadAppVersions()
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户