增加删除已发布应用的功能
This commit is contained in:
parent
d5970329a4
commit
647772a7ab
@ -100,18 +100,10 @@
|
|||||||
{{ t('View Details') }}
|
{{ t('View Details') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
<n-button
|
<n-button
|
||||||
v-if="isAppInstalled(app.app_name || app.name)"
|
type="error"
|
||||||
type="warning"
|
@click="deleteApp(app)"
|
||||||
@click="installApp(app)"
|
|
||||||
>
|
>
|
||||||
{{ t('Update') }}
|
{{ t('Delete') }}
|
||||||
</n-button>
|
|
||||||
<n-button
|
|
||||||
v-else
|
|
||||||
type="primary"
|
|
||||||
@click="installApp(app)"
|
|
||||||
>
|
|
||||||
{{ t('Install') }}
|
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -151,15 +143,6 @@
|
|||||||
</n-empty>
|
</n-empty>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 安装进度弹窗 -->
|
|
||||||
<InstallProgressModal
|
|
||||||
v-model="showProgressModal"
|
|
||||||
:progress="installProgress"
|
|
||||||
:message="installMessage"
|
|
||||||
:status="installStatus"
|
|
||||||
:installing="installing"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -170,8 +153,6 @@ import { NInput, NButton, NIcon, NSpin, NEmpty, NSelect, NPagination, useMessage
|
|||||||
import { Icon } from '@iconify/vue'
|
import { Icon } from '@iconify/vue'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { t } from '@/shared/i18n'
|
import { t } from '@/shared/i18n'
|
||||||
import { get_session_api_headers } from '@/shared/api/auth'
|
|
||||||
import InstallProgressModal from './InstallProgressModal.vue'
|
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
@ -185,16 +166,6 @@ const page = ref(1)
|
|||||||
const pageSize = ref(parseInt(localStorage.getItem('itemsPerPage') || '20'))
|
const pageSize = ref(parseInt(localStorage.getItem('itemsPerPage') || '20'))
|
||||||
const sortBy = ref('creation desc')
|
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 installedAppNames = ref<Set<string>>(new Set())
|
|
||||||
|
|
||||||
// 排序选项
|
// 排序选项
|
||||||
const sortOptions = computed(() => [
|
const sortOptions = computed(() => [
|
||||||
{ label: t('Latest'), value: 'creation desc' },
|
{ label: t('Latest'), value: 'creation desc' },
|
||||||
@ -287,151 +258,56 @@ function getStatusClass(status: string): string {
|
|||||||
return status.toLowerCase().replace(/\s+/g, '-')
|
return status.toLowerCase().replace(/\s+/g, '-')
|
||||||
}
|
}
|
||||||
|
|
||||||
async function installApp(app: any) {
|
async function deleteApp(app: any) {
|
||||||
if (!app.file_url && !app.repository_url) {
|
// 使用记录的name字段删除
|
||||||
message.error(t('应用文件URL或仓库地址不存在'))
|
const recordName = app.name
|
||||||
|
if (!recordName) {
|
||||||
|
message.error(t('应用名称不存在'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 先检查应用是否已存在
|
// 显示确认对话框,显示应用标题
|
||||||
try {
|
const appTitle = app.title || app.app_name || recordName
|
||||||
const appName = app.app_name || app.name
|
dialog.warning({
|
||||||
if (appName) {
|
title: t('确认删除'),
|
||||||
const checkResponse = await axios.get(`/jingrow/check-app/${appName}`)
|
content: t('确定要删除应用 "{0}" 吗?此操作不可恢复。').replace('{0}', appTitle),
|
||||||
|
positiveText: t('确认删除'),
|
||||||
if (checkResponse.data.exists) {
|
negativeText: t('取消'),
|
||||||
// 显示确认对话框
|
onPositiveClick: async () => {
|
||||||
dialog.warning({
|
await performDelete(recordName)
|
||||||
title: t('应用已存在'),
|
|
||||||
content: t('应用 "{0}" 已安装,是否覆盖安装?').replace('{0}', appName),
|
|
||||||
positiveText: t('确认覆盖'),
|
|
||||||
negativeText: t('取消'),
|
|
||||||
onPositiveClick: () => {
|
|
||||||
performInstall(app)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
})
|
||||||
console.error('Check app exists error:', error)
|
|
||||||
}
|
|
||||||
|
|
||||||
performInstall(app)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function performInstall(app: any) {
|
async function performDelete(appName: string) {
|
||||||
try {
|
try {
|
||||||
installing.value = true
|
// 调用本地API,由后端转发到云端
|
||||||
installProgress.value = 0
|
const response = await axios.post('/jingrow/delete-published-app', {
|
||||||
installMessage.value = t('正在准备安装...')
|
name: appName
|
||||||
installStatus.value = 'info'
|
}, {
|
||||||
showProgressModal.value = true
|
withCredentials: true
|
||||||
|
})
|
||||||
|
|
||||||
let response
|
if (response.data && response.data.success) {
|
||||||
|
message.success(response.data.message || t('应用删除成功'))
|
||||||
// 优先使用文件URL,否则使用git仓库
|
// 刷新应用列表
|
||||||
if (app.file_url) {
|
loadApps()
|
||||||
installMessage.value = t('正在下载应用包...')
|
|
||||||
setTimeout(() => {
|
|
||||||
installProgress.value = 20
|
|
||||||
}, 300)
|
|
||||||
|
|
||||||
installProgress.value = 30
|
|
||||||
installMessage.value = t('正在安装应用...')
|
|
||||||
|
|
||||||
response = await axios.post('/jingrow/install-from-url', new URLSearchParams({
|
|
||||||
url: app.file_url
|
|
||||||
}), {
|
|
||||||
headers: {
|
|
||||||
...get_session_api_headers(),
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else if (app.repository_url) {
|
|
||||||
installMessage.value = t('正在克隆仓库...')
|
|
||||||
setTimeout(() => {
|
|
||||||
installProgress.value = 20
|
|
||||||
}, 300)
|
|
||||||
|
|
||||||
installProgress.value = 30
|
|
||||||
installMessage.value = t('正在安装应用...')
|
|
||||||
|
|
||||||
const params = new URLSearchParams({
|
|
||||||
repo_url: app.repository_url
|
|
||||||
})
|
|
||||||
|
|
||||||
response = await axios.post('/jingrow/install-from-git', params, {
|
|
||||||
headers: {
|
|
||||||
...get_session_api_headers(),
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response) {
|
|
||||||
throw new Error(t('无法确定安装方式'))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新进度到安装完成
|
|
||||||
installProgress.value = 100
|
|
||||||
|
|
||||||
if (response.data.success) {
|
|
||||||
// 所有步骤完成后才显示成功
|
|
||||||
installing.value = false
|
|
||||||
installStatus.value = 'success'
|
|
||||||
installMessage.value = t('应用安装成功!')
|
|
||||||
message.success(t('应用安装成功'))
|
|
||||||
|
|
||||||
// 刷新已安装应用列表
|
|
||||||
loadInstalledApps()
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
showProgressModal.value = false
|
|
||||||
}, 2000)
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(response.data.error || t('安装失败'))
|
const errorMsg = response.data?.message || response.data?.error || t('删除失败')
|
||||||
|
message.error(errorMsg)
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('Install app error:', error)
|
console.error('Delete app error:', error)
|
||||||
installing.value = false
|
const errorMsg = error.response?.data?.detail ||
|
||||||
installStatus.value = 'error'
|
error.response?.data?.message ||
|
||||||
installMessage.value = error.response?.data?.detail || error.message || t('安装失败')
|
error.message ||
|
||||||
message.error(error.response?.data?.detail || t('安装失败'))
|
t('删除失败')
|
||||||
|
message.error(errorMsg)
|
||||||
setTimeout(() => {
|
|
||||||
showProgressModal.value = false
|
|
||||||
}, 3000)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载已安装应用列表
|
|
||||||
async function loadInstalledApps() {
|
|
||||||
try {
|
|
||||||
const response = await axios.get('/jingrow/installed-app-names')
|
|
||||||
if (response.data.success) {
|
|
||||||
const apps = response.data.apps || []
|
|
||||||
installedAppNames.value = new Set(apps)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Load installed apps error:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查应用是否已安装
|
|
||||||
function isAppInstalled(appName: string): boolean {
|
|
||||||
if (!appName) return false
|
|
||||||
return installedAppNames.value.has(appName.toLowerCase())
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadApps()
|
loadApps()
|
||||||
loadInstalledApps()
|
|
||||||
|
|
||||||
// 监听全局事件
|
|
||||||
window.addEventListener('installedAppsUpdated', () => {
|
|
||||||
loadInstalledApps()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听搜索和排序变化
|
// 监听搜索和排序变化
|
||||||
|
|||||||
@ -1060,6 +1060,36 @@ async def get_my_published_apps(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/jingrow/delete-published-app")
|
||||||
|
async def delete_published_app(request: Request, payload: Dict[str, Any]):
|
||||||
|
"""删除已发布的应用,根据记录的name字段删除"""
|
||||||
|
session_cookie = request.cookies.get('sid')
|
||||||
|
if not session_cookie:
|
||||||
|
raise HTTPException(status_code=401, detail="未提供认证信息")
|
||||||
|
|
||||||
|
# 使用记录的name字段,不是app_name字段
|
||||||
|
record_name = payload.get('name')
|
||||||
|
if not record_name:
|
||||||
|
raise HTTPException(status_code=400, detail="记录名称不能为空")
|
||||||
|
|
||||||
|
url = f"{get_jingrow_cloud_url()}/api/action/jcloud.api.local_app.delete_local_app"
|
||||||
|
|
||||||
|
headers = get_jingrow_cloud_api_headers()
|
||||||
|
headers['Cookie'] = f'sid={session_cookie}'
|
||||||
|
|
||||||
|
# 传递记录的name字段到云端API
|
||||||
|
response = requests.post(url, json={'name': record_name}, headers=headers, timeout=20)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
data = response.json()
|
||||||
|
result = data.get('message', data)
|
||||||
|
|
||||||
|
if result.get('success'):
|
||||||
|
return {"success": True, "message": result.get('message', '应用删除成功')}
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=400, detail=result.get('message', '删除失败'))
|
||||||
|
|
||||||
|
|
||||||
@router.post("/jingrow/upload-image")
|
@router.post("/jingrow/upload-image")
|
||||||
async def upload_image(file: UploadFile = File(...)):
|
async def upload_image(file: UploadFile = File(...)):
|
||||||
"""上传应用图片"""
|
"""上传应用图片"""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user