шаг 3 завершен

This commit is contained in:
Alisa
2026-06-04 00:27:17 +03:00
parent 420e67c9bd
commit 62ce8c4d01
27 changed files with 1565 additions and 42 deletions
+5
View File
@@ -0,0 +1,5 @@
<?php
declare(strict_types=1);
require_once dirname(__DIR__, 2) . '/admin/index.php';
+259
View File
@@ -10,6 +10,50 @@ body {
background: #f7f8f4;
}
.site-utility {
width: min(1080px, calc(100% - 48px));
display: flex;
gap: 14px;
align-items: center;
margin: 18px auto 0;
}
.back-button {
appearance: none;
border: 1px solid #cfd8c9;
border-radius: 8px;
padding: 10px 12px;
font: inherit;
font-size: 14px;
font-weight: 700;
color: #1d5d3b;
background: #ffffff;
cursor: pointer;
}
.back-button:hover {
border-color: #9fb194;
background: #f5f8f1;
}
.breadcrumbs {
display: flex;
flex-wrap: wrap;
gap: 7px;
align-items: center;
min-width: 0;
font-size: 14px;
color: #687466;
}
.breadcrumbs a {
color: #1d5d3b;
}
.breadcrumbs-separator {
color: #a3ad9d;
}
.page {
min-height: 100vh;
display: grid;
@@ -25,6 +69,10 @@ body {
background: #ffffff;
}
.start-screen.wide {
width: min(1080px, 100%);
}
.eyebrow {
margin: 0 0 8px;
font-size: 14px;
@@ -42,6 +90,25 @@ p {
line-height: 1.55;
}
h2 {
margin: 0 0 16px;
font-size: 22px;
}
h3 {
margin: 0 0 8px;
font-size: 17px;
}
a {
color: #1d5d3b;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.status-box {
display: flex;
gap: 8px;
@@ -78,3 +145,195 @@ p {
.primary-button:hover {
background: #16492e;
}
.content-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 18px;
margin-top: 24px;
}
.panel {
padding: 20px;
border: 1px solid #dfe5da;
border-radius: 8px;
background: #fbfcf8;
}
.products-panel {
margin-top: 18px;
}
.section-heading {
display: flex;
gap: 16px;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 18px;
}
.section-heading .eyebrow,
.section-heading h2 {
margin-bottom: 0;
}
.subtle-link {
flex: 0 0 auto;
font-size: 15px;
font-weight: 700;
}
.muted {
margin: 0;
font-size: 15px;
color: #687466;
}
.category-list {
display: grid;
gap: 10px;
margin: 0;
padding: 0;
list-style: none;
}
.category-list .category-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 8px 0 0;
padding: 0;
list-style: none;
}
.category-list li {
font-size: 16px;
font-weight: 700;
}
.category-list.depth-1 li {
font-size: 14px;
font-weight: 600;
}
.category-list.depth-2 {
padding-left: 10px;
}
.category-list.depth-2 li {
font-size: 13px;
font-weight: 400;
}
.settings-list {
display: grid;
gap: 12px;
margin: 0;
}
.settings-list div {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 12px;
align-items: baseline;
}
.settings-list dt {
color: #687466;
}
.settings-list dd {
margin: 0;
font-weight: 700;
}
.product-grid,
.admin-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 12px;
}
.product-card,
.admin-tile {
min-height: 96px;
padding: 16px;
border: 1px solid #dfe5da;
border-radius: 8px;
background: #ffffff;
}
.product-card p {
margin: 0 0 10px;
font-size: 14px;
color: #687466;
}
.product-card .product-category {
margin-bottom: 8px;
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
color: #7a856f;
}
.price-line {
display: block;
margin-bottom: 6px;
font-size: 14px;
color: #2d372f;
}
.price-tiers {
display: grid;
gap: 6px;
margin: 12px 0 0;
padding: 10px 0 0;
border-top: 1px solid #e3e8de;
list-style: none;
}
.price-tiers li {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 8px;
align-items: baseline;
font-size: 12px;
}
.price-tiers span {
color: #687466;
}
.price-tiers strong {
color: #1d5d3b;
}
.admin-tile {
display: grid;
place-items: center;
min-height: 72px;
font-weight: 700;
text-align: center;
}
@media (max-width: 760px) {
.site-utility {
width: calc(100% - 32px);
display: grid;
margin-top: 12px;
}
.content-grid {
grid-template-columns: 1fr;
}
.settings-list div {
grid-template-columns: 1fr;
gap: 2px;
}
.section-heading {
display: grid;
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
use App\Core\Database;
require_once dirname(__DIR__) . '/app/bootstrap.php';
header('Content-Type: text/plain; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
echo "RybStock diagnostic\n";
echo "version: 2026-06-04-02\n";
echo "file: " . __FILE__ . "\n";
echo "base_path: " . base_path() . "\n";
echo "db: " . app_env('DB_DATABASE', '') . "\n";
echo "home_text_expected: Каталог открывается уже на главной странице\n";
echo "schema_mtime: " . date('Y-m-d H:i:s', filemtime(base_path('database/schema.sql'))) . "\n";
echo "seed_mtime: " . date('Y-m-d H:i:s', filemtime(base_path('database/seed.sql'))) . "\n";
try {
$pdo = Database::pdo();
echo "db_status: connected\n";
$tables = $pdo->query('SHOW TABLES')->fetchAll(PDO::FETCH_COLUMN);
echo "tables_count: " . count($tables) . "\n";
if (in_array('categories', $tables, true)) {
echo "categories_count: " . $pdo->query('SELECT COUNT(*) FROM categories')->fetchColumn() . "\n";
echo "root_categories:\n";
$statement = $pdo->query('SELECT id, name, slug FROM categories WHERE parent_id IS NULL ORDER BY sort_order LIMIT 30');
foreach ($statement->fetchAll() as $category) {
echo "- {$category['name']} ({$category['slug']})\n";
}
} else {
echo "categories_table: missing\n";
}
} catch (Throwable $exception) {
echo "db_status: error\n";
echo "error: " . $exception->getMessage() . "\n";
}
+2 -16
View File
@@ -2,22 +2,8 @@
declare(strict_types=1);
use App\Core\Database;
use App\Controllers\HomeController;
require_once dirname(__DIR__) . '/app/bootstrap.php';
$dbStatus = 'not_checked';
try {
Database::pdo()->query('SELECT 1');
$dbStatus = 'connected';
} catch (Throwable $exception) {
$dbStatus = app_env('APP_DEBUG', 'false') === 'true'
? 'error: ' . $exception->getMessage()
: 'error';
}
view('pages/home', [
'title' => 'Рыбсток',
'dbStatus' => $dbStatus,
]);
(new HomeController())->index();
+62
View File
@@ -12,6 +12,7 @@ $actualToken = $_GET['token'] ?? '';
$canRun = $isLocal && $expectedToken !== '' && hash_equals($expectedToken, (string) $actualToken);
$result = null;
$error = null;
$stats = install_stats();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!$canRun) {
@@ -22,6 +23,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$pdo = Database::pdo();
run_sql_file($pdo, base_path('database/schema.sql'));
run_sql_file($pdo, base_path('database/seed.sql'));
$stats = install_stats();
$result = 'База данных установлена. Таблицы и стартовые данные созданы.';
} catch (Throwable $exception) {
http_response_code(500);
@@ -32,6 +34,33 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
}
}
function install_stats(): array
{
try {
$pdo = Database::pdo();
$tables = $pdo->query('SHOW TABLES')->fetchAll(PDO::FETCH_COLUMN);
$categoryCount = in_array('categories', $tables, true)
? (int) $pdo->query('SELECT COUNT(*) FROM categories')->fetchColumn()
: 0;
$firstCategories = in_array('categories', $tables, true)
? $pdo->query('SELECT name FROM categories WHERE parent_id IS NULL ORDER BY sort_order LIMIT 12')->fetchAll(PDO::FETCH_COLUMN)
: [];
return [
'ok' => true,
'database' => app_env('DB_DATABASE', ''),
'tables_count' => count($tables),
'category_count' => $categoryCount,
'first_categories' => $firstCategories,
];
} catch (Throwable $exception) {
return [
'ok' => false,
'error' => $exception->getMessage(),
];
}
}
function run_sql_file(PDO $pdo, string $path): void
{
if (!is_file($path)) {
@@ -62,6 +91,39 @@ function run_sql_file(PDO $pdo, string $path): void
<h1>Установка базы</h1>
<p>Эта страница применяет `database/schema.sql` и `database/seed.sql`. Таблицы будут пересозданы.</p>
<div class="status-box">
<span>Версия install.php:</span>
<strong>2026-06-04-02</strong>
</div>
<div class="status-box">
<span>Файл:</span>
<strong><?= htmlspecialchars(__FILE__, ENT_QUOTES, 'UTF-8') ?></strong>
</div>
<?php if ($stats['ok'] ?? false): ?>
<div class="status-box">
<span>База:</span>
<strong><?= htmlspecialchars((string) $stats['database'], ENT_QUOTES, 'UTF-8') ?></strong>
</div>
<div class="status-box">
<span>Таблиц:</span>
<strong><?= htmlspecialchars((string) $stats['tables_count'], ENT_QUOTES, 'UTF-8') ?></strong>
</div>
<div class="status-box">
<span>Категорий:</span>
<strong><?= htmlspecialchars((string) $stats['category_count'], ENT_QUOTES, 'UTF-8') ?></strong>
</div>
<?php if (!empty($stats['first_categories'])): ?>
<div class="status-box">
<span>Верхние категории:</span>
<strong><?= htmlspecialchars(implode(', ', $stats['first_categories']), ENT_QUOTES, 'UTF-8') ?></strong>
</div>
<?php endif; ?>
<?php else: ?>
<div class="status-box danger"><?= htmlspecialchars((string) ($stats['error'] ?? 'Нет статистики'), ENT_QUOTES, 'UTF-8') ?></div>
<?php endif; ?>
<?php if (!$isLocal): ?>
<div class="status-box danger">Установка доступна только при APP_ENV=local.</div>
<?php elseif (!$canRun): ?>