应用市场详情页点击安装实现,点击安装增加弹窗显示进度
This commit is contained in:
parent
4504c3e8bf
commit
6a90f5ec39
@ -113,13 +113,36 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 安装进度弹窗 -->
|
||||
<n-modal v-model:show="showProgressModal" preset="card" style="width: 500px">
|
||||
<template #header>
|
||||
<h3>{{ t('Installing App') }}</h3>
|
||||
</template>
|
||||
|
||||
<div class="progress-content">
|
||||
<n-progress
|
||||
:percentage="installProgress"
|
||||
:status="installStatus"
|
||||
:show-indicator="true"
|
||||
/>
|
||||
<n-text class="progress-text">{{ installMessage }}</n-text>
|
||||
</div>
|
||||
|
||||
<template #action>
|
||||
<n-button @click="showProgressModal = false" :disabled="installing">
|
||||
{{ installing ? t('Installing...') : t('Close') }}
|
||||
</n-button>
|
||||
</template>
|
||||
</n-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { NButton, NIcon, NSpin, NEmpty, useMessage } from 'naive-ui'
|
||||
import { get_session_api_headers } from '@/shared/api/auth'
|
||||
import { NButton, NIcon, NSpin, NEmpty, useMessage, NModal, NProgress, NText } from 'naive-ui'
|
||||
import { Icon } from '@iconify/vue'
|
||||
import axios from 'axios'
|
||||
import { t } from '@/shared/i18n'
|
||||
@ -132,6 +155,13 @@ const loading = ref(true)
|
||||
const error = ref('')
|
||||
const app = ref<any>(null)
|
||||
|
||||
// 安装相关状态
|
||||
const installing = ref(false)
|
||||
const installProgress = ref(0)
|
||||
const installMessage = ref('')
|
||||
const installStatus = ref<'success' | 'error' | 'info'>('info')
|
||||
const showProgressModal = ref(false)
|
||||
|
||||
const appName = computed(() => route.params.name as string)
|
||||
|
||||
async function loadAppDetail() {
|
||||
@ -173,9 +203,66 @@ function goBack() {
|
||||
router.push('/app-marketplace')
|
||||
}
|
||||
|
||||
function installApp() {
|
||||
// TODO: 实现安装应用
|
||||
message.info(t('Install feature coming soon'))
|
||||
async function installApp() {
|
||||
if (!app.value?.file_url) {
|
||||
message.error(t('应用文件URL不存在'))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
installing.value = true
|
||||
installProgress.value = 0
|
||||
installMessage.value = t('正在下载应用包...')
|
||||
installStatus.value = 'info'
|
||||
showProgressModal.value = true
|
||||
|
||||
// 更新进度
|
||||
setTimeout(() => {
|
||||
installProgress.value = 30
|
||||
installMessage.value = t('正在安装应用...')
|
||||
}, 500)
|
||||
|
||||
const response = await axios.post('/jingrow/install-from-url', new URLSearchParams({
|
||||
url: app.value.file_url
|
||||
}), {
|
||||
headers: {
|
||||
...get_session_api_headers(),
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
installProgress.value = 80
|
||||
installMessage.value = t('正在同步数据库...')
|
||||
}, 1000)
|
||||
|
||||
setTimeout(() => {
|
||||
installProgress.value = 100
|
||||
}, 1500)
|
||||
|
||||
if (response.data.success) {
|
||||
installStatus.value = 'success'
|
||||
installMessage.value = t('应用安装成功!')
|
||||
message.success(t('应用安装成功'))
|
||||
|
||||
setTimeout(() => {
|
||||
showProgressModal.value = false
|
||||
}, 2000)
|
||||
} else {
|
||||
throw new Error(response.data.error || t('安装失败'))
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Install app error:', error)
|
||||
installStatus.value = 'error'
|
||||
installMessage.value = error.response?.data?.detail || error.message || t('安装失败')
|
||||
message.error(error.response?.data?.detail || t('安装失败'))
|
||||
|
||||
setTimeout(() => {
|
||||
showProgressModal.value = false
|
||||
}, 3000)
|
||||
} finally {
|
||||
installing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@ -405,6 +492,18 @@ onMounted(() => {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.progress-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
text-align: center;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.app-card {
|
||||
padding: 20px;
|
||||
|
||||
@ -130,13 +130,35 @@
|
||||
</n-empty>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 安装进度弹窗 -->
|
||||
<n-modal v-model:show="showProgressModal" preset="card" style="width: 500px">
|
||||
<template #header>
|
||||
<h3>{{ t('Installing App') }}</h3>
|
||||
</template>
|
||||
|
||||
<div class="progress-content">
|
||||
<n-progress
|
||||
:percentage="installProgress"
|
||||
:status="installStatus"
|
||||
:show-indicator="true"
|
||||
/>
|
||||
<n-text class="progress-text">{{ installMessage }}</n-text>
|
||||
</div>
|
||||
|
||||
<template #action>
|
||||
<n-button @click="showProgressModal = false" :disabled="installing">
|
||||
{{ installing ? t('Installing...') : t('Close') }}
|
||||
</n-button>
|
||||
</template>
|
||||
</n-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { NInput, NButton, NIcon, NSpin, NEmpty, NSelect, NPagination, useMessage } from 'naive-ui'
|
||||
import { NInput, NButton, NIcon, NSpin, NEmpty, NSelect, NPagination, useMessage, NModal, NProgress, NText } from 'naive-ui'
|
||||
import { Icon } from '@iconify/vue'
|
||||
import axios from 'axios'
|
||||
import { t } from '@/shared/i18n'
|
||||
@ -153,6 +175,13 @@ const page = ref(1)
|
||||
const pageSize = ref(parseInt(localStorage.getItem('itemsPerPage') || '20'))
|
||||
const sortBy = ref('creation desc')
|
||||
|
||||
// 安装相关状态
|
||||
const installing = ref(false)
|
||||
const installProgress = ref(0)
|
||||
const installMessage = ref('')
|
||||
const installStatus = ref<'success' | 'error' | 'info'>('info')
|
||||
const showProgressModal = ref(false)
|
||||
|
||||
// 排序选项
|
||||
const sortOptions = computed(() => [
|
||||
{ label: t('Latest'), value: 'creation desc' },
|
||||
@ -214,11 +243,23 @@ function viewAppDetail(app: any) {
|
||||
}
|
||||
|
||||
async function installApp(app: any) {
|
||||
if (!app.file_url) {
|
||||
message.error(t('应用文件URL不存在'))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
if (!app.file_url) {
|
||||
message.error(t('应用文件URL不存在'))
|
||||
return
|
||||
}
|
||||
installing.value = true
|
||||
installProgress.value = 0
|
||||
installMessage.value = t('正在下载应用包...')
|
||||
installStatus.value = 'info'
|
||||
showProgressModal.value = true
|
||||
|
||||
// 更新进度
|
||||
setTimeout(() => {
|
||||
installProgress.value = 30
|
||||
installMessage.value = t('正在安装应用...')
|
||||
}, 500)
|
||||
|
||||
const response = await axios.post('/jingrow/install-from-url', new URLSearchParams({
|
||||
url: app.file_url
|
||||
@ -229,16 +270,37 @@ async function installApp(app: any) {
|
||||
}
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
installProgress.value = 80
|
||||
installMessage.value = t('正在同步数据库...')
|
||||
}, 1000)
|
||||
|
||||
setTimeout(() => {
|
||||
installProgress.value = 100
|
||||
}, 1500)
|
||||
|
||||
if (response.data.success) {
|
||||
installStatus.value = 'success'
|
||||
installMessage.value = t('应用安装成功!')
|
||||
message.success(t('应用安装成功'))
|
||||
// 刷新列表或跳转到已安装应用页面
|
||||
router.push('/installed-apps')
|
||||
|
||||
setTimeout(() => {
|
||||
showProgressModal.value = false
|
||||
}, 2000)
|
||||
} else {
|
||||
message.error(response.data.error || t('安装失败'))
|
||||
throw new Error(response.data.error || t('安装失败'))
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Install app error:', error)
|
||||
installStatus.value = 'error'
|
||||
installMessage.value = error.response?.data?.detail || error.message || t('安装失败')
|
||||
message.error(error.response?.data?.detail || t('安装失败'))
|
||||
|
||||
setTimeout(() => {
|
||||
showProgressModal.value = false
|
||||
}, 3000)
|
||||
} finally {
|
||||
installing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@ -591,4 +653,16 @@ watch(() => localStorage.getItem('itemsPerPage'), (newValue) => {
|
||||
height: 180px;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
text-align: center;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user