Оптимизирована производительность React компонентов с помощью мемоизации
КРИТИЧНЫЕ КОМПОНЕНТЫ ОПТИМИЗИРОВАНЫ: • AdminDashboard (346 kB) - добавлены React.memo, useCallback, useMemo • SellerStatisticsDashboard (329 kB) - мемоизация кэша и callback функций • CreateSupplyPage (276 kB) - оптимизированы вычисления и обработчики • EmployeesDashboard (268 kB) - мемоизация списков и функций • SalesTab + AdvertisingTab - React.memo обертка ТЕХНИЧЕСКИЕ УЛУЧШЕНИЯ: ✅ React.memo() для предотвращения лишних рендеров ✅ useMemo() для тяжелых вычислений ✅ useCallback() для стабильных ссылок на функции ✅ Мемоизация фильтрации и сортировки списков ✅ Оптимизация пропсов в компонентах-контейнерах РЕЗУЛЬТАТЫ: • Все компоненты успешно компилируются • Линтер проходит без критических ошибок • Сохранена вся функциональность • Улучшена производительность рендеринга • Снижена нагрузка на React дерево 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
import { Context } from "../context";
|
||||
// import type { Context } from '../context'
|
||||
|
||||
export const authResolvers = {
|
||||
Query: {},
|
||||
Mutation: {},
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Context } from "../context";
|
||||
// import type { Context } from '../context'
|
||||
|
||||
export const employeeResolvers = {
|
||||
Query: {},
|
||||
Mutation: {},
|
||||
};
|
||||
}
|
||||
|
@ -1,40 +1,48 @@
|
||||
import { JSONScalar, DateTimeScalar } from "../scalars";
|
||||
import { authResolvers } from "./auth";
|
||||
import { employeeResolvers } from "./employees";
|
||||
import { logisticsResolvers } from "./logistics";
|
||||
import { suppliesResolvers } from "./supplies";
|
||||
import { resolvers as oldResolvers } from '../resolvers'
|
||||
import { JSONScalar, DateTimeScalar } from '../scalars'
|
||||
|
||||
import { authResolvers } from './auth'
|
||||
import { employeeResolvers } from './employees'
|
||||
import { logisticsResolvers } from './logistics'
|
||||
import { suppliesResolvers } from './supplies'
|
||||
|
||||
// Типы для резолверов
|
||||
interface ResolverObject {
|
||||
Query?: Record<string, unknown>
|
||||
Mutation?: Record<string, unknown>
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
// Функция для объединения резолверов
|
||||
const mergeResolvers = (...resolvers: any[]) => {
|
||||
const result: any = {
|
||||
const mergeResolvers = (...resolvers: ResolverObject[]): ResolverObject => {
|
||||
const result: ResolverObject = {
|
||||
Query: {},
|
||||
Mutation: {},
|
||||
};
|
||||
}
|
||||
|
||||
for (const resolver of resolvers) {
|
||||
if (resolver.Query) {
|
||||
Object.assign(result.Query, resolver.Query);
|
||||
Object.assign(result.Query, resolver.Query)
|
||||
}
|
||||
if (resolver.Mutation) {
|
||||
Object.assign(result.Mutation, resolver.Mutation);
|
||||
Object.assign(result.Mutation, resolver.Mutation)
|
||||
}
|
||||
// Объединяем другие типы резолверов (например, Employee, Organization и т.д.)
|
||||
for (const [key, value] of Object.entries(resolver)) {
|
||||
if (key !== "Query" && key !== "Mutation") {
|
||||
if (key !== 'Query' && key !== 'Mutation') {
|
||||
if (!result[key]) {
|
||||
result[key] = {};
|
||||
result[key] = {}
|
||||
}
|
||||
Object.assign(result[key], value);
|
||||
Object.assign(result[key], value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
return result
|
||||
}
|
||||
|
||||
// Временно импортируем старые резолверы для частей, которые еще не вынесены
|
||||
// TODO: Постепенно убрать это после полного рефакторинга
|
||||
import { resolvers as oldResolvers } from "../resolvers";
|
||||
|
||||
// Объединяем новые модульные резолверы с остальными старыми
|
||||
export const resolvers = mergeResolvers(
|
||||
@ -80,5 +88,5 @@ export const resolvers = mergeResolvers(
|
||||
// SupplyOrder: oldResolvers.SupplyOrder, // Удалено: отсутствует в старых резолверах
|
||||
// Employee берем из нового модуля
|
||||
Employee: undefined,
|
||||
}
|
||||
);
|
||||
},
|
||||
)
|
||||
|
@ -1,25 +1,26 @@
|
||||
import { GraphQLError } from "graphql";
|
||||
import { Context } from "../context";
|
||||
import { prisma } from "../../lib/prisma";
|
||||
import { GraphQLError } from 'graphql'
|
||||
|
||||
import { prisma } from '../../lib/prisma'
|
||||
import { Context } from '../context'
|
||||
|
||||
export const logisticsResolvers = {
|
||||
Query: {
|
||||
// Получить логистические компании-партнеры
|
||||
logisticsPartners: async (_: unknown, __: unknown, context: Context) => {
|
||||
if (!context.user) {
|
||||
throw new GraphQLError("Требуется авторизация", {
|
||||
extensions: { code: "UNAUTHENTICATED" },
|
||||
});
|
||||
throw new GraphQLError('Требуется авторизация', {
|
||||
extensions: { code: 'UNAUTHENTICATED' },
|
||||
})
|
||||
}
|
||||
|
||||
// Получаем все организации типа LOGIST
|
||||
return await prisma.organization.findMany({
|
||||
where: {
|
||||
type: "LOGIST",
|
||||
type: 'LOGIST',
|
||||
// Убираем фильтр по статусу пока не определим правильные значения
|
||||
},
|
||||
orderBy: { createdAt: "desc" }, // Сортируем по дате создания вместо name
|
||||
});
|
||||
orderBy: { createdAt: 'desc' }, // Сортируем по дате создания вместо name
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
@ -28,29 +29,29 @@ export const logisticsResolvers = {
|
||||
assignLogisticsToSupply: async (
|
||||
_: unknown,
|
||||
args: {
|
||||
supplyOrderId: string;
|
||||
logisticsPartnerId: string;
|
||||
responsibleId?: string;
|
||||
supplyOrderId: string
|
||||
logisticsPartnerId: string
|
||||
responsibleId?: string
|
||||
},
|
||||
context: Context
|
||||
context: Context,
|
||||
) => {
|
||||
if (!context.user) {
|
||||
throw new GraphQLError("Требуется авторизация", {
|
||||
extensions: { code: "UNAUTHENTICATED" },
|
||||
});
|
||||
throw new GraphQLError('Требуется авторизация', {
|
||||
extensions: { code: 'UNAUTHENTICATED' },
|
||||
})
|
||||
}
|
||||
|
||||
const currentUser = await prisma.user.findUnique({
|
||||
where: { id: context.user.id },
|
||||
include: { organization: true },
|
||||
});
|
||||
})
|
||||
|
||||
if (!currentUser?.organization) {
|
||||
throw new GraphQLError("У пользователя нет организации");
|
||||
throw new GraphQLError('У пользователя нет организации')
|
||||
}
|
||||
|
||||
if (currentUser.organization.type !== "FULFILLMENT") {
|
||||
throw new GraphQLError("Доступно только для фулфилмент центров");
|
||||
if (currentUser.organization.type !== 'FULFILLMENT') {
|
||||
throw new GraphQLError('Доступно только для фулфилмент центров')
|
||||
}
|
||||
|
||||
try {
|
||||
@ -65,31 +66,29 @@ export const logisticsResolvers = {
|
||||
include: { product: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
if (!existingOrder) {
|
||||
throw new GraphQLError("Заказ поставки не найден");
|
||||
throw new GraphQLError('Заказ поставки не найден')
|
||||
}
|
||||
|
||||
// Проверяем, что это заказ для нашего фулфилмент-центра
|
||||
if (existingOrder.fulfillmentCenterId !== currentUser.organization.id) {
|
||||
throw new GraphQLError("Нет доступа к этому заказу");
|
||||
throw new GraphQLError('Нет доступа к этому заказу')
|
||||
}
|
||||
|
||||
// Проверяем, что статус позволяет назначить логистику
|
||||
if (existingOrder.status !== "SUPPLIER_APPROVED") {
|
||||
throw new GraphQLError(
|
||||
`Нельзя назначить логистику для заказа со статусом ${existingOrder.status}`
|
||||
);
|
||||
if (existingOrder.status !== 'SUPPLIER_APPROVED') {
|
||||
throw new GraphQLError(`Нельзя назначить логистику для заказа со статусом ${existingOrder.status}`)
|
||||
}
|
||||
|
||||
// Проверяем, что логистическая компания существует
|
||||
const logisticsPartner = await prisma.organization.findUnique({
|
||||
where: { id: args.logisticsPartnerId },
|
||||
});
|
||||
})
|
||||
|
||||
if (!logisticsPartner || logisticsPartner.type !== "LOGIST") {
|
||||
throw new GraphQLError("Логистическая компания не найдена");
|
||||
if (!logisticsPartner || logisticsPartner.type !== 'LOGIST') {
|
||||
throw new GraphQLError('Логистическая компания не найдена')
|
||||
}
|
||||
|
||||
// Обновляем заказ
|
||||
@ -99,7 +98,7 @@ export const logisticsResolvers = {
|
||||
logisticsPartner: {
|
||||
connect: { id: args.logisticsPartnerId },
|
||||
},
|
||||
status: "CONFIRMED", // Переводим в статус "подтвержден фулфилментом"
|
||||
status: 'CONFIRMED', // Переводим в статус "подтвержден фулфилментом"
|
||||
},
|
||||
include: {
|
||||
partner: true,
|
||||
@ -109,50 +108,43 @@ export const logisticsResolvers = {
|
||||
include: { product: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
console.log(`✅ Логистика назначена на заказ ${args.supplyOrderId}:`, {
|
||||
console.warn(`✅ Логистика назначена на заказ ${args.supplyOrderId}:`, {
|
||||
logisticsPartner: logisticsPartner.name,
|
||||
responsible: args.responsibleId,
|
||||
newStatus: "CONFIRMED",
|
||||
});
|
||||
newStatus: 'CONFIRMED',
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Логистика успешно назначена",
|
||||
message: 'Логистика успешно назначена',
|
||||
order: updatedOrder,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ Ошибка при назначении логистики:", error);
|
||||
console.error('❌ Ошибка при назначении логистики:', error)
|
||||
return {
|
||||
success: false,
|
||||
message:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Ошибка при назначении логистики",
|
||||
};
|
||||
message: error instanceof Error ? error.message : 'Ошибка при назначении логистики',
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Подтвердить заказ логистической компанией
|
||||
logisticsConfirmOrder: async (
|
||||
_: unknown,
|
||||
args: { id: string },
|
||||
context: Context
|
||||
) => {
|
||||
logisticsConfirmOrder: async (_: unknown, args: { id: string }, context: Context) => {
|
||||
if (!context.user) {
|
||||
throw new GraphQLError("Требуется авторизация", {
|
||||
extensions: { code: "UNAUTHENTICATED" },
|
||||
});
|
||||
throw new GraphQLError('Требуется авторизация', {
|
||||
extensions: { code: 'UNAUTHENTICATED' },
|
||||
})
|
||||
}
|
||||
|
||||
const currentUser = await prisma.user.findUnique({
|
||||
where: { id: context.user.id },
|
||||
include: { organization: true },
|
||||
});
|
||||
})
|
||||
|
||||
if (!currentUser?.organization) {
|
||||
throw new GraphQLError("У пользователя нет организации");
|
||||
throw new GraphQLError('У пользователя нет организации')
|
||||
}
|
||||
|
||||
try {
|
||||
@ -160,21 +152,20 @@ export const logisticsResolvers = {
|
||||
where: {
|
||||
id: args.id,
|
||||
logisticsPartnerId: currentUser.organization.id,
|
||||
OR: [{ status: "SUPPLIER_APPROVED" }, { status: "CONFIRMED" }],
|
||||
OR: [{ status: 'SUPPLIER_APPROVED' }, { status: 'CONFIRMED' }],
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
if (!existingOrder) {
|
||||
return {
|
||||
success: false,
|
||||
message:
|
||||
"Заказ не найден или недоступен для подтверждения логистикой",
|
||||
};
|
||||
message: 'Заказ не найден или недоступен для подтверждения логистикой',
|
||||
}
|
||||
}
|
||||
|
||||
const updatedOrder = await prisma.supplyOrder.update({
|
||||
where: { id: args.id },
|
||||
data: { status: "LOGISTICS_CONFIRMED" },
|
||||
data: { status: 'LOGISTICS_CONFIRMED' },
|
||||
include: {
|
||||
partner: true,
|
||||
organization: true,
|
||||
@ -191,41 +182,37 @@ export const logisticsResolvers = {
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Заказ подтвержден логистической компанией",
|
||||
message: 'Заказ подтвержден логистической компанией',
|
||||
order: updatedOrder,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error confirming supply order:", error);
|
||||
console.error('Error confirming supply order:', error)
|
||||
return {
|
||||
success: false,
|
||||
message: "Ошибка при подтверждении заказа",
|
||||
};
|
||||
message: 'Ошибка при подтверждении заказа',
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Отклонить заказ логистической компанией
|
||||
logisticsRejectOrder: async (
|
||||
_: unknown,
|
||||
args: { id: string },
|
||||
context: Context
|
||||
) => {
|
||||
logisticsRejectOrder: async (_: unknown, args: { id: string }, context: Context) => {
|
||||
if (!context.user) {
|
||||
throw new GraphQLError("Требуется авторизация", {
|
||||
extensions: { code: "UNAUTHENTICATED" },
|
||||
});
|
||||
throw new GraphQLError('Требуется авторизация', {
|
||||
extensions: { code: 'UNAUTHENTICATED' },
|
||||
})
|
||||
}
|
||||
|
||||
const currentUser = await prisma.user.findUnique({
|
||||
where: { id: context.user.id },
|
||||
include: { organization: true },
|
||||
});
|
||||
})
|
||||
|
||||
if (!currentUser?.organization) {
|
||||
throw new GraphQLError("У пользователя нет организации");
|
||||
throw new GraphQLError('У пользователя нет организации')
|
||||
}
|
||||
|
||||
try {
|
||||
@ -233,21 +220,21 @@ export const logisticsResolvers = {
|
||||
where: {
|
||||
id: args.id,
|
||||
logisticsPartnerId: currentUser.organization.id,
|
||||
OR: [{ status: "SUPPLIER_APPROVED" }, { status: "CONFIRMED" }],
|
||||
OR: [{ status: 'SUPPLIER_APPROVED' }, { status: 'CONFIRMED' }],
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
if (!existingOrder) {
|
||||
return {
|
||||
success: false,
|
||||
message: "Заказ не найден или недоступен для отклонения логистикой",
|
||||
};
|
||||
message: 'Заказ не найден или недоступен для отклонения логистикой',
|
||||
}
|
||||
}
|
||||
|
||||
const updatedOrder = await prisma.supplyOrder.update({
|
||||
where: { id: args.id },
|
||||
data: {
|
||||
status: "CANCELLED",
|
||||
status: 'CANCELLED',
|
||||
logisticsPartnerId: null, // Убираем назначенную логистику
|
||||
},
|
||||
include: {
|
||||
@ -266,20 +253,20 @@ export const logisticsResolvers = {
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Заказ отклонен логистической компанией",
|
||||
message: 'Заказ отклонен логистической компанией',
|
||||
order: updatedOrder,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error rejecting supply order:", error);
|
||||
console.error('Error rejecting supply order:', error)
|
||||
return {
|
||||
success: false,
|
||||
message: "Ошибка при отклонении заказа",
|
||||
};
|
||||
message: 'Ошибка при отклонении заказа',
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Context } from "../context";
|
||||
// import type { Context } from '../context'
|
||||
|
||||
export const suppliesResolvers = {
|
||||
Query: {},
|
||||
Mutation: {},
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user