fix(website): Add pinning feature for websites. (#8462)

This commit is contained in:
ChengPlay 2025-04-23 15:44:59 +08:00 committed by GitHub
parent 86cef9803c
commit 9d48e591af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 131 additions and 35 deletions

View file

@ -7,7 +7,7 @@ import (
type WebsiteSearch struct {
dto.PageInfo
Name string `json:"name"`
OrderBy string `json:"orderBy" validate:"required,oneof=primary_domain type status createdAt expire_date created_at"`
OrderBy string `json:"orderBy" validate:"required,oneof=primary_domain type status createdAt expire_date created_at favorite"`
Order string `json:"order" validate:"required,oneof=null ascending descending"`
WebsiteGroupID uint `json:"websiteGroupId"`
Type string `json:"type"`
@ -85,6 +85,7 @@ type WebsiteUpdate struct {
WebsiteGroupID uint `json:"webSiteGroupID"`
ExpireDate string `json:"expireDate"`
IPV6 bool `json:"IPV6"`
Favorite bool `json:"favorite"`
}
type WebsiteDelete struct {

View file

@ -35,6 +35,7 @@ type WebsiteRes struct {
AppInstallID uint `json:"appInstallId"`
ChildSites []string `json:"childSites"`
RuntimeType string `json:"runtimeType"`
Favorite bool `json:"favorite"`
}
type WebsiteOption struct {

View file

@ -35,6 +35,8 @@ type Website struct {
DbType string `json:"dbType"`
DbID uint `json:"dbID"`
Favorite bool `json:"favorite"`
Domains []WebsiteDomain `json:"domains" gorm:"-:migration"`
WebsiteSSL WebsiteSSL `json:"webSiteSSL" gorm:"-:migration"`
}

View file

@ -198,6 +198,7 @@ func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []respons
SitePath: sitePath,
AppInstallID: appInstallID,
RuntimeType: runtimeType,
Favorite: web.Favorite,
}
sites, _ := websiteRepo.List(websiteRepo.WithParentID(web.ID))
@ -529,6 +530,7 @@ func (w WebsiteService) UpdateWebsite(req request.WebsiteUpdate) error {
website.WebsiteGroupID = req.WebsiteGroupID
website.Remark = req.Remark
website.IPV6 = req.IPV6
website.Favorite = req.Favorite
if req.ExpireDate != "" {
expireDate, err := time.Parse(constant.DateLayout, req.ExpireDate)

View file

@ -31,6 +31,7 @@ func InitAgentDB() {
migrations.AddLocalSSHSetting,
migrations.AddAppIgnore,
migrations.UpdateWebsiteSSL,
migrations.UpdateWebsite,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)

View file

@ -342,3 +342,13 @@ var UpdateWebsiteSSL = &gormigrate.Migration{
return nil
},
}
var UpdateWebsite = &gormigrate.Migration{
ID: "20250424-update-website",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Website{}); err != nil {
return err
}
return nil
},
}

View file

@ -26,6 +26,7 @@ export namespace Website {
childSites?: string[];
dbID: number;
dbType: string;
favorite: boolean;
}
export interface WebsiteDTO extends Website {
@ -100,6 +101,7 @@ export namespace Website {
webSiteGroupId: number;
expireDate?: string;
IPV6: boolean;
favorite: boolean;
}
export interface WebSiteOp {

View file

@ -2420,6 +2420,8 @@ const message = {
cacheWarn: 'Please turn off the cache switch in the reverse proxy first',
loadBalanceHelper:
'This section only creates load balancing rules, to use the rules please reverse proxy http(s)://<load balance name>',
favorite: 'Favorite',
cancelFavorite: 'Cancel Favorite',
},
php: {
short_open_tag: 'Short tag support',

View file

@ -2327,6 +2327,8 @@ const message = {
cacheWarn: 'まずリバースプロキシのキャッシュスイッチをオフにしてください',
loadBalanceHelper:
'This section only creates load balancing rules, to use the rules please reverse proxy http(s)://<load balance name>',
favorite: 'お気に入り',
cancelFavorite: 'お気に入りを解除',
},
php: {
short_open_tag: '短いタグサポート',

View file

@ -2288,6 +2288,8 @@ const message = {
cacheWarn: '먼저 리버스 프록시의 캐시 스위치를 끄십시오',
loadBalanceHelper:
'여기서는 로드 밸런싱 규칙만 생성합니다. 규칙을 사용하려면 리버스 프록시 http(s)://<로드 밸런스 이름>을 사용하십시오',
favorite: '즐겨찾기',
cancelFavorite: '즐겨찾기 취소',
},
php: {
short_open_tag: '짧은 태그 지원',

View file

@ -2381,6 +2381,8 @@ const message = {
cacheWarn: 'Sila matikan suis cache dalam pembalikan proksi terlebih dahulu',
loadBalanceHelper:
'Di sini hanya mencipta peraturan keseimbangan beban, untuk menggunakan peraturan sila proksi terbalik http(s)://<nama keseimbangan beban>',
favorite: 'Kegemaran',
cancelFavorite: 'Batalkan Kegemaran',
},
php: {
short_open_tag: 'Sokongan tag pendek',

View file

@ -2377,6 +2377,8 @@ const message = {
cacheWarn: 'Por favor, desligue o interruptor de cache no proxy reverso primeiro',
loadBalanceHelper:
'Esta seção apenas cria regras de balanceamento de carga, para usar as regras, por favor, proxy reverso http(s)://<nome do balanceamento de carga>',
favorite: 'Favorito',
cancelFavorite: 'Cancelar Favorito',
},
php: {
short_open_tag: 'Suporte para short tags',

View file

@ -2378,6 +2378,8 @@ const message = {
cacheWarn: 'Пожалуйста, сначала выключите кэш в обратном прокси',
loadBalanceHelper:
'Здесь создаются только правила балансировки нагрузки, чтобы использовать правила, пожалуйста, используйте обратный прокси http(s)://<имя балансировки нагрузки>',
favorite: 'Избранное',
cancelFavorite: 'Отменить избранное',
},
php: {
short_open_tag: 'Поддержка коротких тегов',

View file

@ -2245,6 +2245,8 @@ const message = {
runtimePortWarn: '當前運行環境沒有端口無法代理',
cacheWarn: '請先關閉反代中的緩存開關',
loadBalanceHelper: '此處只是創建負載均衡規則使用規則請反向代理 http(s)://<負載均衡名稱>',
favorite: '收藏',
cancelFavorite: '取消收藏',
},
php: {
short_open_tag: '短標簽支持',

View file

@ -2235,6 +2235,8 @@ const message = {
runtimePortWarn: '当前运行环境没有端口无法代理',
cacheWarn: '请先关闭反代中的缓存开关',
loadBalanceHelper: '此处只是创建负载均衡规则使用规则请反向代理 http://<负载均衡名称>',
favorite: '收藏',
cancelFavorite: '取消收藏',
},
php: {
short_open_tag: '短标签支持',

View file

@ -90,7 +90,9 @@
sortable
show-overflow-tooltip
>
<template #default="{ row }">
<template #default="{ row, $index }">
<div class="name-row" @mouseenter="showFavorite($index)" @mouseleave="hideFavorite">
<div>
<el-text type="primary" class="cursor-pointer" @click="openConfig(row.id)">
{{ row.primaryDomain }}
</el-text>
@ -107,7 +109,11 @@
<tbody>
<tr v-for="(domain, index) in domains" :key="index">
<td>
<el-button type="primary" link @click="openUrl(getUrl(domain, row))">
<el-button
type="primary"
link
@click="openUrl(getUrl(domain, row))"
>
{{ getUrl(domain, row) }}
</el-button>
</td>
@ -118,6 +124,37 @@
</tbody>
</table>
</el-popover>
</div>
<div>
<el-tooltip
effect="dark"
:content="$t('website.cancelFavorite')"
placement="top-start"
v-if="row.favorite"
>
<el-button
link
icon="Star"
type="warning"
@click="favoriteWebsite(row)"
></el-button>
</el-tooltip>
<el-tooltip
effect="dark"
:content="$t('website.favorite')"
placement="top-start"
v-if="!row.favorite && hoveredRowIndex === $index"
>
<el-button
link
icon="Star"
type="info"
@click="favoriteWebsite(row)"
></el-button>
</el-tooltip>
</div>
</div>
</template>
</el-table-column>
<el-table-column
@ -222,8 +259,8 @@
</template>
</el-table-column>
<fu-table-operations
:ellipsis="10"
width="300px"
:ellipsis="1"
width="150px"
:buttons="buttons"
:label="$t('commons.table.operate')"
:fixed="mobile ? false : 'right'"
@ -314,6 +351,7 @@ let groups = ref<Group.GroupInfo[]>([]);
const dataRef = ref();
const domains = ref<Website.Domain[]>([]);
const columns = ref([]);
const hoveredRowIndex = ref(-1);
const paginationConfig = reactive({
cacheSizeKey: 'website-page-size',
@ -325,8 +363,8 @@ let req = reactive({
name: '',
page: 1,
pageSize: 10,
orderBy: 'createdAt',
order: 'null',
orderBy: 'favorite',
order: 'descending',
websiteGroupId: 0,
type: '',
});
@ -338,6 +376,19 @@ const goRouter = async (key: string) => {
router.push({ name: 'AppAll', query: { install: key } });
};
const showFavorite = (index: any) => {
hoveredRowIndex.value = index;
};
const hideFavorite = () => {
hoveredRowIndex.value = -1;
};
const favoriteWebsite = (row: Website.Website) => {
row.favorite = !row.favorite;
updateWebsitConfig(row);
};
const changeSort = ({ prop, order }) => {
if (order) {
switch (prop) {
@ -353,8 +404,8 @@ const changeSort = ({ prop, order }) => {
req.orderBy = prop;
req.order = order;
} else {
req.orderBy = 'created_at';
req.order = 'null';
req.orderBy = 'favorite';
req.order = 'descending';
}
search();
};
@ -460,6 +511,7 @@ const updateWebsitConfig = (row: any) => {
webSiteGroupId: row.webSiteGroupId,
expireDate: reqDate,
IPV6: row.IPV6,
favorite: row.favorite,
};
updateWebsite(req).then(() => {
@ -588,3 +640,12 @@ onMounted(() => {
listGroup();
});
</script>
<style lang="css" scoped>
.name-row {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}
</style>