feat: 串接練舞清單
This commit is contained in:
@@ -165,6 +165,22 @@ function modules(): array
|
||||
],
|
||||
'list' => ['display_name', 'media_type', 'category', 'file_path', 'status', 'updated_at'],
|
||||
],
|
||||
'dance_practices' => [
|
||||
'label' => '練舞清單', 'item_label' => '練舞項目', 'list_title' => '練舞清單', 'icon' => 'list-check', 'table' => 'dance_practice_items', 'order' => 'sort_order, id', 'group' => 'dance',
|
||||
'fields' => [
|
||||
'title' => ['label' => '歌曲名稱', 'type' => 'text', 'required' => true],
|
||||
'tags' => ['label' => '練習分類', 'type' => 'text'],
|
||||
'practice_focus' => ['label' => '練習重點', 'type' => 'textarea', 'required' => true],
|
||||
'video_url' => ['label' => '參考影片網址', 'type' => 'url'],
|
||||
'difficulty' => ['label' => '難度', 'type' => 'select', 'default' => 'medium', 'required' => true, 'options' => ['easy' => '入門', 'medium' => '中等', 'hard' => '挑戰']],
|
||||
'progress_status' => ['label' => '練習進度', 'type' => 'select', 'default' => 'not_started', 'required' => true, 'options' => ['not_started' => '未開始', 'practicing' => '練習中', 'review' => '待複習', 'completed' => '已完成']],
|
||||
'note_text' => ['label' => '補充說明', 'type' => 'text'],
|
||||
'is_featured' => ['label' => '優先練習', 'type' => 'checkbox'],
|
||||
'sort_order' => ['label' => '排序', 'type' => 'number', 'default' => '0'],
|
||||
'status' => ['label' => '公開狀態', 'type' => 'status', 'required' => true],
|
||||
],
|
||||
'list' => ['title', 'difficulty', 'progress_status', 'is_featured', 'sort_order', 'status', 'updated_at'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -263,9 +279,14 @@ function render_header(string $title, string $active = ''): void
|
||||
<a class="<?= $active === 'dashboard' ? 'active' : '' ?>" href="index.php"><i class="bi bi-speedometer2"></i>控制台</a>
|
||||
<p>內容資料</p>
|
||||
<?php foreach ($mods as $key => $mod): ?>
|
||||
<?php if (($mod['group'] ?? 'content') === 'dance') continue; ?>
|
||||
<a class="<?= $active === $key ? 'active' : '' ?>" href="records.php?module=<?= h($key) ?>"><i class="bi bi-<?= h($mod['icon']) ?>"></i><?= h($mod['label']) ?></a>
|
||||
<?php endforeach; ?>
|
||||
<p>水晶熱舞社</p>
|
||||
<?php foreach ($mods as $key => $mod): ?>
|
||||
<?php if (($mod['group'] ?? 'content') !== 'dance') continue; ?>
|
||||
<a class="<?= $active === $key ? 'active' : '' ?>" href="records.php?module=<?= h($key) ?>"><i class="bi bi-<?= h($mod['icon']) ?>"></i><?= h($mod['label']) ?></a>
|
||||
<?php endforeach; ?>
|
||||
<a class="<?= $active === 'dance-applications' ? 'active' : '' ?>" href="dance-applications.php"><i class="bi bi-person-hearts"></i>30TH 應援報名</a>
|
||||
<p>系統</p>
|
||||
<a class="<?= $active === 'publishing' ? 'active' : '' ?>" href="publishing.php"><i class="bi bi-eye"></i>公開狀態</a>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
CREATE DATABASE IF NOT EXISTS sechskies_cms CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
USE sechskies_cms;
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_users (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
@@ -138,6 +139,39 @@ CREATE TABLE IF NOT EXISTS dance_applications (
|
||||
INDEX idx_dance_applications_email (email)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS dance_practice_items (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
title VARCHAR(160) NOT NULL,
|
||||
tags VARCHAR(255) NULL,
|
||||
practice_focus TEXT NOT NULL,
|
||||
video_url VARCHAR(500) NULL,
|
||||
difficulty ENUM('easy','medium','hard') NOT NULL DEFAULT 'medium',
|
||||
progress_status ENUM('not_started','practicing','review','completed') NOT NULL DEFAULT 'not_started',
|
||||
note_text VARCHAR(255) NULL,
|
||||
is_featured TINYINT(1) NOT NULL DEFAULT 0,
|
||||
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,
|
||||
INDEX idx_dance_practice_order (status, sort_order, id),
|
||||
INDEX idx_dance_practice_title (title)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO dance_practice_items
|
||||
(title, tags, practice_focus, difficulty, progress_status, note_text, is_featured, sort_order, status)
|
||||
SELECT 'Couple', 'Dance,Vocal', '副歌動作、隊形感、甜感表情', 'easy', 'not_started', '可作為第一首示範歌', 1, 10, 'published'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM dance_practice_items WHERE title = 'Couple');
|
||||
|
||||
INSERT INTO dance_practice_items
|
||||
(title, tags, practice_focus, difficulty, progress_status, note_text, is_featured, sort_order, status)
|
||||
SELECT 'Com'' Back', 'Dance,Rap', '強拍、Rap 段落、舞台氣勢', 'medium', 'not_started', '未來擴充', 0, 20, 'coming_soon'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM dance_practice_items WHERE title = 'Com'' Back');
|
||||
|
||||
INSERT INTO dance_practice_items
|
||||
(title, tags, practice_focus, difficulty, progress_status, note_text, is_featured, sort_order, status)
|
||||
SELECT 'Road Fighter', 'Dance,Rap,Performance', '節奏、力量、舞台感', 'hard', 'not_started', '未來擴充', 0, 30, 'coming_soon'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM dance_practice_items WHERE title = 'Road Fighter');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS audit_logs (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
admin_user_id INT UNSIGNED NULL,
|
||||
|
||||
@@ -66,7 +66,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
$record = array_merge($record, $data);
|
||||
}
|
||||
render_header(($id ? '編輯' : '新增') . $module['label'], $key);
|
||||
render_header(($id ? '編輯' : '新增') . ($module['item_label'] ?? $module['label']), $key);
|
||||
?>
|
||||
<?php if ($error): ?><div class="notice notice--error"><?= h($error) ?></div><?php endif; ?>
|
||||
<form class="panel editor" method="post" enctype="multipart/form-data"><input type="hidden" name="csrf" value="<?= h(csrf_token()) ?>"><input type="hidden" name="module" value="<?= h($key) ?>"><input type="hidden" name="id" value="<?= $id ?>"><div class="form-grid">
|
||||
|
||||
+2
-2
@@ -47,8 +47,8 @@ foreach ($module['fields'] as $name => $field) {
|
||||
render_header($module['label'], $key);
|
||||
?>
|
||||
<div class="toolbar"><form class="filters" method="get"><input type="hidden" name="module" value="<?= h($key) ?>"><label class="search"><i class="bi bi-search"></i><input name="q" value="<?= h($query) ?>" placeholder="搜尋本區資料"></label><?php if (isset($module['fields']['status'])): ?><select name="status"><option value="">全部狀態</option><?php foreach (['draft' => '草稿', 'coming_soon' => '籌備中', 'published' => '公開', 'archived' => '封存', 'available' => '可使用'] as $value => $label): ?><option value="<?= $value ?>" <?= $status === $value ? 'selected' : '' ?>><?= $label ?></option><?php endforeach; ?></select><?php endif; ?><button class="button" type="submit">篩選</button></form><a class="button button--primary" href="record-form.php?module=<?= h($key) ?>"><i class="bi bi-plus-lg"></i>新增資料</a></div>
|
||||
<section class="panel"><div class="panel__head"><div><h2><?= h($module['label']) ?>清單</h2><p>共 <?= $total ?> 筆;每頁 <?= $perPage ?> 筆</p></div></div><div class="table-wrap"><table><thead><tr><th>編號</th><?php foreach ($module['list'] as $field): ?><th><?= h($module['fields'][$field]['label'] ?? $field) ?></th><?php endforeach; ?><th>操作</th></tr></thead><tbody>
|
||||
<?php foreach ($rows as $row): ?><tr><td>#<?= (int) $row['id'] ?></td><?php foreach ($module['list'] as $field): ?><td><?php $value = $row[$field] ?? ''; if ($field === 'status'): ?><span class="status status--<?= h($value) ?>"><?= h(status_label($value)) ?></span><?php elseif (isset($relations[$field])): ?><?= h($relations[$field][$value] ?? ('#' . $value)) ?><?php elseif (($module['fields'][$field]['type'] ?? '') === 'checkbox'): ?><?= $value ? '是' : '否' ?><?php else: ?><?= h(mb_strimwidth((string) $value, 0, 42, '…', 'UTF-8')) ?><?php endif; ?></td><?php endforeach; ?><td class="actions"><a href="record-form.php?module=<?= h($key) ?>&id=<?= (int) $row['id'] ?>">編輯</a><form method="post" action="record-delete.php" data-confirm="確定刪除這筆資料?此動作無法復原。"><input type="hidden" name="csrf" value="<?= h(csrf_token()) ?>"><input type="hidden" name="module" value="<?= h($key) ?>"><input type="hidden" name="id" value="<?= (int) $row['id'] ?>"><button type="submit">刪除</button></form></td></tr><?php endforeach; ?>
|
||||
<section class="panel"><div class="panel__head"><div><h2><?= h($module['list_title'] ?? ($module['label'] . '清單')) ?></h2><p>共 <?= $total ?> 筆;每頁 <?= $perPage ?> 筆</p></div></div><div class="table-wrap"><table><thead><tr><th>編號</th><?php foreach ($module['list'] as $field): ?><th><?= h($module['fields'][$field]['label'] ?? $field) ?></th><?php endforeach; ?><th>操作</th></tr></thead><tbody>
|
||||
<?php foreach ($rows as $row): ?><tr><td>#<?= (int) $row['id'] ?></td><?php foreach ($module['list'] as $field): ?><td><?php $value = $row[$field] ?? ''; if ($field === 'status'): ?><span class="status status--<?= h($value) ?>"><?= h(status_label($value)) ?></span><?php elseif (isset($relations[$field])): ?><?= h($relations[$field][$value] ?? ('#' . $value)) ?><?php elseif (($module['fields'][$field]['type'] ?? '') === 'checkbox'): ?><?= $value ? '是' : '否' ?><?php elseif (($module['fields'][$field]['type'] ?? '') === 'select'): ?><?= h($module['fields'][$field]['options'][$value] ?? (string) $value) ?><?php else: ?><?= h(mb_strimwidth((string) $value, 0, 42, '…', 'UTF-8')) ?><?php endif; ?></td><?php endforeach; ?><td class="actions"><a href="record-form.php?module=<?= h($key) ?>&id=<?= (int) $row['id'] ?>">編輯</a><form method="post" action="record-delete.php" data-confirm="確定刪除這筆資料?此動作無法復原。"><input type="hidden" name="csrf" value="<?= h(csrf_token()) ?>"><input type="hidden" name="module" value="<?= h($key) ?>"><input type="hidden" name="id" value="<?= (int) $row['id'] ?>"><button type="submit">刪除</button></form></td></tr><?php endforeach; ?>
|
||||
<?php if (!$rows): ?><tr><td colspan="<?= count($module['list']) + 2 ?>" class="empty">找不到符合條件的資料。</td></tr><?php endif; ?></tbody></table></div>
|
||||
<?php if ($pages > 1): ?><nav class="pagination" aria-label="資料分頁"><?php for ($i = 1; $i <= $pages; $i++): ?><a class="<?= $i === $page ? 'active' : '' ?>" href="?module=<?= h($key) ?>&q=<?= urlencode($query) ?>&status=<?= urlencode($status) ?>&page=<?= $i ?>"><?= $i ?></a><?php endfor; ?></nav><?php endif; ?></section>
|
||||
<?php render_footer();
|
||||
|
||||
Reference in New Issue
Block a user