refactor(app): 将许可证文件功能替换为配置文件功能

- 替换 LicenseFileCrypto 为 ConfigFileCrypto 加密类
- 将 /license-file 相关接口重命名为 /config-file
- 修改数据库实体中的 licenseFileContent 字段为 configFileContent
- 更新前端 API 调用从 downloadLicenseFile 改为 downloadConfigFile
- 将安全中心的 License 文件解析功能改为 Config 文件解析
- 更新文件扩展名从 .xuqmlicense 改为 .xuqmconfig
- 修改后端服务方法 ensureLicenseFile 为 ensureConfigFile
- 调整加密解密逻辑以支持新的配置文件格式
这个提交包含在:
XuqmGroup 2026-06-02 17:35:29 +08:00
父节点 62966dcf20
当前提交 348c04ba72
共有 3 个文件被更改,包括 46 次插入46 次删除

查看文件

@ -196,17 +196,17 @@ export const appApi = {
resetSecret: (appKey: string, code: string) =>
client.post<{ data: { appSecret: string } }>(`/apps/${appKey}/reset-secret`, { code }),
downloadLicenseFile: (appKey: string) =>
client.get<Blob>(`/apps/${appKey}/license-file`, { responseType: 'blob' }),
downloadConfigFile: (appKey: string) =>
client.get<Blob>(`/apps/${appKey}/config-file`, { responseType: 'blob' }),
requestActivation: (appKey: string, serviceType: 'IM' | 'PUSH' | 'UPDATE' | 'LICENSE', reason: string) =>
client.post<{ data: null }>(`/apps/${appKey}/services/request-activation`, null, {
params: { platform: 'ANDROID', serviceType, applyReason: reason },
}),
parseLicenseFile: (content: string) =>
parseConfigFile: (content: string) =>
client.post<{ data: { appKey: string; appName: string; packageName: string; iosBundleId: string; harmonyBundleName: string; baseUrl: string; serverUrl: string } }>(
'/apps/license/parse',
'/apps/config/parse',
{ content },
),
}

查看文件

@ -23,8 +23,8 @@
<el-button link type="warning" @click="openVerifyDialog('RESET_SECRET')">重置</el-button>
</el-descriptions-item>
<el-descriptions-item label="简述" :span="2">{{ app.description ?? '-' }}</el-descriptions-item>
<el-descriptions-item label="License 文件">
<el-button size="small" type="primary" plain @click="downloadLicenseFile">下载</el-button>
<el-descriptions-item label="Config 文件">
<el-button size="small" type="primary" plain @click="downloadConfigFile">下载</el-button>
</el-descriptions-item>
</el-descriptions>
</el-card>
@ -353,12 +353,12 @@ async function submitVerify() {
}
}
async function downloadLicenseFile() {
async function downloadConfigFile() {
const current = app.value
if (!current) return
const res = await appApi.downloadLicenseFile(current.appKey)
const res = await appApi.downloadConfigFile(current.appKey)
const disposition = res.headers['content-disposition'] as string | undefined
const filename = parseFilename(disposition) ?? `${current.name || current.appKey}.xuqmlicense`
const filename = parseFilename(disposition) ?? `${current.name || current.appKey}.xuqmconfig`
const url = URL.createObjectURL(res.data)
const link = document.createElement('a')
link.href = url

查看文件

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