modificaciones de mejora
This commit is contained in:
+29
-6
@@ -26,25 +26,48 @@ func (OssApi) TableName() string {
|
|||||||
return "oss_api"
|
return "oss_api"
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllQrVcard obtiene todos los registros de QrVcard con paginación y búsqueda
|
// GetAllOssApi obtiene todos los registros de OssApi con paginación, búsqueda, filtros y orden
|
||||||
func GetAllOssApi(limit, offset int, search string) ([]OssApi, int64, error) {
|
func GetAllOssApi(limit, offset int, search, provider, estado, sortBy, sortDir, dateFrom, dateTo string) ([]OssApi, int64, error) {
|
||||||
var items []OssApi
|
var items []OssApi
|
||||||
var total int64
|
var total int64
|
||||||
db := app.Http.Database.DB.Model(&OssApi{})
|
db := app.Http.Database.DB.Model(&OssApi{})
|
||||||
|
|
||||||
// Si se pasa un término de búsqueda, lo aplicamos en la consulta
|
|
||||||
if search != "" {
|
if search != "" {
|
||||||
db = db.Where("name LIKE ?", "%"+search+"%")
|
db = db.Where("name LIKE ?", "%"+search+"%")
|
||||||
}
|
}
|
||||||
|
if provider != "" {
|
||||||
|
db = db.Where("provider = ?", provider)
|
||||||
|
}
|
||||||
|
if estado == "activo" {
|
||||||
|
db = db.Where("is_active = ?", true)
|
||||||
|
} else if estado == "inactivo" {
|
||||||
|
db = db.Where("is_active = ?", false)
|
||||||
|
}
|
||||||
|
if dateFrom != "" {
|
||||||
|
db = db.Where("created_at >= ?", dateFrom)
|
||||||
|
}
|
||||||
|
if dateTo != "" {
|
||||||
|
db = db.Where("created_at <= ?", dateTo+" 23:59:59")
|
||||||
|
}
|
||||||
|
|
||||||
// Contamos el total de registros
|
|
||||||
if err := db.Count(&total).Error; err != nil {
|
if err := db.Count(&total).Error; err != nil {
|
||||||
log.Printf("Error counting OssApi: %v", err)
|
log.Printf("Error counting OssApi: %v", err)
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtenemos los registros con paginación
|
allowedSorts := map[string]bool{
|
||||||
if err := db.Order("id DESC").Limit(limit).Offset(offset).Find(&items).Error; err != nil {
|
"id": true, "name": true, "provider": true,
|
||||||
|
"endpoint": true, "bucket_name": true, "region": true,
|
||||||
|
"is_active": true, "created_at": true,
|
||||||
|
}
|
||||||
|
if !allowedSorts[sortBy] {
|
||||||
|
sortBy = "id"
|
||||||
|
}
|
||||||
|
if sortDir != "asc" {
|
||||||
|
sortDir = "desc"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Order(sortBy+" "+sortDir).Limit(limit).Offset(offset).Find(&items).Error; err != nil {
|
||||||
log.Printf("Error retrieving OssApi: %v", err)
|
log.Printf("Error retrieving OssApi: %v", err)
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,12 +56,28 @@
|
|||||||
<!-- Alerta de error -->
|
<!-- Alerta de error -->
|
||||||
<div x-show="errorMsg" class="mb-4 p-3 bg-red-50 border border-red-200 rounded-lg text-sm text-red-700" x-text="errorMsg"></div>
|
<div x-show="errorMsg" class="mb-4 p-3 bg-red-50 border border-red-200 rounded-lg text-sm text-red-700" x-text="errorMsg"></div>
|
||||||
|
|
||||||
<!-- Barra de búsqueda (solo tab config) -->
|
<!-- Filtros (solo tab config) -->
|
||||||
<div x-show="activeTab === 'config'" class="flex flex-col sm:flex-row gap-3 mb-5">
|
<div x-show="activeTab === 'config'" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-6 gap-3 mb-5">
|
||||||
<input x-model="search" @keyup.enter="load()" type="text" placeholder="Buscar por nombre..."
|
<input x-model="search" @keyup.enter="load()" type="text" placeholder="Buscar por nombre..."
|
||||||
class="border border-gray-300 rounded-lg px-3 py-2 text-sm flex-1 focus:outline-none focus:ring-1 focus:ring-[#8eb02f]" />
|
class="border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-[#8eb02f]" />
|
||||||
|
<select x-model="filtroProvider" @change="load()"
|
||||||
|
class="border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-[#8eb02f]">
|
||||||
|
<option value="">Todos los proveedores</option>
|
||||||
|
<option value="s3">S3 / MinIO</option>
|
||||||
|
<option value="alibaba">Alibaba Cloud</option>
|
||||||
|
</select>
|
||||||
|
<select x-model="filtroEstado" @change="load()"
|
||||||
|
class="border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-[#8eb02f]">
|
||||||
|
<option value="">Todos los estados</option>
|
||||||
|
<option value="activo">Activo</option>
|
||||||
|
<option value="inactivo">Inactivo</option>
|
||||||
|
</select>
|
||||||
|
<input x-model="dateFrom" @change="load()" type="date"
|
||||||
|
class="border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-[#8eb02f]" />
|
||||||
|
<input x-model="dateTo" @change="load()" type="date"
|
||||||
|
class="border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-[#8eb02f]" />
|
||||||
<button @click="load()" :disabled="loading"
|
<button @click="load()" :disabled="loading"
|
||||||
class="flex items-center gap-2 px-4 py-2 rounded-lg border border-gray-300 text-sm hover:bg-gray-50 transition disabled:opacity-40">
|
class="flex items-center justify-center gap-2 px-4 py-2 rounded-lg border border-gray-300 text-sm hover:bg-gray-50 transition disabled:opacity-40">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" :class="loading && 'animate-spin'" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" :class="loading && 'animate-spin'" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"/>
|
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"/>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -74,12 +90,24 @@
|
|||||||
<table class="table-auto w-full text-sm">
|
<table class="table-auto w-full text-sm">
|
||||||
<thead class="border-b border-gray-200 text-left text-xs font-semibold text-gray-500 uppercase">
|
<thead class="border-b border-gray-200 text-left text-xs font-semibold text-gray-500 uppercase">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="py-2 px-3">Nombre</th>
|
<th class="py-2 px-3 cursor-pointer select-none hover:text-gray-700" @click="sort('name')">
|
||||||
<th class="py-2 px-3">Proveedor</th>
|
<span class="inline-flex items-center gap-1">Nombre <template x-if="sortBy === 'name'"><span x-text="sortDir === 'asc' ? '↑' : '↓'"></span></template></span>
|
||||||
<th class="py-2 px-3">Endpoint</th>
|
</th>
|
||||||
<th class="py-2 px-3">Bucket</th>
|
<th class="py-2 px-3 cursor-pointer select-none hover:text-gray-700" @click="sort('provider')">
|
||||||
<th class="py-2 px-3">Región</th>
|
<span class="inline-flex items-center gap-1">Proveedor <template x-if="sortBy === 'provider'"><span x-text="sortDir === 'asc' ? '↑' : '↓'"></span></template></span>
|
||||||
<th class="py-2 px-3">Estado</th>
|
</th>
|
||||||
|
<th class="py-2 px-3 cursor-pointer select-none hover:text-gray-700" @click="sort('endpoint')">
|
||||||
|
<span class="inline-flex items-center gap-1">Endpoint <template x-if="sortBy === 'endpoint'"><span x-text="sortDir === 'asc' ? '↑' : '↓'"></span></template></span>
|
||||||
|
</th>
|
||||||
|
<th class="py-2 px-3 cursor-pointer select-none hover:text-gray-700" @click="sort('bucket_name')">
|
||||||
|
<span class="inline-flex items-center gap-1">Bucket <template x-if="sortBy === 'bucket_name'"><span x-text="sortDir === 'asc' ? '↑' : '↓'"></span></template></span>
|
||||||
|
</th>
|
||||||
|
<th class="py-2 px-3 cursor-pointer select-none hover:text-gray-700" @click="sort('region')">
|
||||||
|
<span class="inline-flex items-center gap-1">Región <template x-if="sortBy === 'region'"><span x-text="sortDir === 'asc' ? '↑' : '↓'"></span></template></span>
|
||||||
|
</th>
|
||||||
|
<th class="py-2 px-3 cursor-pointer select-none hover:text-gray-700" @click="sort('is_active')">
|
||||||
|
<span class="inline-flex items-center gap-1">Estado <template x-if="sortBy === 'is_active'"><span x-text="sortDir === 'asc' ? '↑' : '↓'"></span></template></span>
|
||||||
|
</th>
|
||||||
<th class="py-2 px-3 text-right">Acciones</th>
|
<th class="py-2 px-3 text-right">Acciones</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -374,6 +402,12 @@ function ossApiApp() {
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
page: 1,
|
page: 1,
|
||||||
search: '',
|
search: '',
|
||||||
|
filtroProvider: '',
|
||||||
|
filtroEstado: '',
|
||||||
|
dateFrom: '',
|
||||||
|
dateTo: '',
|
||||||
|
sortBy: 'id',
|
||||||
|
sortDir: 'desc',
|
||||||
loading: false,
|
loading: false,
|
||||||
errorMsg: '',
|
errorMsg: '',
|
||||||
showModal: false,
|
showModal: false,
|
||||||
@@ -406,7 +440,16 @@ function ossApiApp() {
|
|||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.errorMsg = '';
|
this.errorMsg = '';
|
||||||
try {
|
try {
|
||||||
const params = new URLSearchParams({ page: this.page, search: this.search });
|
const params = new URLSearchParams({
|
||||||
|
page: this.page,
|
||||||
|
search: this.search,
|
||||||
|
provider: this.filtroProvider,
|
||||||
|
estado: this.filtroEstado,
|
||||||
|
date_from: this.dateFrom,
|
||||||
|
date_to: this.dateTo,
|
||||||
|
sort_by: this.sortBy,
|
||||||
|
sort_dir: this.sortDir,
|
||||||
|
});
|
||||||
const res = await fetch(`/app/loadossapi?${params}`);
|
const res = await fetch(`/app/loadossapi?${params}`);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (!res.ok) throw new Error(data.error || 'Error al cargar');
|
if (!res.ok) throw new Error(data.error || 'Error al cargar');
|
||||||
@@ -420,6 +463,17 @@ function ossApiApp() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
sort(col) {
|
||||||
|
if (this.sortBy === col) {
|
||||||
|
this.sortDir = this.sortDir === 'asc' ? 'desc' : 'asc';
|
||||||
|
} else {
|
||||||
|
this.sortBy = col;
|
||||||
|
this.sortDir = 'asc';
|
||||||
|
}
|
||||||
|
this.page = 1;
|
||||||
|
this.load();
|
||||||
|
},
|
||||||
|
|
||||||
openAdd() {
|
openAdd() {
|
||||||
this.editItem = null;
|
this.editItem = null;
|
||||||
this.form = { name: '', provider: 'alibaba', endpoint: '', access_key_id: '', access_key_secret: '', bucket_name: '', region: '', is_active: true, notes: '' };
|
this.form = { name: '', provider: 'alibaba', endpoint: '', access_key_id: '', access_key_secret: '', bucket_name: '', region: '', is_active: true, notes: '' };
|
||||||
|
|||||||
@@ -44,9 +44,17 @@ func GetOssApiConfigs(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
limit := 20
|
limit := 20
|
||||||
offset := (page - 1) * limit
|
offset := (page - 1) * limit
|
||||||
search := c.Query("search", "")
|
|
||||||
|
|
||||||
items, total, err := models.GetAllOssApi(limit, offset, search)
|
items, total, err := models.GetAllOssApi(
|
||||||
|
limit, offset,
|
||||||
|
c.Query("search", ""),
|
||||||
|
c.Query("provider", ""),
|
||||||
|
c.Query("estado", ""),
|
||||||
|
c.Query("sort_by", "id"),
|
||||||
|
c.Query("sort_dir", "desc"),
|
||||||
|
c.Query("date_from", ""),
|
||||||
|
c.Query("date_to", ""),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user