Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/src/lang/modules/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2027,6 +2027,7 @@ const message = {
uninstallDeleteBackup: '卸载应用-删除备份',
uninstallDeleteImage: '卸载应用-删除镜像',
upgradeBackup: '应用升级前备份应用',
noAppHelper: '未检测到应用,请前往任务中心查看应用商店同步日志',
},
website: {
primaryDomain: '主域名',
Expand Down
149 changes: 149 additions & 0 deletions frontend/src/views/app-store/apps/app/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<template>
<div class="app">
<el-card>
<div class="app-wrapper" @click="openDetail(app.key)">
<div class="app-image">
<el-avatar shape="square" :size="60" :src="'data:image/png;base64,' + app.icon" />
</div>
<div class="app-content">
<div class="content-top">
<el-space wrap :size="1">
<span class="app-title">{{ app.name }}</span>
<el-tag type="success" v-if="app.installed" round size="small" class="!ml-2">
{{ $t('app.allReadyInstalled') }}
</el-tag>
</el-space>
</div>
<div class="content-middle">
<span class="app-description">
{{ app.description }}
</span>
</div>
<div class="content-bottom">
<div class="app-tags">
<el-tag v-for="(tag, ind) in app.tags" :key="ind" type="info">
<span>
{{ tag.name }}
</span>
</el-tag>
<el-tag v-if="app.status === 'TakeDown'" class="p-mr-5">
<span class="text-red-500">{{ $t('app.takeDown') }}</span>
</el-tag>
</div>
<el-button
type="primary"
size="small"
plain
round
:disabled="(app.installed && app.limit == 1) || app.status === 'TakeDown'"
@click.stop="openInstall(app)"
>
{{ $t('commons.button.install') }}
</el-button>
</div>
</div>
</div>
</el-card>
</div>
</template>

<script lang="ts" setup>
defineProps({
app: {
type: Object,
default: () => ({}),
},
});

const em = defineEmits(['openDetail', 'openInstall']);

const openDetail = (key: string) => {
em('openDetail', key);
};

const openInstall = (app: any) => {
em('openInstall', app);
};
</script>

<style lang="scss" scoped>
.app {
margin: 10px;
.el-card {
padding: 0 !important;
border: var(--panel-border) !important;
&:hover {
border: 1px solid var(--el-color-primary) !important;
}
}
.el-card__body {
padding: 8px 8px 2px 8px !important;
}
.app-wrapper {
display: flex;
height: 100%;
cursor: pointer;
}
.app-image {
flex: 0 0 100px;
display: flex;
justify-content: center;
margin-top: 14px;
transition: transform 0.1s;
}

&:hover .app-image {
transform: scale(1.2);
}

.el-avatar {
width: 65px !important;
height: 65px !important;
max-width: 65px;
max-height: 65px;
object-fit: cover;
}
.app-content {
flex: 1;
display: flex;
flex-direction: column;
padding: 10px;
}
.content-top,
.content-bottom {
display: flex;
justify-content: space-between;
align-items: center;
}
.content-middle {
flex: 1;
margin: 10px 0;
overflow: hidden; /* 防止内容溢出 */
}
.app-name {
margin: 0;
line-height: 1.5;
font-weight: 500;
font-size: 16px;
color: var(--el-text-color-regular);
}
.app-description {
margin: 0;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
font-size: 14px;
color: var(--el-text-color-regular);

line-height: 1.2;
height: calc(1.2em * 2);
min-height: calc(1.2em * 2);
}
.app-tags {
display: flex;
gap: 5px;
}
}
</style>
145 changes: 5 additions & 140 deletions frontend/src/views/app-store/apps/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<TableSearch @search="searchByName()" v-model:searchName="req.name" />
</template>
<template #main>
<div>
<div v-if="apps.length > 0">
<MainDiv :heightDiff="300">
<el-alert type="info" :title="$t('app.appHelper')" :closable="false" />
<el-row :gutter="5">
Expand All @@ -43,65 +43,7 @@
:lg="8"
:xl="6"
>
<div class="app">
<el-card>
<div class="app-wrapper" @click="openDetail(app.key)">
<div class="app-image">
<el-avatar
shape="square"
:size="60"
:src="'data:image/png;base64,' + app.icon"
/>
</div>
<div class="app-content">
<div class="content-top">
<el-space wrap :size="1">
<span class="app-title">{{ app.name }}</span>
<el-tag
type="success"
v-if="app.installed"
round
size="small"
class="!ml-2"
>
{{ $t('app.allReadyInstalled') }}
</el-tag>
</el-space>
</div>
<div class="content-middle">
<span class="app-description">
{{ app.description }}
</span>
</div>
<div class="content-bottom">
<div class="app-tags">
<el-tag v-for="(tag, ind) in app.tags" :key="ind" type="info">
<span>
{{ tag.name }}
</span>
</el-tag>
<el-tag v-if="app.status === 'TakeDown'" class="p-mr-5">
<span style="color: red">{{ $t('app.takeDown') }}</span>
</el-tag>
</div>
<el-button
type="primary"
size="small"
plain
round
:disabled="
(app.installed && app.limit == 1) ||
app.status === 'TakeDown'
"
@click.stop="openInstall(app)"
>
{{ $t('commons.button.install') }}
</el-button>
</div>
</div>
</div>
</el-card>
</div>
<AppCard :app="app" @open-install="openInstall" @open-detail="openDetail" />
</el-col>
</el-row>
</MainDiv>
Expand All @@ -116,6 +58,7 @@
/>
</div>
</div>
<NoApp v-if="apps.length == 0 && !loading" />
</template>
</LayoutContent>
</div>
Expand All @@ -139,6 +82,8 @@ import { storeToRefs } from 'pinia';
import bus from '@/global/bus';
import Tags from '@/views/app-store/components/tag.vue';
import DockerStatus from '@/views/container/docker-status/index.vue';
import NoApp from '@/views/app-store/apps/no-app/index.vue';
import AppCard from '@/views/app-store/apps/app/index.vue';
import { jumpToInstall } from '@/utils/app';

const globalStore = GlobalStore();
Expand Down Expand Up @@ -313,86 +258,6 @@ onMounted(async () => {
padding-bottom: 10px;
}

.app {
margin: 10px;
.el-card {
padding: 0 !important;
border: var(--panel-border) !important;
&:hover {
border: 1px solid var(--el-color-primary) !important;
}
}
.el-card__body {
padding: 8px 8px 2px 8px !important;
}
.app-wrapper {
display: flex;
height: 100%;
cursor: pointer;
}
.app-image {
flex: 0 0 100px;
display: flex;
justify-content: center;
margin-top: 14px;
transition: transform 0.1s;
}

&:hover .app-image {
transform: scale(1.2);
}

.el-avatar {
width: 65px !important;
height: 65px !important;
max-width: 65px;
max-height: 65px;
object-fit: cover;
}
.app-content {
flex: 1;
display: flex;
flex-direction: column;
padding: 10px;
}
.content-top,
.content-bottom {
display: flex;
justify-content: space-between;
align-items: center;
}
.content-middle {
flex: 1;
margin: 10px 0;
overflow: hidden; /* 防止内容溢出 */
}
.app-name {
margin: 0;
line-height: 1.5;
font-weight: 500;
font-size: 16px;
color: var(--el-text-color-regular);
}
.app-description {
margin: 0;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
font-size: 14px;
color: var(--el-text-color-regular);

line-height: 1.2;
height: calc(1.2em * 2);
min-height: calc(1.2em * 2);
}
.app-tags {
display: flex;
gap: 5px;
}
}

.tag-button {
margin-right: 10px;
&.no-active {
Expand Down
23 changes: 23 additions & 0 deletions frontend/src/views/app-store/apps/no-app/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<div class="app-warn">
<div class="flex flex-col gap-2 items-center justify-center w-full sm:flex-row">
<span>{{ $t('app.noAppHelper') }}</span>
<span class="flex items-center justify-center gap-0.5" @click="openTask">
<el-icon><Position /></el-icon>
{{ $t('website.check') }}
</span>
</div>
<div>
<img src="@/assets/images/no_app.svg" />
</div>
</div>
<TaskList ref="taskListRef" />
</template>

<script lang="ts" setup>
import TaskList from '@/components/task-list/index.vue';
const taskListRef = ref();
const openTask = () => {
taskListRef.value.acceptParams();
};
</script>
Loading