feat(sdk): 添加鸿蒙SDK核心功能模块

- 实现SDKContext用于配置管理和数据持久化存储
- 定义完整的类型系统包括消息、用户、群组等接口
- 集成更新SDK支持原生应用和RN热更新检查
- 提供统一的XuqmSDK入口类和模块导出
- 编写详细的开发文档和使用示例
这个提交包含在:
XuqmGroup 2026-04-29 19:08:13 +08:00
父节点 470521c3a8
当前提交 e47f510a0b
共有 6 个文件被更改,包括 799 次插入414 次删除

查看文件

@ -15,6 +15,8 @@ declare module 'vue' {
ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElCol: typeof import('element-plus/es')['ElCol'] ElCol: typeof import('element-plus/es')['ElCol']
ElCollapse: typeof import('element-plus/es')['ElCollapse']
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
ElContainer: typeof import('element-plus/es')['ElContainer'] ElContainer: typeof import('element-plus/es')['ElContainer']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
@ -29,6 +31,7 @@ declare module 'vue' {
ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElHeader: typeof import('element-plus/es')['ElHeader'] ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon'] ElIcon: typeof import('element-plus/es')['ElIcon']
ElImage: typeof import('element-plus/es')['ElImage']
ElInput: typeof import('element-plus/es')['ElInput'] ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElLink: typeof import('element-plus/es')['ElLink'] ElLink: typeof import('element-plus/es')['ElLink']

查看文件

@ -39,8 +39,31 @@ updateClient.interceptors.request.use((config) => {
return config return config
}) })
export type StoreType = 'HUAWEI' | 'MI' | 'OPPO' | 'VIVO' | 'HONOR' | 'APP_STORE' | 'GOOGLE_PLAY' export type StoreType = 'HUAWEI' | 'MI' | 'OPPO' | 'VIVO' | 'HONOR' | 'APP_STORE' | 'GOOGLE_PLAY' | 'HARMONY_APP' | 'REVIEW_WEBHOOK'
export type StoreReviewState = 'PENDING' | 'UNDER_REVIEW' | 'APPROVED' | 'REJECTED' export type StoreReviewState = 'PENDING' | 'UNDER_REVIEW' | 'APPROVED' | 'REJECTED'
export type PublishMode = 'MANUAL' | 'NOW' | 'SCHEDULED' | 'AUTO_REVIEW'
export type GrayMode = 'PERCENT' | 'MEMBERS'
export type GraySelectionSource = 'LOCAL' | 'CALLBACK'
export interface PublishConfig {
id: string
appId: string
configJson?: string
updatedAt: string
}
export interface GrayMember {
userId: string
name?: string
groupName?: string
extraJson?: string
updatedAt?: string
}
export interface GrayMemberGroup {
groupName: string
members: GrayMember[]
}
export interface StoreConfig { export interface StoreConfig {
id: string id: string
@ -71,6 +94,10 @@ export interface AppVersion {
webhookUrl?: string webhookUrl?: string
storeSubmitTargets?: string storeSubmitTargets?: string
storeReviewStatus?: string storeReviewStatus?: string
storeSubmitMode?: PublishMode
storeSubmitScheduledAt?: string
grayMode?: GrayMode
grayMemberIds?: string
createdAt: string createdAt: string
} }
@ -94,8 +121,12 @@ export interface RnBundle {
packageName?: string packageName?: string
note?: string note?: string
publishStatus: 'DRAFT' | 'PUBLISHED' | 'DEPRECATED' publishStatus: 'DRAFT' | 'PUBLISHED' | 'DEPRECATED'
publishMode?: PublishMode
scheduledPublishAt?: string
grayEnabled: boolean grayEnabled: boolean
grayPercent: number grayPercent: number
grayMode?: GrayMode
grayMemberIds?: string
createdAt: string createdAt: string
} }
@ -144,16 +175,22 @@ export const updateAdminApi = {
}) })
}, },
publishAppVersion(id: string) { publishAppVersion(id: string, body?: { publishImmediately?: boolean; scheduledPublishAt?: string; forceUpdate?: boolean }) {
return updateClient.post(`/api/v1/updates/app/${id}/publish`) return updateClient.post(`/api/v1/updates/app/${id}/publish`, body ?? {})
}, },
unpublishAppVersion(id: string) { unpublishAppVersion(id: string) {
return updateClient.post(`/api/v1/updates/app/${id}/unpublish`) return updateClient.post(`/api/v1/updates/app/${id}/unpublish`)
}, },
grayAppVersion(id: string, enabled: boolean, percent: number) { grayAppVersion(id: string, body: {
return updateClient.post(`/api/v1/updates/app/${id}/gray`, { enabled, percent }) enabled: boolean
grayMode: GrayMode
percent?: number
memberIds?: string[]
selectionSource?: GraySelectionSource
}) {
return updateClient.post(`/api/v1/updates/app/${id}/gray`, body)
}, },
uploadAppVersion(formData: FormData) { uploadAppVersion(formData: FormData) {
@ -172,16 +209,22 @@ export const updateAdminApi = {
}) })
}, },
publishRnBundle(id: string) { publishRnBundle(id: string, body?: { publishImmediately?: boolean; scheduledPublishAt?: string }) {
return updateClient.post(`/api/v1/rn/${id}/publish`) return updateClient.post(`/api/v1/rn/${id}/publish`, body ?? {})
}, },
unpublishRnBundle(id: string) { unpublishRnBundle(id: string) {
return updateClient.post(`/api/v1/rn/${id}/unpublish`) return updateClient.post(`/api/v1/rn/${id}/unpublish`)
}, },
grayRnBundle(id: string, enabled: boolean, percent: number) { grayRnBundle(id: string, body: {
return updateClient.post(`/api/v1/rn/${id}/gray`, { enabled, percent }) enabled: boolean
grayMode: GrayMode
percent?: number
memberIds?: string[]
selectionSource?: GraySelectionSource
}) {
return updateClient.post(`/api/v1/rn/${id}/gray`, body)
}, },
uploadRnBundle(formData: FormData) { uploadRnBundle(formData: FormData) {
@ -214,10 +257,16 @@ export const updateAdminApi = {
return updateClient.delete(`/api/v1/updates/store/configs/${storeType}`, { params: { appId } }) return updateClient.delete(`/api/v1/updates/store/configs/${storeType}`, { params: { appId } })
}, },
executeSubmitToStores(versionId: string, storeTypes: StoreType[]) { executeSubmitToStores(
versionId: string,
storeTypes: StoreType[],
submitMode: PublishMode = 'MANUAL',
scheduledPublishAt?: string,
autoPublishAfterReview = false,
) {
return updateClient.post<{ data: AppVersion }>( return updateClient.post<{ data: AppVersion }>(
`/api/v1/updates/store/app/${versionId}/execute-submit`, `/api/v1/updates/store/app/${versionId}/execute-submit`,
{ storeTypes }, { storeTypes, submitMode, scheduledPublishAt, autoPublishAfterReview },
) )
}, },
@ -227,4 +276,24 @@ export const updateAdminApi = {
{ storeType, state }, { storeType, state },
) )
}, },
getPublishConfig(appId: string) {
return updateClient.get<{ data: PublishConfig }>('/api/v1/updates/publish/config', { params: { appId } })
},
savePublishConfig(appId: string, config: Record<string, unknown>) {
return updateClient.put<{ data: PublishConfig }>('/api/v1/updates/publish/config', config, { params: { appId } })
},
listGrayMembers(appId: string, keyword?: string, groupName?: string) {
return updateClient.get<{ data: GrayMemberGroup[] }>('/api/v1/updates/gray/members', {
params: { appId, ...(keyword && { keyword }), ...(groupName && { groupName }) },
})
},
syncGrayMembers(appId: string) {
return updateClient.post<{ data: GrayMemberGroup[] }>('/api/v1/updates/gray/members/sync', null, {
params: { appId },
})
},
} }

