Autosave: 20260416-001254

This commit is contained in:
Flatlogic Bot 2026-04-16 00:12:54 +00:00
parent 0965f47f80
commit 4bf27ecfd4
4 changed files with 1593 additions and 250 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 KiB

View File

@ -56,6 +56,7 @@ function sccharacters_bootstrap(): void
cl_sccharacter_notes TEXT DEFAULT NULL, cl_sccharacter_notes TEXT DEFAULT NULL,
cl_sccharacter_share_token VARCHAR(64) NOT NULL, cl_sccharacter_share_token VARCHAR(64) NOT NULL,
cl_sccharacter_share_enabled TINYINT(1) NOT NULL DEFAULT 0, cl_sccharacter_share_enabled TINYINT(1) NOT NULL DEFAULT 0,
cl_sccharacter_category_order TEXT DEFAULT NULL,
cl_sccharacter_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, cl_sccharacter_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
cl_sccharacter_updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, cl_sccharacter_updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (cl_sccharacter_id), PRIMARY KEY (cl_sccharacter_id),
@ -90,6 +91,13 @@ function sccharacters_bootstrap(): void
); );
} }
if (!sccharacters_column_exists($db, 'tbl_sccharacters', 'cl_sccharacter_category_order')) {
$db->exec(
'ALTER TABLE tbl_sccharacters
ADD COLUMN cl_sccharacter_category_order TEXT NULL AFTER cl_sccharacter_share_enabled'
);
}
if (!sccharacters_index_exists($db, 'tbl_sccharacters', 'idx_sccharacter_owner')) { if (!sccharacters_index_exists($db, 'tbl_sccharacters', 'idx_sccharacter_owner')) {
$db->exec( $db->exec(
'ALTER TABLE tbl_sccharacters 'ALTER TABLE tbl_sccharacters
@ -123,11 +131,13 @@ function sccharacters_bootstrap(): void
cl_sccharacteritem_scitemcustom_id INT(11) DEFAULT NULL, cl_sccharacteritem_scitemcustom_id INT(11) DEFAULT NULL,
cl_sccharacteritem_slot VARCHAR(120) NOT NULL DEFAULT '', cl_sccharacteritem_slot VARCHAR(120) NOT NULL DEFAULT '',
cl_sccharacteritem_note TEXT DEFAULT NULL, cl_sccharacteritem_note TEXT DEFAULT NULL,
cl_sccharacteritem_sort_order INT UNSIGNED NOT NULL DEFAULT 0,
cl_sccharacteritem_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, cl_sccharacteritem_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (cl_sccharacteritem_id), PRIMARY KEY (cl_sccharacteritem_id),
KEY idx_sccharacteritem_character (cl_sccharacteritem_character_id), KEY idx_sccharacteritem_character (cl_sccharacteritem_character_id),
KEY idx_sccharacteritem_scobjs (cl_sccharacteritem_scobjs_id), KEY idx_sccharacteritem_scobjs (cl_sccharacteritem_scobjs_id),
KEY idx_sccharacteritem_scitemcustom (cl_sccharacteritem_scitemcustom_id), KEY idx_sccharacteritem_scitemcustom (cl_sccharacteritem_scitemcustom_id),
KEY idx_sccharacteritem_character_sort (cl_sccharacteritem_character_id, cl_sccharacteritem_sort_order, cl_sccharacteritem_id),
CONSTRAINT fk_sccharacteritem_character FOREIGN KEY (cl_sccharacteritem_character_id) CONSTRAINT fk_sccharacteritem_character FOREIGN KEY (cl_sccharacteritem_character_id)
REFERENCES tbl_sccharacters (cl_sccharacter_id) REFERENCES tbl_sccharacters (cl_sccharacter_id)
ON DELETE CASCADE ON DELETE CASCADE
@ -157,6 +167,13 @@ function sccharacters_bootstrap(): void
); );
} }
if (!sccharacters_column_exists($db, 'tbl_sccharacteritems', 'cl_sccharacteritem_sort_order')) {
$db->exec(
'ALTER TABLE tbl_sccharacteritems
ADD COLUMN cl_sccharacteritem_sort_order INT UNSIGNED NOT NULL DEFAULT 0 AFTER cl_sccharacteritem_note'
);
}
if (!sccharacters_index_exists($db, 'tbl_sccharacteritems', 'idx_sccharacteritem_character')) { if (!sccharacters_index_exists($db, 'tbl_sccharacteritems', 'idx_sccharacteritem_character')) {
$db->exec( $db->exec(
'ALTER TABLE tbl_sccharacteritems 'ALTER TABLE tbl_sccharacteritems
@ -178,6 +195,13 @@ function sccharacters_bootstrap(): void
); );
} }
if (!sccharacters_index_exists($db, 'tbl_sccharacteritems', 'idx_sccharacteritem_character_sort')) {
$db->exec(
'ALTER TABLE tbl_sccharacteritems
ADD INDEX idx_sccharacteritem_character_sort (cl_sccharacteritem_character_id, cl_sccharacteritem_sort_order, cl_sccharacteritem_id)'
);
}
if (!sccharacters_foreign_key_exists($db, 'tbl_sccharacteritems', 'fk_sccharacteritem_character')) { if (!sccharacters_foreign_key_exists($db, 'tbl_sccharacteritems', 'fk_sccharacteritem_character')) {
$db->exec( $db->exec(
'ALTER TABLE tbl_sccharacteritems 'ALTER TABLE tbl_sccharacteritems
@ -247,6 +271,76 @@ function sccharacters_generate_share_token(PDO $db): string
return $token; return $token;
} }
function sccharacters_reindex_character_items(PDO $db, int $character_id): void
{
if ($character_id <= 0) {
return;
}
$stmt = $db->prepare(
'SELECT cl_sccharacteritem_id
FROM tbl_sccharacteritems
WHERE cl_sccharacteritem_character_id = :character_id
ORDER BY
CASE WHEN cl_sccharacteritem_sort_order <= 0 THEN 0 ELSE 1 END,
cl_sccharacteritem_sort_order ASC,
cl_sccharacteritem_id ASC'
);
$stmt->execute(['character_id' => $character_id]);
$item_ids = array_map('intval', $stmt->fetchAll(PDO::FETCH_COLUMN));
if ($item_ids === []) {
return;
}
$stmt_update = $db->prepare(
'UPDATE tbl_sccharacteritems
SET cl_sccharacteritem_sort_order = :sort_order
WHERE cl_sccharacteritem_character_id = :character_id
AND cl_sccharacteritem_id = :item_id'
);
$db->beginTransaction();
try {
$position = 1;
foreach ($item_ids as $item_id) {
$stmt_update->execute([
'sort_order' => $position,
'character_id' => $character_id,
'item_id' => $item_id,
]);
$position++;
}
$db->commit();
} catch (Throwable $exception) {
if ($db->inTransaction()) {
$db->rollBack();
}
throw $exception;
}
}
function sccharacters_next_item_sort_order(PDO $db, int $character_id): int
{
if ($character_id <= 0) {
return 1;
}
sccharacters_reindex_character_items($db, $character_id);
$stmt = $db->prepare(
'SELECT COALESCE(MAX(cl_sccharacteritem_sort_order), 0)
FROM tbl_sccharacteritems
WHERE cl_sccharacteritem_character_id = :character_id'
);
$stmt->execute(['character_id' => $character_id]);
return ((int) $stmt->fetchColumn()) + 1;
}
function sccharacters_item_category_options(): array function sccharacters_item_category_options(): array
{ {
@ -265,6 +359,106 @@ function sccharacters_item_category_options(): array
]; ];
} }
function sccharacters_default_category_order(): array
{
return array_keys(sccharacters_item_category_options());
}
function sccharacters_normalize_category_order(array $category_order): array
{
$known_categories = sccharacters_default_category_order();
$known_lookup = array_fill_keys($known_categories, true);
$normalized = [];
foreach ($category_order as $category_key) {
$category_key = trim((string) $category_key);
if ($category_key === '' || !isset($known_lookup[$category_key]) || isset($normalized[$category_key])) {
continue;
}
$normalized[$category_key] = $category_key;
}
foreach ($known_categories as $category_key) {
if (!isset($normalized[$category_key])) {
$normalized[$category_key] = $category_key;
}
}
return array_values($normalized);
}
function sccharacters_parse_category_order(?string $raw_value): array
{
$raw_value = trim((string) $raw_value);
if ($raw_value === '') {
return sccharacters_default_category_order();
}
$decoded = json_decode($raw_value, true);
if (!is_array($decoded)) {
return sccharacters_default_category_order();
}
return sccharacters_normalize_category_order($decoded);
}
function sccharacters_encode_category_order(array $category_order): string
{
$encoded = json_encode(
sccharacters_normalize_category_order($category_order),
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
return $encoded !== false
? $encoded
: json_encode(sccharacters_default_category_order(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
function sccharacters_character_category_order(array $character_row): array
{
return sccharacters_parse_category_order((string) ($character_row['cl_sccharacter_category_order'] ?? ''));
}
function sccharacters_sort_items_by_category_order(array $items_by_category, array $category_order): array
{
if ($items_by_category === []) {
return [];
}
$sorted = [];
foreach (sccharacters_normalize_category_order($category_order) as $category_key) {
if (isset($items_by_category[$category_key])) {
$sorted[$category_key] = $items_by_category[$category_key];
}
}
foreach ($items_by_category as $category_key => $category_items) {
if (!isset($sorted[$category_key])) {
$sorted[$category_key] = $category_items;
}
}
return $sorted;
}
function sccharacters_save_character_category_order(PDO $db, int $character_id, array $category_order): void
{
if ($character_id <= 0) {
return;
}
$stmt = $db->prepare(
'UPDATE tbl_sccharacters
SET cl_sccharacter_category_order = :category_order
WHERE cl_sccharacter_id = :character_id'
);
$stmt->execute([
'category_order' => sccharacters_encode_category_order($category_order),
'character_id' => $character_id,
]);
}
function sccharacters_item_category_label(string $category): string function sccharacters_item_category_label(string $category): string
{ {
$options = sccharacters_item_category_options(); $options = sccharacters_item_category_options();

View File

@ -31,6 +31,8 @@ if ($share_token !== '') {
} }
if ($character) { if ($character) {
sccharacters_reindex_character_items($db, (int) $character['cl_sccharacter_id']);
$stmt_items = $db->prepare( $stmt_items = $db->prepare(
"SELECT "SELECT
ci.*, ci.*,
@ -47,11 +49,7 @@ if ($character) {
LEFT JOIN tbl_scitemcustom co ON co.cl_scitemcustom_id = ci.cl_sccharacteritem_scitemcustom_id LEFT JOIN tbl_scitemcustom co ON co.cl_scitemcustom_id = ci.cl_sccharacteritem_scitemcustom_id
LEFT JOIN tbl_scobjs oo ON oo.cl_scobjs_id = co.cl_scitemcustom_obj_id LEFT JOIN tbl_scobjs oo ON oo.cl_scobjs_id = co.cl_scitemcustom_obj_id
WHERE ci.cl_sccharacteritem_character_id = :character_id WHERE ci.cl_sccharacteritem_character_id = :character_id
ORDER BY ORDER BY ci.cl_sccharacteritem_sort_order ASC, ci.cl_sccharacteritem_id ASC"
CASE WHEN TRIM(ci.cl_sccharacteritem_slot) = '' THEN 1 ELSE 0 END,
ci.cl_sccharacteritem_slot ASC,
COALESCE(oo.cl_scobjs_name, bo.cl_scobjs_name, 'ZZZ') ASC,
ci.cl_sccharacteritem_id ASC"
); );
$stmt_items->execute(['character_id' => (int) $character['cl_sccharacter_id']]); $stmt_items->execute(['character_id' => (int) $character['cl_sccharacter_id']]);
$character_items = $stmt_items->fetchAll(); $character_items = $stmt_items->fetchAll();
@ -93,10 +91,10 @@ if ($character) {
} }
$item_category_options = sccharacters_item_category_options(); $item_category_options = sccharacters_item_category_options();
$character_category_order = $character
? sccharacters_character_category_order($character)
: sccharacters_default_category_order();
$character_items_by_category = []; $character_items_by_category = [];
foreach (array_keys($item_category_options) as $category_key) {
$character_items_by_category[$category_key] = [];
}
foreach ($character_items as $item_row) { foreach ($character_items as $item_row) {
$is_custom = ($item_row['cl_sccharacteritem_source'] ?? '') === 'custom'; $is_custom = ($item_row['cl_sccharacteritem_source'] ?? '') === 'custom';
$type = $is_custom $type = $is_custom
@ -115,9 +113,9 @@ foreach ($character_items as $item_row) {
} }
$character_items_by_category[$category_key][] = $item_row; $character_items_by_category[$category_key][] = $item_row;
} }
$character_items_by_category = array_filter( $character_items_by_category = sccharacters_sort_items_by_category_order(
$character_items_by_category, $character_items_by_category,
static fn(array $items): bool => $items !== [] $character_category_order
); );
?> ?>
<!DOCTYPE html> <!DOCTYPE html>

File diff suppressed because it is too large Load Diff