Merge branch 'feature/refactor' of github.com:AUTO-MAS-Project/AUTO-MAS into feature/refactor
This commit is contained in:
@@ -516,6 +516,47 @@ ipcMain.handle('check-environment', async () => {
|
|||||||
return checkEnvironment(appRoot)
|
return checkEnvironment(appRoot)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 关键文件检查 - 每次都重新检查exe文件是否存在
|
||||||
|
ipcMain.handle('check-critical-files', async () => {
|
||||||
|
try {
|
||||||
|
const appRoot = getAppRoot()
|
||||||
|
|
||||||
|
// 检查Python可执行文件
|
||||||
|
const pythonPath = path.join(appRoot, 'environment', 'python', 'python.exe')
|
||||||
|
const pythonExists = fs.existsSync(pythonPath)
|
||||||
|
|
||||||
|
// 检查pip(通常与Python一起安装)
|
||||||
|
const pipPath = path.join(appRoot, 'environment', 'python', 'Scripts', 'pip.exe')
|
||||||
|
const pipExists = fs.existsSync(pipPath)
|
||||||
|
|
||||||
|
// 检查Git可执行文件
|
||||||
|
const gitPath = path.join(appRoot, 'environment', 'git', 'bin', 'git.exe')
|
||||||
|
const gitExists = fs.existsSync(gitPath)
|
||||||
|
|
||||||
|
// 检查后端主文件
|
||||||
|
const mainPyPath = path.join(appRoot, 'main.py')
|
||||||
|
const mainPyExists = fs.existsSync(mainPyPath)
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
pythonExists,
|
||||||
|
pipExists,
|
||||||
|
gitExists,
|
||||||
|
mainPyExists
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info('关键文件检查结果:', result)
|
||||||
|
return result
|
||||||
|
} catch (error) {
|
||||||
|
log.error('检查关键文件失败:', error)
|
||||||
|
return {
|
||||||
|
pythonExists: false,
|
||||||
|
pipExists: false,
|
||||||
|
gitExists: false,
|
||||||
|
mainPyExists: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Python相关
|
// Python相关
|
||||||
ipcMain.handle('download-python', async (_event, mirror = 'tsinghua') => {
|
ipcMain.handle('download-python', async (_event, mirror = 'tsinghua') => {
|
||||||
const appRoot = getAppRoot()
|
const appRoot = getAppRoot()
|
||||||
@@ -547,6 +588,17 @@ ipcMain.handle('download-git', async () => {
|
|||||||
return downloadGit(appRoot)
|
return downloadGit(appRoot)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('check-git-update', async () => {
|
||||||
|
try {
|
||||||
|
// 这里可以实现检查Git仓库更新的逻辑
|
||||||
|
// 暂时返回false,表示没有更新
|
||||||
|
return { hasUpdate: false }
|
||||||
|
} catch (error) {
|
||||||
|
log.error('检查Git更新失败:', error)
|
||||||
|
return { hasUpdate: false, error: error instanceof Error ? error.message : String(error) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
'clone-backend',
|
'clone-backend',
|
||||||
async (_event, repoUrl = 'https://github.com/AUTO-MAS-Project/AUTO-MAS.git') => {
|
async (_event, repoUrl = 'https://github.com/AUTO-MAS-Project/AUTO-MAS.git') => {
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|||||||
|
|
||||||
// 初始化相关API
|
// 初始化相关API
|
||||||
checkEnvironment: () => ipcRenderer.invoke('check-environment'),
|
checkEnvironment: () => ipcRenderer.invoke('check-environment'),
|
||||||
|
checkCriticalFiles: () => ipcRenderer.invoke('check-critical-files'),
|
||||||
downloadPython: (mirror?: string) => ipcRenderer.invoke('download-python', mirror),
|
downloadPython: (mirror?: string) => ipcRenderer.invoke('download-python', mirror),
|
||||||
installPip: () => ipcRenderer.invoke('install-pip'),
|
installPip: () => ipcRenderer.invoke('install-pip'),
|
||||||
downloadGit: () => ipcRenderer.invoke('download-git'),
|
downloadGit: () => ipcRenderer.invoke('download-git'),
|
||||||
|
checkGitUpdate: () => ipcRenderer.invoke('check-git-update'),
|
||||||
installDependencies: (mirror?: string) => ipcRenderer.invoke('install-dependencies', mirror),
|
installDependencies: (mirror?: string) => ipcRenderer.invoke('install-dependencies', mirror),
|
||||||
cloneBackend: (repoUrl?: string) => ipcRenderer.invoke('clone-backend', repoUrl),
|
cloneBackend: (repoUrl?: string) => ipcRenderer.invoke('clone-backend', repoUrl),
|
||||||
updateBackend: (repoUrl?: string) => ipcRenderer.invoke('update-backend', repoUrl),
|
updateBackend: (repoUrl?: string) => ipcRenderer.invoke('update-backend', repoUrl),
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 弹窗 -->
|
<!-- 强行进入应用弹窗 -->
|
||||||
<a-modal
|
<a-modal
|
||||||
v-model:open="forceEnterVisible"
|
v-model:open="forceEnterVisible"
|
||||||
title="警告"
|
title="警告"
|
||||||
@@ -47,6 +47,8 @@
|
|||||||
show-icon
|
show-icon
|
||||||
/>
|
/>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -83,11 +85,6 @@ const aborted = ref(false)
|
|||||||
// 状态:控制弹窗显隐
|
// 状态:控制弹窗显隐
|
||||||
const forceEnterVisible = ref(false)
|
const forceEnterVisible = ref(false)
|
||||||
|
|
||||||
// 镜像源重试相关状态
|
|
||||||
const currentMirrorIndex = ref(0)
|
|
||||||
const availableMirrors = ref<any[]>([])
|
|
||||||
const maxRetries = ref(3)
|
|
||||||
|
|
||||||
// 点击“强行进入应用”按钮,显示弹窗
|
// 点击“强行进入应用”按钮,显示弹窗
|
||||||
function handleForceEnter() {
|
function handleForceEnter() {
|
||||||
forceEnterVisible.value = true
|
forceEnterVisible.value = true
|
||||||
@@ -197,11 +194,6 @@ async function checkGitUpdate(): Promise<boolean> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据镜像源key获取对应的URL
|
|
||||||
function getGitMirrorUrl(mirrorKey: string): string {
|
|
||||||
return getMirrorUrl('git', mirrorKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试更新后端代码,支持镜像源重试
|
// 尝试更新后端代码,支持镜像源重试
|
||||||
async function tryUpdateBackendWithRetry(config: any): Promise<boolean> {
|
async function tryUpdateBackendWithRetry(config: any): Promise<boolean> {
|
||||||
// 获取所有Git镜像源
|
// 获取所有Git镜像源
|
||||||
|
|||||||
@@ -142,22 +142,20 @@
|
|||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { getConfig, saveConfig } from '@/utils/config'
|
import { getConfig, saveConfig } from '@/utils/config'
|
||||||
import {
|
import {
|
||||||
GIT_MIRRORS,
|
|
||||||
getOfficialMirrors,
|
|
||||||
getMirrorMirrors,
|
|
||||||
sortMirrorsBySpeedAndRecommendation,
|
sortMirrorsBySpeedAndRecommendation,
|
||||||
type MirrorConfig
|
type MirrorConfig
|
||||||
} from '@/config/mirrors'
|
} from '@/config/mirrors'
|
||||||
|
import { mirrorManager } from '@/utils/mirrorManager'
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
backendExists: boolean
|
backendExists: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const gitMirrors = ref<MirrorConfig[]>(GIT_MIRRORS)
|
const gitMirrors = ref<MirrorConfig[]>([])
|
||||||
|
|
||||||
// 按类型分组的镜像源
|
// 按类型分组的镜像源
|
||||||
const officialMirrors = computed(() => getOfficialMirrors('git'))
|
const officialMirrors = computed(() => gitMirrors.value.filter(m => m.type === 'official'))
|
||||||
const mirrorMirrors = computed(() => getMirrorMirrors('git'))
|
const mirrorMirrors = computed(() => gitMirrors.value.filter(m => m.type === 'mirror'))
|
||||||
|
|
||||||
// 按速度和推荐排序的镜像源
|
// 按速度和推荐排序的镜像源
|
||||||
const sortedOfficialMirrors = computed(() => sortMirrorsBySpeedAndRecommendation(officialMirrors.value))
|
const sortedOfficialMirrors = computed(() => sortMirrorsBySpeedAndRecommendation(officialMirrors.value))
|
||||||
@@ -174,18 +172,26 @@ const addingCustomMirror = ref(false)
|
|||||||
// 加载配置中的镜像源选择
|
// 加载配置中的镜像源选择
|
||||||
async function loadMirrorConfig() {
|
async function loadMirrorConfig() {
|
||||||
try {
|
try {
|
||||||
|
// 从镜像管理器获取最新的Git镜像源配置(包含云端数据)
|
||||||
|
const cloudMirrors = mirrorManager.getMirrors('git')
|
||||||
|
|
||||||
const config = await getConfig()
|
const config = await getConfig()
|
||||||
selectedGitMirror.value = config.selectedGitMirror || 'ghproxy_edgeone'
|
selectedGitMirror.value = config.selectedGitMirror || 'ghproxy_edgeone'
|
||||||
|
|
||||||
// 加载自定义镜像源
|
// 加载自定义镜像源
|
||||||
if (config.customGitMirrors && Array.isArray(config.customGitMirrors)) {
|
if (config.customGitMirrors && Array.isArray(config.customGitMirrors)) {
|
||||||
customMirrors.value = config.customGitMirrors
|
customMirrors.value = config.customGitMirrors
|
||||||
// 将自定义镜像源添加到gitMirrors中
|
// 将云端镜像源和自定义镜像源合并
|
||||||
gitMirrors.value = [...GIT_MIRRORS, ...customMirrors.value]
|
gitMirrors.value = [...cloudMirrors, ...customMirrors.value]
|
||||||
|
} else {
|
||||||
|
// 只使用云端镜像源
|
||||||
|
gitMirrors.value = [...cloudMirrors]
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Git镜像源配置已加载:', selectedGitMirror.value)
|
console.log('Git镜像源配置已加载:', selectedGitMirror.value)
|
||||||
|
console.log('云端镜像源已加载:', cloudMirrors.length, '个')
|
||||||
console.log('自定义镜像源已加载:', customMirrors.value.length, '个')
|
console.log('自定义镜像源已加载:', customMirrors.value.length, '个')
|
||||||
|
console.log('云端Git镜像源详情:', cloudMirrors.map(m => ({ name: m.name, key: m.key })))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('加载Git镜像源配置失败:', error)
|
console.warn('加载Git镜像源配置失败:', error)
|
||||||
}
|
}
|
||||||
@@ -321,8 +327,9 @@ async function addCustomMirror() {
|
|||||||
// 添加到自定义镜像源列表
|
// 添加到自定义镜像源列表
|
||||||
customMirrors.value.push(newMirror)
|
customMirrors.value.push(newMirror)
|
||||||
|
|
||||||
// 更新完整的镜像源列表
|
// 更新完整的镜像源列表(云端 + 自定义)
|
||||||
gitMirrors.value = [...GIT_MIRRORS, ...customMirrors.value]
|
const cloudMirrors = mirrorManager.getMirrors('git')
|
||||||
|
gitMirrors.value = [...cloudMirrors, ...customMirrors.value]
|
||||||
|
|
||||||
// 自动选择新添加的镜像源
|
// 自动选择新添加的镜像源
|
||||||
selectedGitMirror.value = customKey
|
selectedGitMirror.value = customKey
|
||||||
@@ -366,8 +373,9 @@ async function removeCustomMirror(key: string) {
|
|||||||
// 从自定义镜像源列表中移除
|
// 从自定义镜像源列表中移除
|
||||||
customMirrors.value = customMirrors.value.filter(m => m.key !== key)
|
customMirrors.value = customMirrors.value.filter(m => m.key !== key)
|
||||||
|
|
||||||
// 更新完整的镜像源列表
|
// 更新完整的镜像源列表(云端 + 自定义)
|
||||||
gitMirrors.value = [...GIT_MIRRORS, ...customMirrors.value]
|
const cloudMirrors = mirrorManager.getMirrors('git')
|
||||||
|
gitMirrors.value = [...cloudMirrors, ...customMirrors.value]
|
||||||
|
|
||||||
// 如果当前选中的是被删除的镜像源,切换到默认镜像源
|
// 如果当前选中的是被删除的镜像源,切换到默认镜像源
|
||||||
if (selectedGitMirror.value === key) {
|
if (selectedGitMirror.value === key) {
|
||||||
|
|||||||
@@ -81,18 +81,16 @@
|
|||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { getConfig, saveConfig } from '@/utils/config'
|
import { getConfig, saveConfig } from '@/utils/config'
|
||||||
import {
|
import {
|
||||||
PIP_MIRRORS,
|
|
||||||
getOfficialMirrors,
|
|
||||||
getMirrorMirrors,
|
|
||||||
sortMirrorsBySpeedAndRecommendation,
|
sortMirrorsBySpeedAndRecommendation,
|
||||||
type MirrorConfig,
|
type MirrorConfig,
|
||||||
} from '@/config/mirrors'
|
} from '@/config/mirrors'
|
||||||
|
import { mirrorManager } from '@/utils/mirrorManager'
|
||||||
|
|
||||||
const pipMirrors = ref<MirrorConfig[]>(PIP_MIRRORS)
|
const pipMirrors = ref<MirrorConfig[]>([])
|
||||||
|
|
||||||
// 按类型分组的镜像源
|
// 按类型分组的镜像源
|
||||||
const officialMirrors = computed(() => getOfficialMirrors('pip'))
|
const officialMirrors = computed(() => pipMirrors.value.filter(m => m.type === 'official'))
|
||||||
const mirrorMirrors = computed(() => getMirrorMirrors('pip'))
|
const mirrorMirrors = computed(() => pipMirrors.value.filter(m => m.type === 'mirror'))
|
||||||
|
|
||||||
// 按速度和推荐排序的镜像源
|
// 按速度和推荐排序的镜像源
|
||||||
const sortedOfficialMirrors = computed(() =>
|
const sortedOfficialMirrors = computed(() =>
|
||||||
@@ -106,9 +104,15 @@ const testingPipSpeed = ref(false)
|
|||||||
// 加载配置中的镜像源选择
|
// 加载配置中的镜像源选择
|
||||||
async function loadMirrorConfig() {
|
async function loadMirrorConfig() {
|
||||||
try {
|
try {
|
||||||
|
// 从镜像管理器获取最新的pip镜像源配置(包含云端数据)
|
||||||
|
const cloudMirrors = mirrorManager.getMirrors('pip')
|
||||||
|
pipMirrors.value = [...cloudMirrors]
|
||||||
|
|
||||||
const config = await getConfig()
|
const config = await getConfig()
|
||||||
selectedPipMirror.value = config.selectedPipMirror
|
selectedPipMirror.value = config.selectedPipMirror || 'aliyun'
|
||||||
console.log('pip镜像源配置已加载:', selectedPipMirror.value)
|
console.log('pip镜像源配置已加载:', selectedPipMirror.value)
|
||||||
|
console.log('云端pip镜像源已加载:', cloudMirrors.length, '个')
|
||||||
|
console.log('云端pip镜像源详情:', cloudMirrors.map(m => ({ name: m.name, key: m.key })))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('加载pip镜像源配置失败:', error)
|
console.warn('加载pip镜像源配置失败:', error)
|
||||||
}
|
}
|
||||||
|
|||||||
185
frontend/src/components/initialization/EnvironmentIncomplete.vue
Normal file
185
frontend/src/components/initialization/EnvironmentIncomplete.vue
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
<template>
|
||||||
|
<div class="environment-incomplete">
|
||||||
|
<div class="header">
|
||||||
|
<img src="/src/assets/AUTO-MAS.ico" alt="logo" class="logo" />
|
||||||
|
<a-typography-title :level="1">AUTO-MAS</a-typography-title>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<a-result
|
||||||
|
status="warning"
|
||||||
|
title="环境不完整"
|
||||||
|
sub-title="检测到运行环境中缺少必要的组件,需要重新配置环境"
|
||||||
|
>
|
||||||
|
<template #extra>
|
||||||
|
<div class="missing-components">
|
||||||
|
<a-typography-title :level="4">缺失的组件:</a-typography-title>
|
||||||
|
<a-list :data-source="missingComponents" size="small">
|
||||||
|
<template #renderItem="{ item }">
|
||||||
|
<a-list-item>
|
||||||
|
<a-typography-text type="danger">
|
||||||
|
<ExclamationCircleOutlined /> {{ item }}
|
||||||
|
</a-typography-text>
|
||||||
|
</a-list-item>
|
||||||
|
</template>
|
||||||
|
</a-list>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="description">
|
||||||
|
<a-typography-paragraph>
|
||||||
|
这种情况通常由以下原因导致:
|
||||||
|
</a-typography-paragraph>
|
||||||
|
<ul>
|
||||||
|
<li>杀毒软件误删了相关文件</li>
|
||||||
|
<li>手动删除了环境文件</li>
|
||||||
|
<li>系统更新或清理工具清理了相关文件</li>
|
||||||
|
</ul>
|
||||||
|
<a-typography-paragraph>
|
||||||
|
建议重新配置环境以确保程序正常运行。
|
||||||
|
</a-typography-paragraph>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="actions">
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
@click="handleReconfigure"
|
||||||
|
>
|
||||||
|
重新配置环境
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
size="large"
|
||||||
|
@click="handleForceEnter"
|
||||||
|
style="margin-left: 16px"
|
||||||
|
>
|
||||||
|
强行进入应用
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-result>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
|
||||||
|
import router from '@/router'
|
||||||
|
|
||||||
|
// Props
|
||||||
|
interface Props {
|
||||||
|
missingComponents: string[]
|
||||||
|
onSwitchToManual: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
// 重新配置环境
|
||||||
|
function handleReconfigure() {
|
||||||
|
props.onSwitchToManual()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 强行进入应用
|
||||||
|
function handleForceEnter() {
|
||||||
|
router.push('/home')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.environment-incomplete {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: calc(100vh - 120px);
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
font-size: 38px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--ant-color-text);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.missing-components {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.missing-components h4 {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description ul {
|
||||||
|
margin: 12px 0;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description li {
|
||||||
|
margin: 4px 0;
|
||||||
|
color: var(--ant-color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式优化 */
|
||||||
|
@media (max-height: 700px) {
|
||||||
|
.environment-incomplete {
|
||||||
|
min-height: auto;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions .ant-btn {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a-steps :current="currentStep" :status="stepStatus" class="init-steps">
|
<a-steps :current="displayCurrentStep" :status="stepStatus" class="init-steps">
|
||||||
<a-step title="设置主题" />
|
<a-step title="设置主题" />
|
||||||
<a-step title="配置环境" />
|
<a-step title="配置环境" />
|
||||||
<a-step title="Git 工具" />
|
<a-step title="Git 工具" />
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from 'vue'
|
import { ref, watch, computed } from 'vue'
|
||||||
import { notification } from 'ant-design-vue'
|
import { notification } from 'ant-design-vue'
|
||||||
import { saveConfig } from '@/utils/config'
|
import { saveConfig } from '@/utils/config'
|
||||||
import { useUpdateChecker } from '@/composables/useUpdateChecker'
|
import { useUpdateChecker } from '@/composables/useUpdateChecker'
|
||||||
@@ -177,6 +177,11 @@ const stepStatus = ref<'wait' | 'process' | 'finish' | 'error'>('process')
|
|||||||
const errorMessage = ref('')
|
const errorMessage = ref('')
|
||||||
const isProcessing = ref(false)
|
const isProcessing = ref(false)
|
||||||
|
|
||||||
|
// 显示的当前步骤就是实际步骤
|
||||||
|
const displayCurrentStep = computed(() => {
|
||||||
|
return currentStep.value
|
||||||
|
})
|
||||||
|
|
||||||
// 全局进度条状态
|
// 全局进度条状态
|
||||||
const globalProgress = ref(0)
|
const globalProgress = ref(0)
|
||||||
const globalProgressStatus = ref<'normal' | 'exception' | 'success'>('normal')
|
const globalProgressStatus = ref<'normal' | 'exception' | 'success'>('normal')
|
||||||
@@ -239,9 +244,8 @@ async function handleNextStep() {
|
|||||||
break
|
break
|
||||||
case 4: // 依赖安装
|
case 4: // 依赖安装
|
||||||
console.log('执行依赖安装')
|
console.log('执行依赖安装')
|
||||||
if (!props.dependenciesInstalled) {
|
// 总是执行依赖安装,确保环境完整
|
||||||
await installDependencies()
|
await installDependencies()
|
||||||
}
|
|
||||||
break
|
break
|
||||||
case 5: // 启动服务
|
case 5: // 启动服务
|
||||||
console.log('执行启动服务')
|
console.log('执行启动服务')
|
||||||
@@ -274,7 +278,7 @@ function getNextButtonText() {
|
|||||||
case 3:
|
case 3:
|
||||||
return props.backendExists ? '更新代码' : '获取代码'
|
return props.backendExists ? '更新代码' : '获取代码'
|
||||||
case 4:
|
case 4:
|
||||||
return '安装依赖'
|
return props.dependenciesInstalled ? '重新安装依赖' : '安装依赖'
|
||||||
case 5:
|
case 5:
|
||||||
return '启动服务'
|
return '启动服务'
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -90,22 +90,20 @@
|
|||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { getConfig, saveConfig } from '@/utils/config'
|
import { getConfig, saveConfig } from '@/utils/config'
|
||||||
import {
|
import {
|
||||||
PYTHON_MIRRORS,
|
|
||||||
getOfficialMirrors,
|
|
||||||
getMirrorMirrors,
|
|
||||||
sortMirrorsBySpeedAndRecommendation,
|
sortMirrorsBySpeedAndRecommendation,
|
||||||
type MirrorConfig
|
type MirrorConfig
|
||||||
} from '@/config/mirrors'
|
} from '@/config/mirrors'
|
||||||
|
import { mirrorManager } from '@/utils/mirrorManager'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
pythonInstalled: boolean
|
pythonInstalled: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const pythonMirrors = ref<MirrorConfig[]>(PYTHON_MIRRORS)
|
const pythonMirrors = ref<MirrorConfig[]>([])
|
||||||
|
|
||||||
// 按类型分组的镜像源
|
// 按类型分组的镜像源
|
||||||
const officialMirrors = computed(() => getOfficialMirrors('python'))
|
const officialMirrors = computed(() => pythonMirrors.value.filter(m => m.type === 'official'))
|
||||||
const mirrorMirrors = computed(() => getMirrorMirrors('python'))
|
const mirrorMirrors = computed(() => pythonMirrors.value.filter(m => m.type === 'mirror'))
|
||||||
|
|
||||||
// 按速度和推荐排序的镜像源
|
// 按速度和推荐排序的镜像源
|
||||||
const sortedOfficialMirrors = computed(() => sortMirrorsBySpeedAndRecommendation(officialMirrors.value))
|
const sortedOfficialMirrors = computed(() => sortMirrorsBySpeedAndRecommendation(officialMirrors.value))
|
||||||
@@ -118,9 +116,15 @@ const reinstalling = ref(false)
|
|||||||
// 加载配置中的镜像源选择
|
// 加载配置中的镜像源选择
|
||||||
async function loadMirrorConfig() {
|
async function loadMirrorConfig() {
|
||||||
try {
|
try {
|
||||||
|
// 从镜像管理器获取最新的Python镜像源配置(包含云端数据)
|
||||||
|
const cloudMirrors = mirrorManager.getMirrors('python')
|
||||||
|
pythonMirrors.value = [...cloudMirrors]
|
||||||
|
|
||||||
const config = await getConfig()
|
const config = await getConfig()
|
||||||
selectedPythonMirror.value = config.selectedPythonMirror
|
selectedPythonMirror.value = config.selectedPythonMirror || 'aliyun'
|
||||||
console.log('Python镜像源配置已加载:', selectedPythonMirror.value)
|
console.log('Python镜像源配置已加载:', selectedPythonMirror.value)
|
||||||
|
console.log('云端Python镜像源已加载:', cloudMirrors.length, '个')
|
||||||
|
console.log('云端Python镜像源详情:', cloudMirrors.map(m => ({ name: m.name, key: m.key })))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('加载Python镜像源配置失败:', error)
|
console.warn('加载Python镜像源配置失败:', error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,16 @@
|
|||||||
<!-- 管理员权限检查 -->
|
<!-- 管理员权限检查 -->
|
||||||
<AdminCheck v-if="!isAdmin" />
|
<AdminCheck v-if="!isAdmin" />
|
||||||
|
|
||||||
|
<!-- 环境不完整页面 -->
|
||||||
|
<EnvironmentIncomplete
|
||||||
|
v-if="showEnvironmentIncomplete"
|
||||||
|
:missing-components="missingComponents"
|
||||||
|
:on-switch-to-manual="switchToManualMode"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 自动初始化模式 -->
|
<!-- 自动初始化模式 -->
|
||||||
<AutoMode
|
<AutoMode
|
||||||
v-if="autoMode"
|
v-else-if="autoMode"
|
||||||
:on-switch-to-manual="switchToManualMode"
|
:on-switch-to-manual="switchToManualMode"
|
||||||
:on-auto-complete="enterApp"
|
:on-auto-complete="enterApp"
|
||||||
/>
|
/>
|
||||||
@@ -33,6 +40,7 @@ import { getConfig, saveConfig, setInitialized } from '@/utils/config'
|
|||||||
import AdminCheck from '@/components/initialization/AdminCheck.vue'
|
import AdminCheck from '@/components/initialization/AdminCheck.vue'
|
||||||
import AutoMode from '@/components/initialization/AutoMode.vue'
|
import AutoMode from '@/components/initialization/AutoMode.vue'
|
||||||
import ManualMode from '@/components/initialization/ManualMode.vue'
|
import ManualMode from '@/components/initialization/ManualMode.vue'
|
||||||
|
import EnvironmentIncomplete from '@/components/initialization/EnvironmentIncomplete.vue'
|
||||||
import type { DownloadProgress } from '@/types/initialization'
|
import type { DownloadProgress } from '@/types/initialization'
|
||||||
import { mirrorManager } from '@/utils/mirrorManager'
|
import { mirrorManager } from '@/utils/mirrorManager'
|
||||||
|
|
||||||
@@ -41,6 +49,8 @@ const router = useRouter()
|
|||||||
// 基础状态
|
// 基础状态
|
||||||
const isAdmin = ref(true)
|
const isAdmin = ref(true)
|
||||||
const autoMode = ref(false)
|
const autoMode = ref(false)
|
||||||
|
const showEnvironmentIncomplete = ref(false)
|
||||||
|
const missingComponents = ref<string[]>([])
|
||||||
|
|
||||||
// 安装状态
|
// 安装状态
|
||||||
const pythonInstalled = ref(false)
|
const pythonInstalled = ref(false)
|
||||||
@@ -64,7 +74,9 @@ function skipToHome() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function switchToManualMode() {
|
function switchToManualMode() {
|
||||||
|
showEnvironmentIncomplete.value = false
|
||||||
autoMode.value = false
|
autoMode.value = false
|
||||||
|
console.log('切换到手动模式')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 进入应用
|
// 进入应用
|
||||||
@@ -143,8 +155,7 @@ async function checkCriticalFiles() {
|
|||||||
// 检查环境状态
|
// 检查环境状态
|
||||||
async function checkEnvironment() {
|
async function checkEnvironment() {
|
||||||
try {
|
try {
|
||||||
|
// 每次都重新检查关键exe文件是否存在,不依赖持久化配置
|
||||||
// 只检查关键exe文件是否存在
|
|
||||||
const criticalFiles = await checkCriticalFiles()
|
const criticalFiles = await checkCriticalFiles()
|
||||||
|
|
||||||
console.log('关键文件检查结果:', criticalFiles)
|
console.log('关键文件检查结果:', criticalFiles)
|
||||||
@@ -154,7 +165,7 @@ async function checkEnvironment() {
|
|||||||
gitInstalled.value = criticalFiles.gitExists
|
gitInstalled.value = criticalFiles.gitExists
|
||||||
backendExists.value = criticalFiles.mainPyExists
|
backendExists.value = criticalFiles.mainPyExists
|
||||||
|
|
||||||
// 检查配置文件中的依赖安装状态
|
// 依赖安装状态从配置文件读取,但在手动模式中会重新安装
|
||||||
const config = await getConfig()
|
const config = await getConfig()
|
||||||
dependenciesInstalled.value = config.dependenciesInstalled || false
|
dependenciesInstalled.value = config.dependenciesInstalled || false
|
||||||
|
|
||||||
@@ -180,27 +191,43 @@ async function checkEnvironment() {
|
|||||||
console.log('- main.py存在:', criticalFiles.mainPyExists)
|
console.log('- main.py存在:', criticalFiles.mainPyExists)
|
||||||
console.log('- 所有关键文件存在:', allExeFilesExist)
|
console.log('- 所有关键文件存在:', allExeFilesExist)
|
||||||
|
|
||||||
// 检查是否应该进入自动模式
|
// 新的自动模式判断逻辑:只要所有关键exe文件都存在且不是第一次启动就进入自动模式
|
||||||
console.log('自动模式判断条件:')
|
console.log('自动模式判断条件:')
|
||||||
console.log('- 不是第一次启动:', !isFirst)
|
console.log('- 不是第一次启动:', !isFirst)
|
||||||
console.log('- 配置显示已初始化:', config.init)
|
|
||||||
console.log('- 所有关键文件存在:', allExeFilesExist)
|
console.log('- 所有关键文件存在:', allExeFilesExist)
|
||||||
|
|
||||||
// 只有在非首次启动、配置显示已初始化、且所有关键exe文件都存在时才进入自动模式
|
// 只要不是第一次启动且所有关键exe文件都存在就进入自动模式
|
||||||
if (!isFirst && config.init && allExeFilesExist) {
|
if (!isFirst && allExeFilesExist) {
|
||||||
console.log('进入自动模式,开始自动启动流程')
|
console.log('进入自动模式,开始自动启动流程')
|
||||||
autoMode.value = true
|
autoMode.value = true
|
||||||
} else {
|
} else {
|
||||||
console.log('进入手动模式')
|
console.log('进入手动模式')
|
||||||
console.log(
|
if (isFirst) {
|
||||||
'原因: isFirst =',
|
console.log('原因: 第一次启动')
|
||||||
isFirst,
|
// 第一次启动直接进入手动模式
|
||||||
', config.init =',
|
autoMode.value = false
|
||||||
config.init,
|
showEnvironmentIncomplete.value = false
|
||||||
', allExeFilesExist =',
|
} else if (!allExeFilesExist) {
|
||||||
allExeFilesExist
|
console.log('原因: 关键exe文件缺失')
|
||||||
)
|
console.log(' - python.exe缺失:', !criticalFiles.pythonExists)
|
||||||
|
console.log(' - git.exe缺失:', !criticalFiles.gitExists)
|
||||||
|
console.log(' - main.py缺失:', !criticalFiles.mainPyExists)
|
||||||
|
|
||||||
|
// 显示环境不完整页面
|
||||||
|
const missing = []
|
||||||
|
if (!criticalFiles.pythonExists) missing.push('Python 环境')
|
||||||
|
if (!criticalFiles.gitExists) missing.push('Git 工具')
|
||||||
|
if (!criticalFiles.mainPyExists) missing.push('后端代码')
|
||||||
|
|
||||||
|
missingComponents.value = missing
|
||||||
|
showEnvironmentIncomplete.value = true
|
||||||
|
autoMode.value = false
|
||||||
|
} else {
|
||||||
|
// 其他情况直接进入手动模式
|
||||||
|
autoMode.value = false
|
||||||
|
showEnvironmentIncomplete.value = false
|
||||||
|
}
|
||||||
|
|
||||||
// 如果关键文件缺失,重置初始化状态
|
// 如果关键文件缺失,重置初始化状态
|
||||||
if (!allExeFilesExist && config.init) {
|
if (!allExeFilesExist && config.init) {
|
||||||
console.log('检测到关键exe文件缺失,重置初始化状态')
|
console.log('检测到关键exe文件缺失,重置初始化状态')
|
||||||
@@ -288,6 +315,8 @@ onUnmounted(() => {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
|
background-color: var(--ant-color-bg-layout);
|
||||||
|
color: var(--ant-color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 响应式优化 */
|
/* 响应式优化 */
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="logs-container">
|
<div class="logs-container">
|
||||||
<div class="logs-header">
|
<div class="logs-header">
|
||||||
<h1>日志查看</h1>
|
<div class="header-content">
|
||||||
<p class="logs-description">查看和管理应用程序日志</p>
|
<div class="title-section">
|
||||||
|
<h1>日志查看</h1>
|
||||||
|
<p class="logs-description">查看和管理应用程序日志</p>
|
||||||
|
</div>
|
||||||
|
<a-button @click="goBack" size="large">
|
||||||
|
<template #icon>
|
||||||
|
<ArrowLeftOutlined />
|
||||||
|
</template>
|
||||||
|
返回设置
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<LogViewer />
|
<LogViewer />
|
||||||
@@ -11,9 +21,12 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { ArrowLeftOutlined } from '@ant-design/icons-vue'
|
||||||
import LogViewer from '@/components/LogViewer.vue'
|
import LogViewer from '@/components/LogViewer.vue'
|
||||||
import { useTheme } from '@/composables/useTheme'
|
import { useTheme } from '@/composables/useTheme'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
const { isDark } = useTheme()
|
const { isDark } = useTheme()
|
||||||
|
|
||||||
const textColor = computed(() =>
|
const textColor = computed(() =>
|
||||||
@@ -22,6 +35,10 @@ const textColor = computed(() =>
|
|||||||
const textSecondaryColor = computed(() =>
|
const textSecondaryColor = computed(() =>
|
||||||
isDark.value ? 'rgba(255, 255, 255, 0.65)' : 'rgba(0, 0, 0, 0.65)'
|
isDark.value ? 'rgba(255, 255, 255, 0.65)' : 'rgba(0, 0, 0, 0.65)'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.push('/settings')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -31,6 +48,19 @@ const textSecondaryColor = computed(() =>
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logs-header {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-section {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.logs-header h1 {
|
.logs-header h1 {
|
||||||
margin: 0 0 8px 0;
|
margin: 0 0 8px 0;
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mirror-test-container">
|
<div class="mirror-test-container">
|
||||||
<div class="test-header">
|
<div class="test-header">
|
||||||
<h2>镜像配置测试页面</h2>
|
<div class="header-content">
|
||||||
<p>用于测试云端镜像配置拉取功能</p>
|
<div class="title-section">
|
||||||
|
<h2>镜像配置测试页面</h2>
|
||||||
|
<p>用于测试云端镜像配置拉取功能</p>
|
||||||
|
</div>
|
||||||
|
<a-button @click="goBack" size="large">
|
||||||
|
<template #icon>
|
||||||
|
<ArrowLeftOutlined />
|
||||||
|
</template>
|
||||||
|
返回设置
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="test-content">
|
<div class="test-content">
|
||||||
@@ -83,10 +93,14 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
|
import { ArrowLeftOutlined } from '@ant-design/icons-vue'
|
||||||
import { mirrorManager } from '@/utils/mirrorManager'
|
import { mirrorManager } from '@/utils/mirrorManager'
|
||||||
import { cloudConfigManager, type CloudMirrorConfig } from '@/utils/cloudConfigManager'
|
import { cloudConfigManager, type CloudMirrorConfig } from '@/utils/cloudConfigManager'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
interface TestLog {
|
interface TestLog {
|
||||||
time: string
|
time: string
|
||||||
message: string
|
message: string
|
||||||
@@ -196,6 +210,10 @@ const testCloudUrl = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.push('/settings')
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
updateStatus()
|
updateStatus()
|
||||||
addLog('镜像配置测试页面已加载', 'info')
|
addLog('镜像配置测试页面已加载', 'info')
|
||||||
@@ -210,10 +228,20 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.test-header {
|
.test-header {
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-section {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.test-header h2 {
|
.test-header h2 {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { goToLogs, openDevTools } = defineProps<{ goToLogs: () => void; openDevTools: () => void }>()
|
const {
|
||||||
|
goToLogs,
|
||||||
|
openDevTools,
|
||||||
|
mirrorConfigStatus,
|
||||||
|
refreshingConfig,
|
||||||
|
refreshMirrorConfig,
|
||||||
|
goToMirrorTest
|
||||||
|
} = defineProps<{
|
||||||
|
goToLogs: () => void
|
||||||
|
openDevTools: () => void
|
||||||
|
mirrorConfigStatus: { isUsingCloudConfig: boolean; version: string; lastUpdated: string; source: 'cloud' | 'fallback' }
|
||||||
|
refreshingConfig: boolean
|
||||||
|
refreshMirrorConfig: () => Promise<void>
|
||||||
|
goToMirrorTest: () => void
|
||||||
|
}>()
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
@@ -16,5 +30,45 @@ const { goToLogs, openDevTools } = defineProps<{ goToLogs: () => void; openDevTo
|
|||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3>镜像站配置</h3>
|
||||||
|
<p class="section-description">管理下载站和加速站配置,支持从云端自动更新最新的镜像站列表</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-row :gutter="24">
|
||||||
|
<a-col :span="24">
|
||||||
|
<div class="form-item-vertical">
|
||||||
|
<div class="form-label-wrapper">
|
||||||
|
<span class="form-label">配置管理</span>
|
||||||
|
</div>
|
||||||
|
<a-space size="large">
|
||||||
|
<a-button type="primary" @click="refreshMirrorConfig" :loading="refreshingConfig"
|
||||||
|
size="large">更新云端最新配置</a-button>
|
||||||
|
<a-button @click="goToMirrorTest" size="large">测试页面</a-button>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-row :gutter="24" style="margin-top: 24px;">
|
||||||
|
<a-col :span="24">
|
||||||
|
<div class="form-item-vertical">
|
||||||
|
<div class="form-label-wrapper">
|
||||||
|
<span class="form-label">说明</span>
|
||||||
|
</div>
|
||||||
|
<a-alert message="镜像配置说明" type="info" show-icon>
|
||||||
|
<template #description>
|
||||||
|
<ul style="margin:8px 0; padding-left:20px;">
|
||||||
|
<li>应用启动时会自动尝试从云端拉取最新的镜像站配置</li>
|
||||||
|
<li>可以手动点击"刷新云端配置"按钮获取最新配置</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
</a-alert>
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
const { mirrorConfigStatus, refreshingConfig, refreshMirrorConfig, goToMirrorTest } = defineProps<{
|
|
||||||
mirrorConfigStatus: { isUsingCloudConfig: boolean; version: string; lastUpdated: string; source: 'cloud' | 'fallback' }
|
|
||||||
refreshingConfig: boolean
|
|
||||||
refreshMirrorConfig: () => Promise<void>
|
|
||||||
goToMirrorTest: () => void
|
|
||||||
}>()
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<div class="tab-content">
|
|
||||||
<div class="form-section">
|
|
||||||
<div class="section-header">
|
|
||||||
<h3>镜像站配置</h3>
|
|
||||||
<p class="section-description">管理下载站和加速站配置,支持从云端自动更新最新的镜像站列表</p>
|
|
||||||
</div>
|
|
||||||
<a-row :gutter="24">
|
|
||||||
<a-col :span="24">
|
|
||||||
<div class="form-item-vertical">
|
|
||||||
<div class="form-label-wrapper">
|
|
||||||
<span class="form-label">配置状态</span>
|
|
||||||
</div>
|
|
||||||
<a-descriptions :column="1" bordered size="small">
|
|
||||||
<a-descriptions-item label="配置来源">
|
|
||||||
<a-tag :color="mirrorConfigStatus.source === 'cloud' ? 'green' : 'orange'">
|
|
||||||
{{ mirrorConfigStatus.source === 'cloud' ? '云端配置' : '本地兜底配置' }}
|
|
||||||
</a-tag>
|
|
||||||
</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="配置版本" v-if="mirrorConfigStatus.version">
|
|
||||||
{{ mirrorConfigStatus.version }}
|
|
||||||
</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="最后更新" v-if="mirrorConfigStatus.lastUpdated">
|
|
||||||
{{ new Date(mirrorConfigStatus.lastUpdated).toLocaleString() }}
|
|
||||||
</a-descriptions-item>
|
|
||||||
</a-descriptions>
|
|
||||||
</div>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
|
|
||||||
<a-row :gutter="24" style="margin-top:24px;">
|
|
||||||
<a-col :span="24">
|
|
||||||
<div class="form-item-vertical">
|
|
||||||
<div class="form-label-wrapper">
|
|
||||||
<span class="form-label">配置管理</span>
|
|
||||||
</div>
|
|
||||||
<a-space size="large">
|
|
||||||
<a-button type="primary" @click="refreshMirrorConfig" :loading="refreshingConfig" size="large">更新云端最新配置</a-button>
|
|
||||||
<a-button @click="goToMirrorTest" size="large">测试页面</a-button>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
|
|
||||||
<a-row :gutter="24" style="margin-top: 24px;">
|
|
||||||
<a-col :span="24">
|
|
||||||
<div class="form-item-vertical">
|
|
||||||
<div class="form-label-wrapper">
|
|
||||||
<span class="form-label">说明</span>
|
|
||||||
</div>
|
|
||||||
<a-alert message="镜像配置说明" type="info" show-icon>
|
|
||||||
<template #description>
|
|
||||||
<ul style="margin:8px 0; padding-left:20px;">
|
|
||||||
<li>应用启动时会自动尝试从云端拉取最新的镜像站配置</li>
|
|
||||||
<li>可以手动点击"刷新云端配置"按钮获取最新配置</li>
|
|
||||||
</ul>
|
|
||||||
</template>
|
|
||||||
</a-alert>
|
|
||||||
</div>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -22,7 +22,6 @@ import TabUpdate from './TabUpdate.vue'
|
|||||||
import TabStart from './TabStart.vue'
|
import TabStart from './TabStart.vue'
|
||||||
import TabVoice from './TabVoice.vue'
|
import TabVoice from './TabVoice.vue'
|
||||||
import TabAdvanced from './TabAdvanced.vue'
|
import TabAdvanced from './TabAdvanced.vue'
|
||||||
import TabMirrors from './TabMirrors.vue'
|
|
||||||
import TabOthers from './TabOthers.vue'
|
import TabOthers from './TabOthers.vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -308,11 +307,10 @@ onMounted(() => {
|
|||||||
<TabVoice :settings="settings" :voice-type-options="voiceTypeOptions" :handle-setting-change="handleSettingChange" />
|
<TabVoice :settings="settings" :voice-type-options="voiceTypeOptions" :handle-setting-change="handleSettingChange" />
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="advanced" tab="高级设置">
|
<a-tab-pane key="advanced" tab="高级设置">
|
||||||
<TabAdvanced :go-to-logs="goToLogs" :open-dev-tools="openDevTools" />
|
<TabAdvanced
|
||||||
</a-tab-pane>
|
:go-to-logs="goToLogs"
|
||||||
<a-tab-pane key="mirrors" tab="镜像配置">
|
:open-dev-tools="openDevTools"
|
||||||
<TabMirrors
|
:mirror-config-status="mirrorConfigStatus"
|
||||||
:mirror-config-status="mirrorConfigStatus.value"
|
|
||||||
:refreshing-config="refreshingConfig"
|
:refreshing-config="refreshingConfig"
|
||||||
:refresh-mirror-config="refreshMirrorConfig"
|
:refresh-mirror-config="refreshMirrorConfig"
|
||||||
:go-to-mirror-test="goToMirrorTest"
|
:go-to-mirror-test="goToMirrorTest"
|
||||||
|
|||||||
Reference in New Issue
Block a user