Update: перенастройка сайта что бы открывать 1 порт на сайт

This commit is contained in:
2026-02-11 15:46:19 +05:00
parent 65a9143bd0
commit 62340e4406
25 changed files with 1393 additions and 1216 deletions

View File

@@ -1,6 +1,7 @@
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import { SECTION_IDS } from '../constants';
import { SparklesIcon } from './icons'; // Using an icon for principles
import { SparklesIcon } from './icons';
import { fetchUploadFiles, STRAPI_URL } from '../strapiService';
const principlesData = [
{
@@ -57,7 +58,35 @@ const PrincipleItem: React.FC<{ title: string; children: React.ReactNode; index:
);
const ABOUT_IMAGE_ALT: [string, string][] = [
['Команда iiEasy за работой в современном офисе в Уфе, обсуждает проект на фоне доски с диаграммами и кодом. Атмосфера сфокусированной совместной работы.', 'Команда iiEasy в Уфе: от идеи к реализации.'],
['Крупный план экрана с кодом или дашбордом предиктивной аналитики. На заднем плане — сфокусированный взгляд разработчика, отражающийся в мониторе.', 'Глубокая техническая работа — основа наших решений.'],
['Групповой снимок команды iiEasy. Разнообразные лица, уверенные и дружелюбные улыбки. Неформальная, но профессиональная обстановка.', 'Наша команда — наш главный актив.'],
['Панорамный вид на Уфу с акцентом на современные здания (например, Конгресс-холл Торатау), символизирующий связь компании с городом и ее нацеленность на будущее развитие региона.', 'Нацелены на будущее развитие нашего региона.'],
];
const PLACEHOLDER_IMAGES = [
'https://picsum.photos/seed/iieasy-team-work/1200/800',
'https://picsum.photos/seed/iieasy-code/1200/800',
'https://picsum.photos/seed/iieasy-team-group/1200/800',
'https://picsum.photos/seed/iieasy-ufa-view/1200/800',
];
const AboutUsSection: React.FC = () => {
const [aboutImages, setAboutImages] = useState<string[]>([]);
useEffect(() => {
let cancelled = false;
(async () => {
const files = await fetchUploadFiles();
if (cancelled) return;
const sorted = [...files].sort((a, b) => (a.name ?? '').localeCompare(b.name ?? ''));
const urls = sorted.slice(0, 4).map((f) => (f.url.startsWith('http') ? f.url : `${STRAPI_URL}${f.url}`));
setAboutImages(urls);
})();
return () => { cancelled = true; };
}, []);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
@@ -68,16 +97,14 @@ const AboutUsSection: React.FC = () => {
}
});
},
{
threshold: 0.1,
}
{ threshold: 0.1 }
);
const elements = document.querySelectorAll('.scroll-animate');
elements.forEach((el) => observer.observe(el));
return () => observer.disconnect();
}, []);
}, [aboutImages]);
const getImageUrl = (index: number) => aboutImages[index] ?? PLACEHOLDER_IMAGES[index];
return (
<section
@@ -100,8 +127,8 @@ const AboutUsSection: React.FC = () => {
</div>
<figure className="my-12 md:my-16 scroll-animate" style={{ transitionDelay: '200ms' }}>
<img src="https://picsum.photos/seed/iieasy-team-work/1200/800" alt="Команда iiEasy за работой в современном офисе в Уфе, обсуждает проект на фоне доски с диаграммами и кодом. Атмосфера сфокусированной совместной работы." className="rounded-lg shadow-xl aspect-video object-cover"/>
<figcaption className="text-center text-sm text-slate-500 mt-3 italic">Команда iiEasy в Уфе: от идеи к реализации.</figcaption>
<img src={getImageUrl(0)} alt={ABOUT_IMAGE_ALT[0][0]} className="rounded-lg shadow-xl aspect-video object-cover"/>
<figcaption className="text-center text-sm text-slate-500 mt-3 italic">{ABOUT_IMAGE_ALT[0][1]}</figcaption>
</figure>
{/* Mission */}
@@ -130,8 +157,8 @@ const AboutUsSection: React.FC = () => {
</div>
<figure className="my-12 md:my-16 scroll-animate" style={{ transitionDelay: '200ms' }}>
<img src="https://picsum.photos/seed/iieasy-code/1200/800" alt="Крупный план экрана с кодом или дашбордом предиктивной аналитики. На заднем плане — сфокусированный взгляд разработчика, отражающийся в мониторе." className="rounded-lg shadow-xl aspect-video object-cover"/>
<figcaption className="text-center text-sm text-slate-500 mt-3 italic">Глубокая техническая работа основа наших решений.</figcaption>
<img src={getImageUrl(1)} alt={ABOUT_IMAGE_ALT[1][0]} className="rounded-lg shadow-xl aspect-video object-cover"/>
<figcaption className="text-center text-sm text-slate-500 mt-3 italic">{ABOUT_IMAGE_ALT[1][1]}</figcaption>
</figure>
{/* Team */}
@@ -143,8 +170,8 @@ const AboutUsSection: React.FC = () => {
</div>
<figure className="my-12 md:my-16 scroll-animate" style={{ transitionDelay: '200ms' }}>
<img src="https://picsum.photos/seed/iieasy-team-group/1200/800" alt="Групповой снимок команды iiEasy. Разнообразные лица, уверенные и дружелюбные улыбки. Неформальная, но профессиональная обстановка." className="rounded-lg shadow-xl aspect-video object-cover"/>
<figcaption className="text-center text-sm text-slate-500 mt-3 italic">Наша команда наш главный актив.</figcaption>
<img src={getImageUrl(2)} alt={ABOUT_IMAGE_ALT[2][0]} className="rounded-lg shadow-xl aspect-video object-cover"/>
<figcaption className="text-center text-sm text-slate-500 mt-3 italic">{ABOUT_IMAGE_ALT[2][1]}</figcaption>
</figure>
{/* Principles */}
@@ -160,8 +187,8 @@ const AboutUsSection: React.FC = () => {
</div>
<figure className="mt-12 md:my-16 scroll-animate" style={{ transitionDelay: '200ms' }}>
<img src="https://picsum.photos/seed/iieasy-ufa-view/1200/800" alt="Панорамный вид на Уфу с акцентом на современные здания (например, Конгресс-холл Торатау), символизирующий связь компании с городом и ее нацеленность на будущее развитие региона." className="rounded-lg shadow-xl aspect-video object-cover"/>
<figcaption className="text-center text-sm text-slate-500 mt-3 italic">Нацелены на будущее развитие нашего региона.</figcaption>
<img src={getImageUrl(3)} alt={ABOUT_IMAGE_ALT[3][0]} className="rounded-lg shadow-xl aspect-video object-cover"/>
<figcaption className="text-center text-sm text-slate-500 mt-3 italic">{ABOUT_IMAGE_ALT[3][1]}</figcaption>
</figure>
</div>
</section>

View File

@@ -5,6 +5,7 @@ import React, { useState, useEffect, useRef } from 'react';
import { CurrentView } from '../types';
import { NAVIGABLE_VIEWS } from '../constants';
import { ArrowUpIcon } from './icons';
import { STRAPI_URL } from '../strapiService';
const PLACEHOLDERS = [
"Создайте мне сайт для моего бизнеса",
@@ -81,32 +82,35 @@ const ChatInput: React.FC<ChatInputProps> = ({ setCurrentView, isSticky = false,
Your entire response must be only the JSON object, with no other text, explanation, or markdown formatting.`;
try {
const response = await fetch('https://ai.iieasy.ru/v1/chat/completions', {
// Запрос через прокси Strapi (/api/ollama/chat) — один origin с фронтом, нет CORS и работает из любой сети
const response = await fetch(`${STRAPI_URL}/api/ollama/chat`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'local-model',
model: 'gemma3n:e4b',
messages: [
{ role: 'system', content: systemInstruction },
{ role: 'user', content: prompt }
],
temperature: 0.1,
stream: false,
}),
});
if (!response.ok) {
throw new Error(`Ошибка сети: ${response.status} ${response.statusText}. Убедитесь, что сервер LM Studio запущен.`);
throw new Error(`Ошибка сети: ${response.status} ${response.statusText}. Убедитесь, что бэкенд и Ollama доступны.`);
}
const data = await response.json();
if (data.error) {
throw new Error(`LM Studio вернула ошибку: ${data.error.message}`);
throw new Error(`Сервер ИИ вернул ошибку: ${typeof data.error === 'string' ? data.error : data.error.message || 'неизвестная ошибка'}`);
}
const responseJsonString = data.choices?.[0]?.message?.content;
// Ответ Ollama в /api/chat (без стриминга):
// { message: { role: 'assistant', content: '...' }, ... }
const responseJsonString = data.message?.content;
if (!responseJsonString) {
throw new Error("LM Studio вернула пустой ответ.");
throw new Error("Сервер ИИ вернул пустой ответ.");
}
// More robust JSON extraction
@@ -127,8 +131,8 @@ const ChatInput: React.FC<ChatInputProps> = ({ setCurrentView, isSticky = false,
setError("К сожалению, я не смог понять ваш запрос. Попробуйте переформулировать.");
}
} catch (err: any) {
console.error("Ошибка при обращении к LM Studio:", err);
setError(err.message || "Произошла ошибка. Убедитесь, что сервер LM Studio запущен и модель загружена. Пожалуйста, попробуйте еще раз.");
console.error("Ошибка при обращении к серверу ИИ (Ollama):", err);
setError(err.message || "Произошла ошибка. Убедитесь, что бэкенд и сервер Ollama доступны. Пожалуйста, попробуйте еще раз.");
} finally {
setIsLoading(false);
}