feat: 容器、数据库、网站、计划任务增加名称排序 (#1490)

This commit is contained in:
ssongliu 2023-06-29 18:40:12 +08:00 committed by GitHub
parent a1c76600e2
commit 38bf54ec3b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 115 additions and 38 deletions

View file

@ -2,7 +2,9 @@ package dto
type SearchWithPage struct { type SearchWithPage struct {
PageInfo PageInfo
Info string `json:"info"` Info string `json:"info"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
} }
type PageInfo struct { type PageInfo struct {

View file

@ -5,6 +5,8 @@ import "time"
type PageContainer struct { type PageContainer struct {
PageInfo PageInfo
Name string `json:"name"` Name string `json:"name"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
Filters string `json:"filters"` Filters string `json:"filters"`
} }

View file

@ -7,6 +7,8 @@ import (
type WebsiteSearch struct { type WebsiteSearch struct {
dto.PageInfo dto.PageInfo
Name string `json:"name"` Name string `json:"name"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
WebsiteGroupID uint `json:"websiteGroupId"` WebsiteGroupID uint `json:"websiteGroupId"`
} }

View file

@ -2,6 +2,7 @@ package repo
import ( import (
"context" "context"
"fmt"
"time" "time"
"github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/constant"
@ -16,6 +17,7 @@ type ICommonRepo interface {
WithByName(name string) DBOption WithByName(name string) DBOption
WithByType(tp string) DBOption WithByType(tp string) DBOption
WithOrderBy(orderStr string) DBOption WithOrderBy(orderStr string) DBOption
WithOrderRuleBy(orderBy, order string) DBOption
WithByGroupID(groupID uint) DBOption WithByGroupID(groupID uint) DBOption
WithLikeName(name string) DBOption WithLikeName(name string) DBOption
WithIdsIn(ids []uint) DBOption WithIdsIn(ids []uint) DBOption
@ -93,6 +95,21 @@ func (c *CommonRepo) WithOrderBy(orderStr string) DBOption {
} }
} }
func (c *CommonRepo) WithOrderRuleBy(orderBy, order string) DBOption {
switch order {
case constant.OrderDesc:
order = "desc"
case constant.OrderAsc:
order = "asc"
default:
orderBy = "created_at"
order = "desc"
}
return func(g *gorm.DB) *gorm.DB {
return g.Order(fmt.Sprintf("%s %s", orderBy, order))
}
}
func (c *CommonRepo) WithIdsIn(ids []uint) DBOption { func (c *CommonRepo) WithIdsIn(ids []uint) DBOption {
return func(g *gorm.DB) *gorm.DB { return func(g *gorm.DB) *gorm.DB {
return g.Where("id in (?)", ids) return g.Where("id in (?)", ids)

View file

@ -83,7 +83,7 @@ func (u *CronjobRepo) Page(page, size int, opts ...DBOption) (int64, []model.Cro
} }
count := int64(0) count := int64(0)
db = db.Count(&count) db = db.Count(&count)
err := db.Order("created_at desc").Limit(size).Offset(size * (page - 1)).Find(&cronjobs).Error err := db.Limit(size).Offset(size * (page - 1)).Find(&cronjobs).Error
return count, cronjobs, err return count, cronjobs, err
} }

View file

@ -67,9 +67,8 @@ func NewIContainerService() IContainerService {
func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, error) { func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, error) {
var ( var (
records []types.Container records []types.Container
list []types.Container list []types.Container
backDatas []dto.ContainerInfo
) )
client, err := docker.NewDockerClient() client, err := docker.NewDockerClient()
if err != nil { if err != nil {
@ -95,9 +94,30 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
} }
} }
} }
sort.Slice(list, func(i, j int) bool { switch req.OrderBy {
return list[i].Created > list[j].Created case "name":
}) sort.Slice(list, func(i, j int) bool {
if req.Order == constant.OrderAsc {
return list[i].Names[0][1:] < list[j].Names[0][1:]
}
return list[i].Names[0][1:] > list[j].Names[0][1:]
})
case "state":
sort.Slice(list, func(i, j int) bool {
if req.Order == constant.OrderAsc {
return list[i].State < list[j].State
}
return list[i].State > list[j].State
})
default:
sort.Slice(list, func(i, j int) bool {
if req.Order == constant.OrderAsc {
return list[i].Created < list[j].Created
}
return list[i].Created > list[j].Created
})
}
total, start, end := len(list), (req.Page-1)*req.PageSize, req.Page*req.PageSize total, start, end := len(list), (req.Page-1)*req.PageSize, req.Page*req.PageSize
if start > total { if start > total {
records = make([]types.Container, 0) records = make([]types.Container, 0)
@ -108,10 +128,11 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
records = list[start:end] records = list[start:end]
} }
backDatas := make([]dto.ContainerInfo, len(records))
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(len(records)) wg.Add(len(records))
for _, container := range records { for i := 0; i < len(records); i++ {
go func(item types.Container) { go func(item types.Container, i int) {
IsFromCompose := false IsFromCompose := false
if _, ok := item.Labels[composeProjectLabel]; ok { if _, ok := item.Labels[composeProjectLabel]; ok {
IsFromCompose = true IsFromCompose = true
@ -129,7 +150,7 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
ports = append(ports, fmt.Sprintf("%v:%v/%s", port.PublicPort, port.PrivatePort, port.Type)) ports = append(ports, fmt.Sprintf("%v:%v/%s", port.PublicPort, port.PrivatePort, port.Type))
} }
cpu, mem := loadCpuAndMem(client, item.ID) cpu, mem := loadCpuAndMem(client, item.ID)
backDatas = append(backDatas, dto.ContainerInfo{ backDatas[i] = dto.ContainerInfo{
ContainerID: item.ID, ContainerID: item.ID,
CreateTime: time.Unix(item.Created, 0).Format("2006-01-02 15:04:05"), CreateTime: time.Unix(item.Created, 0).Format("2006-01-02 15:04:05"),
Name: item.Names[0][1:], Name: item.Names[0][1:],
@ -142,9 +163,9 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
Ports: ports, Ports: ports,
IsFromApp: IsFromApp, IsFromApp: IsFromApp,
IsFromCompose: IsFromCompose, IsFromCompose: IsFromCompose,
}) }
wg.Done() wg.Done()
}(container) }(records[i], i)
} }
wg.Wait() wg.Wait()

View file

@ -36,7 +36,7 @@ func NewICronjobService() ICronjobService {
} }
func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) { func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) {
total, cronjobs, err := cronjobRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info)) total, cronjobs, err := cronjobRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info), commonRepo.WithOrderRuleBy(search.OrderBy, search.Order))
var dtoCronjobs []dto.CronjobInfo var dtoCronjobs []dto.CronjobInfo
for _, cronjob := range cronjobs { for _, cronjob := range cronjobs {
var item dto.CronjobInfo var item dto.CronjobInfo

View file

@ -48,7 +48,7 @@ func NewIMysqlService() IMysqlService {
} }
func (u *MysqlService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) { func (u *MysqlService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) {
total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info)) total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info), commonRepo.WithOrderRuleBy(search.OrderBy, search.Order))
var dtoMysqls []dto.MysqlDBInfo var dtoMysqls []dto.MysqlDBInfo
for _, mysql := range mysqls { for _, mysql := range mysqls {
var item dto.MysqlDBInfo var item dto.MysqlDBInfo

View file

@ -8,6 +8,14 @@ import (
"encoding/pem" "encoding/pem"
"errors" "errors"
"fmt" "fmt"
"os"
"path"
"reflect"
"regexp"
"strconv"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" "github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/utils/cmd" "github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common" "github.com/1Panel-dev/1Panel/backend/utils/common"
@ -18,13 +26,6 @@ import (
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
"gorm.io/gorm" "gorm.io/gorm"
"os"
"path"
"reflect"
"regexp"
"strconv"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto/request" "github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/dto/response" "github.com/1Panel-dev/1Panel/backend/app/dto/response"
@ -96,7 +97,7 @@ func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []respons
} }
return 0, nil, err return 0, nil, err
} }
opts = append(opts, commonRepo.WithOrderBy("created_at desc")) opts = append(opts, commonRepo.WithOrderRuleBy(req.OrderBy, req.Order))
if req.Name != "" { if req.Name != "" {
opts = append(opts, websiteRepo.WithDomainLike(req.Name)) opts = append(opts, websiteRepo.WithDomainLike(req.Name))
} }

View file

@ -10,4 +10,7 @@ const (
StatusEnable = "Enable" StatusEnable = "Enable"
StatusDisable = "Disable" StatusDisable = "Disable"
StatusNone = "None" StatusNone = "None"
OrderDesc = "descending"
OrderAsc = "ascending"
) )

View file

@ -9,6 +9,8 @@ export namespace Container {
export interface ContainerSearch extends ReqPage { export interface ContainerSearch extends ReqPage {
name: string; name: string;
filters: string; filters: string;
orderBy: string;
order: string;
} }
export interface ResourceLimit { export interface ResourceLimit {
cpu: number; cpu: number;

View file

@ -22,6 +22,8 @@ export interface SearchWithPage {
info: string; info: string;
page: number; page: number;
pageSize: number; pageSize: number;
orderBy?: string;
order?: string;
} }
export interface CommonModel { export interface CommonModel {
id: number; id: number;

View file

@ -39,6 +39,8 @@ export namespace Website {
export interface WebSiteSearch extends ReqPage { export interface WebSiteSearch extends ReqPage {
name: string; name: string;
orderBy: string;
order: string;
websiteGroupId: number; websiteGroupId: number;
} }

View file

@ -60,10 +60,11 @@
:pagination-config="paginationConfig" :pagination-config="paginationConfig"
v-model:selects="selects" v-model:selects="selects"
:data="data" :data="data"
@sort-change="search"
@search="search" @search="search"
> >
<el-table-column type="selection" fix /> <el-table-column type="selection" fix />
<el-table-column :label="$t('commons.table.name')" min-width="80" prop="name" fix> <el-table-column :label="$t('commons.table.name')" min-width="80" prop="name" sortable fix>
<template #default="{ row }"> <template #default="{ row }">
<Tooltip @click="onInspect(row.containerID)" :text="row.name" /> <Tooltip @click="onInspect(row.containerID)" :text="row.name" />
</template> </template>
@ -74,7 +75,7 @@
min-width="80" min-width="80"
prop="imageName" prop="imageName"
/> />
<el-table-column :label="$t('commons.table.status')" min-width="60" prop="state" fix> <el-table-column :label="$t('commons.table.status')" min-width="60" prop="state" sortable fix>
<template #default="{ row }"> <template #default="{ row }">
<Status :key="row.state" :status="row.state"></Status> <Status :key="row.state" :status="row.state"></Status>
</template> </template>
@ -225,13 +226,15 @@ const mydetail = ref();
const dialogContainerLogRef = ref(); const dialogContainerLogRef = ref();
const dialogReNameRef = ref(); const dialogReNameRef = ref();
const search = async () => { const search = async (column?: any) => {
let filterItem = props.filters ? props.filters : ''; let filterItem = props.filters ? props.filters : '';
let params = { let params = {
name: searchName.value, name: searchName.value,
page: paginationConfig.currentPage, page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize, pageSize: paginationConfig.pageSize,
filters: filterItem, filters: filterItem,
orderBy: column?.order ? column.prop : 'created_at',
order: column?.order ? column.order : 'null',
}; };
loading.value = true; loading.value = true;
await searchContainer(params) await searchContainer(params)

View file

@ -45,16 +45,17 @@
<ComplexTable <ComplexTable
:pagination-config="paginationConfig" :pagination-config="paginationConfig"
v-model:selects="selects" v-model:selects="selects"
@sort-change="search"
@search="search" @search="search"
:data="data" :data="data"
> >
<el-table-column type="selection" fix /> <el-table-column type="selection" fix />
<el-table-column :label="$t('cronjob.taskName')" :min-width="120" prop="name"> <el-table-column :label="$t('cronjob.taskName')" :min-width="120" prop="name" sortable>
<template #default="{ row }"> <template #default="{ row }">
<Tooltip @click="loadDetail(row)" :text="row.name" /> <Tooltip @click="loadDetail(row)" :text="row.name" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('commons.table.status')" :min-width="80" prop="status"> <el-table-column :label="$t('commons.table.status')" :min-width="80" prop="status" sortable>
<template #default="{ row }"> <template #default="{ row }">
<el-button <el-button
v-if="row.status === 'Enable'" v-if="row.status === 'Enable'"
@ -155,7 +156,7 @@
</el-dialog> </el-dialog>
<OperatrDialog @search="search" ref="dialogRef" /> <OperatrDialog @search="search" ref="dialogRef" />
<Records @search="search()" ref="dialogRecordRef" /> <Records @search="search" ref="dialogRecordRef" />
</div> </div>
</template> </template>
@ -199,11 +200,13 @@ const weekOptions = [
{ label: i18n.global.t('cronjob.sunday'), value: 7 }, { label: i18n.global.t('cronjob.sunday'), value: 7 },
]; ];
const search = async () => { const search = async (column?: any) => {
let params = { let params = {
info: searchName.value, info: searchName.value,
page: paginationConfig.currentPage, page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize, pageSize: paginationConfig.pageSize,
orderBy: column?.order ? column.prop : 'created_at',
order: column?.order ? column.order : 'null',
}; };
loading.value = true; loading.value = true;
await getCronjobPage(params) await getCronjobPage(params)

View file

@ -43,11 +43,12 @@
<template #main v-if="mysqlIsExist && !isOnSetting"> <template #main v-if="mysqlIsExist && !isOnSetting">
<ComplexTable <ComplexTable
:pagination-config="paginationConfig" :pagination-config="paginationConfig"
@sort-change="search"
@search="search" @search="search"
:data="data" :data="data"
:class="{ mask: mysqlStatus != 'Running' }" :class="{ mask: mysqlStatus != 'Running' }"
> >
<el-table-column :label="$t('commons.table.name')" prop="name" /> <el-table-column :label="$t('commons.table.name')" prop="name" sortable />
<el-table-column :label="$t('commons.login.username')" prop="username" /> <el-table-column :label="$t('commons.login.username')" prop="username" />
<el-table-column :label="$t('commons.login.password')" prop="password"> <el-table-column :label="$t('commons.login.password')" prop="password">
<template #default="{ row }"> <template #default="{ row }">
@ -239,11 +240,13 @@ const onSetting = async () => {
settingRef.value!.acceptParams(params); settingRef.value!.acceptParams(params);
}; };
const search = async () => { const search = async (column?: any) => {
let params = { let params = {
page: paginationConfig.currentPage, page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize, pageSize: paginationConfig.pageSize,
info: searchName.value, info: searchName.value,
orderBy: column?.order ? column.prop : 'created_at',
order: column?.order ? column.order : 'null',
}; };
const res = await searchMysqlDBs(params); const res = await searchMysqlDBs(params);
data.value = res.data.items || []; data.value = res.data.items || [];

View file

@ -64,19 +64,28 @@
<ComplexTable <ComplexTable
:pagination-config="paginationConfig" :pagination-config="paginationConfig"
:data="data" :data="data"
@sort-change="search"
@search="search()" @search="search()"
:class="{ mask: nginxStatus != 'Running' }" :class="{ mask: nginxStatus != 'Running' }"
> >
<el-table-column :label="$t('commons.table.name')" fix prop="primaryDomain" min-width="120px"> <el-table-column
:label="$t('commons.table.name')"
fix
prop="primaryDomain"
min-width="120px"
sortable
>
<template #default="{ row }"> <template #default="{ row }">
<Tooltip @click="openConfig(row.id)" :text="row.primaryDomain" /> <Tooltip @click="openConfig(row.id)" :text="row.primaryDomain" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('commons.table.type')" fix show-overflow-tooltip prop="type"> <el-table-column :label="$t('commons.table.type')" fix show-overflow-tooltip prop="type" sortable>
<template #default="{ row }"> <template #default="{ row }">
{{ $t('website.' + row.type) }} <div v-if="row.type">
<span v-if="row.type === 'deployment'">[{{ row.appName }}]</span> {{ $t('website.' + row.type) }}
<span v-if="row.type === 'runtime'">[{{ row.runtimeName }}]</span> <span v-if="row.type === 'deployment'">[{{ row.appName }}]</span>
<span v-if="row.type === 'runtime'">[{{ row.runtimeName }}]</span>
</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('website.sitePath')" prop="sitePath"> <el-table-column :label="$t('website.sitePath')" prop="sitePath">
@ -233,14 +242,19 @@ let req = reactive({
name: '', name: '',
page: 1, page: 1,
pageSize: 10, pageSize: 10,
orderBy: 'created_at',
order: 'null',
websiteGroupId: 0, websiteGroupId: 0,
}); });
const mobile = computed(() => { const mobile = computed(() => {
return globalStore.isMobile(); return globalStore.isMobile();
}); });
const search = async () => { const search = async (column?: any) => {
req.page = paginationConfig.currentPage; req.page = paginationConfig.currentPage;
req.pageSize = paginationConfig.pageSize; req.pageSize = paginationConfig.pageSize;
req.orderBy = column?.order ? column.prop : 'created_at';
req.orderBy = req.orderBy === 'primaryDomain' ? 'primary_domain' : req.orderBy;
req.order = column?.order ? column.order : 'null';
loading.value = true; loading.value = true;
await SearchWebsites(req) await SearchWebsites(req)
.then((res) => { .then((res) => {