Добавлены кастомные скроллбары в глобальные стили. Обновлен компонент карточек товаров: добавлены функции загрузки услуг и расходников для выбранных организаций, изменены интерфейсы для выбора фулфилмент-организаций и расходников, улучшена логика расчета стоимости с учетом дополнительных расходов. Оптимизирован код для повышения читаемости и производительности. Обновлены запросы GraphQL для получения услуг и расходников от контрагентов.

This commit is contained in:
Bivekich
2025-07-21 17:48:12 +03:00
parent 155c6c95cd
commit 4138b64a3e
5 changed files with 675 additions and 240 deletions

View File

@ -612,6 +612,39 @@ export const GET_MY_WILDBERRIES_SUPPLIES = gql`
}
`
// Запросы для получения услуг и расходников от конкретных организаций-контрагентов
export const GET_COUNTERPARTY_SERVICES = gql`
query GetCounterpartyServices($organizationId: ID!) {
counterpartyServices(organizationId: $organizationId) {
id
name
description
price
imageUrl
createdAt
updatedAt
}
}
`
export const GET_COUNTERPARTY_SUPPLIES = gql`
query GetCounterpartySupplies($organizationId: ID!) {
counterpartySupplies(organizationId: $organizationId) {
id
name
description
price
quantity
unit
category
status
imageUrl
createdAt
updatedAt
}
}
`
// Админ запросы
export const ADMIN_ME = gql`
query AdminMe {

View File

@ -810,6 +810,104 @@ export const resolvers = {
});
},
// Публичные услуги контрагента (для фулфилмента)
counterpartyServices: async (
_: unknown,
args: { organizationId: string },
context: Context
) => {
if (!context.user) {
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("У пользователя нет организации");
}
// Проверяем, что запрашиваемая организация является контрагентом
const counterparty = await prisma.counterparty.findFirst({
where: {
organizationId: currentUser.organization.id,
counterpartyId: args.organizationId,
},
});
if (!counterparty) {
throw new GraphQLError("Организация не является вашим контрагентом");
}
// Проверяем, что это фулфилмент центр
const targetOrganization = await prisma.organization.findUnique({
where: { id: args.organizationId },
});
if (!targetOrganization || targetOrganization.type !== "FULFILLMENT") {
throw new GraphQLError("Услуги доступны только у фулфилмент центров");
}
return await prisma.service.findMany({
where: { organizationId: args.organizationId },
include: { organization: true },
orderBy: { createdAt: "desc" },
});
},
// Публичные расходники контрагента (для оптовиков)
counterpartySupplies: async (
_: unknown,
args: { organizationId: string },
context: Context
) => {
if (!context.user) {
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("У пользователя нет организации");
}
// Проверяем, что запрашиваемая организация является контрагентом
const counterparty = await prisma.counterparty.findFirst({
where: {
organizationId: currentUser.organization.id,
counterpartyId: args.organizationId,
},
});
if (!counterparty) {
throw new GraphQLError("Организация не является вашим контрагентом");
}
// Проверяем, что это фулфилмент центр (у них есть расходники)
const targetOrganization = await prisma.organization.findUnique({
where: { id: args.organizationId },
});
if (!targetOrganization || targetOrganization.type !== "FULFILLMENT") {
throw new GraphQLError("Расходники доступны только у фулфилмент центров");
}
return await prisma.supply.findMany({
where: { organizationId: args.organizationId },
include: { organization: true },
orderBy: { createdAt: "desc" },
});
},
// Корзина пользователя
myCart: async (_: unknown, __: unknown, context: Context) => {
if (!context.user) {
@ -4312,6 +4410,32 @@ export const resolvers = {
where: { organizationId: parent.id },
});
},
services: async (parent: { id: string; services?: unknown[] }) => {
// Если услуги уже загружены через include, возвращаем их
if (parent.services) {
return parent.services;
}
// Иначе загружаем отдельно
return await prisma.service.findMany({
where: { organizationId: parent.id },
include: { organization: true },
orderBy: { createdAt: "desc" },
});
},
supplies: async (parent: { id: string; supplies?: unknown[] }) => {
// Если расходники уже загружены через include, возвращаем их
if (parent.supplies) {
return parent.supplies;
}
// Иначе загружаем отдельно
return await prisma.supply.findMany({
where: { organizationId: parent.id },
include: { organization: true },
orderBy: { createdAt: "desc" },
});
},
},
Cart: {

View File

@ -66,6 +66,12 @@ export const typeDefs = gql`
month: Int!
): [EmployeeSchedule!]!
# Публичные услуги контрагента (для фулфилмента)
counterpartyServices(organizationId: ID!): [Service!]!
# Публичные расходники контрагента (для оптовиков)
counterpartySupplies(organizationId: ID!): [Supply!]!
# Админ запросы
adminMe: Admin
allUsers(search: String, limit: Int, offset: Int): UsersResponse!
@ -235,6 +241,8 @@ export const typeDefs = gql`
emails: JSON
users: [User!]!
apiKeys: [ApiKey!]!
services: [Service!]!
supplies: [Supply!]!
isCounterparty: Boolean
isCurrentUser: Boolean
hasOutgoingRequest: Boolean