mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-04-26 09:20:18 +08:00
feat: 仅保留混合模式并根据架构动态构建请求路径
- 删除 AppSidebar.vue 中的 StoreModeSwitcher 引入并删除该组件。 - 强制设置当前商店模式为 'hybrid'。 - 修复了因为 `window.apm_store.arch` 包含 `-store` 或 `-apm` 后缀导致路径替换异常的问题,现在会通过动态添加后缀来构建资源请求路径,以兼容 Spark Store 和 APM Store 服务器不同的资源组织结构。
This commit is contained in:
@@ -428,14 +428,23 @@ ipcMain.handle("check-installed", async (_event, payload: any) => {
|
|||||||
let isInstalled = false;
|
let isInstalled = false;
|
||||||
|
|
||||||
if (origin === "apm") {
|
if (origin === "apm") {
|
||||||
const { code, stdout } = await runCommandCapture("apm", ["list", "--installed"]);
|
const { code, stdout } = await runCommandCapture("apm", [
|
||||||
|
"list",
|
||||||
|
"--installed",
|
||||||
|
]);
|
||||||
if (code === 0) {
|
if (code === 0) {
|
||||||
// eslint-disable-next-line no-control-regex
|
// eslint-disable-next-line no-control-regex
|
||||||
const cleanStdout = stdout.replace(/\x1b\[[0-9;]*m/g, "");
|
const cleanStdout = stdout.replace(/\x1b\[[0-9;]*m/g, "");
|
||||||
const lines = cleanStdout.split("\n");
|
const lines = cleanStdout.split("\n");
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
const trimmed = line.trim();
|
const trimmed = line.trim();
|
||||||
if (!trimmed || trimmed.startsWith("Listing") || trimmed.startsWith("[INFO]") || trimmed.startsWith("警告")) continue;
|
if (
|
||||||
|
!trimmed ||
|
||||||
|
trimmed.startsWith("Listing") ||
|
||||||
|
trimmed.startsWith("[INFO]") ||
|
||||||
|
trimmed.startsWith("警告")
|
||||||
|
)
|
||||||
|
continue;
|
||||||
if (trimmed.includes("/")) {
|
if (trimmed.includes("/")) {
|
||||||
const installedPkg = trimmed.split("/")[0].trim();
|
const installedPkg = trimmed.split("/")[0].trim();
|
||||||
if (installedPkg === pkgname) {
|
if (installedPkg === pkgname) {
|
||||||
|
|||||||
@@ -29,9 +29,11 @@ contextBridge.exposeInMainWorld("apm_store", {
|
|||||||
arch: (() => {
|
arch: (() => {
|
||||||
const arch = process.arch;
|
const arch = process.arch;
|
||||||
if (arch === "x64") {
|
if (arch === "x64") {
|
||||||
return "amd64" + "-store";
|
return "amd64";
|
||||||
|
} else if (arch === "arm64") {
|
||||||
|
return "arm64";
|
||||||
} else {
|
} else {
|
||||||
return arch + "-store";
|
return arch;
|
||||||
}
|
}
|
||||||
})(),
|
})(),
|
||||||
});
|
});
|
||||||
|
|||||||
98
src/App.vue
98
src/App.vue
@@ -239,67 +239,6 @@ const updateError = ref("");
|
|||||||
const showUninstallModal = ref(false);
|
const showUninstallModal = ref(false);
|
||||||
const uninstallTargetApp: Ref<App | null> = ref(null);
|
const uninstallTargetApp: Ref<App | null> = ref(null);
|
||||||
|
|
||||||
// 缓存不同模式的数据
|
|
||||||
const storeCache = ref<
|
|
||||||
Record<
|
|
||||||
string,
|
|
||||||
{
|
|
||||||
apps: App[];
|
|
||||||
categories: Record<string, CategoryInfo>;
|
|
||||||
homeLinks: HomeLink[];
|
|
||||||
homeLists: HomeList[];
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>({});
|
|
||||||
|
|
||||||
const saveToCache = (mode: string) => {
|
|
||||||
storeCache.value[mode] = {
|
|
||||||
apps: [...apps.value],
|
|
||||||
categories: { ...categories.value },
|
|
||||||
homeLinks: [...homeLinks.value],
|
|
||||||
homeLists: [...homeLists.value],
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const restoreFromCache = (mode: string) => {
|
|
||||||
const cache = storeCache.value[mode];
|
|
||||||
if (cache) {
|
|
||||||
apps.value = [...cache.apps];
|
|
||||||
categories.value = { ...cache.categories };
|
|
||||||
homeLinks.value = [...cache.homeLinks];
|
|
||||||
homeLists.value = [...cache.homeLists];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 监听模式变化
|
|
||||||
watch(currentStoreMode, async (newMode, oldMode) => {
|
|
||||||
if (oldMode) {
|
|
||||||
saveToCache(oldMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!restoreFromCache(newMode)) {
|
|
||||||
// 如果没有缓存,清空当前状态并重新加载
|
|
||||||
apps.value = [];
|
|
||||||
categories.value = {};
|
|
||||||
homeLinks.value = [];
|
|
||||||
homeLists.value = [];
|
|
||||||
|
|
||||||
loading.value = true;
|
|
||||||
await loadCategories();
|
|
||||||
await Promise.all([
|
|
||||||
loadHome(),
|
|
||||||
new Promise<void>((resolve) => {
|
|
||||||
loadApps(() => {
|
|
||||||
loading.value = false;
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 计算属性
|
// 计算属性
|
||||||
const filteredApps = computed(() => {
|
const filteredApps = computed(() => {
|
||||||
let result = [...apps.value];
|
let result = [...apps.value];
|
||||||
@@ -475,11 +414,8 @@ const checkAppInstalled = (app: App) => {
|
|||||||
|
|
||||||
const loadScreenshots = (app: App) => {
|
const loadScreenshots = (app: App) => {
|
||||||
screenshots.value = [];
|
screenshots.value = [];
|
||||||
const arch = window.apm_store.arch || "amd64-apm";
|
const arch = window.apm_store.arch || "amd64";
|
||||||
const finalArch =
|
const finalArch = app.origin === "spark" ? `${arch}-store` : `${arch}-apm`;
|
||||||
app.origin === "spark"
|
|
||||||
? arch.replace("-apm", "-store")
|
|
||||||
: arch.replace("-store", "-apm");
|
|
||||||
for (let i = 1; i <= 5; i++) {
|
for (let i = 1; i <= 5; i++) {
|
||||||
const screenshotUrl = `${APM_STORE_BASE_URL}/${finalArch}/${app.category}/${app.pkgname}/screen_${i}.png`;
|
const screenshotUrl = `${APM_STORE_BASE_URL}/${finalArch}/${app.category}/${app.pkgname}/screen_${i}.png`;
|
||||||
screenshots.value.push(screenshotUrl);
|
screenshots.value.push(screenshotUrl);
|
||||||
@@ -512,16 +448,11 @@ const loadHome = async () => {
|
|||||||
homeLinks.value = [];
|
homeLinks.value = [];
|
||||||
homeLists.value = [];
|
homeLists.value = [];
|
||||||
try {
|
try {
|
||||||
const arch = window.apm_store.arch || "amd64-apm";
|
const arch = window.apm_store.arch || "amd64";
|
||||||
const modes: Array<"spark" | "apm"> = [];
|
const modes: Array<"spark" | "apm"> = ["spark", "apm"]; // 只保留混合模式
|
||||||
if (currentStoreMode.value === "hybrid") modes.push("spark", "apm");
|
|
||||||
else modes.push(currentStoreMode.value as "spark" | "apm");
|
|
||||||
|
|
||||||
for (const mode of modes) {
|
for (const mode of modes) {
|
||||||
const finalArch =
|
const finalArch = mode === "spark" ? `${arch}-store` : `${arch}-apm`;
|
||||||
mode === "spark"
|
|
||||||
? arch.replace("-apm", "-store")
|
|
||||||
: arch.replace("-store", "-apm");
|
|
||||||
const base = `${APM_STORE_BASE_URL}/${finalArch}/home`;
|
const base = `${APM_STORE_BASE_URL}/${finalArch}/home`;
|
||||||
|
|
||||||
// homelinks.json
|
// homelinks.json
|
||||||
@@ -662,7 +593,7 @@ const refreshUpgradableApps = async () => {
|
|||||||
updateError.value = result?.message || "检查更新失败";
|
updateError.value = result?.message || "检查更新失败";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
upgradableApps.value = (result.apps || []).map(
|
upgradableApps.value = (result.apps || []).map(
|
||||||
(app: Record<string, string>) => ({
|
(app: Record<string, string>) => ({
|
||||||
...app,
|
...app,
|
||||||
@@ -923,18 +854,13 @@ const openDownloadedApp = (pkgname: string, origin?: "spark" | "apm") => {
|
|||||||
|
|
||||||
const loadCategories = async () => {
|
const loadCategories = async () => {
|
||||||
try {
|
try {
|
||||||
const arch = window.apm_store.arch || "amd64-apm";
|
const arch = window.apm_store.arch || "amd64";
|
||||||
const modes: Array<"spark" | "apm"> = [];
|
const modes: Array<"spark" | "apm"> = ["spark", "apm"];
|
||||||
if (currentStoreMode.value === "hybrid") modes.push("spark", "apm");
|
|
||||||
else modes.push(currentStoreMode.value as "spark" | "apm");
|
|
||||||
|
|
||||||
const categoryData: Record<string, { zh: string; origins: string[] }> = {};
|
const categoryData: Record<string, { zh: string; origins: string[] }> = {};
|
||||||
|
|
||||||
for (const mode of modes) {
|
for (const mode of modes) {
|
||||||
const finalArch =
|
const finalArch = mode === "spark" ? `${arch}-store` : `${arch}-apm`;
|
||||||
mode === "spark"
|
|
||||||
? arch.replace("-apm", "-store")
|
|
||||||
: arch.replace("-store", "-apm");
|
|
||||||
const path =
|
const path =
|
||||||
mode === "spark"
|
mode === "spark"
|
||||||
? "/store/categories.json"
|
? "/store/categories.json"
|
||||||
@@ -971,7 +897,7 @@ const loadApps = async (onFirstBatch?: () => void) => {
|
|||||||
|
|
||||||
const categoriesList = Object.keys(categories.value || {});
|
const categoriesList = Object.keys(categories.value || {});
|
||||||
let firstBatchCallDone = false;
|
let firstBatchCallDone = false;
|
||||||
const arch = window.apm_store.arch || "amd64-apm";
|
const arch = window.apm_store.arch || "amd64";
|
||||||
|
|
||||||
// 并发加载所有分类,每个分类自带重试机制
|
// 并发加载所有分类,每个分类自带重试机制
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@@ -985,9 +911,7 @@ const loadApps = async (onFirstBatch?: () => void) => {
|
|||||||
origins.map(async (mode) => {
|
origins.map(async (mode) => {
|
||||||
try {
|
try {
|
||||||
const finalArch =
|
const finalArch =
|
||||||
mode === "spark"
|
mode === "spark" ? `${arch}-store` : `${arch}-apm`;
|
||||||
? arch.replace("-apm", "-store")
|
|
||||||
: arch.replace("-store", "-apm");
|
|
||||||
|
|
||||||
const path =
|
const path =
|
||||||
mode === "spark"
|
mode === "spark"
|
||||||
|
|||||||
@@ -72,11 +72,9 @@ const loadedIcon = ref(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const iconPath = computed(() => {
|
const iconPath = computed(() => {
|
||||||
const arch = window.apm_store.arch || "amd64-apm";
|
const arch = window.apm_store.arch || "amd64";
|
||||||
const finalArch =
|
const finalArch =
|
||||||
props.app.origin === "spark"
|
props.app.origin === "spark" ? `${arch}-store` : `${arch}-apm`;
|
||||||
? arch.replace("-apm", "-store")
|
|
||||||
: arch.replace("-store", "-apm");
|
|
||||||
return `${APM_STORE_BASE_URL}/${finalArch}/${props.app.category}/${props.app.pkgname}/icon.png`;
|
return `${APM_STORE_BASE_URL}/${finalArch}/${props.app.category}/${props.app.pkgname}/icon.png`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,13 @@
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="inline-flex items-center gap-2 rounded-2xl bg-gradient-to-r from-brand to-brand-dark px-4 py-2 text-sm font-semibold text-white shadow-lg transition hover:-translate-y-0.5"
|
class="inline-flex items-center gap-2 rounded-2xl bg-gradient-to-r from-brand to-brand-dark px-4 py-2 text-sm font-semibold text-white shadow-lg transition hover:-translate-y-0.5"
|
||||||
@click="emit('open-app', displayApp?.pkgname || '', displayApp?.origin)"
|
@click="
|
||||||
|
emit(
|
||||||
|
'open-app',
|
||||||
|
displayApp?.pkgname || '',
|
||||||
|
displayApp?.origin,
|
||||||
|
)
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<i class="fas fa-external-link-alt"></i>
|
<i class="fas fa-external-link-alt"></i>
|
||||||
<span>打开</span>
|
<span>打开</span>
|
||||||
@@ -343,11 +349,9 @@ const installBtnText = computed(() => {
|
|||||||
});
|
});
|
||||||
const iconPath = computed(() => {
|
const iconPath = computed(() => {
|
||||||
if (!displayApp.value) return "";
|
if (!displayApp.value) return "";
|
||||||
const arch = window.apm_store.arch || "amd64-apm";
|
const arch = window.apm_store.arch || "amd64";
|
||||||
const finalArch =
|
const finalArch =
|
||||||
displayApp.value.origin === "spark"
|
displayApp.value.origin === "spark" ? `${arch}-store` : `${arch}-apm`;
|
||||||
? arch.replace("-apm", "-store")
|
|
||||||
: arch.replace("-store", "-apm");
|
|
||||||
return `${APM_STORE_BASE_URL}/${finalArch}/${displayApp.value.category}/${displayApp.value.pkgname}/icon.png`;
|
return `${APM_STORE_BASE_URL}/${finalArch}/${displayApp.value.category}/${displayApp.value.pkgname}/icon.png`;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -360,11 +364,9 @@ watch(
|
|||||||
if (newApp) {
|
if (newApp) {
|
||||||
downloadCount.value = "";
|
downloadCount.value = "";
|
||||||
try {
|
try {
|
||||||
const arch = window.apm_store.arch || "amd64-apm";
|
const arch = window.apm_store.arch || "amd64";
|
||||||
const finalArch =
|
const finalArch =
|
||||||
newApp.origin === "spark"
|
newApp.origin === "spark" ? `${arch}-store` : `${arch}-apm`;
|
||||||
? arch.replace("-apm", "-store")
|
|
||||||
: arch.replace("-store", "-apm");
|
|
||||||
const url = `${APM_STORE_BASE_URL}/${finalArch}/${newApp.category}/${newApp.pkgname}/download-times.txt`;
|
const url = `${APM_STORE_BASE_URL}/${finalArch}/${newApp.category}/${newApp.pkgname}/download-times.txt`;
|
||||||
const resp = await axios.get(url, { responseType: "text" });
|
const resp = await axios.get(url, { responseType: "text" });
|
||||||
if (resp.status === 200) {
|
if (resp.status === 200) {
|
||||||
|
|||||||
@@ -89,7 +89,6 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ThemeToggle from "./ThemeToggle.vue";
|
import ThemeToggle from "./ThemeToggle.vue";
|
||||||
import StoreModeSwitcher from "./StoreModeSwitcher.vue";
|
|
||||||
import amberLogo from "../assets/imgs/spark-store.svg";
|
import amberLogo from "../assets/imgs/spark-store.svg";
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
|||||||
@@ -65,11 +65,8 @@ defineEmits<{
|
|||||||
|
|
||||||
const computedImgUrl = (link: HomeLink) => {
|
const computedImgUrl = (link: HomeLink) => {
|
||||||
if (!link.imgUrl) return "";
|
if (!link.imgUrl) return "";
|
||||||
const arch = window.apm_store.arch || "amd64-apm";
|
const arch = window.apm_store.arch || "amd64";
|
||||||
const finalArch =
|
const finalArch = link.origin === "spark" ? `${arch}-store` : `${arch}-apm`;
|
||||||
link.origin === "spark"
|
|
||||||
? arch.replace("-apm", "-store")
|
|
||||||
: arch.replace("-store", "-apm");
|
|
||||||
return `${APM_STORE_BASE_URL}/${finalArch}${link.imgUrl}`;
|
return `${APM_STORE_BASE_URL}/${finalArch}${link.imgUrl}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div
|
|
||||||
class="flex flex-col gap-2 p-4 rounded-2xl bg-slate-50 dark:bg-slate-800/50 border border-slate-200/70 dark:border-slate-700/70"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 px-1"
|
|
||||||
>商店模式</span
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="grid grid-cols-3 gap-1 p-1 bg-slate-200/50 dark:bg-slate-900/50 rounded-xl"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
v-for="mode in modes"
|
|
||||||
:key="mode.id"
|
|
||||||
type="button"
|
|
||||||
class="flex flex-col items-center justify-center py-2 px-1 rounded-lg text-[10px] font-medium transition-all duration-200"
|
|
||||||
:class="
|
|
||||||
currentStoreMode === mode.id
|
|
||||||
? 'bg-white dark:bg-slate-700 text-brand shadow-sm scale-105 z-10'
|
|
||||||
: 'text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200'
|
|
||||||
"
|
|
||||||
@click="setMode(mode.id as StoreMode)"
|
|
||||||
>
|
|
||||||
<i :class="mode.icon" class="mb-1 text-xs"></i>
|
|
||||||
{{ mode.label }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { currentStoreMode } from "../global/storeConfig";
|
|
||||||
import type { StoreMode } from "../global/typedefinition";
|
|
||||||
|
|
||||||
const modes = [
|
|
||||||
{ id: "spark", label: "星火", icon: "fas fa-fire" },
|
|
||||||
{ id: "apm", label: "APM", icon: "fas fa-box-open" },
|
|
||||||
{ id: "hybrid", label: "混合", icon: "fas fa-layer-group" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const setMode = (mode: StoreMode) => {
|
|
||||||
currentStoreMode.value = mode;
|
|
||||||
localStorage.setItem("store_mode", mode);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -11,6 +11,4 @@ export const APM_STORE_STATS_BASE_URL: string =
|
|||||||
export const currentApp = ref<App | null>(null);
|
export const currentApp = ref<App | null>(null);
|
||||||
export const currentAppIsInstalled = ref(false);
|
export const currentAppIsInstalled = ref(false);
|
||||||
|
|
||||||
const initialMode =
|
export const currentStoreMode = ref<StoreMode>("hybrid");
|
||||||
(localStorage.getItem("store_mode") as StoreMode) || "hybrid";
|
|
||||||
export const currentStoreMode = ref<StoreMode>(initialMode);
|
|
||||||
|
|||||||
@@ -31,11 +31,9 @@ export const handleInstall = (appObj?: App) => {
|
|||||||
|
|
||||||
downloadIdCounter += 1;
|
downloadIdCounter += 1;
|
||||||
// 创建下载任务
|
// 创建下载任务
|
||||||
const arch = window.apm_store.arch || "amd64-apm";
|
const arch = window.apm_store.arch || "amd64";
|
||||||
const finalArch =
|
const finalArch =
|
||||||
targetApp.origin === "spark"
|
targetApp.origin === "spark" ? `${arch}-store` : `${arch}-apm`;
|
||||||
? arch.replace("-apm", "-store")
|
|
||||||
: arch.replace("-store", "-apm");
|
|
||||||
|
|
||||||
const download: DownloadItem = {
|
const download: DownloadItem = {
|
||||||
id: downloadIdCounter,
|
id: downloadIdCounter,
|
||||||
@@ -55,7 +53,7 @@ export const handleInstall = (appObj?: App) => {
|
|||||||
source: "APM Store",
|
source: "APM Store",
|
||||||
retry: false,
|
retry: false,
|
||||||
filename: targetApp.filename,
|
filename: targetApp.filename,
|
||||||
metalinkUrl: `${window.apm_store.arch}/${targetApp.category}/${targetApp.pkgname}/${targetApp.filename}.metalink`,
|
metalinkUrl: `${finalArch}/${targetApp.category}/${targetApp.pkgname}/${targetApp.filename}.metalink`,
|
||||||
};
|
};
|
||||||
|
|
||||||
downloads.value.push(download);
|
downloads.value.push(download);
|
||||||
@@ -73,7 +71,7 @@ export const handleInstall = (appObj?: App) => {
|
|||||||
.post(
|
.post(
|
||||||
"/handle_post",
|
"/handle_post",
|
||||||
{
|
{
|
||||||
path: `${window.apm_store.arch}/${targetApp.category}/${targetApp.pkgname}`,
|
path: `${finalArch}/${targetApp.category}/${targetApp.pkgname}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -102,11 +100,8 @@ export const handleUpgrade = (app: App) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
downloadIdCounter += 1;
|
downloadIdCounter += 1;
|
||||||
const arch = window.apm_store.arch || "amd64-apm";
|
const arch = window.apm_store.arch || "amd64";
|
||||||
const finalArch =
|
const finalArch = app.origin === "spark" ? `${arch}-store` : `${arch}-apm`;
|
||||||
app.origin === "spark"
|
|
||||||
? arch.replace("-apm", "-store")
|
|
||||||
: arch.replace("-store", "-apm");
|
|
||||||
|
|
||||||
const download: DownloadItem = {
|
const download: DownloadItem = {
|
||||||
id: downloadIdCounter,
|
id: downloadIdCounter,
|
||||||
|
|||||||
Reference in New Issue
Block a user