feat(security-center): add license file parser

- SecurityCenterView: add license file upload/parse card with ElUpload and ElDescriptions
- appApi: add parseLicenseFile() calling POST /api/apps/license/parse

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-05-22 18:38:17 +08:00
父节点 655c5bc598
当前提交 a8db0519ae
共有 2 个文件被更改,包括 90 次插入0 次删除

查看文件

@ -203,4 +203,10 @@ export const appApi = {
client.post<{ data: null }>(`/apps/${appKey}/services/request-activation`, null, {
params: { platform: 'ANDROID', serviceType, applyReason: reason },
}),
parseLicenseFile: (content: string) =>
client.post<{ data: { appKey: string; appName: string; packageName: string; iosBundleId: string; harmonyBundleName: string; baseUrl: string; serverUrl: string } }>(
'/apps/license/parse',
{ content },
),
}

查看文件

@ -67,6 +67,43 @@
</el-descriptions>
</el-card>
<!-- License 文件解析 -->
<el-card style="margin-bottom: 16px">
<template #header>License 文件解析</template>
<p style="color: #606266; margin: 0 0 16px;">
上传已下载的 License 文件.xuqmlicense解析并验证文件内容
</p>
<el-input
v-model="licenseFileContent"
type="textarea"
:rows="4"
placeholder="将 License 文件内容粘贴到此处,或点击上传文件"
style="margin-bottom: 12px"
/>
<div style="display: flex; gap: 12px; flex-wrap: wrap; align-items: center;">
<el-upload
ref="licenseUploadRef"
action="#"
:auto-upload="false"
:on-change="handleLicenseFileChange"
:show-file-list="false"
accept=".xuqmlicense"
>
<el-button type="primary" plain>选择 License 文件</el-button>
</el-upload>
<el-button :loading="parsingLicense" @click="parseLicense">解析</el-button>
<el-button v-if="licenseParseResult" @click="clearLicenseParse">清除</el-button>
</div>
<el-descriptions v-if="licenseParseResult" :column="isMobile ? 1 : 2" border style="margin-top: 16px">
<el-descriptions-item label="AppKey">{{ licenseParseResult.appKey }}</el-descriptions-item>
<el-descriptions-item label="应用名称">{{ licenseParseResult.appName || '-' }}</el-descriptions-item>
<el-descriptions-item label="Android 包名">{{ licenseParseResult.packageName || '-' }}</el-descriptions-item>
<el-descriptions-item label="iOS BundleId">{{ licenseParseResult.iosBundleId || '-' }}</el-descriptions-item>
<el-descriptions-item label="鸿蒙 BundleName">{{ licenseParseResult.harmonyBundleName || '-' }}</el-descriptions-item>
<el-descriptions-item label="服务地址">{{ licenseParseResult.serverUrl || licenseParseResult.baseUrl || '-' }}</el-descriptions-item>
</el-descriptions>
</el-card>
<el-card>
<template #header>应用密钥管理</template>
<el-table :data="apps" v-loading="loading" border stripe>
@ -241,6 +278,53 @@ const selectedApp = ref<App | null>(null)
const dialogMode = ref<'REVEAL_SECRET' | 'RESET_SECRET'>('REVEAL_SECRET')
const secretResult = ref('')
// License file parse
const licenseFileContent = ref('')
const parsingLicense = ref(false)
const licenseParseResult = ref<{
appKey: string
appName: string
packageName: string
iosBundleId: string
harmonyBundleName: string
baseUrl: string
serverUrl: string
} | null>(null)
const licenseUploadRef = ref<any>(null)
function handleLicenseFileChange(file: any) {
const reader = new FileReader()
reader.onload = (e) => {
licenseFileContent.value = (e.target?.result as string) || ''
}
reader.readAsText(file.raw)
}
async function parseLicense() {
if (!licenseFileContent.value.trim()) {
ElMessage.warning('请输入或上传 License 文件内容')
return
}
parsingLicense.value = true
try {
const res = await appApi.parseLicenseFile(licenseFileContent.value.trim())
licenseParseResult.value = res.data.data
ElMessage.success('解析成功')
} catch (e: any) {
ElMessage.error(e?.response?.data?.message || '解析失败,请检查文件内容')
} finally {
parsingLicense.value = false
}
}
function clearLicenseParse() {
licenseFileContent.value = ''
licenseParseResult.value = null
if (licenseUploadRef.value) {
licenseUploadRef.value.clearFiles()
}
}
async function loadData() {
loading.value = true
try {