Initialize Edevs Hub repository

This commit is contained in:
Andrey committed 2026-06-17 18:14:16 +03:00
commit aacdd422b3
127 files changed
+10531

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
.env
.git
.venv
__pycache__
*.pyc
node_modules
dist
coverage
playwright-report
test-results
design
docs
+15
View File
@@ -0,0 +1,15 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
[*.py]
indent_size = 4
[*.ps1]
end_of_line = crlf
+22
View File
@@ -0,0 +1,22 @@
COMPOSE_PROJECT_NAME=edevs_hub
HUB_ENV=local
HUB_DEBUG=true
HUB_SECRET_KEY=change-me-only-for-local-development
HUB_ALLOWED_HOSTS=localhost,127.0.0.1,hub.localhost,pay.localhost,chat.localhost
HUB_CSRF_TRUSTED_ORIGINS=http://localhost,http://localhost:8000,http://localhost:5173,http://localhost:5174,http://localhost:5175
POSTGRES_DB=edevs_hub
POSTGRES_USER=edevs_hub
POSTGRES_PASSWORD=edevs_hub
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
REDIS_URL=redis://redis:6379/0
INTERNAL_UI_PORT=5173
CHECKOUT_PORT=5174
WEB_CHAT_PORT=5175
BACKEND_PORT=8010
VITE_API_BASE_URL=http://localhost:8010/api/v1
+13
View File
@@ -0,0 +1,13 @@
.env
.venv/
__pycache__/
*.py[cod]
.pytest_cache/
.ruff_cache/
.mypy_cache/
node_modules/
dist/
coverage/
playwright-report/
test-results/
.DS_Store
+14
View File
@@ -0,0 +1,14 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.0
hooks:
- id: ruff
args: ["--fix"]
- id: ruff-format
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-yaml
- id: check-json
- id: end-of-file-fixer
- id: trailing-whitespace
+29
View File
@@ -0,0 +1,29 @@
# Edevs Hub
Canonical implementation workspace for `hub.edevs.tech`.
## Local start
```powershell
Copy-Item .env.example .env
.\scripts\start.ps1
```
The local compose stack contains:
- Django ASGI backend and background worker;
- PostgreSQL;
- Redis;
- Internal Hub UI;
- Checkout UI;
- Web Chat UI;
- local Nginx reverse proxy.
No production secrets are stored in the repository.
Default local URLs:
- Internal Hub UI: `http://localhost:5173`
- Checkout: `http://localhost:5174`
- Web Chat: `http://localhost:5175`
- Backend API: `http://localhost:8010/api/v1`
View File
Whitespace-only changes.
+15
View File
@@ -0,0 +1,15 @@
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /app
COPY apps/backend/requirements.txt /app/apps/backend/requirements.txt
RUN pip install --no-cache-dir -r /app/apps/backend/requirements.txt
COPY apps/backend /app/apps/backend
WORKDIR /app/apps/backend
EXPOSE 8000
+1
View File
@@ -0,0 +1 @@
+7
View File
@@ -0,0 +1,7 @@
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hub_backend.settings")
application = get_asgi_application()
+134
View File
@@ -0,0 +1,134 @@
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
def env_bool(name: str, default: bool = False) -> bool:
value = os.environ.get(name)
if value is None:
return default
return value.lower() in {"1", "true", "yes", "on"}
def env_list(name: str, default: list[str]) -> list[str]:
value = os.environ.get(name)
if value is None:
return default
return [item.strip() for item in value.split(",") if item.strip()]
SECRET_KEY = os.environ.get("HUB_SECRET_KEY", "local-development-only")
DEBUG = env_bool("HUB_DEBUG")
ALLOWED_HOSTS = env_list("HUB_ALLOWED_HOSTS", ["localhost", "127.0.0.1"])
CSRF_TRUSTED_ORIGINS = env_list("HUB_CSRF_TRUSTED_ORIGINS", [])
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"rest_framework",
"hub_platform.health",
"hub_platform.events",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"hub_platform.http.middleware.LocalCorsMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"hub_platform.events.middleware.CorrelationIdMiddleware",
]
ROOT_URLCONF = "hub_backend.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "hub_backend.wsgi.application"
ASGI_APPLICATION = "hub_backend.asgi.application"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ.get("POSTGRES_DB", "edevs_hub"),
"USER": os.environ.get("POSTGRES_USER", "edevs_hub"),
"PASSWORD": os.environ.get("POSTGRES_PASSWORD", "edevs_hub"),
"HOST": os.environ.get("POSTGRES_HOST", "postgres"),
"PORT": os.environ.get("POSTGRES_PORT", "5432"),
"CONN_MAX_AGE": 60,
}
}
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": os.environ.get("REDIS_URL", "redis://redis:6379/0"),
}
}
AUTH_PASSWORD_VALIDATORS = [
{"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"},
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
]
LANGUAGE_CODE = "ru-ru"
TIME_ZONE = "Europe/Moscow"
USE_I18N = True
USE_TZ = True
STATIC_URL = "static/"
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
REST_FRAMEWORK = {
"DEFAULT_RENDERER_CLASSES": ["rest_framework.renderers.JSONRenderer"],
"DEFAULT_PARSER_CLASSES": ["rest_framework.parsers.JSONParser"],
}
CORS_ALLOWED_ORIGINS = {
"http://localhost:5173",
"http://localhost:5174",
"http://localhost:5175",
}
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"structured": {
"format": "%(asctime)s %(levelname)s %(name)s %(message)s correlation_id=%(correlation_id)s"
}
},
"filters": {
"correlation_id": {"()": "hub_platform.events.logging.CorrelationIdLogFilter"}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "structured",
"filters": ["correlation_id"],
}
},
"root": {"handlers": ["console"], "level": "INFO"},
}
+9
View File
@@ -0,0 +1,9 @@
from django.contrib import admin
from django.urls import include, path
from rest_framework.schemas import get_schema_view
urlpatterns = [
path("admin/", admin.site.urls),
path("api/v1/schema/", get_schema_view(title="Edevs Hub API", version="0.1.0"), name="openapi-schema"),
path("api/v1/health/", include("hub_platform.health.urls")),
]
+7
View File
@@ -0,0 +1,7 @@
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hub_backend.settings")
application = get_wsgi_application()
+1
View File
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+7
View File
@@ -0,0 +1,7 @@
from django.apps import AppConfig
class EventsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "hub_platform.events"
verbose_name = "Domain events"
@@ -0,0 +1,14 @@
from contextvars import ContextVar
from uuid import uuid4
correlation_id_var: ContextVar[str] = ContextVar("correlation_id", default="")
def ensure_correlation_id(value: str | None = None) -> str:
correlation_id = value or str(uuid4())
correlation_id_var.set(correlation_id)
return correlation_id
def get_correlation_id() -> str:
return correlation_id_var.get() or ensure_correlation_id()
@@ -0,0 +1,9 @@
import logging
from hub_platform.events.context import get_correlation_id
class CorrelationIdLogFilter(logging.Filter):
def filter(self, record: logging.LogRecord) -> bool:
record.correlation_id = get_correlation_id()
return True
@@ -0,0 +1 @@
@@ -0,0 +1,18 @@
from django.core.management.base import BaseCommand
from hub_platform.events.services import DomainEvent, enqueue_event
class Command(BaseCommand):
help = "Enqueues a deterministic local test event for E01 checks."
def handle(self, *args: object, **options: object) -> None:
event = enqueue_event(
DomainEvent(
aggregate_type="local_check",
aggregate_id="e01",
event_type="local_check.requested",
payload={"source": "emit_test_event"},
)
)
self.stdout.write(str(event.id))
@@ -0,0 +1,31 @@
import logging
import time
from django.core.management.base import BaseCommand
from django.utils import timezone
from hub_platform.events.models import OutboxStatus
from hub_platform.events.services import claim_next_outbox_event, mark_retry
logger = logging.getLogger(__name__)
class Command(BaseCommand):
help = "Runs the local domain event worker."
def handle(self, *args: object, **options: object) -> None:
self.stdout.write("Hub worker started")
while True:
event = claim_next_outbox_event()
if event is None:
time.sleep(1)
continue
try:
logger.info("Processing outbox event %s", event.id)
event.status = OutboxStatus.PROCESSED
event.processed_at = timezone.now()
event.save(update_fields=["status", "processed_at"])
except Exception as exc: # pragma: no cover
logger.exception("Outbox event failed: %s", event.id)
mark_retry(event, str(exc))
@@ -0,0 +1,19 @@
from collections.abc import Callable
from django.http import HttpRequest, HttpResponse
from hub_platform.events.context import ensure_correlation_id
class CorrelationIdMiddleware:
header_name = "HTTP_X_CORRELATION_ID"
response_header = "X-Correlation-Id"
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]) -> None:
self.get_response = get_response
def __call__(self, request: HttpRequest) -> HttpResponse:
correlation_id = ensure_correlation_id(request.META.get(self.header_name))
response = self.get_response(request)
response[self.response_header] = correlation_id
return response
@@ -0,0 +1,71 @@
import uuid
from django.db import migrations, models
from django.utils import timezone
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="InboxEvent",
fields=[
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
("source", models.CharField(max_length=128)),
("external_event_id", models.CharField(max_length=256)),
("payload_hash", models.CharField(max_length=128)),
("received_at", models.DateTimeField(auto_now_add=True)),
("processed_at", models.DateTimeField(blank=True, null=True)),
],
),
migrations.CreateModel(
name="OutboxEvent",
fields=[
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
("aggregate_type", models.CharField(max_length=128)),
("aggregate_id", models.CharField(max_length=128)),
("event_type", models.CharField(max_length=128)),
("payload", models.JSONField(default=dict)),
(
"status",
models.CharField(
choices=[
("PENDING", "Pending"),
("PROCESSING", "Processing"),
("PROCESSED", "Processed"),
("FAILED", "Failed"),
("DEAD_LETTER", "Dead letter"),
],
db_index=True,
default="PENDING",
max_length=32,
),
),
("attempts", models.PositiveIntegerField(default=0)),
("next_attempt_at", models.DateTimeField(db_index=True, default=timezone.now)),
("correlation_id", models.CharField(blank=True, max_length=128)),
("last_error", models.TextField(blank=True)),
("created_at", models.DateTimeField(auto_now_add=True)),
("processed_at", models.DateTimeField(blank=True, null=True)),
],
options={"ordering": ["created_at"]},
),
migrations.AddConstraint(
model_name="inboxevent",
constraint=models.UniqueConstraint(
fields=("source", "external_event_id"),
name="uniq_inbox_source_external_event_id",
),
),
migrations.AddIndex(
model_name="outboxevent",
index=models.Index(fields=["status", "next_attempt_at"], name="events_outb_status_881ef5_idx"),
),
migrations.AddIndex(
model_name="outboxevent",
index=models.Index(fields=["aggregate_type", "aggregate_id"], name="events_outb_aggrega_a2b510_idx"),
),
]
@@ -0,0 +1 @@
@@ -0,0 +1,62 @@
import uuid
from django.db import models
from django.utils import timezone
class OutboxStatus(models.TextChoices):
PENDING = "PENDING", "Pending"
PROCESSING = "PROCESSING", "Processing"
PROCESSED = "PROCESSED", "Processed"
FAILED = "FAILED", "Failed"
DEAD_LETTER = "DEAD_LETTER", "Dead letter"
class OutboxEvent(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
aggregate_type = models.CharField(max_length=128)
aggregate_id = models.CharField(max_length=128)
event_type = models.CharField(max_length=128)
payload = models.JSONField(default=dict)
status = models.CharField(
max_length=32,
choices=OutboxStatus.choices,
default=OutboxStatus.PENDING,
db_index=True,
)
attempts = models.PositiveIntegerField(default=0)
next_attempt_at = models.DateTimeField(default=timezone.now, db_index=True)
correlation_id = models.CharField(max_length=128, blank=True)
last_error = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
processed_at = models.DateTimeField(null=True, blank=True)
class Meta:
ordering = ["created_at"]
indexes = [
models.Index(fields=["status", "next_attempt_at"]),
models.Index(fields=["aggregate_type", "aggregate_id"]),
]
def __str__(self) -> str:
return f"{self.event_type}:{self.id}"
class InboxEvent(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
source = models.CharField(max_length=128)
external_event_id = models.CharField(max_length=256)
payload_hash = models.CharField(max_length=128)
received_at = models.DateTimeField(auto_now_add=True)
processed_at = models.DateTimeField(null=True, blank=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=["source", "external_event_id"],
name="uniq_inbox_source_external_event_id",
)
]
def __str__(self) -> str:
return f"{self.source}:{self.external_event_id}"
@@ -0,0 +1,53 @@
from dataclasses import dataclass
from datetime import timedelta
from typing import Any
from django.db import transaction
from django.utils import timezone
from hub_platform.events.context import get_correlation_id
from hub_platform.events.models import OutboxEvent, OutboxStatus
@dataclass(frozen=True)
class DomainEvent:
aggregate_type: str
aggregate_id: str
event_type: str
payload: dict[str, Any]
def enqueue_event(event: DomainEvent) -> OutboxEvent:
return OutboxEvent.objects.create(
aggregate_type=event.aggregate_type,
aggregate_id=event.aggregate_id,
event_type=event.event_type,
payload=event.payload,
correlation_id=get_correlation_id(),
)
def mark_retry(event: OutboxEvent, error: str, max_attempts: int = 5) -> None:
event.attempts += 1
event.last_error = error
event.status = OutboxStatus.DEAD_LETTER if event.attempts >= max_attempts else OutboxStatus.FAILED
event.next_attempt_at = timezone.now() + timedelta(seconds=min(300, 2**event.attempts))
event.save(update_fields=["attempts", "last_error", "status", "next_attempt_at"])
def claim_next_outbox_event() -> OutboxEvent | None:
with transaction.atomic():
event = (
OutboxEvent.objects.select_for_update(skip_locked=True)
.filter(
status__in=[OutboxStatus.PENDING, OutboxStatus.FAILED],
next_attempt_at__lte=timezone.now(),
)
.order_by("next_attempt_at", "created_at")
.first()
)
if event is None:
return None
event.status = OutboxStatus.PROCESSING
event.save(update_fields=["status"])
return event
@@ -0,0 +1 @@
+7
View File
@@ -0,0 +1,7 @@
from django.apps import AppConfig
class HealthConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "hub_platform.health"
verbose_name = "Health"
@@ -0,0 +1,9 @@
from django.test import Client, TestCase
class HealthTests(TestCase):
def test_live_endpoint(self) -> None:
response = Client().get("/api/v1/health/live/")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()["status"], "ok")
+8
View File
@@ -0,0 +1,8 @@
from django.urls import path
from hub_platform.health.views import live, ready
urlpatterns = [
path("live/", live, name="health-live"),
path("ready/", ready, name="health-ready"),
]
+21
View File
@@ -0,0 +1,21 @@
from django.core.cache import cache
from django.db import connection
from django.http import JsonResponse
def live(request):
return JsonResponse({"status": "ok", "service": "hub-backend"})
def ready(request):
checks = {"database": False, "redis": False}
with connection.cursor() as cursor:
cursor.execute("SELECT 1")
checks["database"] = cursor.fetchone()[0] == 1
cache.set("healthcheck", "ok", timeout=5)
checks["redis"] = cache.get("healthcheck") == "ok"
status_code = 200 if all(checks.values()) else 503
return JsonResponse({"status": "ok" if status_code == 200 else "degraded", "checks": checks}, status=status_code)
@@ -0,0 +1 @@
@@ -0,0 +1,23 @@
from collections.abc import Callable
from django.conf import settings
from django.http import HttpRequest, HttpResponse
class LocalCorsMiddleware:
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]) -> None:
self.get_response = get_response
def __call__(self, request: HttpRequest) -> HttpResponse:
if request.method == "OPTIONS" and request.headers.get("Origin") in settings.CORS_ALLOWED_ORIGINS:
response = HttpResponse(status=204)
else:
response = self.get_response(request)
origin = request.headers.get("Origin")
if origin in settings.CORS_ALLOWED_ORIGINS:
response["Access-Control-Allow-Origin"] = origin
response["Access-Control-Allow-Credentials"] = "true"
response["Access-Control-Allow-Headers"] = "Content-Type, X-Correlation-Id, X-CSRFToken"
response["Access-Control-Allow-Methods"] = "GET, POST, PUT, PATCH, DELETE, OPTIONS"
response["Vary"] = "Origin"
return response
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env python
import os
import sys
def main() -> None:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hub_backend.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()
+9
View File
@@ -0,0 +1,9 @@
Django>=5.2,<5.3
djangorestframework>=3.16,<3.17
psycopg[binary]>=3.2,<3.3
redis>=5.2,<5.3
uvicorn[standard]>=0.34,<0.35
gunicorn>=23.0,<24.0
pytest>=8.4,<8.5
pytest-django>=4.11,<4.12
ruff>=0.12,<0.13
View File
Whitespace-only changes.
+16
View File
@@ -0,0 +1,16 @@
FROM node:22-alpine
WORKDIR /app
COPY package.json tsconfig.base.json ./
COPY apps/checkout/package.json ./apps/checkout/package.json
COPY packages/ui/package.json ./packages/ui/package.json
COPY packages/contracts/package.json ./packages/contracts/package.json
COPY packages/shared/package.json ./packages/shared/package.json
RUN npm install
COPY apps/checkout ./apps/checkout
COPY packages ./packages
WORKDIR /app/apps/checkout
EXPOSE 5174
+12
View File
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Оформление покупки | Edevs Hub</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+24
View File
@@ -0,0 +1,24 @@
{
"name": "@edevs/checkout",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -p tsconfig.json && vite build",
"typecheck": "tsc -p tsconfig.json",
"test": "vitest run --passWithNoTests"
},
"dependencies": {
"@edevs/contracts": "0.1.0",
"@edevs/shared": "0.1.0",
"@edevs/ui": "0.1.0",
"antd": "^5.26.0",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.0"
}
}
+16
View File
@@ -0,0 +1,16 @@
import { ConfigProvider, Result } from "antd";
import { edevsHubTheme } from "@edevs/ui";
export function App() {
return (
<ConfigProvider theme={edevsHubTheme}>
<main className="checkout-shell">
<Result
status="info"
title="Оформление покупки"
subTitle="Публичный checkout будет реализован после прохождения DG-05. Каркас приложения готов для E01."
/>
</main>
</ConfigProvider>
);
}
+11
View File
@@ -0,0 +1,11 @@
import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "./App";
import "./styles.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
+14
View File
@@ -0,0 +1,14 @@
html,
body,
#root {
min-height: 100%;
margin: 0;
}
.checkout-shell {
min-height: 100vh;
display: grid;
place-items: center;
padding: 24px;
background: #f6f8fb;
}
+4
View File
@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src", "vite.config.ts"]
}
+9
View File
@@ -0,0 +1,9 @@
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [react()],
server: {
port: 5174,
},
});
View File
Whitespace-only changes.
+16
View File
@@ -0,0 +1,16 @@
FROM node:22-alpine
WORKDIR /app
COPY package.json tsconfig.base.json ./
COPY apps/internal-ui/package.json ./apps/internal-ui/package.json
COPY packages/ui/package.json ./packages/ui/package.json
COPY packages/contracts/package.json ./packages/contracts/package.json
COPY packages/shared/package.json ./packages/shared/package.json
RUN npm install
COPY apps/internal-ui ./apps/internal-ui
COPY packages ./packages
WORKDIR /app/apps/internal-ui
EXPOSE 5173
+12
View File
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Edevs Hub</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+25
View File
@@ -0,0 +1,25 @@
{
"name": "@edevs/internal-ui",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -p tsconfig.json && vite build",
"typecheck": "tsc -p tsconfig.json",
"test": "vitest run --passWithNoTests"
},
"dependencies": {
"@ant-design/icons": "^6.0.0",
"@edevs/contracts": "0.1.0",
"@edevs/shared": "0.1.0",
"@edevs/ui": "0.1.0",
"antd": "^5.26.0",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.0"
}
}
+52
View File
@@ -0,0 +1,52 @@
import { ApartmentOutlined, RobotOutlined, ShoppingOutlined, TeamOutlined } from "@ant-design/icons";
import { ConfigProvider, Layout, Menu, Tag, Typography } from "antd";
import { edevsHubTheme } from "@edevs/ui";
const { Header, Sider, Content } = Layout;
export function App() {
return (
<ConfigProvider theme={edevsHubTheme}>
<Layout className="hub-shell">
<Sider width={256} className="hub-sidebar">
<div className="hub-logo">Edevs Hub</div>
<Menu
mode="inline"
selectedKeys={["command-center"]}
items={[
{ key: "command-center", icon: <ApartmentOutlined />, label: "Командный центр" },
{ type: "group", label: "Компания" },
{ key: "departments", icon: <TeamOutlined />, label: "Отделы" },
{ key: "products", icon: <ShoppingOutlined />, label: "Продукты" },
{ type: "group", label: "Платформа" },
{ key: "ai", icon: <RobotOutlined />, label: "AI" },
]}
/>
</Sider>
<Layout>
<Header className="hub-header">
<Typography.Text type="secondary">Edevs / Командный центр</Typography.Text>
<Tag color="success">Локальный контур</Tag>
</Header>
<Content className="hub-content">
<section className="page-header">
<Typography.Title level={1}>Командный центр</Typography.Title>
<Typography.Text type="secondary">
Первый рабочий каркас внутреннего Hub. Реальные домены подключаются на следующих этапах.
</Typography.Text>
</section>
<section className="department-grid">
<article className="department-card">
<div>
<Typography.Title level={2}>Продажи</Typography.Title>
<Tag color="default">NORMAL</Tag>
</div>
<p>Данные отдела появятся после реализации доменных модулей продаж, коммуникаций и коммерческого ядра.</p>
</article>
</section>
</Content>
</Layout>
</Layout>
</ConfigProvider>
);
}
+11
View File
@@ -0,0 +1,11 @@
import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "./App";
import "./styles.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
+52
View File
@@ -0,0 +1,52 @@
html,
body,
#root {
min-width: 1024px;
min-height: 100%;
margin: 0;
}
.hub-shell {
min-height: 100vh;
}
.hub-sidebar {
border-right: 1px solid #e5e7eb;
}
.hub-logo {
height: 56px;
padding: 18px 24px;
font-weight: 700;
}
.hub-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 56px;
padding: 0 24px;
border-bottom: 1px solid #e5e7eb;
}
.hub-content {
padding: 24px;
}
.page-header {
margin-bottom: 24px;
}
.department-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
gap: 16px;
}
.department-card {
min-height: 180px;
padding: 20px;
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 8px;
}
+4
View File
@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src", "vite.config.ts"]
}
+9
View File
@@ -0,0 +1,9 @@
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
},
});
View File
Whitespace-only changes.
+16
View File
@@ -0,0 +1,16 @@
FROM node:22-alpine
WORKDIR /app
COPY package.json tsconfig.base.json ./
COPY apps/web-chat/package.json ./apps/web-chat/package.json
COPY packages/ui/package.json ./packages/ui/package.json
COPY packages/contracts/package.json ./packages/contracts/package.json
COPY packages/shared/package.json ./packages/shared/package.json
RUN npm install
COPY apps/web-chat ./apps/web-chat
COPY packages ./packages
WORKDIR /app/apps/web-chat
EXPOSE 5175
+12
View File
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Web Chat | Edevs Hub</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+24
View File
@@ -0,0 +1,24 @@
{
"name": "@edevs/web-chat",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -p tsconfig.json && vite build",
"typecheck": "tsc -p tsconfig.json",
"test": "vitest run --passWithNoTests"
},
"dependencies": {
"@edevs/contracts": "0.1.0",
"@edevs/shared": "0.1.0",
"@edevs/ui": "0.1.0",
"antd": "^5.26.0",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.0"
}
}
+18
View File
@@ -0,0 +1,18 @@
import { ConfigProvider, FloatButton, Typography } from "antd";
import { edevsHubTheme } from "@edevs/ui";
export function App() {
return (
<ConfigProvider theme={edevsHubTheme}>
<main className="web-chat-demo">
<section className="chat-panel">
<Typography.Title level={2}>Web Chat</Typography.Title>
<Typography.Paragraph>
Каркас публичного виджета готов. Детальная реализация UI ждёт прохождения DG-04.
</Typography.Paragraph>
</section>
<FloatButton badge={{ dot: true }} tooltip="Открыть чат" />
</main>
</ConfigProvider>
);
}
+11
View File
@@ -0,0 +1,11 @@
import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "./App";
import "./styles.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
+22
View File
@@ -0,0 +1,22 @@
html,
body,
#root {
min-height: 100%;
margin: 0;
}
.web-chat-demo {
min-height: 100vh;
padding: 24px;
background: #f6f8fb;
}
.chat-panel {
width: min(420px, calc(100vw - 32px));
margin-left: auto;
padding: 20px;
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 8px;
box-shadow: 0 10px 30px rgb(15 23 42 / 10%);
}
+4
View File
@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src", "vite.config.ts"]
}
+9
View File
@@ -0,0 +1,9 @@
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [react()],
server: {
port: 5175,
},
});
+133
View File
@@ -0,0 +1,133 @@
x-hub-env: &hub-env
- path: .env.example
- path: .env
required: false
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB:-edevs_hub}
POSTGRES_USER: ${POSTGRES_USER:-edevs_hub}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-edevs_hub}
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 10
redis:
image: redis:7-alpine
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 10
backend:
build:
context: .
dockerfile: apps/backend/Dockerfile
env_file: *hub-env
command: >
sh -c "python manage.py migrate &&
uvicorn hub_backend.asgi:application --host 0.0.0.0 --port 8000"
ports:
- "${BACKEND_PORT:-8010}:8000"
volumes:
- ./apps/backend:/app/apps/backend
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test:
[
"CMD",
"python",
"-c",
"import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/v1/health/live/', timeout=3)",
]
interval: 10s
timeout: 5s
retries: 10
worker:
build:
context: .
dockerfile: apps/backend/Dockerfile
env_file: *hub-env
command: python manage.py run_worker
volumes:
- ./apps/backend:/app/apps/backend
depends_on:
backend:
condition: service_healthy
internal-ui:
build:
context: .
dockerfile: apps/internal-ui/Dockerfile
env_file: *hub-env
command: npm run dev -- --host 0.0.0.0 --port 5173
ports:
- "5173:5173"
volumes:
- ./apps/internal-ui:/app/apps/internal-ui
- ./packages:/app/packages
- /app/node_modules
- /app/apps/internal-ui/node_modules
checkout:
build:
context: .
dockerfile: apps/checkout/Dockerfile
env_file: *hub-env
command: npm run dev -- --host 0.0.0.0 --port 5174
ports:
- "5174:5174"
volumes:
- ./apps/checkout:/app/apps/checkout
- ./packages:/app/packages
- /app/node_modules
- /app/apps/checkout/node_modules
web-chat:
build:
context: .
dockerfile: apps/web-chat/Dockerfile
env_file: *hub-env
command: npm run dev -- --host 0.0.0.0 --port 5175
ports:
- "5175:5175"
volumes:
- ./apps/web-chat:/app/apps/web-chat
- ./packages:/app/packages
- /app/node_modules
- /app/apps/web-chat/node_modules
proxy:
image: nginx:1.27-alpine
ports:
- "80:80"
volumes:
- ./deploy/nginx/local.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
backend:
condition: service_healthy
internal-ui:
condition: service_started
checkout:
condition: service_started
web-chat:
condition: service_started
volumes:
postgres_data:
View File
Whitespace-only changes.
+48
View File
@@ -0,0 +1,48 @@
server {
listen 80;
server_name hub.localhost localhost;
location /api/ {
proxy_pass http://backend:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://internal-ui:5173;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name pay.localhost;
location /api/ {
proxy_pass http://backend:8000;
proxy_set_header Host $host;
}
location / {
proxy_pass http://checkout:5174;
proxy_set_header Host $host;
}
}
server {
listen 80;
server_name chat.localhost;
location /api/ {
proxy_pass http://backend:8000;
proxy_set_header Host $host;
}
location / {
proxy_pass http://web-chat:5175;
proxy_set_header Host $host;
}
}
View File
Whitespace-only changes.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,168 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1120px;">
<!-- ============ SIDEBAR (уровень компании) ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span><span style="font-size:11px;color:#8c8c8c;">Уровень компании</span></div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>Командный центр</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="Отделы.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>Отделы</a>
<a href="Сотрудники.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Сотрудники</a>
<a href="Продукты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>Продукты</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/><path d="M2 13.5h2M20 13.5h2"/></svg>AI</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>Интеграции</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><line x1="3" y1="18" x2="11" y2="18"/><circle cx="13" cy="18" r="2"/></svg>Настройки</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><span style="font-weight:500;color:#595959;">AI</span><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">AI-агенты</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<!-- AI SUBNAV -->
<div style="flex:none;background:#fff;border-bottom:1px solid #f0f0f0;padding:0 28px;display:flex;align-items:center;gap:2px;">
<a href="#" style="padding:13px 14px;font-size:13.5px;font-weight:600;color:#1677ff;text-decoration:none;border-bottom:2px solid #1677ff;margin-bottom:-1px;">AI-агенты</a>
<a href="Тестовый чат.dc.html" style="padding:13px 14px;font-size:13.5px;font-weight:500;color:#595959;text-decoration:none;border-bottom:2px solid transparent;margin-bottom:-1px;" style-hover="color:#262626;">Тестовый чат</a>
<a href="#" style="padding:13px 14px;font-size:13.5px;font-weight:500;color:#595959;text-decoration:none;border-bottom:2px solid transparent;margin-bottom:-1px;" style-hover="color:#262626;">Использование AI</a>
</div>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1280px;margin:0 auto;">
<sc-if value="{{ menuId }}" hint-placeholder-val="{{ false }}">
<div onClick="{{ onCloseMenu }}" style="position:fixed;inset:0;z-index:20;"></div>
</sc-if>
<!-- PAGE HEADER -->
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:18px;">
<div>
<h1 style="margin:0;font-size:24px;font-weight:700;letter-spacing:-0.02em;color:#1f1f1f;line-height:1.2;">AI-агенты</h1>
<p style="margin:6px 0 0;font-size:13.5px;color:#8c8c8c;">Sales-агенты продуктов · один агент на продукт</p>
</div>
</div>
<!-- KPI STRIP -->
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:20px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:14px 16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);"><div style="font-size:12px;color:#8c8c8c;">Агентов активно</div><div style="font-size:23px;font-weight:700;color:#262626;margin-top:7px;">2 / 2</div></div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:14px 16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);"><div style="font-size:12px;color:#8c8c8c;">Диалогов на AI сейчас</div><div style="font-size:23px;font-weight:700;color:#262626;margin-top:7px;">35</div></div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:14px 16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);"><div style="font-size:12px;color:#8c8c8c;">Конверсия AI · сегодня</div><div style="font-size:23px;font-weight:700;color:#262626;margin-top:7px;">13,2%</div></div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:14px 16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);"><div style="font-size:12px;color:#8c8c8c;">Стоимость AI · сегодня</div><div style="font-size:23px;font-weight:700;color:#262626;margin-top:7px;">₽1 240</div></div>
</div>
<!-- TABLE -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="overflow-x:auto;">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:1180px;">
<thead><tr style="background:#fafafa;">
<th style="text-align:left;padding:11px 18px;font-size:11px;font-weight:600;color:#8c8c8c;letter-spacing:0.03em;border-bottom:1px solid #f0f0f0;">АГЕНТ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПРОДУКТ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">МОДЕЛЬ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">АКТИВНЫЙ RELEASE</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СТАТУС</th>
<th style="text-align:right;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ДИАЛОГИ СЕЙЧАС</th>
<th style="text-align:right;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">КОНВЕРСИЯ</th>
<th style="width:160px;border-bottom:1px solid #f0f0f0;"></th>
</tr></thead>
<tbody>
<sc-for list="{{ rows }}" as="r" hint-placeholder-count="2">
<tr style="border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<td style="padding:14px 18px;">
<div style="display:flex;align-items:center;gap:12px;">
<div style="width:38px;height:38px;border-radius:10px;background:#f9f0ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="#722ed1" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/></svg></div>
<div><a href="#" style="font-weight:600;color:#1677ff;text-decoration:none;font-size:13.5px;">{{ r.name }}</a><div style="font-size:11.5px;color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ r.id }}</div></div>
</div>
</td>
<td style="padding:14px 12px;"><span style="padding:2px 9px;border-radius:6px;background:{{ r.prodBg }};color:{{ r.prodColor }};font-size:11.5px;font-weight:600;">{{ r.product }}</span></td>
<td style="padding:14px 12px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">{{ r.model }}</td>
<td style="padding:14px 12px;"><a href="ProductAIRelease.dc.html" style="color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;font-weight:500;">{{ r.release }}</a><span style="margin-left:7px;padding:1px 7px;border-radius:5px;background:#f6ffed;color:#389e0d;font-size:10.5px;font-weight:600;">Published</span></td>
<td style="padding:14px 12px;"><span style="display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:600;color:{{ r.stColor }};"><span style="width:7px;height:7px;border-radius:50%;background:{{ r.stDot }};"></span>{{ r.status }}</span></td>
<td style="padding:14px 12px;text-align:right;font-weight:600;color:#262626;">{{ r.dialogs }}</td>
<td style="padding:14px 12px;text-align:right;color:#595959;">{{ r.conv }}</td>
<td style="padding:14px 12px;text-align:right;position:relative;">
<div style="display:inline-flex;align-items:center;gap:7px;">
<a href="Тестовый чат.dc.html" style="display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border-radius:7px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:12.5px;font-weight:500;text-decoration:none;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>Test chat</a>
<button onClick="{{ r.onMenu }}" style="width:32px;height:32px;border-radius:7px;border:1px solid #f0f0f0;background:#fff;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;color:#8c8c8c;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
</div>
<sc-if value="{{ r.menuOpen }}" hint-placeholder-val="{{ false }}">
<div style="position:absolute;right:12px;top:44px;z-index:30;width:218px;background:#fff;border:1px solid #f0f0f0;border-radius:10px;box-shadow:0 6px 20px rgba(0,0,0,0.12);padding:5px;text-align:left;">
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#262626;font-size:13px;font-weight:500;" style-hover="background:#f5f5f5;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg>Открыть агента</a>
<a href="ProductAIRelease.dc.html" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#262626;font-size:13px;font-weight:500;" style-hover="background:#f5f5f5;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Создать release candidate</a>
<div style="height:1px;background:#f5f5f5;margin:4px 8px;"></div>
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#d48806;font-size:13px;font-weight:500;" style-hover="background:#fffbe6;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/></svg>Остановить агента</a>
</div>
</sc-if>
</td>
</tr>
</sc-for>
</tbody>
</table>
</div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 18px;border-top:1px solid #f5f5f5;">
<div style="font-size:12.5px;color:#8c8c8c;">2 агента</div>
<div style="font-size:12.5px;color:#bfbfbf;">В первой итерации — один sales-agent на продукт</div>
</div>
</div>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 900 }
}">
class Component extends DCLogic {
state = { menuId: null };
renderVals() {
const running = { status: 'Активен', stColor: '#389e0d', stDot: '#52c41a' };
const data = [
{ id: 'AGT-FP-01', name: 'FirePage Sales', product: 'FirePage', prodBg: '#e6f4ff', prodColor: '#0958d9', model: 'gpt-4o-mini', release: 'REL-FP-v4', dialogs: '21', conv: '15,1%', ...running },
{ id: 'AGT-FX-01', name: 'Foxray Sales', product: 'Foxray', prodBg: '#f9f0ff', prodColor: '#722ed1', model: 'gpt-4o-mini', release: 'REL-FX-v3', dialogs: '14', conv: '12,8%', ...running },
];
const { menuId } = this.state;
const rows = data.map((d) => ({
...d,
menuOpen: menuId === d.id,
onMenu: () => this.setState((s) => ({ menuId: s.menuId === d.id ? null : d.id })),
}));
return { rows, menuId, onCloseMenu: () => this.setState({ menuId: null }) };
}
}
</script>
</body>
</html>
@@ -0,0 +1,88 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
</style>
</helmet>
<div style="min-height:100vh;display:flex;align-items:center;justify-content:center;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;padding:24px;">
<div style="width:400px;max-width:100%;">
<!-- brand -->
<div style="display:flex;flex-direction:column;align-items:center;margin-bottom:24px;">
<div style="width:48px;height:48px;border-radius:13px;background:#1677ff;display:flex;align-items:center;justify-content:center;margin-bottom:14px;box-shadow:0 4px 12px rgba(22,119,255,0.3);"><svg viewBox="0 0 24 24" width="26" height="26" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<h1 style="margin:0;font-size:20px;font-weight:700;letter-spacing:-0.01em;color:#1f1f1f;">Edevs Hub</h1>
<p style="margin:5px 0 0;font-size:13px;color:#8c8c8c;">Вход во внутренний кабинет</p>
</div>
<!-- form card -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:14px;box-shadow:0 2px 12px rgba(0,0,0,0.05);padding:26px 26px 24px;">
<sc-if value="{{ hasError }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;align-items:flex-start;gap:10px;padding:11px 13px;background:#fff2f0;border:1px solid #ffccc7;border-radius:9px;margin-bottom:18px;">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#cf1322" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex:none;margin-top:1px;"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
<span style="font-size:12.5px;color:#cf1322;line-height:1.45;">Неверный email или пароль. Проверьте данные и попробуйте снова.</span>
</div>
</sc-if>
<label style="display:block;font-size:12.5px;color:#595959;margin-bottom:7px;font-weight:500;">Email</label>
<div style="display:flex;align-items:center;gap:9px;height:42px;padding:0 13px;border:1px solid {{ emailBorder }};border-radius:9px;background:#fff;margin-bottom:16px;">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#bfbfbf" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" style="flex:none;"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-10 5L2 7"/></svg>
<input value="{{ email }}" onInput="{{ onEmail }}" placeholder="you@edevs.tech" style="border:none;outline:none;background:transparent;font-size:14px;color:#262626;width:100%;font-family:inherit;" />
</div>
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:7px;">
<label style="font-size:12.5px;color:#595959;font-weight:500;">Пароль</label>
<a href="#" style="font-size:12px;color:#1677ff;text-decoration:none;font-weight:500;" style-hover="text-decoration:underline;">Восстановить доступ</a>
</div>
<div style="display:flex;align-items:center;gap:9px;height:42px;padding:0 13px;border:1px solid {{ pwdBorder }};border-radius:9px;background:#fff;margin-bottom:22px;">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#bfbfbf" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" style="flex:none;"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
<input type="{{ pwdType }}" value="{{ pwd }}" onInput="{{ onPwd }}" placeholder="Пароль" style="border:none;outline:none;background:transparent;font-size:14px;color:#262626;width:100%;font-family:inherit;" />
<button onClick="{{ onTogglePwd }}" style="border:none;background:transparent;cursor:pointer;color:#bfbfbf;display:flex;flex:none;padding:0;" style-hover="color:#595959;">{{ eyeIcon }}</button>
</div>
<button onClick="{{ onSubmit }}" style="width:100%;height:44px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:14.5px;font-weight:600;cursor:pointer;box-shadow:0 1px 2px rgba(22,119,255,0.3);display:flex;align-items:center;justify-content:center;gap:8px;" style-hover="background:#0958d9;">Войти<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg></button>
</div>
<p style="text-align:center;margin:18px 0 0;font-size:12px;color:#bfbfbf;">Доступ только для сотрудников Edevs · защищённое соединение</p>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 900 }
}">
class Component extends DCLogic {
state = { email: '', pwd: '', show: false, error: false };
renderVals() {
const eye = (open) => open
? React.createElement('svg', { viewBox: '0 0 24 24', width: 16, height: 16, fill: 'none', stroke: 'currentColor', strokeWidth: 1.8, strokeLinecap: 'round', strokeLinejoin: 'round' }, React.createElement('path', { key: 1, d: 'M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z' }), React.createElement('circle', { key: 2, cx: 12, cy: 12, r: 3 }))
: React.createElement('svg', { viewBox: '0 0 24 24', width: 16, height: 16, fill: 'none', stroke: 'currentColor', strokeWidth: 1.8, strokeLinecap: 'round', strokeLinejoin: 'round' }, React.createElement('path', { key: 1, d: 'M9.9 4.2A9.1 9.1 0 0 1 12 4c7 0 10 8 10 8a13 13 0 0 1-1.7 2.7M6.6 6.6A13 13 0 0 0 2 12s3 8 10 8a9 9 0 0 0 3.4-.6' }), React.createElement('path', { key: 2, d: 'M9.9 9.9a3 3 0 0 0 4.2 4.2' }), React.createElement('line', { key: 3, x1: 2, y1: 2, x2: 22, y2: 22 }));
const err = this.state.error;
return {
email: this.state.email, pwd: this.state.pwd,
pwdType: this.state.show ? 'text' : 'password',
eyeIcon: eye(this.state.show),
hasError: err,
emailBorder: err ? '#ffccc7' : '#e8e8e8',
pwdBorder: err ? '#ffccc7' : '#e8e8e8',
onEmail: (e) => this.setState({ email: e.target.value, error: false }),
onPwd: (e) => this.setState({ pwd: e.target.value, error: false }),
onTogglePwd: () => this.setState((s) => ({ show: !s.show })),
onSubmit: () => this.setState({ error: true }),
};
}
}
</script>
</body>
</html>
+35
View File
@@ -0,0 +1,35 @@
d549527b8f9c7a42c08719c881d98733cda85d708f67b4f149cb9fa87bd302ae #U0410#U0443#U0434#U0438#U0442.dc.html
65f1b00ce2b529640284ad25c8e4d59a4e517ef5c1a9f086bac4e439193e131a #U0418#U043d#U0442#U0435#U0433#U0440#U0430#U0446#U0438#U0438.dc.html
01a7727f0b15e3b1e8bd866c624a8a31bb10a2da5e857b4a3b84c53dc55dc888 #U0418#U0441#U043f#U043e#U043b#U044c#U0437#U043e#U0432#U0430#U043d#U0438#U0435 AI.dc.html
9c777f9d4a1a01921f6d3a22b727f3b59e29e6be25a409cd712e9ae048ed360a #U041a#U0430#U0440#U0442#U043e#U0447#U043a#U0430 #U0438#U043d#U0442#U0435#U0433#U0440#U0430#U0446#U0438#U0438.dc.html
5d3d52d5b20c6e0292b697f8fadf3f24f6439dd199895e1452500ba9be73c199 #U041a#U0430#U0440#U0442#U043e#U0447#U043a#U0430 #U043f#U0440#U043e#U0434#U0443#U043a#U0442#U0430.dc.html
7057493435e132ecea34abcf71551ba89449e7ee74df81f617f322d9f3e629a3 #U041a#U0430#U0440#U0442#U043e#U0447#U043a#U0430 #U0441#U043e#U0442#U0440#U0443#U0434#U043d#U0438#U043a#U0430.dc.html
b815c76e76d52db851e0314bfd764c08915aa1670b273eda60f283e4b9d192ad #U041a#U0430#U0440#U0442#U043e#U0447#U043a#U0430 AI-#U0430#U0433#U0435#U043d#U0442#U0430.dc.html
653f41c7ac5a9fcee37f843f4453ff178f744ae43fa0d534988f6a3d882afb3e #U041a#U043e#U043c#U0430#U043d#U0434#U043d#U044b#U0439 #U0446#U0435#U043d#U0442#U0440.dc.html
c6d096b5c645e24d104684373f026239f5c1b7e04d6abd1c8f11c38a9dde3dc6 #U041d#U0430#U0441#U0442#U0440#U043e#U0439#U043a#U0438.dc.html
a003db70efc372ded0ff600000b33d78cd0d59e0f0351cd5f1ce68291afcc711 #U041e#U0442#U0434#U0435#U043b#U044b.dc.html
3a68bfc31de264c1d54466f69f8d1ac38eede69432b1e7dfe55191937c34b355 #U041f#U0440#U043e#U0434#U0430#U0436#U0438 #U00b7 #U0414#U0438#U0430#U043b#U043e#U0433#U0438.dc.html
26ce567d808363a7858fd248d22fa9c0e3548ab1f71783704ee419fd26051155 #U041f#U0440#U043e#U0434#U0430#U0436#U0438 #U00b7 #U041a#U0430#U0440#U0442#U043e#U0447#U043a#U0430 #U0437#U0430#U043a#U0430#U0437#U0430.dc.html
aae56acbc110e3bda8fbde2d3b9f817915e00837a524517c6721b0199d359560 #U041f#U0440#U043e#U0434#U0430#U0436#U0438 #U00b7 #U041a#U0430#U0440#U0442#U043e#U0447#U043a#U0430 #U043a#U043b#U0438#U0435#U043d#U0442#U0430.dc.html
abbbbc373be1ca2386fb1eda7790c77715e643ce06234258dde03a56145fee41 #U041f#U0440#U043e#U0434#U0430#U0436#U0438 #U00b7 #U041a#U043b#U0438#U0435#U043d#U0442#U044b.dc.html
e61ff1cdb6c4ab80463e5afd7fec41bdc5d407f17fbe64ed08aa49d830be349f #U041f#U0440#U043e#U0434#U0430#U0436#U0438 #U00b7 #U041e#U0431#U0437#U043e#U0440.dc.html
86ec3c171f78d2abd7625e3a039dda1e759566641a2329f113ee0be851c2df81 #U041f#U0440#U043e#U0434#U0430#U0436#U0438 #U00b7 #U041f#U0440#U043e#U0434#U0430#U0436#U0438.dc.html
b247932639fa3441bfaff801e733d26d6293cc93e40d67e52c3e7fa9d364c6a6 #U041f#U0440#U043e#U0434#U0443#U043a#U0442#U044b.dc.html
869ad944fdac1acbefd6e017fe59f20c43ac784deda063efd118271b72fece58 #U041f#U0440#U043e#U0444#U0438#U043b#U044c.dc.html
64c50854f460c471e52ab18af50c632a9dbbd4043442b252d8b3b13927141915 #U0421#U043e#U0442#U0440#U0443#U0434#U043d#U0438#U043a#U0438.dc.html
973deac2d4dc992a130e38cd1a792174ccfe0aedc2dc6e0a1628e747ff426d68 #U0422#U0435#U0441#U0442#U043e#U0432#U044b#U0439 #U0447#U0430#U0442.dc.html
94d0f43a0a80086e40ad9be57ca3e1f9460bbc1ac4655a15a8ebe7af8204d017 .thumbnail
6d89697f16bf17a1c2dc8757cd6ec987a34d7de6a16f0b8494d79c2d6148e062 AI-#U0430#U0433#U0435#U043d#U0442#U044b.dc.html
a6396ab0d26b278afa3bb6306e4667d43d2606f75306c9dd72aeed8eb6bccb8f AUTH #U00b7 #U0412#U0445#U043e#U0434.dc.html
80b1436c39c915a8eba25ada02e27d014e847a62b23d3fd635ba010395fbdeed ProductAIRelease.dc.html
cea9065b0892755a5ccb4bf7e1bf214bcd44520e0055f9c981e58bad0c58ecf4 screenshots/01-emp-security.png
e2c4d7a686d71f1d7464c1e121a6a49d813902becf08d3b6a44c77a1cb35e2cd screenshots/01-ov-lower.png
cea9065b0892755a5ccb4bf7e1bf214bcd44520e0055f9c981e58bad0c58ecf4 screenshots/02-emp-security.png
ae02004de7c6427ab3fdcc6b2124494013e2f2ba50b7c92545f81c96102d0bbc screenshots/02-ov-lower.png
d410897bf2fb7614c4cd49a2f5308348382b2cdd5253b2755dd3a16414c6183b screenshots/cc-01.png
e05ab592a28ee75975cfffe1b08def8679d333a29934cee4b79dcb32466a33db screenshots/cc-full.png
f68d5bccb5697155a7235ac38bfc99ce41e14f1f4b7f0f711ff0018f0cdb61bf screenshots/dialogs-waiting.png
cdb685c1642a8cb7f3cd0b80d6338b14c7ba8573cf2586ae56cd3d66747c893b screenshots/overview.png
505f94e08eeccbc87acc6fcc6a47dd9f51fcd74a8d28ab58eb7eb784f7b92efe support.js
212f0e10d99b36513d5eb424183f8d6e4d9ba6eae46495c9e0e27ce7a94b9f6b uploads/ADR-HUB-0013-Internal-UI-Design-System.md
e0067ea9a7cacbc71b0925e02f9277ef8e23c587f11cc23670009919b62acb7d uploads/SPEC-HUB-0004-Internal-Hub-UI.md
@@ -0,0 +1,286 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1120px;">
<!-- ============ SIDEBAR (уровень компании) ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span><span style="font-size:11px;color:#8c8c8c;">Уровень компании</span></div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>Командный центр</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="Отделы.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>Отделы</a>
<a href="Сотрудники.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Сотрудники</a>
<a href="Продукты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>Продукты</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="AI-агенты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/><path d="M2 13.5h2M20 13.5h2"/></svg>AI</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>Интеграции</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><line x1="3" y1="18" x2="11" y2="18"/><circle cx="13" cy="18" r="2"/></svg>Настройки</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">AI</span><span style="color:#d9d9d9;">/</span><a href="Карточка AI-агента.dc.html" style="font-weight:500;color:#595959;text-decoration:none;" style-hover="color:#1677ff;">FirePage Sales</a><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;font-family:'SF Mono',ui-monospace,Menlo,monospace;">REL-FP-v5</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<!-- STATUS BAR -->
<div style="flex:none;background:#fff;border-bottom:1px solid #f0f0f0;padding:14px 28px;display:flex;align-items:center;justify-content:space-between;gap:20px;">
<div style="display:flex;align-items:center;gap:13px;min-width:0;">
<div style="width:40px;height:40px;border-radius:10px;background:#f9f0ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="21" height="21" fill="none" stroke="#722ed1" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/></svg></div>
<div style="min-width:0;">
<div style="display:flex;align-items:center;gap:10px;"><h1 style="margin:0;font-size:17px;font-weight:700;color:#1f1f1f;font-family:'SF Mono',ui-monospace,Menlo,monospace;">REL-FP-v5</h1><span style="display:inline-flex;align-items:center;gap:6px;padding:3px 11px;border-radius:14px;background:{{ st.bg }};border:1px solid {{ st.border }};font-size:11.5px;font-weight:600;color:{{ st.color }};"><span style="width:6px;height:6px;border-radius:50%;background:{{ st.dot }};"></span>{{ st.label }}</span></div>
<div style="font-size:12px;color:#8c8c8c;margin-top:2px;">FirePage Sales · candidate создан сегодня 11:20 · автор Иван Петров</div>
</div>
</div>
<div style="display:flex;align-items:center;gap:9px;flex:none;">
<button style="display:flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M16 3h5v5"/><path d="M8 3H3v5"/><path d="M21 3l-7 7"/><path d="M3 3l7 7"/><path d="M16 21h5v-5"/><path d="M8 21H3v-5"/><path d="M21 21l-7-7"/><path d="M3 21l7-7"/></svg>Сравнить с published</button>
<a href="Тестовый чат.dc.html" style="display:flex;align-items:center;gap:7px;height:38px;padding:0 14px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;text-decoration:none;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>Test chat</a>
<button onClick="{{ onPublish }}" style="{{ publishBtn }}"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 2 11 13"/><path d="M22 2 15 22l-4-9-9-4 20-7Z"/></svg>{{ publishLabel }}</button>
</div>
</div>
<main style="flex:1;overflow-y:auto;padding:20px 28px 40px;">
<div style="max-width:1180px;margin:0 auto;">
<!-- validation banner -->
<div style="display:flex;align-items:center;gap:11px;padding:12px 16px;border-radius:10px;margin-bottom:18px;background:{{ vb.bg }};border:1px solid {{ vb.border }};">
<span style="flex:none;">{{ vb.icon }}</span>
<div style="flex:1;min-width:0;"><div style="font-size:13px;font-weight:600;color:{{ vb.titleColor }};">{{ vb.title }}</div><div style="font-size:12px;color:#595959;margin-top:1px;">{{ vb.note }}</div></div>
<button style="height:32px;padding:0 13px;border-radius:8px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:12.5px;font-weight:500;cursor:pointer;flex:none;" style-hover="border-color:#1677ff;color:#1677ff;">Запустить проверку</button>
</div>
<!-- 3-column layout: Состав | Проверки | Изменения -->
<div style="display:grid;grid-template-columns:1fr 320px;gap:18px;align-items:start;">
<!-- LEFT: Состав release -->
<div style="display:flex;flex-direction:column;gap:16px;">
<h2 style="margin:0;font-size:14px;font-weight:600;color:#595959;letter-spacing:0.01em;">Состав release</h2>
<!-- модель и параметры -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<div style="display:flex;align-items:center;gap:9px;margin-bottom:13px;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#722ed1" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/></svg><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Модель и параметры</h3></div>
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;">
<div><div style="font-size:11px;color:#8c8c8c;">Модель</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">gpt-4o-mini</div></div>
<div><div style="font-size:11px;color:#8c8c8c;">Temperature</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">0.4</div></div>
<div><div style="font-size:11px;color:#8c8c8c;">Max tokens</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">1024</div></div>
<div><div style="font-size:11px;color:#8c8c8c;">Top-p</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">0.9</div></div>
</div>
</div>
<!-- версии prompts -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:14px 18px 11px;display:flex;align-items:center;gap:9px;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#595959" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><polyline points="14 2 14 8 20 8"/></svg><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Версии prompts</h3></div>
<sc-for list="{{ prompts }}" as="p" hint-placeholder-count="4">
<div style="display:flex;align-items:center;gap:12px;padding:11px 18px;border-top:1px solid #f5f5f5;">
<div style="flex:1;min-width:0;"><span style="font-size:13px;font-weight:500;color:#262626;">{{ p.name }}</span><span style="margin-left:8px;font-size:11px;color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ p.ver }}</span></div>
<sc-if value="{{ p.changed }}" hint-placeholder-val="{{ false }}"><span style="padding:1px 8px;border-radius:5px;background:#fff7e6;color:#d48806;font-size:10.5px;font-weight:600;">изменён</span></sc-if>
<span style="font-size:11.5px;color:#bfbfbf;width:90px;text-align:right;">{{ p.updated }}</span>
</div>
</sc-for>
</div>
<!-- обязательные знания + retrieval -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:14px 18px 11px;display:flex;align-items:center;justify-content:space-between;"><div style="display:flex;align-items:center;gap:9px;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#595959" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2Z"/></svg><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Обязательные знания</h3></div><span style="font-size:11.5px;color:#8c8c8c;">retrieval index · <b style="color:#389e0d;">собран</b></span></div>
<sc-for list="{{ knowledge }}" as="k" hint-placeholder-count="3">
<div style="display:flex;align-items:center;gap:11px;padding:10px 18px;border-top:1px solid #f5f5f5;">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="#389e0d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex:none;"><path d="M20 6 9 17l-5-5"/></svg>
<span style="flex:1;font-size:13px;color:#262626;">{{ k.title }}</span>
<span style="font-size:11px;color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ k.ver }}</span>
</div>
</sc-for>
</div>
<!-- инструменты + лимиты -->
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 12px;font-size:14px;font-weight:700;color:#1f1f1f;">Инструменты</h3>
<div style="display:flex;flex-direction:column;gap:8px;">
<div style="display:flex;align-items:center;gap:8px;"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#389e0d" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg><span style="font-size:12.5px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;">create_checkout</span></div>
<div style="display:flex;align-items:center;gap:8px;"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#389e0d" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg><span style="font-size:12.5px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;">get_offers</span></div>
<div style="display:flex;align-items:center;gap:8px;"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#389e0d" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg><span style="font-size:12.5px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;">handoff_to_operator</span></div>
</div>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 12px;font-size:14px;font-weight:700;color:#1f1f1f;">Лимиты</h3>
<div style="display:flex;align-items:center;justify-content:space-between;padding:5px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Диалогов в день</span><span style="font-size:12.5px;font-weight:600;color:#262626;">5 000</span></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:5px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Бюджет в день</span><span style="font-size:12.5px;font-weight:600;color:#262626;">₽5 000</span></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:5px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Макс. сообщений / диалог</span><span style="font-size:12.5px;font-weight:600;color:#262626;">40</span></div>
</div>
</div>
</div>
<!-- RIGHT: Проверки + Изменения -->
<div style="display:flex;flex-direction:column;gap:16px;">
<!-- Проверки -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:14px 18px 11px;display:flex;align-items:center;justify-content:space-between;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Проверки</h3><span style="font-size:11.5px;font-weight:600;color:{{ checksColor }};">{{ checksSummary }}</span></div>
<sc-for list="{{ checks }}" as="c" hint-placeholder-count="5">
<div style="display:flex;align-items:flex-start;gap:10px;padding:10px 18px;border-top:1px solid #f5f5f5;">
<span style="flex:none;margin-top:1px;">{{ c.icon }}</span>
<div style="flex:1;min-width:0;"><div style="font-size:12.5px;font-weight:500;color:#262626;">{{ c.label }}</div><sc-if value="{{ c.detail }}" hint-placeholder-val="{{ false }}"><div style="font-size:11px;color:{{ c.detailColor }};margin-top:1px;">{{ c.detail }}</div></sc-if></div>
</div>
</sc-for>
</div>
<!-- Изменения -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:14px 18px 11px;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Изменения</h3><div style="font-size:11.5px;color:#bfbfbf;margin-top:2px;">Относительно REL-FP-v4 (published)</div></div>
<sc-for list="{{ changes }}" as="ch" hint-placeholder-count="3">
<div style="display:flex;align-items:flex-start;gap:10px;padding:10px 18px;border-top:1px solid #f5f5f5;">
<span style="width:18px;height:18px;border-radius:5px;background:{{ ch.bg }};color:{{ ch.color }};font-size:13px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;flex:none;line-height:1;">{{ ch.sign }}</span>
<div style="flex:1;min-width:0;"><div style="font-size:12.5px;color:#262626;line-height:1.4;">{{ ch.text }}</div></div>
</div>
</sc-for>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- PUBLISH CONFIRM MODAL -->
<sc-if value="{{ modalOpen }}" hint-placeholder-val="{{ false }}">
<div style="position:fixed;inset:0;z-index:50;background:rgba(0,0,0,0.45);display:flex;align-items:center;justify-content:center;padding:20px;">
<div style="width:480px;max-width:100%;background:#fff;border-radius:14px;box-shadow:0 20px 60px rgba(0,0,0,0.3);overflow:hidden;">
<div style="padding:22px 24px 18px;">
<div style="display:flex;align-items:center;gap:12px;margin-bottom:14px;">
<div style="width:42px;height:42px;border-radius:11px;background:#fff7e6;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="#d48806" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="m21.7 18-8-14a2 2 0 0 0-3.5 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3Z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></div>
<div><h3 style="margin:0;font-size:17px;font-weight:700;color:#1f1f1f;">Опубликовать REL-FP-v5?</h3><div style="font-size:12.5px;color:#8c8c8c;margin-top:2px;">Атомарная публикация конфигурации FirePage Sales</div></div>
</div>
<div style="background:#fffbe6;border:1px solid #ffe58f;border-radius:10px;padding:13px 15px;font-size:13px;color:#7c5a00;line-height:1.55;">Новые ответы во <b>всех активных диалогах</b> сразу будут использовать этот release. Текущий REL-FP-v4 перейдёт в архив. Действие необратимо в части уже отправленных ответов.</div>
<div style="display:flex;align-items:center;gap:10px;margin-top:16px;padding:11px 13px;background:#fafafa;border:1px solid #f0f0f0;border-radius:9px;">
<div role="checkbox" onClick="{{ onToggleConfirm }}" style="{{ confirmBox }}"><sc-if value="{{ confirmChecked }}" hint-placeholder-val="{{ false }}"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></sc-if></div>
<span onClick="{{ onToggleConfirm }}" style="font-size:12.5px;color:#262626;cursor:pointer;user-select:none;">Понимаю, что активные диалоги переключатся на новый release</span>
</div>
</div>
<div style="display:flex;justify-content:flex-end;gap:10px;padding:14px 24px;border-top:1px solid #f5f5f5;background:#fafbfc;">
<button onClick="{{ onCancelPublish }}" style="height:38px;padding:0 16px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#595959;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#bfbfbf;color:#262626;">Отмена</button>
<button style="{{ confirmPublishBtn }}"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 2 11 13"/><path d="M22 2 15 22l-4-9-9-4 20-7Z"/></svg>Опубликовать release</button>
</div>
</div>
</div>
</sc-if>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 },
&quot;releaseState&quot;: { &quot;editor&quot;: &quot;enum&quot;, &quot;options&quot;: [&quot;incomplete&quot;, &quot;errors&quot;, &quot;ready_test&quot;, &quot;ready_publish&quot;, &quot;published&quot;], &quot;default&quot;: &quot;ready_publish&quot;, &quot;tsType&quot;: &quot;string&quot; }
}">
class Component extends DCLogic {
state = { modalOpen: false, confirmChecked: false };
renderVals() {
const S = this.props.releaseState ?? 'ready_publish';
const st = {
incomplete: { label: 'Неполный candidate', color: '#8c8c8c', bg: '#f5f5f5', border: '#e8e8e8', dot: '#bfbfbf' },
errors: { label: 'Ошибки валидации', color: '#cf1322', bg: '#fff2f0', border: '#ffccc7', dot: '#ff4d4f' },
ready_test: { label: 'Готов к тестированию', color: '#0958d9', bg: '#e6f4ff', border: '#91caff', dot: '#1677ff' },
ready_publish:{ label: 'Готов к публикации', color: '#389e0d', bg: '#f6ffed', border: '#b7eb8f', dot: '#52c41a' },
published: { label: 'Published', color: '#389e0d', bg: '#f6ffed', border: '#b7eb8f', dot: '#52c41a' },
}[S];
const ok = (color) => React.createElement('svg', { viewBox: '0 0 24 24', width: 16, height: 16, fill: 'none', stroke: color || '#52c41a', strokeWidth: 2.2, strokeLinecap: 'round', strokeLinejoin: 'round' }, React.createElement('circle', { cx: 12, cy: 12, r: 10 }), React.createElement('path', { d: 'M8 12l3 3 5-6' }));
const err = React.createElement('svg', { viewBox: '0 0 24 24', width: 16, height: 16, fill: 'none', stroke: '#ff4d4f', strokeWidth: 2.2, strokeLinecap: 'round', strokeLinejoin: 'round' }, React.createElement('circle', { cx: 12, cy: 12, r: 10 }), React.createElement('line', { x1: 15, y1: 9, x2: 9, y2: 15 }), React.createElement('line', { x1: 9, y1: 9, x2: 15, y2: 15 }));
const warn = React.createElement('svg', { viewBox: '0 0 24 24', width: 16, height: 16, fill: 'none', stroke: '#faad14', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' }, React.createElement('circle', { cx: 12, cy: 12, r: 10 }), React.createElement('line', { x1: 12, y1: 8, x2: 12, y2: 12 }), React.createElement('line', { x1: 12, y1: 16, x2: 12.01, y2: 16 }));
const pending = React.createElement('svg', { viewBox: '0 0 24 24', width: 16, height: 16, fill: 'none', stroke: '#bfbfbf', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' }, React.createElement('circle', { cx: 12, cy: 12, r: 10 }));
const hasErrors = S === 'errors';
const checks = [
{ label: 'Системный prompt задан', icon: ok() },
{ label: 'Обязательные знания в индексе', icon: ok() },
{ label: 'Retrieval index собран', icon: ok() },
hasErrors
? { label: 'Инструменты сконфигурированы', detail: 'create_checkout: не задан Offer по умолчанию', detailColor: '#cf1322', icon: err }
: { label: 'Инструменты сконфигурированы', icon: ok() },
{ label: 'Лимиты в допустимых границах', icon: ok() },
S === 'incomplete'
? { label: 'Sales behavior заполнен', detail: 'раздел пуст', detailColor: '#d48806', icon: warn }
: { label: 'Sales behavior заполнен', icon: ok() },
];
const checksColor = hasErrors ? '#cf1322' : S === 'incomplete' ? '#d48806' : '#389e0d';
const checksSummary = hasErrors ? '1 ошибка' : S === 'incomplete' ? '1 предупреждение' : 'Все пройдены';
const vb = hasErrors
? { bg: '#fff2f0', border: '#ffccc7', titleColor: '#cf1322', title: 'Найдены ошибки валидации', note: 'Исправьте отмеченные пункты в составе release, затем перезапустите проверку.', icon: err }
: S === 'incomplete'
? { bg: '#fffbe6', border: '#ffe58f', titleColor: '#d48806', title: 'Candidate неполный', note: 'Заполните обязательные разделы, чтобы перейти к проверке.', icon: warn }
: S === 'ready_test'
? { bg: '#e6f4ff', border: '#91caff', titleColor: '#0958d9', title: 'Готов к тестированию', note: 'Проверки пройдены. Запустите test chat перед публикацией.', icon: ok('#1677ff') }
: { bg: '#f6ffed', border: '#b7eb8f', titleColor: '#389e0d', title: 'Готов к публикации', note: 'Все проверки пройдены, протестировано в test chat. Можно публиковать.', icon: ok() };
const prompts = [
{ name: 'Системный prompt', ver: 'v5', changed: true, updated: 'сегодня' },
{ name: 'Qualification', ver: 'v4', changed: false, updated: '01 июня' },
{ name: 'Sales behavior', ver: 'v5', changed: true, updated: 'сегодня' },
{ name: 'Ограничения', ver: 'v4', changed: false, updated: '01 июня' },
];
const knowledge = [
{ title: 'Что входит в коробку FirePage', ver: 'v3' },
{ title: 'Условия годовой поддержки', ver: 'v2' },
{ title: 'Частые возражения и ответы', ver: 'v2' },
];
const changes = [
{ sign: '~', bg: '#fff7e6', color: '#d48806', text: 'Системный prompt: уточнён тон и правило передачи оператору.' },
{ sign: '~', bg: '#fff7e6', color: '#d48806', text: 'Sales behavior: добавлено оформление checkout сразу после подтверждения.' },
{ sign: '+', bg: '#f6ffed', color: '#389e0d', text: 'Знания: добавлен материал «Частые возражения и ответы».' },
];
const canPublish = S === 'ready_publish';
const publishBtn = canPublish
? 'display:flex;align-items:center;gap:7px;height:38px;padding:0 18px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer;box-shadow:0 1px 2px rgba(22,119,255,0.3);'
: 'display:flex;align-items:center;gap:7px;height:38px;padding:0 18px;border-radius:9px;border:none;background:#f0f0f0;color:#bfbfbf;font-size:13.5px;font-weight:600;cursor:not-allowed;';
const publishLabel = S === 'published' ? 'Опубликован' : 'Опубликовать';
const confirmChecked = this.state.confirmChecked;
const confirmBox = confirmChecked
? 'width:18px;height:18px;border-radius:5px;border:1.5px solid #1677ff;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;cursor:pointer;'
: 'width:18px;height:18px;border-radius:5px;border:1.5px solid #d9d9d9;background:#fff;display:flex;align-items:center;justify-content:center;flex:none;cursor:pointer;';
const confirmPublishBtn = confirmChecked
? 'display:flex;align-items:center;gap:7px;height:38px;padding:0 18px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13px;font-weight:600;cursor:pointer;'
: 'display:flex;align-items:center;gap:7px;height:38px;padding:0 18px;border-radius:9px;border:none;background:#f0f0f0;color:#bfbfbf;font-size:13px;font-weight:600;cursor:not-allowed;';
return {
st, vb, checks, checksColor, checksSummary, prompts, knowledge, changes,
publishBtn, publishLabel,
modalOpen: this.state.modalOpen, confirmChecked, confirmBox, confirmPublishBtn,
onPublish: () => { if (canPublish) this.setState({ modalOpen: true, confirmChecked: false }); },
onCancelPublish: () => this.setState({ modalOpen: false }),
onToggleConfirm: () => this.setState((s) => ({ confirmChecked: !s.confirmChecked })),
};
}
}
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,163 @@
# ADR-HUB-0013 — Дизайн-система внутреннего интерфейса Hub
## Статус
Принято.
## Дата
2026-06-16.
## Контекст
Внутренний интерфейс Hub должен обслуживать две роли — `OWNER` и `OPERATOR` — и поддерживать:
- командный обзор компании;
- управление отделом продаж;
- плотный realtime-inbox;
- продукты, предложения и цены;
- AI-агентов, знания, промпты и release-снимки;
- интеграции;
- Commerce Core;
- настройки и аудит.
Интерфейс содержит большое количество таблиц, фильтров, форм, статусов и сложных рабочих экранов. Нужна единая промышленная дизайн-система, пригодная для enterprise-приложения и AI-интерфейсов, без разработки базового UI-kit с нуля.
## Решение
Для внутреннего Hub используется:
- **Ant Design** — основная компонентная и UX-система;
- **Ant Design X** — паттерны и компоненты AI-диалогов;
- **Edevs Hub Theme** — собственный набор design tokens и локальных компонентов поверх Ant Design.
Конкретная версия библиотек фиксируется в техническом плане реализации. UI-спецификация привязана к публичным паттернам Ant Design, но не к конкретному номеру major-версии.
## Визуальное направление
- светлая тема;
- премиальный минимализм;
- высокая, но контролируемая информационная плотность;
- спокойная нейтральная основа;
- один основной акцентный цвет;
- цвет используется прежде всего для статусов и действий;
- минимум декоративных элементов;
- отсутствие градиентов, стекломорфизма, неоновых эффектов и визуального шума;
- desktop-first.
## Базовые принципы
### 1. Сначала состояние, затем действие
На управленческих экранах пользователь сначала видит состояние системы, затем доступные действия.
### 2. Один основной CTA на контекст
На странице или в отдельном рабочем блоке выделяется одно основное действие. Вторичные действия не конкурируют с ним визуально.
### 3. Стандартные паттерны не переизобретаются
Таблицы, формы, фильтры, подтверждения, статусы, drawer, modal и navigation должны следовать Ant Design, если нет зафиксированной причины создать локальный компонент.
### 4. Локальные компоненты Hub
Допускаются собственные составные компоненты:
- `DepartmentCard`;
- `AttentionStatus`;
- `ConversationInbox`;
- `ActorBadge`;
- `ChannelBadge`;
- `ProductAIReleaseCard`;
- `CommerceStatusTimeline`;
- `IntegrationHealthCard`;
- `MetricCard`;
- `KnowledgeDocumentEditor`.
Они строятся из Ant Design primitives и используют общие tokens.
### 5. Роль и контекст всегда видимы
Пользователь должен однозначно понимать:
- находится он на уровне всей компании или внутри отдела продаж;
- под какой ролью он работает;
- какой продукт, канал, диалог или заказ открыт.
## Типографика
Используется системный font stack Ant Design без обязательной внешней зависимости от загружаемого шрифта.
Иерархия:
- заголовок страницы;
- заголовок секции;
- основной текст;
- вспомогательный текст;
- метаданные;
- технические идентификаторы.
Технические идентификаторы, release ID, order ID и event ID могут отображаться моноширинным системным шрифтом.
## Цветовая семантика
Обязательные semantic tokens:
- `primary` — основное действие и активная навигация;
- `success` — подтверждённое успешное состояние;
- `warning` — требуется внимание;
- `error` — критическая ошибка или разрушительное действие;
- `info` — нейтральная служебная информация;
- `ai` — визуальное различение AI-участника;
- `human` — визуальное различение человека;
- `channel-*` — различение MAX, Telegram и Web Chat без превращения интерфейса в разноцветную мозаику.
Цвет не является единственным носителем статуса: используются текст, иконка и label.
## Плотность и размеры
- базовая плотность — compact enterprise;
- таблицы по умолчанию используют среднюю или компактную высоту строки;
- большие пустые поля и oversized-карточки запрещены;
- карточки метрик должны содержать только показатель, контекст, изменение и состояние;
- рабочие экраны используют доступную ширину viewport, а не узкую центральную колонку.
## Адаптивность
- основной макет проектируется для ширины `1440 px`;
- обязательная рабочая ширина внутреннего Hub — от `1024 px`;
- при ширине `1024–1279 px` sidebar может переходить в компактный режим;
- мобильный интерфейс внутреннего Hub не входит в первую итерацию;
- публичные Web Chat и checkout проектируются отдельно и не регулируются этим ADR.
## Доступность
- клавиатурная навигация для основных действий;
- видимый focus state;
- достаточный контраст;
- подписи для icon-only кнопок через tooltip и accessible label;
- ошибки формы отображаются рядом с полем и в итоговом сообщении;
- destructive-действия требуют явного подтверждения.
## Последствия
### Положительные
- единая UX-модель сложного корпоративного интерфейса;
- высокая скорость дизайна и реализации;
- предсказуемые таблицы, формы и навигация;
- готовая основа для AI-интерфейсов;
- минимизация собственного базового UI-kit.
### Ограничения
- дизайнер не должен просто воспроизводить стандартный demo-вид Ant Design;
- тема и локальные компоненты Hub обязательны;
- изменение стандартных паттернов должно быть обосновано;
- публичный Web Chat и checkout требуют отдельных UI-спецификаций.
## Официальные источники
- Ant Design: https://ant.design/
- Ant Design React: https://ant.design/docs/react/introduce/
- Ant Design X: https://x.ant.design/
File diff suppressed because it is too large. Load diff
+230
View File
@@ -0,0 +1,230 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1120px;">
<!-- ============ SIDEBAR (уровень компании) ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span><span style="font-size:11px;color:#8c8c8c;">Уровень компании</span></div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>Командный центр</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="Отделы.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>Отделы</a>
<a href="Сотрудники.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Сотрудники</a>
<a href="Продукты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>Продукты</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="AI-агенты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/></svg>AI</a>
<a href="Интеграции.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>Интеграции</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="Настройки.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><line x1="3" y1="18" x2="11" y2="18"/><circle cx="13" cy="18" r="2"/></svg>Настройки</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><a href="Настройки.dc.html" style="font-weight:500;color:#595959;text-decoration:none;" style-hover="color:#1677ff;">Настройки</a><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">Аудит</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1240px;margin:0 auto;">
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:18px;">
<div>
<h1 style="margin:0;font-size:24px;font-weight:700;letter-spacing:-0.02em;color:#1f1f1f;line-height:1.2;">Аудит</h1>
<p style="margin:6px 0 0;font-size:13.5px;color:#8c8c8c;">Журнал действий пользователей и системы · {{ shownCount }} записей</p>
</div>
<button style="display:flex;align-items:center;gap:7px;height:36px;padding:0 14px;border-radius:8px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>Экспорт</button>
</div>
<!-- FILTERS -->
<div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:11px 14px;margin-bottom:16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);">
<div style="display:flex;align-items:center;gap:8px;height:34px;padding:0 11px;border:1px solid #e8e8e8;border-radius:8px;background:#fafafa;width:240px;" style-focus="border-color:#1677ff;">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="#bfbfbf" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input value="{{ q }}" onInput="{{ onSearch }}" placeholder="Поиск по объекту или correlation ID…" style="border:none;outline:none;background:transparent;font-size:13px;color:#262626;width:100%;font-family:inherit;" />
</div>
<div style="position:relative;"><select onChange="{{ onPeriod }}" style="height:34px;padding:0 30px 0 12px;border:1px solid #e8e8e8;border-radius:8px;background:#fff;font-size:13px;color:#262626;font-family:inherit;cursor:pointer;appearance:none;-webkit-appearance:none;"><option value="today">Сегодня</option><option value="d7">7 дней</option><option value="d30">30 дней</option></select><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position:absolute;right:10px;top:10px;pointer-events:none;"><polyline points="6 9 12 15 18 9"/></svg></div>
<div style="position:relative;"><select onChange="{{ onActor }}" style="height:34px;padding:0 30px 0 12px;border:1px solid #e8e8e8;border-radius:8px;background:#fff;font-size:13px;color:#262626;font-family:inherit;cursor:pointer;appearance:none;-webkit-appearance:none;"><option value="all">Все акторы</option><option value="owner">Иван Петров</option><option value="operator">Анна Котова</option><option value="ai">AI-агент</option><option value="system">Система</option></select><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position:absolute;right:10px;top:10px;pointer-events:none;"><polyline points="6 9 12 15 18 9"/></svg></div>
<div style="position:relative;"><select onChange="{{ onAction }}" style="height:34px;padding:0 30px 0 12px;border:1px solid #e8e8e8;border-radius:8px;background:#fff;font-size:13px;color:#262626;font-family:inherit;cursor:pointer;appearance:none;-webkit-appearance:none;"><option value="all">Все действия</option><option value="create">Создание</option><option value="update">Изменение</option><option value="delete">Удаление</option><option value="auth">Вход / доступ</option></select><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position:absolute;right:10px;top:10px;pointer-events:none;"><polyline points="6 9 12 15 18 9"/></svg></div>
<div style="position:relative;"><select onChange="{{ onResult }}" style="height:34px;padding:0 30px 0 12px;border:1px solid #e8e8e8;border-radius:8px;background:#fff;font-size:13px;color:#262626;font-family:inherit;cursor:pointer;appearance:none;-webkit-appearance:none;"><option value="all">Любой результат</option><option value="ok">Успешно</option><option value="fail">Ошибка</option></select><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position:absolute;right:10px;top:10px;pointer-events:none;"><polyline points="6 9 12 15 18 9"/></svg></div>
<div style="flex:1;"></div>
<button onClick="{{ onReset }}" style="height:34px;padding:0 12px;border:none;background:transparent;color:#8c8c8c;font-size:13px;font-weight:500;cursor:pointer;border-radius:8px;" style-hover="color:#1677ff;background:#f5f5f5;">Сбросить</button>
</div>
<!-- TABLE -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="overflow-x:auto;">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:1100px;">
<thead><tr style="background:#fafafa;">
<th style="text-align:left;padding:11px 18px;font-size:11px;font-weight:600;color:#8c8c8c;letter-spacing:0.03em;border-bottom:1px solid #f0f0f0;white-space:nowrap;">ВРЕМЯ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">АКТОР</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ДЕЙСТВИЕ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ОБЪЕКТ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">РЕЗУЛЬТАТ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">CORRELATION ID</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ИСТОЧНИК</th>
<th style="width:44px;border-bottom:1px solid #f0f0f0;"></th>
</tr></thead>
<tbody>
<sc-for list="{{ rows }}" as="r" hint-placeholder-count="10">
<tr onClick="{{ r.onOpen }}" style="border-bottom:1px solid #f5f5f5;cursor:pointer;" style-hover="background:#fafbfc;">
<td style="padding:12px 18px;color:#595959;white-space:nowrap;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">{{ r.time }}</td>
<td style="padding:12px 12px;"><span style="display:inline-flex;align-items:center;gap:7px;"><span style="width:22px;height:22px;border-radius:50%;background:{{ r.actorBg }};color:{{ r.actorColor }};display:flex;align-items:center;justify-content:center;font-size:9.5px;font-weight:700;flex:none;">{{ r.actorMark }}</span><span style="font-size:12.5px;color:#262626;font-weight:500;">{{ r.actor }}</span></span></td>
<td style="padding:12px 12px;color:#262626;">{{ r.action }}</td>
<td style="padding:12px 12px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">{{ r.object }}</td>
<td style="padding:12px 12px;"><span style="display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:500;color:{{ r.resColor }};"><span style="width:6px;height:6px;border-radius:50%;background:{{ r.resDot }};"></span>{{ r.result }}</span></td>
<td style="padding:12px 12px;color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:11.5px;">{{ r.cid }}</td>
<td style="padding:12px 12px;color:#8c8c8c;font-size:12px;">{{ r.source }}</td>
<td style="padding:12px 12px;text-align:center;color:#bfbfbf;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></td>
</tr>
</sc-for>
</tbody>
</table>
</div>
<sc-if value="{{ isEmpty }}" hint-placeholder-val="{{ false }}">
<div style="padding:48px 20px;text-align:center;"><div style="font-size:14px;font-weight:600;color:#595959;">Записи не найдены</div><div style="font-size:12.5px;color:#bfbfbf;margin-top:4px;">Измените фильтры или период.</div></div>
</sc-if>
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 18px;border-top:1px solid #f5f5f5;">
<div style="font-size:12.5px;color:#8c8c8c;">Показано {{ shownCount }} из 1 204</div>
<div style="font-size:12.5px;color:#bfbfbf;">Журнал доступен только для чтения</div>
</div>
</div>
</div>
</main>
</div>
<!-- DETAIL DRAWER -->
<sc-if value="{{ drawerOpen }}" hint-placeholder-val="{{ false }}">
<div onClick="{{ onCloseDrawer }}" style="position:fixed;inset:0;z-index:40;background:rgba(0,0,0,0.35);"></div>
<div style="position:fixed;top:0;right:0;bottom:0;z-index:50;width:460px;max-width:100%;background:#fff;box-shadow:-8px 0 30px rgba(0,0,0,0.15);display:flex;flex-direction:column;">
<div style="flex:none;padding:18px 22px;border-bottom:1px solid #f0f0f0;display:flex;align-items:flex-start;justify-content:space-between;gap:16px;">
<div><div style="font-size:16px;font-weight:700;color:#1f1f1f;">{{ d.action }}</div><div style="font-size:12px;color:#8c8c8c;margin-top:3px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ d.time }} · {{ d.cid }}</div></div>
<button onClick="{{ onCloseDrawer }}" style="width:32px;height:32px;border-radius:8px;border:none;background:#f5f5f5;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;flex:none;" style-hover="background:#e8e8e8;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
</div>
<div style="flex:1;overflow-y:auto;padding:20px 22px;">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px 18px;margin-bottom:20px;">
<div><div style="font-size:11px;color:#8c8c8c;">Актор</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;">{{ d.actor }}</div></div>
<div><div style="font-size:11px;color:#8c8c8c;">Результат</div><div style="font-size:13px;font-weight:600;color:{{ d.resColor }};margin-top:3px;">{{ d.result }}</div></div>
<div><div style="font-size:11px;color:#8c8c8c;">Объект</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ d.object }}</div></div>
<div><div style="font-size:11px;color:#8c8c8c;">Источник / IP</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;">{{ d.source }}</div></div>
</div>
<div style="font-size:11px;font-weight:600;letter-spacing:0.05em;color:#bfbfbf;margin-bottom:10px;">СТРУКТУРИРОВАННЫЕ ИЗМЕНЕНИЯ</div>
<div style="border:1px solid #f0f0f0;border-radius:10px;overflow:hidden;margin-bottom:16px;">
<sc-for list="{{ d.changes }}" as="c" hint-placeholder-count="3">
<div style="padding:11px 14px;border-bottom:1px solid #f5f5f5;">
<div style="font-size:12px;color:#595959;font-weight:500;margin-bottom:5px;">{{ c.field }}</div>
<div style="display:flex;align-items:center;gap:9px;">
<span style="flex:1;font-size:12px;color:#cf1322;background:#fff2f0;border-radius:6px;padding:4px 9px;font-family:'SF Mono',ui-monospace,Menlo,monospace;text-decoration:line-through;text-decoration-color:#ffa39e;">{{ c.from }}</span>
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#bfbfbf" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex:none;"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
<span style="flex:1;font-size:12px;color:#389e0d;background:#f6ffed;border-radius:6px;padding:4px 9px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ c.to }}</span>
</div>
</div>
</sc-for>
</div>
<div style="display:flex;align-items:flex-start;gap:10px;padding:12px 14px;background:#fafafa;border:1px solid #f0f0f0;border-radius:9px;">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#8c8c8c" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" style="flex:none;margin-top:1px;"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
<span style="font-size:12px;color:#8c8c8c;line-height:1.5;">Секреты и чувствительные payload не отображаются в журнале аудита.</span>
</div>
</div>
</div>
</sc-if>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 }
}">
class Component extends DCLogic {
state = { q: '', period: 'd7', actor: 'all', action: 'all', result: 'all', openId: null };
renderVals() {
const A = {
owner: { actor: 'Иван Петров', actorMark: 'ИП', actorBg: '#1677ff', actorColor: '#fff', key: 'owner' },
operator: { actor: 'Анна Котова', actorMark: 'АК', actorBg: '#9254de', actorColor: '#fff', key: 'operator' },
ai: { actor: 'AI-агент', actorMark: 'AI', actorBg: '#f9f0ff', actorColor: '#722ed1', key: 'ai' },
system: { actor: 'Система', actorMark: 'СС', actorBg: '#f0f0f0', actorColor: '#8c8c8c', key: 'system' },
};
const okR = { result: 'Успешно', resColor: '#389e0d', resDot: '#52c41a' };
const failR = { result: 'Ошибка', resColor: '#cf1322', resDot: '#ff4d4f' };
const data = [
{ id: 1, t: '17 июня 14:32', a: 'owner', actType: 'update', action: 'Публикация AI release', object: 'REL-FP-v5', res: okR, cid: 'corr_9f2a31', source: 'Web · 5.18.x.x', changes: [{ field: 'release.status', from: 'candidate', to: 'published' }, { field: 'agent.activeRelease', from: 'REL-FP-v4', to: 'REL-FP-v5' }] },
{ id: 2, t: '17 июня 14:02', a: 'ai', actType: 'create', action: 'Создан заказ', object: 'ORD-10519', res: okR, cid: 'corr_9f2a18', source: 'MAX · agent', changes: [{ field: 'order.status', from: '—', to: 'created' }, { field: 'order.amount', from: '—', to: '2490' }] },
{ id: 3, t: '17 июня 13:40', a: 'operator', actType: 'update', action: 'Изменён контакт', object: 'CUS-4702', res: okR, cid: 'corr_9f2a09', source: 'Web · 5.18.x.x', changes: [{ field: 'contact.email', from: 'e.k@old.ru', to: 'e.kuznetsova@corp.ru' }] },
{ id: 4, t: '17 июня 11:08', a: 'system', actType: 'update', action: 'Webhook timeout', object: 'PAY-88224', res: failR, cid: 'corr_9f29f4', source: 'Точка · webhook', changes: [{ field: 'payment.reconciled', from: 'true', to: 'false' }] },
{ id: 5, t: '17 июня 09:14', a: 'owner', actType: 'update', action: 'Возврат платежа', object: 'REF-3120', res: okR, cid: 'corr_9f29c1', source: 'Web · 5.18.x.x', changes: [{ field: 'refund.status', from: 'requested', to: 'completed' }, { field: 'refund.amount', from: '—', to: '990' }] },
{ id: 6, t: '17 июня 09:02', a: 'operator', actType: 'auth', action: 'Вход в систему', object: 'a.kotova@edevs.tech', res: okR, cid: 'corr_9f29a0', source: 'Web · 5.18.x.x · Chrome' },
{ id: 7, t: '16 июня 20:02', a: 'owner', actType: 'update', action: 'Изменены настройки безопасности', object: 'SET-security', res: okR, cid: 'corr_9f2955', source: 'Web · 5.18.x.x', changes: [{ field: 'password.minLength', from: '8', to: '10' }, { field: 'session.duration', from: '4h', to: '8h' }] },
{ id: 8, t: '16 июня 18:25', a: 'ai', actType: 'create', action: 'Передача оператору', object: 'DLG-77310', res: okR, cid: 'corr_9f2930', source: 'Telegram · agent' },
{ id: 9, t: '16 июня 16:51', a: 'system', actType: 'auth', action: 'Неудачная попытка входа', object: 'unknown@mail.ru', res: failR, cid: 'corr_9f2901', source: 'Web · 91.x.x.x' },
{ id: 10, t: '16 июня 14:20', a: 'operator', actType: 'create', action: 'Объединение контактов', object: 'CUS-4702 ← CUS-4810', res: okR, cid: 'corr_9f28e2', source: 'Web · 5.18.x.x', changes: [{ field: 'contact.merged', from: 'CUS-4810', to: 'CUS-4702' }] },
{ id: 11, t: '16 июня 11:00', a: 'owner', actType: 'delete', action: 'Деактивация Offer', object: 'OFR-FX-OLD', res: okR, cid: 'corr_9f28b0', source: 'Web · 5.18.x.x', changes: [{ field: 'offer.status', from: 'active', to: 'disabled' }] },
{ id: 12, t: '16 июня 08:30', a: 'system', actType: 'update', action: 'Reconciliation завершён', object: 'recon-2026-06-16', res: okR, cid: 'corr_9f2880', source: 'Точка · cron' },
];
const { q, actor, action, result, openId } = this.state;
const ql = q.trim().toLowerCase();
const rowsRaw = data.filter((d) =>
(!ql || d.object.toLowerCase().includes(ql) || d.cid.toLowerCase().includes(ql)) &&
(actor === 'all' || d.a === actor) &&
(action === 'all' || d.actType === action) &&
(result === 'all' || (result === 'ok' ? d.res === okR : d.res === failR)));
const rows = rowsRaw.map((d) => ({
time: d.t, action: d.action, object: d.object, cid: d.cid, source: d.source,
...A[d.a], ...d.res,
onOpen: () => this.setState({ openId: d.id }),
}));
const open = data.find((d) => d.id === openId);
const d = open ? {
action: open.action, time: open.t, cid: open.cid, object: open.object, source: open.source,
actor: A[open.a].actor, result: open.res.result, resColor: open.res.resColor,
changes: open.changes || [],
} : { changes: [] };
return {
rows, isEmpty: rows.length === 0, shownCount: String(rows.length),
q, drawerOpen: !!open, d,
onSearch: (e) => this.setState({ q: e.target.value }),
onPeriod: (e) => this.setState({ period: e.target.value }),
onActor: (e) => this.setState({ actor: e.target.value }),
onAction: (e) => this.setState({ action: e.target.value }),
onResult: (e) => this.setState({ result: e.target.value }),
onReset: () => this.setState({ q: '', actor: 'all', action: 'all', result: 'all' }),
onCloseDrawer: () => this.setState({ openId: null }),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,153 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1080px;">
<!-- ============ SIDEBAR (уровень компании) ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span><span style="font-size:11px;color:#8c8c8c;">Уровень компании</span></div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>Командный центр</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="Отделы.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>Отделы</a>
<a href="Сотрудники.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Сотрудники</a>
<a href="Продукты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>Продукты</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="AI-агенты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/><path d="M2 13.5h2M20 13.5h2"/></svg>AI</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>Интеграции</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><line x1="3" y1="18" x2="11" y2="18"/><circle cx="13" cy="18" r="2"/></svg>Настройки</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">Интеграции</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1080px;margin:0 auto;">
<!-- PAGE HEADER -->
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:18px;">
<div>
<h1 style="margin:0;font-size:24px;font-weight:700;letter-spacing:-0.02em;color:#1f1f1f;line-height:1.2;">Интеграции</h1>
<p style="margin:6px 0 0;font-size:13.5px;color:#8c8c8c;">Внешние сервисы платформы · <span style="color:#389e0d;font-weight:500;">{{ okCount }} в норме</span>, {{ issueCount }} требуют внимания</p>
</div>
<button style="display:flex;align-items:center;gap:7px;height:36px;padding:0 14px;border-radius:8px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/><path d="M3 21v-5h5"/></svg>Проверить все</button>
</div>
<!-- GROUPS -->
<sc-for list="{{ groups }}" as="g" hint-placeholder-count="4">
<div style="margin-bottom:22px;">
<div style="display:flex;align-items:center;gap:9px;margin-bottom:11px;">
<h2 style="margin:0;font-size:13px;font-weight:600;color:#595959;letter-spacing:0.02em;">{{ g.title }}</h2>
<span style="font-size:12px;color:#bfbfbf;">{{ g.note }}</span>
</div>
<div style="display:flex;flex-direction:column;gap:12px;">
<sc-for list="{{ g.items }}" as="i" hint-placeholder-count="2">
<div style="display:flex;align-items:center;gap:16px;background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 2px rgba(0,0,0,0.03);padding:16px 18px;">
<div style="width:44px;height:44px;border-radius:11px;background:{{ i.iconBg }};display:flex;align-items:center;justify-content:center;flex:none;font-size:16px;font-weight:700;color:{{ i.iconColor }};">{{ i.mark }}</div>
<div style="flex:1;min-width:0;">
<div style="display:flex;align-items:center;gap:10px;">
<span style="font-size:14.5px;font-weight:700;color:#1f1f1f;">{{ i.name }}</span>
<span style="display:inline-flex;align-items:center;gap:6px;padding:2px 10px;border-radius:14px;background:{{ i.stBg }};border:1px solid {{ i.stBorder }};"><span style="width:6px;height:6px;border-radius:50%;background:{{ i.stDot }};"></span><span style="font-size:11.5px;font-weight:600;color:{{ i.stColor }};">{{ i.stLabel }}</span></span>
</div>
<div style="font-size:12.5px;color:#8c8c8c;margin-top:4px;">{{ i.desc }}</div>
</div>
<div style="text-align:right;flex:none;margin-right:4px;">
<div style="font-size:11.5px;color:#bfbfbf;">Последняя активность</div>
<div style="font-size:12.5px;color:{{ i.activityColor }};font-weight:500;margin-top:2px;">{{ i.activity }}</div>
</div>
<a href="#" style="{{ i.btnStyle }}">{{ i.btnLabel }}<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></a>
</div>
</sc-for>
</div>
</div>
</sc-for>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 900 }
}">
class Component extends DCLogic {
renderVals() {
const ST = {
connected: { stLabel: 'Подключено', stColor: '#389e0d', stBg: '#f6ffed', stBorder: '#b7eb8f', stDot: '#52c41a' },
degraded: { stLabel: 'Degraded', stColor: '#d48806', stBg: '#fffbe6', stBorder: '#ffe58f', stDot: '#faad14' },
error: { stLabel: 'Ошибка', stColor: '#cf1322', stBg: '#fff2f0', stBorder: '#ffccc7', stDot: '#ff4d4f' },
notset: { stLabel: 'Не настроено', stColor: '#8c8c8c', stBg: '#f5f5f5', stBorder: '#e8e8e8', stDot: '#bfbfbf' },
disabled: { stLabel: 'Отключено', stColor: '#8c8c8c', stBg: '#f5f5f5', stBorder: '#e8e8e8', stDot: '#d9d9d9' },
};
const openBtn = 'display:inline-flex;align-items:center;gap:6px;height:36px;padding:0 15px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;text-decoration:none;flex:none;';
const setupBtn = 'display:inline-flex;align-items:center;gap:6px;height:36px;padding:0 15px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13px;font-weight:600;cursor:pointer;text-decoration:none;flex:none;box-shadow:0 1px 2px rgba(22,119,255,0.3);';
const mk = (o) => {
const st = ST[o.state];
const isNotSet = o.state === 'notset';
return {
name: o.name, mark: o.mark, iconBg: o.iconBg, iconColor: o.iconColor, desc: o.desc,
...st,
activity: o.activity, activityColor: o.state === 'error' ? '#cf1322' : o.state === 'degraded' ? '#d48806' : '#595959',
btnLabel: isNotSet ? 'Настроить' : 'Открыть',
btnStyle: isNotSet ? setupBtn : openBtn,
};
};
const groups = [
{ title: 'AI-провайдер', note: 'модели для агентов', items: [
mk({ name: 'OpenRouter', mark: 'OR', iconBg: '#f9f0ff', iconColor: '#722ed1', state: 'connected', desc: 'gpt-4o-mini по умолчанию · 6 разрешённых моделей', activity: '12 сек назад' }),
]},
{ title: 'Платежи', note: 'приём оплаты и фискализация', items: [
mk({ name: 'Точка', mark: 'Т', iconBg: '#e6f4ff', iconColor: '#0958d9', state: 'degraded', desc: 'Merchant · JWT активен · webhook отвечает с задержкой', activity: '4 мин назад · медленно' }),
]},
{ title: 'Каналы', note: 'источники диалогов', items: [
mk({ name: 'MAX', mark: 'M', iconBg: '#f2f0ff', iconColor: '#6b5be0', state: 'connected', desc: 'FirePage, Foxray · вебхук активен', activity: '8 сек назад' }),
mk({ name: 'Telegram', mark: 'TG', iconBg: '#eaf6fd', iconColor: '#2f8fd0', state: 'connected', desc: 'FirePage, Foxray · бот @edevs_sales', activity: '20 сек назад' }),
mk({ name: 'Web Chat', mark: 'W', iconBg: '#e8f7f4', iconColor: '#0f9b8e', state: 'connected', desc: 'Виджет на сайтах продуктов', activity: '1 мин назад' }),
]},
{ title: 'Исполнение', note: 'выдача продуктов', items: [
mk({ name: 'Fulfillment · FirePage', mark: 'FP', iconBg: '#e6f4ff', iconColor: '#1677ff', state: 'connected', desc: 'Сборка и выдача нишевых сайтов', activity: '14 мин назад' }),
mk({ name: 'Fulfillment · Foxray', mark: 'FX', iconBg: '#f9f0ff', iconColor: '#722ed1', state: 'connected', desc: 'Выдача доступа к SaaS', activity: '6 мин назад' }),
mk({ name: 'Рассылка чеков · ОФД', mark: 'OФ', iconBg: '#f5f5f5', iconColor: '#8c8c8c', state: 'notset', desc: 'Резервный канал доставки чеков на email', activity: '—' }),
]},
];
return { groups, okCount: '7', issueCount: '1' };
}
}
</script>
</body>
</html>
@@ -0,0 +1,265 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1180px;">
<!-- ============ SIDEBAR (уровень компании) ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span><span style="font-size:11px;color:#8c8c8c;">Уровень компании</span></div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>Командный центр</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="Отделы.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>Отделы</a>
<a href="Сотрудники.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Сотрудники</a>
<a href="Продукты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>Продукты</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="AI-агенты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/><path d="M2 13.5h2M20 13.5h2"/></svg>AI</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>Интеграции</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><line x1="3" y1="18" x2="11" y2="18"/><circle cx="13" cy="18" r="2"/></svg>Настройки</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><span style="font-weight:500;color:#595959;">AI</span><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">Использование AI</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<!-- AI SUBNAV -->
<div style="flex:none;background:#fff;border-bottom:1px solid #f0f0f0;padding:0 28px;display:flex;align-items:center;gap:2px;">
<a href="AI-агенты.dc.html" style="padding:13px 14px;font-size:13.5px;font-weight:500;color:#595959;text-decoration:none;border-bottom:2px solid transparent;margin-bottom:-1px;" style-hover="color:#262626;">AI-агенты</a>
<a href="Тестовый чат.dc.html" style="padding:13px 14px;font-size:13.5px;font-weight:500;color:#595959;text-decoration:none;border-bottom:2px solid transparent;margin-bottom:-1px;" style-hover="color:#262626;">Тестовый чат</a>
<a href="#" style="padding:13px 14px;font-size:13.5px;font-weight:600;color:#1677ff;text-decoration:none;border-bottom:2px solid #1677ff;margin-bottom:-1px;">Использование AI</a>
</div>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1280px;margin:0 auto;">
<!-- PAGE HEADER -->
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:18px;">
<div>
<h1 style="margin:0;font-size:24px;font-weight:700;letter-spacing:-0.02em;color:#1f1f1f;line-height:1.2;">Использование AI</h1>
<p style="margin:6px 0 0;font-size:13.5px;color:#8c8c8c;">Стоимость, токены и эффективность агентов · {{ periodLabel }}</p>
</div>
<div style="display:flex;align-items:center;gap:3px;padding:3px;border-radius:9px;background:#f0f2f5;flex:none;">
<button onClick="{{ onToday }}" style="{{ tabToday }}">Сегодня</button>
<button onClick="{{ on7 }}" style="{{ tab7 }}">7 дней</button>
<button onClick="{{ on30 }}" style="{{ tab30 }}">30 дней</button>
</div>
</div>
<!-- KPI GRID -->
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:14px;">
<sc-for list="{{ kpis }}" as="k" hint-placeholder-count="8">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:15px 16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);">
<div style="font-size:12px;color:#8c8c8c;">{{ k.label }}</div>
<div style="font-size:23px;font-weight:700;color:{{ k.color }};line-height:1;margin-top:9px;">{{ k.value }}</div>
<div style="font-size:11.5px;color:#bfbfbf;margin-top:7px;">{{ k.sub }}</div>
</div>
</sc-for>
</div>
<!-- BUDGET BAR -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 20px;margin-bottom:18px;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;">
<span style="font-size:13.5px;font-weight:600;color:#1f1f1f;">Приближение к бюджету · {{ periodLabel }}</span>
<span style="font-size:13px;color:#595959;"><b style="color:#262626;">{{ budgetSpent }}</b> из {{ budgetTotal }} · <span style="color:{{ budgetColor }};font-weight:600;">{{ budgetPct }}%</span></span>
</div>
<div style="height:9px;border-radius:999px;background:#f0f0f0;overflow:hidden;"><div style="height:9px;border-radius:999px;background:{{ budgetColor }};width:{{ budgetPct }}%;"></div></div>
</div>
<!-- CHART (только временная динамика) -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px 14px;margin-bottom:18px;">
<div style="display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:6px;">
<div><h3 style="margin:0;font-size:15px;font-weight:700;color:#1f1f1f;">Динамика стоимости AI</h3><div style="font-size:12px;color:#bfbfbf;margin-top:4px;">{{ periodLabel }} · {{ chartTotal }} суммарно</div></div>
<div style="display:flex;align-items:center;gap:6px;font-size:12px;color:#8c8c8c;"><span style="width:9px;height:9px;border-radius:2px;background:#722ed1;"></span>Стоимость</div>
</div>
<div>
<svg viewBox="0 0 1000 240" preserveAspectRatio="none" style="width:100%;height:210px;display:block;">
<defs><linearGradient id="aiFill" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#722ed1" stop-opacity="0.16"/><stop offset="1" stop-color="#722ed1" stop-opacity="0"/></linearGradient></defs>
<line x1="10" x2="990" y1="{{ g1 }}" y2="{{ g1 }}" stroke="#f2f2f2" stroke-width="1" vector-effect="non-scaling-stroke"/>
<line x1="10" x2="990" y1="{{ g2 }}" y2="{{ g2 }}" stroke="#f2f2f2" stroke-width="1" vector-effect="non-scaling-stroke"/>
<line x1="10" x2="990" y1="{{ g3 }}" y2="{{ g3 }}" stroke="#f2f2f2" stroke-width="1" vector-effect="non-scaling-stroke"/>
<path d="{{ areaPath }}" fill="url(#aiFill)"/>
<path d="{{ linePath }}" fill="none" stroke="#722ed1" stroke-width="2.5" vector-effect="non-scaling-stroke" stroke-linejoin="round" stroke-linecap="round"/>
<circle cx="{{ lastX }}" cy="{{ lastY }}" r="4.5" fill="#722ed1" stroke="#fff" stroke-width="2.5" vector-effect="non-scaling-stroke"/>
</svg>
<div style="display:flex;justify-content:space-between;margin-top:6px;padding:0 2px;">
<sc-for list="{{ xLabels }}" as="x" hint-placeholder-count="7"><span style="font-size:11px;color:#bfbfbf;">{{ x.label }}</span></sc-for>
</div>
</div>
</div>
<!-- BREAKDOWN TABLES -->
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;">
<!-- по продукту -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:14px 18px 11px;border-bottom:1px solid #f5f5f5;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">По продукту</h3></div>
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;"><th style="text-align:left;padding:9px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">ПРОДУКТ</th><th style="text-align:right;padding:9px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">ДИАЛОГИ</th><th style="text-align:right;padding:9px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">СТОИМОСТЬ</th><th style="text-align:right;padding:9px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">/ ДИАЛОГ</th></tr></thead>
<tbody>
<sc-for list="{{ byProduct }}" as="r" hint-placeholder-count="2">
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:11px 18px;"><span style="display:inline-flex;align-items:center;gap:7px;font-weight:500;color:#262626;"><span style="width:8px;height:8px;border-radius:2px;background:{{ r.dot }};"></span>{{ r.name }}</span></td><td style="padding:11px 12px;text-align:right;color:#595959;">{{ r.dialogs }}</td><td style="padding:11px 12px;text-align:right;font-weight:600;color:#262626;">{{ r.cost }}</td><td style="padding:11px 18px;text-align:right;color:#595959;">{{ r.per }}</td></tr>
</sc-for>
</tbody>
</table>
</div>
<!-- по модели -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:14px 18px 11px;border-bottom:1px solid #f5f5f5;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">По модели</h3></div>
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;"><th style="text-align:left;padding:9px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">МОДЕЛЬ</th><th style="text-align:right;padding:9px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">TOKENS IN</th><th style="text-align:right;padding:9px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">TOKENS OUT</th><th style="text-align:right;padding:9px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">СТОИМОСТЬ</th></tr></thead>
<tbody>
<sc-for list="{{ byModel }}" as="r" hint-placeholder-count="2">
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:11px 18px;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;color:#262626;">{{ r.name }}</td><td style="padding:11px 12px;text-align:right;color:#595959;">{{ r.tin }}</td><td style="padding:11px 12px;text-align:right;color:#595959;">{{ r.tout }}</td><td style="padding:11px 18px;text-align:right;font-weight:600;color:#262626;">{{ r.cost }}</td></tr>
</sc-for>
</tbody>
</table>
</div>
<!-- по агенту -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:14px 18px 11px;border-bottom:1px solid #f5f5f5;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">По агенту</h3></div>
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;"><th style="text-align:left;padding:9px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">АГЕНТ</th><th style="text-align:right;padding:9px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">ДИАЛОГИ</th><th style="text-align:right;padding:9px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">HANDOFF</th><th style="text-align:right;padding:9px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">/ ПРОДАЖА</th></tr></thead>
<tbody>
<sc-for list="{{ byAgent }}" as="r" hint-placeholder-count="2">
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:11px 18px;font-weight:500;color:#262626;">{{ r.name }}</td><td style="padding:11px 12px;text-align:right;color:#595959;">{{ r.dialogs }}</td><td style="padding:11px 12px;text-align:right;color:#595959;">{{ r.handoff }}</td><td style="padding:11px 18px;text-align:right;font-weight:600;color:#262626;">{{ r.perSale }}</td></tr>
</sc-for>
</tbody>
</table>
</div>
<!-- по каналу -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:14px 18px 11px;border-bottom:1px solid #f5f5f5;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">По каналу</h3></div>
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;"><th style="text-align:left;padding:9px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">КАНАЛ</th><th style="text-align:right;padding:9px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">ДИАЛОГИ</th><th style="text-align:right;padding:9px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">СТОИМОСТЬ</th><th style="text-align:right;padding:9px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">ДОЛЯ</th></tr></thead>
<tbody>
<sc-for list="{{ byChannel }}" as="r" hint-placeholder-count="3">
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:11px 18px;"><span style="display:inline-flex;align-items:center;gap:7px;font-weight:500;color:#262626;"><span style="width:7px;height:7px;border-radius:50%;background:{{ r.dot }};"></span>{{ r.name }}</span></td><td style="padding:11px 12px;text-align:right;color:#595959;">{{ r.dialogs }}</td><td style="padding:11px 12px;text-align:right;font-weight:600;color:#262626;">{{ r.cost }}</td><td style="padding:11px 18px;text-align:right;color:#595959;">{{ r.share }}</td></tr>
</sc-for>
</tbody>
</table>
</div>
</div>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 900 }
}">
class Component extends DCLogic {
state = { period: 'd30' };
renderVals() {
const period = this.state.period;
const periodLabel = { today: 'Сегодня', d7: '7 дней', d30: '30 дней' }[period];
const f = period === 'd7' ? 7 : period === 'd30' ? 30 : 1;
const fmt = (n) => '₽' + Math.round(n).toLocaleString('ru-RU').replace(/\u00a0/g, ' ');
const base = { dialogs: 42, cost: 1240, tin: 412000, tout: 156000, sales: 18 };
const dialogs = base.dialogs * f, cost = base.cost * f, sales = base.sales * f;
const tin = base.tin * f, tout = base.tout * f;
const kfmt = (n) => n >= 1e6 ? (n / 1e6).toFixed(1).replace('.', ',') + 'М' : Math.round(n / 1e3) + 'K';
const kpis = [
{ label: 'Стоимость за период', value: fmt(cost), color: '#1f1f1f', sub: periodLabel },
{ label: 'Tokens input', value: kfmt(tin), color: '#1f1f1f', sub: 'входящие' },
{ label: 'Tokens output', value: kfmt(tout), color: '#1f1f1f', sub: 'исходящие' },
{ label: 'Диалоги', value: dialogs.toLocaleString('ru-RU').replace(/\u00a0/g, ' '), color: '#1f1f1f', sub: 'обработано AI' },
{ label: 'Стоимость диалога', value: fmt(cost / dialogs), color: '#1f1f1f', sub: 'в среднем' },
{ label: 'Стоимость продажи', value: fmt(cost / sales), color: '#1f1f1f', sub: 'AI-атрибуция' },
{ label: 'Handoff rate', value: '17%', color: '#d48806', sub: 'передано оператору' },
{ label: 'Ошибки', value: '0,3%', color: '#389e0d', sub: 'от вызовов модели' },
];
const budgetTotalN = 5000 * f, budgetSpentN = cost;
const budgetPct = Math.round((budgetSpentN / budgetTotalN) * 100);
const budgetColor = budgetPct >= 85 ? '#ff4d4f' : budgetPct >= 70 ? '#faad14' : '#722ed1';
// chart
const series = {
today: { vals: [60, 110, 90, 180, 150, 220, 170, 240, 280, 260], labels: ['09', '10', '11', '12', '13', '14', '15', '16', '17', '18'] },
d7: { vals: [980, 1120, 1040, 1340, 1180, 1420, 1380], labels: ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'] },
d30: { vals: [820, 900, 880, 1020, 980, 1150, 1240, 1180, 1320, 1280, 1390, 1340, 1480, 1420, 1560], labels: ['1', '5', '10', '15', '20', '25', '30'] },
}[period];
const W = 1000, H = 240, pl = 10, pr = 10, pt = 16, pb = 24;
const iw = W - pl - pr, ih = H - pt - pb, n = series.vals.length;
const max = Math.max(...series.vals) * 1.12;
const xs = (i) => pl + iw * (n === 1 ? 0 : i / (n - 1));
const ys = (v) => pt + ih * (1 - v / max);
const pts = series.vals.map((v, i) => ({ x: xs(i), y: ys(v) }));
const linePath = 'M' + pts.map((p) => p.x.toFixed(1) + ',' + p.y.toFixed(1)).join(' L');
const areaPath = linePath + ` L${xs(n - 1).toFixed(1)},${(pt + ih).toFixed(1)} L${pl.toFixed(1)},${(pt + ih).toFixed(1)} Z`;
const last = pts[n - 1];
const xLabels = series.labels.map((l) => ({ label: l }));
const byProduct = [
{ name: 'FirePage', dot: '#1677ff', dialogs: String(28 * f), cost: fmt(720 * f), per: fmt(720 / 28) },
{ name: 'Foxray', dot: '#722ed1', dialogs: String(14 * f), cost: fmt(520 * f), per: fmt(520 / 14) },
];
const byModel = [
{ name: 'gpt-4o-mini', tin: kfmt(tin), tout: kfmt(tout), cost: fmt(cost) },
];
const byAgent = [
{ name: 'FirePage Sales', dialogs: String(28 * f), handoff: '15%', perSale: fmt(64) },
{ name: 'Foxray Sales', dialogs: String(14 * f), handoff: '21%', perSale: fmt(74) },
];
const byChannel = [
{ name: 'MAX', dot: '#6b5be0', dialogs: String(21 * f), cost: fmt(610 * f), share: '49%' },
{ name: 'Telegram', dot: '#2f8fd0', dialogs: String(13 * f), cost: fmt(410 * f), share: '33%' },
{ name: 'Web Chat', dot: '#0f9b8e', dialogs: String(8 * f), cost: fmt(220 * f), share: '18%' },
];
const tBase = 'padding:6px 15px;border:none;border-radius:7px;font-size:13px;font-weight:500;cursor:pointer;background:transparent;color:#595959;';
const tAct = 'padding:6px 15px;border:none;border-radius:7px;font-size:13px;font-weight:600;cursor:pointer;background:#ffffff;color:#1f1f1f;box-shadow:0 1px 2px rgba(0,0,0,0.1);';
const setP = (p) => this.setState({ period: p });
return {
periodLabel, kpis,
budgetSpent: fmt(budgetSpentN), budgetTotal: fmt(budgetTotalN), budgetPct, budgetColor,
chartTotal: fmt(cost), areaPath, linePath, lastX: last.x.toFixed(1), lastY: last.y.toFixed(1),
g1: (pt + ih * 0.25).toFixed(1), g2: (pt + ih * 0.55).toFixed(1), g3: (pt + ih * 0.85).toFixed(1),
xLabels, byProduct, byModel, byAgent, byChannel,
tabToday: period === 'today' ? tAct : tBase, tab7: period === 'd7' ? tAct : tBase, tab30: period === 'd30' ? tAct : tBase,
onToday: () => setP('today'), on7: () => setP('d7'), on30: () => setP('d30'),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,291 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1080px;">
<!-- ============ SIDEBAR (уровень компании) ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span><span style="font-size:11px;color:#8c8c8c;">Уровень компании</span></div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>Командный центр</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="Отделы.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>Отделы</a>
<a href="Сотрудники.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Сотрудники</a>
<a href="Продукты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>Продукты</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="AI-агенты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/><path d="M2 13.5h2M20 13.5h2"/></svg>AI</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>Интеграции</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><line x1="3" y1="18" x2="11" y2="18"/><circle cx="13" cy="18" r="2"/></svg>Настройки</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><span style="font-weight:500;color:#595959;">AI</span><span style="color:#d9d9d9;">/</span><a href="AI-агенты.dc.html" style="font-weight:500;color:#595959;text-decoration:none;" style-hover="color:#1677ff;">AI-агенты</a><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">FirePage Sales</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1080px;margin:0 auto;">
<!-- HEADER CARD -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:20px 22px;margin-bottom:16px;">
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:20px;">
<div style="display:flex;align-items:flex-start;gap:16px;min-width:0;">
<div style="width:52px;height:52px;border-radius:13px;background:#f9f0ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="27" height="27" fill="none" stroke="#722ed1" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/></svg></div>
<div style="min-width:0;">
<div style="display:flex;align-items:center;gap:11px;flex-wrap:wrap;">
<h1 style="margin:0;font-size:21px;font-weight:700;letter-spacing:-0.01em;color:#1f1f1f;">FirePage Sales</h1>
<span style="display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:14px;background:{{ rt.bg }};border:1px solid {{ rt.border }};font-size:11.5px;font-weight:600;color:{{ rt.color }};"><span style="width:6px;height:6px;border-radius:50%;background:{{ rt.dot }};"></span>{{ rt.label }}</span>
</div>
<div style="display:flex;align-items:center;gap:0;margin-top:12px;flex-wrap:wrap;">
<div style="padding-right:18px;border-right:1px solid #f0f0f0;margin-right:18px;"><div style="font-size:11px;color:#8c8c8c;">Продукт</div><a href="Карточка продукта.dc.html" style="font-size:13.5px;font-weight:600;color:#1677ff;text-decoration:none;margin-top:2px;display:block;">FirePage</a></div>
<div style="padding-right:18px;border-right:1px solid #f0f0f0;margin-right:18px;"><div style="font-size:11px;color:#8c8c8c;">Модель</div><div style="font-size:13.5px;font-weight:600;color:#262626;margin-top:2px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">gpt-4o-mini</div></div>
<div style="padding-right:18px;border-right:1px solid #f0f0f0;margin-right:18px;"><div style="font-size:11px;color:#8c8c8c;">Текущий release</div><a href="ProductAIRelease.dc.html" style="font-size:13.5px;font-weight:600;color:#1677ff;text-decoration:none;margin-top:2px;display:block;font-family:'SF Mono',ui-monospace,Menlo,monospace;">REL-FP-v4</a></div>
<div><div style="font-size:11px;color:#8c8c8c;">Лимиты</div><div style="font-size:13.5px;font-weight:600;color:#262626;margin-top:2px;">5К диал./день · ₽5 000</div></div>
</div>
</div>
</div>
<div style="display:flex;align-items:center;gap:9px;flex:none;">
<a href="Тестовый чат.dc.html" style="display:flex;align-items:center;gap:7px;height:38px;padding:0 15px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;text-decoration:none;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>Тест-чат</a>
<a href="ProductAIRelease.dc.html" style="display:flex;align-items:center;gap:7px;height:38px;padding:0 16px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer;text-decoration:none;box-shadow:0 1px 2px rgba(22,119,255,0.3);" style-hover="background:#0958d9;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Release candidate</a>
</div>
</div>
</div>
<!-- TABS -->
<div style="display:flex;align-items:center;gap:2px;border-bottom:1px solid #e8e8e8;margin-bottom:18px;overflow-x:auto;">
<button onClick="{{ onTabOverview }}" style="{{ tOverview }}">Обзор</button>
<button onClick="{{ onTabInstr }}" style="{{ tInstr }}">Инструкции</button>
<button onClick="{{ onTabKnow }}" style="{{ tKnow }}">Знания</button>
<button onClick="{{ onTabRel }}" style="{{ tRel }}">История releases</button>
<button onClick="{{ onTabMetrics }}" style="{{ tMetrics }}">Метрики</button>
</div>
<!-- ===== ОБЗОР ===== -->
<sc-if value="{{ isOverview }}" hint-placeholder-val="{{ true }}">
<div style="display:flex;gap:18px;align-items:flex-start;">
<div style="flex:1;min-width:0;display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Назначение агента</h3>
<p style="margin:0;font-size:13px;color:#595959;line-height:1.6;">Sales-агент консультирует клиентов по продукту FirePage, квалифицирует потребность, предлагает подходящий Offer и оформляет покупку. При выходе за рамки сценария передаёт диалог оператору.</p>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 14px;font-size:14px;font-weight:700;color:#1f1f1f;">Runtime сейчас</h3>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:#f0f0f0;border:1px solid #f0f0f0;border-radius:9px;overflow:hidden;">
<div style="background:#fff;padding:13px 15px;"><div style="font-size:11.5px;color:#8c8c8c;">Активные диалоги</div><div style="font-size:19px;font-weight:700;color:#262626;margin-top:4px;">21</div></div>
<div style="background:#fff;padding:13px 15px;"><div style="font-size:11.5px;color:#8c8c8c;">В очереди на ответ</div><div style="font-size:19px;font-weight:700;color:#262626;margin-top:4px;">2</div></div>
<div style="background:#fff;padding:13px 15px;"><div style="font-size:11.5px;color:#8c8c8c;">Ср. время ответа</div><div style="font-size:19px;font-weight:700;color:#262626;margin-top:4px;">3,4с</div></div>
</div>
</div>
</div>
<div style="width:316px;flex:none;display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Лимиты</h3>
<div style="display:flex;align-items:center;justify-content:space-between;padding:7px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Диалогов в день</span><span style="font-size:12.5px;font-weight:600;color:#262626;">847 / 5 000</span></div>
<div style="height:6px;border-radius:999px;background:#f0f0f0;overflow:hidden;margin:4px 0 10px;"><div style="height:6px;border-radius:999px;background:#1677ff;width:17%;"></div></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:7px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Бюджет в день</span><span style="font-size:12.5px;font-weight:600;color:#262626;">₽1 240 / ₽5 000</span></div>
<div style="height:6px;border-radius:999px;background:#f0f0f0;overflow:hidden;margin:4px 0 0;"><div style="height:6px;border-radius:999px;background:#1677ff;width:25%;"></div></div>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Управление</h3>
<button style="width:100%;display:flex;align-items:center;gap:9px;height:38px;padding:0 13px;border-radius:9px;border:1px solid #e8e8e8;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;margin-bottom:8px;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/></svg>Изменить лимиты</button>
<button style="width:100%;display:flex;align-items:center;gap:9px;height:38px;padding:0 13px;border-radius:9px;border:1px solid #ffe58f;background:#fffbe6;color:#d48806;font-size:13px;font-weight:500;cursor:pointer;" style-hover="background:#fff7e6;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/></svg>Остановить агента</button>
</div>
</div>
</div>
</sc-if>
<!-- ===== ИНСТРУКЦИИ ===== -->
<sc-if value="{{ isInstr }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;flex-direction:column;gap:16px;">
<div style="display:flex;align-items:center;gap:10px;padding:11px 16px;background:#fffbe6;border:1px solid #ffe58f;border-radius:10px;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#d48806" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" style="flex:none;"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
<span style="font-size:12.5px;color:#7c5a00;">Инструкции редактируются в составе release candidate. Активный release published и доступен только для чтения — изменения применяются после публикации новой версии.</span>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:12px;"><span style="width:24px;height:24px;border-radius:6px;background:#f0f2f5;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:#595959;flex:none;">1</span><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Системный prompt</h3></div>
<div style="background:#fafafa;border:1px solid #f0f0f0;border-radius:9px;padding:13px 15px;font-size:12.5px;color:#595959;line-height:1.65;font-family:'SF Mono',ui-monospace,Menlo,monospace;white-space:pre-line;">Ты — менеджер по продажам FirePage, готовых нишевых сайтов. Отвечай дружелюбно и по делу, на русском. Помогай выбрать между коробкой и годовой поддержкой. Не обещай возможности, которых нет в базе знаний. При запросе человека или нестандартной ситуации — передавай диалог оператору.</div>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:12px;"><span style="width:24px;height:24px;border-radius:6px;background:#f0f2f5;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:#595959;flex:none;">2</span><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Квалификация (qualification)</h3></div>
<div style="display:flex;flex-direction:column;gap:9px;">
<div style="display:flex;gap:10px;align-items:flex-start;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="#1677ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex:none;margin-top:2px;"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg><span style="font-size:13px;color:#595959;line-height:1.45;">Уточни нишу/тематику сайта и нужен ли он под ключ.</span></div>
<div style="display:flex;gap:10px;align-items:flex-start;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="#1677ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex:none;margin-top:2px;"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg><span style="font-size:13px;color:#595959;line-height:1.45;">Выясни, нужна ли годовая поддержка сразу или позже.</span></div>
<div style="display:flex;gap:10px;align-items:flex-start;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="#1677ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex:none;margin-top:2px;"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg><span style="font-size:13px;color:#595959;line-height:1.45;">Определи срочность и бюджет, не дави на клиента.</span></div>
</div>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:12px;"><span style="width:24px;height:24px;border-radius:6px;background:#f0f2f5;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:#595959;flex:none;">3</span><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Поведение в продаже (sales behavior)</h3></div>
<div style="display:flex;flex-direction:column;gap:9px;">
<div style="display:flex;gap:10px;align-items:flex-start;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="#389e0d" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" style="flex:none;margin-top:2px;"><path d="M20 6 9 17l-5-5"/></svg><span style="font-size:13px;color:#595959;line-height:1.45;">Предлагай коробку как основное решение, поддержку — как опцию.</span></div>
<div style="display:flex;gap:10px;align-items:flex-start;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="#389e0d" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" style="flex:none;margin-top:2px;"><path d="M20 6 9 17l-5-5"/></svg><span style="font-size:13px;color:#595959;line-height:1.45;">Оформляй checkout сразу, как клиент подтвердил выбор.</span></div>
<div style="display:flex;gap:10px;align-items:flex-start;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="#389e0d" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" style="flex:none;margin-top:2px;"><path d="M20 6 9 17l-5-5"/></svg><span style="font-size:13px;color:#595959;line-height:1.45;">Используй только актуальные цены из активного release.</span></div>
</div>
</div>
<div style="background:#fff;border:1px solid #ffccc7;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:12px;"><span style="width:24px;height:24px;border-radius:6px;background:#fff2f0;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#cf1322" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg></span><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Ограничения</h3></div>
<div style="display:flex;flex-direction:column;gap:9px;">
<div style="display:flex;gap:10px;align-items:flex-start;"><span style="width:6px;height:6px;border-radius:50%;background:#ff4d4f;flex:none;margin-top:6px;"></span><span style="font-size:13px;color:#595959;line-height:1.45;">Не выдумывай функции и не обещай сроки вне базы знаний.</span></div>
<div style="display:flex;gap:10px;align-items:flex-start;"><span style="width:6px;height:6px;border-radius:50%;background:#ff4d4f;flex:none;margin-top:6px;"></span><span style="font-size:13px;color:#595959;line-height:1.45;">Не предоставляй скидки сверх правил Offer.</span></div>
<div style="display:flex;gap:10px;align-items:flex-start;"><span style="width:6px;height:6px;border-radius:50%;background:#ff4d4f;flex:none;margin-top:6px;"></span><span style="font-size:13px;color:#595959;line-height:1.45;">Не запрашивай данные карты в чате — оплата только через checkout.</span></div>
</div>
</div>
</div>
</sc-if>
<!-- ===== ЗНАНИЯ ===== -->
<sc-if value="{{ isKnow }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:15px 18px 12px;border-bottom:1px solid #f5f5f5;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Обязательные знания release</h3><div style="font-size:11.5px;color:#bfbfbf;margin-top:3px;">Retrieval index · FirePage KB · 6 материалов</div></div>
<sc-for list="{{ knowledge }}" as="k" hint-placeholder-count="4">
<div style="display:flex;align-items:center;gap:13px;padding:13px 18px;border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<span style="width:32px;height:32px;border-radius:8px;background:#f5f5f5;display:flex;align-items:center;justify-content:center;flex:none;color:#8c8c8c;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><polyline points="14 2 14 8 20 8"/></svg></span>
<div style="flex:1;min-width:0;"><div style="font-size:13px;font-weight:500;color:#262626;">{{ k.title }}</div><div style="font-size:11.5px;color:#bfbfbf;margin-top:1px;">{{ k.meta }}</div></div>
<span style="font-size:11.5px;color:#389e0d;font-weight:500;">В индексе</span>
</div>
</sc-for>
</div>
</sc-if>
<!-- ===== ИСТОРИЯ RELEASES ===== -->
<sc-if value="{{ isRel }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;">
<th style="text-align:left;padding:11px 18px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">RELEASE</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СТАТУС</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ДАТА</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">АВТОР</th>
<th style="text-align:right;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ДИАЛОГИ</th>
<th style="text-align:right;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">КОНВЕРСИЯ</th>
<th style="width:44px;border-bottom:1px solid #f0f0f0;"></th>
</tr></thead>
<tbody>
<sc-for list="{{ releases }}" as="r" hint-placeholder-count="4">
<tr style="border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<td style="padding:12px 18px;"><a href="ProductAIRelease.dc.html" style="font-weight:600;color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;">{{ r.id }}</a></td>
<td style="padding:12px 12px;"><span style="padding:2px 9px;border-radius:6px;background:{{ r.bg }};color:{{ r.color }};font-size:11.5px;font-weight:600;">{{ r.status }}</span></td>
<td style="padding:12px 12px;color:#595959;white-space:nowrap;">{{ r.date }}</td>
<td style="padding:12px 12px;color:#595959;">{{ r.author }}</td>
<td style="padding:12px 12px;text-align:right;color:#595959;">{{ r.dialogs }}</td>
<td style="padding:12px 12px;text-align:right;color:#595959;">{{ r.conv }}</td>
<td style="padding:12px 12px;text-align:center;"><a href="ProductAIRelease.dc.html" style="color:#1677ff;text-decoration:none;display:inline-flex;" style-hover="opacity:0.7;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></a></td>
</tr>
</sc-for>
</tbody>
</table>
</div>
</sc-if>
<!-- ===== МЕТРИКИ ===== -->
<sc-if value="{{ isMetrics }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;flex-direction:column;gap:16px;">
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:14px 16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);"><div style="font-size:12px;color:#8c8c8c;">Диалоги · 30 дней</div><div style="font-size:22px;font-weight:700;color:#262626;margin-top:6px;">1 342</div></div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:14px 16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);"><div style="font-size:12px;color:#8c8c8c;">Продажи · 30 дней</div><div style="font-size:22px;font-weight:700;color:#262626;margin-top:6px;">56</div></div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:14px 16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);"><div style="font-size:12px;color:#8c8c8c;">Конверсия</div><div style="font-size:22px;font-weight:700;color:#262626;margin-top:6px;">15,1%</div></div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:14px 16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);"><div style="font-size:12px;color:#8c8c8c;">Стоимость / продажа</div><div style="font-size:22px;font-weight:700;color:#262626;margin-top:6px;">₽67</div></div>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 16px;font-size:14px;font-weight:700;color:#1f1f1f;">Причины передачи оператору · 30 дней</h3>
<div style="display:flex;flex-direction:column;gap:13px;">
<sc-for list="{{ handoffReasons }}" as="h" hint-placeholder-count="3">
<div>
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;"><span style="font-size:13px;color:#262626;">{{ h.label }}</span><span style="font-size:12.5px;color:#8c8c8c;"><b style="color:#262626;">{{ h.count }}</b> · {{ h.pct }}%</span></div>
<div style="height:7px;border-radius:999px;background:#f0f0f0;overflow:hidden;"><div style="height:7px;border-radius:999px;background:{{ h.color }};width:{{ h.pct }}%;"></div></div>
</div>
</sc-for>
</div>
</div>
</div>
</sc-if>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 }
}">
class Component extends DCLogic {
state = { tab: 'overview' };
renderVals() {
const rt = { label: 'Активен · published', color: '#389e0d', bg: '#f6ffed', border: '#b7eb8f', dot: '#52c41a' };
const knowledge = [
{ title: 'Что входит в коробку FirePage', meta: 'FAQ · v3 · обновлено 10 июня' },
{ title: 'Условия годовой поддержки', meta: 'Документ · v2 · обновлено 08 июня' },
{ title: 'Примеры готовых сайтов', meta: 'Подборка · обновлено 02 июня' },
{ title: 'Частые возражения и ответы', meta: 'Скрипт · обновлено 28 мая' },
];
const published = { status: 'Published', bg: '#f6ffed', color: '#389e0d' };
const archived = { status: 'Archived', bg: '#f5f5f5', color: '#8c8c8c' };
const candidate = { status: 'Candidate', bg: '#fff7e6', color: '#d48806' };
const releases = [
{ id: 'REL-FP-v5', ...candidate, date: 'сегодня 11:20', author: 'Иван Петров', dialogs: '—', conv: '—' },
{ id: 'REL-FP-v4', ...published, date: '01 июня 2026', author: 'Иван Петров', dialogs: '1 342', conv: '15,1%' },
{ id: 'REL-FP-v3', ...archived, date: '01 фев 2026', author: 'Иван Петров', dialogs: '3 980', conv: '13,4%' },
{ id: 'REL-FP-v2', ...archived, date: '12 дек 2025', author: 'Иван Петров', dialogs: '2 110', conv: '11,8%' },
];
const handoffReasons = [
{ label: 'Запрос человека', count: '41', pct: 46, color: '#1677ff' },
{ label: 'Вне сценария / сложный вопрос', count: '28', pct: 31, color: '#722ed1' },
{ label: 'Технический сбой', count: '12', pct: 13, color: '#faad14' },
{ label: 'Запрос скидки сверх правил', count: '9', pct: 10, color: '#8c8c8c' },
];
const { tab } = this.state;
const base = 'padding:11px 15px;border:none;background:transparent;border-bottom:2px solid transparent;font-size:14px;font-weight:500;color:#595959;cursor:pointer;margin-bottom:-1px;white-space:nowrap;';
const act = 'padding:11px 15px;border:none;background:transparent;border-bottom:2px solid #1677ff;font-size:14px;font-weight:600;color:#1677ff;cursor:pointer;margin-bottom:-1px;white-space:nowrap;';
const A = (t) => tab === t ? act : base;
const set = (t) => this.setState({ tab: t });
return {
rt, knowledge, releases, handoffReasons,
isOverview: tab === 'overview', isInstr: tab === 'instr', isKnow: tab === 'know', isRel: tab === 'rel', isMetrics: tab === 'metrics',
tOverview: A('overview'), tInstr: A('instr'), tKnow: A('know'), tRel: A('rel'), tMetrics: A('metrics'),
onTabOverview: () => set('overview'), onTabInstr: () => set('instr'), onTabKnow: () => set('know'),
onTabRel: () => set('rel'), onTabMetrics: () => set('metrics'),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,289 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1080px;">
<!-- ============ SIDEBAR (уровень компании) ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span><span style="font-size:11px;color:#8c8c8c;">Уровень компании</span></div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>Командный центр</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="Отделы.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>Отделы</a>
<a href="Сотрудники.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Сотрудники</a>
<a href="Продукты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>Продукты</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="AI-агенты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/></svg>AI</a>
<a href="Интеграции.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>Интеграции</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><circle cx="13" cy="18" r="2"/></svg>Настройки</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><a href="Интеграции.dc.html" style="font-weight:500;color:#595959;text-decoration:none;" style-hover="color:#1677ff;">Интеграции</a><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">{{ name }}</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1080px;margin:0 auto;">
<!-- HEADER + HEALTHCHECK -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:20px 22px;margin-bottom:16px;">
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:20px;">
<div style="display:flex;align-items:center;gap:16px;min-width:0;">
<div style="width:52px;height:52px;border-radius:13px;background:{{ iconBg }};display:flex;align-items:center;justify-content:center;flex:none;font-size:18px;font-weight:700;color:{{ iconColor }};">{{ mark }}</div>
<div style="min-width:0;">
<div style="display:flex;align-items:center;gap:11px;flex-wrap:wrap;">
<h1 style="margin:0;font-size:21px;font-weight:700;letter-spacing:-0.01em;color:#1f1f1f;">{{ name }}</h1>
<span style="display:inline-flex;align-items:center;gap:6px;padding:3px 11px;border-radius:14px;background:{{ st.bg }};border:1px solid {{ st.border }};font-size:11.5px;font-weight:600;color:{{ st.color }};"><span style="width:6px;height:6px;border-radius:50%;background:{{ st.dot }};"></span>{{ st.label }}</span>
</div>
<div style="font-size:12.5px;color:#8c8c8c;margin-top:5px;">{{ subtitle }}</div>
</div>
</div>
<div style="display:flex;align-items:center;gap:9px;flex:none;">
<button style="display:flex;align-items:center;gap:7px;height:38px;padding:0 15px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>Проверить соединение</button>
</div>
</div>
<!-- healthcheck strip -->
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:#f0f0f0;border:1px solid #f0f0f0;border-radius:10px;overflow:hidden;margin-top:18px;">
<div style="background:#fff;padding:13px 16px;"><div style="font-size:11.5px;color:#8c8c8c;">Healthcheck</div><div style="font-size:14px;font-weight:600;color:{{ hc.color }};margin-top:5px;display:flex;align-items:center;gap:6px;"><span style="width:7px;height:7px;border-radius:50%;background:{{ hc.dot }};"></span>{{ hc.label }}</div></div>
<div style="background:#fff;padding:13px 16px;"><div style="font-size:11.5px;color:#8c8c8c;">Аптайм · 30 дней</div><div style="font-size:14px;font-weight:600;color:#262626;margin-top:5px;">{{ uptime }}</div></div>
<div style="background:#fff;padding:13px 16px;"><div style="font-size:11.5px;color:#8c8c8c;">Ответ (p95)</div><div style="font-size:14px;font-weight:600;color:#262626;margin-top:5px;">{{ latency }}</div></div>
<div style="background:#fff;padding:13px 16px;"><div style="font-size:11.5px;color:#8c8c8c;">Последняя проверка</div><div style="font-size:14px;font-weight:600;color:#262626;margin-top:5px;">{{ lastCheck }}</div></div>
</div>
</div>
<!-- TWO COLUMN -->
<div style="display:flex;gap:18px;align-items:flex-start;">
<!-- LEFT -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;gap:16px;">
<!-- параметры (без секретов) -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 4px;font-size:14px;font-weight:700;color:#1f1f1f;">Параметры</h3>
<div style="font-size:11.5px;color:#bfbfbf;margin-bottom:8px;">Секреты не отображаются — только статус и метаданные</div>
<sc-for list="{{ params }}" as="p" hint-placeholder-count="4">
<div style="display:flex;align-items:center;justify-content:space-between;gap:16px;padding:11px 0;border-top:1px solid #f5f5f5;">
<span style="font-size:12.5px;color:#8c8c8c;flex:none;">{{ p.label }}</span>
<span style="font-size:12.5px;color:#262626;font-weight:500;text-align:right;{{ p.mono }}">{{ p.value }}</span>
</div>
</sc-for>
</div>
<!-- спец-блок -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 14px;font-size:14px;font-weight:700;color:#1f1f1f;">{{ specialTitle }}</h3>
<!-- OpenRouter: модели -->
<sc-if value="{{ isOpenRouter }}" hint-placeholder-val="{{ true }}">
<div style="margin-bottom:14px;"><div style="font-size:12px;color:#8c8c8c;margin-bottom:8px;">Модель по умолчанию</div><span style="display:inline-flex;align-items:center;gap:7px;padding:5px 12px;border-radius:8px;background:#f9f0ff;border:1px solid #efdbff;font-size:12.5px;font-weight:600;color:#722ed1;font-family:'SF Mono',ui-monospace,Menlo,monospace;">gpt-4o-mini</span></div>
<div style="font-size:12px;color:#8c8c8c;margin-bottom:8px;">Разрешённые модели</div>
<div style="display:flex;flex-wrap:wrap;gap:7px;">
<sc-for list="{{ models }}" as="m" hint-placeholder-count="4"><span style="padding:4px 10px;border-radius:7px;background:#f5f5f5;font-size:12px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ m.name }}</span></sc-for>
</div>
</sc-if>
<!-- Точка: платежи -->
<sc-if value="{{ isTochka }}" hint-placeholder-val="{{ false }}">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:16px;">
<div><div style="font-size:11.5px;color:#8c8c8c;">Merchant account</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">acc_ed···4021</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">JWT credential</div><div style="font-size:13px;font-weight:600;color:#389e0d;margin-top:3px;">Активен · до 30 июня</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Webhook</div><div style="font-size:13px;font-weight:600;color:#d48806;margin-top:3px;">Задержка ответа</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Reconciliation</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;">Авто · 02:00</div></div>
</div>
<div style="font-size:12px;color:#8c8c8c;margin-bottom:9px;">Последние платёжные события</div>
<div style="display:flex;flex-direction:column;gap:0;">
<sc-for list="{{ payEvents }}" as="e" hint-placeholder-count="3">
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-top:1px solid #f5f5f5;"><span style="width:6px;height:6px;border-radius:50%;background:{{ e.dot }};flex:none;"></span><span style="flex:1;font-size:12.5px;color:#262626;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ e.name }}</span><span style="font-size:11.5px;color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ e.id }}</span><span style="font-size:11.5px;color:#bfbfbf;width:60px;text-align:right;">{{ e.time }}</span></div>
</sc-for>
</div>
</sc-if>
<!-- MAX/Telegram: канал -->
<sc-if value="{{ isChannel }}" hint-placeholder-val="{{ false }}">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px;">
<div><div style="font-size:11.5px;color:#8c8c8c;">Связанные продукты</div><div style="display:flex;gap:6px;margin-top:5px;"><span style="padding:2px 9px;border-radius:6px;background:#e6f4ff;color:#0958d9;font-size:11.5px;font-weight:600;">FirePage</span><span style="padding:2px 9px;border-radius:6px;background:#f9f0ff;color:#722ed1;font-size:11.5px;font-weight:600;">Foxray</span></div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Идентификатор бота</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:5px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">@edevs_sales</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Webhook</div><div style="font-size:13px;font-weight:600;color:#389e0d;margin-top:5px;">Активен</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Сообщений · сегодня</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:5px;">1 284</div></div>
</div>
</sc-if>
</div>
<!-- журнал ошибок -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:15px 20px 12px;display:flex;align-items:center;justify-content:space-between;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Журнал ошибок</h3><span style="font-size:11.5px;color:#bfbfbf;">за 7 дней</span></div>
<sc-if value="{{ hasErrors }}" hint-placeholder-val="{{ true }}">
<sc-for list="{{ errors }}" as="e" hint-placeholder-count="2">
<div style="display:flex;align-items:flex-start;gap:11px;padding:11px 20px;border-top:1px solid #f5f5f5;">
<span style="width:7px;height:7px;border-radius:50%;background:{{ e.dot }};margin-top:5px;flex:none;"></span>
<div style="flex:1;min-width:0;"><div style="font-size:12.5px;font-weight:500;color:#262626;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ e.code }}</div><div style="font-size:12px;color:#8c8c8c;margin-top:2px;">{{ e.message }}</div></div>
<span style="font-size:11.5px;color:#bfbfbf;flex:none;white-space:nowrap;">{{ e.time }}</span>
</div>
</sc-for>
</sc-if>
<sc-if value="{{ noErrors }}" hint-placeholder-val="{{ false }}">
<div style="padding:24px 20px;text-align:center;border-top:1px solid #f5f5f5;"><div style="font-size:13px;color:#8c8c8c;">Ошибок за период нет</div></div>
</sc-if>
</div>
</div>
<!-- RIGHT RAIL -->
<div style="width:316px;flex:none;display:flex;flex-direction:column;gap:16px;">
<!-- подключение -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Подключение</h3>
<div style="display:flex;align-items:center;justify-content:space-between;padding:4px 0 12px;"><span style="font-size:13px;color:#262626;">Статус</span><span style="display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:600;color:{{ st.color }};"><span style="width:7px;height:7px;border-radius:50%;background:{{ st.dot }};"></span>{{ st.label }}</span></div>
<button style="width:100%;display:flex;align-items:center;justify-content:center;gap:8px;height:38px;border-radius:9px;border:1px solid #ffe58f;background:#fffbe6;color:#d48806;font-size:13px;font-weight:500;cursor:pointer;" style-hover="background:#fff7e6;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/></svg>Отключить интеграцию</button>
</div>
<!-- ротация секрета -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 6px;font-size:14px;font-weight:700;color:#1f1f1f;">Секрет</h3>
<div style="font-size:12.5px;color:#8c8c8c;line-height:1.5;margin-bottom:13px;">{{ secretNote }}</div>
<div style="display:flex;align-items:center;gap:9px;padding:10px 12px;background:#fafafa;border:1px solid #f0f0f0;border-radius:9px;margin-bottom:12px;">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#8c8c8c" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" style="flex:none;"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
<span style="flex:1;font-size:12.5px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ secretMask }}</span>
<span style="font-size:11px;color:#bfbfbf;">{{ secretAge }}</span>
</div>
<button style="width:100%;display:flex;align-items:center;justify-content:center;gap:8px;height:38px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/><path d="M3 21v-5h5"/></svg>Ротация секрета</button>
</div>
<!-- последняя активность -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Последняя активность</h3>
<div style="display:flex;flex-direction:column;gap:0;font-size:12.5px;">
<sc-for list="{{ activity }}" as="a" hint-placeholder-count="3">
<div style="display:flex;gap:10px;padding:7px 0;border-bottom:1px solid #f7f7f7;"><span style="width:6px;height:6px;border-radius:50%;background:{{ a.dot }};margin-top:5px;flex:none;"></span><div style="flex:1;"><div style="color:#262626;">{{ a.text }}</div><div style="font-size:11px;color:#bfbfbf;margin-top:1px;">{{ a.time }}</div></div></div>
</sc-for>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 },
&quot;kind&quot;: { &quot;editor&quot;: &quot;enum&quot;, &quot;options&quot;: [&quot;openrouter&quot;, &quot;tochka&quot;, &quot;channel&quot;], &quot;default&quot;: &quot;tochka&quot;, &quot;tsType&quot;: &quot;string&quot; }
}">
class Component extends DCLogic {
renderVals() {
const kind = this.props.kind ?? 'tochka';
const ST = {
connected: { label: 'Подключено', color: '#389e0d', bg: '#f6ffed', border: '#b7eb8f', dot: '#52c41a' },
degraded: { label: 'Degraded', color: '#d48806', bg: '#fffbe6', border: '#ffe58f', dot: '#faad14' },
};
const cfg = {
openrouter: {
name: 'OpenRouter', mark: 'OR', iconBg: '#f9f0ff', iconColor: '#722ed1',
subtitle: 'AI-провайдер · модели для агентов', st: ST.connected,
hc: { label: 'Healthy', color: '#389e0d', dot: '#52c41a' }, uptime: '99,98%', latency: '420 мс', lastCheck: '12 сек назад',
params: [
{ label: 'Эндпоинт', value: 'api.openrouter.ai/v1', mono: true },
{ label: 'API credential', value: 'Активен' },
{ label: 'Организация', value: 'edevs-tech' },
{ label: 'Биллинг', value: 'prepaid · ₽12 400 остаток' },
],
specialTitle: 'Модели и лимиты', isOpenRouter: true, isTochka: false, isChannel: false,
models: [{ name: 'gpt-4o-mini' }, { name: 'gpt-4o' }, { name: 'claude-3.5-sonnet' }, { name: 'claude-3.5-haiku' }, { name: 'llama-3.1-70b' }, { name: 'mistral-large' }],
secretNote: 'API-ключ хранится в зашифрованном виде и не отображается.', secretMask: 'sk-or-····················f2a1', secretAge: '32 дня',
hasErrors: false, noErrors: true, errors: [],
activity: [
{ dot: '#52c41a', text: 'Запрос модели · gpt-4o-mini', time: '12 сек назад' },
{ dot: '#52c41a', text: 'Healthcheck успешен', time: '1 мин назад' },
{ dot: '#bfbfbf', text: 'Пополнение баланса', time: '3 дня назад' },
],
},
tochka: {
name: 'Точка', mark: 'Т', iconBg: '#e6f4ff', iconColor: '#0958d9',
subtitle: 'Платежи и фискализация', st: ST.degraded,
hc: { label: 'Degraded', color: '#d48806', dot: '#faad14' }, uptime: '99,2%', latency: '2 400 мс', lastCheck: '4 мин назад',
params: [
{ label: 'Эндпоинт', value: 'enter.tochka.com/api', mono: true },
{ label: 'Режим', value: 'Боевой (production)' },
{ label: 'Фискализация', value: 'Включена · НДС 20%' },
{ label: 'Валюта', value: 'RUB' },
],
specialTitle: 'Платежи', isOpenRouter: false, isTochka: true, isChannel: false,
payEvents: [
{ dot: '#52c41a', name: 'payment.captured', id: 'PAY-88231', time: '14:02' },
{ dot: '#52c41a', name: 'payment.settled', id: 'PAY-88230', time: '13:41' },
{ dot: '#ff4d4f', name: 'webhook.timeout', id: 'PAY-88224', time: '11:08' },
],
secretNote: 'JWT-ключ доступа хранится в зашифрованном виде. Срок действия — до 30 июня.', secretMask: 'jwt-····················9c30', secretAge: '4 дня',
hasErrors: true, noErrors: false,
errors: [
{ dot: '#ff4d4f', code: 'WEBHOOK_TIMEOUT', message: 'Webhook не ответил за 5с · PAY-88224', time: '11:08' },
{ dot: '#faad14', code: 'SLOW_RESPONSE', message: 'Ответ API 2,4с (порог 2с)', time: '10:42' },
],
activity: [
{ dot: '#52c41a', text: 'Платёж получен · ₽2 490', time: '4 мин назад' },
{ dot: '#faad14', text: 'Webhook с задержкой', time: '11 мин назад' },
{ dot: '#52c41a', text: 'Reconciliation завершён', time: 'сегодня 02:00' },
],
},
channel: {
name: 'MAX', mark: 'M', iconBg: '#f2f0ff', iconColor: '#6b5be0',
subtitle: 'Канал · источник диалогов', st: ST.connected,
hc: { label: 'Healthy', color: '#389e0d', dot: '#52c41a' }, uptime: '99,95%', latency: '180 мс', lastCheck: '8 сек назад',
params: [
{ label: 'Эндпоинт', value: 'botapi.max.ru', mono: true },
{ label: 'Режим доставки', value: 'Webhook' },
{ label: 'Подписка на события', value: 'messages, callbacks' },
{ label: 'Часовой пояс', value: 'Europe/Moscow' },
],
specialTitle: 'Канал', isOpenRouter: false, isTochka: false, isChannel: true,
secretNote: 'Токен бота хранится в зашифрованном виде и не отображается.', secretMask: 'bot-····················7b15', secretAge: '58 дней',
hasErrors: false, noErrors: true, errors: [],
activity: [
{ dot: '#52c41a', text: 'Входящее сообщение', time: '8 сек назад' },
{ dot: '#52c41a', text: 'Healthcheck успешен', time: '2 мин назад' },
{ dot: '#bfbfbf', text: 'Обновлён вебхук', time: '12 дней назад' },
],
},
}[kind];
const params = cfg.params.map((p) => ({ label: p.label, value: p.value, mono: p.mono ? "font-family:'SF Mono',ui-monospace,Menlo,monospace;" : '' }));
return { ...cfg, params };
}
}
</script>
</body>
</html>
@@ -0,0 +1,313 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1080px;">
<!-- ============ SIDEBAR (уровень компании) ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span><span style="font-size:11px;color:#8c8c8c;">Уровень компании</span></div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>Командный центр</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="Отделы.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>Отделы</a>
<a href="Сотрудники.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Сотрудники</a>
<a href="Продукты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>Продукты</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/><path d="M2 13.5h2M20 13.5h2"/></svg>AI</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>Интеграции</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><line x1="3" y1="18" x2="11" y2="18"/><circle cx="13" cy="18" r="2"/></svg>Настройки</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><a href="Продукты.dc.html" style="font-weight:500;color:#595959;text-decoration:none;" style-hover="color:#1677ff;">Продукты</a><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">{{ p.name }}</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1080px;margin:0 auto;">
<!-- HEADER CARD -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:20px 22px;margin-bottom:16px;">
<div style="display:flex;align-items:flex-start;gap:16px;">
<div style="width:52px;height:52px;border-radius:13px;background:{{ p.iconBg }};display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="26" height="26" fill="none" stroke="{{ p.iconColor }}" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg></div>
<div style="flex:1;min-width:0;">
<div style="display:flex;align-items:center;gap:11px;flex-wrap:wrap;">
<h1 style="margin:0;font-size:21px;font-weight:700;letter-spacing:-0.01em;color:#1f1f1f;">{{ p.name }}</h1>
<span style="display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:14px;background:#f6ffed;border:1px solid #b7eb8f;font-size:11.5px;font-weight:600;color:#389e0d;"><span style="width:6px;height:6px;border-radius:50%;background:#52c41a;"></span>Активен</span>
<span style="padding:2px 9px;border-radius:6px;background:{{ p.tagBg }};color:{{ p.tagColor }};font-size:11px;font-weight:600;">{{ p.kind }}</span>
</div>
<p style="margin:6px 0 0;font-size:13px;color:#595959;line-height:1.5;max-width:640px;">{{ p.desc }}</p>
</div>
<button style="display:flex;align-items:center;gap:7px;height:38px;padding:0 16px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;flex:none;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/></svg>Редактировать</button>
</div>
<!-- quick stats -->
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:#f0f0f0;border:1px solid #f0f0f0;border-radius:10px;overflow:hidden;margin-top:18px;">
<div style="background:#fff;padding:13px 16px;"><div style="font-size:11.5px;color:#8c8c8c;">Продажи · 30 дней</div><div style="font-size:18px;font-weight:700;color:#262626;margin-top:4px;">{{ p.sales30 }}</div></div>
<div style="background:#fff;padding:13px 16px;"><div style="font-size:11.5px;color:#8c8c8c;">Выручка · 30 дней</div><div style="font-size:18px;font-weight:700;color:#389e0d;margin-top:4px;">{{ p.rev30 }}</div></div>
<div style="background:#fff;padding:13px 16px;"><div style="font-size:11.5px;color:#8c8c8c;">{{ p.metric3Label }}</div><div style="font-size:18px;font-weight:700;color:#262626;margin-top:4px;">{{ p.metric3 }}</div></div>
<div style="background:#fff;padding:13px 16px;"><div style="font-size:11.5px;color:#8c8c8c;">Конверсия диалогов</div><div style="font-size:18px;font-weight:700;color:#262626;margin-top:4px;">{{ p.conv }}</div></div>
</div>
</div>
<!-- TABS -->
<div style="display:flex;align-items:center;gap:2px;border-bottom:1px solid #e8e8e8;margin-bottom:18px;overflow-x:auto;">
<button onClick="{{ onTabOverview }}" style="{{ tOverview }}">Обзор</button>
<button onClick="{{ onTabOffers }}" style="{{ tOffers }}">Offer и цены</button>
<button onClick="{{ onTabKb }}" style="{{ tKb }}">База знаний</button>
<button onClick="{{ onTabChannels }}" style="{{ tChannels }}">Каналы</button>
<button onClick="{{ onTabFul }}" style="{{ tFul }}">Исполнение</button>
</div>
<!-- ===== ОБЗОР ===== -->
<sc-if value="{{ isOverview }}" hint-placeholder-val="{{ true }}">
<div style="display:flex;gap:18px;align-items:flex-start;">
<div style="flex:1;min-width:0;display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Описание для продаж</h3>
<p style="margin:0;font-size:13px;color:#595959;line-height:1.6;">{{ p.longDesc }}</p>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Ключевые тезисы для AI</h3>
<div style="display:flex;flex-direction:column;gap:9px;">
<sc-for list="{{ p.bullets }}" as="b" hint-placeholder-count="3">
<div style="display:flex;gap:10px;align-items:flex-start;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#389e0d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex:none;margin-top:1px;"><path d="M20 6 9 17l-5-5"/></svg><span style="font-size:13px;color:#595959;line-height:1.45;">{{ b.text }}</span></div>
</sc-for>
</div>
</div>
</div>
<div style="width:316px;flex:none;display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Параметры</h3>
<div style="display:flex;align-items:center;justify-content:space-between;padding:7px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Тип</span><span style="font-size:12.5px;font-weight:500;color:#262626;">{{ p.kind }}</span></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:7px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Отдел</span><span style="font-size:12.5px;font-weight:500;color:#262626;">Продажи</span></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:7px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Sales-agent</span><span style="font-size:12.5px;font-weight:500;color:#722ed1;">{{ p.agent }}</span></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:7px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Создан</span><span style="font-size:12.5px;font-weight:500;color:#262626;">12 мая 2026</span></div>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 4px;font-size:14px;font-weight:700;color:#1f1f1f;">Sales-agent</h3>
<div style="font-size:12.5px;color:#595959;line-height:1.5;margin-top:6px;">{{ p.agentNote }}</div>
<a href="#" style="display:flex;align-items:center;justify-content:center;gap:7px;height:36px;margin-top:12px;border-radius:8px;border:1px solid #d3adf7;background:#fff;color:#722ed1;font-size:13px;font-weight:600;text-decoration:none;" style-hover="background:#f9f0ff;">Открыть конфигурацию AI</a>
</div>
</div>
</div>
</sc-if>
<!-- ===== OFFER И ЦЕНЫ ===== -->
<sc-if value="{{ isOffers }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;flex-direction:column;gap:16px;">
<div style="display:flex;align-items:center;justify-content:space-between;">
<div style="font-size:12.5px;color:#8c8c8c;">Активные Offer привязаны к версии цены. Изменение цены создаёт новую версию — прошлые заказы не затрагиваются.</div>
<button style="display:flex;align-items:center;gap:7px;height:36px;padding:0 14px;border-radius:8px;border:none;background:#1677ff;color:#fff;font-size:13px;font-weight:600;cursor:pointer;flex:none;" style-hover="background:#0958d9;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Добавить Offer</button>
</div>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px;">
<sc-for list="{{ p.offers }}" as="o" hint-placeholder-count="2">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;"><span style="font-size:15px;font-weight:700;color:#1f1f1f;">{{ o.name }}</span><span style="padding:2px 9px;border-radius:6px;background:{{ o.tagBg }};color:{{ o.tagColor }};font-size:11px;font-weight:600;">{{ o.type }}</span></div>
<div style="display:flex;align-items:baseline;gap:7px;"><span style="font-size:22px;font-weight:700;color:#1f1f1f;">{{ o.price }}</span><span style="font-size:12.5px;color:#8c8c8c;">{{ o.unit }}</span></div>
<sc-if value="{{ o.secondary }}" hint-placeholder-val="{{ false }}"><div style="font-size:12px;color:#389e0d;margin-top:6px;font-weight:500;">{{ o.secondary }}</div></sc-if>
<div style="font-size:12.5px;color:#595959;line-height:1.45;margin-top:10px;padding-top:10px;border-top:1px solid #f5f5f5;">{{ o.detail }}</div>
<div style="display:flex;align-items:center;gap:8px;margin-top:12px;"><span style="font-size:11px;color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ o.code }} · price {{ o.priceVer }}</span><span style="margin-left:auto;font-size:11.5px;color:#389e0d;font-weight:500;">AI может предлагать</span></div>
</div>
</sc-for>
</div>
<!-- price history -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:15px 18px 12px;border-bottom:1px solid #f5f5f5;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">История версий цен</h3></div>
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;"><th style="text-align:left;padding:10px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">ВЕРСИЯ</th><th style="text-align:left;padding:10px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">OFFER</th><th style="text-align:right;padding:10px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">ЦЕНА</th><th style="text-align:left;padding:10px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">ДЕЙСТВУЕТ С</th><th style="text-align:left;padding:10px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">СТАТУС</th></tr></thead>
<tbody>
<sc-for list="{{ p.priceHistory }}" as="h" hint-placeholder-count="3">
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:11px 18px;font-family:'SF Mono',ui-monospace,Menlo,monospace;color:#595959;font-size:12px;">{{ h.ver }}</td><td style="padding:11px 12px;color:#262626;">{{ h.offer }}</td><td style="padding:11px 12px;text-align:right;font-weight:600;color:#262626;">{{ h.price }}</td><td style="padding:11px 12px;color:#595959;">{{ h.from }}</td><td style="padding:11px 18px;"><span style="padding:2px 9px;border-radius:6px;background:{{ h.bg }};color:{{ h.color }};font-size:11.5px;font-weight:600;">{{ h.status }}</span></td></tr>
</sc-for>
</tbody>
</table>
</div>
</div>
</sc-if>
<!-- ===== БАЗА ЗНАНИЙ ===== -->
<sc-if value="{{ isKb }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:15px 18px 12px;border-bottom:1px solid #f5f5f5;display:flex;align-items:center;justify-content:space-between;"><div><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">База знаний продукта</h3><div style="font-size:11.5px;color:#bfbfbf;margin-top:3px;">Используется AI-агентом для ответов · {{ p.kbCount }} материалов</div></div><button style="display:flex;align-items:center;gap:7px;height:34px;padding:0 13px;border-radius:8px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:12.5px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Добавить</button></div>
<sc-for list="{{ p.kb }}" as="k" hint-placeholder-count="4">
<div style="display:flex;align-items:center;gap:13px;padding:13px 18px;border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<span style="width:32px;height:32px;border-radius:8px;background:#f5f5f5;display:flex;align-items:center;justify-content:center;flex:none;color:#8c8c8c;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><polyline points="14 2 14 8 20 8"/></svg></span>
<div style="flex:1;min-width:0;"><div style="font-size:13px;font-weight:500;color:#262626;">{{ k.title }}</div><div style="font-size:11.5px;color:#bfbfbf;margin-top:1px;">{{ k.meta }}</div></div>
<span style="font-size:11.5px;color:#389e0d;font-weight:500;">{{ k.status }}</span>
</div>
</sc-for>
</div>
</sc-if>
<!-- ===== КАНАЛЫ ===== -->
<sc-if value="{{ isChannels }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:15px 18px 12px;border-bottom:1px solid #f5f5f5;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Каналы продаж</h3><div style="font-size:11.5px;color:#bfbfbf;margin-top:3px;">Через какие каналы продукт доступен клиентам</div></div>
<sc-for list="{{ channelRows }}" as="c" hint-placeholder-count="3">
<div style="display:flex;align-items:center;gap:13px;padding:14px 18px;border-bottom:1px solid #f5f5f5;">
<span style="width:32px;height:32px;border-radius:8px;background:{{ c.bg }};display:flex;align-items:center;justify-content:center;flex:none;"><span style="width:9px;height:9px;border-radius:50%;background:{{ c.color }};"></span></span>
<div style="flex:1;min-width:0;"><div style="font-size:13px;font-weight:600;color:#262626;">{{ c.name }}</div><div style="font-size:11.5px;color:#8c8c8c;">{{ c.meta }}</div></div>
<span style="font-size:12px;color:#389e0d;font-weight:500;margin-right:12px;">Активен</span>
<div role="switch" style="width:42px;height:24px;border-radius:14px;cursor:pointer;padding:2px;display:flex;align-items:center;justify-content:flex-end;background:#1677ff;flex:none;"><span style="width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,0.2);display:block;"></span></div>
</div>
</sc-for>
</div>
</sc-if>
<!-- ===== ИСПОЛНЕНИЕ ===== -->
<sc-if value="{{ isFul }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<div style="display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:16px;"><div><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Способ исполнения</h3><div style="font-size:11.5px;color:#bfbfbf;margin-top:3px;">{{ p.fulMethod }}</div></div><span style="display:inline-flex;align-items:center;gap:6px;padding:3px 11px;border-radius:14px;background:#f6ffed;border:1px solid #b7eb8f;font-size:11.5px;font-weight:600;color:#389e0d;"><span style="width:6px;height:6px;border-radius:50%;background:#52c41a;"></span>Подключено</span></div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:14px 24px;">
<div><div style="font-size:11.5px;color:#8c8c8c;">Endpoint / handler</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:4px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ p.fulEndpoint }}</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Среднее время</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:4px;">{{ p.fulTime }}</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Успешность · 30 дней</div><div style="font-size:13px;font-weight:600;color:#389e0d;margin-top:4px;">{{ p.fulRate }}</div></div>
</div>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:15px 18px 12px;border-bottom:1px solid #f5f5f5;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Последние операции</h3></div>
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;"><th style="text-align:left;padding:10px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">ЗАКАЗ</th><th style="text-align:left;padding:10px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">ОПЕРАЦИЯ</th><th style="text-align:left;padding:10px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">СТАТУС</th><th style="text-align:right;padding:10px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">ВРЕМЯ</th></tr></thead>
<tbody>
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:11px 18px;"><a href="Продажи · Карточка заказа.dc.html" style="color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;">ORD-10519</a></td><td style="padding:11px 12px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">OP-55120</td><td style="padding:11px 12px;"><span style="padding:2px 9px;border-radius:6px;background:#f6ffed;color:#389e0d;font-size:11.5px;font-weight:600;">Успешно</span></td><td style="padding:11px 18px;text-align:right;color:#595959;">сегодня 14:03</td></tr>
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:11px 18px;"><a href="#" style="color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;">ORD-10516</a></td><td style="padding:11px 12px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">OP-55117</td><td style="padding:11px 12px;"><span style="padding:2px 9px;border-radius:6px;background:#e6f4ff;color:#0958d9;font-size:11.5px;font-weight:600;">В процессе</span></td><td style="padding:11px 18px;text-align:right;color:#595959;">сегодня 12:19</td></tr>
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:11px 18px;"><a href="#" style="color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;">ORD-10470</a></td><td style="padding:11px 12px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">OP-55088</td><td style="padding:11px 12px;"><span style="padding:2px 9px;border-radius:6px;background:#fff2f0;color:#cf1322;font-size:11.5px;font-weight:600;">Ошибка</span></td><td style="padding:11px 18px;text-align:right;color:#595959;">вчера 15:40</td></tr>
</tbody>
</table>
</div>
</div>
</sc-if>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 },
&quot;product&quot;: { &quot;editor&quot;: &quot;enum&quot;, &quot;options&quot;: [&quot;firepage&quot;, &quot;foxray&quot;], &quot;default&quot;: &quot;firepage&quot;, &quot;tsType&quot;: &quot;string&quot; }
}">
class Component extends DCLogic {
state = { tab: 'overview' };
renderVals() {
const which = this.props.product ?? 'firepage';
const okBadge = { bg: '#f6ffed', color: '#389e0d' };
const oldBadge = { bg: '#f5f5f5', color: '#8c8c8c' };
const FP = {
name: 'FirePage', iconBg: '#e6f4ff', iconColor: '#1677ff', kind: 'Коробка · разовая', tagBg: '#e6f4ff', tagColor: '#0958d9',
desc: 'Нишевые сайты под ключ. Продаётся как коробка с единоразовой оплатой и опциональной годовой поддержкой.',
longDesc: 'FirePage — готовые нишевые сайты, которые клиент получает как коробочный продукт. Единоразовая покупка включает сборку и выдачу сайта. Годовая поддержка продлевается отдельно и стоит 30% от цены коробки.',
bullets: [
{ text: 'Коробка ₽4 900 — разовый платёж, сайт выдаётся сразу после оплаты.' },
{ text: 'Годовая поддержка ₽1 470 — обновления и помощь, продление по желанию.' },
{ text: 'Подходит для предпринимателей без своей разработки.' },
],
sales30: '56', rev30: '₽288 100', metric3Label: 'Активная поддержка', metric3: '38', conv: '15,1%',
agent: 'release v4', agentNote: 'AI-агент консультирует по коробке и поддержке, оформляет разовую покупку и предлагает продление поддержки.',
offers: [
{ name: 'Коробка', type: 'разовая', tagBg: '#e6f4ff', tagColor: '#0958d9', price: '₽4 900', unit: 'разово', secondary: '', detail: 'Сборка и выдача нишевого сайта. Единоразовый платёж, бессрочный доступ к сайту.', code: 'OFR-FP-BOX', priceVer: 'v4' },
{ name: 'Годовая поддержка', type: 'продление', tagBg: '#fff7e6', tagColor: '#d48806', price: '₽1 470', unit: '/ год', secondary: '30% от цены коробки', detail: 'Обновления, помощь и хостинг-сопровождение на год. Продлевается по желанию клиента.', code: 'OFR-FP-SUP', priceVer: 'v4' },
],
priceHistory: [
{ ver: 'v4', offer: 'Коробка', price: '₽4 900', from: '01 июня 2026', status: 'Активна', ...okBadge },
{ ver: 'v4', offer: 'Годовая поддержка', price: '₽1 470', from: '01 июня 2026', status: 'Активна', ...okBadge },
{ ver: 'v3', offer: 'Коробка', price: '₽3 900', from: '01 фев 2026', status: 'Архив', ...oldBadge },
],
kbCount: '6', kb: [
{ title: 'Что входит в коробку FirePage', meta: 'FAQ · обновлено 10 июня', status: 'В индексе' },
{ title: 'Условия годовой поддержки', meta: 'Документ · обновлено 08 июня', status: 'В индексе' },
{ title: 'Примеры готовых сайтов', meta: 'Подборка · обновлено 02 июня', status: 'В индексе' },
{ title: 'Частые возражения и ответы', meta: 'Скрипт · обновлено 28 мая', status: 'В индексе' },
],
fulMethod: 'Автоматическая сборка и выдача сайта', fulEndpoint: 'firepage.deploy', fulTime: '2 мин', fulRate: '99,2%',
};
const FX = {
name: 'Foxray', iconBg: '#f9f0ff', iconColor: '#722ed1', kind: 'SaaS · подписка', tagBg: '#f9f0ff', tagColor: '#722ed1',
desc: 'SaaS-сервис по подписке. Два тарифа — Pro и Max, со скидкой 20% при годовой оплате.',
longDesc: 'Foxray — SaaS по ежемесячной подписке с двумя тарифами. Pro для небольших команд, Max для расширенных задач. При оплате за год действует скидка 20%.',
bullets: [
{ text: 'Pro ₽4 900/мес — базовый тариф для старта.' },
{ text: 'Max ₽9 900/мес — расширенные лимиты и возможности.' },
{ text: 'Годовая оплата — скидка 20% к месячной цене.' },
],
sales30: '82', rev30: '₽548 700', metric3Label: 'Активные подписки', metric3: '64', conv: '12,8%',
agent: 'release v3', agentNote: 'AI-агент подбирает тариф, объясняет разницу Pro/Max и предлагает выгоду годовой оплаты.',
offers: [
{ name: 'Pro', type: 'подписка', tagBg: '#f9f0ff', tagColor: '#722ed1', price: '₽4 900', unit: '/ мес', secondary: '₽47 040 / год — скидка 20%', detail: 'Базовый тариф. Помесячная оплата или год со скидкой 20%.', code: 'OFR-FX-PRO', priceVer: 'v3' },
{ name: 'Max', type: 'подписка', tagBg: '#f9f0ff', tagColor: '#722ed1', price: '₽9 900', unit: '/ мес', secondary: '₽95 040 / год — скидка 20%', detail: 'Расширенный тариф. Помесячная оплата или год со скидкой 20%.', code: 'OFR-FX-MAX', priceVer: 'v3' },
],
priceHistory: [
{ ver: 'v3', offer: 'Pro', price: '₽4 900 / мес', from: '01 июня 2026', status: 'Активна', ...okBadge },
{ ver: 'v3', offer: 'Max', price: '₽9 900 / мес', from: '01 июня 2026', status: 'Активна', ...okBadge },
{ ver: 'v2', offer: 'Pro', price: '₽3 900 / мес', from: '01 мар 2026', status: 'Архив', ...oldBadge },
],
kbCount: '7', kb: [
{ title: 'Сравнение тарифов Pro и Max', meta: 'Таблица · обновлено 11 июня', status: 'В индексе' },
{ title: 'Как работает годовая скидка', meta: 'FAQ · обновлено 09 июня', status: 'В индексе' },
{ title: 'Онбординг новых команд', meta: 'Гайд · обновлено 03 июня', status: 'В индексе' },
{ title: 'Лимиты и квоты тарифов', meta: 'Документ · обновлено 30 мая', status: 'В индексе' },
],
fulMethod: 'Автоматическая выдача доступа к SaaS', fulEndpoint: 'foxray.provision', fulTime: '30 сек', fulRate: '99,8%',
};
const p = which === 'foxray' ? FX : FP;
const CH = {
MAX: { name: 'MAX', color: '#6b5be0', bg: '#f2f0ff', meta: 'Мессенджер · основной канал' },
TG: { name: 'Telegram', color: '#2f8fd0', bg: '#eaf6fd', meta: 'Мессенджер' },
WEB: { name: 'Web Chat', color: '#0f9b8e', bg: '#e8f7f4', meta: 'Виджет на сайте' },
};
const channelRows = ['MAX', 'TG', 'WEB'].map((c) => CH[c]);
const { tab } = this.state;
const base = 'padding:11px 15px;border:none;background:transparent;border-bottom:2px solid transparent;font-size:14px;font-weight:500;color:#595959;cursor:pointer;margin-bottom:-1px;white-space:nowrap;';
const act = 'padding:11px 15px;border:none;background:transparent;border-bottom:2px solid #1677ff;font-size:14px;font-weight:600;color:#1677ff;cursor:pointer;margin-bottom:-1px;white-space:nowrap;';
const A = (t) => tab === t ? act : base;
const set = (t) => this.setState({ tab: t });
return {
p, channelRows,
isOverview: tab === 'overview', isOffers: tab === 'offers', isKb: tab === 'kb', isChannels: tab === 'channels', isFul: tab === 'ful',
tOverview: A('overview'), tOffers: A('offers'), tKb: A('kb'), tChannels: A('channels'), tFul: A('ful'),
onTabOverview: () => set('overview'), onTabOffers: () => set('offers'), onTabKb: () => set('kb'),
onTabChannels: () => set('channels'), onTabFul: () => set('ful'),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,203 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1080px;">
<!-- ============ SIDEBAR (уровень компании) ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span><span style="font-size:11px;color:#8c8c8c;">Уровень компании</span></div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>Командный центр</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="Отделы.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>Отделы</a>
<a href="Сотрудники.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Сотрудники</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>Продукты</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/><path d="M2 13.5h2M20 13.5h2"/></svg>AI</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>Интеграции</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><line x1="3" y1="18" x2="11" y2="18"/><circle cx="13" cy="18" r="2"/></svg>Настройки</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><a href="Сотрудники.dc.html" style="font-weight:500;color:#595959;text-decoration:none;" style-hover="color:#1677ff;">Сотрудники</a><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">Анна Котова</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1080px;margin:0 auto;">
<!-- HEADER CARD -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:20px 22px;margin-bottom:18px;">
<div style="display:flex;align-items:center;gap:16px;">
<div style="width:56px;height:56px;border-radius:50%;background:#9254de;color:#fff;display:flex;align-items:center;justify-content:center;font-size:19px;font-weight:600;flex:none;">АК</div>
<div style="flex:1;min-width:0;">
<div style="display:flex;align-items:center;gap:11px;flex-wrap:wrap;">
<h1 style="margin:0;font-size:21px;font-weight:700;letter-spacing:-0.01em;color:#1f1f1f;">Анна Котова</h1>
<span style="padding:2px 9px;border-radius:6px;background:#e6f4ff;color:#0958d9;font-size:11px;font-weight:600;">OPERATOR</span>
<span style="display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:14px;background:{{ st.bg }};border:1px solid {{ st.border }};font-size:11.5px;font-weight:600;color:{{ st.color }};"><span style="width:6px;height:6px;border-radius:50%;background:{{ st.dot }};"></span>{{ st.label }}</span>
</div>
<div style="margin-top:6px;font-size:12.5px;color:#8c8c8c;font-family:'SF Mono',ui-monospace,Menlo,monospace;">a.kotova@edevs.tech · Отдел продаж</div>
</div>
<div style="display:flex;align-items:center;gap:9px;flex:none;">
<button style="height:38px;padding:0 14px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#595959;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#bfbfbf;color:#262626;">Отмена</button>
<button style="display:flex;align-items:center;gap:7px;height:38px;padding:0 18px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer;box-shadow:0 1px 2px rgba(22,119,255,0.3);" style-hover="background:#0958d9;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2Z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>Сохранить</button>
</div>
</div>
</div>
<!-- TWO COLUMN -->
<div style="display:flex;gap:18px;align-items:flex-start;">
<!-- LEFT -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;gap:16px;">
<!-- Основные данные -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 16px;font-size:14px;font-weight:700;color:#1f1f1f;">Основные данные</h3>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px;">
<div><label style="display:block;font-size:12px;color:#8c8c8c;margin-bottom:6px;font-weight:500;">Имя</label><input value="Анна Котова" style="width:100%;height:38px;padding:0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:inherit;outline:none;" style-focus="border-color:#1677ff;" /></div>
<div><label style="display:block;font-size:12px;color:#8c8c8c;margin-bottom:6px;font-weight:500;">Телефон</label><input value="+7 916 245 14 02" style="width:100%;height:38px;padding:0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:inherit;outline:none;" style-focus="border-color:#1677ff;" /></div>
<div style="grid-column:span 2;"><label style="display:block;font-size:12px;color:#8c8c8c;margin-bottom:6px;font-weight:500;">Email <span style="color:#bfbfbf;">· используется для входа</span></label><input value="a.kotova@edevs.tech" style="width:100%;height:38px;padding:0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:'SF Mono',ui-monospace,Menlo,monospace;outline:none;" style-focus="border-color:#1677ff;" /></div>
</div>
</div>
<!-- Роль и доступ -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 16px;font-size:14px;font-weight:700;color:#1f1f1f;">Роль и доступ</h3>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:16px;">
<div><label style="display:block;font-size:12px;color:#8c8c8c;margin-bottom:6px;font-weight:500;">Роль</label><div style="position:relative;"><select style="width:100%;height:38px;padding:0 30px 0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:inherit;cursor:pointer;appearance:none;-webkit-appearance:none;background:#fff;"><option>OPERATOR</option><option>OWNER</option></select><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position:absolute;right:11px;top:12px;pointer-events:none;"><polyline points="6 9 12 15 18 9"/></svg></div></div>
<div><label style="display:block;font-size:12px;color:#8c8c8c;margin-bottom:6px;font-weight:500;">Отдел</label><div style="position:relative;"><select style="width:100%;height:38px;padding:0 30px 0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:inherit;cursor:pointer;appearance:none;-webkit-appearance:none;background:#fff;"><option>Продажи</option></select><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position:absolute;right:11px;top:12px;pointer-events:none;"><polyline points="6 9 12 15 18 9"/></svg></div></div>
</div>
<label style="display:block;font-size:12px;color:#8c8c8c;margin-bottom:8px;font-weight:500;">Доступные разделы</label>
<div style="display:flex;gap:7px;flex-wrap:wrap;">
<span style="display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:7px;background:#f6ffed;border:1px solid #d9f7be;font-size:12px;font-weight:500;color:#389e0d;"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>Диалоги</span>
<span style="display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:7px;background:#f6ffed;border:1px solid #d9f7be;font-size:12px;font-weight:500;color:#389e0d;"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>Клиенты</span>
<span style="display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:7px;background:#f6ffed;border:1px solid #d9f7be;font-size:12px;font-weight:500;color:#389e0d;"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>Заказы · чтение</span>
<span style="display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:7px;background:#fafafa;border:1px solid #f0f0f0;font-size:12px;font-weight:500;color:#bfbfbf;">Финансы · нет</span>
<span style="display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:7px;background:#fafafa;border:1px solid #f0f0f0;font-size:12px;font-weight:500;color:#bfbfbf;">Настройки · нет</span>
</div>
</div>
<!-- Безопасность -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 4px;font-size:14px;font-weight:700;color:#1f1f1f;">Безопасность</h3>
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid #f5f5f5;">
<div><div style="font-size:13px;font-weight:500;color:#262626;">Пароль</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:2px;">Последняя смена: 28 мая 2026</div></div>
<button style="height:34px;padding:0 13px;border-radius:8px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:12.5px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">Сбросить пароль</button>
</div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 0;border-bottom:1px solid #f5f5f5;">
<div><div style="font-size:13px;font-weight:500;color:#262626;">Двухфакторная аутентификация (TOTP)</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:2px;">{{ totpLabel }}</div></div>
<div role="switch" onClick="{{ onToggleTotp }}" style="width:42px;height:24px;border-radius:14px;cursor:pointer;padding:2px;display:flex;align-items:center;justify-content:{{ totpJustify }};background:{{ totpBg }};flex:none;"><span style="width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,0.2);display:block;"></span></div>
</div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 0 4px;">
<div><div style="font-size:13px;font-weight:500;color:#262626;">Активные сессии</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:2px;">2 устройства · Chrome (Москва), Safari (Москва)</div></div>
<button style="height:34px;padding:0 13px;border-radius:8px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:12.5px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">Завершить все</button>
</div>
</div>
<!-- Опасная зона -->
<div style="background:#fff;border:1px solid #ffccc7;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 4px;font-size:14px;font-weight:700;color:#cf1322;">Опасная зона</h3>
<div style="display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:8px;">
<div style="font-size:12.5px;color:#595959;line-height:1.5;">{{ dangerNote }}</div>
<button style="height:38px;padding:0 16px;border-radius:9px;border:1px solid #ffccc7;background:#fff;color:#cf1322;font-size:13px;font-weight:600;cursor:pointer;flex:none;" style-hover="background:#fff2f0;">{{ blockLabel }}</button>
</div>
</div>
</div>
<!-- RIGHT RAIL -->
<div style="width:320px;flex:none;display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Статус аккаунта</h3>
<div style="display:flex;align-items:center;justify-content:space-between;padding:7px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Статус</span><span style="display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:600;color:{{ st.color }};"><span style="width:7px;height:7px;border-radius:50%;background:{{ st.dot }};"></span>{{ st.label }}</span></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:7px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Создан</span><span style="font-size:12.5px;color:#262626;">12 мая 2026</span></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:7px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Приглашение принято</span><span style="font-size:12.5px;color:#262626;">12 мая 2026</span></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:7px 0;"><span style="font-size:12.5px;color:#8c8c8c;">Последний вход</span><span style="font-size:12.5px;color:#262626;">5 мин назад</span></div>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Текущая нагрузка</h3>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:1px;background:#f0f0f0;border:1px solid #f0f0f0;border-radius:8px;overflow:hidden;">
<div style="background:#fff;padding:11px 13px;"><div style="font-size:11.5px;color:#8c8c8c;">Активные диалоги</div><div style="font-size:18px;font-weight:700;color:#262626;margin-top:3px;">3</div></div>
<div style="background:#fff;padding:11px 13px;"><div style="font-size:11.5px;color:#8c8c8c;">В очереди</div><div style="font-size:18px;font-weight:700;color:#262626;margin-top:3px;">0</div></div>
<div style="background:#fff;padding:11px 13px;"><div style="font-size:11.5px;color:#8c8c8c;">Продажи · сегодня</div><div style="font-size:18px;font-weight:700;color:#262626;margin-top:3px;">5</div></div>
<div style="background:#fff;padding:11px 13px;"><div style="font-size:11.5px;color:#8c8c8c;">Ср. ответ</div><div style="font-size:18px;font-weight:700;color:#262626;margin-top:3px;">1м 40с</div></div>
</div>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Последние действия</h3>
<div style="display:flex;flex-direction:column;gap:0;font-size:12.5px;">
<div style="display:flex;gap:10px;padding:7px 0;border-bottom:1px solid #f7f7f7;"><span style="width:6px;height:6px;border-radius:50%;background:#52c41a;margin-top:5px;flex:none;"></span><div style="flex:1;"><div style="color:#262626;">Закрыла диалог · продажа Foxray</div><div style="font-size:11px;color:#bfbfbf;margin-top:1px;">8 мин назад</div></div></div>
<div style="display:flex;gap:10px;padding:7px 0;border-bottom:1px solid #f7f7f7;"><span style="width:6px;height:6px;border-radius:50%;background:#1677ff;margin-top:5px;flex:none;"></span><div style="flex:1;"><div style="color:#262626;">Забрала диалог из очереди</div><div style="font-size:11px;color:#bfbfbf;margin-top:1px;">22 мин назад</div></div></div>
<div style="display:flex;gap:10px;padding:7px 0;"><span style="width:6px;height:6px;border-radius:50%;background:#bfbfbf;margin-top:5px;flex:none;"></span><div style="flex:1;"><div style="color:#262626;">Вход в систему · Chrome</div><div style="font-size:11px;color:#bfbfbf;margin-top:1px;">сегодня 09:02</div></div></div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 },
&quot;status&quot;: { &quot;editor&quot;: &quot;enum&quot;, &quot;options&quot;: [&quot;active&quot;, &quot;blocked&quot;], &quot;default&quot;: &quot;active&quot;, &quot;tsType&quot;: &quot;string&quot; }
}">
class Component extends DCLogic {
state = { totp: false };
renderVals() {
const S = this.props.status ?? 'active';
const st = S === 'blocked'
? { label: 'Заблокирован', color: '#cf1322', bg: '#fff2f0', border: '#ffccc7', dot: '#ff4d4f' }
: { label: 'Активен', color: '#389e0d', bg: '#f6ffed', border: '#b7eb8f', dot: '#52c41a' };
const blocked = S === 'blocked';
const totp = this.state.totp;
return {
st,
blockLabel: blocked ? 'Разблокировать сотрудника' : 'Заблокировать сотрудника',
dangerNote: blocked
? 'Сотрудник заблокирован и не может войти. Разблокировка восстановит доступ к разделам отдела.'
: 'Блокировка немедленно завершит все сессии и закроет доступ. Активные диалоги вернутся в очередь. Действие требует подтверждения.',
totpLabel: totp ? 'Включена · требуется при каждом входе' : 'Отключена для этого сотрудника',
totpJustify: totp ? 'flex-end' : 'flex-start', totpBg: totp ? '#1677ff' : '#d9d9d9',
onToggleTotp: () => this.setState((s) => ({ totp: !s.totp })),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,451 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#d9d9d9;border-radius:8px;border:2px solid #f0f2f5;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;">
<!-- ============ SIDEBAR ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg>
</div>
<div style="display:flex;flex-direction:column;line-height:1.15;">
<span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span>
<span style="font-size:11px;color:#8c8c8c;">Уровень компании</span>
</div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;">
<span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span>
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>
Командный центр
</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>
Отделы
</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
Сотрудники
</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>
Продукты
</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/><path d="M2 13.5h2M20 13.5h2"/></svg>
AI
</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>
Интеграции
</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><line x1="3" y1="18" x2="11" y2="18"/><circle cx="13" cy="18" r="2"/></svg>
Настройки
</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;">
<div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div>
<div style="display:flex;flex-direction:column;line-height:1.2;min-width:0;">
<span style="font-size:13px;font-weight:600;color:#262626;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">Иван Петров</span>
<span style="font-size:11px;color:#8c8c8c;">OWNER</span>
</div>
</a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<!-- TOP BAR -->
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;">
<span style="font-weight:500;color:#595959;">Edevs</span>
<span style="color:#d9d9d9;">/</span>
<span style="font-weight:600;color:#262626;">Командный центр</span>
</div>
<div style="display:flex;align-items:center;gap:14px;">
<div style="display:flex;align-items:center;gap:7px;padding:5px 11px;border-radius:7px;background:{{ st.bg }};border:1px solid {{ st.border }};">
<span style="width:7px;height:7px;border-radius:50%;background:{{ st.dot }};flex:none;"></span>
<span style="font-size:12.5px;font-weight:600;color:{{ st.color }};">{{ st.label }}</span>
</div>
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>
<span style="position:absolute;top:6px;right:7px;min-width:15px;height:15px;padding:0 4px;border-radius:8px;background:#ff4d4f;color:#fff;font-size:10px;font-weight:600;display:flex;align-items:center;justify-content:center;border:1.5px solid #fff;">{{ notif }}</span>
</button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<button style="display:flex;align-items:center;gap:9px;padding:4px 8px 4px 4px;border-radius:8px;border:1px solid transparent;background:transparent;cursor:pointer;" style-hover="background:#f5f5f5;">
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
</button>
</div>
</header>
<!-- SCROLL AREA -->
<main style="flex:1;overflow-y:auto;padding:24px 28px 36px;">
<div style="max-width:1200px;min-width:1040px;margin:0 auto;">
<!-- PAGE HEADER -->
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:20px;">
<div>
<h1 style="margin:0;font-size:26px;font-weight:700;letter-spacing:-0.02em;color:#1f1f1f;line-height:1.2;">Командный центр</h1>
<p style="margin:6px 0 0;font-size:13.5px;color:#8c8c8c;">Состояние компании одним взглядом · обновлено только что</p>
</div>
<div style="display:flex;align-items:center;gap:10px;flex:none;">
<div style="display:flex;align-items:center;gap:2px;padding:3px;border-radius:9px;background:#f0f2f5;">
<button onClick="{{ onToday }}" style="{{ tabToday }}">Сегодня</button>
<button onClick="{{ on7 }}" style="{{ tab7 }}">7 дней</button>
<button onClick="{{ on30 }}" style="{{ tab30 }}">30 дней</button>
</div>
<button style="display:flex;align-items:center;gap:7px;height:36px;padding:0 14px;border-radius:8px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/><path d="M3 21v-5h5"/></svg>
Обновить
</button>
</div>
</div>
<!-- COMPANY STATUS BANNER -->
<div style="display:flex;align-items:center;gap:16px;background:#fff;border:1px solid #f0f0f0;border-left:3px solid {{ st.dot }};border-radius:10px;padding:16px 20px;margin-bottom:20px;box-shadow:0 1px 2px rgba(0,0,0,0.03);">
<div style="width:42px;height:42px;border-radius:50%;background:{{ st.bg }};display:flex;align-items:center;justify-content:center;flex:none;">
<span style="width:13px;height:13px;border-radius:50%;background:{{ st.dot }};"></span>
</div>
<div style="flex:1;min-width:0;">
<div style="display:flex;align-items:center;gap:10px;">
<span style="font-size:16px;font-weight:600;color:#1f1f1f;">Компания: {{ st.label }}</span>
</div>
<p style="margin:3px 0 0;font-size:13.5px;color:#595959;">{{ compSummary }}</p>
</div>
<div style="display:flex;gap:28px;flex:none;padding-left:8px;">
<div style="text-align:right;">
<div style="font-size:12px;color:#8c8c8c;">Отделы</div>
<div style="font-size:18px;font-weight:600;color:#262626;">1</div>
</div>
<div style="text-align:right;">
<div style="font-size:12px;color:#8c8c8c;">Открытые диалоги</div>
<div style="font-size:18px;font-weight:600;color:#262626;">{{ m.open }}</div>
</div>
<div style="text-align:right;">
<div style="font-size:12px;color:#8c8c8c;">Выручка · {{ periodLabel }}</div>
<div style="font-size:18px;font-weight:600;color:#389e0d;">{{ m.rev }}</div>
</div>
</div>
</div>
<!-- TWO COLUMN -->
<div style="display:flex;gap:20px;align-items:flex-start;">
<!-- LEFT: department cards -->
<div style="flex:1;min-width:0;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;">
<h2 style="margin:0;font-size:14px;font-weight:600;color:#595959;letter-spacing:0.01em;">Отделы</h2>
<span style="font-size:12.5px;color:#bfbfbf;">1 активный</span>
</div>
<!-- DEPARTMENT CARD: Продажи -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;padding:20px 22px;box-shadow:0 1px 3px rgba(0,0,0,0.04);">
<div style="display:flex;align-items:flex-start;gap:14px;">
<div style="width:46px;height:46px;border-radius:11px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;flex:none;">
<svg viewBox="0 0 24 24" width="23" height="23" fill="none" stroke="#1677ff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/></svg>
</div>
<div style="flex:1;min-width:0;">
<div style="display:flex;align-items:center;gap:10px;">
<h3 style="margin:0;font-size:18px;font-weight:700;color:#1f1f1f;">Продажи</h3>
<span style="display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:20px;background:{{ st.bg }};border:1px solid {{ st.border }};">
<span style="width:6px;height:6px;border-radius:50%;background:{{ st.dot }};"></span>
<span style="font-size:12px;font-weight:600;color:{{ st.color }};">{{ st.label }}</span>
</span>
</div>
<div style="margin-top:4px;font-size:12.5px;color:#8c8c8c;">Ответственный: Анна Котова · 4 сотрудника · 1 AI-агент</div>
</div>
<button style="display:flex;align-items:center;gap:8px;height:38px;padding:0 16px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer;flex:none;box-shadow:0 1px 2px rgba(22,119,255,0.3);" style-hover="background:#0958d9;">
Открыть отдел
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
</button>
</div>
<div style="margin:16px 0 18px;padding:10px 14px;background:#fafafa;border-radius:8px;font-size:13px;color:#595959;line-height:1.5;">{{ deptSummary }}</div>
<!-- group: dialogs -->
<div style="font-size:11px;font-weight:600;letter-spacing:0.05em;color:#bfbfbf;margin-bottom:8px;">ДИАЛОГИ — СЕЙЧАС</div>
<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:1px;background:#f0f0f0;border:1px solid #f0f0f0;border-radius:9px;overflow:hidden;margin-bottom:16px;">
<div style="background:#fff;padding:13px 15px;">
<div style="font-size:12px;color:#8c8c8c;margin-bottom:7px;">Открытые диалоги</div>
<div style="font-size:23px;font-weight:700;color:#262626;line-height:1;">{{ m.open }}</div>
</div>
<div style="background:#fff;padding:13px 15px;">
<div style="font-size:12px;color:#8c8c8c;margin-bottom:7px;">Активны за 15 мин</div>
<div style="font-size:23px;font-weight:700;color:#262626;line-height:1;">{{ m.active }}</div>
</div>
<div style="background:#fff;padding:13px 15px;">
<div style="display:flex;align-items:center;gap:5px;margin-bottom:7px;"><span style="width:7px;height:7px;border-radius:50%;background:#722ed1;"></span><span style="font-size:12px;color:#8c8c8c;">На AI</span></div>
<div style="font-size:23px;font-weight:700;color:#262626;line-height:1;">{{ m.ai }}</div>
</div>
<div style="background:#fff;padding:13px 15px;">
<div style="display:flex;align-items:center;gap:5px;margin-bottom:7px;"><span style="width:7px;height:7px;border-radius:50%;background:#1677ff;"></span><span style="font-size:12px;color:#8c8c8c;">На операторах</span></div>
<div style="font-size:23px;font-weight:700;color:#262626;line-height:1;">{{ m.op }}</div>
</div>
<div style="background:#fff;padding:13px 15px;">
<div style="font-size:12px;color:#8c8c8c;margin-bottom:7px;">Ожидают оператора</div>
<div style="font-size:23px;font-weight:700;color:{{ m.waitColor }};line-height:1;">{{ m.wait }}</div>
</div>
</div>
<!-- group: commerce -->
<div style="font-size:11px;font-weight:600;letter-spacing:0.05em;color:#bfbfbf;margin-bottom:8px;">КОММЕРЦИЯ — {{ periodLabelUpper }}</div>
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:#f0f0f0;border:1px solid #f0f0f0;border-radius:9px;overflow:hidden;">
<div style="background:#fff;padding:13px 15px;">
<div style="font-size:12px;color:#8c8c8c;margin-bottom:7px;">Незавершённые платежи</div>
<div style="font-size:23px;font-weight:700;color:{{ m.pendColor }};line-height:1;">{{ m.pend }}</div>
</div>
<div style="background:#fff;padding:13px 15px;">
<div style="font-size:12px;color:#8c8c8c;margin-bottom:7px;">Ошибки fulfillment</div>
<div style="font-size:23px;font-weight:700;color:{{ m.ferrColor }};line-height:1;">{{ m.ferr }}</div>
</div>
<div style="background:#fff;padding:13px 15px;">
<div style="font-size:12px;color:#8c8c8c;margin-bottom:7px;">Продажи</div>
<div style="font-size:23px;font-weight:700;color:#262626;line-height:1;">{{ m.sales }}</div>
</div>
<div style="background:#fff;padding:13px 15px;">
<div style="font-size:12px;color:#8c8c8c;margin-bottom:7px;">Чистая выручка</div>
<div style="font-size:23px;font-weight:700;color:#389e0d;line-height:1;">{{ m.rev }}</div>
</div>
</div>
</div>
</div>
<!-- RIGHT RAIL -->
<div style="width:344px;flex:none;display:flex;flex-direction:column;gap:16px;">
<!-- Требует внимания -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="display:flex;align-items:center;justify-content:space-between;padding:15px 18px 12px;">
<div style="display:flex;align-items:center;gap:9px;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#faad14" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m21.7 18-8-14a2 2 0 0 0-3.5 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3Z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
<span style="font-size:14px;font-weight:600;color:#1f1f1f;">Требует внимания</span>
<span style="min-width:20px;height:20px;padding:0 6px;border-radius:10px;background:#f0f0f0;color:#595959;font-size:12px;font-weight:600;display:inline-flex;align-items:center;justify-content:center;">{{ attentionCount }}</span>
</div>
<a href="#" style="font-size:12.5px;color:#1677ff;text-decoration:none;font-weight:500;">Все</a>
</div>
<div>
<sc-for list="{{ attention }}" as="a" hint-placeholder-count="2">
<a href="#" style="display:flex;align-items:flex-start;gap:11px;padding:11px 18px;text-decoration:none;border-top:1px solid #f5f5f5;" style-hover="background:#fafafa;">
<span style="width:8px;height:8px;border-radius:50%;background:{{ a.dot }};margin-top:5px;flex:none;"></span>
<span style="flex:1;min-width:0;">
<span style="display:block;font-size:13px;font-weight:500;color:#262626;line-height:1.35;">{{ a.title }}</span>
<span style="display:block;font-size:11.5px;color:#8c8c8c;margin-top:2px;">{{ a.meta }}</span>
</span>
<span style="font-size:11.5px;color:#bfbfbf;flex:none;white-space:nowrap;">{{ a.time }}</span>
</a>
</sc-for>
</div>
</div>
<!-- Состояние интеграций -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="display:flex;align-items:center;justify-content:space-between;padding:15px 18px 12px;">
<div style="display:flex;align-items:center;gap:9px;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#595959" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>
<span style="font-size:14px;font-weight:600;color:#1f1f1f;">Состояние интеграций</span>
</div>
<span style="font-size:12px;font-weight:600;color:{{ intHeadColor }};">{{ okCount }}/6 в норме</span>
</div>
<div>
<sc-for list="{{ integrations }}" as="i" hint-placeholder-count="6">
<div style="display:flex;align-items:center;gap:11px;padding:10px 18px;border-top:1px solid #f5f5f5;">
<span style="width:8px;height:8px;border-radius:50%;background:{{ i.dot }};flex:none;"></span>
<span style="flex:1;min-width:0;">
<span style="display:block;font-size:13px;font-weight:500;color:#262626;line-height:1.25;">{{ i.name }}</span>
<span style="display:block;font-size:11px;color:#bfbfbf;">{{ i.group }}</span>
</span>
<span style="font-size:12px;font-weight:500;color:{{ i.statusColor }};flex:none;">{{ i.statusLabel }}</span>
</div>
</sc-for>
</div>
</div>
<!-- Расходы AI -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:15px 18px 16px;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
<div style="display:flex;align-items:center;gap:9px;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#722ed1" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
<span style="font-size:14px;font-weight:600;color:#1f1f1f;">Расходы AI</span>
</div>
<span style="font-size:12px;color:#bfbfbf;">{{ periodLabel }}</span>
</div>
<div style="display:flex;align-items:baseline;gap:8px;">
<span style="font-size:26px;font-weight:700;color:#1f1f1f;letter-spacing:-0.01em;">{{ aiSpendStr }}</span>
<span style="font-size:13px;color:#8c8c8c;">из {{ budgetStr }}</span>
</div>
<div style="height:6px;border-radius:999px;background:#f0f0f0;margin:11px 0 7px;overflow:hidden;">
<div style="height:6px;border-radius:999px;background:{{ aiBarColor }};width:{{ aiPct }}%;"></div>
</div>
<div style="font-size:11.5px;color:#8c8c8c;margin-bottom:14px;">{{ aiPct }}% дневного бюджета</div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:#f0f0f0;border:1px solid #f0f0f0;border-radius:8px;overflow:hidden;">
<div style="background:#fff;padding:9px 11px;">
<div style="font-size:11px;color:#8c8c8c;margin-bottom:3px;">Токены</div>
<div style="font-size:14px;font-weight:600;color:#262626;">{{ aiTokens }}</div>
</div>
<div style="background:#fff;padding:9px 11px;">
<div style="font-size:11px;color:#8c8c8c;margin-bottom:3px;">Диалоги</div>
<div style="font-size:14px;font-weight:600;color:#262626;">{{ aiDialogs }}</div>
</div>
<div style="background:#fff;padding:9px 11px;">
<div style="font-size:11px;color:#8c8c8c;margin-bottom:3px;">Цена диалога</div>
<div style="font-size:14px;font-weight:600;color:#262626;">{{ costPerDialog }}</div>
</div>
</div>
</div>
</div>
</div>
<div style="text-align:center;margin-top:24px;font-size:12px;color:#bfbfbf;">Обновлено: сегодня, 14:32 · детерминированная сводка</div>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 },
&quot;scenario&quot;: { &quot;editor&quot;: &quot;enum&quot;, &quot;options&quot;: [&quot;NORMAL&quot;, &quot;ATTENTION&quot;, &quot;CRITICAL&quot;], &quot;default&quot;: &quot;NORMAL&quot;, &quot;tsType&quot;: &quot;string&quot; },
&quot;period&quot;: { &quot;editor&quot;: &quot;enum&quot;, &quot;options&quot;: [&quot;today&quot;, &quot;d7&quot;, &quot;d30&quot;], &quot;default&quot;: &quot;today&quot;, &quot;tsType&quot;: &quot;string&quot; }
}">
class Component extends DCLogic {
state = { period: null };
renderVals() {
const S = this.props.scenario ?? 'NORMAL';
const period = this.state.period ?? this.props.period ?? 'today';
const fmt = (n) => '₽' + Math.round(n).toLocaleString('ru-RU').replace(/\u00a0/g, ' ');
const ops = {
NORMAL: { open: 42, active: 9, ai: 35, op: 7, wait: 0, pend: 1, ferr: 0 },
ATTENTION: { open: 58, active: 14, ai: 41, op: 13, wait: 4, pend: 3, ferr: 0 },
CRITICAL: { open: 73, active: 22, ai: 29, op: 35, wait: 9, pend: 5, ferr: 3 },
}[S];
const com = {
today: { label: 'Сегодня', sales: 18, rev: 146200, aiSpend: 1240, budget: 5000, tokens: '412K', dlg: 42 },
d7: { label: '7 дней', sales: 126, rev: 1024600, aiSpend: 8600, budget: 35000, tokens: '2,9M', dlg: 318 },
d30: { label: '30 дней', sales: 540, rev: 4386000, aiSpend: 36400, budget: 150000, tokens: '12,4M', dlg: 1342 },
}[period];
const st = {
NORMAL: { label: 'Нормально', color: '#389e0d', bg: '#f6ffed', border: '#b7eb8f', dot: '#52c41a' },
ATTENTION: { label: 'Требует внимания', color: '#d48806', bg: '#fffbe6', border: '#ffe58f', dot: '#faad14' },
CRITICAL: { label: 'Критично', color: '#cf1322', bg: '#fff2f0', border: '#ffccc7', dot: '#ff4d4f' },
}[S];
const warn = S === 'CRITICAL' ? '#cf1322' : '#d48806';
const m = {
open: String(ops.open), active: String(ops.active), ai: String(ops.ai), op: String(ops.op),
wait: String(ops.wait), pend: String(ops.pend), ferr: String(ops.ferr),
sales: String(com.sales), rev: fmt(com.rev),
waitColor: ops.wait > 0 ? warn : '#262626',
pendColor: ops.pend > 2 ? warn : '#262626',
ferrColor: ops.ferr > 0 ? '#cf1322' : '#262626',
};
const compSummary = {
NORMAL: 'Все системы в норме. Один отдел активен, критичных событий нет.',
ATTENTION: 'Отдел продаж требует внимания оператора. Критических сбоев нет.',
CRITICAL: 'Критические проблемы в отделе продаж: сбой исполнения и переполненная очередь.',
}[S];
const deptSummary = {
NORMAL: 'AI ведёт большинство диалогов. Очередь оператора пуста, незавершённых задач почти нет.',
ATTENTION: 'Очередь оператора растёт, есть незавершённые платежи. Нужна реакция оператора.',
CRITICAL: 'Сбой исполнения заказов и переполненная очередь операторов. Требуется немедленное вмешательство.',
}[S];
const attentionBy = {
NORMAL: [
{ dot: '#faad14', title: 'Незавершённый платёж · заказ ORD-10482', meta: 'Продажи · Точка', time: '6 мин' },
{ dot: '#1677ff', title: 'Подписка истекает через 2 дня · Foxray Pro', meta: 'Продажи', time: '1 ч' },
],
ATTENTION: [
{ dot: '#faad14', title: 'Очередь оператора: 4 диалога ждут более 10 мин', meta: 'Продажи', time: '3 мин' },
{ dot: '#faad14', title: 'Незавершённые платежи: 3 заказа', meta: 'Точка', time: '12 мин' },
{ dot: '#faad14', title: 'Интеграция Точка: деградация ответа', meta: 'Платежи', time: '18 мин' },
{ dot: '#1677ff', title: 'Подписка истекает через 2 дня · Foxray Pro', meta: 'Продажи', time: '1 ч' },
],
CRITICAL: [
{ dot: '#ff4d4f', title: 'Ошибка fulfillment · 3 заказа не исполнены', meta: 'FirePage · Исполнение', time: '2 мин' },
{ dot: '#ff4d4f', title: 'Очередь оператора: 9 диалогов без ответа', meta: 'Продажи', time: '5 мин' },
{ dot: '#faad14', title: 'Незавершённые платежи: 5 заказов', meta: 'Точка', time: '9 мин' },
],
}[S];
const ok = { dot: '#52c41a', statusLabel: 'Подключено', statusColor: '#52c41a' };
const deg = { dot: '#faad14', statusLabel: 'Деградация', statusColor: '#d48806' };
const err = { dot: '#ff4d4f', statusLabel: 'Ошибка', statusColor: '#cf1322' };
const base = [
{ name: 'OpenRouter', group: 'AI-провайдер' },
{ name: 'Точка', group: 'Платежи и фискализация' },
{ name: 'MAX', group: 'Канал' },
{ name: 'Telegram', group: 'Канал' },
{ name: 'Web Chat', group: 'Канал' },
{ name: 'Fulfillment · FirePage', group: 'Исполнение' },
];
const stateByScenario = {
NORMAL: [ok, ok, ok, ok, ok, ok],
ATTENTION: [ok, deg, ok, ok, ok, ok],
CRITICAL: [ok, deg, ok, ok, ok, err],
}[S];
const integrations = base.map((b, idx) => ({ ...b, ...stateByScenario[idx] }));
const okCount = stateByScenario.filter((x) => x === ok).length;
const intHeadColor = okCount === 6 ? '#389e0d' : (S === 'CRITICAL' ? '#cf1322' : '#d48806');
const aiPct = Math.round((com.aiSpend / com.budget) * 100);
const aiBarColor = aiPct >= 85 ? '#ff4d4f' : (aiPct >= 70 ? '#faad14' : '#1677ff');
const baseTab = 'padding:6px 15px;border:none;border-radius:7px;font-size:13px;font-weight:500;cursor:pointer;background:transparent;color:#595959;transition:all .15s;';
const actTab = 'padding:6px 15px;border:none;border-radius:7px;font-size:13px;font-weight:600;cursor:pointer;background:#ffffff;color:#1f1f1f;box-shadow:0 1px 2px rgba(0,0,0,0.1);';
const setP = (p) => this.setState({ period: p });
return {
m, st, compSummary, deptSummary,
attention: attentionBy, attentionCount: String(attentionBy.length),
integrations, okCount: String(okCount), intHeadColor,
periodLabel: com.label, periodLabelUpper: com.label.toUpperCase(),
aiSpendStr: fmt(com.aiSpend), budgetStr: fmt(com.budget), aiPct, aiBarColor,
aiTokens: com.tokens, aiDialogs: String(com.dlg), costPerDialog: fmt(com.aiSpend / com.dlg),
notif: S === 'CRITICAL' ? '7' : (S === 'ATTENTION' ? '4' : '2'),
tabToday: period === 'today' ? actTab : baseTab,
tab7: period === 'd7' ? actTab : baseTab,
tab30: period === 'd30' ? actTab : baseTab,
onToday: () => setP('today'), on7: () => setP('d7'), on30: () => setP('d30'),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,246 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1080px;">
<!-- ============ SIDEBAR (уровень компании) ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span><span style="font-size:11px;color:#8c8c8c;">Уровень компании</span></div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>Командный центр</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="Отделы.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>Отделы</a>
<a href="Сотрудники.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Сотрудники</a>
<a href="Продукты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>Продукты</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="AI-агенты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/></svg>AI</a>
<a href="Интеграции.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>Интеграции</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><line x1="3" y1="18" x2="11" y2="18"/><circle cx="13" cy="18" r="2"/></svg>Настройки</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">Настройки</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1080px;margin:0 auto;">
<div style="margin-bottom:20px;">
<h1 style="margin:0;font-size:24px;font-weight:700;letter-spacing:-0.02em;color:#1f1f1f;line-height:1.2;">Настройки</h1>
<p style="margin:6px 0 0;font-size:13.5px;color:#8c8c8c;">Конфигурация компании и платформы</p>
</div>
<div style="display:flex;gap:24px;align-items:flex-start;">
<!-- section nav -->
<div style="width:230px;flex:none;position:sticky;top:0;">
<sc-for list="{{ sections }}" as="s" hint-placeholder-count="5">
<button onClick="{{ s.onPick }}" style="{{ s.style }}">
<span style="flex:none;">{{ s.icon }}</span>
<span style="flex:1;text-align:left;">{{ s.label }}</span>
<sc-if value="{{ s.warn }}" hint-placeholder-val="{{ false }}"><span style="width:7px;height:7px;border-radius:50%;background:#faad14;flex:none;"></span></sc-if>
</button>
</sc-for>
</div>
<!-- content -->
<div style="flex:1;min-width:0;">
<!-- ОРГАНИЗАЦИЯ -->
<sc-if value="{{ isOrg }}" hint-placeholder-val="{{ true }}">
<div style="display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 16px;font-size:14px;font-weight:700;color:#1f1f1f;">Реквизиты</h3>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px;">
<div style="grid-column:span 2;"><label style="display:block;font-size:12px;color:#8c8c8c;margin-bottom:6px;font-weight:500;">Название компании</label><input value="ООО «Эдевс»" style="width:100%;height:38px;padding:0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:inherit;outline:none;" style-focus="border-color:#1677ff;" /></div>
<div><label style="display:block;font-size:12px;color:#8c8c8c;margin-bottom:6px;font-weight:500;">ИНН</label><input value="7701234567" style="width:100%;height:38px;padding:0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:'SF Mono',ui-monospace,Menlo,monospace;outline:none;" style-focus="border-color:#1677ff;" /></div>
<div><label style="display:block;font-size:12px;color:#8c8c8c;margin-bottom:6px;font-weight:500;">КПП</label><input value="770101001" style="width:100%;height:38px;padding:0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:'SF Mono',ui-monospace,Menlo,monospace;outline:none;" style-focus="border-color:#1677ff;" /></div>
</div>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 16px;font-size:14px;font-weight:700;color:#1f1f1f;">Брендинг и локаль</h3>
<div style="display:flex;align-items:center;gap:14px;margin-bottom:16px;"><div style="width:48px;height:48px;border-radius:11px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div><div style="flex:1;"><div style="font-size:13px;font-weight:500;color:#262626;">Логотип Hub</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:1px;">PNG или SVG, до 1 МБ</div></div><button style="height:34px;padding:0 13px;border-radius:8px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:12.5px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">Заменить</button></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px;">
<div><label style="display:block;font-size:12px;color:#8c8c8c;margin-bottom:6px;font-weight:500;">Часовой пояс</label><div style="position:relative;"><select style="width:100%;height:38px;padding:0 30px 0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:inherit;cursor:pointer;appearance:none;-webkit-appearance:none;background:#fff;"><option>Europe/Moscow (UTC+3)</option></select><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position:absolute;right:11px;top:12px;pointer-events:none;"><polyline points="6 9 12 15 18 9"/></svg></div></div>
<div><label style="display:block;font-size:12px;color:#8c8c8c;margin-bottom:6px;font-weight:500;">Валюта</label><div style="position:relative;"><select style="width:100%;height:38px;padding:0 30px 0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:inherit;cursor:pointer;appearance:none;-webkit-appearance:none;background:#fff;"><option>RUB · ₽</option></select><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position:absolute;right:11px;top:12px;pointer-events:none;"><polyline points="6 9 12 15 18 9"/></svg></div></div>
</div>
</div>
<div style="display:flex;justify-content:flex-end;gap:10px;"><button style="height:38px;padding:0 16px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#595959;font-size:13px;font-weight:500;cursor:pointer;">Отмена</button><button style="height:38px;padding:0 18px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer;box-shadow:0 1px 2px rgba(22,119,255,0.3);">Сохранить</button></div>
</div>
</sc-if>
<!-- НАЛОГОВЫЙ ПРОФИЛЬ -->
<sc-if value="{{ isTax }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;flex-direction:column;gap:16px;">
<div style="display:flex;align-items:center;gap:11px;padding:12px 16px;background:#fffbe6;border:1px solid #ffe58f;border-radius:10px;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#d48806" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" style="flex:none;"><path d="m21.7 18-8-14a2 2 0 0 0-3.5 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3Z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
<span style="font-size:12.5px;color:#7c5a00;">Не указан резервный канал доставки чеков (ОФД email). Конфигурация считается неполной — чеки уходят только основным способом.</span>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Текущий фискальный профиль</h3><span style="padding:2px 10px;border-radius:14px;background:#f6ffed;border:1px solid #b7eb8f;font-size:11.5px;font-weight:600;color:#389e0d;">Активен · v2</span></div>
<div style="display:grid;grid-template-columns:repeat(2,1fr);gap:14px 24px;">
<div><div style="font-size:11.5px;color:#8c8c8c;">Режим налогообложения</div><div style="font-size:13.5px;font-weight:600;color:#262626;margin-top:3px;">УСН «Доходы»</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Ставка НДС</div><div style="font-size:13.5px;font-weight:600;color:#262626;margin-top:3px;">20%</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Признак способа расчёта</div><div style="font-size:13.5px;font-weight:600;color:#262626;margin-top:3px;">Полный расчёт</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Период действия</div><div style="font-size:13.5px;font-weight:600;color:#262626;margin-top:3px;">с 01 янв 2026</div></div>
</div>
<div style="margin-top:16px;padding-top:14px;border-top:1px solid #f5f5f5;font-size:12px;color:#8c8c8c;line-height:1.5;">Изменение фискального профиля создаёт новую версию — прошлые чеки сохраняют профиль, действовавший на момент продажи.</div>
</div>
<div style="display:flex;justify-content:flex-end;gap:10px;"><button style="height:38px;padding:0 16px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">История версий</button><button style="height:38px;padding:0 18px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer;box-shadow:0 1px 2px rgba(22,119,255,0.3);">Новая версия профиля</button></div>
</div>
</sc-if>
<!-- БЕЗОПАСНОСТЬ -->
<sc-if value="{{ isSec }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 4px;font-size:14px;font-weight:700;color:#1f1f1f;">Политика паролей</h3>
<div style="display:flex;align-items:center;justify-content:space-between;padding:13px 0;border-bottom:1px solid #f5f5f5;"><div><div style="font-size:13px;color:#262626;font-weight:500;">Минимальная длина</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:1px;">символов в пароле</div></div><div style="position:relative;"><select style="height:36px;padding:0 30px 0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:inherit;cursor:pointer;appearance:none;-webkit-appearance:none;background:#fff;"><option>10</option><option>8</option><option>12</option></select><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position:absolute;right:11px;top:12px;pointer-events:none;"><polyline points="6 9 12 15 18 9"/></svg></div></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:13px 0 4px;"><div><div style="font-size:13px;color:#262626;font-weight:500;">Требовать спецсимволы и цифры</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:1px;">усложнённая сложность пароля</div></div><div role="switch" onClick="{{ onTogglePwd }}" style="width:42px;height:24px;border-radius:14px;cursor:pointer;padding:2px;display:flex;align-items:center;justify-content:{{ pwdJustify }};background:{{ pwdBg }};flex:none;"><span style="width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,0.2);display:block;"></span></div></div>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 4px;font-size:14px;font-weight:700;color:#1f1f1f;">Доступ и сессии</h3>
<div style="display:flex;align-items:center;justify-content:space-between;padding:13px 0;border-bottom:1px solid #f5f5f5;"><div><div style="font-size:13px;color:#262626;font-weight:500;">TOTP владельца</div><div style="font-size:11.5px;color:#389e0d;margin-top:1px;">включена</div></div><div role="switch" onClick="{{ onToggleTotp }}" style="width:42px;height:24px;border-radius:14px;cursor:pointer;padding:2px;display:flex;align-items:center;justify-content:{{ totpJustify }};background:{{ totpBg }};flex:none;"><span style="width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,0.2);display:block;"></span></div></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:13px 0;border-bottom:1px solid #f5f5f5;"><div><div style="font-size:13px;color:#262626;font-weight:500;">Длительность сессии</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:1px;">до повторного входа</div></div><div style="position:relative;"><select style="height:36px;padding:0 30px 0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:inherit;cursor:pointer;appearance:none;-webkit-appearance:none;background:#fff;"><option>8 часов</option><option>4 часа</option><option>24 часа</option></select><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position:absolute;right:11px;top:12px;pointer-events:none;"><polyline points="6 9 12 15 18 9"/></svg></div></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:13px 0 4px;"><div><div style="font-size:13px;color:#262626;font-weight:500;">Активные сессии</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:1px;">5 устройств у сотрудников</div></div><button style="height:34px;padding:0 13px;border-radius:8px;border:1px solid #ffccc7;background:#fff;color:#cf1322;font-size:12.5px;font-weight:500;cursor:pointer;" style-hover="background:#fff2f0;">Завершить все</button></div>
</div>
</div>
</sc-if>
<!-- УВЕДОМЛЕНИЯ -->
<sc-if value="{{ isNotif }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 14px;font-size:14px;font-weight:700;color:#1f1f1f;">Категории уведомлений</h3>
<sc-for list="{{ notifRows }}" as="n" hint-placeholder-count="4">
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-top:1px solid #f5f5f5;"><div><div style="font-size:13px;color:#262626;font-weight:500;">{{ n.label }}</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:1px;">{{ n.desc }}</div></div><div role="switch" onClick="{{ n.onToggle }}" style="width:42px;height:24px;border-radius:14px;cursor:pointer;padding:2px;display:flex;align-items:center;justify-content:{{ n.justify }};background:{{ n.bg }};flex:none;"><span style="width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,0.2);display:block;"></span></div></div>
</sc-for>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 4px;font-size:14px;font-weight:700;color:#1f1f1f;">Для операторов</h3>
<div style="display:flex;align-items:center;justify-content:space-between;padding:13px 0;border-bottom:1px solid #f5f5f5;"><div style="font-size:13px;color:#262626;font-weight:500;">Звуковое уведомление о новом диалоге</div><div role="switch" onClick="{{ onToggleSound }}" style="width:42px;height:24px;border-radius:14px;cursor:pointer;padding:2px;display:flex;align-items:center;justify-content:{{ soundJustify }};background:{{ soundBg }};flex:none;"><span style="width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,0.2);display:block;"></span></div></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:13px 0 4px;"><div style="font-size:13px;color:#262626;font-weight:500;">Browser notifications</div><div role="switch" onClick="{{ onToggleBrowser }}" style="width:42px;height:24px;border-radius:14px;cursor:pointer;padding:2px;display:flex;align-items:center;justify-content:{{ browserJustify }};background:{{ browserBg }};flex:none;"><span style="width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,0.2);display:block;"></span></div></div>
</div>
</div>
</sc-if>
<!-- ХРАНЕНИЕ ДАННЫХ -->
<sc-if value="{{ isData }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 16px;font-size:14px;font-weight:700;color:#1f1f1f;">Сроки хранения (retention)</h3>
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-top:1px solid #f5f5f5;"><div><div style="font-size:13px;color:#262626;font-weight:500;">Диалоги и сообщения</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:1px;">после закрытия диалога</div></div><div style="position:relative;"><select style="height:36px;padding:0 30px 0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:inherit;cursor:pointer;appearance:none;-webkit-appearance:none;background:#fff;"><option>12 месяцев</option><option>6 месяцев</option><option>24 месяца</option></select><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position:absolute;right:11px;top:12px;pointer-events:none;"><polyline points="6 9 12 15 18 9"/></svg></div></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-top:1px solid #f5f5f5;"><div><div style="font-size:13px;color:#262626;font-weight:500;">Вложения</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:1px;">файлы из диалогов</div></div><div style="position:relative;"><select style="height:36px;padding:0 30px 0 12px;border:1px solid #e8e8e8;border-radius:8px;font-size:13px;color:#262626;font-family:inherit;cursor:pointer;appearance:none;-webkit-appearance:none;background:#fff;"><option>6 месяцев</option><option>3 месяца</option><option>12 месяцев</option></select><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="position:absolute;right:11px;top:12px;pointer-events:none;"><polyline points="6 9 12 15 18 9"/></svg></div></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 0 4px;border-top:1px solid #f5f5f5;"><div><div style="font-size:13px;color:#262626;font-weight:500;">Автообезличивание неактивных контактов</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:1px;">через 24 месяца без активности</div></div><div role="switch" onClick="{{ onToggleAnon }}" style="width:42px;height:24px;border-radius:14px;cursor:pointer;padding:2px;display:flex;align-items:center;justify-content:{{ anonJustify }};background:{{ anonBg }};flex:none;"><span style="width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,0.2);display:block;"></span></div></div>
</div>
<div style="display:flex;align-items:flex-start;gap:11px;padding:14px 16px;background:#f7faff;border:1px solid #d6e4ff;border-radius:10px;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#1677ff" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" style="flex:none;margin-top:1px;"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
<span style="font-size:12.5px;color:#0958d9;line-height:1.5;">Обязательные финансовые записи (заказы, платежи, чеки) хранятся бессрочно по требованиям законодательства и не удаляются автоматически.</span>
</div>
</div>
</sc-if>
</div>
</div>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 }
}">
class Component extends DCLogic {
state = {
section: 'org',
pwd: true, totp: true, sound: true, browser: false, anon: true,
notif: { sale: true, payErr: true, handoff: true, integration: true },
};
renderVals() {
const icon = (path) => React.createElement('svg', { viewBox: '0 0 24 24', width: 17, height: 17, fill: 'none', stroke: 'currentColor', strokeWidth: 1.7, strokeLinecap: 'round', strokeLinejoin: 'round' }, ...path);
const icons = {
org: icon([React.createElement('path', { key: 1, d: 'M3 21h18' }), React.createElement('path', { key: 2, d: 'M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16' }), React.createElement('path', { key: 3, d: 'M9 9h1M14 9h1M9 13h1M14 13h1' })]),
tax: icon([React.createElement('path', { key: 1, d: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z' }), React.createElement('path', { key: 2, d: 'M14 2v6h6' }), React.createElement('path', { key: 3, d: 'M9 15l6-6M9.5 9.5h.01M14.5 14.5h.01' })]),
sec: icon([React.createElement('path', { key: 1, d: 'M12 2 4 5v6c0 5 3.4 8.5 8 10 4.6-1.5 8-5 8-10V5Z' })]),
notif: icon([React.createElement('path', { key: 1, d: 'M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9' }), React.createElement('path', { key: 2, d: 'M10.3 21a1.94 1.94 0 0 0 3.4 0' })]),
data: icon([React.createElement('ellipse', { key: 1, cx: 12, cy: 5, rx: 9, ry: 3 }), React.createElement('path', { key: 2, d: 'M3 5v14a9 3 0 0 0 18 0V5' }), React.createElement('path', { key: 3, d: 'M3 12a9 3 0 0 0 18 0' })]),
};
const sec = this.state.section;
const navBase = 'width:100%;display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:9px;border:none;background:transparent;color:#595959;font-size:13.5px;font-weight:500;cursor:pointer;margin-bottom:3px;';
const navAct = 'width:100%;display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:9px;border:none;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;cursor:pointer;margin-bottom:3px;';
const secs = [
{ id: 'org', label: 'Организация', warn: false },
{ id: 'tax', label: 'Налоговый профиль', warn: true },
{ id: 'sec', label: 'Безопасность', warn: false },
{ id: 'notif', label: 'Уведомления', warn: false },
{ id: 'data', label: 'Хранение данных', warn: false },
];
const sections = secs.map((s) => ({
label: s.label, warn: s.warn, icon: icons[s.id],
style: sec === s.id ? navAct : navBase,
onPick: () => this.setState({ section: s.id }),
}));
const sw = (on) => ({ justify: on ? 'flex-end' : 'flex-start', bg: on ? '#1677ff' : '#d9d9d9' });
const p = sw(this.state.pwd), t = sw(this.state.totp), so = sw(this.state.sound), br = sw(this.state.browser), an = sw(this.state.anon);
const N = this.state.notif;
const notifMeta = [
{ id: 'sale', label: 'Новая продажа', desc: 'оформлен и оплачен заказ' },
{ id: 'payErr', label: 'Ошибка платежа / fulfillment', desc: 'сбой исполнения или незавершённый платёж' },
{ id: 'handoff', label: 'Передача оператору', desc: 'AI передал диалог человеку' },
{ id: 'integration', label: 'Сбой интеграции', desc: 'degraded или error внешнего сервиса' },
];
const notifRows = notifMeta.map((n) => {
const s = sw(N[n.id]);
return { label: n.label, desc: n.desc, justify: s.justify, bg: s.bg, onToggle: () => this.setState((st) => ({ notif: { ...st.notif, [n.id]: !st.notif[n.id] } })) };
});
return {
sections,
isOrg: sec === 'org', isTax: sec === 'tax', isSec: sec === 'sec', isNotif: sec === 'notif', isData: sec === 'data',
pwdJustify: p.justify, pwdBg: p.bg, totpJustify: t.justify, totpBg: t.bg,
soundJustify: so.justify, soundBg: so.bg, browserJustify: br.justify, browserBg: br.bg, anonJustify: an.justify, anonBg: an.bg,
notifRows,
onTogglePwd: () => this.setState((s) => ({ pwd: !s.pwd })),
onToggleTotp: () => this.setState((s) => ({ totp: !s.totp })),
onToggleSound: () => this.setState((s) => ({ sound: !s.sound })),
onToggleBrowser: () => this.setState((s) => ({ browser: !s.browser })),
onToggleAnon: () => this.setState((s) => ({ anon: !s.anon })),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,141 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1040px;">
<!-- ============ SIDEBAR (уровень компании) ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span><span style="font-size:11px;color:#8c8c8c;">Уровень компании</span></div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>Командный центр</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>Отделы</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Сотрудники</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>Продукты</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/><path d="M2 13.5h2M20 13.5h2"/></svg>AI</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>Интеграции</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><line x1="3" y1="18" x2="11" y2="18"/><circle cx="13" cy="18" r="2"/></svg>Настройки</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">Отделы</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<button style="display:flex;align-items:center;gap:9px;padding:4px 8px 4px 4px;border-radius:8px;border:1px solid transparent;background:transparent;cursor:pointer;" style-hover="background:#f5f5f5;"><div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1180px;margin:0 auto;">
<!-- PAGE HEADER -->
<div style="margin-bottom:20px;">
<h1 style="margin:0;font-size:24px;font-weight:700;letter-spacing:-0.02em;color:#1f1f1f;line-height:1.2;">Отделы</h1>
<p style="margin:6px 0 0;font-size:13.5px;color:#8c8c8c;">Существующие отделы компании · 1 активный</p>
</div>
<!-- DEPARTMENT CARD -->
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(380px,460px));gap:18px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:14px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<!-- header -->
<div style="padding:20px 22px 16px;">
<div style="display:flex;align-items:flex-start;gap:14px;">
<div style="width:48px;height:48px;border-radius:12px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="#1677ff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/></svg></div>
<div style="flex:1;min-width:0;">
<div style="display:flex;align-items:center;gap:10px;">
<h2 style="margin:0;font-size:19px;font-weight:700;color:#1f1f1f;">Продажи</h2>
<span style="display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:16px;background:{{ st.bg }};border:1px solid {{ st.border }};"><span style="width:6px;height:6px;border-radius:50%;background:{{ st.dot }};"></span><span style="font-size:11.5px;font-weight:600;color:{{ st.color }};">{{ st.label }}</span></span>
</div>
<p style="margin:5px 0 0;font-size:12.5px;color:#8c8c8c;line-height:1.45;">{{ summary }}</p>
</div>
</div>
</div>
<!-- meta -->
<div style="padding:0 22px 16px;display:flex;flex-direction:column;gap:13px;">
<div style="display:flex;align-items:center;justify-content:space-between;">
<span style="font-size:12.5px;color:#8c8c8c;">Ответственный</span>
<span style="display:inline-flex;align-items:center;gap:8px;"><span style="width:24px;height:24px;border-radius:50%;background:#9254de;color:#fff;display:flex;align-items:center;justify-content:center;font-size:10.5px;font-weight:600;">АК</span><span style="font-size:13px;font-weight:500;color:#262626;">Анна Котова</span></span>
</div>
<div style="display:flex;align-items:center;justify-content:space-between;">
<span style="font-size:12.5px;color:#8c8c8c;">Состав</span>
<span style="font-size:13px;font-weight:500;color:#262626;">4 сотрудника · 1 AI-агент</span>
</div>
<div style="display:flex;align-items:center;justify-content:space-between;">
<span style="font-size:12.5px;color:#8c8c8c;">Связанные продукты</span>
<span style="display:flex;gap:6px;"><span style="padding:2px 9px;border-radius:6px;background:#e6f4ff;color:#0958d9;font-size:11.5px;font-weight:600;">FirePage</span><span style="padding:2px 9px;border-radius:6px;background:#f9f0ff;color:#722ed1;font-size:11.5px;font-weight:600;">Foxray</span></span>
</div>
</div>
<!-- metrics -->
<div style="border-top:1px solid #f5f5f5;display:grid;grid-template-columns:repeat(3,1fr);">
<div style="padding:14px 16px;border-right:1px solid #f5f5f5;"><div style="font-size:11.5px;color:#8c8c8c;">Открытые диалоги</div><div style="font-size:19px;font-weight:700;color:#262626;margin-top:5px;">{{ open }}</div></div>
<div style="padding:14px 16px;border-right:1px solid #f5f5f5;"><div style="font-size:11.5px;color:#8c8c8c;">Продажи · сегодня</div><div style="font-size:19px;font-weight:700;color:#262626;margin-top:5px;">{{ sales }}</div></div>
<div style="padding:14px 16px;"><div style="font-size:11.5px;color:#8c8c8c;">Выручка</div><div style="font-size:19px;font-weight:700;color:#389e0d;margin-top:5px;">{{ rev }}</div></div>
</div>
<!-- action -->
<div style="padding:14px 22px 18px;border-top:1px solid #f5f5f5;">
<a href="Продажи · Обзор.dc.html" style="display:flex;align-items:center;justify-content:center;gap:8px;height:40px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer;text-decoration:none;box-shadow:0 1px 2px rgba(22,119,255,0.3);" style-hover="background:#0958d9;">Открыть отдел<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg></a>
</div>
</div>
</div>
<p style="margin:18px 0 0;font-size:12.5px;color:#bfbfbf;">Новые отделы появятся здесь по мере их создания.</p>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 900 },
&quot;scenario&quot;: { &quot;editor&quot;: &quot;enum&quot;, &quot;options&quot;: [&quot;NORMAL&quot;, &quot;ATTENTION&quot;, &quot;CRITICAL&quot;], &quot;default&quot;: &quot;NORMAL&quot;, &quot;tsType&quot;: &quot;string&quot; }
}">
class Component extends DCLogic {
renderVals() {
const S = this.props.scenario ?? 'NORMAL';
const st = {
NORMAL: { label: 'Нормально', color: '#389e0d', bg: '#f6ffed', border: '#b7eb8f', dot: '#52c41a' },
ATTENTION: { label: 'Требует внимания', color: '#d48806', bg: '#fffbe6', border: '#ffe58f', dot: '#faad14' },
CRITICAL: { label: 'Критично', color: '#cf1322', bg: '#fff2f0', border: '#ffccc7', dot: '#ff4d4f' },
}[S];
const data = {
NORMAL: { summary: 'AI ведёт большинство диалогов, очередь оператора пуста.', open: '42', sales: '18', rev: '₽146 200' },
ATTENTION: { summary: 'Очередь оператора растёт, есть незавершённые платежи.', open: '58', sales: '16', rev: '₽132 000' },
CRITICAL: { summary: 'Сбой исполнения и переполненная очередь операторов.', open: '73', sales: '12', rev: '₽98 400' },
}[S];
return { st, ...data };
}
}
</script>
</body>
</html>
@@ -0,0 +1,523 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:8px;height:8px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid transparent;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
@keyframes hubTyping{0%,80%,100%{opacity:.25;transform:translateY(0);}40%{opacity:1;transform:translateY(-2px);}}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1400px;">
<!-- ============ SIDEBAR (отдел продаж) ============ -->
<aside style="width:240px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;padding:0 14px;border-bottom:1px solid #f5f5f5;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:9px;height:36px;padding:0 12px;border-radius:8px;text-decoration:none;color:#595959;font-size:13px;font-weight:500;border:1px solid #f0f0f0;width:100%;" style-hover="background:#f5f5f5;color:#1677ff;border-color:#d9d9d9;">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
Назад в Hub
</a>
</div>
<div style="padding:16px 16px 8px;">
<div style="display:flex;align-items:center;gap:11px;">
<div style="width:34px;height:34px;border-radius:9px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;flex:none;">
<svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="#1677ff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/></svg>
</div>
<div style="display:flex;flex-direction:column;line-height:1.15;">
<span style="font-size:15px;font-weight:700;color:#1f1f1f;">Продажи</span>
<span style="font-size:11px;color:#8c8c8c;">Рабочее пространство</span>
</div>
</div>
</div>
<nav style="flex:1;overflow-y:auto;padding:8px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 13h8V3H3zM13 21h8V11h-8zM13 3v6h8V3zM3 17h8v4H3z"/></svg>
Обзор
</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;">
<span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span>
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
Диалоги
<span style="margin-left:auto;min-width:20px;height:20px;padding:0 6px;border-radius:10px;background:#faad14;color:#fff;font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;">2</span>
</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
Клиенты
</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h2l2.6 12.4a2 2 0 0 0 2 1.6h9.7a2 2 0 0 0 2-1.6L23 6H6"/><circle cx="9" cy="20" r="1"/><circle cx="18" cy="20" r="1"/></svg>
Продажи
</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;">
<div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div>
<div style="display:flex;flex-direction:column;line-height:1.2;min-width:0;">
<span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span>
<span style="font-size:11px;color:#8c8c8c;">OWNER</span>
</div>
</a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<!-- TOP BAR -->
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;">
<span style="font-weight:500;color:#595959;">Edevs</span>
<span style="color:#d9d9d9;">/</span>
<span style="font-weight:500;color:#595959;">Продажи</span>
<span style="color:#d9d9d9;">/</span>
<span style="font-weight:600;color:#262626;">Диалоги</span>
</div>
<div style="display:flex;align-items:center;gap:14px;">
<span style="display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:6px;background:#f5f5f5;font-size:12px;font-weight:600;color:#595959;">
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 5v6c0 5 3.4 8.5 8 10 4.6-1.5 8-5 8-10V5Z"/></svg>
OWNER
</span>
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>
<span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span>
</button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<!-- ============ INBOX: 3 panels ============ -->
<div style="flex:1;min-height:0;display:flex;overflow:hidden;">
<!-- ---- LEFT: conversation list ---- -->
<section style="width:344px;flex:none;background:#fff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;min-height:0;">
<div style="flex:none;padding:14px 16px 10px;border-bottom:1px solid #f5f5f5;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:11px;">
<h2 style="margin:0;font-size:16px;font-weight:700;color:#1f1f1f;">Диалоги</h2>
<span style="font-size:12px;color:#8c8c8c;">{{ totalCount }} всего</span>
</div>
<div style="display:flex;align-items:center;gap:8px;height:34px;padding:0 11px;border:1px solid #e8e8e8;border-radius:8px;background:#fafafa;" style-focus="border-color:#1677ff;">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="#bfbfbf" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input placeholder="Поиск по клиенту, продукту…" style="border:none;outline:none;background:transparent;font-size:13px;color:#262626;width:100%;font-family:inherit;" />
</div>
</div>
<!-- filter tabs -->
<div style="flex:none;display:flex;gap:4px;padding:10px 12px;border-bottom:1px solid #f5f5f5;overflow-x:auto;">
<button onClick="{{ onTabAll }}" style="{{ tabAll }}">Все</button>
<button onClick="{{ onTabWait }}" style="{{ tabWait }}">Ждут оператора <span style="margin-left:5px;padding:0 5px;border-radius:8px;background:#fff7e6;color:#d48806;font-size:11px;font-weight:700;">2</span></button>
<button onClick="{{ onTabAI }}" style="{{ tabAI }}">AI</button>
<button onClick="{{ onTabOp }}" style="{{ tabOp }}">Оператор</button>
<button onClick="{{ onTabUnread }}" style="{{ tabUnread }}">Непрочитанные</button>
</div>
<!-- list -->
<div style="flex:1;overflow-y:auto;">
<sc-for list="{{ list }}" as="c" hint-placeholder-count="6">
<a href="#" onClick="{{ c.onSelect }}" style="display:flex;gap:11px;padding:12px 16px;text-decoration:none;border-bottom:1px solid #f7f7f7;position:relative;background:{{ c.bg }};" style-hover="background:#fafafa;">
<span style="position:absolute;left:0;top:0;bottom:0;width:3px;background:{{ c.bar }};"></span>
<div style="position:relative;flex:none;">
<div style="width:38px;height:38px;border-radius:50%;background:{{ c.avatarBg }};color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;">{{ c.initials }}</div>
<span style="position:absolute;bottom:-1px;right:-1px;width:11px;height:11px;border-radius:50%;background:{{ c.modeDot }};border:2px solid #fff;"></span>
</div>
<div style="flex:1;min-width:0;">
<div style="display:flex;align-items:center;gap:6px;">
<span style="font-size:13.5px;font-weight:600;color:#262626;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;">{{ c.name }}</span>
<span style="font-size:11px;color:#bfbfbf;flex:none;">{{ c.time }}</span>
</div>
<div style="display:flex;align-items:center;gap:6px;margin:3px 0 4px;">
<span style="font-size:11px;color:#8c8c8c;">{{ c.product }}</span>
<span style="display:inline-flex;align-items:center;gap:4px;padding:1px 7px;border-radius:5px;background:{{ c.chBg }};">
<span style="width:5px;height:5px;border-radius:50%;background:{{ c.chColor }};"></span>
<span style="font-size:10.5px;font-weight:600;color:{{ c.chColor }};">{{ c.chLabel }}</span>
</span>
</div>
<div style="display:flex;align-items:center;gap:8px;">
<span style="font-size:12.5px;color:{{ c.previewColor }};white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;">{{ c.preview }}</span>
<sc-if value="{{ c.unread }}" hint-placeholder-val="{{ false }}">
<span style="min-width:18px;height:18px;padding:0 5px;border-radius:9px;background:#1677ff;color:#fff;font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;flex:none;">{{ c.unread }}</span>
</sc-if>
</div>
</div>
</a>
</sc-for>
</div>
</section>
<!-- ---- CENTER: conversation ---- -->
<section style="flex:1;min-width:0;display:flex;flex-direction:column;background:#f7f8fa;min-height:0;">
<!-- conversation header -->
<div style="flex:none;background:#fff;border-bottom:1px solid #f0f0f0;padding:11px 20px;display:flex;align-items:center;justify-content:space-between;gap:16px;">
<div style="display:flex;align-items:center;gap:12px;min-width:0;">
<div style="width:40px;height:40px;border-radius:50%;background:#eb6f4b;color:#fff;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:600;flex:none;">МС</div>
<div style="min-width:0;">
<div style="display:flex;align-items:center;gap:9px;">
<span style="font-size:15px;font-weight:700;color:#1f1f1f;">Мария Соколова</span>
<span style="display:inline-flex;align-items:center;gap:5px;padding:2px 9px;border-radius:20px;background:{{ st.bg }};border:1px solid {{ st.border }};">
<span style="width:6px;height:6px;border-radius:50%;background:{{ st.dot }};"></span>
<span style="font-size:11.5px;font-weight:600;color:{{ st.color }};">{{ st.label }}</span>
</span>
</div>
<div style="display:flex;align-items:center;gap:8px;margin-top:2px;font-size:12px;color:#8c8c8c;">
<span>FirePage</span><span style="color:#d9d9d9;">·</span>
<span style="display:inline-flex;align-items:center;gap:4px;"><span style="width:5px;height:5px;border-radius:50%;background:#6b5be0;"></span>MAX</span>
<span style="color:#d9d9d9;">·</span><span>@maria.s</span>
</div>
</div>
</div>
<div style="display:flex;align-items:center;gap:8px;flex:none;">
<sc-if value="{{ isWaiting }}" hint-placeholder-val="{{ true }}">
<button style="display:flex;align-items:center;gap:7px;height:36px;padding:0 16px;border-radius:8px;border:none;background:#1677ff;color:#fff;font-size:13px;font-weight:600;cursor:pointer;box-shadow:0 1px 2px rgba(22,119,255,0.3);" style-hover="background:#0958d9;">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
Забрать
</button>
</sc-if>
<sc-if value="{{ isAI }}" hint-placeholder-val="{{ false }}">
<button style="display:flex;align-items:center;gap:7px;height:36px;padding:0 16px;border-radius:8px;border:1px solid #d3adf7;background:#fff;color:#722ed1;font-size:13px;font-weight:600;cursor:pointer;" style-hover="background:#f9f0ff;">
Перехватить AI
</button>
</sc-if>
<button style="width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg>
</button>
</div>
</div>
<!-- timeline -->
<div style="flex:1;overflow-y:auto;padding:18px 24px 8px;">
<div style="max-width:760px;margin:0 auto;">
<div style="display:flex;align-items:center;gap:12px;margin:4px 0 16px;">
<div style="flex:1;height:1px;background:#ececec;"></div>
<span style="font-size:11.5px;color:#bfbfbf;font-weight:500;">Сегодня</span>
<div style="flex:1;height:1px;background:#ececec;"></div>
</div>
<div style="text-align:center;margin-bottom:16px;"><span style="display:inline-flex;align-items:center;gap:6px;padding:4px 12px;border-radius:20px;background:#eef0f2;font-size:11.5px;color:#8c8c8c;"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>Диалог начат · канал MAX · 14:02</span></div>
<!-- client -->
<div style="display:flex;gap:10px;margin-bottom:14px;">
<div style="width:30px;height:30px;border-radius:50%;background:#eb6f4b;color:#fff;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;flex:none;">МС</div>
<div style="max-width:74%;">
<div style="background:#fff;border:1px solid #eee;border-radius:4px 14px 14px 14px;padding:10px 14px;font-size:13.5px;line-height:1.5;color:#262626;">Здравствуйте! Смотрю FirePage для лендингов. Есть тариф на команду?</div>
<div style="font-size:11px;color:#bfbfbf;margin:4px 0 0 4px;">14:02</div>
</div>
</div>
<!-- AI -->
<div style="display:flex;flex-direction:row-reverse;gap:10px;margin-bottom:14px;">
<div style="width:30px;height:30px;border-radius:50%;background:#f9f0ff;border:1px solid #efdbff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#722ed1" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/></svg></div>
<div style="max-width:74%;">
<div style="display:flex;align-items:center;gap:6px;justify-content:flex-end;margin-bottom:4px;"><span style="font-size:11px;font-weight:600;color:#722ed1;">AI-агент FirePage</span></div>
<div style="background:#f9f0ff;border:1px solid #efdbff;border-radius:14px 4px 14px 14px;padding:10px 14px;font-size:13.5px;line-height:1.5;color:#262626;">Да! Для команд есть тариф <b>Business</b>: до 10 пользователей, общие проекты и приоритетная поддержка. Помесячная оплата доступна.</div>
<div style="font-size:11px;color:#bfbfbf;margin:4px 4px 0 0;text-align:right;">14:03</div>
</div>
</div>
<!-- client -->
<div style="display:flex;gap:10px;margin-bottom:14px;">
<div style="width:30px;height:30px;border-radius:50%;background:#eb6f4b;color:#fff;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;flex:none;">МС</div>
<div style="max-width:74%;">
<div style="background:#fff;border:1px solid #eee;border-radius:4px 14px 14px 14px;padding:10px 14px;font-size:13.5px;line-height:1.5;color:#262626;">Отлично. И ещё вопрос по интеграции с нашей CRM (amoCRM) — можно обсудить с менеджером?</div>
<div style="font-size:11px;color:#bfbfbf;margin:4px 0 0 4px;">14:08</div>
</div>
</div>
<!-- WAITING tail -->
<sc-if value="{{ isWaiting }}" hint-placeholder-val="{{ true }}">
<div style="text-align:center;margin:18px 0 8px;"><span style="display:inline-flex;align-items:center;gap:7px;padding:6px 14px;border-radius:20px;background:#fffbe6;border:1px solid #ffe58f;font-size:12px;color:#d48806;font-weight:500;"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/></svg>AI передал диалог оператору · причина: запрос человека (CRM-интеграция)</span></div>
<div style="text-align:center;margin-bottom:8px;"><span style="font-size:11.5px;color:#bfbfbf;">Ожидает оператора · 4 мин</span></div>
</sc-if>
<!-- AI tail (typing) -->
<sc-if value="{{ isAI }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;flex-direction:row-reverse;gap:10px;margin-bottom:8px;">
<div style="width:30px;height:30px;border-radius:50%;background:#f9f0ff;border:1px solid #efdbff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#722ed1" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/></svg></div>
<div style="background:#f9f0ff;border:1px solid #efdbff;border-radius:14px 4px 14px 14px;padding:13px 16px;display:flex;align-items:center;gap:5px;">
<span style="width:7px;height:7px;border-radius:50%;background:#b37feb;animation:hubTyping 1.2s infinite ease-in-out;"></span>
<span style="width:7px;height:7px;border-radius:50%;background:#b37feb;animation:hubTyping 1.2s infinite ease-in-out .2s;"></span>
<span style="width:7px;height:7px;border-radius:50%;background:#b37feb;animation:hubTyping 1.2s infinite ease-in-out .4s;"></span>
</div>
</div>
</sc-if>
<!-- HUMAN tail -->
<sc-if value="{{ isHuman }}" hint-placeholder-val="{{ false }}">
<div style="text-align:center;margin:18px 0 14px;"><span style="display:inline-flex;align-items:center;gap:7px;padding:6px 14px;border-radius:20px;background:#e6f4ff;border:1px solid #91caff;font-size:12px;color:#0958d9;font-weight:500;"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>Иван Петров забрал диалог · 14:09</span></div>
<div style="display:flex;flex-direction:row-reverse;gap:10px;margin-bottom:8px;">
<div style="width:30px;height:30px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;flex:none;">ИП</div>
<div style="max-width:74%;">
<div style="display:flex;align-items:center;gap:6px;justify-content:flex-end;margin-bottom:4px;"><span style="font-size:11px;font-weight:600;color:#0958d9;">Иван · оператор</span></div>
<div style="background:#e6f4ff;border:1px solid #91caff;border-radius:14px 4px 14px 14px;padding:10px 14px;font-size:13.5px;line-height:1.5;color:#262626;">Здравствуйте, Мария! Я подключился. По amoCRM — у FirePage Business есть готовая двусторонняя интеграция, лиды и сделки синхронизируются автоматически. Расскажу подробнее?</div>
<div style="font-size:11px;color:#bfbfbf;margin:4px 4px 0 0;text-align:right;">14:10</div>
</div>
</div>
</sc-if>
</div>
</div>
<!-- composer -->
<div style="flex:none;background:#fff;border-top:1px solid #f0f0f0;padding:14px 24px 16px;">
<div style="max-width:760px;margin:0 auto;">
<!-- WAITING composer -->
<sc-if value="{{ isWaiting }}" hint-placeholder-val="{{ true }}">
<div style="display:flex;align-items:center;gap:14px;padding:14px 18px;border:1px dashed #ffd591;border-radius:12px;background:#fffdf5;">
<div style="width:38px;height:38px;border-radius:10px;background:#fff7e6;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="#d48806" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
<div style="flex:1;min-width:0;">
<div style="font-size:13.5px;font-weight:600;color:#262626;">Диалог ждёт оператора</div>
<div style="font-size:12px;color:#8c8c8c;margin-top:1px;">Возьмите диалог, чтобы ответить клиенту. AI поставлен на паузу.</div>
</div>
<div style="display:flex;gap:9px;flex:none;">
<button style="height:38px;padding:0 14px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#595959;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#bfbfbf;color:#262626;">Вернуть в очередь</button>
<button style="display:flex;align-items:center;gap:7px;height:38px;padding:0 18px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer;box-shadow:0 1px 2px rgba(22,119,255,0.3);" style-hover="background:#0958d9;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>Забрать диалог</button>
</div>
</div>
</sc-if>
<!-- AI composer -->
<sc-if value="{{ isAI }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;align-items:center;gap:14px;padding:14px 18px;border:1px solid #efdbff;border-radius:12px;background:#fcfaff;">
<div style="width:38px;height:38px;border-radius:10px;background:#f9f0ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="#722ed1" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/></svg></div>
<div style="flex:1;min-width:0;">
<div style="font-size:13.5px;font-weight:600;color:#262626;">AI ведёт диалог</div>
<div style="font-size:12px;color:#8c8c8c;margin-top:1px;">Перехватите, чтобы ответить вручную. Контроль перейдёт к вам.</div>
</div>
<button style="height:38px;padding:0 18px;border-radius:9px;border:1px solid #d3adf7;background:#fff;color:#722ed1;font-size:13.5px;font-weight:600;cursor:pointer;flex:none;" style-hover="background:#f9f0ff;">Перехватить AI</button>
</div>
</sc-if>
<!-- HUMAN composer -->
<sc-if value="{{ isHuman }}" hint-placeholder-val="{{ false }}">
<div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:10px;">
<button style="display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 11px;border-radius:14px;border:1px solid #e8e8e8;background:#fafafa;color:#595959;font-size:12px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">Шаблоны ответов</button>
<button style="display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 11px;border-radius:14px;border:1px solid #e8e8e8;background:#fafafa;color:#595959;font-size:12px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">Создать checkout</button>
<div style="flex:1;"></div>
<button style="display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 11px;border-radius:14px;border:1px solid #d3adf7;background:#f9f0ff;color:#722ed1;font-size:12px;font-weight:600;cursor:pointer;">Вернуть AI</button>
<button style="display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 11px;border-radius:14px;border:1px solid #e8e8e8;background:#fafafa;color:#595959;font-size:12px;font-weight:500;cursor:pointer;" style-hover="border-color:#bfbfbf;color:#262626;">Закрыть</button>
</div>
<div style="display:flex;align-items:flex-end;gap:10px;border:1px solid #e8e8e8;border-radius:12px;padding:8px 8px 8px 14px;background:#fff;" style-focus="border-color:#1677ff;">
<button style="width:34px;height:34px;border-radius:8px;border:none;background:transparent;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#8c8c8c;flex:none;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg></button>
<textarea rows="1" placeholder="Введите сообщение…" style="flex:1;border:none;outline:none;resize:none;font-size:13.5px;line-height:1.5;color:#262626;font-family:inherit;padding:7px 0;max-height:120px;"></textarea>
<button style="display:flex;align-items:center;gap:7px;height:38px;padding:0 16px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13px;font-weight:600;cursor:pointer;flex:none;" style-hover="background:#0958d9;">Отправить<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg></button>
</div>
</div>
</sc-if>
</div>
</div>
</section>
<!-- ---- RIGHT: context ---- -->
<section style="width:336px;flex:none;background:#fff;border-left:1px solid #f0f0f0;display:flex;flex-direction:column;min-height:0;">
<!-- right tabs -->
<div style="flex:none;display:flex;border-bottom:1px solid #f0f0f0;padding:0 8px;">
<button onClick="{{ onRClient }}" style="{{ rtClient }}">Клиент</button>
<button onClick="{{ onRProduct }}" style="{{ rtProduct }}">Продукт</button>
<button onClick="{{ onRHistory }}" style="{{ rtHistory }}">История</button>
</div>
<div style="flex:1;overflow-y:auto;">
<!-- CLIENT -->
<sc-if value="{{ showClient }}" hint-placeholder-val="{{ true }}">
<div style="padding:18px 18px 24px;">
<div style="display:flex;flex-direction:column;align-items:center;text-align:center;padding-bottom:16px;border-bottom:1px solid #f5f5f5;">
<div style="width:58px;height:58px;border-radius:50%;background:#eb6f4b;color:#fff;display:flex;align-items:center;justify-content:center;font-size:20px;font-weight:600;">МС</div>
<div style="margin-top:11px;font-size:16px;font-weight:700;color:#1f1f1f;">Мария Соколова</div>
<div style="margin-top:3px;display:inline-flex;align-items:center;gap:6px;padding:2px 9px;border-radius:14px;background:#f6ffed;border:1px solid #b7eb8f;font-size:11.5px;font-weight:600;color:#389e0d;"><svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>Согласие получено</div>
</div>
<div style="padding:16px 0;border-bottom:1px solid #f5f5f5;">
<div style="font-size:11px;font-weight:600;letter-spacing:0.05em;color:#bfbfbf;margin-bottom:11px;">КАНАЛЫ И КОНТАКТЫ</div>
<div style="display:flex;align-items:center;gap:10px;margin-bottom:11px;">
<span style="width:28px;height:28px;border-radius:7px;background:#f2f0ff;display:flex;align-items:center;justify-content:center;flex:none;"><span style="width:8px;height:8px;border-radius:50%;background:#6b5be0;"></span></span>
<div style="flex:1;min-width:0;"><div style="font-size:13px;color:#262626;font-weight:500;">MAX</div><div style="font-size:11.5px;color:#8c8c8c;">@maria.s</div></div>
<span style="font-size:11px;color:#389e0d;font-weight:500;">основной</span>
</div>
<div style="display:flex;align-items:center;gap:10px;margin-bottom:11px;">
<span style="width:28px;height:28px;border-radius:7px;background:#f5f5f5;display:flex;align-items:center;justify-content:center;flex:none;color:#8c8c8c;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-10 5L2 7"/></svg></span>
<div style="flex:1;min-width:0;"><div style="font-size:13px;color:#262626;font-weight:500;font-family:'SF Mono',ui-monospace,Menlo,monospace;">m.sokolova@workmail.ru</div><div style="font-size:11.5px;color:#8c8c8c;">Email · подтверждён</div></div>
</div>
<div style="display:flex;align-items:center;gap:10px;">
<span style="width:28px;height:28px;border-radius:7px;background:#f5f5f5;display:flex;align-items:center;justify-content:center;flex:none;color:#8c8c8c;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92Z"/></svg></span>
<div style="flex:1;min-width:0;"><div style="font-size:13px;color:#8c8c8c;font-weight:500;font-family:'SF Mono',ui-monospace,Menlo,monospace;">+7 ··· ·· 14</div><div style="font-size:11.5px;color:#bfbfbf;">Телефон · скрыт</div></div>
</div>
</div>
<div style="padding:16px 0;border-bottom:1px solid #f5f5f5;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:9px;">
<span style="font-size:11px;font-weight:600;letter-spacing:0.05em;color:#bfbfbf;">РАБОЧАЯ ЗАМЕТКА</span>
<button style="font-size:11.5px;color:#1677ff;background:none;border:none;cursor:pointer;font-weight:500;padding:0;">Изменить</button>
</div>
<div style="background:#fafafa;border:1px solid #f0f0f0;border-radius:9px;padding:11px 13px;font-size:12.5px;line-height:1.55;color:#595959;">Команда ~8 человек, интересует <b style="color:#262626;">FirePage Business</b> помесячно. Открытый вопрос — интеграция с их CRM (amoCRM).</div>
</div>
<div style="padding:16px 0;border-bottom:1px solid #f5f5f5;">
<div style="font-size:11px;font-weight:600;letter-spacing:0.05em;color:#bfbfbf;margin-bottom:11px;">СВОДКА</div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:#f0f0f0;border:1px solid #f0f0f0;border-radius:8px;overflow:hidden;">
<div style="background:#fff;padding:10px 12px;"><div style="font-size:11px;color:#8c8c8c;">Заказы</div><div style="font-size:17px;font-weight:700;color:#262626;">0</div></div>
<div style="background:#fff;padding:10px 12px;"><div style="font-size:11px;color:#8c8c8c;">Диалоги</div><div style="font-size:17px;font-weight:700;color:#262626;">2</div></div>
<div style="background:#fff;padding:10px 12px;"><div style="font-size:11px;color:#8c8c8c;">Покупки</div><div style="font-size:17px;font-weight:700;color:#262626;">₽0</div></div>
</div>
<div style="font-size:11.5px;color:#bfbfbf;margin-top:8px;">Первый контакт: сегодня, 14:02</div>
</div>
<div style="padding-top:16px;">
<div style="font-size:11px;font-weight:600;letter-spacing:0.05em;color:#bfbfbf;margin-bottom:10px;">ДЕЙСТВИЯ OWNER</div>
<button style="width:100%;display:flex;align-items:center;gap:9px;height:38px;padding:0 13px;border-radius:9px;border:1px solid #e8e8e8;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;margin-bottom:8px;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6h10M8 12h10M8 18h10"/><circle cx="4" cy="6" r="1"/><circle cx="4" cy="12" r="1"/><circle cx="4" cy="18" r="1"/></svg>Объединить контакты</button>
<button style="width:100%;display:flex;align-items:center;gap:9px;height:38px;padding:0 13px;border-radius:9px;border:1px solid #f5f5f5;background:#fff;color:#cf1322;font-size:13px;font-weight:500;cursor:pointer;" style-hover="background:#fff2f0;border-color:#ffccc7;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9.88 9.88a3 3 0 1 0 4.24 4.24"/><path d="M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68"/><path d="M6.61 6.61A13.5 13.5 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61"/><line x1="2" y1="2" x2="22" y2="22"/></svg>Обезличить данные</button>
</div>
</div>
</sc-if>
<!-- PRODUCT -->
<sc-if value="{{ showProduct }}" hint-placeholder-val="{{ false }}">
<div style="padding:18px;">
<div style="display:flex;align-items:center;gap:11px;padding-bottom:14px;border-bottom:1px solid #f5f5f5;">
<div style="width:38px;height:38px;border-radius:9px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="#1677ff" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg></div>
<div><div style="font-size:14px;font-weight:700;color:#1f1f1f;">FirePage</div><div style="font-size:11.5px;color:#8c8c8c;">Конструктор лендингов · активен</div></div>
</div>
<div style="font-size:11px;font-weight:600;letter-spacing:0.05em;color:#bfbfbf;margin:16px 0 10px;">ПОДХОДЯЩИЕ OFFER</div>
<div style="border:1px solid #91caff;border-radius:10px;padding:13px;margin-bottom:10px;background:#f7fbff;">
<div style="display:flex;align-items:center;justify-content:space-between;"><span style="font-size:14px;font-weight:700;color:#1f1f1f;">Business</span><span style="font-size:11px;font-weight:600;color:#389e0d;padding:1px 7px;border-radius:5px;background:#f6ffed;">AI может предлагать</span></div>
<div style="display:flex;align-items:baseline;gap:6px;margin:7px 0;"><span style="font-size:20px;font-weight:700;color:#1f1f1f;">₽2 490</span><span style="font-size:12px;color:#8c8c8c;">/ мес · помесячно</span></div>
<div style="font-size:12px;color:#595959;line-height:1.45;">До 10 пользователей · общие проекты · amoCRM-интеграция · приоритетная поддержка.</div>
</div>
<div style="border:1px solid #f0f0f0;border-radius:10px;padding:13px;">
<div style="display:flex;align-items:center;justify-content:space-between;"><span style="font-size:14px;font-weight:700;color:#1f1f1f;">Pro</span><span style="font-size:11px;color:#8c8c8c;">для одного</span></div>
<div style="display:flex;align-items:baseline;gap:6px;margin:7px 0;"><span style="font-size:20px;font-weight:700;color:#1f1f1f;">₽990</span><span style="font-size:12px;color:#8c8c8c;">/ мес</span></div>
<div style="font-size:12px;color:#595959;line-height:1.45;">1 пользователь · все шаблоны · базовая поддержка.</div>
</div>
</div>
</sc-if>
<!-- HISTORY -->
<sc-if value="{{ showHistory }}" hint-placeholder-val="{{ false }}">
<div style="padding:18px;">
<div style="font-size:11px;font-weight:600;letter-spacing:0.05em;color:#bfbfbf;margin-bottom:12px;">ПРЕДЫДУЩИЕ ДИАЛОГИ</div>
<div style="display:flex;flex-direction:column;gap:10px;">
<div style="border:1px solid #f0f0f0;border-radius:10px;padding:12px 13px;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px;"><span style="font-size:13px;font-weight:600;color:#262626;">Консультация по тарифам</span><span style="font-size:11px;color:#bfbfbf;">3 дня назад</span></div>
<div style="font-size:12px;color:#8c8c8c;line-height:1.45;">FirePage · MAX · закрыт. Клиент уточнял лимиты тарифов, продажа не оформлена.</div>
</div>
<div style="border:1px solid #f0f0f0;border-radius:10px;padding:12px 13px;background:#fafbff;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px;"><span style="font-size:13px;font-weight:600;color:#262626;">Текущий диалог</span><span style="font-size:11px;color:#d48806;font-weight:600;">сейчас</span></div>
<div style="font-size:12px;color:#8c8c8c;line-height:1.45;">FirePage · MAX · ждёт оператора. Вопрос по amoCRM-интеграции для команды.</div>
</div>
</div>
</div>
</sc-if>
</div>
</section>
</div>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;controlMode&quot;: { &quot;editor&quot;: &quot;enum&quot;, &quot;options&quot;: [&quot;waiting&quot;, &quot;ai&quot;, &quot;human&quot;], &quot;default&quot;: &quot;waiting&quot;, &quot;tsType&quot;: &quot;string&quot; }
}">
class Component extends DCLogic {
state = { listTab: 'all', rightTab: 'client', selectedId: 1 };
renderVals() {
const mode = this.state.mode ?? this.props.controlMode ?? 'waiting';
const isWaiting = mode === 'waiting', isAI = mode === 'ai', isHuman = mode === 'human';
const st = isAI
? { label: 'AI отвечает', color: '#722ed1', bg: '#f9f0ff', border: '#efdbff', dot: '#722ed1' }
: isHuman
? { label: 'Вы ведёте диалог', color: '#0958d9', bg: '#e6f4ff', border: '#91caff', dot: '#1677ff' }
: { label: 'Ждёт оператора', color: '#d48806', bg: '#fffbe6', border: '#ffe58f', dot: '#faad14' };
const ch = {
MAX: { chLabel: 'MAX', chColor: '#6b5be0', chBg: '#f2f0ff' },
TG: { chLabel: 'Telegram', chColor: '#2f8fd0', chBg: '#eaf6fd' },
WEB: { chLabel: 'Web', chColor: '#0f9b8e', chBg: '#e8f7f4' },
};
const md = {
wait: { modeDot: '#faad14' },
ai: { modeDot: '#722ed1' },
operator: { modeDot: '#1677ff' },
closed: { modeDot: '#bfbfbf' },
};
const raw = [
{ id: 1, name: 'Мария Соколова', initials: 'МС', avatarBg: '#eb6f4b', product: 'FirePage', chan: 'MAX', m: 'wait', preview: 'Вопрос по интеграции с CRM — можно с менеджером?', time: '14:08', unread: 2 },
{ id: 2, name: 'Дмитрий Орлов', initials: 'ДО', avatarBg: '#3b82c4', product: 'Foxray', chan: 'TG', m: 'ai', preview: 'AI: Подскажу по тарифам Foxray Pro…', time: '14:07', unread: 0 },
{ id: 3, name: 'Гость 8842', initials: 'Г8', avatarBg: '#8c8c8c', product: 'FirePage', chan: 'WEB', m: 'wait', preview: 'Не приходит чек на почту после оплаты', time: '13:55', unread: 1 },
{ id: 4, name: 'Елена Кузнецова',initials: 'ЕК', avatarBg: '#9254de', product: 'Foxray', chan: 'MAX', m: 'operator', preview: 'Вы: Отправила счёт, жду подтверждения', time: '13:50', unread: 0 },
{ id: 5, name: 'Сергей Волков', initials: 'СВ', avatarBg: '#13a8a8', product: 'FirePage', chan: 'TG', m: 'ai', preview: 'Клиент: А пробный период есть?', time: '13:42', unread: 1 },
{ id: 6, name: 'Ольга Зайцева', initials: 'ОЗ', avatarBg: '#d4860b', product: 'Foxray', chan: 'WEB', m: 'operator', preview: 'Вы: Помогу с настройкой', time: '13:30', unread: 0 },
{ id: 7, name: 'Павел Новиков', initials: 'ПН', avatarBg: '#52a838', product: 'FirePage', chan: 'MAX', m: 'closed', preview: 'Диалог закрыт · продажа Business', time: '12:58', unread: 0 },
{ id: 8, name: 'Гость 5510', initials: 'Г5', avatarBg: '#8c8c8c', product: 'Foxray', chan: 'TG', m: 'ai', preview: 'AI: Чем могу помочь?', time: '11:20', unread: 0 },
];
const tab = this.state.listTab;
const filtered = raw.filter((r) =>
tab === 'all' ? true :
tab === 'wait' ? r.m === 'wait' :
tab === 'ai' ? r.m === 'ai' :
tab === 'operator' ? r.m === 'operator' :
tab === 'unread' ? r.unread > 0 : true);
const sel = this.state.selectedId;
const list = filtered.map((r) => ({
id: r.id, name: r.name, initials: r.initials, avatarBg: r.avatarBg,
product: r.product, preview: r.preview, time: r.time,
unread: r.unread > 0 ? String(r.unread) : 0,
previewColor: r.unread > 0 ? '#262626' : '#8c8c8c',
...ch[r.chan], ...md[r.m],
bg: r.id === sel ? '#e6f4ff' : 'transparent',
bar: r.id === sel ? '#1677ff' : 'transparent',
onSelect: () => this.setState({ selectedId: r.id }),
}));
const baseTab = 'flex:none;padding:6px 12px;border:none;border-radius:7px;font-size:12.5px;font-weight:500;cursor:pointer;background:transparent;color:#595959;white-space:nowrap;display:inline-flex;align-items:center;';
const actTab = 'flex:none;padding:6px 12px;border:none;border-radius:7px;font-size:12.5px;font-weight:600;cursor:pointer;background:#e6f4ff;color:#0958d9;white-space:nowrap;display:inline-flex;align-items:center;';
const setTab = (t) => this.setState({ listTab: t });
const rt = this.state.rightTab;
const rBase = 'flex:1;padding:13px 0;border:none;background:transparent;border-bottom:2px solid transparent;font-size:13px;font-weight:500;color:#8c8c8c;cursor:pointer;margin-bottom:-1px;';
const rAct = 'flex:1;padding:13px 0;border:none;background:transparent;border-bottom:2px solid #1677ff;font-size:13px;font-weight:600;color:#1677ff;cursor:pointer;margin-bottom:-1px;';
const setR = (t) => this.setState({ rightTab: t });
return {
st, isWaiting, isAI, isHuman,
list, totalCount: String(raw.length),
tabAll: tab === 'all' ? actTab : baseTab,
tabWait: tab === 'wait' ? actTab : baseTab,
tabAI: tab === 'ai' ? actTab : baseTab,
tabOp: tab === 'operator' ? actTab : baseTab,
tabUnread: tab === 'unread' ? actTab : baseTab,
onTabAll: () => setTab('all'), onTabWait: () => setTab('wait'),
onTabAI: () => setTab('ai'), onTabOp: () => setTab('operator'),
onTabUnread: () => setTab('unread'),
showClient: rt === 'client', showProduct: rt === 'product', showHistory: rt === 'history',
rtClient: rt === 'client' ? rAct : rBase,
rtProduct: rt === 'product' ? rAct : rBase,
rtHistory: rt === 'history' ? rAct : rBase,
onRClient: () => setR('client'), onRProduct: () => setR('product'), onRHistory: () => setR('history'),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,282 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1180px;">
<!-- ============ SIDEBAR ============ -->
<aside style="width:240px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;padding:0 14px;border-bottom:1px solid #f5f5f5;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:9px;height:36px;padding:0 12px;border-radius:8px;text-decoration:none;color:#595959;font-size:13px;font-weight:500;border:1px solid #f0f0f0;width:100%;" style-hover="background:#f5f5f5;color:#1677ff;border-color:#d9d9d9;">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
Назад в Hub
</a>
</div>
<div style="padding:16px 16px 8px;">
<div style="display:flex;align-items:center;gap:11px;">
<div style="width:34px;height:34px;border-radius:9px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="#1677ff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:15px;font-weight:700;color:#1f1f1f;">Продажи</span><span style="font-size:11px;color:#8c8c8c;">Рабочее пространство</span></div>
</div>
</div>
<nav style="flex:1;overflow-y:auto;padding:8px 12px;">
<a href="Продажи · Обзор.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 13h8V3H3zM13 21h8V11h-8zM13 3v6h8V3zM3 17h8v4H3z"/></svg>Обзор</a>
<a href="Продажи · Диалоги.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>Диалоги<span style="margin-left:auto;min-width:20px;height:20px;padding:0 6px;border-radius:10px;background:#faad14;color:#fff;font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;">2</span></a>
<a href="Продажи · Клиенты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Клиенты</a>
<a href="Продажи · Продажи.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h2l2.6 12.4a2 2 0 0 0 2 1.6h9.7a2 2 0 0 0 2-1.6L23 6H6"/><circle cx="9" cy="20" r="1"/><circle cx="18" cy="20" r="1"/></svg>Продажи</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><span style="font-weight:500;color:#595959;">Продажи</span><span style="color:#d9d9d9;">/</span><a href="Продажи · Продажи.dc.html" style="font-weight:500;color:#595959;text-decoration:none;" style-hover="color:#1677ff;">Продажи</a><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;font-family:'SF Mono',ui-monospace,Menlo,monospace;">ORD-10519</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<span style="display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:6px;background:#f5f5f5;font-size:12px;font-weight:600;color:#595959;"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 5v6c0 5 3.4 8.5 8 10 4.6-1.5 8-5 8-10V5Z"/></svg>OWNER</span>
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1180px;margin:0 auto;">
<sc-if value="{{ menuOpen }}" hint-placeholder-val="{{ false }}">
<div onClick="{{ onCloseMenu }}" style="position:fixed;inset:0;z-index:20;"></div>
</sc-if>
<!-- HEADER CARD -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:20px 22px;margin-bottom:16px;">
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:20px;">
<div style="min-width:0;">
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;">
<h1 style="margin:0;font-size:21px;font-weight:700;letter-spacing:-0.01em;color:#1f1f1f;font-family:'SF Mono',ui-monospace,Menlo,monospace;">ORD-10519</h1>
<span style="display:inline-flex;align-items:center;gap:6px;padding:4px 12px;border-radius:16px;background:#f6ffed;border:1px solid #b7eb8f;font-size:12.5px;font-weight:600;color:#389e0d;"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>Выполнен · подписка активна</span>
</div>
<div style="display:flex;align-items:center;gap:0;margin-top:14px;flex-wrap:wrap;">
<div style="padding-right:20px;border-right:1px solid #f0f0f0;margin-right:20px;"><div style="font-size:11.5px;color:#8c8c8c;">Сумма</div><div style="font-size:16px;font-weight:700;color:#1f1f1f;margin-top:2px;">₽2 490 <span style="font-size:11px;font-weight:500;color:#8c8c8c;">/ мес</span></div></div>
<div style="padding-right:20px;border-right:1px solid #f0f0f0;margin-right:20px;"><div style="font-size:11.5px;color:#8c8c8c;">Клиент</div><a href="Продажи · Карточка клиента.dc.html" style="font-size:14px;font-weight:600;color:#1677ff;text-decoration:none;margin-top:2px;display:block;">Татьяна Лебедева</a></div>
<div style="padding-right:20px;border-right:1px solid #f0f0f0;margin-right:20px;"><div style="font-size:11.5px;color:#8c8c8c;">Продукт / Offer</div><div style="font-size:14px;font-weight:600;color:#262626;margin-top:2px;">FirePage · Business</div></div>
<div style="padding-right:20px;border-right:1px solid #f0f0f0;margin-right:20px;"><div style="font-size:11.5px;color:#8c8c8c;">Дата</div><div style="font-size:14px;font-weight:600;color:#262626;margin-top:2px;">16 июня 2026</div></div>
<div style="padding-right:20px;border-right:1px solid #f0f0f0;margin-right:20px;"><div style="font-size:11.5px;color:#8c8c8c;">Источник</div><div style="font-size:14px;font-weight:600;color:#262626;margin-top:2px;display:inline-flex;align-items:center;gap:6px;"><span style="width:7px;height:7px;border-radius:50%;background:#6b5be0;"></span>MAX</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Оформление</div><div style="font-size:14px;font-weight:600;color:#722ed1;margin-top:2px;display:inline-flex;align-items:center;gap:6px;"><span style="width:7px;height:7px;border-radius:50%;background:#722ed1;"></span>AI-агент</div></div>
</div>
</div>
<div style="position:relative;flex:none;">
<button onClick="{{ onToggleMenu }}" style="{{ menuBtn }}">Действия<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="transform:{{ menuRot }};"><polyline points="6 9 12 15 18 9"/></svg></button>
<sc-if value="{{ menuOpen }}" hint-placeholder-val="{{ false }}">
<div style="position:absolute;right:0;top:46px;z-index:30;width:256px;background:#fff;border:1px solid #f0f0f0;border-radius:10px;box-shadow:0 6px 20px rgba(0,0,0,0.12);padding:5px;">
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#262626;font-size:13px;font-weight:500;" style-hover="background:#f5f5f5;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/><path d="M3 21v-5h5"/></svg>Повторить fulfillment</a>
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#262626;font-size:13px;font-weight:500;" style-hover="background:#f5f5f5;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-15-6.7L3 13"/></svg>Запустить reconciliation</a>
<div style="height:1px;background:#f5f5f5;margin:4px 8px;"></div>
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#cf1322;font-size:13px;font-weight:500;" style-hover="background:#fff2f0;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-15-6.7L3 13"/></svg>Выполнить возврат</a>
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#cf1322;font-size:13px;font-weight:500;" style-hover="background:#fff2f0;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-15-6.7L3 13"/></svg>Возврат подписки</a>
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#cf1322;font-size:13px;font-weight:500;" style-hover="background:#fff2f0;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><line x1="9" y1="9" x2="15" y2="15"/><line x1="15" y1="9" x2="9" y2="15"/></svg>Отменить подписку</a>
</div>
</sc-if>
</div>
</div>
</div>
<!-- COMMERCE TIMELINE -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 22px 16px;margin-bottom:16px;">
<h3 style="margin:0 0 18px;font-size:14px;font-weight:700;color:#1f1f1f;">Commerce timeline</h3>
<div style="display:flex;align-items:flex-start;overflow-x:auto;padding-bottom:4px;">
<div style="flex:none;width:108px;text-align:center;"><div style="width:30px;height:30px;border-radius:50%;background:#52c41a;display:flex;align-items:center;justify-content:center;margin:0 auto;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div><div style="font-size:12.5px;font-weight:600;color:#262626;margin-top:8px;">Checkout</div><div style="font-size:11px;color:#bfbfbf;margin-top:2px;">14:00</div></div>
<div style="flex:1;height:2px;background:#b7eb8f;margin-top:14px;border-radius:2px;min-width:18px;"></div>
<div style="flex:none;width:108px;text-align:center;"><div style="width:30px;height:30px;border-radius:50%;background:#52c41a;display:flex;align-items:center;justify-content:center;margin:0 auto;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div><div style="font-size:12.5px;font-weight:600;color:#262626;margin-top:8px;">Order</div><div style="font-size:11px;color:#bfbfbf;margin-top:2px;">14:01</div></div>
<div style="flex:1;height:2px;background:#b7eb8f;margin-top:14px;border-radius:2px;min-width:18px;"></div>
<div style="flex:none;width:108px;text-align:center;"><div style="width:30px;height:30px;border-radius:50%;background:#52c41a;display:flex;align-items:center;justify-content:center;margin:0 auto;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div><div style="font-size:12.5px;font-weight:600;color:#262626;margin-top:8px;">Payment</div><div style="font-size:11px;color:#bfbfbf;margin-top:2px;">14:02</div></div>
<div style="flex:1;height:2px;background:#b7eb8f;margin-top:14px;border-radius:2px;min-width:18px;"></div>
<div style="flex:none;width:108px;text-align:center;"><div style="width:30px;height:30px;border-radius:50%;background:#52c41a;display:flex;align-items:center;justify-content:center;margin:0 auto;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div><div style="font-size:12.5px;font-weight:600;color:#262626;margin-top:8px;">Receipt</div><div style="font-size:11px;color:#bfbfbf;margin-top:2px;">14:02</div></div>
<div style="flex:1;height:2px;background:#b7eb8f;margin-top:14px;border-radius:2px;min-width:18px;"></div>
<div style="flex:none;width:108px;text-align:center;"><div style="width:30px;height:30px;border-radius:50%;background:#52c41a;display:flex;align-items:center;justify-content:center;margin:0 auto;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div><div style="font-size:12.5px;font-weight:600;color:#262626;margin-top:8px;">Fulfillment</div><div style="font-size:11px;color:#bfbfbf;margin-top:2px;">14:03</div></div>
<div style="flex:1;height:2px;background:#b7eb8f;margin-top:14px;border-radius:2px;min-width:18px;"></div>
<div style="flex:none;width:108px;text-align:center;"><div style="width:30px;height:30px;border-radius:50%;background:#52c41a;display:flex;align-items:center;justify-content:center;margin:0 auto;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div><div style="font-size:12.5px;font-weight:600;color:#262626;margin-top:8px;">Entitlement</div><div style="font-size:11px;color:#389e0d;margin-top:2px;font-weight:500;">активен</div></div>
<div style="flex:1;height:2px;background:#f0f0f0;margin-top:14px;border-radius:2px;min-width:18px;"></div>
<div style="flex:none;width:108px;text-align:center;opacity:0.65;"><div style="width:30px;height:30px;border-radius:50%;background:#f5f5f5;border:1.5px solid #e8e8e8;display:flex;align-items:center;justify-content:center;margin:0 auto;"><span style="width:8px;height:2px;background:#bfbfbf;border-radius:2px;"></span></div><div style="font-size:12.5px;font-weight:600;color:#8c8c8c;margin-top:8px;">Refund</div><div style="font-size:11px;color:#bfbfbf;margin-top:2px;">нет</div></div>
</div>
</div>
<!-- TABS -->
<div style="display:flex;align-items:center;gap:2px;border-bottom:1px solid #e8e8e8;margin-bottom:18px;overflow-x:auto;">
<button onClick="{{ onTabSummary }}" style="{{ tSummary }}">Состав</button>
<button onClick="{{ onTabPays }}" style="{{ tPays }}">Платежи</button>
<button onClick="{{ onTabReceipts }}" style="{{ tReceipts }}">Чеки</button>
<button onClick="{{ onTabFul }}" style="{{ tFul }}">Исполнение</button>
<button onClick="{{ onTabSub }}" style="{{ tSub }}">Подписка</button>
<button onClick="{{ onTabAudit }}" style="{{ tAudit }}">Аудит</button>
</div>
<!-- ===== СОСТАВ ===== -->
<sc-if value="{{ isSummary }}" hint-placeholder-val="{{ true }}">
<div style="display:flex;gap:18px;align-items:flex-start;">
<div style="flex:1;min-width:0;display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:15px 18px 12px;border-bottom:1px solid #f5f5f5;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Позиции заказа</h3><div style="font-size:11.5px;color:#bfbfbf;margin-top:3px;">Снимок на момент оформления · цена зафиксирована</div></div>
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;"><th style="text-align:left;padding:10px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">OFFER</th><th style="text-align:left;padding:10px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">ТИП</th><th style="text-align:right;padding:10px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">ЦЕНА</th><th style="text-align:right;padding:10px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">КОЛ-ВО</th><th style="text-align:right;padding:10px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">ИТОГО</th></tr></thead>
<tbody>
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:13px 18px;"><div style="font-weight:600;color:#262626;">FirePage · Business</div><div style="font-size:11.5px;color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;">OFR-FP-BUS · price v4</div></td><td style="padding:13px 12px;color:#595959;">Подписка · мес</td><td style="padding:13px 12px;text-align:right;color:#595959;">₽2 490</td><td style="padding:13px 12px;text-align:right;color:#595959;">1</td><td style="padding:13px 18px;text-align:right;font-weight:600;color:#262626;">₽2 490</td></tr>
</tbody>
<tfoot><tr style="border-top:1px solid #f0f0f0;background:#fafafa;"><td colspan="4" style="padding:12px 18px;text-align:right;font-size:13px;font-weight:600;color:#595959;">Итого к оплате</td><td style="padding:12px 18px;text-align:right;font-size:15px;font-weight:700;color:#1f1f1f;">₽2 490</td></tr></tfoot>
</table>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Принятые документы</h3>
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid #f5f5f5;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#389e0d" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg><span style="flex:1;font-size:13px;color:#262626;">Публичная оферта <span style="color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:11.5px;">v3.1</span></span><span style="font-size:11.5px;color:#bfbfbf;">принято 16 июня 14:00</span></div>
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#389e0d" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg><span style="flex:1;font-size:13px;color:#262626;">Политика обработки персональных данных</span><span style="font-size:11.5px;color:#bfbfbf;">принято 16 июня 14:00</span></div>
</div>
</div>
<div style="width:330px;flex:none;display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Данные покупателя</h3>
<div style="font-size:13px;color:#262626;font-weight:600;">Татьяна Лебедева</div>
<div style="font-size:12.5px;color:#595959;margin-top:6px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">t.lebedeva@agency.ru</div>
<div style="font-size:12.5px;color:#8c8c8c;margin-top:3px;">ООО «Агентство Лебедева» · ИНН 7701234567</div>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Источник оформления</h3>
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#262626;"><span style="width:8px;height:8px;border-radius:50%;background:#6b5be0;"></span>Канал MAX · диалог с AI-агентом</div>
<a href="Продажи · Диалоги.dc.html" style="font-size:12.5px;color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;display:block;margin-top:8px;" style-hover="text-decoration:underline;">checkout CHK-77120 →</a>
<div style="font-size:11.5px;color:#bfbfbf;margin-top:4px;">создан 16 июня 14:00</div>
</div>
</div>
</div>
</sc-if>
<!-- ===== ПЛАТЕЖИ ===== -->
<sc-if value="{{ isPays }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;flex-direction:column;gap:16px;">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:15px 18px 12px;border-bottom:1px solid #f5f5f5;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Платежи и попытки</h3></div>
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;"><th style="text-align:left;padding:10px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">ПЛАТЁЖ</th><th style="text-align:left;padding:10px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">ПРОВАЙДЕР</th><th style="text-align:right;padding:10px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">СУММА</th><th style="text-align:left;padding:10px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">МЕТОД</th><th style="text-align:left;padding:10px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">СТАТУС</th><th style="text-align:left;padding:10px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">СВЕРКА</th></tr></thead>
<tbody><tr style="border-top:1px solid #f5f5f5;"><td style="padding:13px 18px;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-weight:600;color:#262626;font-size:12.5px;">PAY-88231</td><td style="padding:13px 12px;color:#595959;">Точка</td><td style="padding:13px 12px;text-align:right;font-weight:600;">₽2 490</td><td style="padding:13px 12px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">Карта ···4242</td><td style="padding:13px 12px;"><span style="padding:2px 9px;border-radius:6px;background:#f6ffed;color:#389e0d;font-size:11.5px;font-weight:600;">Успешно</span></td><td style="padding:13px 18px;font-size:12px;color:#389e0d;">Сверено</td></tr></tbody>
</table>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">События провайдера</h3>
<div style="display:flex;flex-direction:column;gap:0;font-size:12.5px;">
<div style="display:flex;align-items:center;gap:10px;padding:7px 0;border-bottom:1px solid #f7f7f7;"><span style="width:6px;height:6px;border-radius:50%;background:#52c41a;"></span><span style="flex:1;color:#262626;">payment.authorized</span><span style="color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;">evt_8831a</span><span style="color:#bfbfbf;width:64px;text-align:right;">14:02:03</span></div>
<div style="display:flex;align-items:center;gap:10px;padding:7px 0;border-bottom:1px solid #f7f7f7;"><span style="width:6px;height:6px;border-radius:50%;background:#52c41a;"></span><span style="flex:1;color:#262626;">payment.captured</span><span style="color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;">evt_8831b</span><span style="color:#bfbfbf;width:64px;text-align:right;">14:02:05</span></div>
<div style="display:flex;align-items:center;gap:10px;padding:7px 0;"><span style="width:6px;height:6px;border-radius:50%;background:#52c41a;"></span><span style="flex:1;color:#262626;">payment.settled</span><span style="color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;">evt_8832c</span><span style="color:#bfbfbf;width:64px;text-align:right;">02:10</span></div>
</div>
</div>
</div>
</sc-if>
<!-- ===== ЧЕКИ ===== -->
<sc-if value="{{ isReceipts }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<div style="display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:16px;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Фискальный чек</h3><span style="padding:3px 11px;border-radius:14px;background:#f6ffed;border:1px solid #b7eb8f;font-size:11.5px;font-weight:600;color:#389e0d;">Отправлен в ОФД</span></div>
<div style="display:grid;grid-template-columns:repeat(2,1fr);gap:14px 32px;">
<div><div style="font-size:11.5px;color:#8c8c8c;">Чек</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">RCP-44021</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Тип</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;">Приход</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Фискальный признак (ФПД)</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">3920··· 7741</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Сумма</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;">₽2 490 · НДС 20%</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">ОФД</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;">Принят · 16 июня 14:02</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Отправлен клиенту</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:3px;">Email · доставлен</div></div>
</div>
</div>
</sc-if>
<!-- ===== ИСПОЛНЕНИЕ ===== -->
<sc-if value="{{ isFul }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<div style="display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:16px;"><div><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Product fulfillment</h3><div style="font-size:11.5px;color:#bfbfbf;margin-top:3px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">OP-55120 · FirePage</div></div><div style="display:flex;align-items:center;gap:10px;"><span style="padding:3px 11px;border-radius:14px;background:#f6ffed;border:1px solid #b7eb8f;font-size:11.5px;font-weight:600;color:#389e0d;">Исполнен</span><button style="display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border-radius:7px;border:1px solid #d9d9d9;background:#fff;color:#595959;font-size:12.5px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/><path d="M3 21v-5h5"/></svg>Повторить</button></div></div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:14px 24px;margin-bottom:16px;">
<div><div style="font-size:11.5px;color:#8c8c8c;">Попытки</div><div style="font-size:15px;font-weight:700;color:#262626;margin-top:3px;">1</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Результат</div><div style="font-size:13px;font-weight:600;color:#389e0d;margin-top:5px;">Успешно</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Обновлено</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:5px;">16 июня 14:03</div></div>
</div>
<div style="font-size:11.5px;color:#8c8c8c;margin-bottom:7px;">PAYLOAD (SUMMARY)</div>
<div style="background:#fafafa;border:1px solid #f0f0f0;border-radius:9px;padding:12px 14px;font-size:12px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;line-height:1.6;">{ "product": "firepage", "plan": "business", "seats": 10, "account": "agency-lebedeva", "activate_at": "2026-06-16T14:03Z" }</div>
</div>
</sc-if>
<!-- ===== ПОДПИСКА ===== -->
<sc-if value="{{ isSub }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<div style="display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:16px;"><div><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Подписка</h3><div style="font-size:11.5px;color:#bfbfbf;margin-top:3px;font-family:'SF Mono',ui-monospace,Menlo,monospace;">SUB-2041 · FirePage Business</div></div><span style="padding:3px 11px;border-radius:14px;background:#f6ffed;border:1px solid #b7eb8f;font-size:11.5px;font-weight:600;color:#389e0d;">Активна</span></div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:14px 24px;">
<div><div style="font-size:11.5px;color:#8c8c8c;">Текущий период</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:5px;">16 июн — 16 июл 2026</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Следующее списание</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:5px;">16 июля 2026 · ₽2 490</div></div>
<div><div style="font-size:11.5px;color:#8c8c8c;">Entitlement</div><div style="font-size:13px;font-weight:600;color:#262626;margin-top:5px;">10 рабочих мест</div></div>
</div>
<div style="display:flex;gap:9px;margin-top:18px;padding-top:16px;border-top:1px solid #f5f5f5;">
<button style="height:36px;padding:0 14px;border-radius:8px;border:1px solid #ffccc7;background:#fff;color:#cf1322;font-size:13px;font-weight:500;cursor:pointer;" style-hover="background:#fff2f0;">Возврат подписки</button>
<button style="height:36px;padding:0 14px;border-radius:8px;border:1px solid #ffccc7;background:#fff;color:#cf1322;font-size:13px;font-weight:500;cursor:pointer;" style-hover="background:#fff2f0;">Отменить подписку</button>
</div>
</div>
</sc-if>
<!-- ===== АУДИТ ===== -->
<sc-if value="{{ isAudit }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;"><th style="text-align:left;padding:11px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">ВРЕМЯ</th><th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">ДЕЙСТВИЕ</th><th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;">АКТОР</th><th style="text-align:left;padding:11px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">РЕЗУЛЬТАТ</th></tr></thead>
<tbody>
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:12px 18px;color:#595959;white-space:nowrap;">16 июня 14:03</td><td style="padding:12px 12px;color:#262626;">Fulfillment выполнен · OP-55120</td><td style="padding:12px 12px;color:#8c8c8c;font-weight:500;">система</td><td style="padding:12px 18px;"><span style="font-size:12px;color:#389e0d;font-weight:500;">успешно</span></td></tr>
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:12px 18px;color:#595959;white-space:nowrap;">16 июня 14:02</td><td style="padding:12px 12px;color:#262626;">Чек отправлен в ОФД · RCP-44021</td><td style="padding:12px 12px;color:#8c8c8c;font-weight:500;">система</td><td style="padding:12px 18px;"><span style="font-size:12px;color:#389e0d;font-weight:500;">успешно</span></td></tr>
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:12px 18px;color:#595959;white-space:nowrap;">16 июня 14:02</td><td style="padding:12px 12px;color:#262626;">Платёж получен · PAY-88231</td><td style="padding:12px 12px;color:#595959;font-weight:500;">Точка</td><td style="padding:12px 18px;"><span style="font-size:12px;color:#389e0d;font-weight:500;">успешно</span></td></tr>
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:12px 18px;color:#595959;white-space:nowrap;">16 июня 14:01</td><td style="padding:12px 12px;color:#262626;">Заказ создан · ORD-10519</td><td style="padding:12px 12px;color:#722ed1;font-weight:500;">AI-агент</td><td style="padding:12px 18px;"><span style="font-size:12px;color:#389e0d;font-weight:500;">успешно</span></td></tr>
<tr style="border-top:1px solid #f5f5f5;"><td style="padding:12px 18px;color:#595959;white-space:nowrap;">16 июня 14:00</td><td style="padding:12px 12px;color:#262626;">Checkout оформлен · CHK-77120</td><td style="padding:12px 12px;color:#722ed1;font-weight:500;">AI-агент</td><td style="padding:12px 18px;"><span style="font-size:12px;color:#389e0d;font-weight:500;">успешно</span></td></tr>
</tbody>
</table>
</div>
</sc-if>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 }
}">
class Component extends DCLogic {
state = { tab: 'summary', menuOpen: false };
renderVals() {
const { tab, menuOpen } = this.state;
const base = 'padding:11px 15px;border:none;background:transparent;border-bottom:2px solid transparent;font-size:14px;font-weight:500;color:#595959;cursor:pointer;margin-bottom:-1px;white-space:nowrap;';
const act = 'padding:11px 15px;border:none;background:transparent;border-bottom:2px solid #1677ff;font-size:14px;font-weight:600;color:#1677ff;cursor:pointer;margin-bottom:-1px;white-space:nowrap;';
const A = (t) => tab === t ? act : base;
const set = (t) => this.setState({ tab: t, menuOpen: false });
const mBase = 'display:inline-flex;align-items:center;gap:8px;height:38px;padding:0 16px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13.5px;font-weight:600;cursor:pointer;';
const mOn = 'display:inline-flex;align-items:center;gap:8px;height:38px;padding:0 16px;border-radius:9px;border:1px solid #1677ff;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;cursor:pointer;';
return {
menuOpen, menuBtn: menuOpen ? mOn : mBase, menuRot: menuOpen ? 'rotate(180deg)' : 'none',
onToggleMenu: () => this.setState((s) => ({ menuOpen: !s.menuOpen })),
onCloseMenu: () => this.setState({ menuOpen: false }),
isSummary: tab === 'summary', isPays: tab === 'pays', isReceipts: tab === 'receipts',
isFul: tab === 'ful', isSub: tab === 'sub', isAudit: tab === 'audit',
tSummary: A('summary'), tPays: A('pays'), tReceipts: A('receipts'), tFul: A('ful'), tSub: A('sub'), tAudit: A('audit'),
onTabSummary: () => set('summary'), onTabPays: () => set('pays'), onTabReceipts: () => set('receipts'),
onTabFul: () => set('ful'), onTabSub: () => set('sub'), onTabAudit: () => set('audit'),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,276 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1180px;">
<!-- ============ SIDEBAR ============ -->
<aside style="width:240px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;padding:0 14px;border-bottom:1px solid #f5f5f5;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:9px;height:36px;padding:0 12px;border-radius:8px;text-decoration:none;color:#595959;font-size:13px;font-weight:500;border:1px solid #f0f0f0;width:100%;" style-hover="background:#f5f5f5;color:#1677ff;border-color:#d9d9d9;">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
Назад в Hub
</a>
</div>
<div style="padding:16px 16px 8px;">
<div style="display:flex;align-items:center;gap:11px;">
<div style="width:34px;height:34px;border-radius:9px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="#1677ff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:15px;font-weight:700;color:#1f1f1f;">Продажи</span><span style="font-size:11px;color:#8c8c8c;">Рабочее пространство</span></div>
</div>
</div>
<nav style="flex:1;overflow-y:auto;padding:8px 12px;">
<a href="Продажи · Обзор.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 13h8V3H3zM13 21h8V11h-8zM13 3v6h8V3zM3 17h8v4H3z"/></svg>Обзор</a>
<a href="Продажи · Диалоги.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>Диалоги<span style="margin-left:auto;min-width:20px;height:20px;padding:0 6px;border-radius:10px;background:#faad14;color:#fff;font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;">2</span></a>
<a href="Продажи · Клиенты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Клиенты</a>
<a href="Продажи · Продажи.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h2l2.6 12.4a2 2 0 0 0 2 1.6h9.7a2 2 0 0 0 2-1.6L23 6H6"/><circle cx="9" cy="20" r="1"/><circle cx="18" cy="20" r="1"/></svg>Продажи</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><span style="font-weight:500;color:#595959;">Продажи</span><span style="color:#d9d9d9;">/</span><a href="Продажи · Клиенты.dc.html" style="font-weight:500;color:#595959;text-decoration:none;" style-hover="color:#1677ff;">Клиенты</a><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">Елена Кузнецова</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<span style="display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:6px;background:#f5f5f5;font-size:12px;font-weight:600;color:#595959;"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 5v6c0 5 3.4 8.5 8 10 4.6-1.5 8-5 8-10V5Z"/></svg>OWNER</span>
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1180px;margin:0 auto;">
<sc-if value="{{ menuOpen }}" hint-placeholder-val="{{ false }}">
<div onClick="{{ onCloseMenu }}" style="position:fixed;inset:0;z-index:20;"></div>
</sc-if>
<!-- HEADER CARD -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:20px 22px;margin-bottom:18px;">
<div style="display:flex;align-items:flex-start;gap:16px;">
<div style="width:56px;height:56px;border-radius:50%;background:#9254de;color:#fff;display:flex;align-items:center;justify-content:center;font-size:19px;font-weight:600;flex:none;">ЕК</div>
<div style="flex:1;min-width:0;">
<div style="display:flex;align-items:center;gap:11px;flex-wrap:wrap;">
<h1 style="margin:0;font-size:21px;font-weight:700;letter-spacing:-0.01em;color:#1f1f1f;">Елена Кузнецова</h1>
<span style="display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:14px;background:#f6ffed;border:1px solid #b7eb8f;font-size:11.5px;font-weight:600;color:#389e0d;"><svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>Согласие получено</span>
<span style="font-size:12px;color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;">CUS-4702</span>
</div>
<div style="display:flex;align-items:center;gap:14px;margin-top:9px;flex-wrap:wrap;font-size:12.5px;color:#595959;">
<span style="display:inline-flex;align-items:center;gap:6px;"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#8c8c8c" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-10 5L2 7"/></svg><span style="font-family:'SF Mono',ui-monospace,Menlo,monospace;">e.kuznetsova@corp.ru</span></span>
<span style="display:inline-flex;align-items:center;gap:6px;"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#8c8c8c" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92Z"/></svg><span style="font-family:'SF Mono',ui-monospace,Menlo,monospace;color:#8c8c8c;">+7 ··· ·· 88</span></span>
<span style="display:inline-flex;align-items:center;gap:6px;"><span style="display:inline-flex;align-items:center;gap:4px;padding:1px 8px;border-radius:5px;background:#f2f0ff;"><span style="width:5px;height:5px;border-radius:50%;background:#6b5be0;"></span><span style="font-size:10.5px;font-weight:600;color:#6b5be0;">MAX</span></span><span style="display:inline-flex;align-items:center;gap:4px;padding:1px 8px;border-radius:5px;background:#e8f7f4;"><span style="width:5px;height:5px;border-radius:50%;background:#0f9b8e;"></span><span style="font-size:10.5px;font-weight:600;color:#0f9b8e;">Web</span></span></span>
</div>
</div>
<div style="display:flex;align-items:center;gap:9px;flex:none;position:relative;">
<a href="Продажи · Диалоги.dc.html" style="display:flex;align-items:center;gap:7px;height:38px;padding:0 16px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer;text-decoration:none;box-shadow:0 1px 2px rgba(22,119,255,0.3);" style-hover="background:#0958d9;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>Открыть диалог</a>
<button onClick="{{ onToggleMenu }}" style="{{ menuBtn }}"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
<sc-if value="{{ menuOpen }}" hint-placeholder-val="{{ false }}">
<div style="position:absolute;right:0;top:46px;z-index:30;width:236px;background:#fff;border:1px solid #f0f0f0;border-radius:10px;box-shadow:0 6px 20px rgba(0,0,0,0.12);padding:5px;">
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#262626;font-size:13px;font-weight:500;" style-hover="background:#f5f5f5;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6h10M8 12h10M8 18h10"/><circle cx="4" cy="6" r="1"/><circle cx="4" cy="12" r="1"/><circle cx="4" cy="18" r="1"/></svg>Объединить контакты</a>
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#262626;font-size:13px;font-weight:500;" style-hover="background:#f5f5f5;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h7m11 0h-7M7 8l-4 4 4 4m10-8 4 4-4 4"/></svg>Разъединить контакты</a>
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#262626;font-size:13px;font-weight:500;" style-hover="background:#f5f5f5;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/></svg>Исправить данные</a>
<div style="height:1px;background:#f5f5f5;margin:4px 8px;"></div>
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#cf1322;font-size:13px;font-weight:500;" style-hover="background:#fff2f0;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9.88 9.88a3 3 0 1 0 4.24 4.24"/><path d="M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68"/><path d="M6.61 6.61A13.5 13.5 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61"/><line x1="2" y1="2" x2="22" y2="22"/></svg>Обезличить данные</a>
</div>
</sc-if>
</div>
</div>
</div>
<!-- TABS -->
<div style="display:flex;align-items:center;gap:2px;border-bottom:1px solid #e8e8e8;margin-bottom:18px;overflow-x:auto;">
<button onClick="{{ onTabOverview }}" style="{{ tOverview }}">Обзор</button>
<button onClick="{{ onTabDialogs }}" style="{{ tDialogs }}">Диалоги</button>
<button onClick="{{ onTabOrders }}" style="{{ tOrders }}">Заказы</button>
<button onClick="{{ onTabIds }}" style="{{ tIds }}">Идентификаторы каналов</button>
<button onClick="{{ onTabConsent }}" style="{{ tConsent }}">Consent</button>
<button onClick="{{ onTabAudit }}" style="{{ tAudit }}">Аудит</button>
</div>
<!-- ===== ОБЗОР ===== -->
<sc-if value="{{ isOverview }}" hint-placeholder-val="{{ true }}">
<div style="display:flex;gap:18px;align-items:flex-start;">
<div style="flex:1;min-width:0;display:flex;flex-direction:column;gap:16px;">
<!-- summary -->
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:#f0f0f0;border:1px solid #f0f0f0;border-radius:11px;overflow:hidden;">
<div style="background:#fff;padding:15px 16px;"><div style="font-size:12px;color:#8c8c8c;">Заказы</div><div style="font-size:22px;font-weight:700;color:#262626;margin-top:6px;">3</div></div>
<div style="background:#fff;padding:15px 16px;"><div style="font-size:12px;color:#8c8c8c;">Сумма покупок</div><div style="font-size:22px;font-weight:700;color:#389e0d;margin-top:6px;">₽12 470</div></div>
<div style="background:#fff;padding:15px 16px;"><div style="font-size:12px;color:#8c8c8c;">Диалоги</div><div style="font-size:22px;font-weight:700;color:#262626;margin-top:6px;">4</div></div>
<div style="background:#fff;padding:15px 16px;"><div style="font-size:12px;color:#8c8c8c;">Первый контакт</div><div style="font-size:14px;font-weight:600;color:#262626;margin-top:9px;">28 мая 2026</div></div>
</div>
<!-- note -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Потребность и заметка</h3><button style="font-size:12px;color:#1677ff;background:none;border:none;cursor:pointer;font-weight:500;">Изменить</button></div>
<div style="background:#fafafa;border:1px solid #f0f0f0;border-radius:9px;padding:12px 14px;font-size:13px;line-height:1.55;color:#595959;">Команда дизайна, 5 рабочих мест. Пользуется <b style="color:#262626;">Foxray Team</b>, рассматривает FirePage для лендингов. Платит по счёту, ЛПР — сама Елена.</div>
</div>
<!-- activity -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 14px;font-size:14px;font-weight:700;color:#1f1f1f;">Последняя активность</h3>
<div style="display:flex;flex-direction:column;gap:0;">
<div style="display:flex;gap:12px;"><div style="display:flex;flex-direction:column;align-items:center;"><span style="width:9px;height:9px;border-radius:50%;background:#1677ff;margin-top:4px;"></span><span style="flex:1;width:2px;background:#f0f0f0;"></span></div><div style="padding-bottom:16px;"><div style="font-size:13px;color:#262626;font-weight:500;">Создан заказ <span style="font-family:'SF Mono',ui-monospace,Menlo,monospace;color:#1677ff;">ORD-10512</span> · Foxray Team</div><div style="font-size:11.5px;color:#bfbfbf;margin-top:2px;">сегодня 11:05</div></div></div>
<div style="display:flex;gap:12px;"><div style="display:flex;flex-direction:column;align-items:center;"><span style="width:9px;height:9px;border-radius:50%;background:#52c41a;margin-top:4px;"></span><span style="flex:1;width:2px;background:#f0f0f0;"></span></div><div style="padding-bottom:16px;"><div style="font-size:13px;color:#262626;font-weight:500;">Оплата ₽6 500 · <span style="font-family:'SF Mono',ui-monospace,Menlo,monospace;color:#595959;">ORD-10455</span></div><div style="font-size:11.5px;color:#bfbfbf;margin-top:2px;">02 июня 18:22</div></div></div>
<div style="display:flex;gap:12px;"><div style="display:flex;flex-direction:column;align-items:center;"><span style="width:9px;height:9px;border-radius:50%;background:#722ed1;margin-top:4px;"></span><span style="flex:1;width:2px;background:#f0f0f0;"></span></div><div style="padding-bottom:16px;"><div style="font-size:13px;color:#262626;font-weight:500;">Диалог закрыт · продажа Foxray Pro</div><div style="font-size:11.5px;color:#bfbfbf;margin-top:2px;">02 июня 14:00</div></div></div>
<div style="display:flex;gap:12px;"><div style="display:flex;flex-direction:column;align-items:center;"><span style="width:9px;height:9px;border-radius:50%;background:#bfbfbf;margin-top:4px;"></span></div><div><div style="font-size:13px;color:#262626;font-weight:500;">Первый контакт · канал MAX</div><div style="font-size:11.5px;color:#bfbfbf;margin-top:2px;">28 мая 2026</div></div></div>
</div>
</div>
</div>
<div style="width:330px;flex:none;display:flex;flex-direction:column;gap:16px;">
<!-- current dialog -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:11px;"><h3 style="margin:0;font-size:14px;font-weight:700;color:#1f1f1f;">Текущий диалог</h3><span style="display:inline-flex;align-items:center;gap:5px;padding:2px 9px;border-radius:14px;background:#e6f4ff;border:1px solid #91caff;font-size:11px;font-weight:600;color:#0958d9;"><span style="width:6px;height:6px;border-radius:50%;background:#1677ff;"></span>Оператор</span></div>
<div style="font-size:12.5px;color:#595959;line-height:1.5;">Foxray · Web Chat · ведёт <b style="color:#262626;">Иван Петров</b>.<br/>«Помогу с настройкой рабочих мест.»</div>
<a href="Продажи · Диалоги.dc.html" style="display:flex;align-items:center;justify-content:center;gap:7px;height:36px;margin-top:13px;border-radius:8px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;text-decoration:none;" style-hover="border-color:#1677ff;color:#1677ff;">Открыть диалог</a>
</div>
<!-- products -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:16px 18px;">
<h3 style="margin:0 0 13px;font-size:14px;font-weight:700;color:#1f1f1f;">Связанные продукты</h3>
<div style="display:flex;align-items:center;justify-content:space-between;padding:9px 0;border-bottom:1px solid #f5f5f5;"><span style="display:inline-flex;align-items:center;gap:8px;font-size:13px;font-weight:500;color:#262626;"><span style="width:8px;height:8px;border-radius:2px;background:#722ed1;"></span>Foxray</span><span style="font-size:12px;color:#8c8c8c;">Team · активна</span></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:9px 0;"><span style="display:inline-flex;align-items:center;gap:8px;font-size:13px;font-weight:500;color:#262626;"><span style="width:8px;height:8px;border-radius:2px;background:#1677ff;"></span>FirePage</span><span style="font-size:12px;color:#8c8c8c;">Pro · разовая</span></div>
</div>
</div>
</div>
</sc-if>
<!-- ===== ДИАЛОГИ ===== -->
<sc-if value="{{ isDialogs }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<a href="Продажи · Диалоги.dc.html" style="display:flex;align-items:center;gap:13px;padding:14px 18px;text-decoration:none;border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<span style="width:8px;height:8px;border-radius:50%;background:#1677ff;flex:none;"></span>
<div style="flex:1;"><div style="font-size:13.5px;font-weight:600;color:#262626;">Настройка рабочих мест · Foxray</div><div style="font-size:12px;color:#8c8c8c;margin-top:2px;">Web Chat · ведёт Иван Петров</div></div>
<span style="font-size:12px;color:#0958d9;font-weight:500;">Оператор</span><span style="font-size:11.5px;color:#bfbfbf;width:74px;text-align:right;">18 мин назад</span>
</a>
<a href="Продажи · Диалоги.dc.html" style="display:flex;align-items:center;gap:13px;padding:14px 18px;text-decoration:none;border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<span style="width:8px;height:8px;border-radius:50%;background:#bfbfbf;flex:none;"></span>
<div style="flex:1;"><div style="font-size:13.5px;font-weight:600;color:#262626;">Покупка Foxray Pro</div><div style="font-size:12px;color:#8c8c8c;margin-top:2px;">MAX · закрыт · продажа</div></div>
<span style="font-size:12px;color:#8c8c8c;font-weight:500;">Закрыт</span><span style="font-size:11.5px;color:#bfbfbf;width:74px;text-align:right;">02 июня</span>
</a>
<a href="Продажи · Диалоги.dc.html" style="display:flex;align-items:center;gap:13px;padding:14px 18px;text-decoration:none;border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<span style="width:8px;height:8px;border-radius:50%;background:#bfbfbf;flex:none;"></span>
<div style="flex:1;"><div style="font-size:13.5px;font-weight:600;color:#262626;">Консультация по тарифам</div><div style="font-size:12px;color:#8c8c8c;margin-top:2px;">MAX · закрыт</div></div>
<span style="font-size:12px;color:#8c8c8c;font-weight:500;">Закрыт</span><span style="font-size:11.5px;color:#bfbfbf;width:74px;text-align:right;">28 мая</span>
</a>
<a href="Продажи · Диалоги.dc.html" style="display:flex;align-items:center;gap:13px;padding:14px 18px;text-decoration:none;" style-hover="background:#fafbfc;">
<span style="width:8px;height:8px;border-radius:50%;background:#bfbfbf;flex:none;"></span>
<div style="flex:1;"><div style="font-size:13.5px;font-weight:600;color:#262626;">Первичный вопрос о продукте</div><div style="font-size:12px;color:#8c8c8c;margin-top:2px;">MAX · закрыт</div></div>
<span style="font-size:12px;color:#8c8c8c;font-weight:500;">Закрыт</span><span style="font-size:11.5px;color:#bfbfbf;width:74px;text-align:right;">28 мая</span>
</a>
</div>
</sc-if>
<!-- ===== ЗАКАЗЫ ===== -->
<sc-if value="{{ isOrders }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;">
<th style="text-align:left;padding:11px 18px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ЗАКАЗ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ДАТА</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПРОДУКТ / OFFER</th>
<th style="text-align:right;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СУММА</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ОПЛАТА</th>
<th style="text-align:left;padding:11px 18px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ИСПОЛНЕНИЕ</th>
</tr></thead>
<tbody>
<tr style="border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;"><td style="padding:12px 18px;"><a href="#" style="font-weight:600;color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;">ORD-10512</a></td><td style="padding:12px 12px;color:#595959;">сегодня 11:05</td><td style="padding:12px 12px;color:#595959;">Foxray · Team</td><td style="padding:12px 12px;text-align:right;font-weight:600;">₽4 980</td><td style="padding:12px 12px;"><span style="padding:2px 9px;border-radius:6px;background:#f6ffed;color:#389e0d;font-size:11.5px;font-weight:600;">Оплачен</span></td><td style="padding:12px 18px;"><span style="padding:2px 9px;border-radius:6px;background:#f6ffed;color:#389e0d;font-size:11.5px;font-weight:600;">Исполнен</span></td></tr>
<tr style="border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;"><td style="padding:12px 18px;"><a href="#" style="font-weight:600;color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;">ORD-10455</a></td><td style="padding:12px 12px;color:#595959;">02 июня</td><td style="padding:12px 12px;color:#595959;">Foxray · Pro</td><td style="padding:12px 12px;text-align:right;font-weight:600;">₽6 500</td><td style="padding:12px 12px;"><span style="padding:2px 9px;border-radius:6px;background:#f6ffed;color:#389e0d;font-size:11.5px;font-weight:600;">Оплачен</span></td><td style="padding:12px 18px;"><span style="padding:2px 9px;border-radius:6px;background:#f6ffed;color:#389e0d;font-size:11.5px;font-weight:600;">Исполнен</span></td></tr>
<tr style="border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;"><td style="padding:12px 18px;"><a href="#" style="font-weight:600;color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;">ORD-10390</a></td><td style="padding:12px 12px;color:#595959;">28 мая</td><td style="padding:12px 12px;color:#595959;">FirePage · Pro</td><td style="padding:12px 12px;text-align:right;font-weight:600;">₽990</td><td style="padding:12px 12px;"><span style="padding:2px 9px;border-radius:6px;background:#f6ffed;color:#389e0d;font-size:11.5px;font-weight:600;">Оплачен</span></td><td style="padding:12px 18px;"><span style="padding:2px 9px;border-radius:6px;background:#f6ffed;color:#389e0d;font-size:11.5px;font-weight:600;">Исполнен</span></td></tr>
</tbody>
</table>
</div>
</sc-if>
<!-- ===== ИДЕНТИФИКАТОРЫ КАНАЛОВ ===== -->
<sc-if value="{{ isIds }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="display:flex;align-items:center;gap:12px;padding:14px 18px;border-bottom:1px solid #f5f5f5;"><span style="width:30px;height:30px;border-radius:8px;background:#f2f0ff;display:flex;align-items:center;justify-content:center;flex:none;"><span style="width:9px;height:9px;border-radius:50%;background:#6b5be0;"></span></span><div style="flex:1;"><div style="font-size:13px;font-weight:600;color:#262626;">MAX</div><div style="font-size:12px;color:#8c8c8c;font-family:'SF Mono',ui-monospace,Menlo,monospace;">@elena.kuz</div></div><span style="font-size:11.5px;color:#389e0d;font-weight:500;">основной · подтверждён</span><button style="margin-left:14px;font-size:12px;color:#1677ff;background:none;border:none;cursor:pointer;font-weight:500;">Исправить</button></div>
<div style="display:flex;align-items:center;gap:12px;padding:14px 18px;border-bottom:1px solid #f5f5f5;"><span style="width:30px;height:30px;border-radius:8px;background:#e8f7f4;display:flex;align-items:center;justify-content:center;flex:none;"><span style="width:9px;height:9px;border-radius:50%;background:#0f9b8e;"></span></span><div style="flex:1;"><div style="font-size:13px;font-weight:600;color:#262626;">Web Chat</div><div style="font-size:12px;color:#8c8c8c;font-family:'SF Mono',ui-monospace,Menlo,monospace;">session 9f2a··· </div></div><span style="font-size:11.5px;color:#389e0d;font-weight:500;">активна</span><button style="margin-left:14px;font-size:12px;color:#1677ff;background:none;border:none;cursor:pointer;font-weight:500;">Исправить</button></div>
<div style="display:flex;align-items:center;gap:12px;padding:14px 18px;border-bottom:1px solid #f5f5f5;"><span style="width:30px;height:30px;border-radius:8px;background:#f5f5f5;display:flex;align-items:center;justify-content:center;flex:none;color:#8c8c8c;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-10 5L2 7"/></svg></span><div style="flex:1;"><div style="font-size:13px;font-weight:600;color:#262626;">Email</div><div style="font-size:12px;color:#8c8c8c;font-family:'SF Mono',ui-monospace,Menlo,monospace;">e.kuznetsova@corp.ru</div></div><span style="font-size:11.5px;color:#389e0d;font-weight:500;">подтверждён</span><button style="margin-left:14px;font-size:12px;color:#1677ff;background:none;border:none;cursor:pointer;font-weight:500;">Исправить</button></div>
<div style="display:flex;align-items:center;gap:12px;padding:14px 18px;"><span style="width:30px;height:30px;border-radius:8px;background:#f5f5f5;display:flex;align-items:center;justify-content:center;flex:none;color:#8c8c8c;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92Z"/></svg></span><div style="flex:1;"><div style="font-size:13px;font-weight:600;color:#262626;">Телефон</div><div style="font-size:12px;color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;">+7 ··· ·· 88 · скрыт</div></div><span style="font-size:11.5px;color:#8c8c8c;font-weight:500;">не подтверждён</span><button style="margin-left:14px;font-size:12px;color:#1677ff;background:none;border:none;cursor:pointer;font-weight:500;">Исправить</button></div>
</div>
</sc-if>
<!-- ===== CONSENT ===== -->
<sc-if value="{{ isConsent }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:18px 20px;">
<h3 style="margin:0 0 16px;font-size:14px;font-weight:700;color:#1f1f1f;">История согласий</h3>
<div style="display:flex;gap:13px;"><div style="display:flex;flex-direction:column;align-items:center;"><span style="width:11px;height:11px;border-radius:50%;background:#52c41a;margin-top:3px;"></span><span style="flex:1;width:2px;background:#f0f0f0;"></span></div><div style="padding-bottom:18px;"><div style="font-size:13px;font-weight:600;color:#262626;">Согласие на обработку данных · получено</div><div style="font-size:12px;color:#8c8c8c;margin-top:3px;">Канал MAX · подтверждено пользователем</div><div style="font-size:11.5px;color:#bfbfbf;margin-top:2px;">04 июня 2026, 14:20</div></div></div>
<div style="display:flex;gap:13px;"><div style="display:flex;flex-direction:column;align-items:center;"><span style="width:11px;height:11px;border-radius:50%;background:#52c41a;margin-top:3px;"></span><span style="flex:1;width:2px;background:#f0f0f0;"></span></div><div style="padding-bottom:18px;"><div style="font-size:13px;font-weight:600;color:#262626;">Согласие на маркетинговые сообщения · получено</div><div style="font-size:12px;color:#8c8c8c;margin-top:3px;">Канал MAX</div><div style="font-size:11.5px;color:#bfbfbf;margin-top:2px;">04 июня 2026, 14:20</div></div></div>
<div style="display:flex;gap:13px;"><div style="display:flex;flex-direction:column;align-items:center;"><span style="width:11px;height:11px;border-radius:50%;background:#bfbfbf;margin-top:3px;"></span></div><div><div style="font-size:13px;font-weight:600;color:#262626;">Первичный контакт · согласие ещё не получено</div><div style="font-size:12px;color:#8c8c8c;margin-top:3px;">Канал MAX · обработка по законному интересу</div><div style="font-size:11.5px;color:#bfbfbf;margin-top:2px;">28 мая 2026</div></div></div>
</div>
</sc-if>
<!-- ===== АУДИТ ===== -->
<sc-if value="{{ isAudit }}" hint-placeholder-val="{{ false }}">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;">
<th style="text-align:left;padding:11px 18px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ВРЕМЯ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ДЕЙСТВИЕ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ОБЪЕКТ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">АКТОР</th>
<th style="text-align:left;padding:11px 18px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">РЕЗУЛЬТАТ</th>
</tr></thead>
<tbody>
<tr style="border-bottom:1px solid #f5f5f5;"><td style="padding:12px 18px;color:#595959;white-space:nowrap;">сегодня 11:05</td><td style="padding:12px 12px;color:#262626;">Создан заказ</td><td style="padding:12px 12px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">ORD-10512</td><td style="padding:12px 12px;color:#722ed1;font-weight:500;">AI-агент</td><td style="padding:12px 18px;"><span style="font-size:12px;color:#389e0d;font-weight:500;">успешно</span></td></tr>
<tr style="border-bottom:1px solid #f5f5f5;"><td style="padding:12px 18px;color:#595959;white-space:nowrap;">02 июня 18:22</td><td style="padding:12px 12px;color:#262626;">Объединение контактов</td><td style="padding:12px 12px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">CUS-4702 ← CUS-4810</td><td style="padding:12px 12px;color:#262626;font-weight:500;">Иван Петров</td><td style="padding:12px 18px;"><span style="font-size:12px;color:#389e0d;font-weight:500;">успешно</span></td></tr>
<tr style="border-bottom:1px solid #f5f5f5;"><td style="padding:12px 18px;color:#595959;white-space:nowrap;">02 июня 14:00</td><td style="padding:12px 12px;color:#262626;">Изменены контактные данные</td><td style="padding:12px 12px;color:#595959;">email</td><td style="padding:12px 12px;color:#262626;font-weight:500;">Иван Петров</td><td style="padding:12px 18px;"><span style="font-size:12px;color:#389e0d;font-weight:500;">успешно</span></td></tr>
<tr style="border-bottom:1px solid #f5f5f5;"><td style="padding:12px 18px;color:#595959;white-space:nowrap;">28 мая 2026</td><td style="padding:12px 12px;color:#262626;">Контакт создан</td><td style="padding:12px 12px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">CUS-4702</td><td style="padding:12px 12px;color:#8c8c8c;font-weight:500;">система</td><td style="padding:12px 18px;"><span style="font-size:12px;color:#389e0d;font-weight:500;">успешно</span></td></tr>
</tbody>
</table>
</div>
</sc-if>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 }
}">
class Component extends DCLogic {
state = { tab: 'overview', menuOpen: false };
renderVals() {
const { tab, menuOpen } = this.state;
const base = 'padding:11px 15px;border:none;background:transparent;border-bottom:2px solid transparent;font-size:14px;font-weight:500;color:#595959;cursor:pointer;margin-bottom:-1px;white-space:nowrap;';
const act = 'padding:11px 15px;border:none;background:transparent;border-bottom:2px solid #1677ff;font-size:14px;font-weight:600;color:#1677ff;cursor:pointer;margin-bottom:-1px;white-space:nowrap;';
const A = (t) => tab === t ? act : base;
const set = (t) => this.setState({ tab: t, menuOpen: false });
const menuBtnBase = 'width:38px;height:38px;border-radius:9px;border:1px solid #d9d9d9;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;';
const menuBtnOn = 'width:38px;height:38px;border-radius:9px;border:1px solid #1677ff;background:#e6f4ff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#0958d9;';
return {
menuOpen, menuBtn: menuOpen ? menuBtnOn : menuBtnBase,
onToggleMenu: () => this.setState((s) => ({ menuOpen: !s.menuOpen })),
onCloseMenu: () => this.setState({ menuOpen: false }),
isOverview: tab === 'overview', isDialogs: tab === 'dialogs', isOrders: tab === 'orders',
isIds: tab === 'ids', isConsent: tab === 'consent', isAudit: tab === 'audit',
tOverview: A('overview'), tDialogs: A('dialogs'), tOrders: A('orders'),
tIds: A('ids'), tConsent: A('consent'), tAudit: A('audit'),
onTabOverview: () => set('overview'), onTabDialogs: () => set('dialogs'), onTabOrders: () => set('orders'),
onTabIds: () => set('ids'), onTabConsent: () => set('consent'), onTabAudit: () => set('audit'),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,334 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1180px;">
<!-- ============ SIDEBAR ============ -->
<aside style="width:240px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;padding:0 14px;border-bottom:1px solid #f5f5f5;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:9px;height:36px;padding:0 12px;border-radius:8px;text-decoration:none;color:#595959;font-size:13px;font-weight:500;border:1px solid #f0f0f0;width:100%;" style-hover="background:#f5f5f5;color:#1677ff;border-color:#d9d9d9;">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
Назад в Hub
</a>
</div>
<div style="padding:16px 16px 8px;">
<div style="display:flex;align-items:center;gap:11px;">
<div style="width:34px;height:34px;border-radius:9px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="#1677ff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:15px;font-weight:700;color:#1f1f1f;">Продажи</span><span style="font-size:11px;color:#8c8c8c;">Рабочее пространство</span></div>
</div>
</div>
<nav style="flex:1;overflow-y:auto;padding:8px 12px;">
<a href="Продажи · Обзор.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 13h8V3H3zM13 21h8V11h-8zM13 3v6h8V3zM3 17h8v4H3z"/></svg>Обзор</a>
<a href="Продажи · Диалоги.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>Диалоги<span style="margin-left:auto;min-width:20px;height:20px;padding:0 6px;border-radius:10px;background:#faad14;color:#fff;font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;">2</span></a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Клиенты</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h2l2.6 12.4a2 2 0 0 0 2 1.6h9.7a2 2 0 0 0 2-1.6L23 6H6"/><circle cx="9" cy="20" r="1"/><circle cx="18" cy="20" r="1"/></svg>Продажи</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><span style="font-weight:500;color:#595959;">Продажи</span><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">Клиенты</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<span style="display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:6px;background:#f5f5f5;font-size:12px;font-weight:600;color:#595959;"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 5v6c0 5 3.4 8.5 8 10 4.6-1.5 8-5 8-10V5Z"/></svg>OWNER</span>
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1340px;margin:0 auto;">
<!-- PAGE HEADER -->
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:18px;">
<div>
<h1 style="margin:0;font-size:24px;font-weight:700;letter-spacing:-0.02em;color:#1f1f1f;line-height:1.2;">Клиенты</h1>
<p style="margin:6px 0 0;font-size:13.5px;color:#8c8c8c;">Контакты отдела продаж · показано <b style="color:#595959;">{{ shownCount }}</b> из 248</p>
</div>
<div style="display:flex;align-items:center;gap:9px;flex:none;">
<button style="display:flex;align-items:center;gap:7px;height:36px;padding:0 14px;border-radius:8px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/></svg>Столбцы</button>
<button style="display:flex;align-items:center;gap:7px;height:36px;padding:0 14px;border-radius:8px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>Экспорт</button>
</div>
</div>
<!-- FILTER BAR -->
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:11px 14px;margin-bottom:16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);">
<div style="display:flex;align-items:center;gap:8px;height:34px;padding:0 11px;border:1px solid #e8e8e8;border-radius:8px;background:#fafafa;width:280px;" style-focus="border-color:#1677ff;">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="#bfbfbf" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input value="{{ q }}" onInput="{{ onSearch }}" placeholder="Поиск по имени или email…" style="border:none;outline:none;background:transparent;font-size:13px;color:#262626;width:100%;font-family:inherit;" />
</div>
<sc-if value="{{ ddAnyOpen }}" hint-placeholder-val="{{ false }}">
<div onClick="{{ onCloseDD }}" style="position:fixed;inset:0;z-index:20;"></div>
</sc-if>
<!-- Product dropdown -->
<div style="position:relative;">
<button onClick="{{ onToggleProd }}" style="{{ ddProdBtn }}">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>
{{ prodLabel }}
<sc-if value="{{ prodCount }}" hint-placeholder-val="{{ false }}"><span style="min-width:17px;height:17px;padding:0 5px;border-radius:9px;background:#1677ff;color:#fff;font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;">{{ prodCount }}</span></sc-if>
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="transform:{{ ddProdRot }};opacity:0.55;"><polyline points="6 9 12 15 18 9"/></svg>
</button>
<sc-if value="{{ ddProdOpen }}" hint-placeholder-val="{{ false }}">
<div style="position:absolute;top:40px;left:0;z-index:30;width:212px;background:#fff;border:1px solid #f0f0f0;border-radius:10px;box-shadow:0 6px 20px rgba(0,0,0,0.12);padding:6px;">
<sc-for list="{{ prodOpts }}" as="o" hint-placeholder-count="2">
<label onClick="{{ o.onToggle }}" style="display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:7px;cursor:pointer;font-size:13px;font-weight:500;color:#262626;" style-hover="background:#f5f5f5;">
<span style="{{ o.box }}"><sc-if value="{{ o.checked }}" hint-placeholder-val="{{ false }}"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></sc-if></span>
{{ o.name }}
</label>
</sc-for>
</div>
</sc-if>
</div>
<!-- Channel dropdown -->
<div style="position:relative;">
<button onClick="{{ onToggleChan }}" style="{{ ddChanBtn }}">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
{{ chanLabel }}
<sc-if value="{{ chanCount }}" hint-placeholder-val="{{ false }}"><span style="min-width:17px;height:17px;padding:0 5px;border-radius:9px;background:#1677ff;color:#fff;font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;">{{ chanCount }}</span></sc-if>
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="transform:{{ ddChanRot }};opacity:0.55;"><polyline points="6 9 12 15 18 9"/></svg>
</button>
<sc-if value="{{ ddChanOpen }}" hint-placeholder-val="{{ false }}">
<div style="position:absolute;top:40px;left:0;z-index:30;width:212px;background:#fff;border:1px solid #f0f0f0;border-radius:10px;box-shadow:0 6px 20px rgba(0,0,0,0.12);padding:6px;">
<sc-for list="{{ chanOpts }}" as="o" hint-placeholder-count="3">
<label onClick="{{ o.onToggle }}" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;cursor:pointer;font-size:13px;font-weight:500;color:#262626;" style-hover="background:#f5f5f5;">
<span style="{{ o.box }}"><sc-if value="{{ o.checked }}" hint-placeholder-val="{{ false }}"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></sc-if></span>
<span style="width:8px;height:8px;border-radius:50%;background:{{ o.dot }};flex:none;"></span>
{{ o.name }}
</label>
</sc-for>
</div>
</sc-if>
</div>
<button onClick="{{ onOpenToggle }}" style="{{ chipOpen }}"><span style="width:7px;height:7px;border-radius:50%;background:#faad14;"></span>С открытым диалогом</button>
<button onClick="{{ onBuyerToggle }}" style="{{ chipBuyer }}"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>Есть покупка</button>
<div style="flex:1;"></div>
<button onClick="{{ onReset }}" style="height:34px;padding:0 12px;border:none;background:transparent;color:#8c8c8c;font-size:13px;font-weight:500;cursor:pointer;border-radius:8px;" style-hover="color:#1677ff;background:#f5f5f5;">Сбросить</button>
</div>
<!-- TABLE -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="overflow-x:auto;">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:1080px;">
<thead>
<tr style="background:#fafafa;">
<th style="text-align:left;padding:11px 16px;font-size:11px;font-weight:600;color:#8c8c8c;letter-spacing:0.03em;position:sticky;top:0;background:#fafafa;border-bottom:1px solid #f0f0f0;">КЛИЕНТ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;position:sticky;top:0;background:#fafafa;border-bottom:1px solid #f0f0f0;">КОНТАКТЫ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;position:sticky;top:0;background:#fafafa;border-bottom:1px solid #f0f0f0;">КАНАЛЫ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;position:sticky;top:0;background:#fafafa;border-bottom:1px solid #f0f0f0;">ПРОДУКТЫ</th>
<th onClick="{{ onSortLast }}" style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;position:sticky;top:0;background:#fafafa;border-bottom:1px solid #f0f0f0;cursor:pointer;white-space:nowrap;">ПОСЛ. ДИАЛОГ {{ arrLast }}</th>
<th onClick="{{ onSortOpen }}" style="text-align:right;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;position:sticky;top:0;background:#fafafa;border-bottom:1px solid #f0f0f0;cursor:pointer;white-space:nowrap;">ОТКР. {{ arrOpen }}</th>
<th onClick="{{ onSortOrders }}" style="text-align:right;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;position:sticky;top:0;background:#fafafa;border-bottom:1px solid #f0f0f0;cursor:pointer;white-space:nowrap;">ЗАКАЗЫ {{ arrOrders }}</th>
<th onClick="{{ onSortTotal }}" style="text-align:right;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;position:sticky;top:0;background:#fafafa;border-bottom:1px solid #f0f0f0;cursor:pointer;white-space:nowrap;">СУММА ПОКУПОК {{ arrTotal }}</th>
<th style="width:48px;position:sticky;top:0;background:#fafafa;border-bottom:1px solid #f0f0f0;"></th>
</tr>
</thead>
<tbody>
<sc-for list="{{ rows }}" as="r" hint-placeholder-count="8">
<tr style="border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<td style="padding:12px 16px;">
<div style="display:flex;align-items:center;gap:11px;">
<div style="width:34px;height:34px;border-radius:50%;background:{{ r.avatarBg }};color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;flex:none;">{{ r.initials }}</div>
<div style="min-width:0;">
<a href="#" style="font-weight:600;color:#1677ff;text-decoration:none;font-size:13.5px;">{{ r.name }}</a>
<div style="font-size:11px;color:#bfbfbf;font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ r.cid }}</div>
</div>
</div>
</td>
<td style="padding:12px 12px;">
<div style="font-size:12.5px;color:{{ r.emailColor }};font-family:'SF Mono',ui-monospace,Menlo,monospace;">{{ r.email }}</div>
<div style="font-size:11.5px;color:#bfbfbf;">{{ r.phone }}</div>
</td>
<td style="padding:12px 12px;">
<div style="display:flex;gap:5px;">
<sc-for list="{{ r.channels }}" as="ch" hint-placeholder-count="1">
<span title="{{ ch.full }}" style="display:inline-flex;align-items:center;gap:4px;padding:2px 7px;border-radius:5px;background:{{ ch.bg }};"><span style="width:5px;height:5px;border-radius:50%;background:{{ ch.color }};"></span><span style="font-size:10.5px;font-weight:600;color:{{ ch.color }};">{{ ch.label }}</span></span>
</sc-for>
</div>
</td>
<td style="padding:12px 12px;">
<div style="display:flex;gap:5px;flex-wrap:wrap;">
<sc-for list="{{ r.products }}" as="pr" hint-placeholder-count="1">
<span style="padding:2px 8px;border-radius:5px;background:{{ pr.bg }};font-size:11px;font-weight:500;color:{{ pr.color }};">{{ pr.name }}</span>
</sc-for>
</div>
</td>
<td style="padding:12px 12px;">
<div style="display:flex;align-items:center;gap:7px;"><span style="width:7px;height:7px;border-radius:50%;background:{{ r.lastDot }};flex:none;"></span><span style="font-size:12.5px;color:#595959;white-space:nowrap;">{{ r.lastLabel }}</span></div>
</td>
<td style="padding:12px 12px;text-align:right;"><span style="font-size:13px;font-weight:600;color:{{ r.openColor }};">{{ r.openD }}</span></td>
<td style="padding:12px 12px;text-align:right;color:#595959;">{{ r.orders }}</td>
<td style="padding:12px 12px;text-align:right;font-weight:600;color:{{ r.totalColor }};white-space:nowrap;">{{ r.total }}</td>
<td style="padding:12px 12px;text-align:center;position:relative;">
<button onClick="{{ r.onMenu }}" style="width:30px;height:30px;border-radius:7px;border:none;background:transparent;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;color:#8c8c8c;" style-hover="background:#f0f0f0;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
<sc-if value="{{ r.menuOpen }}" hint-placeholder-val="{{ false }}">
<div style="position:absolute;right:12px;top:42px;z-index:10;width:212px;background:#fff;border:1px solid #f0f0f0;border-radius:10px;box-shadow:0 6px 20px rgba(0,0,0,0.12);padding:5px;text-align:left;">
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#262626;font-size:13px;font-weight:500;" style-hover="background:#f5f5f5;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg>Открыть клиента</a>
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#262626;font-size:13px;font-weight:500;" style-hover="background:#f5f5f5;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6h10M8 12h10M8 18h10"/><circle cx="4" cy="6" r="1"/><circle cx="4" cy="12" r="1"/><circle cx="4" cy="18" r="1"/></svg>Объединить контакты</a>
<div style="height:1px;background:#f5f5f5;margin:4px 8px;"></div>
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#cf1322;font-size:13px;font-weight:500;" style-hover="background:#fff2f0;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9.88 9.88a3 3 0 1 0 4.24 4.24"/><path d="M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68"/><path d="M6.61 6.61A13.5 13.5 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61"/><line x1="2" y1="2" x2="22" y2="22"/></svg>Обезличить данные</a>
</div>
</sc-if>
</td>
</tr>
</sc-for>
</tbody>
</table>
</div>
<!-- empty state -->
<sc-if value="{{ isEmpty }}" hint-placeholder-val="{{ false }}">
<div style="padding:54px 20px;text-align:center;">
<div style="width:48px;height:48px;border-radius:50%;background:#f5f5f5;display:inline-flex;align-items:center;justify-content:center;margin-bottom:14px;"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="#bfbfbf" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg></div>
<div style="font-size:14px;font-weight:600;color:#595959;">Клиенты не найдены</div>
<div style="font-size:12.5px;color:#bfbfbf;margin-top:4px;">Измените условия фильтра или сбросьте их.</div>
</div>
</sc-if>
<!-- pagination -->
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 18px;border-top:1px solid #f5f5f5;">
<div style="font-size:12.5px;color:#8c8c8c;">Показано {{ shownCount }} из 248</div>
<div style="display:flex;align-items:center;gap:6px;">
<button style="height:30px;min-width:30px;padding:0 9px;border:1px solid #e8e8e8;border-radius:7px;background:#fff;color:#bfbfbf;font-size:13px;cursor:not-allowed;">‹</button>
<button style="height:30px;min-width:30px;border:1px solid #1677ff;border-radius:7px;background:#1677ff;color:#fff;font-size:13px;font-weight:600;cursor:pointer;">1</button>
<button style="height:30px;min-width:30px;border:1px solid #e8e8e8;border-radius:7px;background:#fff;color:#595959;font-size:13px;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">2</button>
<button style="height:30px;min-width:30px;border:1px solid #e8e8e8;border-radius:7px;background:#fff;color:#595959;font-size:13px;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">3</button>
<span style="font-size:13px;color:#bfbfbf;padding:0 2px;">…</span>
<button style="height:30px;min-width:30px;border:1px solid #e8e8e8;border-radius:7px;background:#fff;color:#595959;font-size:13px;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">25</button>
<button style="height:30px;min-width:30px;padding:0 9px;border:1px solid #e8e8e8;border-radius:7px;background:#fff;color:#595959;font-size:13px;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">›</button>
<div style="width:1px;height:20px;background:#f0f0f0;margin:0 4px;"></div>
<span style="font-size:12.5px;color:#8c8c8c;">10 / стр.</span>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 }
}">
class Component extends DCLogic {
state = { q: '', products: [], channels: [], openOnly: false, buyerOnly: false, sortKey: 'last', sortDir: 'asc', menuId: null, openDD: null };
renderVals() {
const fmt = (n) => n === 0 ? '—' : '₽' + n.toLocaleString('ru-RU').replace(/\u00a0/g, ' ');
const CH = {
MAX: { label: 'MAX', full: 'MAX', color: '#6b5be0', bg: '#f2f0ff' },
TG: { label: 'TG', full: 'Telegram', color: '#2f8fd0', bg: '#eaf6fd' },
WEB: { label: 'Web', full: 'Web Chat', color: '#0f9b8e', bg: '#e8f7f4' },
};
const PR = {
FP: { name: 'FirePage', color: '#0958d9', bg: '#e6f4ff' },
FX: { name: 'Foxray', color: '#722ed1', bg: '#f9f0ff' },
};
const dot = { wait: '#faad14', ai: '#722ed1', operator: '#1677ff', closed: '#bfbfbf' };
const data = [
{ name: 'Мария Соколова', initials: 'МС', avatarBg: '#eb6f4b', cid: 'CUS-4821', email: 'm.sokolova@workmail.ru', phone: '+7 ··· ·· 14', ch: ['MAX'], pr: ['FP'], last: 5, lastLabel: '5 мин назад', mode: 'wait', openD: 1, orders: 0, total: 0 },
{ name: 'Дмитрий Орлов', initials: 'ДО', avatarBg: '#3b82c4', cid: 'CUS-4789', email: 'd.orlov@gmail.com', phone: '+7 ··· ·· 03', ch: ['TG'], pr: ['FX'], last: 8, lastLabel: '8 мин назад', mode: 'ai', openD: 1, orders: 2, total: 4980 },
{ name: 'Елена Кузнецова', initials: 'ЕК', avatarBg: '#9254de', cid: 'CUS-4702', email: 'e.kuznetsova@corp.ru', phone: '+7 ··· ·· 88', ch: ['MAX', 'WEB'], pr: ['FX', 'FP'], last: 18, lastLabel: '18 мин назад', mode: 'operator', openD: 1, orders: 3, total: 12470 },
{ name: 'Сергей Волков', initials: 'СВ', avatarBg: '#13a8a8', cid: 'CUS-4655', email: 's.volkov@mail.ru', phone: '+7 ··· ·· 21', ch: ['TG'], pr: ['FP'], last: 26, lastLabel: '26 мин назад', mode: 'ai', openD: 1, orders: 1, total: 2490 },
{ name: 'Ольга Зайцева', initials: 'ОЗ', avatarBg: '#d4860b', cid: 'CUS-4590', email: 'o.zaytseva@yandex.ru', phone: '+7 ··· ·· 47', ch: ['WEB'], pr: ['FX'], last: 35, lastLabel: '35 мин назад', mode: 'operator', openD: 1, orders: 0, total: 0 },
{ name: 'Павел Новиков', initials: 'ПН', avatarBg: '#52a838', cid: 'CUS-4410', email: 'p.novikov@firm.io', phone: '+7 ··· ·· 60', ch: ['MAX'], pr: ['FP'], last: 60, lastLabel: '1 ч назад', mode: 'closed', openD: 0, orders: 4, total: 19600 },
{ name: 'Анна Морозова', initials: 'АМ', avatarBg: '#c4456b', cid: 'CUS-4322', email: 'a.morozova@studio.com', phone: '+7 ··· ·· 12', ch: ['TG', 'MAX'], pr: ['FP', 'FX'], last: 180, lastLabel: '3 ч назад', mode: 'closed', openD: 0, orders: 6, total: 31200 },
{ name: 'Гость 8842', initials: 'Г8', avatarBg: '#8c8c8c', cid: 'CUS-4901', email: 'без контакта', phone: 'идентификация по каналу', anon: true, ch: ['WEB'], pr: ['FP'], last: 12, lastLabel: '12 мин назад', mode: 'wait', openD: 1, orders: 0, total: 0 },
{ name: 'Игорь Соколов', initials: 'ИС', avatarBg: '#4c6ef0', cid: 'CUS-4188', email: 'i.sokolov@dev.team', phone: '+7 ··· ·· 35', ch: ['MAX'], pr: ['FX'], last: 300, lastLabel: '5 ч назад', mode: 'closed', openD: 0, orders: 2, total: 6970 },
{ name: 'Татьяна Лебедева', initials: 'ТЛ', avatarBg: '#7048b6', cid: 'CUS-3980', email: 't.lebedeva@agency.ru', phone: '+7 ··· ·· 99', ch: ['TG', 'MAX'], pr: ['FP'], last: 1440, lastLabel: '1 д назад', mode: 'closed', openD: 0, orders: 8, total: 42800 },
];
const { q, products, channels, openOnly, buyerOnly, sortKey, sortDir, menuId, openDD } = this.state;
const ql = q.trim().toLowerCase();
let rows = data.filter((d) =>
(!ql || d.name.toLowerCase().includes(ql) || d.email.toLowerCase().includes(ql)) &&
(products.length === 0 || d.pr.some((p) => products.includes(p))) &&
(channels.length === 0 || d.ch.some((c) => channels.includes(c))) &&
(!openOnly || d.openD > 0) &&
(!buyerOnly || d.orders > 0));
const key = { last: 'last', open: 'openD', orders: 'orders', total: 'total' }[sortKey];
rows = [...rows].sort((a, b) => sortDir === 'asc' ? a[key] - b[key] : b[key] - a[key]);
const out = rows.map((d) => ({
name: d.name, initials: d.initials, avatarBg: d.avatarBg, cid: d.cid,
email: d.email, phone: d.phone, emailColor: d.anon ? '#bfbfbf' : '#595959',
channels: d.ch.map((c) => CH[c]),
products: d.pr.map((p) => PR[p]),
lastLabel: d.lastLabel, lastDot: dot[d.mode],
openD: String(d.openD), openColor: d.openD > 0 ? '#d48806' : '#bfbfbf',
orders: String(d.orders),
total: fmt(d.total), totalColor: d.total > 0 ? '#262626' : '#bfbfbf',
menuOpen: menuId === d.cid,
onMenu: () => this.setState((s) => ({ menuId: s.menuId === d.cid ? null : d.cid })),
}));
const ddBase = 'display:inline-flex;align-items:center;gap:8px;height:34px;padding:0 12px;border:1px solid #e8e8e8;border-radius:8px;background:#fff;color:#595959;font-size:13px;font-weight:500;cursor:pointer;white-space:nowrap;';
const ddActive = 'display:inline-flex;align-items:center;gap:8px;height:34px;padding:0 12px;border:1px solid #1677ff;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap;';
const boxBase = 'width:17px;height:17px;border-radius:5px;border:1.5px solid #d9d9d9;background:#fff;display:inline-flex;align-items:center;justify-content:center;flex:none;';
const boxOn = 'width:17px;height:17px;border-radius:5px;border:1.5px solid #1677ff;background:#1677ff;display:inline-flex;align-items:center;justify-content:center;flex:none;';
const PRLIST = [{ code: 'FP', name: 'FirePage' }, { code: 'FX', name: 'Foxray' }];
const CHLIST = [{ code: 'MAX', name: 'MAX' }, { code: 'TG', name: 'Telegram' }, { code: 'WEB', name: 'Web Chat' }];
const toggleArr = (key, code) => this.setState((s) => {
const arr = s[key]; return { [key]: arr.includes(code) ? arr.filter((x) => x !== code) : [...arr, code] };
});
const prodOpts = PRLIST.map((o) => ({ name: o.name, checked: products.includes(o.code), box: products.includes(o.code) ? boxOn : boxBase, onToggle: () => toggleArr('products', o.code) }));
const chanOpts = CHLIST.map((o) => ({ name: o.name, dot: CH[o.code].color, checked: channels.includes(o.code), box: channels.includes(o.code) ? boxOn : boxBase, onToggle: () => toggleArr('channels', o.code) }));
const chipOff = 'display:inline-flex;align-items:center;gap:6px;height:34px;padding:0 13px;border:1px solid #e8e8e8;border-radius:8px;background:#fff;color:#595959;font-size:12.5px;font-weight:500;cursor:pointer;white-space:nowrap;';
const chipOn = 'display:inline-flex;align-items:center;gap:6px;height:34px;padding:0 13px;border:1px solid #1677ff;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:12.5px;font-weight:600;cursor:pointer;white-space:nowrap;';
const arrow = (k) => sortKey === k ? (sortDir === 'asc' ? '↑' : '↓') : '';
const sortBy = (k) => this.setState((s) => ({ sortKey: k, sortDir: s.sortKey === k && s.sortDir === 'asc' ? 'desc' : 'asc', menuId: null }));
return {
rows: out, shownCount: String(out.length), isEmpty: out.length === 0,
q,
prodOpts, chanOpts,
prodLabel: products.length ? 'Продукты' : 'Все продукты',
chanLabel: channels.length ? 'Каналы' : 'Все каналы',
prodCount: products.length || 0, chanCount: channels.length || 0,
ddProdBtn: (products.length > 0 || openDD === 'prod') ? ddActive : ddBase,
ddChanBtn: (channels.length > 0 || openDD === 'chan') ? ddActive : ddBase,
ddProdOpen: openDD === 'prod', ddChanOpen: openDD === 'chan', ddAnyOpen: openDD !== null,
ddProdRot: openDD === 'prod' ? 'rotate(180deg)' : 'none',
ddChanRot: openDD === 'chan' ? 'rotate(180deg)' : 'none',
onToggleProd: () => this.setState((s) => ({ openDD: s.openDD === 'prod' ? null : 'prod', menuId: null })),
onToggleChan: () => this.setState((s) => ({ openDD: s.openDD === 'chan' ? null : 'chan', menuId: null })),
onCloseDD: () => this.setState({ openDD: null }),
chipOpen: openOnly ? chipOn : chipOff,
chipBuyer: buyerOnly ? chipOn : chipOff,
arrLast: arrow('last'), arrOpen: arrow('open'), arrOrders: arrow('orders'), arrTotal: arrow('total'),
onSearch: (e) => this.setState({ q: e.target.value, menuId: null }),
onOpenToggle: () => this.setState((s) => ({ openOnly: !s.openOnly, menuId: null, openDD: null })),
onBuyerToggle: () => this.setState((s) => ({ buyerOnly: !s.buyerOnly, menuId: null, openDD: null })),
onReset: () => this.setState({ q: '', products: [], channels: [], openOnly: false, buyerOnly: false, menuId: null, openDD: null }),
onSortLast: () => sortBy('last'), onSortOpen: () => sortBy('open'),
onSortOrders: () => sortBy('orders'), onSortTotal: () => sortBy('total'),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,371 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1180px;">
<!-- ============ SIDEBAR (отдел продаж) ============ -->
<aside style="width:240px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;padding:0 14px;border-bottom:1px solid #f5f5f5;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:9px;height:36px;padding:0 12px;border-radius:8px;text-decoration:none;color:#595959;font-size:13px;font-weight:500;border:1px solid #f0f0f0;width:100%;" style-hover="background:#f5f5f5;color:#1677ff;border-color:#d9d9d9;">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
Назад в Hub
</a>
</div>
<div style="padding:16px 16px 8px;">
<div style="display:flex;align-items:center;gap:11px;">
<div style="width:34px;height:34px;border-radius:9px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;flex:none;">
<svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="#1677ff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/></svg>
</div>
<div style="display:flex;flex-direction:column;line-height:1.15;">
<span style="font-size:15px;font-weight:700;color:#1f1f1f;">Продажи</span>
<span style="font-size:11px;color:#8c8c8c;">Рабочее пространство</span>
</div>
</div>
</div>
<nav style="flex:1;overflow-y:auto;padding:8px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;">
<span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span>
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 13h8V3H3zM13 21h8V11h-8zM13 3v6h8V3zM3 17h8v4H3z"/></svg>
Обзор
</a>
<a href="Продажи · Диалоги.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
Диалоги
<span style="margin-left:auto;min-width:20px;height:20px;padding:0 6px;border-radius:10px;background:#faad14;color:#fff;font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;">2</span>
</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
Клиенты
</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h2l2.6 12.4a2 2 0 0 0 2 1.6h9.7a2 2 0 0 0 2-1.6L23 6H6"/><circle cx="9" cy="20" r="1"/><circle cx="18" cy="20" r="1"/></svg>
Продажи
</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;">
<div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div>
<div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div>
</a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;">
<span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span>
<span style="font-weight:500;color:#595959;">Продажи</span><span style="color:#d9d9d9;">/</span>
<span style="font-weight:600;color:#262626;">Обзор</span>
</div>
<div style="display:flex;align-items:center;gap:14px;">
<span style="display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:6px;background:#f5f5f5;font-size:12px;font-weight:600;color:#595959;"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 5v6c0 5 3.4 8.5 8 10 4.6-1.5 8-5 8-10V5Z"/></svg>OWNER</span>
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1280px;margin:0 auto;">
<!-- PAGE HEADER -->
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:20px;">
<div>
<h1 style="margin:0;font-size:24px;font-weight:700;letter-spacing:-0.02em;color:#1f1f1f;line-height:1.2;">Обзор отдела продаж</h1>
<p style="margin:6px 0 0;font-size:13.5px;color:#8c8c8c;">Операционное состояние и результаты · обновлено только что</p>
</div>
<div style="display:flex;align-items:center;gap:3px;padding:3px;border-radius:9px;background:#f0f2f5;flex:none;">
<button onClick="{{ onToday }}" style="{{ tabToday }}">Сегодня</button>
<button onClick="{{ on7 }}" style="{{ tab7 }}">7 дней</button>
<button onClick="{{ on30 }}" style="{{ tab30 }}">30 дней</button>
</div>
</div>
<!-- LEVEL 1: operational -->
<div style="font-size:11px;font-weight:600;letter-spacing:0.05em;color:#bfbfbf;margin:0 0 10px 2px;">ОПЕРАЦИОННЫЕ · СЕЙЧАС</div>
<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:14px;margin-bottom:20px;">
<sc-for list="{{ opsKpi }}" as="k" hint-placeholder-count="5">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:15px 16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);">
<div style="font-size:12.5px;color:#8c8c8c;margin-bottom:9px;display:flex;align-items:center;gap:6px;"><sc-if value="{{ k.dot }}" hint-placeholder-val="{{ false }}"><span style="width:7px;height:7px;border-radius:50%;background:{{ k.dot }};"></span></sc-if>{{ k.label }}</div>
<div style="font-size:25px;font-weight:700;color:{{ k.valueColor }};line-height:1;">{{ k.value }}</div>
<div style="font-size:12px;color:{{ k.subColor }};margin-top:8px;">{{ k.sub }}</div>
</div>
</sc-for>
</div>
<!-- LEVEL 1: results -->
<div style="font-size:11px;font-weight:600;letter-spacing:0.05em;color:#bfbfbf;margin:0 0 10px 2px;">РЕЗУЛЬТАТ · {{ periodUpper }}</div>
<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:14px;margin-bottom:24px;">
<sc-for list="{{ resKpi }}" as="k" hint-placeholder-count="5">
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:11px;padding:15px 16px;box-shadow:0 1px 2px rgba(0,0,0,0.03);">
<div style="font-size:12.5px;color:#8c8c8c;margin-bottom:9px;">{{ k.label }}</div>
<div style="font-size:25px;font-weight:700;color:#1f1f1f;line-height:1;">{{ k.value }}</div>
<div style="display:flex;align-items:center;gap:7px;margin-top:9px;">
<span style="display:inline-flex;align-items:center;gap:3px;color:{{ k.deltaColor }};font-size:12px;font-weight:600;">
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="{{ k.deltaColor }}" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" style="transform:{{ k.arrowRot }};"><polyline points="6 14 12 8 18 14"/></svg>
{{ k.deltaText }}
</span>
<span style="font-size:11.5px;color:#bfbfbf;">{{ k.sub }}</span>
</div>
</div>
</sc-for>
</div>
<!-- LEVEL 2: chart -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;padding:18px 20px 14px;box-shadow:0 1px 3px rgba(0,0,0,0.04);margin-bottom:18px;">
<div style="display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:6px;">
<div>
<h3 style="margin:0;font-size:15px;font-weight:700;color:#1f1f1f;">Динамика продаж</h3>
<div style="display:flex;align-items:baseline;gap:9px;margin-top:6px;">
<span style="font-size:22px;font-weight:700;color:#1f1f1f;">{{ chartTotal }}</span>
<span style="display:inline-flex;align-items:center;gap:3px;color:#389e0d;font-size:12.5px;font-weight:600;"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#389e0d" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 14 12 8 18 14"/></svg>{{ chartDelta }}</span>
<span style="font-size:12px;color:#bfbfbf;">чистая выручка · {{ periodLabel }}</span>
</div>
</div>
<div style="display:flex;align-items:center;gap:6px;font-size:12px;color:#8c8c8c;"><span style="width:9px;height:9px;border-radius:2px;background:#1677ff;"></span>Выручка</div>
</div>
<div style="position:relative;">
<svg viewBox="0 0 1000 260" preserveAspectRatio="none" style="width:100%;height:230px;display:block;">
<defs><linearGradient id="salesFill" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#1677ff" stop-opacity="0.16"/><stop offset="1" stop-color="#1677ff" stop-opacity="0"/></linearGradient></defs>
<line x1="10" x2="990" y1="{{ g1 }}" y2="{{ g1 }}" stroke="#f2f2f2" stroke-width="1" vector-effect="non-scaling-stroke"/>
<line x1="10" x2="990" y1="{{ g2 }}" y2="{{ g2 }}" stroke="#f2f2f2" stroke-width="1" vector-effect="non-scaling-stroke"/>
<line x1="10" x2="990" y1="{{ g3 }}" y2="{{ g3 }}" stroke="#f2f2f2" stroke-width="1" vector-effect="non-scaling-stroke"/>
<path d="{{ areaPath }}" fill="url(#salesFill)"/>
<path d="{{ linePath }}" fill="none" stroke="#1677ff" stroke-width="2.5" vector-effect="non-scaling-stroke" stroke-linejoin="round" stroke-linecap="round"/>
<circle cx="{{ lastX }}" cy="{{ lastY }}" r="4.5" fill="#1677ff" stroke="#fff" stroke-width="2.5" vector-effect="non-scaling-stroke"/>
</svg>
<div style="display:flex;justify-content:space-between;margin-top:6px;padding:0 2px;">
<sc-for list="{{ xLabels }}" as="x" hint-placeholder-count="7">
<span style="font-size:11px;color:#bfbfbf;">{{ x.label }}</span>
</sc-for>
</div>
</div>
</div>
<!-- LEVEL 2: blocks grid -->
<div style="display:grid;grid-template-columns:repeat(12,1fr);gap:16px;">
<!-- Продукты -->
<div style="grid-column:span 7;background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:15px 18px 12px;border-bottom:1px solid #f5f5f5;display:flex;align-items:center;justify-content:space-between;">
<h3 style="margin:0;font-size:15px;font-weight:700;color:#1f1f1f;">Продукты</h3>
<a href="#" style="font-size:12.5px;color:#1677ff;text-decoration:none;font-weight:500;">Все продукты</a>
</div>
<table style="width:100%;border-collapse:collapse;font-size:13px;">
<thead><tr style="background:#fafafa;">
<th style="text-align:left;padding:9px 18px;font-size:11px;font-weight:600;color:#8c8c8c;letter-spacing:0.03em;">ПРОДУКТ</th>
<th style="text-align:left;padding:9px 10px;font-size:11px;font-weight:600;color:#8c8c8c;">СТАТУС</th>
<th style="text-align:right;padding:9px 10px;font-size:11px;font-weight:600;color:#8c8c8c;">ПРОДАЖИ</th>
<th style="text-align:right;padding:9px 10px;font-size:11px;font-weight:600;color:#8c8c8c;">ВЫРУЧКА</th>
<th style="text-align:right;padding:9px 10px;font-size:11px;font-weight:600;color:#8c8c8c;">КОНВ.</th>
<th style="text-align:right;padding:9px 18px;font-size:11px;font-weight:600;color:#8c8c8c;">ДИАЛОГИ</th>
</tr></thead>
<tbody>
<sc-for list="{{ products }}" as="p" hint-placeholder-count="2">
<tr style="border-top:1px solid #f5f5f5;">
<td style="padding:12px 18px;"><a href="#" style="font-weight:600;color:#1677ff;text-decoration:none;">{{ p.name }}</a></td>
<td style="padding:12px 10px;"><span style="display:inline-flex;align-items:center;gap:5px;font-size:12px;color:#389e0d;font-weight:500;"><span style="width:6px;height:6px;border-radius:50%;background:#52c41a;"></span>{{ p.status }}</span></td>
<td style="padding:12px 10px;text-align:right;font-weight:600;color:#262626;">{{ p.sales }}</td>
<td style="padding:12px 10px;text-align:right;font-weight:600;color:#262626;">{{ p.rev }}</td>
<td style="padding:12px 10px;text-align:right;color:#595959;">{{ p.conv }}</td>
<td style="padding:12px 18px;text-align:right;color:#595959;">{{ p.dlg }}</td>
</tr>
</sc-for>
</tbody>
</table>
</div>
<!-- Каналы -->
<div style="grid-column:span 5;background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:15px 18px 18px;">
<h3 style="margin:0 0 14px;font-size:15px;font-weight:700;color:#1f1f1f;">Каналы</h3>
<sc-for list="{{ channels }}" as="c" hint-placeholder-count="3">
<div style="margin-bottom:15px;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:7px;">
<span style="display:inline-flex;align-items:center;gap:7px;font-size:13px;font-weight:600;color:#262626;"><span style="width:8px;height:8px;border-radius:50%;background:{{ c.color }};"></span>{{ c.name }}</span>
<span style="font-size:12px;color:#8c8c8c;">{{ c.dlg }} диал. · <b style="color:#262626;">{{ c.sales }}</b> продаж</span>
</div>
<div style="height:7px;border-radius:999px;background:#f0f0f0;overflow:hidden;"><div style="height:7px;border-radius:999px;background:{{ c.color }};width:{{ c.share }}%;"></div></div>
</div>
</sc-for>
</div>
<!-- AI и операторы -->
<div style="grid-column:span 4;background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);padding:15px 18px 18px;">
<h3 style="margin:0 0 14px;font-size:15px;font-weight:700;color:#1f1f1f;">AI и операторы</h3>
<div style="display:flex;flex-direction:column;gap:12px;">
<div style="border:1px solid #efdbff;border-radius:10px;padding:12px 13px;background:#fcfaff;">
<div style="display:flex;align-items:center;gap:7px;margin-bottom:10px;"><span style="width:22px;height:22px;border-radius:6px;background:#f9f0ff;display:flex;align-items:center;justify-content:center;"><span style="width:8px;height:8px;border-radius:50%;background:#722ed1;"></span></span><span style="font-size:13px;font-weight:600;color:#722ed1;">AI-агент</span></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;">
<div><div style="font-size:11px;color:#8c8c8c;">Диалоги</div><div style="font-size:16px;font-weight:700;color:#262626;">{{ aiDlg }}</div></div>
<div><div style="font-size:11px;color:#8c8c8c;">Продажи</div><div style="font-size:16px;font-weight:700;color:#262626;">{{ aiSales }}</div></div>
<div><div style="font-size:11px;color:#8c8c8c;">Конверсия</div><div style="font-size:16px;font-weight:700;color:#262626;">{{ aiConv }}</div></div>
<div><div style="font-size:11px;color:#8c8c8c;">Стоимость</div><div style="font-size:16px;font-weight:700;color:#262626;">{{ aiCost }}</div></div>
</div>
</div>
<div style="border:1px solid #d6e4ff;border-radius:10px;padding:12px 13px;background:#f7faff;">
<div style="display:flex;align-items:center;gap:7px;margin-bottom:10px;"><span style="width:22px;height:22px;border-radius:6px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;"><span style="width:8px;height:8px;border-radius:50%;background:#1677ff;"></span></span><span style="font-size:13px;font-weight:600;color:#0958d9;">Операторы</span></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;">
<div><div style="font-size:11px;color:#8c8c8c;">Диалоги</div><div style="font-size:16px;font-weight:700;color:#262626;">{{ opDlg }}</div></div>
<div><div style="font-size:11px;color:#8c8c8c;">Продажи</div><div style="font-size:16px;font-weight:700;color:#262626;">{{ opSales }}</div></div>
<div><div style="font-size:11px;color:#8c8c8c;">Конверсия</div><div style="font-size:16px;font-weight:700;color:#262626;">{{ opConv }}</div></div>
<div><div style="font-size:11px;color:#8c8c8c;">Передано AI→</div><div style="font-size:16px;font-weight:700;color:#262626;">{{ handoff }}</div></div>
</div>
</div>
</div>
</div>
<!-- Проблемные диалоги -->
<div style="grid-column:span 4;background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:15px 18px 12px;display:flex;align-items:center;gap:9px;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#faad14" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m21.7 18-8-14a2 2 0 0 0-3.5 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3Z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
<h3 style="margin:0;font-size:15px;font-weight:700;color:#1f1f1f;">Проблемные диалоги</h3>
</div>
<sc-for list="{{ problems }}" as="p" hint-placeholder-count="2">
<a href="Продажи · Диалоги.dc.html" style="display:flex;align-items:flex-start;gap:11px;padding:11px 18px;text-decoration:none;border-top:1px solid #f5f5f5;" style-hover="background:#fafafa;">
<span style="width:8px;height:8px;border-radius:50%;background:{{ p.dot }};margin-top:5px;flex:none;"></span>
<span style="flex:1;min-width:0;"><span style="display:block;font-size:13px;font-weight:500;color:#262626;line-height:1.35;">{{ p.title }}</span><span style="display:block;font-size:11.5px;color:#8c8c8c;margin-top:2px;">{{ p.meta }}</span></span>
<span style="font-size:11.5px;color:#bfbfbf;flex:none;">{{ p.time }}</span>
</a>
</sc-for>
</div>
<!-- Платежи / fulfillment -->
<div style="grid-column:span 4;background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="padding:15px 18px 12px;display:flex;align-items:center;gap:9px;">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#595959" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="5" width="20" height="14" rx="2"/><line x1="2" y1="10" x2="22" y2="10"/></svg>
<h3 style="margin:0;font-size:15px;font-weight:700;color:#1f1f1f;">Платежи и fulfillment</h3>
</div>
<sc-for list="{{ payments }}" as="p" hint-placeholder-count="2">
<a href="#" style="display:flex;align-items:flex-start;gap:11px;padding:11px 18px;text-decoration:none;border-top:1px solid #f5f5f5;" style-hover="background:#fafafa;">
<span style="width:8px;height:8px;border-radius:50%;background:{{ p.dot }};margin-top:5px;flex:none;"></span>
<span style="flex:1;min-width:0;"><span style="display:block;font-size:13px;font-weight:500;color:#262626;line-height:1.35;">{{ p.title }}</span><span style="display:block;font-size:11.5px;color:#8c8c8c;margin-top:2px;">{{ p.meta }}</span></span>
<span style="font-size:11.5px;color:#bfbfbf;flex:none;">{{ p.time }}</span>
</a>
</sc-for>
</div>
</div>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 },
&quot;period&quot;: { &quot;editor&quot;: &quot;enum&quot;, &quot;options&quot;: [&quot;today&quot;, &quot;d7&quot;, &quot;d30&quot;], &quot;default&quot;: &quot;today&quot;, &quot;tsType&quot;: &quot;string&quot; }
}">
class Component extends DCLogic {
state = { period: null };
renderVals() {
const period = this.state.period ?? this.props.period ?? 'today';
const f = period === 'd7' ? 7 : period === 'd30' ? 30 : 1;
const fmt = (n) => '₽' + Math.round(n).toLocaleString('ru-RU').replace(/\u00a0/g, ' ');
const periodLabel = { today: 'Сегодня', d7: '7 дней', d30: '30 дней' }[period];
// --- operational (now) ---
const opsKpi = [
{ label: 'Открытые диалоги', value: '42', sub: 'в работе', subColor: '#8c8c8c' },
{ label: 'Активные сейчас', value: '9', sub: 'за 15 минут', subColor: '#8c8c8c' },
{ label: 'На AI', value: '35', sub: '83% диалогов', subColor: '#8c8c8c', dot: '#722ed1' },
{ label: 'На операторах', value: '7', sub: '17% диалогов', subColor: '#8c8c8c', dot: '#1677ff' },
{ label: 'Ожидают оператора', value: '0', valueColor: '#389e0d', sub: 'очередь пуста', subColor: '#389e0d' },
].map((k) => ({ dot: k.dot ?? false, valueColor: k.valueColor ?? '#1f1f1f', ...k }));
// --- results (period) ---
const up = '#389e0d', down = '#cf1322', neutral = '#8c8c8c';
const resData = {
today: { sales: '18', rev: fmt(146200), conv: '14,2%', aiCost: fmt(1240), perSale: fmt(69) },
d7: { sales: '126', rev: fmt(1024600), conv: '13,6%', aiCost: fmt(8600), perSale: fmt(68) },
d30: { sales: '540', rev: fmt(4386000), conv: '13,1%', aiCost: fmt(36400), perSale: fmt(67) },
}[period];
const resKpi = [
{ label: 'Продажи', value: resData.sales, deltaText: '+12%', deltaColor: up, up: true, sub: 'к пред.' },
{ label: 'Чистая выручка', value: resData.rev, deltaText: '+8%', deltaColor: up, up: true, sub: 'к пред.' },
{ label: 'Конверсия', value: resData.conv, deltaText: '+1,3 пп', deltaColor: up, up: true, sub: 'к пред.' },
{ label: 'Стоимость AI', value: resData.aiCost, deltaText: '+4%', deltaColor: neutral, up: true, sub: 'к пред.' },
{ label: 'Стоимость AI / продажа', value: resData.perSale, deltaText: '−3%', deltaColor: up, up: false, sub: 'дешевле' },
].map((k) => ({ ...k, arrowRot: k.up ? 'none' : 'rotate(180deg)' }));
// --- chart ---
const series = {
today: { vals: [6, 9, 7, 14, 11, 18, 13, 16, 21, 19], labels: ['09', '10', '11', '12', '13', '14', '15', '16', '17', '18'] },
d7: { vals: [78, 92, 85, 140, 118, 164, 150], labels: ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'] },
d30: { vals: [120, 135, 128, 150, 142, 168, 175, 160, 182, 176, 190, 185, 205, 198, 220], labels: ['1', '5', '10', '15', '20', '25', '30'] },
}[period];
const W = 1000, H = 260, pl = 10, pr = 10, pt = 18, pb = 26;
const iw = W - pl - pr, ih = H - pt - pb, n = series.vals.length;
const max = Math.max(...series.vals) * 1.12;
const xs = (i) => pl + iw * (n === 1 ? 0 : i / (n - 1));
const ys = (v) => pt + ih * (1 - v / max);
const pts = series.vals.map((v, i) => ({ x: xs(i), y: ys(v) }));
const linePath = 'M' + pts.map((p) => p.x.toFixed(1) + ',' + p.y.toFixed(1)).join(' L');
const areaPath = linePath + ` L${xs(n - 1).toFixed(1)},${(pt + ih).toFixed(1)} L${pl.toFixed(1)},${(pt + ih).toFixed(1)} Z`;
const last = pts[n - 1];
const xLabels = series.labels.map((l) => ({ label: l }));
// --- products / channels scaled by f ---
const products = [
{ name: 'FirePage', status: 'Активен', salesN: 12, revN: 98400, conv: '15,1%', dlg: '28' },
{ name: 'Foxray', status: 'Активен', salesN: 6, revN: 47800, conv: '12,8%', dlg: '14' },
].map((p) => ({ name: p.name, status: p.status, conv: p.conv, dlg: p.dlg, sales: String(p.salesN * f), rev: fmt(p.revN * f) }));
const channels = [
{ name: 'MAX', color: '#6b5be0', dlg: '18', salesN: 9, share: 50 },
{ name: 'Telegram', color: '#2f8fd0', dlg: '14', salesN: 6, share: 33 },
{ name: 'Web Chat', color: '#0f9b8e', dlg: '10', salesN: 3, share: 17 },
].map((c) => ({ ...c, sales: String(c.salesN * f) }));
// --- AI / operators ---
const aiSales = 11 * f, opSales = 7 * f;
const problems = [
{ dot: '#faad14', title: 'Гость 8842 · нет ответа клиента 18 мин', meta: 'FirePage · Web Chat', time: '18 мин' },
{ dot: '#1677ff', title: 'Длинный диалог · 24 сообщения без продажи', meta: 'Foxray · Telegram', time: '32 мин' },
{ dot: '#faad14', title: 'Гость 5510 · повторное обращение', meta: 'Foxray · Telegram', time: '1 ч' },
];
const payments = [
{ dot: '#faad14', title: 'Незавершённый платёж · ORD-10482', meta: 'Точка · ₽2 490 · FirePage', time: '6 мин' },
{ dot: '#1677ff', title: 'Подписка: продление через 2 дня', meta: 'Foxray Pro · ORD-10311', time: '—' },
];
const baseTab = 'padding:6px 15px;border:none;border-radius:7px;font-size:13px;font-weight:500;cursor:pointer;background:transparent;color:#595959;';
const actTab = 'padding:6px 15px;border:none;border-radius:7px;font-size:13px;font-weight:600;cursor:pointer;background:#ffffff;color:#1f1f1f;box-shadow:0 1px 2px rgba(0,0,0,0.1);';
const setP = (p) => this.setState({ period: p });
return {
opsKpi, resKpi, periodLabel, periodUpper: periodLabel.toUpperCase(),
areaPath, linePath, lastX: last.x.toFixed(1), lastY: last.y.toFixed(1),
g1: (pt + ih * 0.25).toFixed(1), g2: (pt + ih * 0.55).toFixed(1), g3: (pt + ih * 0.85).toFixed(1),
xLabels, chartTotal: resData.rev, chartDelta: '+8%',
products, channels,
aiDlg: '35', aiSales: String(aiSales), aiConv: '13,2%', aiCost: resData.aiCost,
opDlg: '7', opSales: String(opSales), opConv: '41%', handoff: '4',
problems, payments,
tabToday: period === 'today' ? actTab : baseTab,
tab7: period === 'd7' ? actTab : baseTab,
tab30: period === 'd30' ? actTab : baseTab,
onToday: () => setP('today'), on7: () => setP('d7'), on30: () => setP('d30'),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,364 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1180px;">
<!-- ============ SIDEBAR ============ -->
<aside style="width:240px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;padding:0 14px;border-bottom:1px solid #f5f5f5;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:9px;height:36px;padding:0 12px;border-radius:8px;text-decoration:none;color:#595959;font-size:13px;font-weight:500;border:1px solid #f0f0f0;width:100%;" style-hover="background:#f5f5f5;color:#1677ff;border-color:#d9d9d9;">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
Назад в Hub
</a>
</div>
<div style="padding:16px 16px 8px;">
<div style="display:flex;align-items:center;gap:11px;">
<div style="width:34px;height:34px;border-radius:9px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="#1677ff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:15px;font-weight:700;color:#1f1f1f;">Продажи</span><span style="font-size:11px;color:#8c8c8c;">Рабочее пространство</span></div>
</div>
</div>
<nav style="flex:1;overflow-y:auto;padding:8px 12px;">
<a href="Продажи · Обзор.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 13h8V3H3zM13 21h8V11h-8zM13 3v6h8V3zM3 17h8v4H3z"/></svg>Обзор</a>
<a href="Продажи · Диалоги.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>Диалоги<span style="margin-left:auto;min-width:20px;height:20px;padding:0 6px;border-radius:10px;background:#faad14;color:#fff;font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;">2</span></a>
<a href="Продажи · Клиенты.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Клиенты</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h2l2.6 12.4a2 2 0 0 0 2 1.6h9.7a2 2 0 0 0 2-1.6L23 6H6"/><circle cx="9" cy="20" r="1"/><circle cx="18" cy="20" r="1"/></svg>Продажи</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><span style="font-weight:500;color:#595959;">Продажи</span><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">Продажи</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<span style="display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:6px;background:#f5f5f5;font-size:12px;font-weight:600;color:#595959;"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#8c8c8c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 5v6c0 5 3.4 8.5 8 10 4.6-1.5 8-5 8-10V5Z"/></svg>OWNER</span>
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1340px;margin:0 auto;">
<!-- PAGE HEADER -->
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:18px;">
<div>
<h1 style="margin:0;font-size:24px;font-weight:700;letter-spacing:-0.02em;color:#1f1f1f;line-height:1.2;">Продажи</h1>
<p style="margin:6px 0 0;font-size:13.5px;color:#8c8c8c;">Заказы, платежи, возвраты, подписки и исполнение · основной объект — заказ</p>
</div>
<div style="display:flex;align-items:center;gap:9px;flex:none;">
<div style="display:flex;align-items:center;gap:8px;height:36px;padding:0 12px;border:1px solid #e8e8e8;border-radius:8px;background:#fff;width:240px;" style-focus="border-color:#1677ff;">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="#bfbfbf" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input value="{{ q }}" onInput="{{ onSearch }}" placeholder="Поиск по ID или клиенту…" style="border:none;outline:none;background:transparent;font-size:13px;color:#262626;width:100%;font-family:inherit;" />
</div>
<button style="display:flex;align-items:center;gap:7px;height:36px;padding:0 14px;border-radius:8px;border:1px solid #d9d9d9;background:#fff;color:#262626;font-size:13px;font-weight:500;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>Экспорт</button>
</div>
</div>
<!-- TABS -->
<div style="display:flex;align-items:center;gap:4px;border-bottom:1px solid #e8e8e8;margin-bottom:18px;">
<button onClick="{{ onTabO }}" style="{{ tabO }}">Заказы <span style="{{ badgeO }}">6</span></button>
<button onClick="{{ onTabS }}" style="{{ tabS }}">Подписки <span style="{{ badgeS }}">4</span></button>
<button onClick="{{ onTabP }}" style="{{ tabP }}">Платежи <span style="{{ badgeP }}">5</span></button>
<button onClick="{{ onTabR }}" style="{{ tabR }}">Возвраты <span style="{{ badgeR }}">3</span></button>
<button onClick="{{ onTabE }}" style="{{ tabE }}">Исполнение <span style="{{ badgeE }}">4</span></button>
</div>
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="overflow-x:auto;">
<!-- ===== ЗАКАЗЫ ===== -->
<sc-if value="{{ isOrders }}" hint-placeholder-val="{{ true }}">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:1180px;">
<thead><tr style="background:#fafafa;">
<th style="text-align:left;padding:11px 16px;font-size:11px;font-weight:600;color:#8c8c8c;letter-spacing:0.03em;border-bottom:1px solid #f0f0f0;">ЗАКАЗ</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ДАТА</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">КЛИЕНТ</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПРОДУКТ / OFFER</th>
<th style="text-align:right;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СУММА</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ОПЛАТА</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ИСПОЛНЕНИЕ</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ИСТОЧНИК</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПРОДАВЕЦ</th>
<th style="width:44px;border-bottom:1px solid #f0f0f0;"></th>
</tr></thead>
<tbody>
<sc-for list="{{ rows }}" as="r" hint-placeholder-count="6">
<tr style="border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<td style="padding:12px 16px;"><a href="#" style="font-weight:600;color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;">{{ r.id }}</a></td>
<td style="padding:12px 10px;color:#595959;white-space:nowrap;">{{ r.date }}</td>
<td style="padding:12px 10px;color:#262626;">{{ r.client }}</td>
<td style="padding:12px 10px;color:#595959;">{{ r.offer }}</td>
<td style="padding:12px 10px;text-align:right;font-weight:600;color:#262626;white-space:nowrap;">{{ r.amount }}</td>
<td style="padding:12px 10px;"><span style="padding:2px 9px;border-radius:6px;background:{{ r.payBg }};color:{{ r.payColor }};font-size:11.5px;font-weight:600;white-space:nowrap;">{{ r.payLabel }}</span></td>
<td style="padding:12px 10px;"><span style="padding:2px 9px;border-radius:6px;background:{{ r.fulBg }};color:{{ r.fulColor }};font-size:11.5px;font-weight:600;white-space:nowrap;">{{ r.fulLabel }}</span></td>
<td style="padding:12px 10px;"><span style="display:inline-flex;align-items:center;gap:5px;font-size:12px;color:#595959;"><span style="width:6px;height:6px;border-radius:50%;background:{{ r.srcColor }};"></span>{{ r.srcLabel }}</span></td>
<td style="padding:12px 10px;"><span style="font-size:12.5px;color:{{ r.sellerColor }};font-weight:500;">{{ r.seller }}</span></td>
<td style="padding:12px 10px;text-align:center;"><button style="width:30px;height:30px;border-radius:7px;border:none;background:transparent;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;color:#8c8c8c;" style-hover="background:#f0f0f0;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button></td>
</tr>
</sc-for>
</tbody>
</table>
</sc-if>
<!-- ===== ПОДПИСКИ ===== -->
<sc-if value="{{ isSubs }}" hint-placeholder-val="{{ false }}">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:1080px;">
<thead><tr style="background:#fafafa;">
<th style="text-align:left;padding:11px 16px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПОДПИСКА</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">КЛИЕНТ</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">OFFER</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СТАТУС</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПЕРИОД</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СЛЕД. СПИСАНИЕ</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ENTITLEMENT</th>
<th style="width:44px;border-bottom:1px solid #f0f0f0;"></th>
</tr></thead>
<tbody>
<sc-for list="{{ rows }}" as="r" hint-placeholder-count="4">
<tr style="border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<td style="padding:12px 16px;"><a href="#" style="font-weight:600;color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;">{{ r.id }}</a></td>
<td style="padding:12px 10px;color:#262626;">{{ r.client }}</td>
<td style="padding:12px 10px;color:#595959;">{{ r.offer }}</td>
<td style="padding:12px 10px;"><span style="padding:2px 9px;border-radius:6px;background:{{ r.stBg }};color:{{ r.stColor }};font-size:11.5px;font-weight:600;">{{ r.stLabel }}</span></td>
<td style="padding:12px 10px;color:#595959;white-space:nowrap;">{{ r.period }}</td>
<td style="padding:12px 10px;color:#595959;white-space:nowrap;">{{ r.next }}</td>
<td style="padding:12px 10px;color:#595959;">{{ r.ent }}</td>
<td style="padding:12px 10px;text-align:center;"><button style="width:30px;height:30px;border-radius:7px;border:none;background:transparent;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;color:#8c8c8c;" style-hover="background:#f0f0f0;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button></td>
</tr>
</sc-for>
</tbody>
</table>
</sc-if>
<!-- ===== ПЛАТЕЖИ ===== -->
<sc-if value="{{ isPays }}" hint-placeholder-val="{{ false }}">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:1120px;">
<thead><tr style="background:#fafafa;">
<th style="text-align:left;padding:11px 16px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПЛАТЁЖ</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ЗАКАЗ</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПРОВАЙДЕР</th>
<th style="text-align:right;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СУММА</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СТАТУС</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">МЕТОД</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ДАТА</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СВЕРКА</th>
</tr></thead>
<tbody>
<sc-for list="{{ rows }}" as="r" hint-placeholder-count="5">
<tr style="border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<td style="padding:12px 16px;"><span style="font-weight:600;color:#262626;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;">{{ r.id }}</span></td>
<td style="padding:12px 10px;"><a href="#" style="color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;">{{ r.order }}</a></td>
<td style="padding:12px 10px;color:#595959;">{{ r.provider }}</td>
<td style="padding:12px 10px;text-align:right;font-weight:600;color:#262626;white-space:nowrap;">{{ r.amount }}</td>
<td style="padding:12px 10px;"><span style="padding:2px 9px;border-radius:6px;background:{{ r.stBg }};color:{{ r.stColor }};font-size:11.5px;font-weight:600;">{{ r.stLabel }}</span></td>
<td style="padding:12px 10px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">{{ r.method }}</td>
<td style="padding:12px 10px;color:#595959;white-space:nowrap;">{{ r.date }}</td>
<td style="padding:12px 10px;"><span style="font-size:12px;color:{{ r.recColor }};">{{ r.rec }}</span></td>
</tr>
</sc-for>
</tbody>
</table>
</sc-if>
<!-- ===== ВОЗВРАТЫ ===== -->
<sc-if value="{{ isRefunds }}" hint-placeholder-val="{{ false }}">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:1000px;">
<thead><tr style="background:#fafafa;">
<th style="text-align:left;padding:11px 16px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ВОЗВРАТ</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ЗАКАЗ / ПЛАТЁЖ</th>
<th style="text-align:right;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СУММА</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПРИЧИНА</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СТАТУС</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ИНИЦИАТОР</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ДАТА</th>
</tr></thead>
<tbody>
<sc-for list="{{ rows }}" as="r" hint-placeholder-count="3">
<tr style="border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<td style="padding:12px 16px;"><span style="font-weight:600;color:#262626;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;">{{ r.id }}</span></td>
<td style="padding:12px 10px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">{{ r.ref }}</td>
<td style="padding:12px 10px;text-align:right;font-weight:600;color:#262626;white-space:nowrap;">{{ r.amount }}</td>
<td style="padding:12px 10px;color:#595959;">{{ r.reason }}</td>
<td style="padding:12px 10px;"><span style="padding:2px 9px;border-radius:6px;background:{{ r.stBg }};color:{{ r.stColor }};font-size:11.5px;font-weight:600;">{{ r.stLabel }}</span></td>
<td style="padding:12px 10px;color:#595959;">{{ r.actor }}</td>
<td style="padding:12px 10px;color:#595959;white-space:nowrap;">{{ r.date }}</td>
</tr>
</sc-for>
</tbody>
</table>
</sc-if>
<!-- ===== ИСПОЛНЕНИЕ ===== -->
<sc-if value="{{ isExec }}" hint-placeholder-val="{{ false }}">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:1080px;">
<thead><tr style="background:#fafafa;">
<th style="text-align:left;padding:11px 16px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ЗАКАЗ</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПРОДУКТ</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ОПЕРАЦИЯ</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СТАТУС</th>
<th style="text-align:right;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПОПЫТКИ</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПОСЛ. ОШИБКА</th>
<th style="text-align:left;padding:11px 10px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ОБНОВЛЕНО</th>
<th style="text-align:right;padding:11px 16px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ДЕЙСТВИЕ</th>
</tr></thead>
<tbody>
<sc-for list="{{ rows }}" as="r" hint-placeholder-count="4">
<tr style="border-bottom:1px solid #f5f5f5;" style-hover="background:#fafbfc;">
<td style="padding:12px 16px;"><a href="#" style="color:#1677ff;text-decoration:none;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12.5px;font-weight:600;">{{ r.order }}</a></td>
<td style="padding:12px 10px;color:#595959;">{{ r.product }}</td>
<td style="padding:12px 10px;color:#595959;font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:12px;">{{ r.op }}</td>
<td style="padding:12px 10px;"><span style="padding:2px 9px;border-radius:6px;background:{{ r.stBg }};color:{{ r.stColor }};font-size:11.5px;font-weight:600;">{{ r.stLabel }}</span></td>
<td style="padding:12px 10px;text-align:right;color:{{ r.attColor }};font-weight:600;">{{ r.attempts }}</td>
<td style="padding:12px 10px;color:{{ r.errColor }};font-family:'SF Mono',ui-monospace,Menlo,monospace;font-size:11.5px;">{{ r.error }}</td>
<td style="padding:12px 10px;color:#595959;white-space:nowrap;">{{ r.updated }}</td>
<td style="padding:12px 16px;text-align:right;">
<sc-if value="{{ r.canRetry }}" hint-placeholder-val="{{ false }}">
<button style="display:inline-flex;align-items:center;gap:6px;height:30px;padding:0 12px;border-radius:7px;border:1px solid #ffccc7;background:#fff;color:#cf1322;font-size:12.5px;font-weight:600;cursor:pointer;" style-hover="background:#fff2f0;"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/><path d="M3 21v-5h5"/></svg>Повторить</button>
</sc-if>
<sc-if value="{{ r.noRetry }}" hint-placeholder-val="{{ true }}">
<span style="font-size:12px;color:#bfbfbf;">—</span>
</sc-if>
</td>
</tr>
</sc-for>
</tbody>
</table>
</sc-if>
<!-- empty -->
<sc-if value="{{ isEmpty }}" hint-placeholder-val="{{ false }}">
<div style="padding:54px 20px;text-align:center;">
<div style="width:48px;height:48px;border-radius:50%;background:#f5f5f5;display:inline-flex;align-items:center;justify-content:center;margin-bottom:14px;"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="#bfbfbf" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg></div>
<div style="font-size:14px;font-weight:600;color:#595959;">Ничего не найдено</div>
<div style="font-size:12.5px;color:#bfbfbf;margin-top:4px;">Измените поисковый запрос.</div>
</div>
</sc-if>
</div>
<!-- pagination -->
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 18px;border-top:1px solid #f5f5f5;">
<div style="font-size:12.5px;color:#8c8c8c;">Показано {{ shownCount }} из {{ totalCount }}</div>
<div style="display:flex;align-items:center;gap:6px;">
<button style="height:30px;min-width:30px;padding:0 9px;border:1px solid #e8e8e8;border-radius:7px;background:#fff;color:#bfbfbf;font-size:13px;cursor:not-allowed;">‹</button>
<button style="height:30px;min-width:30px;border:1px solid #1677ff;border-radius:7px;background:#1677ff;color:#fff;font-size:13px;font-weight:600;cursor:pointer;">1</button>
<button style="height:30px;min-width:30px;border:1px solid #e8e8e8;border-radius:7px;background:#fff;color:#595959;font-size:13px;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">2</button>
<button style="height:30px;min-width:30px;padding:0 9px;border:1px solid #e8e8e8;border-radius:7px;background:#fff;color:#595959;font-size:13px;cursor:pointer;" style-hover="border-color:#1677ff;color:#1677ff;">›</button>
<div style="width:1px;height:20px;background:#f0f0f0;margin:0 4px;"></div>
<span style="font-size:12.5px;color:#8c8c8c;">20 / стр.</span>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 940 }
}">
class Component extends DCLogic {
state = { tab: 'orders', q: '' };
renderVals() {
const S = {
green: { color: '#389e0d', bg: '#f6ffed' },
amber: { color: '#d48806', bg: '#fffbe6' },
red: { color: '#cf1322', bg: '#fff2f0' },
blue: { color: '#0958d9', bg: '#e6f4ff' },
gray: { color: '#8c8c8c', bg: '#f5f5f5' },
purple: { color: '#722ed1', bg: '#f9f0ff' },
};
const SRC = { MAX: '#6b5be0', Telegram: '#2f8fd0', Web: '#0f9b8e' };
const ai = '#722ed1';
const orders = [
{ id: 'ORD-10519', date: 'сегодня 14:02', client: 'Татьяна Лебедева', offer: 'FirePage · Business', amount: '₽2 490', pay: 'green:Оплачен', ful: 'green:Исполнен', src: 'MAX', seller: 'AI-агент', sellerAI: true },
{ id: 'ORD-10518', date: 'сегодня 13:40', client: 'Анна Морозова', offer: 'Foxray · Pro', amount: '₽990', pay: 'green:Оплачен', ful: 'green:Исполнен', src: 'Telegram', seller: 'Анна Котова' },
{ id: 'ORD-10516', date: 'сегодня 12:18', client: 'Павел Новиков', offer: 'FirePage · Business', amount: '₽2 490', pay: 'green:Оплачен', ful: 'blue:В процессе', src: 'MAX', seller: 'AI-агент', sellerAI: true },
{ id: 'ORD-10512', date: 'сегодня 11:05', client: 'Елена Кузнецова', offer: 'Foxray · Team', amount: '₽4 980', pay: 'amber:Ожидает', ful: 'gray:—', src: 'Web', seller: 'Иван Петров' },
{ id: 'ORD-10508', date: 'вчера 18:22', client: 'Игорь Соколов', offer: 'Foxray · Pro', amount: '₽990', pay: 'gray:Возврат', ful: 'green:Исполнен', src: 'MAX', seller: 'AI-агент', sellerAI: true },
{ id: 'ORD-10482', date: 'вчера 16:50', client: 'Сергей Волков', offer: 'FirePage · Business', amount: '₽2 490', pay: 'red:Не оплачен', ful: 'gray:—', src: 'Telegram', seller: 'AI-агент', sellerAI: true },
].map((o) => {
const [pk, pl] = o.pay.split(':'); const [fk, fl] = o.ful.split(':');
return { ...o, payColor: S[pk].color, payBg: S[pk].bg, payLabel: pl, fulColor: S[fk].color, fulBg: S[fk].bg, fulLabel: fl, srcColor: SRC[o.src], srcLabel: o.src, sellerColor: o.sellerAI ? ai : '#262626', _s: (o.id + o.client).toLowerCase() };
});
const subs = [
{ id: 'SUB-2041', client: 'Татьяна Лебедева', offer: 'FirePage Business · мес', st: 'green:Активна', period: '16 июн — 16 июл', next: '16 июл 2026', ent: '10 мест' },
{ id: 'SUB-2038', client: 'Анна Морозова', offer: 'Foxray Pro · мес', st: 'green:Активна', period: '02 июн — 02 июл', next: '02 июл 2026', ent: '1 место' },
{ id: 'SUB-2025', client: 'Игорь Соколов', offer: 'Foxray Pro · мес', st: 'gray:Отменена', period: '—', next: '—', ent: '—' },
{ id: 'SUB-2011', client: 'Елена Кузнецова', offer: 'Foxray Team · год', st: 'amber:Приостановлена', period: '10 мар — 10 мар 27', next: 'пауза', ent: '5 мест' },
].map((o) => { const [k, l] = o.st.split(':'); return { ...o, stColor: S[k].color, stBg: S[k].bg, stLabel: l, _s: (o.id + o.client).toLowerCase() }; });
const pays = [
{ id: 'PAY-88231', order: 'ORD-10519', provider: 'Точка', amount: '₽2 490', st: 'green:Успешно', method: 'Карта ···4242', date: 'сегодня 14:02', rec: 'green:Сверено' },
{ id: 'PAY-88230', order: 'ORD-10518', provider: 'Точка', amount: '₽990', st: 'green:Успешно', method: 'СБП', date: 'сегодня 13:40', rec: 'green:Сверено' },
{ id: 'PAY-88224', order: 'ORD-10512', provider: 'Точка', amount: '₽4 980', st: 'amber:Ожидает', method: 'Карта', date: 'сегодня 11:05', rec: 'amber:Ожидает сверки' },
{ id: 'PAY-88210', order: 'ORD-10508', provider: 'Точка', amount: '₽990', st: 'gray:Возврат', method: 'Карта ···1188', date: 'вчера 18:25', rec: 'green:Сверено' },
{ id: 'PAY-88198', order: 'ORD-10482', provider: 'Точка', amount: '₽2 490', st: 'red:Отклонён', method: 'Карта ···7701', date: 'вчера 16:51', rec: 'gray:—' },
].map((o) => { const [k, l] = o.st.split(':'); const [rk, rl] = o.rec.split(':'); return { ...o, stColor: S[k].color, stBg: S[k].bg, stLabel: l, recColor: S[rk].color, rec: rl, _s: (o.id + o.order).toLowerCase() }; });
const refunds = [
{ id: 'REF-3120', ref: 'ORD-10508 · PAY-88210', amount: '₽990', reason: 'Запрос клиента', st: 'green:Завершён', actor: 'Иван Петров', date: 'сегодня 09:14' },
{ id: 'REF-3118', ref: 'ORD-10455 · PAY-87990', amount: '₽2 490', reason: 'Дубль оплаты', st: 'amber:В обработке', actor: 'OWNER', date: 'вчера 20:02' },
{ id: 'REF-3101', ref: 'ORD-10390 · PAY-87740', amount: '₽4 980', reason: 'Брак поставки', st: 'red:Отклонён', actor: 'Иван Петров', date: '13 июн' },
].map((o) => { const [k, l] = o.st.split(':'); return { ...o, stColor: S[k].color, stBg: S[k].bg, stLabel: l, _s: (o.id + o.ref).toLowerCase() }; });
const exec = [
{ order: 'ORD-10519', product: 'FirePage', op: 'OP-55120', st: 'green:Успешно', attempts: '1', error: '—', updated: 'сегодня 14:03', retry: false },
{ order: 'ORD-10516', product: 'FirePage', op: 'OP-55117', st: 'blue:В процессе', attempts: '1', error: '—', updated: 'сегодня 12:19', retry: false },
{ order: 'ORD-10512', product: 'Foxray', op: 'OP-55110', st: 'amber:Ожидает оплаты', attempts: '0', error: '—', updated: 'сегодня 11:05', retry: false },
{ order: 'ORD-10470', product: 'Foxray', op: 'OP-55088', st: 'red:Ошибка', attempts: '3', error: 'TIMEOUT: provider 504', updated: 'вчера 15:40', retry: true },
].map((o) => { const [k, l] = o.st.split(':'); return { ...o, stColor: S[k].color, stBg: S[k].bg, stLabel: l, attColor: Number(o.attempts) >= 3 ? '#cf1322' : '#595959', errColor: o.retry ? '#cf1322' : '#bfbfbf', canRetry: o.retry, noRetry: !o.retry, _s: (o.order + o.op).toLowerCase() }; });
const all = { orders, subs, pays, refunds, exec };
const totals = { orders: 6, subs: 4, pays: 5, refunds: 3, exec: 4 };
const { tab, q } = this.state;
const ql = q.trim().toLowerCase();
const rows = all[tab].filter((r) => !ql || r._s.includes(ql));
const tBase = 'padding:11px 16px;border:none;background:transparent;border-bottom:2px solid transparent;font-size:14px;font-weight:500;color:#595959;cursor:pointer;margin-bottom:-1px;display:inline-flex;align-items:center;gap:8px;';
const tAct = 'padding:11px 16px;border:none;background:transparent;border-bottom:2px solid #1677ff;font-size:14px;font-weight:600;color:#1677ff;cursor:pointer;margin-bottom:-1px;display:inline-flex;align-items:center;gap:8px;';
const bBase = 'min-width:20px;height:20px;padding:0 6px;border-radius:10px;background:#f0f0f0;color:#8c8c8c;font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;';
const bAct = 'min-width:20px;height:20px;padding:0 6px;border-radius:10px;background:#e6f4ff;color:#1677ff;font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;';
const setTab = (t) => this.setState({ tab: t, q: '' });
const A = (t) => tab === t ? tAct : tBase;
const B = (t) => tab === t ? bAct : bBase;
return {
rows, q,
isOrders: tab === 'orders', isSubs: tab === 'subs', isPays: tab === 'pays', isRefunds: tab === 'refunds', isExec: tab === 'exec',
isEmpty: rows.length === 0,
shownCount: String(rows.length), totalCount: String(totals[tab]),
tabO: A('orders'), tabS: A('subs'), tabP: A('pays'), tabR: A('refunds'), tabE: A('exec'),
badgeO: B('orders'), badgeS: B('subs'), badgeP: B('pays'), badgeR: B('refunds'), badgeE: B('exec'),
onTabO: () => setTab('orders'), onTabS: () => setTab('subs'), onTabP: () => setTab('pays'),
onTabR: () => setTab('refunds'), onTabE: () => setTab('exec'),
onSearch: (e) => this.setState({ q: e.target.value }),
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,213 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-thumb{background:#dcdcdc;border-radius:8px;border:2px solid #f0f2f5;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#bfbfbf;background-clip:content-box;}
</style>
</helmet>
<div style="display:flex;height:100vh;overflow:hidden;background:#f0f2f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#262626;-webkit-font-smoothing:antialiased;min-width:1100px;">
<!-- ============ SIDEBAR (уровень компании) ============ -->
<aside style="width:248px;flex:none;background:#ffffff;border-right:1px solid #f0f0f0;display:flex;flex-direction:column;height:100vh;">
<div style="height:56px;flex:none;display:flex;align-items:center;gap:11px;padding:0 20px;border-bottom:1px solid #f5f5f5;">
<div style="width:30px;height:30px;border-radius:8px;background:#1677ff;display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2 6 4-14 2 8h6"/></svg></div>
<div style="display:flex;flex-direction:column;line-height:1.15;"><span style="font-size:14px;font-weight:600;color:#1f1f1f;letter-spacing:-0.01em;">Edevs Hub</span><span style="font-size:11px;color:#8c8c8c;">Уровень компании</span></div>
</div>
<nav style="flex:1;overflow-y:auto;padding:12px 12px 8px;">
<a href="Командный центр.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="9" rx="1.4"/><rect x="14" y="3" width="7" height="5" rx="1.4"/><rect x="14" y="12" width="7" height="9" rx="1.4"/><rect x="3" y="16" width="7" height="5" rx="1.4"/></svg>Командный центр</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">КОМПАНИЯ</div>
<a href="Отделы.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 8h1.5M13.5 8H15M9 12h1.5M13.5 12H15M9 16h1.5M13.5 16H15"/></svg>Отделы</a>
<a href="Сотрудники.dc.html" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Сотрудники</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;background:#e6f4ff;color:#0958d9;font-size:13.5px;font-weight:600;text-decoration:none;margin-bottom:2px;position:relative;"><span style="position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:#1677ff;"></span><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>Продукты</a>
<div style="font-size:11px;font-weight:600;letter-spacing:0.06em;color:#bfbfbf;padding:14px 12px 6px;">ПЛАТФОРМА</div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2.5"/><path d="M12 8V4.5"/><circle cx="12" cy="3.5" r="1.2"/><circle cx="9" cy="13.5" r="1"/><circle cx="15" cy="13.5" r="1"/><path d="M2 13.5h2M20 13.5h2"/></svg>AI</a>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2.5M15 8V2.5M18 8v5.5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 17.5V22"/></svg>Интеграции</a>
<div style="height:1px;background:#f5f5f5;margin:14px 12px 10px;"></div>
<a href="#" style="display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:8px;color:#595959;font-size:13.5px;font-weight:500;text-decoration:none;margin-bottom:2px;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><line x1="21" y1="6" x2="9" y2="6"/><line x1="3" y1="6" x2="5" y2="6"/><circle cx="7" cy="6" r="2"/><line x1="21" y1="12" x2="13" y2="12"/><line x1="3" y1="12" x2="9" y2="12"/><circle cx="11" cy="12" r="2"/><line x1="21" y1="18" x2="15" y2="18"/><line x1="3" y1="18" x2="11" y2="18"/><circle cx="13" cy="18" r="2"/></svg>Настройки</a>
</nav>
<div style="flex:none;border-top:1px solid #f5f5f5;padding:10px 12px;">
<a href="#" style="display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;text-decoration:none;" style-hover="background:#f5f5f5;"><div style="width:32px;height:32px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;flex:none;">ИП</div><div style="display:flex;flex-direction:column;line-height:1.2;"><span style="font-size:13px;font-weight:600;color:#262626;">Иван Петров</span><span style="font-size:11px;color:#8c8c8c;">OWNER</span></div></a>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="flex:1;min-width:0;display:flex;flex-direction:column;height:100vh;">
<header style="height:56px;flex:none;background:#ffffff;border-bottom:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;padding:0 24px;">
<div style="display:flex;align-items:center;gap:8px;font-size:13px;color:#8c8c8c;"><span style="font-weight:500;color:#595959;">Edevs</span><span style="color:#d9d9d9;">/</span><span style="font-weight:600;color:#262626;">Продукты</span></div>
<div style="display:flex;align-items:center;gap:14px;">
<button style="position:relative;width:36px;height:36px;border-radius:8px;border:1px solid #f0f0f0;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#595959;" style-hover="background:#f5f5f5;color:#262626;"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg><span style="position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:#ff4d4f;border:1.5px solid #fff;"></span></button>
<div style="width:1px;height:24px;background:#f0f0f0;"></div>
<div style="width:28px;height:28px;border-radius:50%;background:#1677ff;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;">ИП</div>
</div>
</header>
<main style="flex:1;overflow-y:auto;padding:24px 28px 40px;">
<div style="max-width:1280px;margin:0 auto;">
<sc-if value="{{ menuId }}" hint-placeholder-val="{{ false }}">
<div onClick="{{ onCloseMenu }}" style="position:fixed;inset:0;z-index:20;"></div>
</sc-if>
<!-- PAGE HEADER -->
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:18px;">
<div>
<h1 style="margin:0;font-size:24px;font-weight:700;letter-spacing:-0.02em;color:#1f1f1f;line-height:1.2;">Продукты</h1>
<p style="margin:6px 0 0;font-size:13.5px;color:#8c8c8c;">2 активных продукта · цены и Offer управляются в карточке продукта</p>
</div>
<div style="display:flex;align-items:center;gap:10px;flex:none;">
<div style="display:flex;align-items:center;gap:3px;padding:3px;border-radius:9px;background:#f0f2f5;">
<button onClick="{{ onToday }}" style="{{ tabToday }}">Сегодня</button>
<button onClick="{{ on7 }}" style="{{ tab7 }}">7 дней</button>
<button onClick="{{ on30 }}" style="{{ tab30 }}">30 дней</button>
</div>
<button style="display:flex;align-items:center;gap:8px;height:38px;padding:0 16px;border-radius:9px;border:none;background:#1677ff;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer;box-shadow:0 1px 2px rgba(22,119,255,0.3);" style-hover="background:#0958d9;"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Создать продукт</button>
</div>
</div>
<!-- TABLE -->
<div style="background:#fff;border:1px solid #f0f0f0;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.04);overflow:hidden;">
<div style="overflow-x:auto;">
<table style="width:100%;border-collapse:collapse;font-size:13px;min-width:1180px;">
<thead><tr style="background:#fafafa;">
<th style="text-align:left;padding:11px 18px;font-size:11px;font-weight:600;color:#8c8c8c;letter-spacing:0.03em;border-bottom:1px solid #f0f0f0;">ПРОДУКТ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">СТАТУС</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;width:300px;">OFFER И ЦЕНЫ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">SALES-AGENT</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">КАНАЛЫ</th>
<th style="text-align:left;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">FULFILLMENT</th>
<th style="text-align:right;padding:11px 12px;font-size:11px;font-weight:600;color:#8c8c8c;border-bottom:1px solid #f0f0f0;">ПРОДАЖИ · {{ periodUpper }}</th>
<th style="width:48px;border-bottom:1px solid #f0f0f0;"></th>
</tr></thead>
<tbody>
<sc-for list="{{ rows }}" as="r" hint-placeholder-count="2">
<tr style="border-bottom:1px solid #f5f5f5;vertical-align:top;" style-hover="background:#fafbfc;">
<td style="padding:15px 18px;">
<div style="display:flex;align-items:center;gap:12px;">
<div style="width:40px;height:40px;border-radius:10px;background:{{ r.iconBg }};display:flex;align-items:center;justify-content:center;flex:none;"><svg viewBox="0 0 24 24" width="21" height="21" fill="none" stroke="{{ r.iconColor }}" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg></div>
<div><a href="#" style="font-weight:700;color:#1677ff;text-decoration:none;font-size:14px;">{{ r.name }}</a><div style="font-size:11.5px;color:#bfbfbf;margin-top:1px;">{{ r.sub }}</div></div>
</div>
</td>
<td style="padding:15px 12px;"><span style="display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:500;color:#389e0d;"><span style="width:7px;height:7px;border-radius:50%;background:#52c41a;"></span>Активен</span></td>
<td style="padding:13px 12px;">
<sc-for list="{{ r.offers }}" as="o" hint-placeholder-count="2">
<div style="display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding:3px 0;">
<span style="font-size:12.5px;color:#262626;">{{ o.name }} <span style="color:#bfbfbf;font-size:11px;">· {{ o.type }}</span></span>
<span style="font-size:12.5px;font-weight:600;color:#262626;white-space:nowrap;">{{ o.price }}</span>
</div>
</sc-for>
<sc-if value="{{ r.note }}" hint-placeholder-val="{{ false }}">
<div style="font-size:11px;color:#8c8c8c;margin-top:4px;display:inline-flex;align-items:center;gap:5px;"><svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="#389e0d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="5" x2="5" y2="19"/><circle cx="6.5" cy="6.5" r="2.5"/><circle cx="17.5" cy="17.5" r="2.5"/></svg>{{ r.note }}</div>
</sc-if>
</td>
<td style="padding:15px 12px;"><span style="display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:#722ed1;font-weight:500;"><span style="width:7px;height:7px;border-radius:50%;background:#722ed1;"></span>AI-агент</span><div style="font-size:11px;color:#bfbfbf;margin-top:2px;">{{ r.agentRelease }}</div></td>
<td style="padding:15px 12px;">
<div style="display:flex;gap:5px;flex-wrap:wrap;">
<sc-for list="{{ r.channels }}" as="c" hint-placeholder-count="3">
<span style="display:inline-flex;align-items:center;gap:4px;padding:2px 7px;border-radius:5px;background:{{ c.bg }};"><span style="width:5px;height:5px;border-radius:50%;background:{{ c.color }};"></span><span style="font-size:10.5px;font-weight:600;color:{{ c.color }};">{{ c.label }}</span></span>
</sc-for>
</div>
</td>
<td style="padding:15px 12px;"><span style="display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:#389e0d;font-weight:500;"><span style="width:7px;height:7px;border-radius:50%;background:#52c41a;"></span>Подключён</span><div style="font-size:11px;color:#bfbfbf;margin-top:2px;">{{ r.fulfillment }}</div></td>
<td style="padding:15px 12px;text-align:right;"><div style="font-size:15px;font-weight:700;color:#1f1f1f;">{{ r.salesSum }}</div><div style="font-size:11.5px;color:#8c8c8c;margin-top:2px;">{{ r.salesN }} продаж</div></td>
<td style="padding:15px 12px;text-align:center;position:relative;">
<button onClick="{{ r.onMenu }}" style="width:30px;height:30px;border-radius:7px;border:none;background:transparent;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;color:#8c8c8c;" style-hover="background:#f0f0f0;color:#262626;"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
<sc-if value="{{ r.menuOpen }}" hint-placeholder-val="{{ false }}">
<div style="position:absolute;right:12px;top:42px;z-index:30;width:200px;background:#fff;border:1px solid #f0f0f0;border-radius:10px;box-shadow:0 6px 20px rgba(0,0,0,0.12);padding:5px;text-align:left;">
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#262626;font-size:13px;font-weight:500;" style-hover="background:#f5f5f5;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg>Открыть продукт</a>
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#262626;font-size:13px;font-weight:500;" style-hover="background:#f5f5f5;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Добавить Offer</a>
<div style="height:1px;background:#f5f5f5;margin:4px 8px;"></div>
<a href="#" style="display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:7px;text-decoration:none;color:#d48806;font-size:13px;font-weight:500;" style-hover="background:#fffbe6;"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/></svg>Деактивировать</a>
</div>
</sc-if>
</td>
</tr>
</sc-for>
</tbody>
</table>
</div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 18px;border-top:1px solid #f5f5f5;">
<div style="font-size:12.5px;color:#8c8c8c;">2 продукта</div>
<div style="font-size:12.5px;color:#bfbfbf;">Активная цена не редактируется задним числом — создаётся новая версия</div>
</div>
</div>
</div>
</main>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{
&quot;$preview&quot;: { &quot;width&quot;: 1440, &quot;height&quot;: 900 }
}">
class Component extends DCLogic {
state = { period: 'd30', menuId: null };
renderVals() {
const CH = {
MAX: { label: 'MAX', color: '#6b5be0', bg: '#f2f0ff' },
TG: { label: 'TG', color: '#2f8fd0', bg: '#eaf6fd' },
WEB: { label: 'Web', color: '#0f9b8e', bg: '#e8f7f4' },
};
const { period, menuId } = this.state;
const periodLabel = { today: 'Сегодня', d7: '7 дней', d30: '30 дней' }[period];
const data = [
{
id: 'fp', name: 'FirePage', sub: 'Нишевые сайты · коробка', iconBg: '#e6f4ff', iconColor: '#1677ff',
offers: [
{ name: 'Коробка', type: 'разовая', price: '₽4 900' },
{ name: 'Годовая поддержка', type: 'продление', price: '₽1 470 / год' },
],
note: 'Поддержка — 30% от цены коробки',
agentRelease: 'release v4 · published', channels: ['MAX', 'TG', 'WEB'], fulfillment: 'Сборка и выдача сайта',
sales: { today: { n: 2, sum: '₽9 800' }, d7: { n: 14, sum: '₽71 540' }, d30: { n: 56, sum: '₽288 100' } },
},
{
id: 'fx', name: 'Foxray', sub: 'SaaS · подписка', iconBg: '#f9f0ff', iconColor: '#722ed1',
offers: [
{ name: 'Pro', type: 'подписка', price: '₽4 900 / мес' },
{ name: 'Max', type: 'подписка', price: '₽9 900 / мес' },
],
note: 'Скидка 20% при оплате за год',
agentRelease: 'release v3 · published', channels: ['MAX', 'TG', 'WEB'], fulfillment: 'Выдача доступа',
sales: { today: { n: 3, sum: '₽16 400' }, d7: { n: 19, sum: '₽104 200' }, d30: { n: 82, sum: '₽548 700' } },
},
];
const rows = data.map((d) => ({
name: d.name, sub: d.sub, iconBg: d.iconBg, iconColor: d.iconColor,
offers: d.offers, note: d.note,
agentRelease: d.agentRelease, fulfillment: d.fulfillment,
channels: d.channels.map((c) => CH[c]),
salesN: String(d.sales[period].n), salesSum: d.sales[period].sum,
menuOpen: menuId === d.id,
onMenu: () => this.setState((s) => ({ menuId: s.menuId === d.id ? null : d.id })),
}));
const base = 'padding:6px 15px;border:none;border-radius:7px;font-size:13px;font-weight:500;cursor:pointer;background:transparent;color:#595959;';
const act = 'padding:6px 15px;border:none;border-radius:7px;font-size:13px;font-weight:600;cursor:pointer;background:#ffffff;color:#1f1f1f;box-shadow:0 1px 2px rgba(0,0,0,0.1);';
const setP = (p) => this.setState({ period: p, menuId: null });
return {
rows, menuId, periodUpper: periodLabel.toUpperCase(),
tabToday: period === 'today' ? act : base, tab7: period === 'd7' ? act : base, tab30: period === 'd30' ? act : base,
onToday: () => setP('today'), on7: () => setP('d7'), on30: () => setP('d30'),
onCloseMenu: () => this.setState({ menuId: null }),
};
}
}
</script>
</body>
</html>
Loaded 100 of 127 files, more files were not shown because too many files have changed in this diff. Show more