This commit is contained in:
2026-11-03 17:15:03 +08:00
parent 1afc7034cd
commit 01d0a81603
4 changed files with 50 additions and 16 deletions
+3 -2
View File
@@ -53,10 +53,10 @@ describe('adminNavigation', () => {
{ title: '财务管理', children: ['海外费用明细', '客户账户', '客户应收应付', '应收款统计表', '客户对账单', '结算单应收', '结算单应付'] },
{ title: '海外仓', children: ['经营总览', '销量分析', '库存分析', '数据采集'] },
{ title: '通用', children: ['费用项目', '汇率管理', '仓库管理', '海外仓报价', '车队报价', '船期价格表', '下载中心', '供应商列表'] },
{ title: '系统管理', children: ['用户管理', '角色权限', '菜单权限'] },
{ title: '系统管理', children: ['用户管理', '角色权限', '菜单权限', 'PDA版本'] },
])
expect(visible).toHaveLength(13)
expect(visible.flatMap(node => node.children ?? [])).toHaveLength(60)
expect(visible.flatMap(node => node.children ?? [])).toHaveLength(61)
expect(adminNavigation.find((item) => item.key === 'notifications')).toBeUndefined()
})
@@ -172,6 +172,7 @@ describe('adminNavigation', () => {
const paths = getNavigationLeaves(filtered).map((item) => item.path)
expect(paths).toContain('/system/permissions')
expect(paths).not.toContain('/prototype/finance/profit-report')
expect(paths).not.toContain('/system/pda-releases')
expect(paths).not.toContain('/notifications/messages')
expect(paths).not.toContain('/customers')
expect(filtered.map((item) => item.title)).toEqual(['首页数据看板', '系统管理'])
+1 -1
View File
@@ -223,7 +223,7 @@ export const adminNavigation: AdminNavigationNode[] = [
{ key: 'tenant-management', title: '租户管理', icon: Building2, path: '/prototype/system-management/tenant-management', hidden: true },
{ key: 'brand-settings', title: '品牌设置', icon: Settings, path: '/prototype/system-management/brand-settings', hidden: true },
{ key: 'permissions', title: '菜单权限', icon: KeyRound, path: '/system/permissions', permission: 'platform:permission:list' },
{ key: 'pda-releases', title: 'PDA版本', icon: Download, path: '/system/pda-releases', permission: 'platform:pda-release:list', hidden: true },
{ key: 'pda-releases', title: 'PDA版本', icon: Download, path: '/system/pda-releases', permission: 'platform:pda-release:list' },
],
},
]
@@ -3,7 +3,7 @@ import '@/styles/adminWorkbench.css'
import '@/styles/adminDensity.css'
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, RefreshCw } from '@lucide/vue'
import { FileUp, Plus, RefreshCw } from '@lucide/vue'
import AdminPage from '@/shared/components/AdminPage.vue'
import AppDialog from '@/shared/components/AppDialog.vue'
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'
@@ -24,6 +24,7 @@ const error = ref('')
const actionId = ref('')
const uploadOpen = ref(false)
const uploading = ref(false)
const fileInput = ref<HTMLInputElement | null>(null)
const form = reactive({ packageType: 'wgt' as PdaPackageType, versionName: '', versionCode: 1,
minAppVersionCode: 1, mandatory: false, releaseNotes: '', file: null as File | null })
const columns: DataTableColumn[] = [
@@ -60,11 +61,13 @@ async function load() {
}
watch(app, () => { rows.value = []; void load() })
watch(() => form.packageType, () => { form.file = null })
onMounted(() => { void load() })
function openUpload() {
Object.assign(form, { packageType: 'wgt', versionName: '', versionCode: currentApk.value?.versionCode ?? 1,
minAppVersionCode: currentApk.value?.versionCode ?? 1, mandatory: false, releaseNotes: '', file: null })
if (fileInput.value) fileInput.value.value = ''
uploadOpen.value = true
}
@@ -159,19 +162,27 @@ function download(row: PdaRelease) {
</DataTable></div>
</ListPageLayout>
<AppDialog v-model="uploadOpen" class="admin-density-dialog admin-workbench is-dialog" title="上传PDA版本" width="min(640px, calc(100vw - 28px))" confirm-text="保存草稿" :confirm-loading="uploading" @confirm="upload">
<el-form label-position="top" class="pda-release-form">
<el-form-item label="包类型">
<el-radio-group v-model="form.packageType"><el-radio-button value="apk">APK 整包</el-radio-button><el-radio-button value="wgt">WGT 热更新</el-radio-button></el-radio-group>
</el-form-item>
<div class="pda-release-fields">
<el-form-item label="版本号"><el-input v-model.trim="form.versionName" placeholder="例如 0.0.4" /></el-form-item>
<el-form-item label="APK版本码"><el-input-number v-model="form.versionCode" :min="1" :controls="false" placeholder="请输入APK版本码" /></el-form-item>
<el-form-item label="最低兼容APK版本码"><el-input-number v-model="form.minAppVersionCode" :min="1" :controls="false" placeholder="请输入最低兼容APK版本码" /></el-form-item>
<AppDialog v-model="uploadOpen" class="admin-density-dialog admin-workbench is-dialog" :title="`上传${app === 'overseas' ? '海外' : '国内'}PDA版本`" width="min(640px, calc(100vw - 28px))" confirm-text="保存草稿" :confirm-loading="uploading" @confirm="upload">
<el-form label-position="top" class="pda-release-form density-form density-form--outlined density-form--flush-end" :disabled="uploading">
<div class="pda-release-options">
<el-form-item label="包类型">
<el-radio-group v-model="form.packageType"><el-radio-button value="apk">APK 整包</el-radio-button><el-radio-button value="wgt">WGT 热更新</el-radio-button></el-radio-group>
</el-form-item>
<el-form-item label="强制更新"><el-switch v-model="form.mandatory" /></el-form-item>
</div>
<div class="pda-release-fields">
<el-form-item label="版本号"><el-input v-model.trim="form.versionName" placeholder="例如 0.0.4" /></el-form-item>
<el-form-item label="APK版本码"><el-input-number v-model="form.versionCode" :min="1" :controls="false" align="left" placeholder="版本码" /></el-form-item>
<el-form-item label="最低兼容APK版本码"><el-input-number v-model="form.minAppVersionCode" :min="1" :controls="false" align="left" placeholder="最低版本码" /></el-form-item>
</div>
<el-form-item label="更新说明"><el-input v-model="form.releaseNotes" type="textarea" :rows="3" maxlength="1000" show-word-limit placeholder="请输入更新说明" /></el-form-item>
<el-form-item :label="`选择 ${form.packageType.toUpperCase()} 文件(最大200MB)`"><input :key="form.packageType" type="file" :accept="`.${form.packageType}`" @change="selectFile" /></el-form-item>
<el-form-item label="更新包(最大200MB)">
<input :key="form.packageType" ref="fileInput" class="pda-release-file-input" type="file" :accept="`.${form.packageType}`" :aria-label="`选择 ${form.packageType.toUpperCase()} 更新包`" tabindex="-1" :disabled="uploading" @change="selectFile" />
<div class="pda-release-file-control">
<el-button :icon="FileUp" :disabled="uploading" @click="fileInput?.click()">选择 {{ form.packageType.toUpperCase() }} 文件</el-button>
<div class="pda-release-file-meta"><span class="pda-release-file-name">{{ form.file?.name || '未选择文件' }}</span><span v-if="form.file" class="pda-release-file-size">{{ (form.file.size / 1024 / 1024).toFixed(2) }} MB</span></div>
</div>
</el-form-item>
</el-form>
</AppDialog>
</AdminPage>
@@ -187,7 +198,14 @@ function download(row: PdaRelease) {
.pda-release-current dd { margin: 0; color: var(--workbench-text); font-size: var(--admin-font-body); font-variant-numeric: tabular-nums; }
.pda-release-actions { display: flex; align-items: center; gap: var(--admin-space-2); }
.pda-release-actions :deep(.el-button) { display: inline-flex; align-items: center; gap: 5px; }
.pda-release-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 18px; }
.pda-release-form :deep(.el-input-number) { width: 100%; }
.pda-release-options { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 0 var(--admin-space-6); }
.pda-release-fields { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 var(--admin-space-6); }
.pda-release-options > *, .pda-release-fields > * { min-width: 0; }
.pda-release-file-input { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.pda-release-file-control { display: flex; width: 100%; min-width: 0; align-items: flex-start; gap: var(--admin-space-5); }
.pda-release-file-control > :deep(.el-button) { flex-shrink: 0; }
.pda-release-file-meta { flex: 1; min-width: 0; line-height: 1.6; }
.pda-release-file-name { display: block; color: var(--cc-text); overflow-wrap: anywhere; }
.pda-release-file-size { display: block; color: var(--cc-muted); font-size: var(--admin-font-caption); }
@media (max-width: 900px) { .pda-release-context { align-items: flex-start; flex-direction: column; gap: var(--admin-space-3); } }
</style>
+15
View File
@@ -820,6 +820,21 @@ describe('approved Admin density ownership', () => {
for (const source of [list, detail]) expect(source).toContain("customClass: 'admin-density-confirm'")
})
it('keeps PDA version upload on the shared form scale with a keyboard file trigger and complete filenames', () => {
const source = read('modules/pda-releases/pages/PdaReleasesView.vue')
const [dialog] = expectWorkbenchDialogs(source)
expect(dialog!.loc.source).toContain(':confirm-loading="uploading"')
const form = elementsOf(source, 'el-form')[0]!
expect(classesOf(form)).toEqual(expect.arrayContaining(['density-form', 'density-form--outlined', 'density-form--flush-end']))
expect(form.loc.source).toContain(':disabled="uploading"')
const fileInput = elementsOf(source, 'input').find(element => element.loc.source.includes('type="file"'))!
expect(fileInput.loc.source).toContain('@change="selectFile"')
expect(fileInput.loc.source).toContain(':disabled="uploading"')
expect(source).toContain('@click="fileInput?.click()"')
expect(source).toContain('overflow-wrap: anywhere')
expect(source).not.toContain('text-overflow: ellipsis')
})
it('uses shared frames, continuous tables and readonly facts for fleet quote dialogs', () => {
const editor = read('modules/overseas-master-data/components/FleetQuoteEditor.vue')
const importer = read('modules/overseas-master-data/components/FleetQuoteImport.vue')