Добавлены новые зависимости, обновлены стили и улучшена структура проекта. Обновлен README с описанием функционала и технологий. Реализована анимация и адаптивный дизайн. Настроена авторизация с использованием Apollo Client.

This commit is contained in:
Bivekich
2025-07-16 18:00:41 +03:00
parent d260749bc9
commit 823ef9a28c
69 changed files with 15539 additions and 210 deletions

View File

@ -0,0 +1,223 @@
import axios from 'axios'
export interface MarketplaceValidationResult {
isValid: boolean
message: string
data?: {
sellerId?: string
sellerName?: string
[key: string]: unknown
}
}
export interface WildberriesSellerInfo {
id: number
name: string
inn: string
kpp?: string
}
export interface OzonSellerInfo {
id: number
name: string
status: string
}
export class MarketplaceService {
private wbApiUrl: string
private ozonApiUrl: string
constructor() {
this.wbApiUrl = process.env.WILDBERRIES_API_URL || 'https://common-api.wildberries.ru'
this.ozonApiUrl = process.env.OZON_API_URL || 'https://api-seller.ozon.ru'
}
/**
* Валидирует API ключ Wildberries
*/
async validateWildberriesApiKey(apiKey: string): Promise<MarketplaceValidationResult> {
try {
// Пытаемся получить информацию о продавце
const response = await axios.get(
`${this.wbApiUrl}/api/v1/seller-info`,
{
headers: {
'Authorization': apiKey,
'Content-Type': 'application/json'
},
timeout: 10000
}
)
if (response.status === 200 && response.data) {
const sellerData = response.data
return {
isValid: true,
message: 'API ключ Wildberries валиден',
data: {
sellerId: sellerData.id?.toString(),
sellerName: sellerData.name || sellerData.supplierName,
inn: sellerData.inn
}
}
}
return {
isValid: false,
message: 'Не удалось получить информацию о продавце Wildberries'
}
} catch (error) {
console.error('Wildberries API validation error:', error)
if (axios.isAxiosError(error)) {
if (error.response?.status === 401) {
return {
isValid: false,
message: 'Неверный API ключ Wildberries'
}
}
if (error.response?.status === 403) {
return {
isValid: false,
message: 'Доступ запрещён. Проверьте права API ключа Wildberries'
}
}
if (error.code === 'ECONNABORTED') {
return {
isValid: false,
message: 'Превышено время ожидания ответа от Wildberries API'
}
}
}
return {
isValid: false,
message: 'Ошибка при проверке API ключа Wildberries'
}
}
}
/**
* Валидирует API ключ Ozon
*/
async validateOzonApiKey(apiKey: string, clientId?: string): Promise<MarketplaceValidationResult> {
try {
// Для Ozon нужен Client-Id
if (!clientId) {
return {
isValid: false,
message: 'Для Ozon API требуется Client-Id'
}
}
// Пытаемся получить информацию о продавце
const response = await axios.post(
`${this.ozonApiUrl}/v1/seller/info`,
{},
{
headers: {
'Api-Key': apiKey,
'Client-Id': clientId,
'Content-Type': 'application/json'
},
timeout: 10000
}
)
if (response.status === 200 && response.data?.result) {
const sellerData = response.data.result as OzonSellerInfo
return {
isValid: true,
message: 'API ключ Ozon валиден',
data: {
sellerId: sellerData.id?.toString(),
sellerName: sellerData.name,
status: sellerData.status
}
}
}
return {
isValid: false,
message: 'Не удалось получить информацию о продавце Ozon'
}
} catch (error) {
console.error('Ozon API validation error:', error)
if (axios.isAxiosError(error)) {
if (error.response?.status === 401) {
return {
isValid: false,
message: 'Неверный API ключ или Client-Id для Ozon'
}
}
if (error.response?.status === 403) {
return {
isValid: false,
message: 'Доступ запрещён. Проверьте права API ключа Ozon'
}
}
if (error.code === 'ECONNABORTED') {
return {
isValid: false,
message: 'Превышено время ожидания ответа от Ozon API'
}
}
}
return {
isValid: false,
message: 'Ошибка при проверке API ключа Ozon'
}
}
}
/**
* Общий метод валидации API ключа по типу маркетплейса
*/
async validateApiKey(
marketplace: 'WILDBERRIES' | 'OZON',
apiKey: string,
clientId?: string
): Promise<MarketplaceValidationResult> {
switch (marketplace) {
case 'WILDBERRIES':
return this.validateWildberriesApiKey(apiKey)
case 'OZON':
return this.validateOzonApiKey(apiKey, clientId)
default:
return {
isValid: false,
message: 'Неподдерживаемый тип маркетплейса'
}
}
}
/**
* Проверяет формат API ключа перед отправкой запроса
*/
validateApiKeyFormat(marketplace: 'WILDBERRIES' | 'OZON', apiKey: string): boolean {
if (!apiKey || typeof apiKey !== 'string') {
return false
}
switch (marketplace) {
case 'WILDBERRIES':
// Wildberries API ключи обычно содержат буквы, цифры и дефисы
return /^[a-zA-Z0-9\-_]{10,}$/.test(apiKey)
case 'OZON':
// Ozon API ключи обычно содержат буквы, цифры и дефисы
return /^[a-zA-Z0-9\-_]{10,}$/.test(apiKey)
default:
return false
}
}
}