318075d686
modified: internal/domain/appeal/dto.go new file: internal/domain/appeal/handler.go modified: internal/domain/appeal/router.go modified: internal/domain/appeal/service.go modified: internal/models/appeal.go modified: internal/router/router.go fix bag with no embeded the Base into appeal
219 lines
8.4 KiB
Go
219 lines
8.4 KiB
Go
package appeal
|
|
|
|
import (
|
|
"time"
|
|
"api_yal/internal/models"
|
|
)
|
|
|
|
// CreateAppealRequest DTO для создания обращения
|
|
type CreateAppealRequest struct {
|
|
Type string `json:"type" validate:"required,oneof=complaint suggestion wish question other"`
|
|
Title string `json:"title" validate:"required,min=3,max=255"`
|
|
Message string `json:"message" validate:"required,min=10"`
|
|
Priority string `json:"priority" validate:"omitempty,oneof=low medium high critical"`
|
|
ObjectID *uint `json:"object_id,omitempty"`
|
|
FeedbackID *uint `json:"feedback_id,omitempty"`
|
|
CommentID *uint `json:"comment_id,omitempty"`
|
|
ContactName string `json:"contact_name,omitempty"`
|
|
ContactEmail string `json:"contact_email,omitempty" validate:"omitempty,email"`
|
|
ContactPhone string `json:"contact_phone,omitempty"`
|
|
Attachments []string `json:"attachments,omitempty"`
|
|
Category string `json:"category,omitempty"`
|
|
Labels []string `json:"labels,omitempty"`
|
|
CustomData map[string]interface{} `json:"custom_data,omitempty"`
|
|
IPAddress string `json:"ip_address,omitempty"`
|
|
UserAgent string `json:"user_agent,omitempty"`
|
|
}
|
|
|
|
// UpdateAppealRequest DTO для обновления обращения
|
|
type UpdateAppealRequest struct {
|
|
Title *string `json:"title,omitempty" validate:"omitempty,min=3,max=255"`
|
|
Message *string `json:"message,omitempty" validate:"omitempty,min=10"`
|
|
Priority *string `json:"priority,omitempty" validate:"omitempty,oneof=low medium high critical"`
|
|
Category *string `json:"category,omitempty"`
|
|
Labels []string `json:"labels,omitempty"`
|
|
Attachments []string `json:"attachments,omitempty"`
|
|
CustomData map[string]interface{} `json:"custom_data,omitempty"`
|
|
}
|
|
|
|
// UpdateStatusRequest DTO для обновления статуса
|
|
type UpdateStatusRequest struct {
|
|
Status string `json:"status" validate:"required,oneof=new in_progress resolved rejected closed"`
|
|
Comment string `json:"comment,omitempty"`
|
|
}
|
|
|
|
// AssignRequest DTO для назначения ответственного
|
|
type AssignRequest struct {
|
|
AssignedToID *uint `json:"assigned_to_id"`
|
|
}
|
|
|
|
// ResolveRequest DTO для решения обращения
|
|
type ResolveRequest struct {
|
|
Resolution string `json:"resolution" validate:"required,min=5"`
|
|
}
|
|
|
|
// AppealResponse DTO для ответа
|
|
type AppealResponse struct {
|
|
ID uint `json:"id"`
|
|
Type string `json:"type"`
|
|
Status string `json:"status"`
|
|
Priority string `json:"priority"`
|
|
Title string `json:"title"`
|
|
Message string `json:"message"`
|
|
AuthorID *uint `json:"author_id,omitempty"`
|
|
Author *AuthorInfo `json:"author,omitempty"`
|
|
ObjectID *uint `json:"object_id,omitempty"`
|
|
Object *ObjectInfo `json:"object,omitempty"`
|
|
FeedbackID *uint `json:"feedback_id,omitempty"`
|
|
CommentID *uint `json:"comment_id,omitempty"`
|
|
ContactName string `json:"contact_name,omitempty"`
|
|
ContactEmail string `json:"contact_email,omitempty"`
|
|
ContactPhone string `json:"contact_phone,omitempty"`
|
|
Attachments []string `json:"attachments,omitempty"`
|
|
Category string `json:"category,omitempty"`
|
|
Labels []string `json:"labels,omitempty"`
|
|
AssignedToID *uint `json:"assigned_to_id,omitempty"`
|
|
AssignedTo *AuthorInfo `json:"assigned_to,omitempty"`
|
|
ResolvedAt *time.Time `json:"resolved_at,omitempty"`
|
|
ResolvedBy *uint `json:"resolved_by,omitempty"`
|
|
Resolution string `json:"resolution,omitempty"`
|
|
CustomData map[string]interface{} `json:"custom_data,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
// AuthorInfo информация об авторе
|
|
type AuthorInfo struct {
|
|
ID uint `json:"id"`
|
|
Email string `json:"email"`
|
|
FirstName string `json:"first_name"`
|
|
LastName string `json:"last_name"`
|
|
}
|
|
|
|
// ObjectInfo информация об объекте
|
|
type ObjectInfo struct {
|
|
ID uint `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
}
|
|
|
|
// ListAppealsResponse DTO для списка обращений
|
|
type ListAppealsResponse struct {
|
|
Data []AppealResponse `json:"data"`
|
|
Total int64 `json:"total"`
|
|
Offset int `json:"offset"`
|
|
Limit int `json:"limit"`
|
|
TotalPages int `json:"total_pages"`
|
|
}
|
|
|
|
// AppealHistoryResponse DTO для истории
|
|
type AppealHistoryResponse struct {
|
|
ID uint `json:"id"`
|
|
AppealID uint `json:"appeal_id"`
|
|
UserID *uint `json:"user_id,omitempty"`
|
|
User *AuthorInfo `json:"user,omitempty"`
|
|
OldStatus string `json:"old_status"`
|
|
NewStatus string `json:"new_status"`
|
|
Comment string `json:"comment,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// ListHistoryResponse DTO для списка истории
|
|
type ListHistoryResponse struct {
|
|
Data []AppealHistoryResponse `json:"data"`
|
|
Total int64 `json:"total"`
|
|
Offset int `json:"offset"`
|
|
Limit int `json:"limit"`
|
|
TotalPages int `json:"total_pages"`
|
|
}
|
|
|
|
// AppealStatisticsResponse DTO для статистики
|
|
type AppealStatisticsResponse struct {
|
|
Total int64 `json:"total"`
|
|
ByStatus map[string]int64 `json:"by_status"`
|
|
ByType map[string]int64 `json:"by_type"`
|
|
ByPriority map[string]int64 `json:"by_priority"`
|
|
ByCategory map[string]int64 `json:"by_category,omitempty"`
|
|
AvgResolveTime float64 `json:"avg_resolve_time_hours"`
|
|
}
|
|
|
|
// NewAppealResponse создает AppealResponse из модели
|
|
func NewAppealResponse(appeal *models.Appeal) AppealResponse {
|
|
resp := AppealResponse{
|
|
ID: appeal.ID,
|
|
Type: string(appeal.Type),
|
|
Status: string(appeal.Status),
|
|
Priority: string(appeal.Priority),
|
|
Title: appeal.Title,
|
|
Message: appeal.Message,
|
|
AuthorID: appeal.AuthorID,
|
|
ObjectID: appeal.ObjectID,
|
|
FeedbackID: appeal.FeedbackID,
|
|
CommentID: appeal.CommentID,
|
|
ContactName: appeal.ContactName,
|
|
ContactEmail: appeal.ContactEmail,
|
|
ContactPhone: appeal.ContactPhone,
|
|
Attachments: appeal.Attachments,
|
|
Category: appeal.Category,
|
|
Labels: appeal.Labels,
|
|
AssignedToID: appeal.AssignedToID,
|
|
ResolvedAt: appeal.ResolvedAt,
|
|
ResolvedBy: appeal.ResolvedBy,
|
|
Resolution: appeal.Resolution,
|
|
CustomData: appeal.CustomData,
|
|
CreatedAt: appeal.CreatedAt,
|
|
UpdatedAt: appeal.UpdatedAt,
|
|
}
|
|
|
|
if appeal.Author != nil {
|
|
resp.Author = &AuthorInfo{
|
|
ID: appeal.Author.ID,
|
|
Email: appeal.Author.Email,
|
|
FirstName: appeal.Author.FirstName,
|
|
LastName: appeal.Author.LastName,
|
|
}
|
|
}
|
|
|
|
if appeal.Object != nil {
|
|
resp.Object = &ObjectInfo{
|
|
ID: appeal.Object.ID,
|
|
Name: appeal.Object.ShortName,
|
|
Description: appeal.Object.Description,
|
|
}
|
|
}
|
|
|
|
if appeal.AssignedTo != nil {
|
|
resp.AssignedTo = &AuthorInfo{
|
|
ID: appeal.AssignedTo.ID,
|
|
Email: appeal.AssignedTo.Email,
|
|
FirstName: appeal.AssignedTo.FirstName,
|
|
LastName: appeal.AssignedTo.LastName,
|
|
}
|
|
}
|
|
|
|
return resp
|
|
}
|
|
|
|
// NewAppealHistoryResponse создает AppealHistoryResponse из модели
|
|
func NewAppealHistoryResponse(history *models.AppealHistory) AppealHistoryResponse {
|
|
resp := AppealHistoryResponse{
|
|
ID: history.ID,
|
|
AppealID: history.AppealID,
|
|
UserID: history.UserID,
|
|
OldStatus: string(history.OldStatus),
|
|
NewStatus: string(history.NewStatus),
|
|
Comment: history.Comment,
|
|
CreatedAt: history.CreatedAt,
|
|
}
|
|
|
|
if history.User != nil {
|
|
resp.User = &AuthorInfo{
|
|
ID: history.User.ID,
|
|
Email: history.User.Email,
|
|
FirstName: history.User.FirstName,
|
|
LastName: history.User.LastName,
|
|
}
|
|
}
|
|
|
|
return resp
|
|
} |