後臺整理

This commit is contained in:
2026-08-19 16:05:52 +08:00
parent 5d30332267
commit d51f26e170
10 changed files with 56 additions and 23 deletions
+2 -2
View File
@@ -81,7 +81,7 @@
**待確認:**
- developer-rules 健檢尚未執行
- `sechskies_fans`(新獨立專案)本機尚未建 MySQL 資料庫、尚未跑過 `admin/setup.php`;Render 部署中,資料庫主機未定
- `portal-nav.js` 新增的「水晶練習室」項目目前是 `data-coming-soon` 佔位(href=`#`),等 sechskies_fans 網址確定後要補上真實外部連結並移除 coming-soon 標記
- `portal-nav.js` 新增的「小黃練習室」項目目前是 `data-coming-soon` 佔位(href=`#`),等 sechskies_fans 網址確定後要補上真實外部連結並移除 coming-soon 標記
**歷史定位(文案不可再寫錯):**
- 水晶熱舞社是水晶男孩粉絲自主成立的舞蹈社團,並非水晶男孩推廣部旗下組織
@@ -96,7 +96,7 @@
- `extra/site-guide.html` 同步更新:全員發瘋 → 世紀級寶藏
- 新增 `admin/` 推廣部後臺第一階段:登入、控制台、管理者帳號、通用 CRUD、媒體上傳及公開狀態總覽
- 水晶熱舞社/水晶練習室/偶像練習生已於 2026-08-04 拆成獨立專案 `sechskies_fans`(另一個 repo,路徑 `d:\Developer\projects\sechskies_fans`,不在本站範圍):30TH 應援報名表單、練舞清單、後台 CRUD 與管理者登入都已搬走並改用自己的資料庫;`extra/site-guide.html` 與本站 `admin/bootstrap.php``admin/database/schema.sql` 已同步移除相關項目
- `portal-nav.js` 頂欄新增第 7 項「水晶練習室」(Yellow Note 之後),連到獨立專案 sechskies_fans`extra/site-guide.html` 同步新增對應項目;目前是 coming-soon 佔位,尚未接上真實網址
- `portal-nav.js` 頂欄新增第 7 項「小黃練習室」(Yellow Note 之後),連到獨立專案 sechskies_fans`extra/site-guide.html` 同步新增對應項目;目前是 coming-soon 佔位,尚未接上真實網址
- `variety/` 資料夾整個改名為 `vedio/`,同步修正 portal-nav.js、site-guide.html、style.css 註解、docs/site-structure.md、portal-nav-rules.md 等連結
---
+7 -5
View File
@@ -67,7 +67,7 @@
5. **commit 前網站不會更新**。本地端強制重整用 `Ctrl+Shift+R`GitHub Pages 需 `git push` 後等約 1 分鐘。
6. **頂層 `<li>` 固定 5 個,沒有例外**(淪陷瞬間、完整的六顆、現場的震撼、黃色留聲機、Yellow Note)。「水晶練習室」籌備中佔位也收進「Yellow Note」子選單,不再獨立於頂層。新頁面/佔位一律收進其中一項的子選單,不要自己開新的頂層項目。詳見 `developer-rules/rules/portal-nav-rules.md` §8。
6. **頂層 `<li>` 固定 5 個,沒有例外**(淪陷瞬間、完整的六顆、現場的震撼、黃色留聲機、Yellow Note)。「小黃練習室」籌備中佔位也收進「Yellow Note」子選單,不再獨立於頂層。新頁面/佔位一律收進其中一項的子選單,不要自己開新的頂層項目。詳見 `developer-rules/rules/portal-nav-rules.md` §8。
---
@@ -75,7 +75,7 @@
<!-- 每次對話結束後更新這個區塊 -->
**最後更新:** 2026-08-18
**最後更新:** 2026-08-19
**進行中:**
- `calendar2026.html``<h1>` 標題「水晶萬年曆」還在想更好的名字(要求:不用「水晶」前綴、不重複站上已用意象詞、要有典故/查證過的出處),已否決多輪提案,暫緩
@@ -84,10 +84,12 @@
- developer-rules 健檢尚未執行
**已完成:**
- 新增「打歌舞台管理」後台模組(key `stages`,歌曲管理正下方):`admin/database/schema.sql` 新增 `stage_performances` 表(`song_id` 外鍵關聯 `songs`,欄位含播出日期/電視台/節目名稱/舞台標題/YouTube 連結/備註/排序/公開狀態四態);`admin/bootstrap.php``modules()` 加對應設定,沿用既有通用 CRUD`records.php``record-form.php``publishing.php`),沒新增獨立頁面。概念取自 `待確認/三個詞專案/php-admin-practice/`THREE WORDS·10TH 打歌舞台練習專案)的資料結構,但該資料夾本身維持原樣不動、資料庫也不共用,純粹借用欄位設計。**尚待做:**既有 `sechskies_cms` 資料庫要重新匯入一次 `schema.sql``CREATE TABLE IF NOT EXISTS` 不會動到既有表,只會補上新表)
- 「水晶練習室」全站更名為「小黃練習室」(英文副標 CRYSTAL PRACTICE ROOM → YEKKI PRACTICE ROOM,「小黃」英文簡稱定為 Yekki,「水晶男孩」簡稱 Jekki,站上不再使用 crystal 字樣指稱練習室):`yellow-note/practice-room.html`titleh1h2hero 文案/CSS 註解)、`assets/js/portal-nav.js`Yellow Note 子選單標籤與註解)、`extra/site-guide.html` 心智圖同步;CLAUDE.mdAGENTS.mdportal-nav-rules.md 內提到此頁名稱的歷史記錄一併同步(已拆到獨立專案 sechskies_fans 的舊「水晶熱舞社/水晶練習室/偶像練習生」歷史敘述維持原樣,不屬於本站現名範圍)
- `yellow-note/minister.html`(視覺進化論)Journey 時間軸重構:3 個大 `<article data-era="2016/2017/NOW">` 拆成每個月獨立一個 `story-node``data-era="2016.07"` 格式),套用 `.merged-storyline` 既有奇偶交錯排版,不再手寫「07 月|」字樣。真實照片只有 `2018.07`「415 天健身挑戰」(`fitness-calendar.png`,7/13 李宰鎮生日發起的每日健身計畫,年份待查證);其餘節點 `data-photo-pending="true"`、不渲染 `<figure>`,等後台控制方式定案後再補真照片
- `yellow-note/minister.html``calendar2026.html` 內文提到「水晶廢人字幕組」處都連到頻道(`youtube.com/channel/UCJnhlm_t9C7BmcILcjHDk_w`),minister.html 用 `.story-external-inline` 外部連結樣式
- `yellow-note/practice-room.html`水晶練習室)練舞清單接上第一支影片(SECHSKIES 回歸編舞練習),新增 `yellow-note/dance-practices-data.php` 靜態資料端點頂著(完整 MySQL 後台版在獨立專案 `sechskies_fans`,未部署)
- portal-nav 全開檢查用的 `TEMP_OPEN_ALL_FOR_REVIEW` 已還原為 `false``minister.html` 正式從 `COMING_SOON_PAGES` 移除(今天做完,永久開放),「水晶練習室」改為永久真連結(今天做完),「隊長的氣場」維持籌備中(今天沒動它,回到原狀)
- `yellow-note/practice-room.html`小黃練習室)練舞清單接上第一支影片(SECHSKIES 回歸編舞練習),新增 `yellow-note/dance-practices-data.php` 靜態資料端點頂著(完整 MySQL 後台版在獨立專案 `sechskies_fans`,未部署)
- portal-nav 全開檢查用的 `TEMP_OPEN_ALL_FOR_REVIEW` 已還原為 `false``minister.html` 正式從 `COMING_SOON_PAGES` 移除(今天做完,永久開放),「小黃練習室」改為永久真連結(今天做完),「隊長的氣場」維持籌備中(今天沒動它,回到原狀)
- 建立 CLAUDE.md 跨裝置上下文檔案
- 新增 `vedio/bangxiao.html`(世紀級寶藏 / 爆笑養老院,甜蜜負擔計量器)
- `vedio/variety-shows.html` 重構:移除多層包裝,對齊 albums.html 扁平結構
@@ -95,7 +97,7 @@
- `extra/site-guide.html` 同步更新:全員發瘋 → 世紀級寶藏
- `variety/` 資料夾整個改名為 `vedio/`,同步修正 portal-nav.js、site-guide.html、style.css 註解、docs/site-structure.md、portal-nav-rules.md 等連結
- `calendar2026.html` 新增「粉絲應援 / 字幕作品」(`fanwork`) 分類,收錄「水晶廢人字幕組」頻道全部 8 支影片+ MTV 我愛偶像報導影片(4/4,重啟活動20週年),依上架日期分布;`assets/css/calendar.css` 新增對應淺金配色(比生日金淺、hover 提亮)
- 修正 portal-nav.js 兩次頂層項目迴歸:「世紀級寶藏」移回「淪陷瞬間」子選單、「水晶練習室」移入「Yellow Note」子選單;`portal-nav-rules.md` 新增 §8 頂層 5 主項上限規則(無例外),`extra/site-guide.html` 心智圖同步
- 修正 portal-nav.js 兩次頂層項目迴歸:「世紀級寶藏」移回「淪陷瞬間」子選單、「小黃練習室」移入「Yellow Note」子選單;`portal-nav-rules.md` 新增 §8 頂層 5 主項上限規則(無例外),`extra/site-guide.html` 心智圖同步
---
+2 -2
View File
@@ -10,7 +10,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim((string) ($_POST['username'] ?? ''));
$name = trim((string) ($_POST['display_name'] ?? ''));
$password = (string) ($_POST['password'] ?? '');
if (!preg_match('/^[A-Za-z0-9_.-]{4,50}$/', $username) || mb_strlen($name) < 2 || strlen($password) < 10) {
if (!preg_match('/^[A-Za-z0-9_.-]{4,50}$/', $username) || mb_strlen($name) < 2 || strlen($password) < 6) {
$error = '請確認帳號、名稱與至少 10 字元的密碼。';
} else {
try {
@@ -30,6 +30,6 @@ $users = db()->query('SELECT id, username, display_name, email, is_active, last_
render_header('管理者帳號', 'admins');
?>
<?php if ($error): ?><div class="notice notice--error"><?= h($error) ?></div><?php endif; ?>
<section class="panel"><div class="panel__head"><div><h2>新增管理者</h2><p>密碼使用不可逆雜湊儲存</p></div></div><form class="inline-form" method="post"><input type="hidden" name="csrf" value="<?= h(csrf_token()) ?>"><input type="hidden" name="action" value="create"><label>登入帳號<input name="username" required></label><label>顯示名稱<input name="display_name" required></label><label>電子信箱<input name="email" type="email"></label><label>密碼<input name="password" type="password" minlength="10" required></label><button class="button button--primary" type="submit">新增帳號</button></form></section>
<section class="panel"><div class="panel__head"><div><h2>新增管理者</h2><p>密碼使用不可逆雜湊儲存</p></div></div><form class="inline-form" method="post"><input type="hidden" name="csrf" value="<?= h(csrf_token()) ?>"><input type="hidden" name="action" value="create"><label>登入帳號<input name="username" required></label><label>顯示名稱<input name="display_name" required></label><label>電子信箱<input name="email" type="email"></label><label>密碼<input name="password" type="password" minlength="6" required></label><button class="button button--primary" type="submit">新增帳號</button></form></section>
<section class="panel"><div class="panel__head"><div><h2>帳號清單</h2><p>停用帳號後將無法登入</p></div></div><div class="table-wrap"><table><thead><tr><th>帳號</th><th>顯示名稱</th><th>信箱</th><th>最後登入</th><th>狀態</th><th>操作</th></tr></thead><tbody><?php foreach ($users as $user): ?><tr><td><?= h($user['username']) ?></td><td><?= h($user['display_name']) ?></td><td><?= h($user['email']) ?></td><td><?= h($user['last_login_at'] ?? '尚未登入') ?></td><td><span class="status status--<?= $user['is_active'] ? 'published' : 'archived' ?>"><?= $user['is_active'] ? '啟用' : '停用' ?></span></td><td><form method="post" data-confirm="確定變更此管理者狀態?"><input type="hidden" name="csrf" value="<?= h(csrf_token()) ?>"><input type="hidden" name="action" value="toggle"><input type="hidden" name="id" value="<?= (int) $user['id'] ?>"><button class="table-button" type="submit" <?= (int) $user['id'] === (int) $_SESSION['admin_id'] ? 'disabled' : '' ?>><?= $user['is_active'] ? '停用' : '啟用' ?></button></form></td></tr><?php endforeach; ?></tbody></table></div></section>
<?php render_footer();
+15
View File
@@ -99,6 +99,21 @@ function modules(): array
],
'list' => ['title', 'album_id', 'track_no', 'is_title_track', 'status', 'updated_at'],
],
'stages' => [
'label' => '打歌舞台管理', 'icon' => 'mic', 'table' => 'stage_performances', 'order' => 'stage_date DESC, sort_order, id',
'fields' => [
'song_id' => ['label' => '所屬歌曲', 'type' => 'relation', 'table' => 'songs', 'required' => true],
'stage_date' => ['label' => '播出日期', 'type' => 'date', 'required' => true],
'station' => ['label' => '電視台', 'type' => 'text', 'required' => true],
'program' => ['label' => '節目名稱', 'type' => 'text', 'required' => true],
'title' => ['label' => '舞台標題', 'type' => 'text', 'required' => true],
'youtube_url' => ['label' => 'YouTube 連結', 'type' => 'url'],
'note' => ['label' => '備註', 'type' => 'textarea'],
'sort_order' => ['label' => '排序', 'type' => 'number', 'default' => '0'],
'status' => ['label' => '公開狀態', 'type' => 'status', 'required' => true],
],
'list' => ['title', 'song_id', 'stage_date', 'station', 'program', 'status', 'updated_at'],
],
'concerts' => [
'label' => '演唱會管理', 'icon' => 'ticket-perforated', 'table' => 'concert_events', 'order' => 'event_date DESC, id DESC',
'fields' => [
+16
View File
@@ -60,6 +60,22 @@ CREATE TABLE IF NOT EXISTS songs (
CONSTRAINT fk_songs_album FOREIGN KEY (album_id) REFERENCES albums(id) ON DELETE CASCADE
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS stage_performances (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
song_id INT UNSIGNED NOT NULL,
stage_date DATE NOT NULL,
station VARCHAR(80) NOT NULL,
program VARCHAR(120) NOT NULL,
title VARCHAR(160) NOT NULL,
youtube_url VARCHAR(500) NULL,
note TEXT NULL,
sort_order INT NOT NULL DEFAULT 0,
status ENUM('draft','coming_soon','published','archived') NOT NULL DEFAULT 'draft',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT fk_stage_song FOREIGN KEY (song_id) REFERENCES songs(id) ON DELETE CASCADE
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS concert_events (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
tour_name VARCHAR(180) NOT NULL,
+3 -3
View File
@@ -22,8 +22,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && $error === '') {
$error = '帳號須為 450 個英數字或 ._-。';
} elseif (mb_strlen($displayName) < 2) {
$error = '請填寫管理者顯示名稱。';
} elseif (strlen($password) < 10) {
$error = '密碼至少需要 10 個字元。';
} elseif (strlen($password) < 6) {
$error = '密碼至少需要 6 個字元。';
} else {
$stmt = db()->prepare('INSERT INTO admin_users (username, password_hash, display_name, email) VALUES (?, ?, ?, ?)');
$stmt->execute([$username, password_hash($password, PASSWORD_DEFAULT), $displayName, $email ?: null]);
@@ -33,4 +33,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && $error === '') {
?>
<!doctype html><html lang="zh-Hant"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>初始化後臺</title><link rel="stylesheet" href="assets/admin.css"></head>
<body class="auth-page"><main class="auth-card"><a class="auth-brand" href="../index.html" aria-label="返回水晶男孩推廣部前台"><img src="../assets/images/logov.svg" alt="SECHSKIES 水晶男孩推廣部"><span>CONTENT MANAGEMENT SYSTEM</span></a><p class="eyebrow">FIRST-TIME SETUP</p><h1>建立第一位管理者</h1><p>水晶男孩推廣部內容管理系統</p><?php if ($error): ?><div class="notice notice--error"><?= h($error) ?></div><?php endif; ?>
<form method="post"><input type="hidden" name="csrf" value="<?= h(csrf_token()) ?>"><label>登入帳號<input name="username" required autocomplete="username"></label><label>顯示名稱<input name="display_name" required></label><label>電子信箱<input name="email" type="email"></label><label>登入密碼<input name="password" type="password" required minlength="10" autocomplete="new-password"></label><button class="button button--primary" type="submit">建立管理者</button></form></main></body></html>
<form method="post"><input type="hidden" name="csrf" value="<?= h(csrf_token()) ?>"><label>登入帳號<input name="username" required autocomplete="username"></label><label>顯示名稱<input name="display_name" required></label><label>電子信箱<input name="email" type="email"></label><label>登入密碼<input name="password" type="password" required minlength="6" autocomplete="new-password"></label><button class="button button--primary" type="submit">建立管理者</button></form></main></body></html>
+2 -2
View File
@@ -242,7 +242,7 @@
/** 全站導覽 HTML — `rp` 為站根相對前綴;僅修改此模板即可同步所有頁面
* 五主項固定:淪陷瞬間、完整的六顆、現場的震撼、黃色留聲機、Yellow Note,不得再開第 6 個頂層項目。
* 世紀級寶藏收在「淪陷瞬間」子選單內;水晶練習室收在「Yellow Note」子選單內(見 site-guide.html 心智圖)。 */
* 世紀級寶藏收在「淪陷瞬間」子選單內;小黃練習室收在「Yellow Note」子選單內(見 site-guide.html 心智圖)。 */
function buildPortalNavInnerHTML(rp) {
return `
<a class="logo" target="_blank" rel="noopener noreferrer" href="${rp}index.html"><img src="${rp}assets/images/logov.svg" alt="SECHSKIES Logo"></a>
@@ -285,7 +285,7 @@
<ul class="portal-submenu">
<li><a target="_blank" rel="noopener noreferrer" href="${rp}yellow-note/minister.html"><span class="portal-nav__label">視覺進化論</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="${rp}yellow-note/map.html"><span class="portal-nav__label">聖地巡禮</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="${rp}yellow-note/practice-room.html"><span class="portal-nav__label">水晶練習室</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="${rp}yellow-note/practice-room.html"><span class="portal-nav__label">小黃練習室</span></a></li>
</ul>
</li>
</ul>
+1 -1
View File
@@ -133,7 +133,7 @@ alwaysApply: true
- **除非站主明講要新增第 6 個正式主項**,否則任何新頁面/新功能一律收進上述 5 項之一的子選單(`portal-submenu` / `portal-nav__subgroup`),**禁止**在頂層再開新的 `<li>`。
- 對照表見 `extra/site-guide.html` 的 `data-site-guide-depth="1"` 節點;動 `buildPortalNavInnerHTML` 前務必先數一次頂層 `<li>` 數量,超過就是做錯。
- 血淚教訓:「世紀級寶藏」(`vedio/bangxiao.html`)本該收在「淪陷瞬間」子選單裡,曾被誤植成獨立頂層項目,導致主項變 7 個;「水晶練習室」(外站 `sechskies_fans``data-coming-soon`)也曾一度單獨佔用頂層,後改收進「Yellow Note」子選單。往後新增類似頁面請比照辦理,先找歸屬的主項子選單,不要預設「獨立一項」。
- 血淚教訓:「世紀級寶藏」(`vedio/bangxiao.html`)本該收在「淪陷瞬間」子選單裡,曾被誤植成獨立頂層項目,導致主項變 7 個;「小黃練習室」(外站 `sechskies_fans``data-coming-soon`)也曾一度單獨佔用頂層,後改收進「Yellow Note」子選單。往後新增類似頁面請比照辦理,先找歸屬的主項子選單,不要預設「獨立一項」。
## 名詞
+1 -1
View File
@@ -142,7 +142,7 @@
</ul>
</li>
<li data-site-guide-depth="2">
<span class="sg-node"><a href="../yellow-note/practice-room.html">水晶練習室</a></span>
<span class="sg-node"><a href="../yellow-note/practice-room.html">小黃練習室</a></span>
</li>
</ul>
</li>
+7 -7
View File
@@ -4,12 +4,12 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>水晶男孩推廣部|水晶練習室</title>
<title>水晶男孩推廣部|小黃練習室</title>
<link rel="stylesheet" href="../assets/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<link rel="stylesheet" href="../assets/css/tablet.css">
<style>
/* ── 水晶練習室 scope token ── */
/* ── 小黃練習室 scope token ── */
body.practice-room-page {
--practice-accent: var(--color-brand);
--practice-accent-soft: var(--color-brand-light);
@@ -681,9 +681,9 @@
<body class="practice-room-page">
<header class="inner-page-header">
<div class="header-inner site-header-inner">
<h1 class="main-title">水晶練習室</h1>
<h1 class="main-title">小黃練習室</h1>
<div class="subtitle-wrap">
<span class="sub-title">CRYSTAL PRACTICE ROOM</span>
<span class="sub-title">YEKKI PRACTICE ROOM</span>
</div>
</div>
</header>
@@ -697,10 +697,10 @@
<!-- ① Hero -->
<section class="practice-room__hero" aria-labelledby="practice-hero-title">
<span class="practice-room__hero-badge">SECHSKIES PRACTICE DEMO</span>
<h2 class="practice-room__hero-title" id="practice-hero-title">水晶練習室</h2>
<p class="practice-room__hero-en">Crystal Practice Room</p>
<h2 class="practice-room__hero-title" id="practice-hero-title">小黃練習室</h2>
<p class="practice-room__hero-en">Yekki Practice Room</p>
<p class="practice-room__hero-lead">
水晶練習室延續我們當年以<span class="mark_b mark_y">水晶熱舞社、水晶歌詞社與水晶嘻哈社</span>等名稱交流的玩心,將歌曲、舞蹈、歌詞、Rap 與應援整理成可以反覆練習的粉絲向互動工具。第一版先以舞蹈影片練習與歌詞段落整理為主,未來可擴充唱歌、Rap、應援詞、錄音回放與練習紀錄。
小黃練習室延續我們當年以<span class="mark_b mark_y">水晶熱舞社、水晶歌詞社與水晶嘻哈社</span>等名稱交流的玩心,將歌曲、舞蹈、歌詞、Rap 與應援整理成可以反覆練習的粉絲向互動工具。第一版先以舞蹈影片練習與歌詞段落整理為主,未來可擴充唱歌、Rap、應援詞、錄音回放與練習紀錄。
</p>
<div class="practice-room__tag-row">
<span class="practice-room__tag"><i class="fa-solid fa-fire" aria-hidden="true"></i> 水晶熱舞社</span>