1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-31 22:18:07 +08:00

feat: 修改应用商店 应用列表

This commit is contained in:
zhengkunwang223 2023-01-12 15:12:01 +08:00 committed by zhengkunwang223
parent 3dda250b4d
commit 2ed62864b8
7 changed files with 202 additions and 172 deletions

View File

@ -3,79 +3,81 @@
// Read more: https://github.com/vuejs/vue-next/pull/3399 // Read more: https://github.com/vuejs/vue-next/pull/3399
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
403: typeof import('./src/components/error-message/403.vue')['default']; 403: typeof import('./src/components/error-message/403.vue')['default']
404: typeof import('./src/components/error-message/404.vue')['default']; 404: typeof import('./src/components/error-message/404.vue')['default']
500: typeof import('./src/components/error-message/500.vue')['default']; 500: typeof import('./src/components/error-message/500.vue')['default']
AppLayout: typeof import('./src/components/app-layout/index.vue')['default']; AppLayout: typeof import('./src/components/app-layout/index.vue')['default']
AppStatus: typeof import('./src/components/app-status/index.vue')['default']; AppStatus: typeof import('./src/components/app-status/index.vue')['default']
BackButton: typeof import('./src/components/back-button/index.vue')['default']; BackButton: typeof import('./src/components/back-button/index.vue')['default']
BreadCrumbs: typeof import('./src/components/bread-crumbs/index.vue')['default']; BreadCrumbs: typeof import('./src/components/bread-crumbs/index.vue')['default']
BreadCrumbsItem: typeof import('./src/components/bread-crumbs/bread-crumbs-item.vue')['default']; BreadCrumbsItem: typeof import('./src/components/bread-crumbs/bread-crumbs-item.vue')['default']
Codemirror: typeof import('./src/components/codemirror-dialog/codemirror.vue')['default']; Codemirror: typeof import('./src/components/codemirror-dialog/codemirror.vue')['default']
ComplexTable: typeof import('./src/components/complex-table/index.vue')['default']; ComplexTable: typeof import('./src/components/complex-table/index.vue')['default']
ConfirmDialog: typeof import('./src/components/confirm-dialog/index.vue')['default']; ConfirmDialog: typeof import('./src/components/confirm-dialog/index.vue')['default']
ContainerLog: typeof import('./src/components/container-log/index.vue')['default']; ContainerLog: typeof import('./src/components/container-log/index.vue')['default']
DrawerHeader: typeof import('./src/components/drawer-header/index.vue')['default']; DrawerHeader: typeof import('./src/components/drawer-header/index.vue')['default']
ElAlert: typeof import('element-plus/es')['ElAlert']; ElAlert: typeof import('element-plus/es')['ElAlert']
ElAside: typeof import('element-plus/es')['ElAside']; ElAside: typeof import('element-plus/es')['ElAside']
ElButton: typeof import('element-plus/es')['ElButton']; ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']; ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']; ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup'];
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']; ElCard: typeof import('element-plus/es')['ElCard']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']; ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCol: typeof import('element-plus/es')['ElCol']; ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElCollapse: typeof import('element-plus/es')['ElCollapse']; ElCol: typeof import('element-plus/es')['ElCol']
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']; ElCollapse: typeof import('element-plus/es')['ElCollapse']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']; ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
ElContainer: typeof import('element-plus/es')['ElContainer']; ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']; ElContainer: typeof import('element-plus/es')['ElContainer']
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']; ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']; ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
ElDialog: typeof import('element-plus/es')['ElDialog']; ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
ElDivider: typeof import('element-plus/es')['ElDivider']; ElDialog: typeof import('element-plus/es')['ElDialog']
ElDrawer: typeof import('element-plus/es')['ElDrawer']; ElDivider: typeof import('element-plus/es')['ElDivider']
ElFooter: typeof import('element-plus/es')['ElFooter']; ElDraw: typeof import('element-plus/es')['ElDraw']
ElForm: typeof import('element-plus/es')['ElForm']; ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElFormItem: typeof import('element-plus/es')['ElFormItem']; ElFooter: typeof import('element-plus/es')['ElFooter']
ElHeader: typeof import('element-plus/es')['ElHeader']; ElForm: typeof import('element-plus/es')['ElForm']
ElIcon: typeof import('element-plus/es')['ElIcon']; ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElImage: typeof import('element-plus/es')['ElImage']; ElHeader: typeof import('element-plus/es')['ElHeader']
ElInput: typeof import('element-plus/es')['ElInput']; ElIcon: typeof import('element-plus/es')['ElIcon']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']; ElImage: typeof import('element-plus/es')['ElImage']
ElLink: typeof import('element-plus/es')['ElLink']; ElInput: typeof import('element-plus/es')['ElInput']
ElMain: typeof import('element-plus/es')['ElMain']; ElInputNumber: typeof import('element-plus/es')['ElInputNumber'];
ElMenu: typeof import('element-plus/es')['ElMenu']; ElLink: typeof import('element-plus/es')['ElLink']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']; ElMain: typeof import('element-plus/es')['ElMain']
ElOption: typeof import('element-plus/es')['ElOption']; ElMenu: typeof import('element-plus/es')['ElMenu']
ElPageHeader: typeof import('element-plus/es')['ElPageHeader']; ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElPopover: typeof import('element-plus/es')['ElPopover']; ElOption: typeof import('element-plus/es')['ElOption']
ElProgress: typeof import('element-plus/es')['ElProgress']; ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
ElRadio: typeof import('element-plus/es')['ElRadio']; ElPopover: typeof import('element-plus/es')['ElPopover']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']; ElProgress: typeof import('element-plus/es')['ElProgress']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']; ElRadio: typeof import('element-plus/es')['ElRadio']
ElRow: typeof import('element-plus/es')['ElRow']; ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']; ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElSelect: typeof import('element-plus/es')['ElSelect']; ElRow: typeof import('element-plus/es')['ElRow']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']; ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSwitch: typeof import('element-plus/es')['ElSwitch']; ElSelect: typeof import('element-plus/es')['ElSelect']
ElTable: typeof import('element-plus/es')['ElTable']; ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']; ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTabPane: typeof import('element-plus/es')['ElTabPane']; ElTable: typeof import('element-plus/es')['ElTable']
ElTabs: typeof import('element-plus/es')['ElTabs']; ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTag: typeof import('element-plus/es')['ElTag']; ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElUpload: typeof import('element-plus/es')['ElUpload']; ElTabs: typeof import('element-plus/es')['ElTabs']
FileList: typeof import('./src/components/file-list/index.vue')['default']; ElTag: typeof import('element-plus/es')['ElTag']
FileRole: typeof import('./src/components/file-role/index.vue')['default']; ElUpload: typeof import('element-plus/es')['ElUpload']
Footer: typeof import('./src/components/app-layout/footer/index.vue')['default']; FileList: typeof import('./src/components/file-list/index.vue')['default']
Loading: typeof import('element-plus/es')['ElLoadingDirective']; FileRole: typeof import('./src/components/file-role/index.vue')['default']
Logo: typeof import('./src/components/app-layout/menu/components/Logo.vue')['default']; Footer: typeof import('./src/components/app-layout/footer/index.vue')['default']
Menu: typeof import('./src/components/app-layout/menu/index.vue')['default']; Loading: typeof import('element-plus/es')['ElLoadingDirective']
RouterButton: typeof import('./src/components/router-button/index.vue')['default']; Logo: typeof import('./src/components/app-layout/menu/components/Logo.vue')['default']
Status: typeof import('./src/components/status/index.vue')['default']; Menu: typeof import('./src/components/app-layout/menu/index.vue')['default']
SubItem: typeof import('./src/components/app-layout/menu/components/sub-item.vue')['default']; RouterButton: typeof import('./src/components/router-button/index.vue')['default']
SvgIcon: typeof import('./src/components/svg-icon/svg-icon.vue')['default']; Status: typeof import('./src/components/status/index.vue')['default']
} SubItem: typeof import('./src/components/app-layout/menu/components/sub-item.vue')['default']
SvgIcon: typeof import('./src/components/svg-icon/svg-icon.vue')['default']
}
} }
export {}; export { }

