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

This commit is contained in:
Bivekich
2025-07-19 14:53:45 +03:00
parent f24c015021
commit 6287449521
26 changed files with 3931 additions and 19 deletions

View File

@ -1,4 +1,5 @@
import jwt from 'jsonwebtoken'
import bcrypt from 'bcryptjs'
import { GraphQLError } from 'graphql'
import { GraphQLScalarType, Kind } from 'graphql'
import { prisma } from '@/lib/prisma'
@ -18,6 +19,10 @@ interface Context {
id: string
phone: string
}
admin?: {
id: string
username: string
}
}
interface CreateEmployeeInput {
@ -3736,4 +3741,167 @@ const logisticsMutations = {
resolvers.Mutation = {
...resolvers.Mutation,
...logisticsMutations
}
// Админ резолверы
const adminQueries = {
adminMe: async (_: unknown, __: unknown, context: Context) => {
if (!context.admin) {
throw new GraphQLError('Требуется авторизация администратора', {
extensions: { code: 'UNAUTHENTICATED' }
})
}
const admin = await prisma.admin.findUnique({
where: { id: context.admin.id }
})
if (!admin) {
throw new GraphQLError('Администратор не найден')
}
return admin
},
allUsers: async (_: unknown, args: { search?: string; limit?: number; offset?: number }, context: Context) => {
if (!context.admin) {
throw new GraphQLError('Требуется авторизация администратора', {
extensions: { code: 'UNAUTHENTICATED' }
})
}
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' } },
{ fullName: { contains: args.search, mode: 'insensitive' } },
{ inn: { contains: args.search, mode: 'insensitive' } }
]
}
}
]
}
: {}
// Получаем пользователей с пагинацией
const [users, total] = await Promise.all([
prisma.user.findMany({
where: whereCondition,
include: {
organization: true
},
take: limit,
skip: offset,
orderBy: { createdAt: 'desc' }
}),
prisma.user.count({
where: whereCondition
})
])
return {
users,
total,
hasMore: offset + limit < total
}
}
}
const adminMutations = {
adminLogin: async (_: unknown, args: { username: string; password: string }) => {
try {
// Найти администратора
const admin = await prisma.admin.findUnique({
where: { username: args.username }
})
if (!admin) {
return {
success: false,
message: 'Неверные учетные данные'
}
}
// Проверить активность
if (!admin.isActive) {
return {
success: false,
message: 'Аккаунт заблокирован'
}
}
// Проверить пароль
const isPasswordValid = await bcrypt.compare(args.password, admin.password)
if (!isPasswordValid) {
return {
success: false,
message: 'Неверные учетные данные'
}
}
// Обновить время последнего входа
await prisma.admin.update({
where: { id: admin.id },
data: { lastLogin: new Date() }
})
// Создать токен
const token = jwt.sign(
{
adminId: admin.id,
username: admin.username,
type: 'admin'
},
process.env.JWT_SECRET!,
{ expiresIn: '24h' }
)
return {
success: true,
message: 'Успешная авторизация',
token,
admin: {
...admin,
password: undefined // Не возвращаем пароль
}
}
} catch (error) {
console.error('Admin login error:', error)
return {
success: false,
message: 'Ошибка авторизации'
}
}
},
adminLogout: async (_: unknown, __: unknown, context: Context) => {
if (!context.admin) {
throw new GraphQLError('Требуется авторизация администратора', {
extensions: { code: 'UNAUTHENTICATED' }
})
}
return true
}
}
// Добавляем админ запросы и мутации к основным резолверам
resolvers.Query = {
...resolvers.Query,
...adminQueries
}
resolvers.Mutation = {
...resolvers.Mutation,
...adminMutations
}