1
0
mirror of https://github.com/ZeroCatDev/Classworks.git synced 2025-12-07 21:13:11 +00:00
copilot-swe-agent[bot] 5d3721d069 fix: remove duplicate deletePersistentNotification method definition
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
2025-11-30 10:07:04 +00:00

474 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<v-card
border
hover
rounded="xl"
>
<v-card-item>
<template #prepend>
<v-icon
class="mr-2"
icon="mdi-information"
size="large"
/>
</template>
<v-card-title class="text-h6">
关于
</v-card-title>
</v-card-item>
<v-card-text>
<v-row>
<v-col
class="mx-auto"
cols="12"
md="8"
>
<div class="d-flex flex-column align-start">
<v-avatar
class="mb-4"
size="120"
>
<v-img
alt="Classworks"
src="../../assets/cslogo.png"
/>
</v-avatar>
<h2 class="text-h5 mb-2">
Classworks
</h2>
<p class="text-body-1 mb-4">
适用于班级大屏的作业板小工具
</p>
<div class="d-flex gap-2 flex-wrap mb-6">
<v-btn
color="red"
prepend-icon="mdi-bug"
variant="tonal"
@click="openReportDialog"
>
报告问题
</v-btn>
<v-btn
color="primary"
href="https://qm.qq.com/q/qNBX4ZZVeg"
prepend-icon="mdi-qqchat"
target="_blank"
variant="tonal"
>
QQ
</v-btn>
<v-btn
href="https://github.com/ClassworksDev/Classworks"
prepend-icon="mdi-github"
target="_blank"
variant="text"
>
前端
</v-btn>
<v-btn
href="https://github.com/ClassworksDev/ClassworksServer"
prepend-icon="mdi-github"
target="_blank"
variant="text"
>
后端
</v-btn>
</div>
<v-divider class="mb-4 w-100" />
<h3 class="text-h6 mb-2">
备注与致谢
</h3>
<v-list class="mb-4 bg-transparent">
<v-list-item
append-icon="mdi-link"
href="https://github.com/EnderWolf006/HomeworkBoard"
target="_blank"
>
<v-list-item-title>
本项目受到 HomeworkBoard 的启发而开发
</v-list-item-title>
<v-list-item-subtitle>
感谢 EnderWolf006 (@EnderWolf) fhzit(@Hellofhz) KeyFac
等人的贡献
</v-list-item-subtitle>
</v-list-item>
<v-list-item
append-icon="mdi-link"
href="https://hlyun.org"
target="_blank"
>
<v-list-item-title>
Classworks <strong>厚浪云</strong>提供
</v-list-item-title>
<v-list-item-subtitle>
长江后浪推前浪 浮事新人换旧人
</v-list-item-subtitle>
</v-list-item>
<v-list-item
append-icon="mdi-link"
href="https://zerocat.houlangs.com"
target="_blank"
>
<v-list-item-title>
感谢 ZeroCat 社区的开发者们
</v-list-item-title>
<v-list-item-subtitle>
新一代开源编程社区
</v-list-item-subtitle>
</v-list-item>
<v-divider class="ma-1" />
<v-list-item
append-icon="mdi-link"
href="https://github.com/HUSX100/IslandCaller"
target="_blank"
>
<v-list-item-title>
本项目与 IslandCaller 没有从属关系
</v-list-item-title>
<v-list-item-subtitle>
IslandCaller 是由 HUSX100 开发的基于 ClassIsland
提醒服务的轻量级点名器
</v-list-item-subtitle>
</v-list-item>
<v-list-item
append-icon="mdi-link"
href="https://classisland.tech"
target="_blank"
>
<v-list-item-title>
本项目与 ClassIsland 没有从属关系
</v-list-item-title>
<v-list-item-subtitle>
ClassIsland 是由 HelloWRC
开发的适用于班级大屏的课表信息显示工具
</v-list-item-subtitle>
</v-list-item>
</v-list>
<v-btn
class="mb-4"
prepend-icon="mdi-package-variant"
variant="text"
@click="showDeps = true"
>
查看使用的第三方库
</v-btn>
<v-dialog
v-model="showDeps"
fullscreen
transition="dialog-bottom-transition"
>
<v-card>
<v-toolbar>
<v-btn
icon="mdi-close"
@click="showDeps = false"
/>
<v-toolbar-title>使用的第三方库</v-toolbar-title>
<v-spacer />
</v-toolbar>
<v-card-text>
<v-list>
<v-list-item
v-for="dep in Dependencies"
:key="dep.name"
:href="'https://www.npmjs.com/package/' + dep.name"
append-icon="mdi-link"
target="_blank"
>
<v-list-item-title>
{{ dep.name }}
</v-list-item-title>
<v-list-item-subtitle>
v{{ dep.version }}
</v-list-item-subtitle>
</v-list-item>
</v-list>
</v-card-text>
</v-card>
</v-dialog>
<!-- 报告问题对话框 -->
<v-dialog
v-model="showReportDialog"
max-width="640"
>
<v-card>
<v-toolbar density="compact">
<v-btn
icon="mdi-close"
@click="showReportDialog = false"
/>
<v-toolbar-title>报告问题</v-toolbar-title>
<v-spacer />
</v-toolbar>
<v-card-text>
<p class="mb-4">
调试ID与下方的浏览器环境信息将帮助我们快速定位问题请在反馈中一并附上
</p>
<v-sheet
class="mb-3 pa-3 bg-grey-lighten-4 rounded"
style="max-height: 260px; overflow: auto;"
>
<pre
class="text-body-2"
style="white-space: pre-wrap; margin: 0;"
>{{ envBoxText }}</pre>
</v-sheet>
<div class="d-flex gap-2 flex-wrap mb-4">
<v-btn
size="small"
variant="text"
prepend-icon="mdi-refresh"
:loading="visitorLoading"
@click="reloadVisitorId"
>
刷新
</v-btn>
<v-btn
size="small"
variant="text"
prepend-icon="mdi-content-copy"
@click="copyEnvInfo"
>
复制信息
</v-btn>
<v-btn
size="small"
variant="text"
prepend-icon="mdi-open-in-new"
@click="goToDebug"
>
查看 /debug 页面
</v-btn>
</div>
<v-alert
v-if="copyOk"
type="success"
density="compact"
class="mb-4"
>
已复制到剪贴板
</v-alert>
<h4 class="text-subtitle-1 mb-2">
反馈渠道
</h4>
<v-list
lines="one"
class="bg-transparent"
>
<v-list-item
:href="qqGroupLink"
target="_blank"
prepend-icon="mdi-qqchat"
>
<v-list-item-title>QQ群 ({{ qqGroupNumber }})</v-list-item-title>
<v-list-item-subtitle>964979747</v-list-item-subtitle>
</v-list-item>
<v-list-item
:href="githubIssueUrl"
target="_blank"
prepend-icon="mdi-github"
>
<v-list-item-title>GitHub Issue</v-list-item-title>
<v-list-item-subtitle>ZeroCatDev/Classworks</v-list-item-subtitle>
</v-list-item>
<v-list-item
:href="mailtoLink"
target="_blank"
prepend-icon="mdi-email"
>
<v-list-item-title>邮件</v-list-item-title>
<v-list-item-subtitle>sun@wuyuan.dev</v-list-item-subtitle>
</v-list-item>
</v-list>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn
variant="text"
@click="showReportDialog = false"
>
关闭
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<p class="text-caption text-medium-emphasis">
Copyright © {{ new Date().getFullYear() }} Sunwuyuan
</p>
</div>
</v-col>
</v-row>
</v-card-text>
</v-card>
</template>
<script>
import {ref, onMounted, computed} from "vue";
import { useRouter } from 'vue-router'
import { getVisitorId } from '@/utils/fingerprint'
import packageJson from "../../../package.json";
export default {
name: "AboutCard",
setup() {
const Dependencies = ref([]);
const showDeps = ref(false);
const showReportDialog = ref(false);
const debugIdInput = ref('');
const visitorLoading = ref(false);
const copyOk = ref(false);
const qqGroupNumber = '964979747';
const qqGroupLink = 'https://qm.qq.com/q/T6qImKJjGi';
const router = useRouter();
const loadDependencies = () => {
try {
// 合并 dependencies 和 devDependencies
const allDependencies = {
...(packageJson.dependencies || {}),
...(packageJson.devDependencies || {}),
};
// 转换为数组并过滤掉不需要显示的依赖
const deps = Object.entries(allDependencies).map(([name, version]) => ({
name,
version: version.replace(/[\^~]/g, ""),
description: getDependencyDescription(name),
}));
Dependencies.value = deps;
} catch (error) {
console.error("加载依赖信息失败:", error);
Dependencies.value = [];
}
};
const getDependencyDescription = (name) => {
const descriptions = {
vue: "渐进式 JavaScript 框架",
vuetify: "材料设计组件框架",
axios: "Promise 基础的 HTTP 客户端",
pinia: "Vue 状态管理库",
"vue-router": "Vue.js 官方路由管理器",
"@vitejs/plugin-vue": "Vite 的 Vue 插件",
};
return descriptions[name] || "";
};
const goToDebug = () => {
router.push('/debug');
};
const loadVisitorId = async () => {
visitorLoading.value = true;
try {
const id = await getVisitorId();
debugIdInput.value = id || '';
} catch (e) {
console.error('获取访客ID失败', e);
} finally {
visitorLoading.value = false;
}
};
const reloadVisitorId = () => loadVisitorId();
const openReportDialog = async () => {
showReportDialog.value = true;
if (!debugIdInput.value) await loadVisitorId();
};
const copyEnvInfo = async () => {
try {
await navigator.clipboard.writeText(envBoxText.value);
copyOk.value = true;
setTimeout(() => (copyOk.value = false), 1800);
} catch (e) {
console.error('复制失败', e);
}
};
const envInfo = computed(() => {
const nav = navigator || {};
const intl = (typeof Intl !== 'undefined' && Intl.DateTimeFormat) ? Intl.DateTimeFormat().resolvedOptions() : {};
const tz = intl && intl.timeZone ? intl.timeZone : '';
const routePath = router.currentRoute?.value?.fullPath || location.pathname;
const lines = [
`App 版本: v${packageJson?.version || 'unknown'}`,
`URL: ${location.href}`,
`路由: ${routePath}`,
`UserAgent: ${nav.userAgent || ''}`,
`语言: ${nav.language || ''}`,
`时区: ${tz}`,
`平台: ${nav.platform || ''}`,
`在线: ${String(nav.onLine)}`,
`屏幕: ${screen?.width || '-'}x${screen?.height || '-'}`,
`视口: ${window.innerWidth || '-'}x${window.innerHeight || '-'}`,
];
return lines.join('\n');
});
const envBoxText = computed(() => {
return `调试ID: ${debugIdInput.value || '获取失败'}\n\n浏览器/环境信息:\n${envInfo.value}`;
});
const reportBody = computed(() => {
return [
`问题描述:`,
`1. 期望行为:`,
`2. 实际行为:`,
`3. 复现步骤:`,
'',
envBoxText.value,
].join('\n');
});
const githubIssueUrl = computed(() => {
const base = 'https://github.com/ZeroCatDev/Classworks/issues/new';
const title = encodeURIComponent('问题报告');
const body = encodeURIComponent(reportBody.value);
return `${base}?title=${title}&body=${body}`;
});
const mailtoLink = computed(() => {
const subject = encodeURIComponent('Classworks 问题报告');
const body = encodeURIComponent(reportBody.value);
return `mailto:sun@wuyuan.dev?subject=${subject}&body=${body}`;
});
onMounted(() => {
loadDependencies();
});
return {
Dependencies,
showDeps,
showReportDialog,
debugIdInput,
visitorLoading,
copyOk,
qqGroupNumber,
qqGroupLink,
goToDebug,
reloadVisitorId,
openReportDialog,
copyEnvInfo,
envBoxText,
envInfo,
reportBody,
githubIssueUrl,
mailtoLink,
};
},
};
</script>