From 47a4c63de21b598967acd5edaccded989620233f Mon Sep 17 00:00:00 2001 From: fanbook-wangdage <124357765+fanbook-wangdage@users.noreply.github.com> Date: Sun, 8 Feb 2026 13:47:20 +0800 Subject: [PATCH 1/3] =?UTF-8?q?msix=E6=98=AF=E4=BD=BF=E7=94=A8zip=E6=89=93?= =?UTF-8?q?=E5=8C=85=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/download/index.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/views/download/index.vue b/src/views/download/index.vue index af21a0e..d59880b 100644 --- a/src/views/download/index.vue +++ b/src/views/download/index.vue @@ -229,7 +229,12 @@ function downloadFile(item: VersionInfo, packageType: 'msi' | 'msix') { const a = document.createElement('a') a.href = downloadUrl - a.download = `Snap.Hutao.${item.version}.${packageType}` + // 如果是msix的话,文件是用zip格式压缩的 + if (packageType === 'msix') { + a.download = `Snap.Hutao.${item.version}.zip` + } else { + a.download = `Snap.Hutao.${item.version}.msi` + } a.target = '_blank' document.body.appendChild(a) a.click() From e58057665b32fb088480b5875d2bde2cb7f0d7ce Mon Sep 17 00:00:00 2001 From: fanbook-wangdage <124357765+fanbook-wangdage@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:58:41 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=98=BE=E7=A4=BA=E6=B5=8B=E8=AF=95=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/download.ts | 16 +++ src/views/download-manager/index.vue | 20 +++ src/views/download/index.vue | 184 +++++++++++++++++++++++++-- 3 files changed, 212 insertions(+), 8 deletions(-) diff --git a/src/api/download.ts b/src/api/download.ts index c7fb288..b75e6cf 100644 --- a/src/api/download.ts +++ b/src/api/download.ts @@ -10,6 +10,7 @@ export interface DownloadResource { file_hash: string | null file_size: string | null is_active: boolean | null + is_test?: boolean package_type: string version: string } @@ -36,6 +37,20 @@ export function getLatestVersionApi(): Promise { }) } +/** + * 获取测试版本 + * GET /download-resources?is_test=true + */ +export function getTestVersionApi(): Promise { + return request({ + url: '/download-resources', + method: 'get', + params: { + is_test: true + } + }) +} + /** * 获取资源列表(包含未激活的) * GET /web-api/download-resources @@ -86,6 +101,7 @@ export interface CreateResourceRequest { file_size?: string | null file_hash?: string | null is_active?: boolean | null + is_test?: boolean } /** 创建资源响应数据类型 */ diff --git a/src/views/download-manager/index.vue b/src/views/download-manager/index.vue index 2014ba1..d8acaf0 100644 --- a/src/views/download-manager/index.vue +++ b/src/views/download-manager/index.vue @@ -231,6 +231,14 @@ /> + + + + + + + + ({ file_size: '', file_hash: '', is_active: true, + is_test: false, }) const createRules: FormRules = { @@ -410,6 +427,7 @@ const editForm = reactive({ file_size: '', file_hash: '', is_active: true, + is_test: false, }) const editRules: FormRules = { @@ -499,6 +517,7 @@ function handleCreate() { file_size: '', file_hash: '', is_active: true, + is_test: false, }) createDialogVisible.value = true } @@ -543,6 +562,7 @@ function handleEdit(resource: DownloadResource) { file_size: resource.file_size || '', file_hash: resource.file_hash || '', is_active: resource.is_active ?? true, + is_test: resource.is_test ?? false, }) editDialogVisible.value = true } diff --git a/src/views/download/index.vue b/src/views/download/index.vue index d59880b..d831e34 100644 --- a/src/views/download/index.vue +++ b/src/views/download/index.vue @@ -13,12 +13,51 @@ 下载中心

选择适合您的安装包,立即开始使用 Snap Hutao
系统要求:新版本Windows10及Windows11

+ + +
+ + + + + + + + + + + +

测试版可能存在未知的 Bug 和稳定性问题,仅供测试和体验新功能使用。如需稳定使用,请下载正式版。

+
+
- 最新版本 + + {{ versionType === 'test' ? '最新测试版本' : '最新版本' }} +

{{ latestVersion.version }}

@@ -70,16 +109,18 @@
- 历史版本 + + 历史版本 -
-
+ +

暂无历史版本

-
+ +
+ + +
+ +

暂无测试版本

+
@@ -147,7 +194,7 @@ import { FolderOpened, } from '@element-plus/icons-vue' import Header from '@/components/Header.vue' -import { getDownloadResourcesApi } from '@/api/download' +import { getDownloadResourcesApi, getTestVersionApi } from '@/api/download' const router = useRouter() @@ -200,6 +247,7 @@ const latestVersion = ref(null) const historyVersions = ref([]) const loading = ref(false) const downloading = ref(false) +const versionType = ref<'stable' | 'test'>('stable') /** * 格式化日期 @@ -261,7 +309,7 @@ function getTooltipText(item: VersionInfo, packageType: 'msi' | 'msix') { } /** - * 加载所有版本 + * 加载正式版本 */ async function loadAllVersions() { try { @@ -324,6 +372,91 @@ async function loadAllVersions() { } } +/** + * 加载测试版本 + */ +async function loadTestVersion() { + try { + loading.value = true + const data = await getTestVersionApi() + if (!data || data.length === 0) { + latestVersion.value = null + historyVersions.value = [] + return + } + + // 按版本号分组 + const versionMap = new Map() + + data.forEach((item) => { + if (!versionMap.has(item.version)) { + // 首次遇到该版本,创建新记录 + versionMap.set(item.version, { + version: item.version, + created_at: item.created_at, + created_by: item.created_by, + features: item.features, + file_hash: item.file_hash, + file_size: item.file_size, + is_active: item.is_active, + packages: { + msi: null, + msix: null, + msi_size: null, + msix_size: null, + }, + }) + } + + // 添加包类型的下载链接和大小 + const versionInfo = versionMap.get(item.version) + if (versionInfo) { + if (item.package_type === 'msi') { + versionInfo.packages.msi = item.download_url + versionInfo.packages.msi_size = item.file_size + } else if (item.package_type === 'msix') { + versionInfo.packages.msix = item.download_url + versionInfo.packages.msix_size = item.file_size + } + } + }) + + // 转换为数组并按创建时间倒序排序 + const versions = Array.from(versionMap.values()).sort((a, b) => + new Date(b.created_at).getTime() - new Date(a.created_at).getTime() + ) + + if (versions.length > 0) { + latestVersion.value = versions[0] ?? null + // 测试版本只显示最新版本,不显示历史版本 + historyVersions.value = [] + } else { + latestVersion.value = null + historyVersions.value = [] + } + } catch (error) { + console.error('加载测试版本失败:', error) + ElMessage.error('加载测试版本失败') + } finally { + loading.value = false + } +} + +/** + * 切换版本类型 + */ +function switchVersionType(type: 'stable' | 'test') { + versionType.value = type + latestVersion.value = null + historyVersions.value = [] + + if (type === 'stable') { + loadAllVersions() + } else { + loadTestVersion() + } +} + onMounted(() => { loadAllVersions() }) @@ -365,7 +498,42 @@ onMounted(() => { font-size: 16px; color: var(--text-color); opacity: 0.8; - margin-bottom: 10px; + margin-bottom: 20px; +} + +/* 版本类型切换 */ +.version-tabs { + margin-bottom: 32px; +} + +.version-tabs :deep(.el-tabs__header) { + margin: 0; +} + +.version-tabs :deep(.el-tabs__nav-wrap::after) { + display: none; +} + +.version-tabs :deep(.el-tabs__item) { + font-size: 16px; + padding: 0 24px; +} + +.version-tabs .tab-label { + display: flex; + align-items: center; + gap: 6px; +} + +.version-tabs :deep(.el-alert) { + margin-top: 16px; + padding: 12px 16px; +} + +.version-tabs :deep(.el-alert__description) { + margin-top: 8px; + font-size: 14px; + line-height: 1.5; } /* 最新版本卡片 */ From 29409e3e95ffaba29fa9057f212e7c22b3d38eb9 Mon Sep 17 00:00:00 2001 From: fanbook-wangdage <124357765+fanbook-wangdage@users.noreply.github.com> Date: Tue, 10 Feb 2026 20:20:40 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E7=9A=84=E9=AB=98=E7=BA=A7=E7=AD=9B=E9=80=89?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 20 + package.json | 1 + src/api/user.ts | 22 +- src/components/GitHubSearchInput.vue | 637 +++++++++++++++++++++++++++ src/views/user/index.vue | 163 ++++--- 5 files changed, 767 insertions(+), 76 deletions(-) create mode 100644 src/components/GitHubSearchInput.vue diff --git a/package-lock.json b/package-lock.json index 5e9a810..6db890a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "ht-web", "version": "0.0.0", "dependencies": { + "@primer/css": "^22.1.0", "@tsparticles/slim": "^3.9.1", "@tsparticles/vue3": "^3.0.1", "axios": "^1.13.2", @@ -1082,6 +1083,25 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@primer/css": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@primer/css/-/css-22.1.0.tgz", + "integrity": "sha512-Nwg9QaRiBeu0BU6h+Su0X07daihX1obiuqGRG8y+SexOnvWhN2J5n4OFAvGfQsit07Y7Q6gGoK+yVU5tb8CtDA==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@primer/primitives": "10.x || 11.x" + } + }, + "node_modules/@primer/primitives": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/@primer/primitives/-/primitives-11.4.0.tgz", + "integrity": "sha512-JIt98Fs0c8vhOw3uNf+sxqmvCdo0VoCZPBRg4frNK/xNpDMZsQh7V0Rp7wiGbr3f1w+4oqv40sfgaftMQTnwXQ==", + "license": "MIT", + "peer": true + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.53", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz", diff --git a/package.json b/package.json index 569e4cf..8bcf422 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "preview": "vite preview" }, "dependencies": { + "@primer/css": "^22.1.0", "@tsparticles/slim": "^3.9.1", "@tsparticles/vue3": "^3.0.1", "axios": "^1.13.2", diff --git a/src/api/user.ts b/src/api/user.ts index e862734..9dd7ac9 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -44,14 +44,22 @@ export function getUserInfoApi(): Promise { /** * 获取用户列表 * GET /web-api/users - * @param q 搜索参数,可搜索用户名、邮箱、_id + * @param params 搜索和筛选参数 + * @param params.q 搜索关键词,可搜索用户名、邮箱、_id + * @param params.role 按角色筛选:maintainer, developer, user + * @param params.email 按邮箱筛选 + * @param params.username 按用户名筛选 + * @param params.id 按用户ID筛选 + * @param params.is 按状态筛选:licensed, not-licensed */ -export function getUserListApi(q?: string): Promise { - const params: Record = {} - if (q) { - params.q = q - } - +export function getUserListApi(params?: { + q?: string + role?: string + email?: string + username?: string + id?: string + is?: string +}): Promise { return request({ url: '/web-api/users', method: 'get', diff --git a/src/components/GitHubSearchInput.vue b/src/components/GitHubSearchInput.vue new file mode 100644 index 0000000..d1fa52e --- /dev/null +++ b/src/components/GitHubSearchInput.vue @@ -0,0 +1,637 @@ + + + + + + + \ No newline at end of file diff --git a/src/views/user/index.vue b/src/views/user/index.vue index a6c2cd7..d486479 100644 --- a/src/views/user/index.vue +++ b/src/views/user/index.vue @@ -2,28 +2,27 @@
- - - - +
+ - - - 搜索 - 重置 - - - -
- - - - -
+
+ 搜索 + 重置 +
+
+ + +
+ + + + +
@@ -67,45 +66,41 @@