Объявления: окно у игрока и редактор в админке
Окно — вариант E из макетов: заголовок в плашке-шапке, текст, точки очереди и «Понятно», крестика нет. Очередь идёт от старого к новому; закрытое сразу уходит из кэша, следующее открывается без ожидания сети. У повторно показанного объявления под заголовком — красная пометка «обновлено». AppShell показывает окно на любой странице и только когда пароль задан: обязательное окно пароля всегда первое. Новые и изменённые объявления приходят SSE-событием announcements, отложенное начало показа — перезапросом раз в 5 минут. Админка — вкладка «Объявления» с редактором R1: contenteditable и панель (жирный, курсив, золотой и красный акцент, эмодзи, снятие оформления), вставка и перетаскивание только простым текстом, счётчик символов, период показа по МСК, переключатели «показывать новым игрокам» и «показать заново». Предпросмотр — тем же окном, что у игрока. Список со статусом, счётчиком «закрыли N из M» и действиями: изменить, снять с показа, дублировать, удалить. Выделение текста в форме — полупрозрачный оранжевый вместо синего. schema.d.ts пересобран из OpenAPI. #84 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Vendored
+395
@@ -842,6 +842,40 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/announcements/pending": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** Pending */
|
||||
get: operations["pending_api_announcements_pending_get"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/announcements/{announcement_id}/ack": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/** Acknowledge */
|
||||
post: operations["acknowledge_api_announcements__announcement_id__ack_post"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/admin/auth/login": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -1140,6 +1174,62 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/admin/announcements": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** List Announcements */
|
||||
get: operations["list_announcements_api_admin_announcements_get"];
|
||||
put?: never;
|
||||
/** Create Announcement */
|
||||
post: operations["create_announcement_api_admin_announcements_post"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/admin/announcements/{announcement_id}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
/** Update Announcement */
|
||||
put: operations["update_announcement_api_admin_announcements__announcement_id__put"];
|
||||
post?: never;
|
||||
/** Delete Announcement */
|
||||
delete: operations["delete_announcement_api_admin_announcements__announcement_id__delete"];
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/admin/announcements/{announcement_id}/stop": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/**
|
||||
* Stop Announcement
|
||||
* @description «Снять с показа»: период идущего объявления заканчивается сейчас.
|
||||
*/
|
||||
post: operations["stop_announcement_api_admin_announcements__announcement_id__stop_post"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/admin/audit-logs": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -1277,6 +1367,36 @@ export interface components {
|
||||
/** Group Id */
|
||||
group_id?: number | null;
|
||||
};
|
||||
/** AdminAnnouncementRead */
|
||||
AdminAnnouncementRead: {
|
||||
/** Id */
|
||||
id: number;
|
||||
/** Title */
|
||||
title: string;
|
||||
/** Body Html */
|
||||
body_html: string;
|
||||
/** Starts At */
|
||||
starts_at: string;
|
||||
/** Ends At */
|
||||
ends_at: string;
|
||||
/** Show To New Players */
|
||||
show_to_new_players: boolean;
|
||||
/** Revision */
|
||||
revision: number;
|
||||
/**
|
||||
* Status
|
||||
* @enum {string}
|
||||
*/
|
||||
status: "planned" | "live" | "finished";
|
||||
/** Seen Count */
|
||||
seen_count: number;
|
||||
/** Audience Count */
|
||||
audience_count: number;
|
||||
/** Created At */
|
||||
created_at: string;
|
||||
/** Updated At */
|
||||
updated_at: string;
|
||||
};
|
||||
/** AdminGroupRead */
|
||||
AdminGroupRead: {
|
||||
/** Id */
|
||||
@@ -1361,6 +1481,76 @@ export interface components {
|
||||
/** Is Active */
|
||||
is_active?: boolean | null;
|
||||
};
|
||||
/** AnnouncementAck */
|
||||
AnnouncementAck: {
|
||||
/** Revision */
|
||||
revision: number;
|
||||
};
|
||||
/** AnnouncementRead */
|
||||
AnnouncementRead: {
|
||||
/** Id */
|
||||
id: number;
|
||||
/** Title */
|
||||
title: string;
|
||||
/** Body Html */
|
||||
body_html: string;
|
||||
/** Revision */
|
||||
revision: number;
|
||||
/**
|
||||
* Updated
|
||||
* @default false
|
||||
*/
|
||||
updated: boolean;
|
||||
};
|
||||
/** AnnouncementUpdate */
|
||||
AnnouncementUpdate: {
|
||||
/** Title */
|
||||
title: string;
|
||||
/** Body Html */
|
||||
body_html: string;
|
||||
/**
|
||||
* Starts At
|
||||
* Format: date-time
|
||||
*/
|
||||
starts_at: string;
|
||||
/**
|
||||
* Ends At
|
||||
* Format: date-time
|
||||
*/
|
||||
ends_at: string;
|
||||
/**
|
||||
* Show To New Players
|
||||
* @default true
|
||||
*/
|
||||
show_to_new_players: boolean;
|
||||
/**
|
||||
* Reshow
|
||||
* @default false
|
||||
*/
|
||||
reshow: boolean;
|
||||
};
|
||||
/** AnnouncementWrite */
|
||||
AnnouncementWrite: {
|
||||
/** Title */
|
||||
title: string;
|
||||
/** Body Html */
|
||||
body_html: string;
|
||||
/**
|
||||
* Starts At
|
||||
* Format: date-time
|
||||
*/
|
||||
starts_at: string;
|
||||
/**
|
||||
* Ends At
|
||||
* Format: date-time
|
||||
*/
|
||||
ends_at: string;
|
||||
/**
|
||||
* Show To New Players
|
||||
* @default true
|
||||
*/
|
||||
show_to_new_players: boolean;
|
||||
};
|
||||
/** AttachmentRead */
|
||||
AttachmentRead: {
|
||||
/** Id */
|
||||
@@ -3980,6 +4170,61 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
pending_api_announcements_pending_get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["AnnouncementRead"][];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
acknowledge_api_announcements__announcement_id__ack_post: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
announcement_id: number;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["AnnouncementAck"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["OkResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
admin_login_api_admin_auth_login_post: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -4676,6 +4921,156 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
list_announcements_api_admin_announcements_get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["AdminAnnouncementRead"][];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
create_announcement_api_admin_announcements_post: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["AnnouncementWrite"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["AdminAnnouncementRead"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
update_announcement_api_admin_announcements__announcement_id__put: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
announcement_id: number;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["AnnouncementUpdate"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["AdminAnnouncementRead"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
delete_announcement_api_admin_announcements__announcement_id__delete: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
announcement_id: number;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["OkResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
stop_announcement_api_admin_announcements__announcement_id__stop_post: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
announcement_id: number;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["AdminAnnouncementRead"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
audit_logs_api_admin_audit_logs_get: {
|
||||
parameters: {
|
||||
query?: {
|
||||
|
||||
Reference in New Issue
Block a user