View File

@ -854,6 +854,7 @@ export default {
noService: '{0}', noService: '{0}',
toInstall: '去安装', toInstall: '去安装',
param: '参数配置', param: '参数配置',
syncAppList: '更新应用列表',
}, },
website: { website: {
website: '网站', website: '网站',

View File

@ -35,8 +35,13 @@
<span v-else> <span v-else>
{{ title }} {{ title }}
<el-divider v-if="slots.buttons" direction="vertical" /> <span v-if="slots.buttons">
<slot v-if="slots.buttons" name="buttons"></slot> <el-divider direction="vertical" />
<slot name="buttons"></slot>
</span>
<span style="float: right">
<slot v-if="slots.rightButton" name="rightButton"></slot>
</span>
</span> </span>
</slot> </slot>
</div> </div>

View File

@ -1,89 +1,84 @@
<template> <template>
<div> <LayoutContent v-loading="loading" v-if="!showDetail" :title="$t('website.website')">
<el-card v-loading="loading" v-if="!showDetail"> <template #toolbar>
<el-row :gutter="5"> <el-row :gutter="5">
<el-col :span="2"> <el-col :span="20">
<el-button @click="sync" type="primary" :plain="true">{{ $t('app.sync') }}</el-button> <div>
<el-button @click="changeTag('all')" type="primary" :plain="activeTag !== 'all'">
{{ $t('app.all') }}
</el-button>
<div v-for="item in tags" :key="item.key" style="display: inline">
<el-button
class="tag-button"
@click="changeTag(item.key)"
type="primary"
:plain="activeTag !== item.key"
>
{{ item.name }}
</el-button>
</div>
</div>
</el-col> </el-col>
<el-col :span="22"> <el-col :span="4">
<div style="float: right"> <div style="float: right">
<el-input <el-input
style="display: inline; margin-right: 5px" class="table-button"
v-model="req.name" v-model="req.name"
clearable clearable
@clear="searchByName('')" @clear="searchByName('')"
suffix-icon="Search"
@keyup.enter="searchByName(req.name)"
@blur="searchByName(req.name)"
:placeholder="$t('commons.button.search')"
></el-input> ></el-input>
<el-button
style="display: inline; margin-right: 5px"
v-model="req.name"
@click="searchByName(req.name)"
>
{{ $t('app.search') }}
</el-button>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<br /> </template>
<el-row> <template #rightButton>
<el-button <el-button @click="sync" type="text" :plain="true">{{ $t('app.syncAppList') }}</el-button>
style="margin-right: 5px" </template>
@click="changeTag('all')" <template #main>
type="primary" <div class="divider"></div>
:plain="activeTag !== 'all'"
>
{{ $t('app.all') }}
</el-button>
<div style="margin-right: 5px" :span="1" v-for="item in tags" :key="item.key">
<el-button @click="changeTag(item.key)" type="primary" :plain="activeTag !== item.key">
{{ item.name }}
</el-button>
</div>
</el-row>
<el-row :gutter="5"> <el-row :gutter="5">
<el-col v-for="(app, index) in apps" :key="index" :span="6"> <el-col v-for="(app, index) in apps" :key="index" :span="8">
<div @click="getAppDetail(app.id)"> <div class="a-card">
<el-card :body-style="{ padding: '0px' }" class="a-card"> <el-row :gutter="24">
<el-row :gutter="24"> <el-col :span="5">
<el-col :span="8"> <div class="icon">
<div class="icon"> <el-avatar shape="square" :size="60" :src="'data:image/png;base64,' + app.icon" />
<el-image class="image" :src="'data:image/png;base64,' + app.icon"></el-image> </div>
</el-col>
<el-col :span="19">
<div class="a-detail">
<div class="d-name">
<span class="name">{{ app.name }}</span>
<el-button class="h-button" round @click="getAppDetail(app.id)">安装</el-button>
</div> </div>
</el-col> <div class="d-description">
<el-col :span="16"> <span class="description">
<div class="a-detail"> {{ app.shortDesc }}
<div class="d-name"> </span>
<span style="font-weight: 500; font-size: 16px">
{{ app.name }}
</span>
</div>
<div class="d-description">
<span>
{{ app.shortDesc }}
</span>
</div>
<div class="d-tag" style="margin-top: 5px">
<el-tag
v-for="(tag, ind) in app.tags"
:key="ind"
round
:colr="getColor(ind)"
>
{{ tag.name }}
</el-tag>
</div>
</div> </div>
</el-col> <div class="d-tag" style="margin-top: 5px">
</el-row> <el-tag v-for="(tag, ind) in app.tags" :key="ind" :colr="getColor(ind)">
</el-card> {{ tag.name }}
</el-tag>
</div>
<div class="divider"></div>
</div>
</el-col>
</el-row>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
</el-card> </template>
<Detail v-if="showDetail" :id="appId"></Detail> </LayoutContent>
</div> <Detail v-if="showDetail" :id="appId"></Detail>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import LayoutContent from '@/layout/layout-content.vue';
import { App } from '@/api/interface/app'; import { App } from '@/api/interface/app';
import { onMounted, reactive, ref } from 'vue'; import { onMounted, reactive, ref } from 'vue';
import { SearchApp, SyncApp } from '@/api/modules/app'; import { SearchApp, SyncApp } from '@/api/modules/app';
@ -159,14 +154,15 @@ onMounted(() => {
} }
.a-card { .a-card {
height: 100px; height: 120px;
margin-top: 10px; margin-top: 10px;
cursor: pointer; cursor: pointer;
padding: 5px; padding: 5px;
.icon { .icon {
margin-left: 10px;
width: 80px; width: 80px;
height: 100%; height: 80%;
padding: 5px; padding: 5px;
display: flex; display: flex;
align-items: center; align-items: center;
@ -185,24 +181,46 @@ onMounted(() => {
.d-name { .d-name {
height: 20%; height: 20%;
.name {
font-weight: 500;
font-size: 16px;
color: #1f2329;
}
.h-button {
float: right;
}
} }
.d-description { .d-description {
margin-top: 5px; margin-top: 10px;
overflow: hidden; overflow: hidden;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
.description {
font-size: 14px;
color: #646a73;
}
} }
} }
} }
.a-card:hover { .a-card:hover {
transform: scale(1.1); background-color: rgba(0, 94, 235, 0.03);
} }
.table-button { .table-button {
display: inline; display: inline;
margin-right: 5px; margin-right: 5px;
} }
.tag-button {
margin-left: 10px;
}
.divider {
margin-top: 5px;
border: 0;
border-top: 1px solid #ccc;
}
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<el-card> <LayoutContent :title="$t('app.detail')" :reload="true" :v-loading="loadingDetail">
<LayoutContent :header="$t('app.detail')" :back-name="'App'" :v-loading="loadingDetail"> <template #main>
<div class="brief"> <div class="brief">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="4"> <el-col :span="4">
@ -63,9 +63,9 @@
<div class="detail" v-loading="loadingDetail"> <div class="detail" v-loading="loadingDetail">
<v-md-preview :text="appDetail.readme"></v-md-preview> <v-md-preview :text="appDetail.readme"></v-md-preview>
</div> </div>
<Install ref="installRef"></Install> </template>
</LayoutContent> </LayoutContent>
</el-card> <Install ref="installRef"></Install>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -1,24 +1,27 @@
<template> <template>
<el-dialog <el-drawer v-model="open" :title="$t('app.install')" size="50%" :before-close="handleClose" :show-close="false">
v-model="open" <template #header>
:title="$t('app.install')" <Header :header="$t('app.install')" :back="handleClose" />
:close-on-click-modal="false" </template>
width="40%"
:before-close="handleClose" <el-row>
> <el-col :span="22" :offset="1">
<el-form <el-form
ref="paramForm" ref="paramForm"
label-position="left" label-position="top"
:model="form" :model="form"
label-width="150px" label-width="150px"
:rules="rules" :rules="rules"
:validate-on-rule-change="false" :validate-on-rule-change="false"
> >
<el-form-item :label="$t('app.name')" prop="NAME"> <el-form-item :label="$t('app.name')" prop="NAME">
<el-input v-model.trim="form['NAME']"></el-input> <el-input v-model.trim="form['NAME']"></el-input>
</el-form-item> </el-form-item>
<Params v-model:form="form" v-model:params="installData.params" v-model:rules="rules"></Params> <Params v-model:form="form" v-model:params="installData.params" v-model:rules="rules"></Params>
</el-form> </el-form>
</el-col>
</el-row>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button> <el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
@ -27,7 +30,7 @@
</el-button> </el-button>
</span> </span>
</template> </template>
</el-dialog> </el-drawer>
</template> </template>
<script lang="ts" setup name="appInstall"> <script lang="ts" setup name="appInstall">
@ -38,6 +41,8 @@ import { FormInstance, FormRules } from 'element-plus';
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import Params from '../params/index.vue'; import Params from '../params/index.vue';
import Header from '@/components/drawer-header/index.vue';
const router = useRouter(); const router = useRouter();
interface InstallRrops { interface InstallRrops {

View File

@ -1,7 +1,6 @@
<template> <template>
<div> <div>
<RouterButton :buttons="buttons" /> <RouterButton :buttons="buttons" />
<br />
<LayoutContent> <LayoutContent>
<router-view></router-view> <router-view></router-view>
</LayoutContent> </LayoutContent>