查看文件

@ -53,10 +53,6 @@ const router = createRouter({
path: 'apps/:appId/update', path: 'apps/:appId/update',
component: () => import('@/views/update/VersionManagementView.vue'), component: () => import('@/views/update/VersionManagementView.vue'),
}, },
{
path: 'apps/:appId/update-guide',
component: () => import('@/views/update/StoreGuideView.vue'),
},
{ {
path: 'accounts', path: 'accounts',
component: () => import('@/views/accounts/SubAccountView.vue'), component: () => import('@/views/accounts/SubAccountView.vue'),

查看文件

@ -74,7 +74,7 @@
</el-tag> </el-tag>
<span class="service-status-text"> <span class="service-status-text">
{{ svcType === 'UPDATE' {{ svcType === 'UPDATE'
? 'Android / iOS / 鸿蒙版本在版本管理页内分别配置。' ? 'Android 整包版本在版本管理页上传;iOS / 鸿蒙仅记录版本号和市场跳转页。商店配置与发布配置都在版本管理页。'
: '推送服务开通后即可在终端接收设备级推送。' }} : '推送服务开通后即可在终端接收设备级推送。' }}
</span> </span>
</div> </div>
@ -169,7 +169,7 @@ function serviceHelp(type: string) {
return { return {
IM: 'IM 服务独立开通后,在管理页配置回调和消息能力。', IM: 'IM 服务独立开通后,在管理页配置回调和消息能力。',
PUSH: '一次开通后,推送配置在服务管理页按平台维护。', PUSH: '一次开通后,推送配置在服务管理页按平台维护。',
UPDATE: '一次开通后,版本管理页按平台维护版本和发布。', UPDATE: '一次开通后,版本管理页只管理 Android 整包版本,iOS / 鸿蒙仅记录提醒信息。',
}[type] ?? '' }[type] ?? ''
} }

查看文件

@ -3,7 +3,7 @@
<el-page-header @back="$router.back()" :content="`应用配置指引 — ${appId}`" /> <el-page-header @back="$router.back()" :content="`应用配置指引 — ${appId}`" />
<el-alert <el-alert
title="这里是应用商店配置的独立指引页。建议先完成凭据配置,再回到版本管理页提交审核。Harmony 应用仅跳转应用市场,不做本地安装。" title="这里是应用商店配置的独立指引页。建议先完成凭据配置和市场跳转页,再回到版本管理页提交审核。Harmony 应用仅跳转应用市场,不做本地安装。"
type="info" type="info"
show-icon show-icon
:closable="false" :closable="false"
@ -117,6 +117,20 @@ const STORE_GUIDES = [
image: honorGuideImage, image: honorGuideImage,
enabled: true, enabled: true,
}, },
{
type: 'HARMONY_APP',
label: '鸿蒙应用',
subtitle: '鸿蒙应用市场独立跳转页',
url: 'https://developer.huawei.com/consumer/cn/',
urlLabel: '查看鸿蒙官方文档',
steps: [
{ title: '确认鸿蒙应用页', description: '准备独立的鸿蒙应用市场详情页。' },
{ title: '复制跳转链接', description: '把市场详情页链接填写到应用商店配置。' },
{ title: '回到版本管理页', description: '鸿蒙版本仅记录版本号和跳转页。' },
],
hint: '鸿蒙应用配置只维护市场跳转页,不参与 Android 审核上传。',
enabled: true,
},
{ {
type: 'APP_STORE', type: 'APP_STORE',
label: 'Apple App Store', label: 'Apple App Store',