update:添加apm与普通商店双支持

This commit is contained in:
2026-03-11 08:36:24 +08:00
parent 8f2c758bf5
commit edd9368c56
11 changed files with 12218 additions and 128 deletions

View File

@@ -17,10 +17,22 @@
/>
</div>
<div class="flex flex-1 flex-col gap-1 overflow-hidden">
<div
class="truncate text-base font-semibold text-slate-900 dark:text-white"
>
{{ app.name || "" }}
<div class="flex items-center gap-2">
<div
class="truncate text-base font-semibold text-slate-900 dark:text-white"
>
{{ app.name || "" }}
</div>
<span
:class="[
'rounded-md px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wider shadow-sm',
app.origin === 'spark'
? 'bg-orange-100 text-orange-600 dark:bg-orange-900/30 dark:text-orange-400'
: 'bg-blue-100 text-blue-600 dark:bg-blue-900/30 dark:text-blue-400',
]"
>
{{ app.origin === "spark" ? "Spark" : "APM" }}
</span>
</div>
<div class="text-sm text-slate-500 dark:text-slate-400">
{{ app.pkgname || "" }} · {{ app.version || "" }}
@@ -52,7 +64,12 @@ const loadedIcon = ref(
);
const iconPath = computed(() => {
return `${APM_STORE_BASE_URL}/${window.apm_store.arch}/${props.app.category}/${props.app.pkgname}/icon.png`;
const arch = window.apm_store.arch || "amd64-apm";
const finalArch =
props.app.origin === "spark"
? arch.replace("-apm", "-store")
: arch.replace("-store", "-apm");
return `${APM_STORE_BASE_URL}/${finalArch}/${props.app.category}/${props.app.pkgname}/icon.png`;
});
const description = computed(() => {

View File

@@ -36,7 +36,17 @@
<p class="text-2xl font-bold text-slate-900 dark:text-white">
{{ app?.name || "" }}
</p>
<!-- Close button for mobile layout could be considered here if needed, but for now sticking to desktop layout logic mainly -->
<span
v-if="app"
:class="[
'rounded-md px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wider shadow-sm',
app.origin === 'spark'
? 'bg-orange-100 text-orange-600 dark:bg-orange-900/30 dark:text-orange-400'
: 'bg-blue-100 text-blue-600 dark:bg-blue-900/30 dark:text-blue-400',
]"
>
{{ app.origin === "spark" ? "Spark" : "APM" }}
</span>
</div>
<p class="text-sm text-slate-500 dark:text-slate-400">
{{ app?.pkgname || "" }} · {{ app?.version || "" }}
@@ -269,7 +279,12 @@ const installBtnText = computed(() => {
});
const iconPath = computed(() => {
if (!props.app) return "";
return `${APM_STORE_BASE_URL}/${window.apm_store.arch}/${props.app.category}/${props.app.pkgname}/icon.png`;
const arch = window.apm_store.arch || "amd64-apm";
const finalArch =
props.app.origin === "spark"
? arch.replace("-apm", "-store")
: arch.replace("-store", "-apm");
return `${APM_STORE_BASE_URL}/${finalArch}/${props.app.category}/${props.app.pkgname}/icon.png`;
});
const downloadCount = ref<string>("");
@@ -281,7 +296,12 @@ watch(
if (newApp) {
downloadCount.value = "";
try {
const url = `${APM_STORE_BASE_URL}/${window.apm_store.arch}/${newApp.category}/${newApp.pkgname}/download-times.txt`;
const arch = window.apm_store.arch || "amd64-apm";
const finalArch =
newApp.origin === "spark"
? arch.replace("-apm", "-store")
: arch.replace("-store", "-apm");
const url = `${APM_STORE_BASE_URL}/${finalArch}/${newApp.category}/${newApp.pkgname}/download-times.txt`;
const resp = await axios.get(url, { responseType: "text" });
if (resp.status === 200) {
downloadCount.value = String(resp.data).trim();

View File

@@ -28,6 +28,7 @@
</div>
<ThemeToggle :theme-mode="themeMode" @toggle="toggleTheme" />
<StoreModeSwitcher />
<div class="flex-1 space-y-2 overflow-y-auto scrollbar-muted pr-2">
<button
@@ -88,6 +89,7 @@
<script setup lang="ts">
import ThemeToggle from "./ThemeToggle.vue";
import StoreModeSwitcher from "./StoreModeSwitcher.vue";
import amberLogo from "../assets/imgs/spark-store.svg";
defineProps<{

View File

@@ -15,7 +15,7 @@
:title="link.more"
>
<img
:src="computedImgUrl(link.imgUrl)"
:src="computedImgUrl(link)"
class="h-20 w-full object-contain"
loading="lazy"
/>
@@ -62,10 +62,14 @@ defineEmits<{
(e: "open-detail", app: Record<string, unknown>): void;
}>();
const computedImgUrl = (imgUrl: string) => {
if (!imgUrl) return "";
// imgUrl is like /home/links/bbs.png -> join with base
return `${APM_STORE_BASE_URL}/${window.apm_store.arch}${imgUrl}`;
const computedImgUrl = (link: Record<string, any>) => {
if (!link.imgUrl) return "";
const arch = window.apm_store.arch || "amd64-apm";
const finalArch =
link.origin === "spark"
? arch.replace("-apm", "-store")
: arch.replace("-store", "-apm");
return `${APM_STORE_BASE_URL}/${finalArch}${link.imgUrl}`;
};
const onLinkClick = (link: Record<string, unknown>) => {

View File

@@ -0,0 +1,38 @@
<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);
// Reload page to re-fetch data based on new mode
window.location.reload();
};
</script>