feat(initialization): 优化镜像源选择界面和逻辑,修改后端端口为36163
- 将镜像源按类型分组展示,增加官方源和推荐标签 - 实现按速度和推荐程度排序镜像源的功能 - 添加镜像源描述信息,提高用户体验 - 优化后端服务和 WebSocket 连接端口
This commit is contained in:
@@ -507,7 +507,7 @@ export async function startBackend(appRoot: string): Promise<{ success: boolean;
|
|||||||
console.log('Backend output:', output)
|
console.log('Backend output:', output)
|
||||||
|
|
||||||
// 检查是否包含启动成功的标志
|
// 检查是否包含启动成功的标志
|
||||||
if (output.includes('Uvicorn running') || output.includes('8000')) {
|
if (output.includes('Uvicorn running') || output.includes('36163')) {
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
@@ -519,7 +519,7 @@ export async function startBackend(appRoot: string): Promise<{ success: boolean;
|
|||||||
console.error('Backend error:', output) // 保留原有日志
|
console.error('Backend error:', output) // 保留原有日志
|
||||||
|
|
||||||
// ✅ 在 stderr 中也检查启动标志
|
// ✅ 在 stderr 中也检查启动标志
|
||||||
if (output.includes('Uvicorn running') || output.includes('8000')) {
|
if (output.includes('Uvicorn running') || output.includes('36163')) {
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,25 @@
|
|||||||
<div class="install-section">
|
<div class="install-section">
|
||||||
<p>{{ backendExists ? '更新最新的后端代码' : '获取后端源代码' }}</p>
|
<p>{{ backendExists ? '更新最新的后端代码' : '获取后端源代码' }}</p>
|
||||||
|
|
||||||
|
<!-- 镜像源 -->
|
||||||
|
<div class="mirror-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h4>镜像源</h4>
|
||||||
|
<a-tag color="green">推荐使用</a-tag>
|
||||||
|
</div>
|
||||||
<div class="mirror-grid">
|
<div class="mirror-grid">
|
||||||
<div
|
<div
|
||||||
v-for="mirror in gitMirrors"
|
v-for="mirror in sortedMirrorMirrors"
|
||||||
:key="mirror.key"
|
:key="mirror.key"
|
||||||
class="mirror-card"
|
class="mirror-card"
|
||||||
:class="{ active: selectedGitMirror === mirror.key }"
|
:class="{ active: selectedGitMirror === mirror.key }"
|
||||||
@click="selectedGitMirror = mirror.key"
|
@click="selectedGitMirror = mirror.key"
|
||||||
>
|
>
|
||||||
<div class="mirror-header">
|
<div class="mirror-header">
|
||||||
|
<div class="mirror-title">
|
||||||
<h4>{{ mirror.name }}</h4>
|
<h4>{{ mirror.name }}</h4>
|
||||||
|
<a-tag v-if="mirror.recommended" color="gold" size="small">推荐</a-tag>
|
||||||
|
</div>
|
||||||
<div class="speed-badge" :class="getSpeedClass(mirror.speed)">
|
<div class="speed-badge" :class="getSpeedClass(mirror.speed)">
|
||||||
<span v-if="mirror.speed === null && !testingGitSpeed">未测试</span>
|
<span v-if="mirror.speed === null && !testingGitSpeed">未测试</span>
|
||||||
<span v-else-if="testingGitSpeed">测试中...</span>
|
<span v-else-if="testingGitSpeed">测试中...</span>
|
||||||
@@ -21,9 +30,42 @@
|
|||||||
<span v-else>{{ mirror.speed }}ms</span>
|
<span v-else>{{ mirror.speed }}ms</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mirror-description">{{ mirror.description }}</div>
|
||||||
<div class="mirror-url">{{ mirror.url }}</div>
|
<div class="mirror-url">{{ mirror.url }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 官方源 -->
|
||||||
|
<div class="mirror-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h4>官方源</h4>
|
||||||
|
<a-tag color="orange">中国大陆连通性不佳</a-tag>
|
||||||
|
</div>
|
||||||
|
<div class="mirror-grid">
|
||||||
|
<div
|
||||||
|
v-for="mirror in sortedOfficialMirrors"
|
||||||
|
:key="mirror.key"
|
||||||
|
class="mirror-card"
|
||||||
|
:class="{ active: selectedGitMirror === mirror.key }"
|
||||||
|
@click="selectedGitMirror = mirror.key"
|
||||||
|
>
|
||||||
|
<div class="mirror-header">
|
||||||
|
<div class="mirror-title">
|
||||||
|
<h4>{{ mirror.name }}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="speed-badge" :class="getSpeedClass(mirror.speed)">
|
||||||
|
<span v-if="mirror.speed === null && !testingGitSpeed">未测试</span>
|
||||||
|
<span v-else-if="testingGitSpeed">测试中...</span>
|
||||||
|
<span v-else-if="mirror.speed === 9999">超时</span>
|
||||||
|
<span v-else>{{ mirror.speed }}ms</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mirror-description">{{ mirror.description }}</div>
|
||||||
|
<div class="mirror-url">{{ mirror.url }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="test-actions">
|
<div class="test-actions">
|
||||||
<a-button @click="testGitMirrorSpeed" :loading="testingGitSpeed" type="primary">
|
<a-button @click="testGitMirrorSpeed" :loading="testingGitSpeed" type="primary">
|
||||||
@@ -36,25 +78,31 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { getConfig, saveConfig } from '@/utils/config'
|
import { getConfig, saveConfig } from '@/utils/config'
|
||||||
|
import {
|
||||||
interface Mirror {
|
GIT_MIRRORS,
|
||||||
key: string
|
getOfficialMirrors,
|
||||||
name: string
|
getMirrorMirrors,
|
||||||
url: string
|
sortMirrorsBySpeedAndRecommendation,
|
||||||
speed: number | null
|
type MirrorConfig
|
||||||
}
|
} from '@/config/mirrors'
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
backendExists: boolean
|
backendExists: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
import { GIT_MIRRORS } from '@/config/mirrors'
|
const gitMirrors = ref<MirrorConfig[]>(GIT_MIRRORS)
|
||||||
|
|
||||||
const gitMirrors = ref<Mirror[]>(GIT_MIRRORS)
|
// 按类型分组的镜像源
|
||||||
|
const officialMirrors = computed(() => getOfficialMirrors('git'))
|
||||||
|
const mirrorMirrors = computed(() => getMirrorMirrors('git'))
|
||||||
|
|
||||||
const selectedGitMirror = ref('github')
|
// 按速度和推荐排序的镜像源
|
||||||
|
const sortedOfficialMirrors = computed(() => sortMirrorsBySpeedAndRecommendation(officialMirrors.value))
|
||||||
|
const sortedMirrorMirrors = computed(() => sortMirrorsBySpeedAndRecommendation(mirrorMirrors.value))
|
||||||
|
|
||||||
|
const selectedGitMirror = ref('ghproxy_edgeone')
|
||||||
const testingGitSpeed = ref(false)
|
const testingGitSpeed = ref(false)
|
||||||
|
|
||||||
// 加载配置中的镜像源选择
|
// 加载配置中的镜像源选择
|
||||||
@@ -107,9 +155,10 @@ async function testGitMirrorSpeed() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
gitMirrors.value.sort((a, b) => (a.speed || 9999) - (b.speed || 9999))
|
|
||||||
|
|
||||||
const fastest = gitMirrors.value.find(m => m.speed !== 9999)
|
// 优先选择推荐的且速度最快的镜像源
|
||||||
|
const sortedMirrors = sortMirrorsBySpeedAndRecommendation(gitMirrors.value)
|
||||||
|
const fastest = sortedMirrors.find(m => m.speed !== 9999)
|
||||||
if (fastest) {
|
if (fastest) {
|
||||||
selectedGitMirror.value = fastest.key
|
selectedGitMirror.value = fastest.key
|
||||||
await saveMirrorConfig() // 保存最快的镜像源选择
|
await saveMirrorConfig() // 保存最快的镜像源选择
|
||||||
@@ -204,6 +253,12 @@ onMounted(async () => {
|
|||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mirror-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.mirror-header h4 {
|
.mirror-header h4 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -211,6 +266,8 @@ onMounted(async () => {
|
|||||||
color: var(--ant-color-text);
|
color: var(--ant-color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.speed-badge {
|
.speed-badge {
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -238,12 +295,37 @@ onMounted(async () => {
|
|||||||
color: var(--ant-color-error);
|
color: var(--ant-color-error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mirror-description {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--ant-color-text-secondary);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
.mirror-url {
|
.mirror-url {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--ant-color-text-tertiary);
|
color: var(--ant-color-text-tertiary);
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mirror-section {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header h4 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--ant-color-text);
|
||||||
|
}
|
||||||
|
|
||||||
.test-actions {
|
.test-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -4,16 +4,25 @@
|
|||||||
<div class="install-section">
|
<div class="install-section">
|
||||||
<p>通过 pip 安装项目所需的 Python 依赖包</p>
|
<p>通过 pip 安装项目所需的 Python 依赖包</p>
|
||||||
|
|
||||||
|
<!-- 镜像源 -->
|
||||||
|
<div class="mirror-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h4>镜像源</h4>
|
||||||
|
<a-tag color="green">推荐使用</a-tag>
|
||||||
|
</div>
|
||||||
<div class="mirror-grid">
|
<div class="mirror-grid">
|
||||||
<div
|
<div
|
||||||
v-for="mirror in pipMirrors"
|
v-for="mirror in sortedMirrorMirrors"
|
||||||
:key="mirror.key"
|
:key="mirror.key"
|
||||||
class="mirror-card"
|
class="mirror-card"
|
||||||
:class="{ active: selectedPipMirror === mirror.key }"
|
:class="{ active: selectedPipMirror === mirror.key }"
|
||||||
@click="selectedPipMirror = mirror.key"
|
@click="selectedPipMirror = mirror.key"
|
||||||
>
|
>
|
||||||
<div class="mirror-header">
|
<div class="mirror-header">
|
||||||
|
<div class="mirror-title">
|
||||||
<h4>{{ mirror.name }}</h4>
|
<h4>{{ mirror.name }}</h4>
|
||||||
|
<a-tag v-if="mirror.recommended" color="gold" size="small">推荐</a-tag>
|
||||||
|
</div>
|
||||||
<div class="speed-badge" :class="getSpeedClass(mirror.speed)">
|
<div class="speed-badge" :class="getSpeedClass(mirror.speed)">
|
||||||
<span v-if="mirror.speed === null && !testingPipSpeed">未测试</span>
|
<span v-if="mirror.speed === null && !testingPipSpeed">未测试</span>
|
||||||
<span v-else-if="testingPipSpeed">测试中...</span>
|
<span v-else-if="testingPipSpeed">测试中...</span>
|
||||||
@@ -21,9 +30,42 @@
|
|||||||
<span v-else>{{ mirror.speed }}ms</span>
|
<span v-else>{{ mirror.speed }}ms</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mirror-description">{{ mirror.description }}</div>
|
||||||
<div class="mirror-url">{{ mirror.url }}</div>
|
<div class="mirror-url">{{ mirror.url }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 官方源 -->
|
||||||
|
<div class="mirror-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h4>官方源</h4>
|
||||||
|
<a-tag color="orange">中国大陆连通性不佳</a-tag>
|
||||||
|
</div>
|
||||||
|
<div class="mirror-grid">
|
||||||
|
<div
|
||||||
|
v-for="mirror in sortedOfficialMirrors"
|
||||||
|
:key="mirror.key"
|
||||||
|
class="mirror-card"
|
||||||
|
:class="{ active: selectedPipMirror === mirror.key }"
|
||||||
|
@click="selectedPipMirror = mirror.key"
|
||||||
|
>
|
||||||
|
<div class="mirror-header">
|
||||||
|
<div class="mirror-title">
|
||||||
|
<h4>{{ mirror.name }}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="speed-badge" :class="getSpeedClass(mirror.speed)">
|
||||||
|
<span v-if="mirror.speed === null && !testingPipSpeed">未测试</span>
|
||||||
|
<span v-else-if="testingPipSpeed">测试中...</span>
|
||||||
|
<span v-else-if="mirror.speed === 9999">超时</span>
|
||||||
|
<span v-else>{{ mirror.speed }}ms</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mirror-description">{{ mirror.description }}</div>
|
||||||
|
<div class="mirror-url">{{ mirror.url }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="test-actions">
|
<div class="test-actions">
|
||||||
<a-button @click="testPipMirrorSpeed" :loading="testingPipSpeed" type="primary">
|
<a-button @click="testPipMirrorSpeed" :loading="testingPipSpeed" type="primary">
|
||||||
@@ -36,21 +78,27 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { getConfig, saveConfig } from '@/utils/config'
|
import { getConfig, saveConfig } from '@/utils/config'
|
||||||
|
import {
|
||||||
|
PIP_MIRRORS,
|
||||||
|
getOfficialMirrors,
|
||||||
|
getMirrorMirrors,
|
||||||
|
sortMirrorsBySpeedAndRecommendation,
|
||||||
|
type MirrorConfig
|
||||||
|
} from '@/config/mirrors'
|
||||||
|
|
||||||
interface Mirror {
|
const pipMirrors = ref<MirrorConfig[]>(PIP_MIRRORS)
|
||||||
key: string
|
|
||||||
name: string
|
|
||||||
url: string
|
|
||||||
speed: number | null
|
|
||||||
}
|
|
||||||
|
|
||||||
import { PIP_MIRRORS } from '@/config/mirrors'
|
// 按类型分组的镜像源
|
||||||
|
const officialMirrors = computed(() => getOfficialMirrors('pip'))
|
||||||
|
const mirrorMirrors = computed(() => getMirrorMirrors('pip'))
|
||||||
|
|
||||||
const pipMirrors = ref<Mirror[]>(PIP_MIRRORS)
|
// 按速度和推荐排序的镜像源
|
||||||
|
const sortedOfficialMirrors = computed(() => sortMirrorsBySpeedAndRecommendation(officialMirrors.value))
|
||||||
|
const sortedMirrorMirrors = computed(() => sortMirrorsBySpeedAndRecommendation(mirrorMirrors.value))
|
||||||
|
|
||||||
const selectedPipMirror = ref('tsinghua')
|
const selectedPipMirror = ref('aliyun')
|
||||||
const testingPipSpeed = ref(false)
|
const testingPipSpeed = ref(false)
|
||||||
|
|
||||||
// 加载配置中的镜像源选择
|
// 加载配置中的镜像源选择
|
||||||
@@ -103,9 +151,10 @@ async function testPipMirrorSpeed() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
pipMirrors.value.sort((a, b) => (a.speed || 9999) - (b.speed || 9999))
|
|
||||||
|
|
||||||
const fastest = pipMirrors.value.find(m => m.speed !== 9999)
|
// 优先选择推荐的且速度最快的镜像源
|
||||||
|
const sortedMirrors = sortMirrorsBySpeedAndRecommendation(pipMirrors.value)
|
||||||
|
const fastest = sortedMirrors.find(m => m.speed !== 9999)
|
||||||
if (fastest) {
|
if (fastest) {
|
||||||
selectedPipMirror.value = fastest.key
|
selectedPipMirror.value = fastest.key
|
||||||
await saveMirrorConfig() // 保存最快的镜像源选择
|
await saveMirrorConfig() // 保存最快的镜像源选择
|
||||||
@@ -199,6 +248,12 @@ onMounted(async () => {
|
|||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mirror-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.mirror-header h4 {
|
.mirror-header h4 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -206,6 +261,8 @@ onMounted(async () => {
|
|||||||
color: var(--ant-color-text);
|
color: var(--ant-color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.speed-badge {
|
.speed-badge {
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -233,12 +290,37 @@ onMounted(async () => {
|
|||||||
color: var(--ant-color-error);
|
color: var(--ant-color-error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mirror-description {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--ant-color-text-secondary);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
.mirror-url {
|
.mirror-url {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--ant-color-text-tertiary);
|
color: var(--ant-color-text-tertiary);
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mirror-section {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header h4 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--ant-color-text);
|
||||||
|
}
|
||||||
|
|
||||||
.test-actions {
|
.test-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -4,16 +4,25 @@
|
|||||||
<div v-if="!pythonInstalled" class="install-section">
|
<div v-if="!pythonInstalled" class="install-section">
|
||||||
<p>需要安装 Python 3.13.0 运行环境(64位嵌入式版本)</p>
|
<p>需要安装 Python 3.13.0 运行环境(64位嵌入式版本)</p>
|
||||||
|
|
||||||
|
<!-- 镜像源 -->
|
||||||
|
<div class="mirror-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h4>镜像源</h4>
|
||||||
|
<a-tag color="green">推荐使用</a-tag>
|
||||||
|
</div>
|
||||||
<div class="mirror-grid">
|
<div class="mirror-grid">
|
||||||
<div
|
<div
|
||||||
v-for="mirror in pythonMirrors"
|
v-for="mirror in sortedMirrorMirrors"
|
||||||
:key="mirror.key"
|
:key="mirror.key"
|
||||||
class="mirror-card"
|
class="mirror-card"
|
||||||
:class="{ active: selectedPythonMirror === mirror.key }"
|
:class="{ active: selectedPythonMirror === mirror.key }"
|
||||||
@click="selectedPythonMirror = mirror.key"
|
@click="selectedPythonMirror = mirror.key"
|
||||||
>
|
>
|
||||||
<div class="mirror-header">
|
<div class="mirror-header">
|
||||||
|
<div class="mirror-title">
|
||||||
<h4>{{ mirror.name }}</h4>
|
<h4>{{ mirror.name }}</h4>
|
||||||
|
<a-tag v-if="mirror.recommended" color="gold" size="small">推荐</a-tag>
|
||||||
|
</div>
|
||||||
<div class="speed-badge" :class="getSpeedClass(mirror.speed)">
|
<div class="speed-badge" :class="getSpeedClass(mirror.speed)">
|
||||||
<span v-if="mirror.speed === null && !testingSpeed">未测试</span>
|
<span v-if="mirror.speed === null && !testingSpeed">未测试</span>
|
||||||
<span v-else-if="testingSpeed">测试中...</span>
|
<span v-else-if="testingSpeed">测试中...</span>
|
||||||
@@ -21,9 +30,42 @@
|
|||||||
<span v-else>{{ mirror.speed }}ms</span>
|
<span v-else>{{ mirror.speed }}ms</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mirror-description">{{ mirror.description }}</div>
|
||||||
<div class="mirror-url">{{ mirror.url }}</div>
|
<div class="mirror-url">{{ mirror.url }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 官方源 -->
|
||||||
|
<div class="mirror-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h4>官方源</h4>
|
||||||
|
<a-tag color="orange">中国大陆连通性不佳</a-tag>
|
||||||
|
</div>
|
||||||
|
<div class="mirror-grid">
|
||||||
|
<div
|
||||||
|
v-for="mirror in sortedOfficialMirrors"
|
||||||
|
:key="mirror.key"
|
||||||
|
class="mirror-card"
|
||||||
|
:class="{ active: selectedPythonMirror === mirror.key }"
|
||||||
|
@click="selectedPythonMirror = mirror.key"
|
||||||
|
>
|
||||||
|
<div class="mirror-header">
|
||||||
|
<div class="mirror-title">
|
||||||
|
<h4>{{ mirror.name }}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="speed-badge" :class="getSpeedClass(mirror.speed)">
|
||||||
|
<span v-if="mirror.speed === null && !testingSpeed">未测试</span>
|
||||||
|
<span v-else-if="testingSpeed">测试中...</span>
|
||||||
|
<span v-else-if="mirror.speed === 9999">超时</span>
|
||||||
|
<span v-else>{{ mirror.speed }}ms</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mirror-description">{{ mirror.description }}</div>
|
||||||
|
<div class="mirror-url">{{ mirror.url }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="test-actions">
|
<div class="test-actions">
|
||||||
<a-button @click="testPythonMirrorSpeed" :loading="testingSpeed" type="primary">
|
<a-button @click="testPythonMirrorSpeed" :loading="testingSpeed" type="primary">
|
||||||
@@ -45,25 +87,31 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { getConfig, saveConfig } from '@/utils/config'
|
import { getConfig, saveConfig } from '@/utils/config'
|
||||||
|
import {
|
||||||
interface Mirror {
|
PYTHON_MIRRORS,
|
||||||
key: string
|
getOfficialMirrors,
|
||||||
name: string
|
getMirrorMirrors,
|
||||||
url: string
|
sortMirrorsBySpeedAndRecommendation,
|
||||||
speed: number | null
|
type MirrorConfig
|
||||||
}
|
} from '@/config/mirrors'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
pythonInstalled: boolean
|
pythonInstalled: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
import { PYTHON_MIRRORS } from '@/config/mirrors'
|
const pythonMirrors = ref<MirrorConfig[]>(PYTHON_MIRRORS)
|
||||||
|
|
||||||
const pythonMirrors = ref<Mirror[]>(PYTHON_MIRRORS)
|
// 按类型分组的镜像源
|
||||||
|
const officialMirrors = computed(() => getOfficialMirrors('python'))
|
||||||
|
const mirrorMirrors = computed(() => getMirrorMirrors('python'))
|
||||||
|
|
||||||
const selectedPythonMirror = ref('tsinghua')
|
// 按速度和推荐排序的镜像源
|
||||||
|
const sortedOfficialMirrors = computed(() => sortMirrorsBySpeedAndRecommendation(officialMirrors.value))
|
||||||
|
const sortedMirrorMirrors = computed(() => sortMirrorsBySpeedAndRecommendation(mirrorMirrors.value))
|
||||||
|
|
||||||
|
const selectedPythonMirror = ref('aliyun')
|
||||||
const testingSpeed = ref(false)
|
const testingSpeed = ref(false)
|
||||||
const reinstalling = ref(false)
|
const reinstalling = ref(false)
|
||||||
|
|
||||||
@@ -118,9 +166,9 @@ async function testPythonMirrorSpeed() {
|
|||||||
|
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
|
|
||||||
pythonMirrors.value.sort((a, b) => (a.speed || 9999) - (b.speed || 9999))
|
// 优先选择推荐的且速度最快的镜像源
|
||||||
|
const sortedMirrors = sortMirrorsBySpeedAndRecommendation(pythonMirrors.value)
|
||||||
const fastest = pythonMirrors.value.find(m => m.speed !== 9999)
|
const fastest = sortedMirrors.find(m => m.speed !== 9999)
|
||||||
if (fastest) {
|
if (fastest) {
|
||||||
selectedPythonMirror.value = fastest.key
|
selectedPythonMirror.value = fastest.key
|
||||||
await saveMirrorConfig() // 保存最快的镜像源选择
|
await saveMirrorConfig() // 保存最快的镜像源选择
|
||||||
@@ -245,6 +293,12 @@ onMounted(async () => {
|
|||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mirror-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.mirror-header h4 {
|
.mirror-header h4 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -252,6 +306,8 @@ onMounted(async () => {
|
|||||||
color: var(--ant-color-text);
|
color: var(--ant-color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.speed-badge {
|
.speed-badge {
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -284,12 +340,37 @@ onMounted(async () => {
|
|||||||
color: var(--ant-color-error);
|
color: var(--ant-color-error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mirror-description {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--ant-color-text-secondary);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
.mirror-url {
|
.mirror-url {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--ant-color-text-tertiary);
|
color: var(--ant-color-text-tertiary);
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mirror-section {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header h4 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--ant-color-text);
|
||||||
|
}
|
||||||
|
|
||||||
.test-actions {
|
.test-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export function useWebSocket() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const websocketId = response.websocketId
|
const websocketId = response.websocketId
|
||||||
const wsUrl = `ws://localhost:8000/api/dispatch/ws/${websocketId}`
|
const wsUrl = `ws://localhost:36163/api/dispatch/ws/${websocketId}`
|
||||||
|
|
||||||
// 建立WebSocket连接
|
// 建立WebSocket连接
|
||||||
const ws = new WebSocket(wsUrl)
|
const ws = new WebSocket(wsUrl)
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ export interface MirrorConfig {
|
|||||||
name: string
|
name: string
|
||||||
url: string
|
url: string
|
||||||
speed?: number | null
|
speed?: number | null
|
||||||
|
type: 'official' | 'mirror'
|
||||||
|
chinaConnectivity?: 'poor' | 'good' | 'excellent'
|
||||||
|
description?: string
|
||||||
|
recommended?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MirrorCategory {
|
export interface MirrorCategory {
|
||||||
@@ -15,105 +19,192 @@ export interface MirrorCategory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Git 仓库镜像源配置
|
* Git 仓库官方源配置
|
||||||
*/
|
*/
|
||||||
export const GIT_MIRRORS: MirrorConfig[] = [
|
export const GIT_OFFICIAL_MIRRORS: MirrorConfig[] = [
|
||||||
{
|
{
|
||||||
key: 'github',
|
key: 'github',
|
||||||
name: 'GitHub 官方',
|
name: 'GitHub 官方',
|
||||||
url: 'https://github.com/DLmaster361/AUTO_MAA.git',
|
url: 'https://github.com/DLmaster361/AUTO_MAA.git',
|
||||||
speed: null,
|
speed: null,
|
||||||
|
type: 'official',
|
||||||
|
chinaConnectivity: 'poor',
|
||||||
|
description: '官方源,在中国大陆连通性不佳,可能需要科学上网',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Git 仓库镜像源配置
|
||||||
|
*/
|
||||||
|
export const GIT_MIRROR_MIRRORS: MirrorConfig[] = [
|
||||||
|
{
|
||||||
|
key: 'ghproxy_cloudflare',
|
||||||
|
name: 'gh-proxy (Cloudflare)',
|
||||||
|
url: 'https://gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git',
|
||||||
|
speed: null,
|
||||||
|
type: 'mirror',
|
||||||
|
chinaConnectivity: 'good',
|
||||||
|
description: 'Cloudflare CDN 镜像,适合全球用户',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'ghproxy_hongkong',
|
||||||
|
name: 'gh-proxy (香港节点)',
|
||||||
|
url: 'https://hk.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git',
|
||||||
|
speed: null,
|
||||||
|
type: 'mirror',
|
||||||
|
chinaConnectivity: 'excellent',
|
||||||
|
description: '香港节点镜像,对中国大陆用户友好',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'ghproxy_fastly',
|
||||||
|
name: 'gh-proxy (Fastly CDN)',
|
||||||
|
url: 'https://cdn.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git',
|
||||||
|
speed: null,
|
||||||
|
type: 'mirror',
|
||||||
|
chinaConnectivity: 'good',
|
||||||
|
description: 'Fastly CDN 镜像服务',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'ghproxy_edgeone',
|
||||||
|
name: 'gh-proxy (EdgeOne)',
|
||||||
|
url: 'https://edgeone.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git',
|
||||||
|
speed: null,
|
||||||
|
type: 'mirror',
|
||||||
|
chinaConnectivity: 'good',
|
||||||
|
description: 'EdgeOne 镜像服务',
|
||||||
|
recommended: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'ghfast',
|
key: 'ghfast',
|
||||||
name: 'ghfast 镜像',
|
name: 'ghfast 镜像',
|
||||||
url: 'https://ghfast.top/https://github.com/DLmaster361/AUTO_MAA.git',
|
url: 'https://ghfast.top/https://github.com/DLmaster361/AUTO_MAA.git',
|
||||||
speed: null,
|
speed: null,
|
||||||
},
|
type: 'mirror',
|
||||||
{
|
chinaConnectivity: 'good',
|
||||||
key: 'ghproxy_cloudflare',
|
description: '第三方镜像服务',
|
||||||
name: 'gh-proxy (Cloudflare加速)',
|
|
||||||
url: 'https://gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git',
|
|
||||||
speed: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'ghproxy_hongkong',
|
|
||||||
name: 'gh-proxy (香港节点加速)',
|
|
||||||
url: 'https://hk.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git',
|
|
||||||
speed: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'ghproxy_fastly',
|
|
||||||
name: 'gh-proxy (Fastly CDN加速)',
|
|
||||||
url: 'https://cdn.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git',
|
|
||||||
speed: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'ghproxy_edgeone',
|
|
||||||
name: 'gh-proxy (EdgeOne加速)',
|
|
||||||
url: 'https://edgeone.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git',
|
|
||||||
speed: null,
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Python 下载镜像源配置(3.12.0 embed版本)
|
* Git 仓库所有镜像源配置(按类型分组)
|
||||||
*/
|
*/
|
||||||
export const PYTHON_MIRRORS: MirrorConfig[] = [
|
export const GIT_MIRRORS: MirrorConfig[] = [
|
||||||
|
...GIT_MIRROR_MIRRORS,
|
||||||
|
...GIT_OFFICIAL_MIRRORS,
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Python 官方源配置(3.12.0 embed版本)
|
||||||
|
*/
|
||||||
|
export const PYTHON_OFFICIAL_MIRRORS: MirrorConfig[] = [
|
||||||
{
|
{
|
||||||
key: 'official',
|
key: 'official',
|
||||||
name: 'Python 官方',
|
name: 'Python 官方',
|
||||||
url: 'https://www.python.org/ftp/python/3.12.0/python-3.12.0-embed-amd64.zip',
|
url: 'https://www.python.org/ftp/python/3.12.0/python-3.12.0-embed-amd64.zip',
|
||||||
speed: null,
|
speed: null,
|
||||||
|
type: 'official',
|
||||||
|
chinaConnectivity: 'poor',
|
||||||
|
description: 'Python 官方下载源,在中国大陆连通性不佳',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Python 镜像源配置(3.12.0 embed版本)
|
||||||
|
*/
|
||||||
|
export const PYTHON_MIRROR_MIRRORS: MirrorConfig[] = [
|
||||||
|
{
|
||||||
|
key: 'aliyun',
|
||||||
|
name: '阿里云镜像',
|
||||||
|
url: 'https://mirrors.aliyun.com/python-release/windows/python-3.12.0-embed-amd64.zip',
|
||||||
|
speed: null,
|
||||||
|
type: 'mirror',
|
||||||
|
chinaConnectivity: 'excellent',
|
||||||
|
description: '阿里云镜像服务,国内访问速度快',
|
||||||
|
recommended: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'tsinghua',
|
key: 'tsinghua',
|
||||||
name: '清华 TUNA 镜像',
|
name: '清华 TUNA 镜像',
|
||||||
url: 'https://mirrors.tuna.tsinghua.edu.cn/python/3.12.0/python-3.12.0-embed-amd64.zip',
|
url: 'https://mirrors.tuna.tsinghua.edu.cn/python/3.12.0/python-3.12.0-embed-amd64.zip',
|
||||||
speed: null,
|
speed: null,
|
||||||
|
type: 'mirror',
|
||||||
|
chinaConnectivity: 'excellent',
|
||||||
|
description: '清华大学开源软件镜像站,国内访问速度快',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'huawei',
|
key: 'huawei',
|
||||||
name: '华为云镜像',
|
name: '华为云镜像',
|
||||||
url: 'https://mirrors.huaweicloud.com/repository/toolkit/python/3.12.0/python-3.12.0-embed-amd64.zip',
|
url: 'https://mirrors.huaweicloud.com/repository/toolkit/python/3.12.0/python-3.12.0-embed-amd64.zip',
|
||||||
speed: null,
|
speed: null,
|
||||||
|
type: 'mirror',
|
||||||
|
chinaConnectivity: 'excellent',
|
||||||
|
description: '华为云镜像服务,国内访问稳定',
|
||||||
},
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Python 下载所有镜像源配置(按类型分组)
|
||||||
|
*/
|
||||||
|
export const PYTHON_MIRRORS: MirrorConfig[] = [
|
||||||
|
...PYTHON_MIRROR_MIRRORS,
|
||||||
|
...PYTHON_OFFICIAL_MIRRORS,
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PyPI pip 官方源配置
|
||||||
|
*/
|
||||||
|
export const PIP_OFFICIAL_MIRRORS: MirrorConfig[] = [
|
||||||
{
|
{
|
||||||
key: 'aliyun',
|
key: 'official',
|
||||||
name: '阿里云镜像',
|
name: 'PyPI 官方',
|
||||||
url: 'https://mirrors.aliyun.com/python-release/windows/python-3.12.0-embed-amd64.zip',
|
url: 'https://pypi.org/simple/',
|
||||||
speed: null,
|
speed: null,
|
||||||
|
type: 'official',
|
||||||
|
chinaConnectivity: 'poor',
|
||||||
|
description: 'PyPI 官方源,在中国大陆连通性不佳,下载速度慢',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PyPI pip 镜像源配置
|
* PyPI pip 镜像源配置
|
||||||
*/
|
*/
|
||||||
export const PIP_MIRRORS: MirrorConfig[] = [
|
export const PIP_MIRROR_MIRRORS: MirrorConfig[] = [
|
||||||
{
|
{
|
||||||
key: 'official',
|
key: 'aliyun',
|
||||||
name: 'PyPI 官方',
|
name: '阿里云',
|
||||||
url: 'https://pypi.org/simple/',
|
url: 'https://mirrors.aliyun.com/pypi/simple/',
|
||||||
speed: null,
|
speed: null,
|
||||||
|
type: 'mirror',
|
||||||
|
chinaConnectivity: 'excellent',
|
||||||
|
description: '阿里云 PyPI 镜像,国内访问速度快',
|
||||||
|
recommended: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'tsinghua',
|
key: 'tsinghua',
|
||||||
name: '清华大学',
|
name: '清华大学',
|
||||||
url: 'https://pypi.tuna.tsinghua.edu.cn/simple/',
|
url: 'https://pypi.tuna.tsinghua.edu.cn/simple/',
|
||||||
speed: null,
|
speed: null,
|
||||||
|
type: 'mirror',
|
||||||
|
chinaConnectivity: 'excellent',
|
||||||
|
description: '清华大学 PyPI 镜像,国内访问速度快',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'ustc',
|
key: 'ustc',
|
||||||
name: '中科大',
|
name: '中科大',
|
||||||
url: 'https://pypi.mirrors.ustc.edu.cn/simple/',
|
url: 'https://pypi.mirrors.ustc.edu.cn/simple/',
|
||||||
speed: null,
|
speed: null,
|
||||||
|
type: 'mirror',
|
||||||
|
chinaConnectivity: 'excellent',
|
||||||
|
description: '中科大 PyPI 镜像,国内访问稳定',
|
||||||
},
|
},
|
||||||
{
|
]
|
||||||
key: 'aliyun',
|
|
||||||
name: '阿里云',
|
/**
|
||||||
url: 'https://mirrors.aliyun.com/pypi/simple/',
|
* PyPI pip 所有镜像源配置(按类型分组)
|
||||||
speed: null,
|
*/
|
||||||
},
|
export const PIP_MIRRORS: MirrorConfig[] = [
|
||||||
|
...PIP_MIRROR_MIRRORS,
|
||||||
|
...PIP_OFFICIAL_MIRRORS,
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -121,9 +212,9 @@ export const PIP_MIRRORS: MirrorConfig[] = [
|
|||||||
*/
|
*/
|
||||||
export const API_ENDPOINTS = {
|
export const API_ENDPOINTS = {
|
||||||
// 本地开发服务器
|
// 本地开发服务器
|
||||||
local: 'http://localhost:8000',
|
local: 'http://localhost:36163',
|
||||||
// WebSocket连接基础URL
|
// WebSocket连接基础URL
|
||||||
websocket: 'ws://localhost:8000',
|
websocket: 'ws://localhost:36163',
|
||||||
// 代理服务器示例
|
// 代理服务器示例
|
||||||
proxy: 'http://127.0.0.1:7890',
|
proxy: 'http://127.0.0.1:7890',
|
||||||
}
|
}
|
||||||
@@ -202,3 +293,71 @@ export function getFastestMirror(type: keyof MirrorCategory): MirrorConfig | nul
|
|||||||
const sortedMirrors = sortMirrorsBySpeed(mirrors)
|
const sortedMirrors = sortMirrorsBySpeed(mirrors)
|
||||||
return sortedMirrors.find(m => m.speed !== null && m.speed !== 9999) || null
|
return sortedMirrors.find(m => m.speed !== null && m.speed !== 9999) || null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据类型筛选镜像源
|
||||||
|
*/
|
||||||
|
export function getMirrorsBySourceType(
|
||||||
|
type: keyof MirrorCategory,
|
||||||
|
sourceType: 'official' | 'mirror'
|
||||||
|
): MirrorConfig[] {
|
||||||
|
const mirrors = getMirrorsByType(type)
|
||||||
|
return mirrors.filter(m => m.type === sourceType)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取官方源(标注中国大陆连通性)
|
||||||
|
*/
|
||||||
|
export function getOfficialMirrors(type: keyof MirrorCategory): MirrorConfig[] {
|
||||||
|
return getMirrorsBySourceType(type, 'official')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取镜像源
|
||||||
|
*/
|
||||||
|
export function getMirrorMirrors(type: keyof MirrorCategory): MirrorConfig[] {
|
||||||
|
return getMirrorsBySourceType(type, 'mirror')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取推荐的镜像源
|
||||||
|
*/
|
||||||
|
export function getRecommendedMirrors(type: keyof MirrorCategory): MirrorConfig[] {
|
||||||
|
const mirrors = getMirrorsByType(type)
|
||||||
|
return mirrors.filter(m => m.recommended === true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据速度排序镜像源(推荐的排在前面)
|
||||||
|
*/
|
||||||
|
export function sortMirrorsBySpeedAndRecommendation(mirrors: MirrorConfig[]): MirrorConfig[] {
|
||||||
|
return [...mirrors].sort((a, b) => {
|
||||||
|
// 推荐的排在前面
|
||||||
|
if (a.recommended && !b.recommended) return -1
|
||||||
|
if (!a.recommended && b.recommended) return 1
|
||||||
|
|
||||||
|
// 然后按速度排序
|
||||||
|
const speedA = a.speed === null ? 9999 : a.speed
|
||||||
|
const speedB = b.speed === null ? 9999 : b.speed
|
||||||
|
return speedA - speedB
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据中国大陆连通性筛选镜像源
|
||||||
|
*/
|
||||||
|
export function getMirrorsByChinaConnectivity(
|
||||||
|
type: keyof MirrorCategory,
|
||||||
|
connectivity: 'poor' | 'good' | 'excellent'
|
||||||
|
): MirrorConfig[] {
|
||||||
|
const mirrors = getMirrorsByType(type)
|
||||||
|
return mirrors.filter(m => m.chinaConnectivity === connectivity)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取适合中国大陆用户的镜像源(排除连通性差的)
|
||||||
|
*/
|
||||||
|
export function getChinaFriendlyMirrors(type: keyof MirrorCategory): MirrorConfig[] {
|
||||||
|
const mirrors = getMirrorsByType(type)
|
||||||
|
return mirrors.filter(m => m.chinaConnectivity !== 'poor')
|
||||||
|
}
|
||||||
|
|||||||
@@ -529,7 +529,7 @@ const cancelAddTask = () => {
|
|||||||
|
|
||||||
// 连接WebSocket
|
// 连接WebSocket
|
||||||
const connectWebSocket = (task: RunningTask) => {
|
const connectWebSocket = (task: RunningTask) => {
|
||||||
const wsUrl = `ws://localhost:8000/api/dispatch/ws/${task.websocketId}`
|
const wsUrl = `ws://localhost:36163/api/dispatch/ws/${task.websocketId}`
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const ws = new WebSocket(wsUrl)
|
const ws = new WebSocket(wsUrl)
|
||||||
|
|||||||
Reference in New Issue
Block a user