Compare commits
10 Commits
2649cca69d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6de61c24b2 | ||
|
|
f6bbd95b77 | ||
|
|
a28bb3a54d | ||
|
|
9bca019b50 | ||
|
|
6288a1b01b | ||
|
|
c7da09d327 | ||
|
|
2ac1428c34 | ||
|
|
3da20d0097 | ||
|
|
f5d9963f3c | ||
|
|
cf6dfac6a3 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -23,4 +23,6 @@ logs
|
|||||||
.env.*
|
.env.*
|
||||||
!.env.example
|
!.env.example
|
||||||
|
|
||||||
repomix-output.xml
|
repomix-output.xml
|
||||||
|
|
||||||
|
content/members/members.csv
|
||||||
@@ -1,9 +1,36 @@
|
|||||||
@import "./markdown.css";
|
/* @import "./markdown.css"; */
|
||||||
|
|
||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
@import "@nuxt/ui";
|
@import "@nuxt/ui";
|
||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--color-primary: #fb9e3a;
|
--color-primary: #fb9e3a;
|
||||||
|
--color-primary-50: #fff8f0;
|
||||||
|
--color-primary-100: #feecd8;
|
||||||
|
--color-primary-200: #fdd4ab;
|
||||||
|
--color-primary-300: #fbb674;
|
||||||
|
--color-primary-400: #fb9e3a;
|
||||||
|
--color-primary-500: #f9840a;
|
||||||
|
--color-primary-600: #dd6b06;
|
||||||
|
--color-primary-700: #b74f07;
|
||||||
|
--color-primary-800: #943e0d;
|
||||||
|
--color-primary-900: #7a340e;
|
||||||
|
--color-primary-950: #461902;
|
||||||
|
|
||||||
--color-secondary: #fcef91;
|
--color-secondary: #fcef91;
|
||||||
|
--color-secondary-50: #fffeea;
|
||||||
|
--color-secondary-100: #fffbc5;
|
||||||
|
--color-secondary-200: #fcef91;
|
||||||
|
--color-secondary-300: #f9df53;
|
||||||
|
--color-secondary-400: #f6ca24;
|
||||||
|
--color-secondary-500: #e6b010;
|
||||||
|
--color-secondary-600: #c6880a;
|
||||||
|
--color-secondary-700: #9e610c;
|
||||||
|
--color-secondary-800: #834d12;
|
||||||
|
--color-secondary-900: #6f3f15;
|
||||||
|
--color-secondary-950: #412008;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
--color-gray-800: oklch(85% 0 275);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,565 +0,0 @@
|
|||||||
/* markdown.css
|
|
||||||
默认:明亮 / 白色背景主题
|
|
||||||
同时提供:.dark .prose 覆盖(如需启用 class-based dark 模式)
|
|
||||||
依赖:全局定义的 CSS 变量 --color-primary 和 --color-secondary
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* 平滑滚动 */
|
|
||||||
html {
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- 默认:明亮主题(Light) ---------- */
|
|
||||||
|
|
||||||
/* 美化 prose 内容样式 */
|
|
||||||
.prose {
|
|
||||||
@apply text-gray-800 leading-relaxed;
|
|
||||||
font-feature-settings:
|
|
||||||
"kern" 1,
|
|
||||||
"liga" 1;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标题层级 */
|
|
||||||
.prose h1 {
|
|
||||||
@apply text-4xl font-bold mt-8 mb-6 pb-4 border-b border-gray-200;
|
|
||||||
background-image: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
var(--color-primary),
|
|
||||||
var(--color-secondary)
|
|
||||||
);
|
|
||||||
background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
color: transparent;
|
|
||||||
background-size: 200% 200%;
|
|
||||||
animation: gradientShift 3s ease infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose h2 {
|
|
||||||
@apply text-3xl font-bold text-gray-900 mt-10 mb-5 pb-3 border-b border-gray-200 relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose h2::before {
|
|
||||||
content: "";
|
|
||||||
@apply absolute bottom-0 left-0 w-12 h-0.5 rounded-full;
|
|
||||||
background-image: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
var(--color-primary),
|
|
||||||
var(--color-secondary)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose h3 {
|
|
||||||
@apply text-2xl font-semibold text-gray-800 mt-8 mb-4;
|
|
||||||
color: rgba(31, 41, 55, 0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose h4 {
|
|
||||||
@apply text-xl font-semibold text-gray-700 mt-7 mb-3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose h5 {
|
|
||||||
@apply text-lg font-medium text-gray-700 mt-6 mb-3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose h6 {
|
|
||||||
@apply text-base font-medium text-gray-600 mt-5 mb-2 italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 段落和文本 */
|
|
||||||
.prose p {
|
|
||||||
@apply text-gray-700 leading-relaxed mb-5;
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose strong {
|
|
||||||
@apply font-bold px-1 rounded;
|
|
||||||
background: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
rgba(252, 239, 145, 0.22),
|
|
||||||
rgba(251, 158, 58, 0.12)
|
|
||||||
);
|
|
||||||
color: rgba(31, 41, 55, 0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose em {
|
|
||||||
@apply italic px-1 rounded;
|
|
||||||
color: var(--color-secondary);
|
|
||||||
background: rgba(251, 158, 58, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose del {
|
|
||||||
@apply line-through px-1 rounded;
|
|
||||||
color: #ef4444;
|
|
||||||
background: rgba(239, 68, 68, 0.06);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 链接 */
|
|
||||||
.prose a {
|
|
||||||
@apply font-medium relative transition-all duration-300;
|
|
||||||
color: var(--color-secondary);
|
|
||||||
text-decoration: underline;
|
|
||||||
text-underline-offset: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose a:hover {
|
|
||||||
color: var(--color-primary);
|
|
||||||
transform: translateY(1px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose a::after {
|
|
||||||
content: "";
|
|
||||||
@apply absolute bottom-0 left-0 w-0 h-0.5 transition-all duration-300;
|
|
||||||
background: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
var(--color-primary),
|
|
||||||
var(--color-secondary)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose a:hover::after {
|
|
||||||
@apply w-full;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 外部链接图标 */
|
|
||||||
.prose a[href^="http"]::before {
|
|
||||||
content: "↗";
|
|
||||||
@apply inline-block mr-1 text-xs translate-y-[2px] opacity-70;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose h1 a,
|
|
||||||
.prose h2 a,
|
|
||||||
.prose h3 a,
|
|
||||||
.prose h4 a,
|
|
||||||
.prose h5 a,
|
|
||||||
.prose h6 a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 列表 */
|
|
||||||
.prose ul {
|
|
||||||
@apply list-none space-y-3 mb-6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose ul li {
|
|
||||||
@apply relative pl-6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose ul li::before {
|
|
||||||
content: "";
|
|
||||||
@apply absolute left-0 top-3 w-1.5 h-1.5 rounded-full;
|
|
||||||
background: var(--color-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose ol {
|
|
||||||
@apply list-decimal list-inside space-y-3 mb-6;
|
|
||||||
counter-reset: list-counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose ol li {
|
|
||||||
@apply relative pl-8;
|
|
||||||
counter-increment: list-counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose ol li::before {
|
|
||||||
content: counter(list-counter);
|
|
||||||
@apply absolute left-0 top-0 w-6 h-6 text-white text-xs rounded-full flex items-center justify-center font-bold;
|
|
||||||
background-image: linear-gradient(
|
|
||||||
135deg,
|
|
||||||
var(--color-primary),
|
|
||||||
var(--color-secondary)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 代码块(浅色风格) */
|
|
||||||
.prose pre {
|
|
||||||
@apply rounded-xl p-6 my-8 border shadow-sm overflow-x-auto;
|
|
||||||
border: 1px solid rgba(229, 231, 235, 1); /* gray-200 */
|
|
||||||
background: linear-gradient(180deg, #ffffff, #f8fafc);
|
|
||||||
box-shadow: 0 6px 18px rgba(15, 23, 42, 0.04);
|
|
||||||
backdrop-filter: blur(6px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose code {
|
|
||||||
@apply px-2 py-1 rounded text-sm font-mono;
|
|
||||||
background: rgba(243, 244, 246, 0.8); /* gray-50-ish */
|
|
||||||
border: 1px solid rgba(229, 231, 235, 1);
|
|
||||||
color: #0f172a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose pre code {
|
|
||||||
@apply bg-transparent p-0 text-current border-none;
|
|
||||||
color: #0f172a;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 引用块(浅色友好) */
|
|
||||||
.prose blockquote {
|
|
||||||
@apply pl-6 italic text-gray-700 my-8 py-4 pr-6 rounded-r-xl relative overflow-hidden;
|
|
||||||
border-left: 4px solid transparent;
|
|
||||||
border-image: linear-gradient(
|
|
||||||
to bottom,
|
|
||||||
rgba(252, 239, 145, 0.9),
|
|
||||||
rgba(251, 158, 58, 0.9)
|
|
||||||
)
|
|
||||||
1;
|
|
||||||
background: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
rgba(252, 239, 145, 0.06),
|
|
||||||
rgba(255, 255, 255, 0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose blockquote::before {
|
|
||||||
content: '"';
|
|
||||||
@apply absolute -top-4 -left-2 text-6xl opacity-20 font-serif;
|
|
||||||
color: var(--color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose blockquote p {
|
|
||||||
@apply mb-3 last:mb-0 relative z-10;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 图片 */
|
|
||||||
.prose img {
|
|
||||||
@apply rounded-2xl my-8 mx-auto transition-all duration-500 border-2;
|
|
||||||
border-color: rgba(226, 232, 240, 0.6); /* gray-200 */
|
|
||||||
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.04);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose img:hover {
|
|
||||||
@apply scale-[1.02];
|
|
||||||
border-color: var(--color-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose figure {
|
|
||||||
@apply my-8 text-center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose figcaption {
|
|
||||||
@apply text-sm text-gray-500 mt-3 italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 表格 */
|
|
||||||
.prose table {
|
|
||||||
@apply w-full border-collapse my-8 text-sm rounded-xl overflow-hidden shadow-sm;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose thead {
|
|
||||||
background-image: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
rgba(252, 239, 145, 0.18),
|
|
||||||
rgba(251, 158, 58, 0.12)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose th {
|
|
||||||
@apply border px-6 py-4 text-left font-bold text-gray-800 text-sm uppercase tracking-wider;
|
|
||||||
border-color: rgba(226, 232, 240, 0.6);
|
|
||||||
background: rgba(250, 250, 250, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose td {
|
|
||||||
@apply border px-6 py-4 text-gray-700;
|
|
||||||
border-color: rgba(226, 232, 240, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose tr:nth-child(even) {
|
|
||||||
@apply bg-gray-50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose tr:hover {
|
|
||||||
background: rgba(251, 158, 58, 0.06);
|
|
||||||
transition: background 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 分割线 */
|
|
||||||
.prose hr {
|
|
||||||
@apply border-gray-200 my-12 relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose hr::before {
|
|
||||||
content: "";
|
|
||||||
@apply absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-8 h-8 rounded-full opacity-20;
|
|
||||||
background-image: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
var(--color-primary),
|
|
||||||
var(--color-secondary)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 任务列表(checkbox) */
|
|
||||||
.prose input[type="checkbox"] {
|
|
||||||
@apply mr-3 rounded w-5 h-5 transition-all duration-200;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid rgba(226, 232, 240, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose input[type="checkbox"]:checked {
|
|
||||||
background-image: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
var(--color-primary),
|
|
||||||
var(--color-secondary)
|
|
||||||
);
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose .task-list-item {
|
|
||||||
@apply list-none pl-0 flex items-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose .task-list-item input[type="checkbox"] {
|
|
||||||
@apply mt-0.5 flex-shrink-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 强调和标记 */
|
|
||||||
.prose mark {
|
|
||||||
@apply px-2 py-1 rounded font-medium;
|
|
||||||
background: linear-gradient(
|
|
||||||
120deg,
|
|
||||||
rgba(252, 239, 145, 0.22),
|
|
||||||
rgba(251, 158, 58, 0.18)
|
|
||||||
);
|
|
||||||
color: #8a4b00;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 键盘按键 */
|
|
||||||
.prose kbd {
|
|
||||||
@apply border rounded-lg px-3 py-1.5 text-sm font-mono shadow-sm;
|
|
||||||
background: rgba(247, 249, 250, 0.9);
|
|
||||||
border-color: rgba(226, 232, 240, 0.8);
|
|
||||||
color: #0f172a;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 动画定义 */
|
|
||||||
@keyframes gradientShift {
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
background-position: 0% 50%;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
background-position: 100% 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 滚动条(浅色) */
|
|
||||||
.prose pre::-webkit-scrollbar {
|
|
||||||
@apply h-2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose pre::-webkit-scrollbar-track {
|
|
||||||
@apply rounded-full;
|
|
||||||
background: rgba(243, 244, 246, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose pre::-webkit-scrollbar-thumb {
|
|
||||||
border-radius: 9999px;
|
|
||||||
background-image: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
var(--color-primary),
|
|
||||||
var(--color-secondary)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端优化 */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.prose {
|
|
||||||
@apply text-base;
|
|
||||||
}
|
|
||||||
.prose h1 {
|
|
||||||
@apply text-3xl;
|
|
||||||
}
|
|
||||||
.prose h2 {
|
|
||||||
@apply text-2xl;
|
|
||||||
}
|
|
||||||
.prose h3 {
|
|
||||||
@apply text-xl;
|
|
||||||
}
|
|
||||||
.prose pre {
|
|
||||||
@apply p-4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 打印优化 */
|
|
||||||
@media print {
|
|
||||||
.prose {
|
|
||||||
@apply text-black;
|
|
||||||
}
|
|
||||||
.prose a {
|
|
||||||
@apply text-black no-underline;
|
|
||||||
}
|
|
||||||
.prose pre {
|
|
||||||
@apply bg-gray-100 border border-gray-300;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- 可选:深色模式覆盖(.dark class 优先) ---------- */
|
|
||||||
/* 如果你使用 Tailwind 的 class-based dark 模式(<html class="dark">),.dark .prose 会生效 */
|
|
||||||
/* 也可替换为 @media (prefers-color-scheme: dark) {...} 来自动跟随系统 dark 模式 */
|
|
||||||
|
|
||||||
.dark .prose {
|
|
||||||
@apply text-gray-200;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark .prose h1 {
|
|
||||||
border-color: rgba(55, 65, 81, 0.5);
|
|
||||||
}
|
|
||||||
.dark .prose h2 {
|
|
||||||
color: #fff;
|
|
||||||
border-color: rgba(55, 65, 81, 0.4);
|
|
||||||
}
|
|
||||||
.dark .prose p {
|
|
||||||
@apply text-gray-300;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark .prose pre {
|
|
||||||
border: 1px solid rgba(55, 65, 81, 0.6);
|
|
||||||
background: linear-gradient(
|
|
||||||
135deg,
|
|
||||||
rgba(17, 24, 39, 0.9),
|
|
||||||
rgba(31, 41, 55, 0.9)
|
|
||||||
);
|
|
||||||
box-shadow: 0 8px 30px rgba(2, 6, 23, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark .prose code {
|
|
||||||
background: rgba(31, 41, 55, 0.6);
|
|
||||||
border: 1px solid rgba(55, 65, 81, 0.5);
|
|
||||||
color: #e6eef8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark .prose blockquote {
|
|
||||||
border-image: linear-gradient(
|
|
||||||
to bottom,
|
|
||||||
var(--color-primary),
|
|
||||||
var(--color-secondary)
|
|
||||||
)
|
|
||||||
1;
|
|
||||||
background: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
rgba(255, 255, 255, 0.02),
|
|
||||||
rgba(255, 255, 255, 0)
|
|
||||||
);
|
|
||||||
color: rgba(255, 255, 255, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark .prose table thead {
|
|
||||||
background-image: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
rgba(252, 239, 145, 0.06),
|
|
||||||
rgba(251, 158, 58, 0.04)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
.dark .prose tr:nth-child(even) {
|
|
||||||
background: rgba(255, 255, 255, 0.02);
|
|
||||||
}
|
|
||||||
.dark .prose td,
|
|
||||||
.dark .prose th {
|
|
||||||
color: rgba(255, 255, 255, 0.9);
|
|
||||||
}
|
|
||||||
.dark .prose img {
|
|
||||||
box-shadow: 0 10px 30px rgba(2, 6, 23, 0.6);
|
|
||||||
border-color: rgba(55, 65, 81, 0.5);
|
|
||||||
}
|
|
||||||
.dark .prose kbd {
|
|
||||||
background: rgba(31, 41, 55, 0.7);
|
|
||||||
border-color: rgba(55, 65, 81, 0.6);
|
|
||||||
color: #e6eef8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 滚动条(深色) */
|
|
||||||
.dark .prose pre::-webkit-scrollbar-track {
|
|
||||||
background: rgba(17, 24, 39, 0.8);
|
|
||||||
}
|
|
||||||
.dark .prose pre::-webkit-scrollbar-thumb {
|
|
||||||
background-image: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
var(--color-primary),
|
|
||||||
var(--color-secondary)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
.prose {
|
|
||||||
@apply text-gray-200;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose h1 {
|
|
||||||
border-color: rgba(55, 65, 81, 0.5);
|
|
||||||
}
|
|
||||||
.prose h2 {
|
|
||||||
color: #fff;
|
|
||||||
border-color: rgba(55, 65, 81, 0.4);
|
|
||||||
}
|
|
||||||
.prose p {
|
|
||||||
@apply text-gray-300;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose pre {
|
|
||||||
border: 1px solid rgba(55, 65, 81, 0.6);
|
|
||||||
background: linear-gradient(
|
|
||||||
135deg,
|
|
||||||
rgba(17, 24, 39, 0.9),
|
|
||||||
rgba(31, 41, 55, 0.9)
|
|
||||||
);
|
|
||||||
box-shadow: 0 8px 30px rgba(2, 6, 23, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose code {
|
|
||||||
background: rgba(31, 41, 55, 0.6);
|
|
||||||
border: 1px solid rgba(55, 65, 81, 0.5);
|
|
||||||
color: #e6eef8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose blockquote {
|
|
||||||
border-image: linear-gradient(
|
|
||||||
to bottom,
|
|
||||||
var(--color-primary),
|
|
||||||
var(--color-secondary)
|
|
||||||
)
|
|
||||||
1;
|
|
||||||
background: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
rgba(255, 255, 255, 0.02),
|
|
||||||
rgba(255, 255, 255, 0)
|
|
||||||
);
|
|
||||||
color: rgba(255, 255, 255, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose table thead {
|
|
||||||
background-image: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
rgba(252, 239, 145, 0.06),
|
|
||||||
rgba(251, 158, 58, 0.04)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
.prose tr:nth-child(even) {
|
|
||||||
background: rgba(255, 255, 255, 0.02);
|
|
||||||
}
|
|
||||||
.prose td,
|
|
||||||
.prose th {
|
|
||||||
color: rgba(255, 255, 255, 0.9);
|
|
||||||
}
|
|
||||||
.prose img {
|
|
||||||
box-shadow: 0 10px 30px rgba(2, 6, 23, 0.6);
|
|
||||||
border-color: rgba(55, 65, 81, 0.5);
|
|
||||||
}
|
|
||||||
.prose kbd {
|
|
||||||
background: rgba(31, 41, 55, 0.7);
|
|
||||||
border-color: rgba(55, 65, 81, 0.6);
|
|
||||||
color: #e6eef8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 滚动条(深色) */
|
|
||||||
.prose pre::-webkit-scrollbar-track {
|
|
||||||
background: rgba(17, 24, 39, 0.8);
|
|
||||||
}
|
|
||||||
.prose pre::-webkit-scrollbar-thumb {
|
|
||||||
background-image: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
var(--color-primary),
|
|
||||||
var(--color-secondary)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 活动模块 -->
|
<!-- 活动模块 -->
|
||||||
<UPageSection title="校友活动" class="bg-gray-100">
|
<UPageSection title="校友活动" class="bg-gray-100 dark:bg-slate-800">
|
||||||
<UPageGrid>
|
<UPageGrid>
|
||||||
<div
|
<div
|
||||||
v-for="event in events"
|
v-for="event in events"
|
||||||
:key="event.id"
|
:key="event.id"
|
||||||
class="bg-white shadow rounded-xl"
|
class="bg-white dark:bg-slate-700 shadow rounded-xl"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
:src="event.cover"
|
:src="event.cover"
|
||||||
:alt="event.title"
|
:alt="event.title"
|
||||||
class="w-full aspect-[16/9] object-cover rounded-t-xl"
|
class="w-full aspect-video object-cover rounded-t-xl"
|
||||||
/>
|
/>
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<h4 class="font-semibold text-lg mb-2">{{ event.title }}</h4>
|
<h4 class="font-semibold text-lg mb-2">{{ event.title }}</h4>
|
||||||
<p class="text-sm text-gray-600 mb-1">
|
<p class="text-sm text-gray-600 dark:text-gray-400 mb-1">
|
||||||
日期:{{ useChineseDateFormat(event.date) }}
|
日期:{{ useChineseDateFormat(event.date) }}
|
||||||
</p>
|
</p>
|
||||||
<p class="text-sm text-gray-600 mb-4">地点:{{ event.location }}</p>
|
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">地点:{{ event.location }}</p>
|
||||||
<UButton
|
<UButton
|
||||||
label="阅读详情"
|
label="阅读详情"
|
||||||
:to="event.path"
|
:to="event.path"
|
||||||
@@ -31,7 +31,11 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const { data: events } = await useAsyncData("events", () =>
|
const { data: events } = await useAsyncData("events", () =>
|
||||||
queryCollection("events").order("date", "DESC").limit(3).all()
|
queryCollection("events")
|
||||||
|
.where("draft", "=", false)
|
||||||
|
.order("date", "DESC")
|
||||||
|
.limit(3)
|
||||||
|
.all()
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
<img
|
<img
|
||||||
:src="person.photo"
|
:src="person.photo"
|
||||||
:alt="person.name"
|
:alt="person.name"
|
||||||
class="w-40 rounded-full border-primary border-4"
|
class="w-40 rounded-full border-primary-400 border-4"
|
||||||
/>
|
/>
|
||||||
<h4 class="text-lg font-bold">{{ person.name }}</h4>
|
<h4 class="text-lg font-bold">{{ person.name }}</h4>
|
||||||
<p class="text-sm text-gray-500">{{ person.title }}</p>
|
<p class="text-sm text-gray-500 dark:text-gray-400">{{ person.title }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</UPageSection>
|
</UPageSection>
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ const errorColor = computed(() => {
|
|||||||
<button
|
<button
|
||||||
@click="goHome"
|
@click="goHome"
|
||||||
class="px-5 py-2.5 rounded-md text-white font-medium transition-colors flex items-center gap-2"
|
class="px-5 py-2.5 rounded-md text-white font-medium transition-colors flex items-center gap-2"
|
||||||
style="background-color: var(--color-primary)"
|
style="background-color: var(--color-primary-400)"
|
||||||
>
|
>
|
||||||
<span>返回首页</span>
|
<span>返回首页</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<div class="flex gap-4 items-center">
|
<div class="flex gap-4 items-center">
|
||||||
<img class="inline h-12 w-auto" src="/Logo.svg" alt="YPHS Alumni" />
|
<img class="inline h-12 w-auto" src="/Logo.svg" alt="YPHS Alumni" />
|
||||||
<h1
|
<h1
|
||||||
class="text-xl font-bold text-gray-900 hover:text-primary hidden md:inline"
|
class="text-xl font-bold text-gray-900 hover:text-primary-400 hidden md:inline"
|
||||||
>
|
>
|
||||||
永平中学校友会
|
永平中学校友会
|
||||||
</h1>
|
</h1>
|
||||||
@@ -52,7 +52,9 @@
|
|||||||
|
|
||||||
<UMain>
|
<UMain>
|
||||||
<Transition name="page" mode="out-in">
|
<Transition name="page" mode="out-in">
|
||||||
<NuxtPage />
|
<div>
|
||||||
|
<NuxtPage />
|
||||||
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
</UMain>
|
</UMain>
|
||||||
|
|
||||||
@@ -105,6 +107,11 @@ const bannerActions = ref<ButtonProps[]>([
|
|||||||
const items = computed<NavigationMenuItem[]>(() => [
|
const items = computed<NavigationMenuItem[]>(() => [
|
||||||
{ label: "首页", to: "/" },
|
{ label: "首页", to: "/" },
|
||||||
{ label: "新闻", to: "/news", active: route.path.startsWith("/news") },
|
{ label: "新闻", to: "/news", active: route.path.startsWith("/news") },
|
||||||
|
{
|
||||||
|
label: "会员",
|
||||||
|
to: "/members",
|
||||||
|
active: route.path.startsWith("/members"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: "活动",
|
label: "活动",
|
||||||
to: "/events",
|
to: "/events",
|
||||||
@@ -122,7 +129,7 @@ const items = computed<NavigationMenuItem[]>(() => [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "关于校友会",
|
label: "关于",
|
||||||
to: "/about",
|
to: "/about",
|
||||||
active: route.path.startsWith("/about"),
|
active: route.path.startsWith("/about"),
|
||||||
children: [
|
children: [
|
||||||
@@ -132,17 +139,23 @@ const items = computed<NavigationMenuItem[]>(() => [
|
|||||||
active: route.path.startsWith("/about/founded-history"),
|
active: route.path.startsWith("/about/founded-history"),
|
||||||
icon: "mdi:history",
|
icon: "mdi:history",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "组织架构",
|
||||||
|
to: "/about/org-structure/20",
|
||||||
|
active: route.path.startsWith("/about/org-structure"),
|
||||||
|
icon: "mdi:account-group",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: "特殊校友:中补班",
|
label: "特殊校友:中补班",
|
||||||
description: "永平中学补习班(1956年):一封迟来的贴文",
|
description: "永平中学补习班(1956年):一封迟来的贴文",
|
||||||
to: "/about/middle-highschool-tuition-class",
|
to: "/about/middle-highschool-tuition-class",
|
||||||
active: route.path.startsWith("/about/middle-highschool-tuition-class"),
|
active: route.path.startsWith("/about/middle-highschool-tuition-class"),
|
||||||
icon: "mdi:mail"
|
icon: "mdi:mail",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "友情链接",
|
label: "链接",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: "永平中学官网",
|
label: "永平中学官网",
|
||||||
|
|||||||
@@ -131,7 +131,7 @@
|
|||||||
:class="[
|
:class="[
|
||||||
'px-4',
|
'px-4',
|
||||||
'py-2',
|
'py-2',
|
||||||
idx < 2 ? 'font-bold text-primary' : '',
|
idx < 2 ? 'font-bold text-primary-400' : '',
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
{{ donor.amount }}
|
{{ donor.amount }}
|
||||||
@@ -167,7 +167,7 @@
|
|||||||
{{ money.format(serviceDonor.amount) }}
|
{{ money.format(serviceDonor.amount) }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="bg-amber-50 font-semibold text-primary">
|
<tr class="bg-amber-50 font-semibold text-primary-400">
|
||||||
<td class="px-4 py-2">总额</td>
|
<td class="px-4 py-2">总额</td>
|
||||||
<td class="px-4 py-2">专业服务及装修项目</td>
|
<td class="px-4 py-2">专业服务及装修项目</td>
|
||||||
<td class="px-4 py-2">{{ money.format(33170) }}</td>
|
<td class="px-4 py-2">{{ money.format(33170) }}</td>
|
||||||
|
|||||||
16
app/pages/about/org-structure.vue
Normal file
16
app/pages/about/org-structure.vue
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<UContainer>
|
||||||
|
<UDashboardToolbar>
|
||||||
|
<UNavigationMenu :items="subPages" />
|
||||||
|
</UDashboardToolbar>
|
||||||
|
<NuxtPage />
|
||||||
|
</UContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { NavigationMenuItem } from "@nuxt/ui";
|
||||||
|
|
||||||
|
const subPages = ref<NavigationMenuItem[]>([{ label: "20 届", to: "/about/org-structure/20" }]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
||||||
228
app/pages/about/org-structure/[slug].vue
Normal file
228
app/pages/about/org-structure/[slug].vue
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
<template>
|
||||||
|
<UPage>
|
||||||
|
<UPageHeader
|
||||||
|
:title="`第 ${generation} 届组织架构`"
|
||||||
|
description="精英汇聚,携手共创卓越未来"
|
||||||
|
/>
|
||||||
|
<UPageBody>
|
||||||
|
<UPageSection
|
||||||
|
v-for="category in categories"
|
||||||
|
:key="category"
|
||||||
|
:title="category"
|
||||||
|
>
|
||||||
|
<!-- <h2 class="text-3xl font-extrabold text-center mb-10">领导团队</h2> -->
|
||||||
|
<UPageGrid class="!grid-cols-1 sm:!grid-cols-2 lg:!grid-cols-4">
|
||||||
|
<UCard
|
||||||
|
v-for="person in orgStructure.filter((p) => p.category == category)"
|
||||||
|
:key="person.name"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<h3 class="text-xl font-semibold mb-2">{{ person.position }}</h3>
|
||||||
|
<div class="text-2xl font-bold">{{ person.name }}</div>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
|
<div class="text-center">
|
||||||
|
<img
|
||||||
|
class="h-40 w-auto object-contain inline rounded-md"
|
||||||
|
:src="person.photo"
|
||||||
|
:alt="person.name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #footer
|
||||||
|
><p class="text-muted">{{ person.description }}</p></template
|
||||||
|
>
|
||||||
|
</UCard>
|
||||||
|
</UPageGrid>
|
||||||
|
</UPageSection>
|
||||||
|
</UPageBody>
|
||||||
|
</UPage>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
useSeoMeta({
|
||||||
|
title: "组织架构",
|
||||||
|
description:
|
||||||
|
"永平中学校友会组织架构,领导团队、职能部门与专项部门精英汇聚,携手共创卓越未来。",
|
||||||
|
keywords:
|
||||||
|
"永平中学校友会, 校友会组织架构, 领导团队, 职能部门, 专项部门, 理事会成员",
|
||||||
|
ogTitle: "永平中学校友会组织架构",
|
||||||
|
ogDescription:
|
||||||
|
"了解永平中学校友会的领导团队、职能与专项部门,见证校友情谊与组织力量。",
|
||||||
|
ogImage: "https://img.yphsalumni.org/i/2025/11/28/qq4k4z.png",
|
||||||
|
ogType: "website",
|
||||||
|
});
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const generation = route.params.slug;
|
||||||
|
|
||||||
|
const categories = ref(["领导团队", "职能部门", "专项部门"]);
|
||||||
|
|
||||||
|
// TODO: Fetch from api
|
||||||
|
const orgStructure = ref([
|
||||||
|
{
|
||||||
|
name: "李煜斌",
|
||||||
|
position: "主席",
|
||||||
|
category: "领导团队",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qm2sjz.png",
|
||||||
|
description:
|
||||||
|
"全面领导与战略决策,统筹理事会整体工作,确保组织愿景与使命的实现。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "郑惠忠",
|
||||||
|
position: "副主席",
|
||||||
|
category: "领导团队",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qm3nod.png",
|
||||||
|
description: "协助主席制定战略方向,分管外部关系与合作伙伴发展。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "陈月丽",
|
||||||
|
position: "副主席",
|
||||||
|
category: "领导团队",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qm41qp.png",
|
||||||
|
description: "协助主席处理内部事务,分管人力资源与组织文化建设。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "余东照",
|
||||||
|
position: "副主席",
|
||||||
|
category: "领导团队",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qm4izj.png",
|
||||||
|
description: "协助主席推动重点项目,分管创新业务与发展规划。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "蓝宜宏",
|
||||||
|
position: "秘书",
|
||||||
|
category: "职能部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qmrsai.png",
|
||||||
|
description: "文件管理、会议组织、行政协调与日常事务处理。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "陈冠宇",
|
||||||
|
position: "副秘书",
|
||||||
|
category: "职能部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qms4el.png",
|
||||||
|
description: "协助秘书处理文档、会议安排与行政支持工作。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "余粝栎",
|
||||||
|
position: "财政",
|
||||||
|
category: "职能部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qmsnhy.png",
|
||||||
|
description: "全面财务管理、预算控制、资金运作与财务报告。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "曾国书",
|
||||||
|
position: "副财政",
|
||||||
|
category: "职能部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qmslmm.jpg",
|
||||||
|
description: "协助财政处理账务、报销与日常财务管理工作。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "颜志宝",
|
||||||
|
position: "总务",
|
||||||
|
category: "职能部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qnfyb0.png",
|
||||||
|
description: "物资采购、资产管理、场地协调与后勤保障服务。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "温敬富",
|
||||||
|
position: "副总务",
|
||||||
|
category: "职能部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qnglal.png",
|
||||||
|
description: "协助总务处理物资管理、设备维护与后勤支持。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "胡少菲",
|
||||||
|
position: "康乐",
|
||||||
|
category: "职能部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qnre6r.png",
|
||||||
|
description: "文化活动策划、康乐项目组织与会员联谊活动。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "林剑宝",
|
||||||
|
position: "副康乐",
|
||||||
|
category: "职能部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qns52y.png",
|
||||||
|
description: "协助文康组织文体活动、兴趣小组与社交聚会。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "余美枫",
|
||||||
|
position: "福利主任",
|
||||||
|
category: "专项部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qodchd.png",
|
||||||
|
description: "会员福利规划、实施与评估,提升会员满意度。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "郑惠国",
|
||||||
|
position: "副福利主任",
|
||||||
|
category: "专项部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qoe3ua.png",
|
||||||
|
description: "协助会员福利规划、实施与评估,提升会员满意度。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "程靖原",
|
||||||
|
position: "会员籍暨咨询管理",
|
||||||
|
category: "专项部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qof326.png",
|
||||||
|
description: "会员信息管理、咨询服务提供与会员关系维护。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "许福源",
|
||||||
|
position: "副会员籍暨咨询管理",
|
||||||
|
category: "专项部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qog4aa.png",
|
||||||
|
description: "协助会员管理、咨询响应与信息系统维护。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "麦祖奕",
|
||||||
|
position: "副会员籍暨咨询管理",
|
||||||
|
category: "专项部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qoo8lx.png",
|
||||||
|
description: "协助会员管理、咨询响应与信息系统开发。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "许浩铭",
|
||||||
|
position: "奖励金主任",
|
||||||
|
category: "专项部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qoos64.png",
|
||||||
|
description: "奖励金制度设计、评审组织与发放管理。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "黄楚茵",
|
||||||
|
position: "副奖励金主任",
|
||||||
|
category: "专项部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qoxrim.png",
|
||||||
|
description: "协助奖励金评审、资料审核与发放流程管理。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "陈廷添",
|
||||||
|
position: "理事",
|
||||||
|
category: "专项部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qoyjo8.png",
|
||||||
|
description: "参与理事会决策、专项工作推进与建议提出。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "邱康勤",
|
||||||
|
position: "理事",
|
||||||
|
category: "专项部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qp8tni.png",
|
||||||
|
description: "参与理事会决策、专项工作推进与建议提出。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "张键国",
|
||||||
|
position: "稽查",
|
||||||
|
category: "专项部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qp99ia.png",
|
||||||
|
description: "内部审计、合规监督与风险控制管理。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "许皓杰",
|
||||||
|
position: "稽查",
|
||||||
|
category: "专项部门",
|
||||||
|
photo: "https://img.yphsalumni.org/i/2025/11/28/qp9l0z.png",
|
||||||
|
description: "内部审计、合规监督与风险控制管理。",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
||||||
@@ -1,24 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="min-h-screen bg-white">
|
<div class="min-h-screen">
|
||||||
<!-- 装饰性背景元素(浅色柔和光晕) -->
|
|
||||||
<div class="fixed inset-0 overflow-hidden pointer-events-none">
|
|
||||||
<div class="absolute -top-40 -right-40 w-80 h-80 bg-blue-100/40 rounded-full blur-3xl"></div>
|
|
||||||
<div class="absolute -bottom-40 -left-40 w-80 h-80 bg-purple-100/40 rounded-full blur-3xl"></div>
|
|
||||||
<div
|
|
||||||
class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-96 h-96 bg-cyan-100/40 rounded-full blur-3xl">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<section class="relative py-16 px-4 sm:px-6 lg:px-8">
|
<section class="relative py-16 px-4 sm:px-6 lg:px-8">
|
||||||
<div class="container mx-auto max-w-4xl">
|
<div class="container mx-auto max-w-4xl">
|
||||||
<!-- 内容卡片 -->
|
<!-- 内容卡片 -->
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<!-- 卡片装饰边框(浅色渐变) -->
|
<!-- 卡片装饰边框(浅色渐变) -->
|
||||||
<div class="absolute inset-0 bg-gradient-to-r from-blue-100 to-purple-100 rounded-2xl blur-sm"></div>
|
<!-- <div class="absolute inset-0 bg-linear-to-r from-blue-100 to-purple-100 rounded-2xl blur-sm"></div> -->
|
||||||
|
|
||||||
<div class="relative bg-white rounded-xl border border-gray-200 shadow-xl overflow-hidden">
|
<div
|
||||||
|
class="relative rounded-xl border border-gray-200 shadow-xl overflow-hidden"
|
||||||
|
>
|
||||||
<!-- 顶部装饰条(明亮渐变) -->
|
<!-- 顶部装饰条(明亮渐变) -->
|
||||||
<div class="h-1 bg-gradient-to-r from-blue-400 via-purple-400 to-cyan-400"></div>
|
<div
|
||||||
|
class="h-1 bg-linear-to-r from-blue-400 via-purple-400 to-cyan-400"
|
||||||
|
></div>
|
||||||
|
|
||||||
<div class="p-8 sm:p-10 lg:p-12">
|
<div class="p-8 sm:p-10 lg:p-12">
|
||||||
<!-- 内容渲染器 -->
|
<!-- 内容渲染器 -->
|
||||||
@@ -26,16 +21,32 @@
|
|||||||
<ContentRenderer :value="event ?? {}">
|
<ContentRenderer :value="event ?? {}">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="text-center py-16">
|
<div class="text-center py-16">
|
||||||
<div class="inline-flex items-center justify-center w-16 h-16 bg-blue-100 rounded-full mb-4">
|
<div
|
||||||
<svg class="w-8 h-8 text-blue-500 animate-spin" fill="none" viewBox="0 0 24 24">
|
class="inline-flex items-center justify-center w-16 h-16 bg-blue-100 rounded-full mb-4"
|
||||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4">
|
>
|
||||||
</circle>
|
<svg
|
||||||
<path class="opacity-75" fill="currentColor"
|
class="w-8 h-8 text-blue-500 animate-spin"
|
||||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
|
fill="none"
|
||||||
</path>
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
class="opacity-25"
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="4"
|
||||||
|
></circle>
|
||||||
|
<path
|
||||||
|
class="opacity-75"
|
||||||
|
fill="currentColor"
|
||||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||||
|
></path>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-700 text-lg font-medium">内容加载中...</p>
|
<p class="text-gray-700 text-lg font-medium">
|
||||||
|
内容加载中...
|
||||||
|
</p>
|
||||||
<p class="text-gray-400 text-sm mt-2">请稍等片刻</p>
|
<p class="text-gray-400 text-sm mt-2">请稍等片刻</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -50,16 +61,43 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const route = useRoute()
|
const route = useRoute();
|
||||||
const { data: event } = await useAsyncData('event-detail', () =>
|
const { data: event } = await useAsyncData("event-detail", () =>
|
||||||
queryCollection('events')
|
queryCollection("events").path(`/events/${route.params.slug}`).first()
|
||||||
.path(`/events/${route.params.slug}`)
|
);
|
||||||
.first()
|
|
||||||
)
|
|
||||||
|
|
||||||
useHead({
|
if (event.value) {
|
||||||
title: event.value?.title
|
// 1. 确定图片:优先用 ogImage,没有就用 cover
|
||||||
})
|
const shareImage = event.value.ogImage || event.value.cover;
|
||||||
|
|
||||||
|
// 2. 确定标题和描述:优先用 seoTitle,没有就用 title
|
||||||
|
const shareTitle = event.value.seoTitle || event.value.title;
|
||||||
|
const shareDesc = event.value.seoDescription || event.value.description;
|
||||||
|
|
||||||
|
// 3. 注入 SEO
|
||||||
|
useSeoMeta({
|
||||||
|
// 基础
|
||||||
|
title: shareTitle,
|
||||||
|
description: shareDesc,
|
||||||
|
|
||||||
|
// Open Graph (Facebook / WhatsApp)
|
||||||
|
ogTitle: shareTitle,
|
||||||
|
ogDescription: shareDesc,
|
||||||
|
ogImage: shareImage,
|
||||||
|
ogType: "article",
|
||||||
|
|
||||||
|
// Twitter Card
|
||||||
|
twitterCard: "summary_large_image",
|
||||||
|
twitterTitle: shareTitle,
|
||||||
|
twitterDescription: shareDesc,
|
||||||
|
twitterImage: shareImage,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果你用了 nuxt-og-image 模块生成动态图
|
||||||
|
if (shareImage) {
|
||||||
|
defineOgImage({ url: shareImage });
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -12,7 +12,11 @@
|
|||||||
import type { ChangelogVersionProps } from "@nuxt/ui";
|
import type { ChangelogVersionProps } from "@nuxt/ui";
|
||||||
|
|
||||||
const { data: events } = await useAsyncData("events", () =>
|
const { data: events } = await useAsyncData("events", () =>
|
||||||
queryCollection("events").order("date", "DESC").limit(3).all()
|
queryCollection("events")
|
||||||
|
.where("draft", "=", false)
|
||||||
|
.order("date", "DESC")
|
||||||
|
.limit(3)
|
||||||
|
.all()
|
||||||
);
|
);
|
||||||
|
|
||||||
// 将 news 数据转换成 UBlogPosts 可用格式
|
// 将 news 数据转换成 UBlogPosts 可用格式
|
||||||
|
|||||||
@@ -2,12 +2,8 @@
|
|||||||
<UPage>
|
<UPage>
|
||||||
<!-- Hero Banner -->
|
<!-- Hero Banner -->
|
||||||
<UPageHero
|
<UPageHero
|
||||||
class="bg-cover bg-center"
|
:class="heroClass"
|
||||||
style="
|
:style="heroStyle"
|
||||||
background-image: url("/hero-image.jpg");
|
|
||||||
background-color: rgba(255, 255, 255, 0.5); /* Semi-transparent black */
|
|
||||||
background-blend-mode: lighten;
|
|
||||||
"
|
|
||||||
title="连接校友 · 传承精神"
|
title="连接校友 · 传承精神"
|
||||||
description="马来西亚柔佛永平中学校友会官方网站"
|
description="马来西亚柔佛永平中学校友会官方网站"
|
||||||
:links="heroCta"
|
:links="heroCta"
|
||||||
@@ -23,7 +19,7 @@
|
|||||||
|
|
||||||
<!-- 捐赠模块 -->
|
<!-- 捐赠模块 -->
|
||||||
<UPageCTA
|
<UPageCTA
|
||||||
class="bg-secondary"
|
class="bg-secondary-200 dark:bg-secondary-900"
|
||||||
title="支持与捐赠(功能暂未开放)"
|
title="支持与捐赠(功能暂未开放)"
|
||||||
description="您的捐赠将用于奖学金、校园建设及校友活动发展。感谢您对母校的支持!"
|
description="您的捐赠将用于奖学金、校园建设及校友活动发展。感谢您对母校的支持!"
|
||||||
:links="donationLinks"
|
:links="donationLinks"
|
||||||
@@ -34,6 +30,24 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { BlogPostProps } from "@nuxt/ui";
|
import type { BlogPostProps } from "@nuxt/ui";
|
||||||
|
|
||||||
|
useSeoMeta({
|
||||||
|
title: "首页",
|
||||||
|
});
|
||||||
|
|
||||||
|
const colorMode = useColorMode()
|
||||||
|
const heroClass = 'bg-cover bg-center'
|
||||||
|
const heroStyle = computed(() => ({
|
||||||
|
backgroundImage: colorMode.value === 'dark'
|
||||||
|
? 'url("https://img.yphsalumni.org/i/2025/11/28/qzxrpq.png")'
|
||||||
|
: 'url("https://img.yphsalumni.org/i/2025/11/28/qk9fe8.png")',
|
||||||
|
backgroundPositionY: '-40px',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundColor: colorMode.value === 'dark'
|
||||||
|
? 'rgba(0, 0, 0, 0.5)'
|
||||||
|
: 'rgba(255, 255, 255, 0.5)',
|
||||||
|
backgroundBlendMode: colorMode.value === 'dark' ? 'darken' : 'lighten'
|
||||||
|
}))
|
||||||
|
|
||||||
const heroCta = ref([
|
const heroCta = ref([
|
||||||
{
|
{
|
||||||
label: "立即加入我们",
|
label: "立即加入我们",
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ const handleSubmit = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UPage class="bg-primary">
|
<UPage class="bg-primary-400">
|
||||||
<div
|
<div
|
||||||
class="cursor-not-allowed fixed flex items-center justify-center min-h-screen min-w-screen bg-black opacity-50"
|
class="cursor-not-allowed fixed flex items-center justify-center min-h-screen min-w-screen bg-black opacity-50"
|
||||||
>
|
>
|
||||||
|
|||||||
116
app/pages/members/index.vue
Normal file
116
app/pages/members/index.vue
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<UPage>
|
||||||
|
<UContainer>
|
||||||
|
<UPageHeader title="会员总览" description="查询每个会员的信息" />
|
||||||
|
<UPageBody>
|
||||||
|
<UTable :data="members" :columns="columns" />
|
||||||
|
</UPageBody>
|
||||||
|
</UContainer>
|
||||||
|
</UPage>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { TableColumn } from "@nuxt/ui";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
useSeoMeta({
|
||||||
|
title: "会员总览",
|
||||||
|
description:
|
||||||
|
"永平中学校友会会员总览,查询每位校友的毕业年份、届别、加入年份与现居国家。",
|
||||||
|
keywords: "永平中学校友会, 校友会员, 毕业届别, 会员名录, 校友查询",
|
||||||
|
ogTitle: "永平中学校友会会员总览",
|
||||||
|
ogDescription: "浏览永平中学校友会会员资料,了解各届校友的分布与加入年份。",
|
||||||
|
// ogImage: "/members/ogImage.png",
|
||||||
|
ogType: "website",
|
||||||
|
});
|
||||||
|
|
||||||
|
const MemberSchema = z.object({
|
||||||
|
memberId: z.string(),
|
||||||
|
chineseName: z.string(),
|
||||||
|
englishName: z.string(),
|
||||||
|
// ic: z.string(),
|
||||||
|
// mobile: z.string(),
|
||||||
|
// home: z.string(),
|
||||||
|
// email: z.string(),
|
||||||
|
graduateLevel: z.string(),
|
||||||
|
graduateYear: z.string(),
|
||||||
|
// marriageNtatus: z.string(),
|
||||||
|
livingCountry: z.string(),
|
||||||
|
// addressLine1: z.string(),
|
||||||
|
// addressLine2: z.string(),
|
||||||
|
// addressLine3: z.string(),
|
||||||
|
joinedYear: z.string(),
|
||||||
|
// receiptNumber: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
type Member = z.infer<typeof MemberSchema>;
|
||||||
|
|
||||||
|
const { data: members } = await useAsyncData("members", async () => {
|
||||||
|
const file = await queryCollection("members").first();
|
||||||
|
// ✅ 关键点:取 meta.body
|
||||||
|
return MemberSchema.array().parse(file?.meta.body);
|
||||||
|
});
|
||||||
|
|
||||||
|
const columns: TableColumn<Member>[] = [
|
||||||
|
{
|
||||||
|
accessorKey: "memberId",
|
||||||
|
header: "会员编号",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "chineseName",
|
||||||
|
header: "中文姓名",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "englishName",
|
||||||
|
header: "英文姓名",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "graduateYear",
|
||||||
|
header: "毕业/离校年份",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "graduateLevel",
|
||||||
|
header: "毕业/离校届别",
|
||||||
|
cell: ({ row }) => {
|
||||||
|
switch (row.original.graduateLevel) {
|
||||||
|
case "j":
|
||||||
|
// 初中毕业
|
||||||
|
// 如果 row.original.graduateYear 不能转换成数字,就写成初中毕业
|
||||||
|
// 否则计算届别
|
||||||
|
return isNaN(Number(row.original.graduateYear)) || row.original.graduateYear.trim() == ""
|
||||||
|
? "初中毕业"
|
||||||
|
: `初中第 ${Number(row.original.graduateYear) - 1958} 届`;
|
||||||
|
case "s":
|
||||||
|
// 高中毕业
|
||||||
|
return isNaN(Number(row.original.graduateYear)) || row.original.graduateYear.trim() == ""
|
||||||
|
? "高中毕业"
|
||||||
|
: `高中第 ${Number(row.original.graduateYear) - 1965} 届`;
|
||||||
|
case "dj1":
|
||||||
|
return "初一肆业";
|
||||||
|
case "dj2":
|
||||||
|
return "初二肆业";
|
||||||
|
case "dj3":
|
||||||
|
return "初三肆业";
|
||||||
|
case "ds1":
|
||||||
|
return "高一肆业";
|
||||||
|
case "ds2":
|
||||||
|
return "高二肆业";
|
||||||
|
case "ds3":
|
||||||
|
return "高三肆业";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "joinedYear",
|
||||||
|
header: "加入年份",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "livingCountry",
|
||||||
|
header: "现居国家",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
||||||
@@ -18,16 +18,43 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const route = useRoute()
|
const route = useRoute();
|
||||||
const { data: n } = await useAsyncData('new-detail', () =>
|
const { data: n } = await useAsyncData("new-detail", () =>
|
||||||
queryCollection('news')
|
queryCollection("news").path(`/news/${route.params.slug}`).first()
|
||||||
.path(`/news/${route.params.slug}`)
|
);
|
||||||
.first()
|
|
||||||
)
|
|
||||||
|
|
||||||
useHead({
|
if (n.value) {
|
||||||
title: n.value?.title
|
// 1. 确定图片:优先用 ogImage,没有就用 cover
|
||||||
})
|
const shareImage = n.value.ogImage || n.value.cover;
|
||||||
|
|
||||||
|
// 2. 确定标题和描述:优先用 seoTitle,没有就用 title
|
||||||
|
const shareTitle = n.value.seoTitle || n.value.title;
|
||||||
|
const shareDesc = n.value.seoDescription || n.value.description;
|
||||||
|
|
||||||
|
// 3. 注入 SEO
|
||||||
|
useSeoMeta({
|
||||||
|
// 基础
|
||||||
|
title: shareTitle,
|
||||||
|
description: shareDesc,
|
||||||
|
|
||||||
|
// Open Graph (Facebook / WhatsApp)
|
||||||
|
ogTitle: shareTitle,
|
||||||
|
ogDescription: shareDesc,
|
||||||
|
ogImage: shareImage,
|
||||||
|
ogType: "article",
|
||||||
|
|
||||||
|
// Twitter Card
|
||||||
|
twitterCard: "summary_large_image",
|
||||||
|
twitterTitle: shareTitle,
|
||||||
|
twitterDescription: shareDesc,
|
||||||
|
twitterImage: shareImage,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果你用了 nuxt-og-image 模块生成动态图
|
||||||
|
if (shareImage) {
|
||||||
|
defineOgImage({ url: shareImage });
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style></style>
|
<style></style>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { defineContentConfig, defineCollection, z } from "@nuxt/content";
|
import { defineContentConfig, defineCollection, z } from "@nuxt/content";
|
||||||
|
import { asSeoCollection } from "@nuxtjs/seo/content";
|
||||||
|
|
||||||
export default defineContentConfig({
|
export default defineContentConfig({
|
||||||
collections: {
|
collections: {
|
||||||
@@ -12,31 +13,35 @@ export default defineContentConfig({
|
|||||||
date: z.coerce.date(),
|
date: z.coerce.date(),
|
||||||
location: z.string(),
|
location: z.string(),
|
||||||
cover: z.string().url(),
|
cover: z.string().url(),
|
||||||
|
draft: z.boolean().optional().default(false),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
// 新闻集合
|
// 新闻集合
|
||||||
news: defineCollection({
|
news: defineCollection(
|
||||||
type: "page",
|
asSeoCollection({
|
||||||
source: "news/*.md",
|
type: "page",
|
||||||
schema: z.object({
|
source: "news/*.md",
|
||||||
title: z.string(),
|
schema: z.object({
|
||||||
date: z.coerce.date(),
|
title: z.string(),
|
||||||
updated: z.coerce.date().optional(),
|
date: z.coerce.date(),
|
||||||
author: z.string(),
|
updated: z.coerce.date().optional(),
|
||||||
description: z.string(),
|
author: z.string(),
|
||||||
cover: z.string().optional(),
|
description: z.string(),
|
||||||
tags: z.array(z.string()).optional(),
|
cover: z.string().optional(),
|
||||||
category: z.enum(["活动", "通知", "招聘", "博客"]).optional(),
|
tags: z.array(z.string()).optional(),
|
||||||
highlight: z.boolean().optional(),
|
category: z.enum(["活动", "通知", "招聘", "博客"]).optional(),
|
||||||
seoTitle: z.string().optional(),
|
highlight: z.boolean().optional(),
|
||||||
seoDescription: z.string().optional(),
|
seoTitle: z.string().optional(),
|
||||||
ogImage: z.string().optional(),
|
seoDescription: z.string().optional(),
|
||||||
}),
|
ogImage: z.string().optional(),
|
||||||
}),
|
draft: z.boolean().optional().default(false),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
),
|
||||||
// 名人堂
|
// 名人堂
|
||||||
hallOfFames: defineCollection({
|
hallOfFames: defineCollection({
|
||||||
type: "page",
|
type: "page",
|
||||||
source: "hall-of-fames/*md",
|
source: "hall-of-fames/*.md",
|
||||||
schema: z.object({
|
schema: z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
photo: z.string().url(),
|
photo: z.string().url(),
|
||||||
@@ -45,5 +50,28 @@ export default defineContentConfig({
|
|||||||
gallery: z.array(z.string()),
|
gallery: z.array(z.string()),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
// 会员名册
|
||||||
|
members: defineCollection({
|
||||||
|
type: "data",
|
||||||
|
source: "members/members.csv",
|
||||||
|
schema: z.object({
|
||||||
|
// id: z.number(),
|
||||||
|
// chinese_name: z.string(),
|
||||||
|
// english_name: z.string(),
|
||||||
|
// ic: z.string(),
|
||||||
|
// mobile: z.string(),
|
||||||
|
// home: z.string(),
|
||||||
|
// email: z.string(),
|
||||||
|
// graduate_level: z.string(),
|
||||||
|
// graduate_year: z.string(),
|
||||||
|
// marriage_status: z.string(),
|
||||||
|
// living_country: z.string(),
|
||||||
|
// address_line_1: z.string(),
|
||||||
|
// address_line_2: z.string(),
|
||||||
|
// address_line_3: z.string(),
|
||||||
|
// joined_year: z.string(),
|
||||||
|
// receipt_number: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ title: "927 永中 • 钟意你"
|
|||||||
subtitle: "永中校友会 39周年庆"
|
subtitle: "永中校友会 39周年庆"
|
||||||
date: "2025-09-27"
|
date: "2025-09-27"
|
||||||
location: "永平中学校园"
|
location: "永平中学校园"
|
||||||
cover: "/events/20250927-return-to-school/event-photo-1.jpg"
|
cover: "https://img.yphsalumni.org/i/2025/11/28/qr1l7k.jpg"
|
||||||
---
|
---
|
||||||
# 永中校友会39周年会庆午宴 温馨欢聚350人
|
# 永中校友会39周年会庆午宴 温馨欢聚350人
|
||||||
|
|
||||||

|

|
||||||
来宾打卡照(星洲日报记者,邹智敏摄)
|
来宾打卡照(星洲日报记者,邹智敏摄)
|
||||||
|
|
||||||
永平中学校友会于 9 月 27 日举办“927 永中·钟意你”39 周年会庆午宴,吸引约 350 位校友与社会贤达齐聚一堂,共度温馨时光,场面热闹盛大。
|
永平中学校友会于 9 月 27 日举办“927 永中·钟意你”39 周年会庆午宴,吸引约 350 位校友与社会贤达齐聚一堂,共度温馨时光,场面热闹盛大。
|
||||||
|
|
||||||

|

|
||||||
与会嘉宾向永中校友会献上祝福,左起:许敏捷、王飞兴、林添顺、李煜斌、刘镇东、蓝宜宏、傅庆隆、张嘉群及郑凯聪(星洲日报记者,邹智敏摄)
|
与会嘉宾向永中校友会献上祝福,左起:许敏捷、王飞兴、林添顺、李煜斌、刘镇东、蓝宜宏、傅庆隆、张嘉群及郑凯聪(星洲日报记者,邹智敏摄)
|
||||||
|
|
||||||
本次会庆出席嘉宾包括:
|
本次会庆出席嘉宾包括:
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: "柔联校友会 20 届历史就职典礼"
|
title: "柔联校友会 20 届理事就职典礼"
|
||||||
subtitle: "中学生写作比赛颁奖"
|
subtitle: "中学生写作比赛颁奖"
|
||||||
date: "2025-10-09"
|
date: "2025-10-09"
|
||||||
location: "富华冷气酒家 2 楼"
|
location: "富华冷气酒家 2 楼"
|
||||||
cover: "/events/20251009-roulian-xiaoyouhui-20th/event-photo-1.jpg"
|
cover: "https://img.yphsalumni.org/i/2025/11/28/qryfft.jpg"
|
||||||
---
|
---
|
||||||
# 柔联校友会 20 届历史就职典礼
|
# 柔联校友会 20 届理事就职典礼
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
柔佛州华校校友联合会日前举办第 20 届理事就职典礼与 2025 年 “林赛花教育基金” 柔佛州中学生现场写作比赛颁奖典礼,由马来西亚华校校友会联合总会会长萧成兴担任监誓人。
|
柔佛州华校校友联合会日前举办第 20 届理事就职典礼与 2025 年 “林赛花教育基金” 柔佛州中学生现场写作比赛颁奖典礼,由马来西亚华校校友会联合总会会长萧成兴担任监誓人。
|
||||||
|
|
||||||
|
|||||||
113
content/events/20251115-graduation-ceremony-60.md
Normal file
113
content/events/20251115-graduation-ceremony-60.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
---
|
||||||
|
title: "永平中学第 60 届毕业典礼"
|
||||||
|
subtitle: "暨初中第 67 届毕业典礼"
|
||||||
|
date: "2025-11-15"
|
||||||
|
location: "永平中学邱廉书礼堂"
|
||||||
|
cover: "https://img.yphsalumni.org/i/2025/11/27/st6hzt.jpg"
|
||||||
|
draft: false
|
||||||
|
|
||||||
|
# SEO 主要字段
|
||||||
|
description: "永平中学高中第 60 届与初中第 67 届毕业典礼圆满举行,师生与家长齐聚邱廉书礼堂,共同见证学子的重要里程碑,并向荣休教师刘连升老师致以诚挚祝福。"
|
||||||
|
keywords:
|
||||||
|
- 永平中学
|
||||||
|
- 毕业典礼
|
||||||
|
- 高中第60届
|
||||||
|
- 初中第67届
|
||||||
|
- 校园活动
|
||||||
|
- 刘连升老师
|
||||||
|
- 永中校友会
|
||||||
|
|
||||||
|
# --- SEO 专用字段 (对应你的 Zod Schema) ---
|
||||||
|
|
||||||
|
# 对应 schema: seoTitle
|
||||||
|
# 如果不填,代码里会默认使用 title
|
||||||
|
seoTitle: "永平中学第 60 届毕业典礼|初中第 67 届毕业典礼"
|
||||||
|
|
||||||
|
# 对应 schema: seoDescription
|
||||||
|
# 如果不填,代码里会默认使用 description
|
||||||
|
seoDescription: "2025 年永平中学毕业典礼隆重举行,包含师长致辞、奖学金颁发、荣休老师欢送,以及学生精彩演出等精彩环节。"
|
||||||
|
|
||||||
|
# 对应 schema: ogImage
|
||||||
|
# 只有当你想要分享的图片和封面图不一样时才填,否则代码里会默认用 cover
|
||||||
|
ogImage: "https://img.yphsalumni.org/i/2025/11/27/st6hzt.jpg"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 永平中学高中第 60 届、初中第 67 届毕业典礼圆满举行
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
2025 年 11 月 15 日,永平中学邱廉书礼堂见证了一个充满祝福与感动的重要时刻:高中第 60 届与初中第 67 届毕业典礼隆重举行。礼堂内座无虚席,毕业生、家长、师长与嘉宾齐聚一堂,共同庆祝学子们学习旅程的重要里程碑。
|
||||||
|
|
||||||
|
经过六年的努力与成长,高三学生正式迎来人生的新阶段;初三毕业生亦迈向更高层次的挑战。典礼在庄严的国州歌声中启幕,掀开充满意义的一天。
|
||||||
|
|
||||||
|
## 董事长马彣清博士致词(由代表宣读)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
因公务繁忙未克出席,马彣清董事长由董事会秘书长黄仰力董事代表致辞。他转达董事长的寄语:“成功从来不是侥幸,而是毅力不断累积的成果。” 同时肯定毕业生在求学路上的坚持,并勉励他们继续以积极态度面对未来。
|
||||||
|
|
||||||
|
## 张嘉群校长三项叮咛:以品格与眼界开创未来
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
张嘉群校长在致辞中寄语毕业生,并提出三项叮咛,期许他们在往后的道路上继续发光发热:
|
||||||
|
|
||||||
|
### 叮咛一:永怀初心
|
||||||
|
|
||||||
|
* 保持对学习的好奇与热情
|
||||||
|
* 无论未来走得多远,都不要忘记自己最初的信念
|
||||||
|
|
||||||
|
### 叮咛二:中正致远
|
||||||
|
|
||||||
|
* 既要正直谦和,也要坚守原则
|
||||||
|
* 不只追求速度,更追求稳健与长远
|
||||||
|
|
||||||
|
### 叮咛三:站在巨人肩膀上成为巨人
|
||||||
|
|
||||||
|
* 以董事、父母与师长为榜样
|
||||||
|
* 持续成长,努力成为对国家、社会与家庭有贡献的人才
|
||||||
|
|
||||||
|
## 柔佛州董联会主席兼校务顾问陈大锦先生致辞
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
陈大锦先生分享了他访问上海中医药大学的见闻,特别是该校完善的奖助学金制度。他希望本校辅导处与升学资讯处能协助学生把握机会,踊跃申请明年 9 月开课的相关奖学金,为升学之路开拓更多可能。
|
||||||
|
|
||||||
|
## 欢送刘连升老师光荣荣休
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
在典礼上,校方特别举行了“欢送刘连升老师荣休”环节,为这位服务永平中学 35 年、深受师生爱戴的资深教师献上诚挚祝福。
|
||||||
|
|
||||||
|
刘连升老师在任职期间,以其和蔼可亲的性格与渊博的历史知识,陪伴无数学生走过求学阶段。他不仅课堂上“聊古论今”,从古代帝王先烈谈到世界变迁,更在课余时与学生畅谈时事,从传统文化一路聊到新兴科技与 AI 技术,是学生眼中既严谨又风趣的良师益友。
|
||||||
|
|
||||||
|
许多毕业生回忆,与刘老师的关系早已超越师生,成为无话不谈的朋友。他的教学风格温和细腻,待人真诚,使无数学子在成长路上深受启发。
|
||||||
|
|
||||||
|
典礼现场气氛温馨感人,全体与会者向刘老师献上热烈掌声,感谢他 35 年来在校园里的付出与贡献。校方也祝愿刘老师退休生活悠然自得、健康安康,继续以他的人生智慧照亮身边的人。
|
||||||
|
|
||||||
|
## 颁发董事长设立的奖学金
|
||||||
|
|
||||||
|
典礼上同步进行董事长设立的各项奖学金颁发仪式,以表扬在学业、操行与综合表现上有卓越成绩的学生。
|
||||||
|
(详见[图集](https://drive.google.com/drive/folders/1n3aRxxBwn-k6jzAOogV2ChBHKDA0c0qG))
|
||||||
|
|
||||||
|
## 特别演出:永中之星冠军林妤桐献唱
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
在典礼进入高潮之前,校方安排了一场温馨惊喜表演 —— 第一届“永中之星”冠军、来自初三诚的林妤桐学妹献唱两首歌曲:《Forever Young》以及《凤凰花开的路口》。她以清亮而富感染力的歌声,向高三学长姐献上最真挚的祝福,也为典礼增添一份青春与深情的色彩。
|
||||||
|
|
||||||
|
## 高三教师团队呈献毕业回忆视频
|
||||||
|
|
||||||
|
随后,由高三各班班导师亲自策划的毕业回忆视频在礼堂大屏幕播出。画面记录了学生们在校园中的点点滴滴,从努力备考到日常生活,从欢笑到奋斗,皆在此刻化为珍贵回忆。
|
||||||
|
|
||||||
|
校方希望学生们在未来面对困难与挫折时,也能记起这份勇敢、乐观与纯真,继续向前迈进。
|
||||||
|
|
||||||
|
## 歌声中道别,在掌声中启航
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
典礼尾声,高三毕业生深情演唱《再见》,而初三与高三学生共同合唱《毕业歌》,歌声回荡礼堂,为今年的毕业典礼写下温馨句点。现场气氛在歌声中变得格外动人,许多毕业生眼眶泛红,纷纷表示将铭记这一刻。
|
||||||
|
|
||||||
|
上午 11 时正,典礼圆满结束。为感谢师生与来宾的参与,马彣清董事长特别准备了供 600 人享用的自助餐,设宴于礼堂楼下。现场气氛融洽温馨。同时,本校友会也成功招收 14 名新会员,为未来的发展注入新的力量。
|
||||||
|
|
||||||
|
[2025 年毕业典礼图集](https://drive.google.com/drive/folders/1n3aRxxBwn-k6jzAOogV2ChBHKDA0c0qG)
|
||||||
1
content/members/members-sample.csv
Normal file
1
content/members/members-sample.csv
Normal file
@@ -0,0 +1 @@
|
|||||||
|
memberId,chineseName,englishName,ic,mobile,home,email,graduateLevel,,graduateYear,marriageStatus,livingCountry,addressLine1,addressLine2,addressLine3,joinedYear,receiptNumber
|
||||||
|
@@ -4,14 +4,13 @@ date: "2025-10-01"
|
|||||||
updated: "2025-10-01"
|
updated: "2025-10-01"
|
||||||
author: "麦祖奕学长"
|
author: "麦祖奕学长"
|
||||||
description: "永中校友会官网正式上线,为校友提供最新资讯、活动报名及互动交流平台。"
|
description: "永中校友会官网正式上线,为校友提供最新资讯、活动报名及互动交流平台。"
|
||||||
cover: "/news/20251001-official-web-launch/Screenshot.png"
|
cover: "https://img.yphsalumni.org/i/2025/11/28/qqc3ft.png"
|
||||||
tags: ["活动", "公告", "产品更新"]
|
tags: ["活动", "公告", "产品更新"]
|
||||||
category: "通知"
|
category: "通知"
|
||||||
highlight: true
|
highlight: true
|
||||||
seoTitle: "永中校友会官网上线 | 最新活动与资讯平台"
|
seoTitle: "永中校友会官网上线 | 最新活动与资讯平台"
|
||||||
seoDescription: "永中校友会官网正式上线,校友可在平台获取最新资讯、报名活动及参与互动。"
|
seoDescription: "永中校友会官网正式上线,校友可在平台获取最新资讯、报名活动及参与互动。"
|
||||||
ogImage: "/images/og/news-launch.jpg"
|
ogImage: "https://img.yphsalumni.org/i/2025/11/28/qqc3ft.png"
|
||||||
slug: "/news/20251001-official-web-launch"
|
|
||||||
---
|
---
|
||||||
永中校友会官网正式上线啦!🎉
|
永中校友会官网正式上线啦!🎉
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
title: "永平中学校友会与校友联络处的区别"
|
||||||
|
date: "2025-11-28"
|
||||||
|
updated: "2025-11-28"
|
||||||
|
author: "永平中学校友会"
|
||||||
|
description: "毕业校友常说“我都加入校友群组了”,实则误入了校友联络处。本文厘清其与永平中学校友会的区别与使命。"
|
||||||
|
cover: "https://img.yphsalumni.org/i/2025/11/28/sbk8ue.jpeg"
|
||||||
|
tags: ["永平中学", "校友会", "校友联络处", "区别", "公告"]
|
||||||
|
category: "公告"
|
||||||
|
highlight: true
|
||||||
|
seoTitle: "永平中学校友会与校友联络处的区别 | 官方说明"
|
||||||
|
seoDescription: "毕业校友常说“我都加入校友群组了”,实则误入了校友联络处。本文厘清其与永平中学校友会的区别与使命。"
|
||||||
|
ogImage: "https://img.yphsalumni.org/i/2025/11/28/sbk8ue.jpeg"
|
||||||
|
---
|
||||||
|
|
||||||
|
**永平中学校友会致广大校友的一封信**
|
||||||
|
|
||||||
|
亲爱的永平中学校友们:
|
||||||
|
|
||||||
|
在近期的毕业典礼上,我们欣喜地听到许多新校友分享“我已加入校友群组”的喜悦。这份对母校的深切情谊,令我们深深感动。
|
||||||
|
|
||||||
|
我们同时也注意到,部分校友可能产生了一个美丽的误会:大家加入的“校友联络处”群组,是由学校董事会设立的官方联络平台,主要负责校友信息的收集与传达。而我们所熟知的“永平中学校友会”,则是一个由历届毕业生**自发创建、独立运作的校友社区组织**。
|
||||||
|
|
||||||
|
自成立以来,永平中学校友会始终秉承以下宗旨,由校友共建、为校友服务:
|
||||||
|
|
||||||
|
- **联结校友情谊**:搭建纯粹、活跃的交流平台,让友谊跨越届别。
|
||||||
|
- **支持母校发展**:凝聚校友力量,回馈我们共同的永平中学。
|
||||||
|
- **推动教育、文化与社区活动**:举办丰富多彩的活动,丰富校友生活。
|
||||||
|
- **建立校友与在校生之间的桥梁**:传承经验与关怀,助力学弟学妹成长。
|
||||||
|
|
||||||
|
校友联络处与校友会,二者服务校友的初心一致,是相辅相成的伙伴。我们由衷欢迎每一位热心校友加入我们这个充满活力的毕业生社区,共同为母校的发展注入来自校友群体的独特力量!
|
||||||
|
|
||||||
|
**加入我们,共同书写校友故事:**
|
||||||
|
|
||||||
|
校友会官方平台:https://yphsalumni.org/
|
||||||
|
|
||||||
|
<!-- 联系我们:[请在此处填入邮箱或具体负责人联系方式] -->
|
||||||
|
|
||||||
|
永平中学校友会<br/>
|
||||||
|
2025年11月28日
|
||||||
54
docs/20251128-misunderstanding-yphsalumni-and-alumnigroup.md
Normal file
54
docs/20251128-misunderstanding-yphsalumni-and-alumnigroup.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
下面给你一个**实用、可直接交给设计师落地的公告封面设计方案**,基于你们「校友会 vs 校友联络处」容易混淆这一情境,重点是**清晰、正式、易识别、避免再次误会**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🎨 公告封面设计方案(适用于官网首页 / Banner / WhatsApp 分享图)
|
||||||
|
|
||||||
|
## **1. 视觉主题**
|
||||||
|
|
||||||
|
**关键词:清晰区隔、正式感、组织可信度**
|
||||||
|
色调保持学校主色系(如#fb9e3a、#fcef91),并加上一条亮色做强调,提升官方感。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **2. 版式构成**
|
||||||
|
|
||||||
|
### ### **A. 顶部:醒目的组织身份**
|
||||||
|
|
||||||
|
**「永平中学校友会」**
|
||||||
|
|
||||||
|
* 使用学校和校友会 logo(左) + 标题文字(右)
|
||||||
|
* 字体使用较厚重、带权威感的 Serif / Sans Serif
|
||||||
|
* 加上小字「官方公告」标签
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **B. 中间:公告主标题(视觉核心)**
|
||||||
|
|
||||||
|
标题建议直接点出“澄清 & 提醒”的意图:
|
||||||
|
|
||||||
|
* **《校友会与校友联络处群组区分公告》**
|
||||||
|
|
||||||
|
字体加粗,居中,字号大,确保在手机上也能一眼看懂。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **C. 配图 / 图标建议**
|
||||||
|
|
||||||
|
#### **徽章背景淡化**
|
||||||
|
|
||||||
|
校徽做 20% 透明大背景,体现官方权威。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **3. 尺寸 & 格式(设计师直接可用)**
|
||||||
|
|
||||||
|
* Website banner: **1920×1080**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **4. 文案建议(印在封面下方的小字)**
|
||||||
|
|
||||||
|
> “近期部分校友误将校友联络处群组误认为校友会官方群组,特此澄清。”
|
||||||
|
|
||||||
|
---
|
||||||
56
docs/Onboarding Message.md
Normal file
56
docs/Onboarding Message.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
**主题:欢迎加入永平中学校友会!**
|
||||||
|
|
||||||
|
亲爱的校友,您好!
|
||||||
|
|
||||||
|
感谢您加入 **永平中学校友会(Yong Peng High School Alumni Association)**!
|
||||||
|
自您成为会员的这一刻起,我们正式迎来了一位新的伙伴,也多了一份共同守护母校与社区的力量。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 **我们是谁?**
|
||||||
|
|
||||||
|
永平中学校友会成立以来,一直致力于:
|
||||||
|
|
||||||
|
* **联结校友情谊**
|
||||||
|
* **支持母校发展**
|
||||||
|
* **推动教育、文化与社区活动**
|
||||||
|
* **建立校友与在校生之间的桥梁**
|
||||||
|
|
||||||
|
您的加入,让我们更有力量继续前进。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📌 **作为会员,您可享有:**
|
||||||
|
|
||||||
|
* 活动、讲座、聚会的**优先参与权**
|
||||||
|
* 校友资讯、重要公告的**第一时间通知**
|
||||||
|
* 参与校友会项目、社区计划的**贡献机会**
|
||||||
|
* 与来自各领域校友建立联系的**交流平台**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗓️ **接下来能做什么?**
|
||||||
|
|
||||||
|
为帮助您更快融入校友会生态,我们建议:
|
||||||
|
|
||||||
|
1. **保存本会的官方联系方式**(WhatsApp / 社媒)
|
||||||
|
2. **访问我们的官网**
|
||||||
|
3. **留意即将发布的活动资讯**
|
||||||
|
4. 若愿意参与志工 / 筹委,请随时回复我们
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ❤️ **我们欢迎您与我们同行**
|
||||||
|
|
||||||
|
无论您身处何地,校友会的大门永远为您敞开。
|
||||||
|
让我们一同继续延续永中的精神,传承、回馈、成长。
|
||||||
|
|
||||||
|
若您有任何疑问,欢迎随时与我们联系。
|
||||||
|
|
||||||
|
谢谢您再次加入我们,
|
||||||
|
**欢迎回家!**
|
||||||
|
|
||||||
|
**永平中学校友会**
|
||||||
|
Yong Peng High School Alumni Association
|
||||||
|
https://yphsalumni.org
|
||||||
|
|
||||||
89
docs/PPT Designs v1.md
Normal file
89
docs/PPT Designs v1.md
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
目标时长
|
||||||
|
|
||||||
|
- 5–7 分钟(6–8 页),节奏轻快,现场可插入 60–90 秒演示
|
||||||
|
|
||||||
|
推荐结构(6–8 页)
|
||||||
|
|
||||||
|
- 封面:项目名称、口号、日期与主办单位
|
||||||
|
- 为什么做:痛点与目标
|
||||||
|
- 核心功能:面向校友和公众的主要板块
|
||||||
|
- 设计与技术:品牌视觉与技术栈亮点
|
||||||
|
- 运营与上线:内容节奏、参与方式与上线计划
|
||||||
|
- 路线图:后续可期与合作方向
|
||||||
|
- 现场演示:30–90 秒 Demo 流程说明
|
||||||
|
- 行动号召与致谢:访问方式、参与方式、鸣谢
|
||||||
|
|
||||||
|
每页文案示例(可直接放入 PPT)
|
||||||
|
|
||||||
|
- 封面
|
||||||
|
- 标题:永平中学校友会官网上线发布
|
||||||
|
- 口号:连接校友 · 传承精神
|
||||||
|
- 时间地点:2025.10 永平中学
|
||||||
|
- 主办:永平中学校友会 | 技术支持:Tootaio Studio
|
||||||
|
- 右侧放二维码(yphsalumni.org)+ public/Logo.svg
|
||||||
|
- 为什么做(愿景与价值)
|
||||||
|
- 信息更集中:新闻公告、活动安排、校友故事统一发布
|
||||||
|
- 连接更紧密:线上平台增强校友互联与参与感
|
||||||
|
- 传承更长久:记录校史、人事与精神资产
|
||||||
|
- 数字化基建:为后续报名、征文、捐赠等打基础
|
||||||
|
- 核心功能(首发)
|
||||||
|
- 新闻与公告:重要信息一处直达
|
||||||
|
- 校友活动:预告、报名与回顾
|
||||||
|
- 名人堂:优秀校友故事与图集
|
||||||
|
- 关于校友会:宗旨、会徽、校歌
|
||||||
|
- 入会申请:表单已就绪(当前为占位,逐步开通)
|
||||||
|
- 后台脚手架:内容与会员管理后续接通
|
||||||
|
- 设计与技术(可信与可持续)
|
||||||
|
- 视觉基因:主色 #fb9e3a、副色 #fcef91(温暖、亲和、纪念感)
|
||||||
|
- 易读排版:专属 Markdown 样式,移动优先
|
||||||
|
- 技术栈:Nuxt 4、TypeScript、Tailwind CSS、@nuxt/ui、@nuxt/content
|
||||||
|
- SEO 就绪:Sitemap、Robots、Meta/OG/Twitter 卡片
|
||||||
|
- 部署灵活:可静态托管,也可 SSR 托管
|
||||||
|
- 运营与上线(如何用起来)
|
||||||
|
- 内容节奏:每周1–2篇新闻/活动;名人堂按策划发布
|
||||||
|
- 投稿机制:校友/老师/班级提供图文,统一编审发布
|
||||||
|
- 渠道联动:官网首发,同步 Facebook/TikTok
|
||||||
|
- 数据分析:尊重隐私的访问统计,用于优化内容结构
|
||||||
|
- 路线图(Roadmap)
|
||||||
|
- Q4:入会表单接通审核流程、内容 CRUD 后台
|
||||||
|
- Q1:活动报名/签到、相册;捐赠模块调研
|
||||||
|
- Q2:校友企业与招聘、专题档案与时间轴
|
||||||
|
- 长期:多语言、校友地图、移动端优化
|
||||||
|
- 现场演示(30–90 秒)
|
||||||
|
- 首页开场 → 打开一条新闻 → 切到活动详情 → 看名人堂图集
|
||||||
|
- 快速展示入会表单(目前“功能未开放”提示)
|
||||||
|
- 如需:展示后台仪表盘框架(结构就绪,等接入)
|
||||||
|
- 行动号召与致谢
|
||||||
|
- 访问:yphsalumni.org(扫码关注)
|
||||||
|
- 参与:投稿、提供史料、报名志愿者、提供赞助与合作
|
||||||
|
- 关注我们:Facebook「永平中学校友会」、TikTok「@yphs.alumni」
|
||||||
|
- 致谢:校董会/校方/校友与志愿者、Tootaio Studio 技术支持
|
||||||
|
|
||||||
|
视觉与排版建议
|
||||||
|
|
||||||
|
- 版式:16:9,黑/深灰背景或浅色质感底,突出橙色点缀
|
||||||
|
- 字体:中文优先思源黑体/Noto Sans SC;标题粗体、正文中等
|
||||||
|
- 统一元素:使用 public/Logo.svg 与 public/hero-image-2.jpg 作封面/过渡图
|
||||||
|
- 图片素材:新闻/活动封面取自 public/news/*、public/events/*、public/hall-of-fame/*
|
||||||
|
- 最少字多图:每页 3–5 条要点,每条不超过一行半
|
||||||
|
|
||||||
|
演示备选方案(网络不稳时)
|
||||||
|
|
||||||
|
- 准备 30–60 秒无声/配乐屏录视频(首页→新闻→活动→名人堂→入会)
|
||||||
|
- 关键页面截图备选:主页、新闻详情、活动详情、名人堂人物页、后台仪表盘
|
||||||
|
- 本地二维码图片(指向官网),避免临场生成失败
|
||||||
|
|
||||||
|
可选加页(视场合增减)
|
||||||
|
|
||||||
|
- 用户故事:校友/老师/在校生各 1 个使用场景
|
||||||
|
- 隐私与安全:不采集敏感信息、分析工具与停用开关
|
||||||
|
- 合作与赞助:纪念册/活动共创与鸣谢方式
|
||||||
|
- FAQ:如何投稿、如何加入志愿者、如何反馈问题
|
||||||
|
|
||||||
|
素材清单(制作 PPT 前先备齐)
|
||||||
|
|
||||||
|
- Logo 与主视觉:public/Logo.svg、public/hero-image-2.jpg
|
||||||
|
- 二维码:yphsalumni.org(建议白底黑码,配校色边框)
|
||||||
|
- 页面截图:主页、新闻、活动、名人堂、入会、后台
|
||||||
|
- 文案确认:宗旨口号、愿景 1 句话、路线图 3–5 条
|
||||||
|
- 联系方式:官方邮箱/表单链接、官方社媒链接
|
||||||
109
docs/PPT Designs v2.md
Normal file
109
docs/PPT Designs v2.md
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
呈现原则
|
||||||
|
|
||||||
|
- 低调而清晰:把“报效 + 价值 + 开源”讲清楚,不喧宾夺主。
|
||||||
|
- 一致口径:PPT、主持人口播、新闻通稿用同一措辞。
|
||||||
|
- 可验证与可持续:展示交付范围和开源地址,强调长期可维护。
|
||||||
|
|
||||||
|
推荐版式(7–9 页)
|
||||||
|
|
||||||
|
- 封面:项目名、口号、日期、主办单位、技术支持
|
||||||
|
- 背景与目标:为什么要做官网
|
||||||
|
- 亮点与模块:新闻/活动/名人堂/关于/入会(占位)/后台脚手架
|
||||||
|
- 交付与价值:高定项目、价值、交付清单
|
||||||
|
- 开源与授权:开源协议、仓库地址、版权说明
|
||||||
|
- 运营与上线:内容节奏、参与方式、渠道联动
|
||||||
|
- 路线图:后续工作与可期
|
||||||
|
- 现场演示:流程提示(30–90 秒)
|
||||||
|
- 鸣谢与行动号召:访问方式、参与方式、致谢
|
||||||
|
|
||||||
|
关键页完整文案(可直接放入 PPT)
|
||||||
|
|
||||||
|
- 封面
|
||||||
|
- 标题:永平中学校友会官网上线发布
|
||||||
|
- 口号:连接校友 · 传承精神
|
||||||
|
- 时间地点:2025.10 永平中学
|
||||||
|
- 主办单位:永平中学校友会
|
||||||
|
- 技术支持(赞助):Tootaio Studio
|
||||||
|
- 右侧放站点二维码(yphsalumni.org)与 public/Logo.svg
|
||||||
|
- 背景与目标
|
||||||
|
- 信息更集中:新闻公告、活动、校友故事统一发布
|
||||||
|
- 连接更紧密:线上平台增强凝聚力与参与感
|
||||||
|
- 长期可持续:标准化内容、可复用组件、开源治理
|
||||||
|
- 数字化基建:为报名、征文、捐赠等后续功能打基础
|
||||||
|
- 亮点与模块
|
||||||
|
- 新闻/公告:首发权威信息,SEO 友好
|
||||||
|
- 校友活动:预告、回顾与多媒体内容
|
||||||
|
- 名人堂:人物故事与图集
|
||||||
|
- 关于校友会:宗旨、会徽、校歌
|
||||||
|
- 入会申请:表单就绪(将逐步开通流程)
|
||||||
|
- 管理后台:内容与会员管理脚手架,随时对接后端
|
||||||
|
- 交付与价值(高定与报效)
|
||||||
|
- 本项目由 Tootaio Studio 报效永平中学校友会
|
||||||
|
- 价值:RM 30,000(高定项目)
|
||||||
|
- 交付清单(概览)
|
||||||
|
- 产品与信息架构:栏目与内容模型设计
|
||||||
|
- 视觉与 UI:主题风格、导航、Markdown 样式与组件库适配
|
||||||
|
- 前端开发:Nuxt 4、TypeScript、Tailwind、@nuxt/ui、@nuxt/content 集成
|
||||||
|
- 内容迁移与示例:新闻/活动/名人堂样例、封面与图集
|
||||||
|
- SEO 与分析:Sitemap/Robots/OG 元信息、可选 Umami 统计接入
|
||||||
|
- 构建与部署:静态导出/SSR 双方案、上线脚本与文档
|
||||||
|
- 说明:以上价值不含域名、服务器及第三方服务费用
|
||||||
|
- 开源与授权(透明与共建)
|
||||||
|
- 代码开源:项目源代码公开,便于校友与开发者共建
|
||||||
|
- 开源协议:MIT/Apache-2.0(二选一,建议在仓库添加 LICENSE)
|
||||||
|
- 仓库地址:Github 仓库链接与二维码(上线后填入)
|
||||||
|
- 版权说明:代码遵循开源协议;文字与图片等内容版权归原作者/校友会所有
|
||||||
|
- 贡献方式:提交 Issue/PR,按 content.config.ts 字段规范撰写内容
|
||||||
|
- 运营与上线
|
||||||
|
- 内容节奏:每周 1–2 篇新闻/活动;名人堂按策划发布
|
||||||
|
- 参与方式:投稿、提供史料、报名志愿者、技术共建
|
||||||
|
- 渠道联动:官网首发,同步 Facebook/TikTok
|
||||||
|
- 数据与隐私:尊重用户隐私,分析仅用于内容优化
|
||||||
|
- 路线图(示例)
|
||||||
|
- Q4:入会表单接通审核流程、内容后台 CRUD
|
||||||
|
- Q1:活动报名/签到、相册;捐赠模块调研
|
||||||
|
- Q2:校友企业与招聘、专题档案与时间轴
|
||||||
|
- 长期:多语言、校友地图、移动端优化
|
||||||
|
- 现场演示(30–90 秒)
|
||||||
|
- 首页 → 新闻详情 → 活动详情 → 名人堂图集 → 入会表单(现提示“功能未开放”)
|
||||||
|
- 若网络不稳:准备 45 秒屏录视频与关键页面截图备用
|
||||||
|
- 鸣谢与行动号召
|
||||||
|
- 访问:yphsalumni.org(扫码)
|
||||||
|
- 参与:投稿/志愿者/合作/赞助(留邮箱或表单链接)
|
||||||
|
- 鸣谢:校董会/校方/校友与志愿者、Tootaio Studio 技术支持
|
||||||
|
- 结束语:连接校友 · 传承精神
|
||||||
|
|
||||||
|
金额与赞助信息的呈现技巧
|
||||||
|
|
||||||
|
- 将“报效/价值/开源”分散露出,避免单页过度“商业化”:封面页署名(技术支持)、中段“交付与价值”页清晰展现、高尾页鸣谢再次确认。
|
||||||
|
- “RM30,000”用一行大数字配副标题“高定项目(报效)”,旁边放交付清单,强调价值而不过度营销。
|
||||||
|
- 视觉上弱化工作室 Logo(相对校友会 Logo 约 1/2–1/3 宽度),保持庄重。
|
||||||
|
|
||||||
|
主持人口播(15–20 秒)
|
||||||
|
|
||||||
|
- “本次官网由 Tootaio Studio 报效搭建,项目价值 RM 三万,为高定定制并全面开源。感谢工作室团队的专业支持,也欢迎校友与开发者共同参与建设。”
|
||||||
|
|
||||||
|
新闻通稿段落(可复用)
|
||||||
|
|
||||||
|
- “永平中学校友会官网今日正式上线。该项目由 Tootaio Studio 报效支持,项目价值 RM30,000,为高定定制网站并以开源方式发布。平台将持续发布新闻活动、名人堂故事等内容,欢迎校友访问
|
||||||
|
yphsalumni.org 并参与共建。”
|
||||||
|
|
||||||
|
素材清单
|
||||||
|
|
||||||
|
- 官网二维码(yphsalumni.org)
|
||||||
|
- 仓库二维码(开源后补充)
|
||||||
|
- Logo:public/Logo.svg、主视觉 public/hero-image-2.jpg
|
||||||
|
- 页面截图:主页、新闻、活动、名人堂、入会(与后台仪表盘)
|
||||||
|
- 一页式“交付清单与价值”图(可用饼图/图标矩阵)
|
||||||
|
|
||||||
|
合规与落地建议
|
||||||
|
|
||||||
|
- 确认开源协议(建议 MIT)并在仓库根目录添加 LICENSE
|
||||||
|
- 在 README.md 保留“报效/开源”说明与致谢,PPT 与通稿用同一表述
|
||||||
|
- 金额声明附说明:不含域名/服务器/第三方服务费
|
||||||
|
- 现场背景板与屏幕页脚统一“技术支持:Tootaio Studio”
|
||||||
|
|
||||||
|
需要的话,我可以:
|
||||||
|
|
||||||
|
- 直接为你生成一份可放映的 Marp/Reveal.js Markdown 幻灯,或输出 PPTX 模板(含上述文案与占位图)。
|
||||||
|
- 创建“交付与价值”信息图一页(AI 矢量),用于 PPT 与对外物料。
|
||||||
57
docs/Statistic Card 建议.md
Normal file
57
docs/Statistic Card 建议.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
### 🎓 校友群体类(展示规模)
|
||||||
|
|
||||||
|
* **注册会员人数**(基础指标)
|
||||||
|
* **校友分布地区数**(如「分布于 12 个国家」)
|
||||||
|
* **历届毕业生总数**
|
||||||
|
* **校友企业数**(若可统计,代表社会影响力)
|
||||||
|
* **理事人数 / 活跃志工人数**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 💰 贡献与资源类(展示凝聚力)
|
||||||
|
|
||||||
|
* **教育基金总额**(例如「林赛花教育基金已累计 RM XXX,XXX」)
|
||||||
|
* **奖助学金受惠人数**
|
||||||
|
* **年度捐款总额 / 参与人数**
|
||||||
|
* **历年活动赞助商数量**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🏛️ 历史与传承类(展示深度)
|
||||||
|
|
||||||
|
* **成立年份 / 周年数**(基础指标)
|
||||||
|
* **举办活动次数**(历届聚会 / 座谈 / 校庆)
|
||||||
|
* **出版刊物 / 纪念册数量**
|
||||||
|
* **历届理事会届数**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🌏 影响与传播类(展示影响面)
|
||||||
|
|
||||||
|
* **官方网站访问量 / 月均访问数**
|
||||||
|
* **社交媒体关注人数 / 互动量**
|
||||||
|
* **媒体报道次数**(可简化为“媒体曝光数”)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 💡 进阶玩法(让页面更有活力)
|
||||||
|
|
||||||
|
* **“活跃率”**:例如「本年度活动参与率 72%」
|
||||||
|
* **“成长曲线”**:每年会员人数变化趋势(用小图表示)
|
||||||
|
* **“校友情谊值”**:趣味指标,比如根据活动签到 / 捐赠 / 投稿自动算出的综合分数(可 Gamify)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ✅ 推荐组合(简洁又有格调)
|
||||||
|
|
||||||
|
| 分类 | 指标 | 示例展示 |
|
||||||
|
| -------- | ------------- | ---------------- |
|
||||||
|
| 校友群体 | 会员总数 | 1,237 位注册会员 |
|
||||||
|
| 成立历程 | 成立时间 | 创立于 1985 年 |
|
||||||
|
| 贡献力量 | 教育基金累计 | RM 245,000 |
|
||||||
|
| 活动热度 | 年度活动次数 | 12 场活动 |
|
||||||
|
| 社群影响 | Facebook 关注 | 3.4k Followers |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
要我帮你把这五个指标设计成一个统一风格的 **Statistic Card UI**(适合放在 Nuxt + @nuxt/ui 项目里)吗?我可以直接给出结构和样式建议 🔥
|
||||||
@@ -5,14 +5,15 @@ export default defineNuxtConfig({
|
|||||||
compatibilityDate: "2025-07-15",
|
compatibilityDate: "2025-07-15",
|
||||||
devtools: { enabled: true },
|
devtools: { enabled: true },
|
||||||
modules: [
|
modules: [
|
||||||
|
"@nuxt/ui",
|
||||||
|
"@nuxtjs/seo",
|
||||||
"@nuxt/content",
|
"@nuxt/content",
|
||||||
"@nuxt/image",
|
"@nuxt/image",
|
||||||
"@nuxt/ui",
|
|
||||||
"reka-ui/nuxt",
|
"reka-ui/nuxt",
|
||||||
"@nuxtjs/robots",
|
"@nuxtjs/robots",
|
||||||
"@nuxtjs/seo",
|
|
||||||
"@nuxtjs/sitemap",
|
"@nuxtjs/sitemap",
|
||||||
],
|
],
|
||||||
|
ssr: true,
|
||||||
css: ["~/assets/css/main.css"],
|
css: ["~/assets/css/main.css"],
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [tailwindcss()],
|
plugins: [tailwindcss()],
|
||||||
@@ -50,7 +51,7 @@ export default defineNuxtConfig({
|
|||||||
{ property: "og:url", content: "https://yphsalumni.org" }, // ✅ 换成你网站的真实域名
|
{ property: "og:url", content: "https://yphsalumni.org" }, // ✅ 换成你网站的真实域名
|
||||||
{
|
{
|
||||||
property: "og:image",
|
property: "og:image",
|
||||||
content: "https://yphsalumni.org/hero-image.jpg",
|
content: "https://img.yphsalumni.org/i/2025/11/28/qk9fe8.png",
|
||||||
}, // ✅ 上传一张封面图
|
}, // ✅ 上传一张封面图
|
||||||
|
|
||||||
// Twitter Card
|
// Twitter Card
|
||||||
@@ -62,7 +63,7 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "twitter:image",
|
name: "twitter:image",
|
||||||
content: "https://yphsalumni.org/hero-image.jpg",
|
content: "https://img.yphsalumni.org/i/2025/11/28/qk9fe8.png",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
3764
pnpm-lock.yaml
generated
3764
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 116 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 131 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 58 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 96 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 MiB |
Reference in New Issue
Block a user