- 后端增加至少填写一个平台包名的验证逻辑 - 前端调整应用数据模型,将包名字段改为可选类型 - 添加应用详情页的编辑功能和表单验证 - 优化应用列表页包名显示逻辑,支持多平台包名展示 - 重构应用配置指引页面,按平台分类展示商店配置指南 - 在版本管理页面增加包名配置检查和相应提示 - 新增应用信息编辑弹窗组件和相关业务逻辑
166 行
5.3 KiB
Vue
166 行
5.3 KiB
Vue
<template>
|
||
<div>
|
||
<div class="page-header">
|
||
<h2>我的应用</h2>
|
||
<el-button type="primary" @click="showCreate = true">
|
||
<el-icon><Plus /></el-icon> 创建应用
|
||
</el-button>
|
||
</div>
|
||
|
||
<div class="table-wrap">
|
||
<el-table :data="apps" v-loading="loading" style="width:100%">
|
||
<el-table-column prop="name" label="应用名称" min-width="120" />
|
||
<el-table-column label="包名" min-width="160">
|
||
<template #default="{ row }">
|
||
{{ row.packageName || row.iosBundleId || row.harmonyBundleName || '-' }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="appKey" label="AppKey" min-width="220" show-overflow-tooltip />
|
||
<el-table-column prop="createdAt" label="创建时间" width="180">
|
||
<template #default="{ row }">{{ formatDate(row.createdAt) }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template #default="{ row }">
|
||
<el-button link type="primary" @click="$router.push(`/apps/${row.appKey}`)">详情</el-button>
|
||
<el-button link type="danger" @click="handleDelete(row.appKey)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
|
||
<el-dialog v-model="showCreate" title="创建应用" :width="dialogWidth">
|
||
<el-form ref="createFormRef" :model="createForm" :rules="createRules" label-position="top">
|
||
<el-form-item label="应用名称" prop="name">
|
||
<el-input v-model="createForm.name" placeholder="我的应用" />
|
||
</el-form-item>
|
||
<el-form-item label="Android 包名">
|
||
<el-input v-model="createForm.packageName" placeholder="com.example.app(可选)" />
|
||
</el-form-item>
|
||
<el-form-item label="iOS Bundle ID">
|
||
<el-input v-model="createForm.iosBundleId" placeholder="com.example.app(可选)" />
|
||
</el-form-item>
|
||
<el-form-item label="鸿蒙 Bundle Name">
|
||
<el-input v-model="createForm.harmonyBundleName" placeholder="com.example.app(可选)" />
|
||
</el-form-item>
|
||
<el-form-item label="简述">
|
||
<el-input v-model="createForm.description" type="textarea" :rows="3" placeholder="应用简述(可选)" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<div class="create-tip">至少填写一个平台的包名</div>
|
||
<template #footer>
|
||
<el-button @click="showCreate = false">取消</el-button>
|
||
<el-button type="primary" :loading="creating" @click="handleCreate">确定</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
import type { FormInstance, FormRules } from 'element-plus'
|
||
import { appApi, type App } from '@/api/app'
|
||
import { formatTime } from '@/utils/date'
|
||
|
||
const apps = ref<App[]>([])
|
||
const loading = ref(false)
|
||
const showCreate = ref(false)
|
||
const creating = ref(false)
|
||
const createFormRef = ref<FormInstance>()
|
||
const isMobile = ref(false)
|
||
const dialogWidth = computed(() => (isMobile.value ? 'calc(100vw - 24px)' : '480px'))
|
||
|
||
const createForm = reactive({ packageName: '', iosBundleId: '', harmonyBundleName: '', name: '', description: '' })
|
||
const createRules: FormRules = {
|
||
name: [{ required: true, message: '请输入应用名' }],
|
||
}
|
||
|
||
async function loadApps() {
|
||
loading.value = true
|
||
try {
|
||
const res = await appApi.list()
|
||
apps.value = res.data.data
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
async function handleCreate() {
|
||
await createFormRef.value?.validate()
|
||
if (!createForm.packageName.trim() && !createForm.iosBundleId.trim() && !createForm.harmonyBundleName.trim()) {
|
||
ElMessage.warning('至少填写一个平台的包名')
|
||
return
|
||
}
|
||
creating.value = true
|
||
try {
|
||
await appApi.create({
|
||
name: createForm.name.trim(),
|
||
packageName: createForm.packageName.trim() || undefined,
|
||
iosBundleId: createForm.iosBundleId.trim() || undefined,
|
||
harmonyBundleName: createForm.harmonyBundleName.trim() || undefined,
|
||
description: createForm.description.trim() || undefined,
|
||
})
|
||
showCreate.value = false
|
||
ElMessage.success('应用创建成功')
|
||
loadApps()
|
||
} finally {
|
||
creating.value = false
|
||
}
|
||
}
|
||
|
||
async function handleDelete(appKey: string) {
|
||
await ElMessageBox.confirm('确定删除此应用?删除后不可恢复。', '警告', { type: 'warning' })
|
||
await appApi.delete(appKey)
|
||
ElMessage.success('已删除')
|
||
loadApps()
|
||
}
|
||
|
||
const formatDate = formatTime
|
||
|
||
function updateViewport() {
|
||
isMobile.value = window.innerWidth < 768
|
||
}
|
||
|
||
onMounted(() => {
|
||
loadApps()
|
||
updateViewport()
|
||
window.addEventListener('resize', updateViewport)
|
||
})
|
||
|
||
onBeforeUnmount(() => {
|
||
window.removeEventListener('resize', updateViewport)
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.page-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
gap: 12px;
|
||
margin-bottom: 16px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.table-wrap {
|
||
overflow-x: auto;
|
||
background: #fff;
|
||
border-radius: 12px;
|
||
}
|
||
.create-tip {
|
||
font-size: 12px;
|
||
color: var(--el-text-color-secondary);
|
||
margin-top: -8px;
|
||
padding-left: 4px;
|
||
}
|
||
|
||
@media (max-width: 767px) {
|
||
.page-header {
|
||
align-items: stretch;
|
||
}
|
||
|
||
.page-header :deep(.el-button) {
|
||
width: 100%;
|
||
}
|
||
}
|
||
</style>
|