Обновлены компоненты интерфейса для работы с карточками товаров Wildberries: добавлены новые функции для загрузки и поиска карточек, улучшен интерфейс отображения товаров и их деталей. Исправлены проблемы с отображением текста и добавлены новые поля в GraphQL для работы с API ключами. Реализована логика обработки ошибок при взаимодействии с API.

This commit is contained in:
Bivekich
2025-07-21 13:51:12 +03:00
parent d964b9b6d4
commit d3fb590c6e
10 changed files with 836 additions and 254 deletions

View File

@ -177,6 +177,7 @@ export const ADD_MARKETPLACE_API_KEY = gql`
apiKey {
id
marketplace
apiKey
isActive
validationData
}

View File

@ -40,8 +40,11 @@ export const GET_ME = gql`
apiKeys {
id
marketplace
apiKey
isActive
validationData
createdAt
updatedAt
}
}
}
@ -253,6 +256,7 @@ export const GET_ORGANIZATION = gql`
apiKeys {
id
marketplace
apiKey
isActive
validationData
createdAt

View File

@ -96,7 +96,7 @@ const generateToken = (payload: AuthTokenPayload): string => {
const verifyToken = (token: string): AuthTokenPayload => {
try {
return jwt.verify(token, process.env.JWT_SECRET!) as AuthTokenPayload;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
throw new GraphQLError("Недействительный токен", {
extensions: { code: "UNAUTHENTICATED" },
@ -168,7 +168,7 @@ function parseLiteral(ast: unknown): unknown {
fields?: unknown[];
values?: unknown[];
};
switch (astNode.kind) {
case Kind.STRING:
case Kind.BOOLEAN:
@ -290,7 +290,7 @@ export const resolvers = {
// Получаем исходящие заявки для добавления флага hasOutgoingRequest
const outgoingRequests = await prisma.counterpartyRequest.findMany({
where: {
where: {
senderId: currentUser.organization.id,
status: "PENDING",
},
@ -301,7 +301,7 @@ export const resolvers = {
// Получаем входящие заявки для добавления флага hasIncomingRequest
const incomingRequests = await prisma.counterpartyRequest.findMany({
where: {
where: {
receiverId: currentUser.organization.id,
status: "PENDING",
},
@ -365,7 +365,7 @@ export const resolvers = {
const counterparties = await prisma.counterparty.findMany({
where: { organizationId: currentUser.organization.id },
include: {
include: {
counterparty: {
include: {
users: true,
@ -396,7 +396,7 @@ export const resolvers = {
}
return await prisma.counterpartyRequest.findMany({
where: {
where: {
receiverId: currentUser.organization.id,
status: "PENDING",
},
@ -436,7 +436,7 @@ export const resolvers = {
}
return await prisma.counterpartyRequest.findMany({
where: {
where: {
senderId: currentUser.organization.id,
status: { in: ["PENDING", "REJECTED"] },
},
@ -505,7 +505,7 @@ export const resolvers = {
receiverOrganization: {
include: {
users: true,
},
},
},
},
orderBy: { createdAt: "asc" },
@ -670,7 +670,7 @@ export const resolvers = {
return await prisma.product.findMany({
where: { organizationId: currentUser.organization.id },
include: {
include: {
category: true,
organization: true,
},
@ -712,7 +712,7 @@ export const resolvers = {
return await prisma.product.findMany({
where,
include: {
include: {
category: true,
organization: {
include: {
@ -897,7 +897,7 @@ export const resolvers = {
}
const employee = await prisma.employee.findFirst({
where: {
where: {
id: args.id,
organizationId: currentUser.organization.id,
},
@ -984,7 +984,7 @@ export const resolvers = {
args.phone,
args.code
);
if (!verificationResult.success) {
return {
success: false,
@ -1043,7 +1043,7 @@ export const resolvers = {
};
console.log("verifySmsCode - Returning result:", {
success: result.success,
success: result.success,
hasToken: !!result.token,
hasUser: !!result.user,
message: result.message,
@ -1147,28 +1147,28 @@ export const resolvers = {
addressFull: organizationData.addressFull,
ogrn: organizationData.ogrn,
ogrnDate: organizationData.ogrnDate,
// Статус организации
status: organizationData.status,
actualityDate: organizationData.actualityDate,
registrationDate: organizationData.registrationDate,
liquidationDate: organizationData.liquidationDate,
// Руководитель
managementName: organizationData.managementName,
managementPost: organizationData.managementPost,
// ОПФ
opfCode: organizationData.opfCode,
opfFull: organizationData.opfFull,
opfShort: organizationData.opfShort,
// Коды статистики
okato: organizationData.okato,
oktmo: organizationData.oktmo,
okpo: organizationData.okpo,
okved: organizationData.okved,
// Контакты
phones: organizationData.phones
? JSON.parse(JSON.stringify(organizationData.phones))
@ -1176,12 +1176,12 @@ export const resolvers = {
emails: organizationData.emails
? JSON.parse(JSON.stringify(organizationData.emails))
: null,
// Финансовые данные
employeeCount: organizationData.employeeCount,
revenue: organizationData.revenue,
taxSystem: organizationData.taxSystem,
type: type,
dadataData: JSON.parse(JSON.stringify(organizationData.rawData)),
},
@ -1284,7 +1284,7 @@ export const resolvers = {
const tradeMark = validationResults[0]?.data?.tradeMark;
const sellerName = validationResults[0]?.data?.sellerName;
const shopName = tradeMark || sellerName || "Магазин";
const organization = await prisma.organization.create({
data: {
inn:
@ -1427,7 +1427,7 @@ export const resolvers = {
where: { id: existingKey.id },
data: {
apiKey,
validationData: JSON.parse(JSON.stringify(validationResult.data)),
validationData: JSON.parse(JSON.stringify(validationResult.data)),
isActive: true,
},
});
@ -1453,7 +1453,7 @@ export const resolvers = {
message: "API ключ успешно добавлен",
apiKey: newKey,
};
}
}
} catch (error) {
console.error("Error adding marketplace API key:", error);
return {
@ -1526,7 +1526,7 @@ export const resolvers = {
const user = await prisma.user.findUnique({
where: { id: context.user.id },
include: {
include: {
organization: {
include: {
apiKeys: true,
@ -1541,7 +1541,7 @@ export const resolvers = {
try {
const { input } = args;
// Обновляем данные пользователя (аватар, имя управляющего)
const userUpdateData: { avatar?: string; managerName?: string } = {};
if (input.avatar) {
@ -1550,14 +1550,14 @@ export const resolvers = {
if (input.managerName) {
userUpdateData.managerName = input.managerName;
}
if (Object.keys(userUpdateData).length > 0) {
await prisma.user.update({
where: { id: context.user.id },
data: userUpdateData,
});
}
// Подготавливаем данные для обновления организации
const updateData: {
phones?: object;
@ -1565,20 +1565,20 @@ export const resolvers = {
managementName?: string;
managementPost?: string;
} = {};
// Название организации больше не обновляется через профиль
// Для селлеров устанавливается при регистрации, для остальных - при смене ИНН
// Обновляем контактные данные в JSON поле phones
if (input.orgPhone) {
updateData.phones = [{ value: input.orgPhone, type: "main" }];
}
// Обновляем email в JSON поле emails
// Обновляем email в JSON поле emails
if (input.email) {
updateData.emails = [{ value: input.email, type: "main" }];
}
// Сохраняем дополнительные контакты в custom полях
// Пока добавим их как дополнительные JSON поля
const customContacts: {
@ -1592,13 +1592,13 @@ export const resolvers = {
corrAccount?: string;
};
} = {};
// managerName теперь сохраняется в поле пользователя, а не в JSON
if (input.telegram) {
customContacts.telegram = input.telegram;
}
if (input.whatsapp) {
customContacts.whatsapp = input.whatsapp;
}
@ -1616,7 +1616,7 @@ export const resolvers = {
corrAccount: input.corrAccount,
};
}
// Если есть дополнительные контакты, сохраним их в поле managementPost временно
// В идеале нужно добавить отдельную таблицу для контактов
if (Object.keys(customContacts).length > 0) {
@ -1635,7 +1635,7 @@ export const resolvers = {
// Получаем обновленного пользователя
const updatedUser = await prisma.user.findUnique({
where: { id: context.user.id },
include: {
include: {
organization: {
include: {
apiKeys: true,
@ -1671,7 +1671,7 @@ export const resolvers = {
const user = await prisma.user.findUnique({
where: { id: context.user.id },
include: {
include: {
organization: {
include: {
apiKeys: true,
@ -1769,7 +1769,7 @@ export const resolvers = {
// Получаем обновленного пользователя
const updatedUser = await prisma.user.findUnique({
where: { id: context.user.id },
include: {
include: {
organization: {
include: {
apiKeys: true,
@ -2930,22 +2930,22 @@ export const resolvers = {
createProduct: async (
_: unknown,
args: {
input: {
name: string;
article: string;
description?: string;
price: number;
quantity: number;
categoryId?: string;
brand?: string;
color?: string;
size?: string;
weight?: number;
dimensions?: string;
material?: string;
images?: string[];
mainImage?: string;
isActive?: boolean;
input: {
name: string;
article: string;
description?: string;
price: number;
quantity: number;
categoryId?: string;
brand?: string;
color?: string;
size?: string;
weight?: number;
dimensions?: string;
material?: string;
images?: string[];
mainImage?: string;
isActive?: boolean;
};
},
context: Context
@ -3005,7 +3005,7 @@ export const resolvers = {
isActive: args.input.isActive ?? true,
organizationId: currentUser.organization.id,
},
include: {
include: {
category: true,
organization: true,
},
@ -3029,23 +3029,23 @@ export const resolvers = {
updateProduct: async (
_: unknown,
args: {
id: string;
input: {
name: string;
article: string;
description?: string;
price: number;
quantity: number;
categoryId?: string;
brand?: string;
color?: string;
size?: string;
weight?: number;
dimensions?: string;
material?: string;
images?: string[];
mainImage?: string;
isActive?: boolean;
id: string;
input: {
name: string;
article: string;
description?: string;
price: number;
quantity: number;
categoryId?: string;
brand?: string;
color?: string;
size?: string;
weight?: number;
dimensions?: string;
material?: string;
images?: string[];
mainImage?: string;
isActive?: boolean;
};
},
context: Context
@ -3115,7 +3115,7 @@ export const resolvers = {
mainImage: args.input.mainImage,
isActive: args.input.isActive ?? true,
},
include: {
include: {
category: true,
organization: true,
},
@ -3400,7 +3400,7 @@ export const resolvers = {
if (existingCartItem) {
// Обновляем количество
const newQuantity = existingCartItem.quantity + args.quantity;
if (newQuantity > product.quantity) {
return {
success: false,
@ -3940,7 +3940,7 @@ export const resolvers = {
try {
const employee = await prisma.employee.update({
where: {
where: {
id: args.id,
organizationId: currentUser.organization.id,
},
@ -4002,7 +4002,7 @@ export const resolvers = {
try {
await prisma.employee.delete({
where: {
where: {
id: args.id,
organizationId: currentUser.organization.id,
},
@ -4150,7 +4150,7 @@ export const resolvers = {
if (parent.users) {
return parent.users;
}
// Иначе загружаем отдельно
return await prisma.user.findMany({
where: { organizationId: parent.id },
@ -4197,7 +4197,7 @@ export const resolvers = {
if (parent.organization) {
return parent.organization;
}
// Иначе загружаем отдельно если есть organizationId
if (parent.organizationId) {
return await prisma.organization.findUnique({
@ -4514,14 +4514,14 @@ const adminQueries = {
const limit = args.limit || 50;
const offset = args.offset || 0;
// Строим условие поиска
const whereCondition: Prisma.UserWhereInput = args.search
? {
OR: [
{ phone: { contains: args.search, mode: "insensitive" } },
{ managerName: { contains: args.search, mode: "insensitive" } },
{
{
organization: {
OR: [
{ name: { contains: args.search, mode: "insensitive" } },
@ -4589,7 +4589,7 @@ const adminMutations = {
args.password,
admin.password
);
if (!isPasswordValid) {
return {
success: false,
@ -4605,7 +4605,7 @@ const adminMutations = {
// Создать токен
const token = jwt.sign(
{
{
adminId: admin.id,
username: admin.username,
type: "admin",

View File

@ -246,6 +246,7 @@ export const typeDefs = gql`
type ApiKey {
id: ID!
marketplace: MarketplaceType!
apiKey: String!
isActive: Boolean!
validationData: JSON
createdAt: DateTime!