update admin
@ -39,7 +39,7 @@ export function installAddon(params: Record<string, any>) {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function cloudInstallAddon(params: Record<string, any>) {
|
export function cloudInstallAddon(params: Record<string, any>) {
|
||||||
return request.post(`addon/cloudinstall/${params.addon}`, params)
|
return request.post(`addon/cloudinstall/${params.addon}`, params, { timeout: 60 * 1000 })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -38,3 +38,9 @@ export function getLoginConfig() {
|
|||||||
export function getAuthaddon() {
|
export function getAuthaddon() {
|
||||||
return request.get(`auth/authaddon`)
|
return request.get(`auth/authaddon`)
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 获取当前版本信息
|
||||||
|
*/
|
||||||
|
export function getVersions() {
|
||||||
|
return request.get(`sys/info`)
|
||||||
|
}
|
||||||
|
|||||||
BIN
admin/src/app/assets/images/tools/addon_develop.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
admin/src/app/assets/images/tools/app_auth.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
admin/src/app/assets/images/tools/auth_menu.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
admin/src/app/assets/images/tools/code.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
admin/src/app/assets/images/tools/official_market.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
admin/src/app/assets/images/tools/sys_dict_list.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
admin/src/app/assets/images/tools/tools_Update_cache.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
admin/src/app/assets/images/tools/tools_check_environment.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
admin/src/app/assets/images/tools/tools_schedule.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
@ -1,8 +1,10 @@
|
|||||||
{
|
{
|
||||||
"app": "应用管理",
|
"app": "应用中心",
|
||||||
"descriptionLeft": "暂未安装任何应用,请到",
|
"descriptionLeft": "请点击",
|
||||||
"link": "插件管理",
|
"link": "安装应用",
|
||||||
"descriptionRight": "进行安装使用",
|
"descriptionRight": "安装使用",
|
||||||
"niucloud": "Niucloud官网",
|
"niucloud": "Niucloud官网",
|
||||||
"appStore": "插件管理"
|
"appStore": "安装应用",
|
||||||
|
"versionInfo":"版本信息:",
|
||||||
|
"currentVersion":"当前版本"
|
||||||
}
|
}
|
||||||
@ -1,4 +1,10 @@
|
|||||||
{
|
{
|
||||||
|
"search":"搜索应用名称",
|
||||||
|
"appName":"应用名/版本信息",
|
||||||
|
"introduction":"简介",
|
||||||
|
"type":"类型",
|
||||||
|
"app":"应用",
|
||||||
|
"addon":"插件",
|
||||||
"noPlug":"暂无应用",
|
"noPlug":"暂无应用",
|
||||||
"install":"安装",
|
"install":"安装",
|
||||||
"unload":"卸载",
|
"unload":"卸载",
|
||||||
@ -6,9 +12,10 @@
|
|||||||
"uninstalledLabel":"未安装",
|
"uninstalledLabel":"未安装",
|
||||||
"version":"版本",
|
"version":"版本",
|
||||||
"title":"名称",
|
"title":"名称",
|
||||||
"desc":"描述",
|
"desc":"简介",
|
||||||
"plugDetail": "插件信息",
|
"plugDetail": "插件信息",
|
||||||
"author": "作者",
|
"author": "作者",
|
||||||
|
"detail":"详情",
|
||||||
"addonInstall": "插件安装",
|
"addonInstall": "插件安装",
|
||||||
"dirPermission": "目录读写权限",
|
"dirPermission": "目录读写权限",
|
||||||
"path": "路径",
|
"path": "路径",
|
||||||
@ -56,5 +63,6 @@
|
|||||||
"updateCode": "重新绑定",
|
"updateCode": "重新绑定",
|
||||||
"notHaveAuth": "还没有授权?去购买",
|
"notHaveAuth": "还没有授权?去购买",
|
||||||
"authInfoTips": "授权码和授权秘钥可在Niucloud官网我的授权 授权详情中查看",
|
"authInfoTips": "授权码和授权秘钥可在Niucloud官网我的授权 授权详情中查看",
|
||||||
"addonUninstall": "插件卸载"
|
"addonUninstall": "插件卸载",
|
||||||
|
"noAddon":"暂无插件"
|
||||||
}
|
}
|
||||||
@ -9,7 +9,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mt-[30px] flex items-center text-[14px] text-[#797979]">
|
<div class="mt-[30px] flex items-center text-[14px] text-[#797979]">
|
||||||
<span>当前版本</span>
|
<span>当前版本</span>
|
||||||
<span class="text-[26px] ml-[15px] mr-[10px] text-[#656668]">1.0.35</span>
|
<span class="text-[26px] ml-[15px] mr-[10px] text-[#656668]">{{versions}}</span>
|
||||||
<em class="text-[12px]">(当前已是最新版本)</em>
|
<em class="text-[12px]">(当前已是最新版本)</em>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -40,7 +40,7 @@
|
|||||||
<div class="flex flex-1 flex-wrap justify-end relative">
|
<div class="flex flex-1 flex-wrap justify-end relative">
|
||||||
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary"
|
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary"
|
||||||
@click="authCodeApproveFn">授权码认证</el-button>
|
@click="authCodeApproveFn">授权码认证</el-button>
|
||||||
<el-popover ref="getAuthCodeDialog" placement="bottom" :width="478" trigger="click"
|
<el-popover ref="getAuthCodeDialog" placement="bottom-start" :width="478" trigger="click"
|
||||||
class="mt-[8px]">
|
class="mt-[8px]">
|
||||||
<div class="px-[18px] py-[8px]">
|
<div class="px-[18px] py-[8px]">
|
||||||
<p class="leading-[32px] text-[14px]">您在官方应用市场购买任意一款应用,即可获得授权码。输入正确授权码认证通过后,即可支持在线升级和其它相关服务
|
<p class="leading-[32px] text-[14px]">您在官方应用市场购买任意一款应用,即可获得授权码。输入正确授权码认证通过后,即可支持在线升级和其它相关服务
|
||||||
@ -95,6 +95,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
|
import { getVersions } from '@/app/api/auth'
|
||||||
import { getAuthinfo, setAuthinfo, getAdminAuthinfo } from '@/app/api/module'
|
import { getAuthinfo, setAuthinfo, getAdminAuthinfo } from '@/app/api/module'
|
||||||
import { FormInstance, FormRules } from 'element-plus'
|
import { FormInstance, FormRules } from 'element-plus'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
@ -165,7 +166,6 @@ const save = async (formEl: FormInstance | undefined) => {
|
|||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
saveLoading.value = false
|
saveLoading.value = false
|
||||||
authCodeApproveDialog.value = false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -174,6 +174,14 @@ const save = async (formEl: FormInstance | undefined) => {
|
|||||||
const market = () => {
|
const market = () => {
|
||||||
window.open('https://www.niucloud.com/product')
|
window.open('https://www.niucloud.com/product')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const versions = ref('')
|
||||||
|
const getVersionsInfo = () =>{
|
||||||
|
getVersions().then(res =>{
|
||||||
|
versions.value = res.data.version.version
|
||||||
|
})
|
||||||
|
}
|
||||||
|
getVersionsInfo()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -1,18 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="h-[480px] box-border pt-[20px] px-[20px]" v-loading="loading">
|
<div class="box-border pt-[68px] px-[76px] overview-top" v-loading="loading">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<div class="font-600 text-[20px] text-[#222]">{{ t('app') }}</div>
|
<div>
|
||||||
<el-button @click="toAppStore">
|
<div class="font-[600] text-[26px] text-[#222] leading-[37px]">{{ t('app') }}</div>
|
||||||
<el-icon class="mr-[2px]"><Download /></el-icon>
|
<div class="font-[500] text-[14px] text-[#222] leading-[20px] mt-[12px]">{{ t('versionInfo') }} {{ t('currentVersion') }} {{ versions }}</div>
|
||||||
<span>{{t('appStore')}}</span>
|
</div>
|
||||||
|
<el-button @click="toAppStore" class="px-[15px]">
|
||||||
|
<div class="mr-[9px] text-[#3F3F3F] iconfont iconxiazai01"></div>
|
||||||
|
<span class="font-[600] text-[14px] text-[#222] leading-[20px]">{{t('appStore')}}</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap mt-[28px]">
|
<div class="flex flex-wrap mt-[40px]">
|
||||||
<template v-for="(item, index) in detail.appList" :key="index">
|
<template v-for="(item, index) in detail.appList" :key="index">
|
||||||
<div class="app-item w-[284px] box-border p-[18px] pb-[24px] bg-[#fff] rounded-[8px] cursor-pointer mr-[24px] mb-[24px]"
|
<div class="app-item w-[280px] box-border py-[42px] px-[32px] bg-[#fff] rounded-[8px] cursor-pointer mr-[20px] mb-[20px] "
|
||||||
@click="itemPath(item)">
|
@click="itemPath(item)">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<el-image class="w-[40px] h-[40px] rounded-[8px]" :src="img(item.icon)" fit="contain">
|
<el-image class="w-[44px] h-[44px] rounded-[8px]" :src="img(item.icon)" fit="contain">
|
||||||
<template #error>
|
<template #error>
|
||||||
<div class="image-slot">
|
<div class="image-slot">
|
||||||
<img class="w-[40px] h-[40px] rounded-[8px]"
|
<img class="w-[40px] h-[40px] rounded-[8px]"
|
||||||
@ -20,9 +23,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-image>
|
</el-image>
|
||||||
<div class="flex-1 font-600 text-[14px] text-[#222] ml-[12px]">{{ item.title }}</div>
|
<div class="ml-[12px] flex-1">
|
||||||
|
<div class="font-[600] text-[14px] text-[#222] leading-[20px]">{{ item.title }}</div>
|
||||||
|
<div class="font-[500] text-[13px] text-[#6D7278] leading-[18px] mt-[6px] w-[160px] truncate">{{ item.desc }}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="font-500 text-[13px] text-[#6D7278] mt-[14px]">{{ item.desc }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -47,10 +52,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {reactive, ref, onMounted, computed} from 'vue'
|
import { reactive, ref, onMounted , computed} from 'vue'
|
||||||
import {t} from '@/lang'
|
import { t } from '@/lang'
|
||||||
import {getAuthaddon} from '@/app/api/auth'
|
import { getAuthaddon, getVersions} from '@/app/api/auth'
|
||||||
import {img} from '@/utils/common'
|
import { img} from '@/utils/common'
|
||||||
import {useRouter} from 'vue-router'
|
import {useRouter} from 'vue-router'
|
||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
import {findFirstValidRoute} from '@/router/routers'
|
import {findFirstValidRoute} from '@/router/routers'
|
||||||
@ -126,6 +131,13 @@
|
|||||||
userStore.logout();
|
userStore.logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const versions = ref('')
|
||||||
|
const getVersionsInfo = () =>{
|
||||||
|
getVersions().then(res =>{
|
||||||
|
versions.value = res.data.version.version
|
||||||
|
})
|
||||||
|
}
|
||||||
|
getVersionsInfo()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -134,10 +146,11 @@
|
|||||||
min-height: calc(100vh - 64px);
|
min-height: calc(100vh - 64px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.overview-top {
|
.overview-top{
|
||||||
background-image: url('@/app/assets/images/index/overview.png');
|
background-image: url('@/app/assets/images/index/overview.png');
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
|
height: calc(100vh - 120px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-item {
|
.app-item {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container w-full p-5 bg-white" v-loading="loading">
|
<div class="main-container w-full p-[64px] bg-white" v-loading="loading">
|
||||||
<div class="flex justify-between items-center h-[32px] mb-4">
|
<div class="flex justify-between items-center h-[32px] mb-4">
|
||||||
<span class="text-[20px]">{{ t('personal') }}</span>
|
<span class="text-[20px]">{{ t('personal') }}</span>
|
||||||
<span class="text-[14px] text-[#999] cursor-pointer" @click="toEditPersonal">{{ t('editPersonal') }}</span>
|
<span class="text-[14px] text-[#999] cursor-pointer" @click="toEditPersonal">{{ t('editPersonal') }}</span>
|
||||||
@ -7,7 +7,13 @@
|
|||||||
<el-card class="box-card !border-none" shadow="never">
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
<el-form :model="saveInfo" label-width="90px" ref="formRef" class="page-form">
|
<el-form :model="saveInfo" label-width="90px" ref="formRef" class="page-form">
|
||||||
<el-form-item :label="t('headImg')">
|
<el-form-item :label="t('headImg')">
|
||||||
<el-image class="w-[70px] h-[70px]" :src="img(saveInfo.head_img)" fit="contain" />
|
<el-image class="w-[70px] h-[70px] rounded-full" :src="img(saveInfo.head_img)" fit="contain">
|
||||||
|
<template #error>
|
||||||
|
<div class="image-slot w-[70px] h-[70px] bg-[#c0c4cc] flex items-center justify-center">
|
||||||
|
<el-icon class="text-[45px] text-[#fff]"><UserFilled /></el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="t('userName')">
|
<el-form-item :label="t('userName')">
|
||||||
<div>{{saveInfo.username}}</div>
|
<div>{{saveInfo.username}}</div>
|
||||||
@ -21,6 +27,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { UserFilled } from '@element-plus/icons-vue'
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
||||||
|
|||||||
@ -1,280 +1,165 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main-container w-full p-5 bg-white" v-loading="loading">
|
<div class="pt-[64px] px-[90px] app-store" v-loading="loading">
|
||||||
<div class="flex justify-between items-center h-[32px] mb-4">
|
<div class="flex justify-between items-center h-[32px] mb-4">
|
||||||
<span class="text-[20px]">{{ t('localAppText') }}</span>
|
<span class="text-[26px] text-[#222] font-600">{{ t('localAppText') }}</span>
|
||||||
|
<el-input class="w-[247px]" :placeholder="t('search')" v-model="search_name" @keyup.enter="query">
|
||||||
|
<template #suffix>
|
||||||
|
<el-icon class="el-input__icon cursor-pointer" size="14px" @click="query">
|
||||||
|
<search />
|
||||||
|
</el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="relative">
|
<div class="flex mt-[24px]">
|
||||||
<!-- <div class="absolute right-0 top-[2px] flex items-center cursor-pointer z-[4] border border-inherit">
|
<div :class="{ '!bg-[#000] !border-0 !text-[#fff]': activeName === 'installed' }"
|
||||||
<div class="flex item-center justify-center px-[6px] py-[4px]"
|
class="w-[78px] h-[30rpx] text-[14px] text-[#242424] text-center rounded-[15px] leading-[30px] bg-[#F0F0F0] border-solid border-1 border-[#E0E0E0] cursor-pointer mr-[24px]"
|
||||||
:class="{ 'bg-slate-200': showType == 'small' }" @click="showType = 'small'">
|
@click="activeName = 'installed'">
|
||||||
<img src="@/app/assets/images/app_store/switch_icon_1.png" class=" w-[16px] h-[16px]">
|
{{ t('installLabel') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex item-center justify-center px-[6px] py-[4px]"
|
<div :class="{ '!bg-[#000] !border-0 !text-[#fff]': activeName === 'uninstalled' }"
|
||||||
:class="{ 'bg-slate-200': showType == 'large' }" @click="showType = 'large'">
|
class="w-[78px] h-[30rpx] text-[14px] text-[#242424] text-center rounded-[15px] leading-[30px] bg-[#F0F0F0] border-solid border-1 border-[#E0E0E0] cursor-pointer mr-[24px]"
|
||||||
<img src="@/app/assets/images/app_store/switch_icon_2.png" class="w-[16px] h-[16px] ">
|
@click="activeName = 'uninstalled'">
|
||||||
</div>
|
{{ t('uninstalledLabel') }}
|
||||||
</div> -->
|
</div>
|
||||||
|
<div :class="{ '!bg-[#000] !border-0 !text-[#fff]': activeName === 'all' }"
|
||||||
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
class="w-[78px] h-[30rpx] text-[14px] text-[#242424] text-center rounded-[15px] leading-[30px] bg-[#F0F0F0] border-solid border-1 border-[#E0E0E0] cursor-pointer mr-[24px]"
|
||||||
<el-tab-pane :label="installLabel" name="installed">
|
@click="activeName = 'all'">
|
||||||
<div class="flex flex-wrap px-2 plug-list pb-10">
|
{{ t('buyLabel') }}
|
||||||
<div v-for="(item, index) in localList.installed" :key="index + 'a'"
|
</div>
|
||||||
class="flex items-center cursor-pointer w-[295px] relative plug-item mr-4 mb-4"
|
</div>
|
||||||
@click="getAddonDetialFn(item)" v-if="showType == 'small'">
|
<div class="mt-[32px]">
|
||||||
<div class="p-3">
|
<el-table v-if="localList[activeName].length" :data="info[activeName]" size="large" class="pt-[5px]">
|
||||||
<img class="w-[44px] h-[44px] rounded-sm" v-if="item.icon" :src="item.icon" alt="">
|
<template #empty>
|
||||||
<img class="w-[44px] h-[44px] rounded-sm" v-else src="@/app/assets/images/icon-addon.png"
|
<span>{{ t('noAddon') }}</span>
|
||||||
alt="">
|
</template>
|
||||||
</div>
|
<el-table-column :label="t('appName')" align="left" min-width="200">
|
||||||
<div class="flex items-center w-[220px] border-b py-3 justify-between">
|
<template #default="{ row }">
|
||||||
<div class="flex flex-col">
|
<div class="flex items-center">
|
||||||
<span class="text-[14px] truncate w-[160px]">{{ item.title }}</span>
|
<el-image class="w-[54px] h-[54px] flex-shrink-0" :src="row.icon" fit="contain">
|
||||||
<span class="text-xs text-gray-400 truncate w-[160px] mt-[4px]">{{ item.desc }}</span>
|
<template #error>
|
||||||
</div>
|
<img class="w-[54px] h-[54px]" src="@/app/assets/images/icon-addon.png" alt="">
|
||||||
<el-button size="small" round class="!text-primary !border-primary !bg-transparent"
|
</template>
|
||||||
@click.stop="uninstallAddonFn(item.key)">{{ t('unload')
|
</el-image>
|
||||||
}}</el-button>
|
<div class="flex flex-col justify-center pl-[20px] text-[#222] font-500 text-[13px]">
|
||||||
|
<div class="multi-hidden leading-[20px]">{{ row.title }}</div>
|
||||||
|
<div class="leading-[18px] mt-[6px]">{{ row.version }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="" :label="t('introduction')" align="left" min-width="200">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span class="text-[#222] font-500 text-[13px] multi-hidden">{{ row.desc }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="t('type')" align="left" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span class="text-[#222] font-500 text-[13px]">{{ row.type === 'app' ? t('app') : t('addon')
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="" :label="t('author')" align="left" min-width="200">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span class="text-[#222] font-500 text-[13px] multi-hidden">{{ row.author }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="t('operation')" align="right" width="180">
|
||||||
|
<template #default="{ row }">
|
||||||
|
|
||||||
<div class="flex flex-wrap plug-list pb-10 plug-large" v-if="showType == 'large'">
|
<el-button class="!text-[13px]" v-if="row.install_info && Object.keys(row.install_info)?.length"
|
||||||
<div class="app-item cursor-pointer mr-4 mt-[20px] pb-2 bg-[#f7f7f7]"
|
type="primary" link @click="uninstallAddonFn(row.key)">{{ t('unload') }}</el-button>
|
||||||
v-for="(item, index) in localList.installed" :key="index + 'a'"
|
|
||||||
@click="getAddonDetialFn(item)">
|
|
||||||
<div class="flex justify-center items-center">
|
|
||||||
<img class="w-[240px] h-[120px]" v-if="item.cover" :src="item.cover" />
|
|
||||||
<img v-else class="w-[240px] h-[120px]"
|
|
||||||
src="@/app/assets/images/app_store/app_store_default.png" />
|
|
||||||
</div>
|
|
||||||
<div class="flex w-[240px] h-[46px]">
|
|
||||||
<div class="text-left mt-2 w-[190px]">
|
|
||||||
<p class="app-text text-[14px] text-[#222] pl-2">{{ item.title }}</p>
|
|
||||||
<p class="app-text text-[12px] text-[#999] pl-2">{{ item.desc }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center pr-2">
|
|
||||||
<el-button size="small" round class="!text-primary !border-primary !bg-transparent"
|
|
||||||
@click.stop="uninstallAddonFn(item.key)">{{ t('unload')
|
|
||||||
}}</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-empty class="mx-auto overview-empty" v-if="!localList.installed.length && !loading">
|
<el-button class="!text-[13px]" v-else-if="row.is_download && row.install_info <= 0" type="primary"
|
||||||
<template #image>
|
link @click="installAddonFn(row.key)">{{ t('install')
|
||||||
<div class="w-[230px] mx-auto">
|
}}</el-button>
|
||||||
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
<el-button class="!text-[13px]" v-else :loading="downloading == row.key"
|
||||||
</div>
|
:disabled="downloading != ''" type="primary" link @click.stop="downEvent(row)">{{
|
||||||
</template>
|
t('down') }}</el-button>
|
||||||
<template #description>
|
<el-button class="!text-[13px]" type="primary" link @click="getAddonDetialFn(row)">{{ t('detail')
|
||||||
<p class="flex items-center">{{ t('installed-empty') }}</p>
|
}}</el-button>
|
||||||
</template>
|
|
||||||
</el-empty>
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<el-empty class="mx-auto overview-empty"
|
||||||
|
v-if="!localList.installed.length && !loading && activeName == 'installed'">
|
||||||
|
<template #image>
|
||||||
|
<div class="w-[230px] mx-auto">
|
||||||
|
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</template>
|
||||||
<el-tab-pane :label="uninstalledLabel" name="uninstalled">
|
<template #description>
|
||||||
<div class="flex flex-wrap px-2 plug-list pb-10">
|
<p class="flex items-center">{{ t('installed-empty') }}</p>
|
||||||
|
</template>
|
||||||
<div v-for="(item, index) in localList.uninstalled" :key="index + 'a'"
|
</el-empty>
|
||||||
class="flex items-center cursor-pointer w-[295px] relative plug-item mr-4 mb-4"
|
<el-empty class="mx-auto overview-empty"
|
||||||
@click="getAddonDetialFn(item)" v-if="showType == 'small'">
|
v-if="!localList.uninstalled.length && !loading && activeName == 'uninstalled'">
|
||||||
<div class="p-3">
|
<template #image>
|
||||||
<img v-if="item.icon" class="w-[44px] h-[44px] rounded-sm" :src="item.icon" alt="">
|
<div class="w-[230px] mx-auto">
|
||||||
<img v-else class="w-[44px] h-[44px] rounded-sm" src="@/app/assets/images/icon-addon.png"
|
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
||||||
alt="">
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center w-[220px] border-b py-3 justify-between">
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<span class="text-[14px] truncate w-[160px]">{{ item.title }}</span>
|
|
||||||
<span class="text-xs text-gray-400 truncate w-[160px] mt-[4px]">{{ item.desc }}</span>
|
|
||||||
</div>
|
|
||||||
<el-button v-if="item.is_download" size="small" round
|
|
||||||
class="!text-primary !border-primary !bg-transparent"
|
|
||||||
@click.stop="installAddonFn(item.key)">{{ t('install')
|
|
||||||
}}</el-button>
|
|
||||||
<el-button v-else size="small" :loading="downloading == item.key"
|
|
||||||
:disabled="downloading != ''" round
|
|
||||||
class="!text-primary !border-primary !bg-transparent" @click.stop="downEvent(item)">{{
|
|
||||||
t('down') }}</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-wrap plug-list pb-10 plug-large" v-if="showType == 'large'">
|
|
||||||
<div class="app-item cursor-pointer mr-4 mt-[20px] pb-2 bg-[#f7f7f7]"
|
|
||||||
v-for="(item, index) in localList.uninstalled" :key="index + 'a'"
|
|
||||||
@click="getAddonDetialFn(item)">
|
|
||||||
<div class="flex justify-center items-center">
|
|
||||||
<img v-if="item.cover && !item.is_download" class="w-[240px] h-[120px]"
|
|
||||||
:src="img(item.cover)" />
|
|
||||||
<img v-else-if="item.cover && item.is_download" class="w-[240px] h-[120px]"
|
|
||||||
:src="item.cover" />
|
|
||||||
<img v-else class="w-[240px] h-[120px]"
|
|
||||||
src="@/app/assets/images/app_store/app_store_default.png" />
|
|
||||||
</div>
|
|
||||||
<div class="flex w-[240px] h-[46px]">
|
|
||||||
<div class="text-left mt-2 w-[190px]">
|
|
||||||
<p class="app-text text-[14px] text-[#222] pl-2">{{ item.title }}</p>
|
|
||||||
<p class="app-text text-[12px] text-[#999] pl-2">{{ item.desc }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center pr-2">
|
|
||||||
<el-button v-if="item.is_download" size="small" round
|
|
||||||
class="!text-primary !border-primary !bg-transparent"
|
|
||||||
@click.stop="installAddonFn(item.key)">{{ t('install')
|
|
||||||
}}</el-button>
|
|
||||||
<el-button v-else size="small" :loading="downloading == item.key"
|
|
||||||
:disabled="downloading != ''" round
|
|
||||||
class="!text-primary !border-primary !bg-transparent"
|
|
||||||
@click.stop="downEvent(item)">{{ t('down') }}</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-empty class="mx-auto overview-empty" v-if="!localList.uninstalled.length && !loading">
|
|
||||||
<template #image>
|
|
||||||
<div class="w-[230px] mx-auto">
|
|
||||||
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #description>
|
|
||||||
<p class="flex items-center">
|
|
||||||
<span>{{ t('descriptionLeft') }}</span>
|
|
||||||
<el-link type="primary" @click="goRouter" class="mx-[5px]">{{ t('link') }}</el-link>
|
|
||||||
<span>{{ t('descriptionRight') }}</span>
|
|
||||||
</p>
|
|
||||||
</template>
|
|
||||||
</el-empty>
|
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</template>
|
||||||
<el-tab-pane :label="allLabel" name="buy">
|
<template #description>
|
||||||
|
<p class="flex items-center">
|
||||||
<div class="flex flex-wrap px-2 plug-list pb-10">
|
<span>{{ t('descriptionLeft') }}</span>
|
||||||
|
<el-link type="primary" @click="goRouter" class="mx-[5px]">{{ t('link') }}</el-link>
|
||||||
<template v-if="authinfo">
|
<span>{{ t('descriptionRight') }}</span>
|
||||||
<div v-for="(item, index) in localList.all" :key="index + 'a'"
|
</p>
|
||||||
class="flex items-center cursor-pointer w-[295px] relative plug-item mr-4 mb-4"
|
</template>
|
||||||
@click="getAddonDetialFn(item)" v-if="showType == 'small'">
|
</el-empty>
|
||||||
<div class="p-3">
|
<div v-if="!localList.all.length && !loading && !authinfo && activeName == 'all'"
|
||||||
<img v-if="item.icon" class="w-[44px] h-[44px] rounded-sm" :src="item.icon" alt="">
|
class="mx-auto overview-empty flex flex-col items-center pt-14 pb-6">
|
||||||
<img v-else class="w-[44px] h-[44px] rounded-sm"
|
<div class="mb-[20px] text-sm text-[#888]">检测到当前账号尚未绑定授权,请先绑定授权!</div>
|
||||||
src="@/app/assets/images/icon-addon.png" alt="">
|
<div class="flex flex-1 flex-wrap justify-center relative">
|
||||||
</div>
|
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary"
|
||||||
<div class="flex items-center w-[220px] border-b py-3 justify-between">
|
@click="authCodeApproveFn">授权码认证</el-button>
|
||||||
<div class="flex flex-col">
|
<el-popover ref="getAuthCodeDialog" placement="bottom" :width="478" trigger="click" class="mt-[8px]">
|
||||||
<span class="text-[14px] truncate w-[160px]">{{ item.title }}</span>
|
<div class="px-[18px] py-[8px]">
|
||||||
<span class="text-xs text-gray-400 truncate w-[160px] mt-[4px]">{{ item.desc
|
<p class="leading-[32px] text-[14px]">
|
||||||
}}</span>
|
您在官方应用市场购买任意一款应用,即可获得授权码。输入正确授权码认证通过后,即可支持在线升级和其它相关服务</p>
|
||||||
</div>
|
<div class="flex justify-end mt-[36px]">
|
||||||
<el-button v-if="item.install_info && Object.keys(item.install_info)?.length"
|
<el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button>
|
||||||
size="small" round class="!text-primary !border-primary !bg-transparent"
|
<el-button class="w-[100px] !h-[48px]" plain
|
||||||
@click.stop="uninstallAddonFn(item.key)">{{ t('unload')
|
@click="getAuthCodeDialog.hide()">关闭</el-button>
|
||||||
}}</el-button>
|
|
||||||
<el-button v-else-if="item.is_download && item.install_info <= 0" size="small" round
|
|
||||||
class="!text-primary !border-primary !bg-transparent"
|
|
||||||
@click.stop="installAddonFn(item.key)">{{ t('install')
|
|
||||||
}}</el-button>
|
|
||||||
<el-button v-else size="small" :loading="downloading == item.key"
|
|
||||||
:disabled="downloading != ''" round
|
|
||||||
class="!text-primary !border-primary !bg-transparent"
|
|
||||||
@click.stop="downEvent(item)">{{
|
|
||||||
t('down') }}</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-wrap plug-list pb-10 plug-large" v-if="showType == 'large'">
|
|
||||||
<div class="app-item cursor-pointer mr-4 mt-[20px] pb-2 bg-[#f7f7f7]"
|
|
||||||
v-for="(item, index) in localList.all" :key="index + 'a'"
|
|
||||||
@click="getAddonDetialFn(item)">
|
|
||||||
<div class="flex justify-center items-center">
|
|
||||||
<img v-if="item.icon && !item.is_download" class="w-[240px] h-[120px]"
|
|
||||||
:src="img(item.icon)" />
|
|
||||||
<img v-else-if="item.icon && item.is_download" class="w-[240px] h-[120px]"
|
|
||||||
:src="item.icon" />
|
|
||||||
<img v-else class="w-[240px] h-[120px]"
|
|
||||||
src="@/app/assets/images/app_store/app_store_default.png" />
|
|
||||||
</div>
|
|
||||||
<div class="flex w-[240px] h-[46px]">
|
|
||||||
<div class="text-left mt-2 w-[190px]">
|
|
||||||
<p class="app-text text-[14px] text-[#222] pl-2">{{ item.title }}</p>
|
|
||||||
<p class="app-text text-[12px] text-[#999] pl-2">{{ item.desc }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center pr-2">
|
|
||||||
<el-button v-if="item.install_info && Object.keys(item.install_info)?.length"
|
|
||||||
size="small" round class="!text-primary !border-primary !bg-transparent"
|
|
||||||
@click.stop="uninstallAddonFn(item.key)">{{ t('unload')
|
|
||||||
}}</el-button>
|
|
||||||
<el-button v-else-if="item.is_download && item.install_info <= 0" size="small"
|
|
||||||
round class="!text-primary !border-primary !bg-transparent"
|
|
||||||
@click.stop="installAddonFn(item.key)">{{ t('install')
|
|
||||||
}}</el-button>
|
|
||||||
<el-button v-else size="small" round :loading="downloading == item.key"
|
|
||||||
:disabled="downloading != ''"
|
|
||||||
class="!text-primary !border-primary !bg-transparent"
|
|
||||||
@click.stop="downEvent(item)">{{ t('down') }}</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #reference>
|
||||||
|
<el-button
|
||||||
|
class="w-[154px] !h-[48px] mt-[8px] !text-[var(--el-color-primary)] hover:!text-[var(--el-color-primary)] !bg-transparent"
|
||||||
|
plain type="primary">如何获取授权码?</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
</el-popover>
|
||||||
<div v-if="!localList.all.length && !loading && !authinfo"
|
</div>
|
||||||
class="mx-auto overview-empty flex flex-col items-center pt-14 pb-6">
|
</div>
|
||||||
<div class="mb-[20px] text-sm text-[#888]">检测到当前账号尚未绑定授权,请先绑定授权!</div>
|
|
||||||
<div class="flex flex-1 flex-wrap justify-center relative">
|
|
||||||
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary"
|
|
||||||
@click="authCodeApproveFn">授权码认证</el-button>
|
|
||||||
<el-popover ref="getAuthCodeDialog" placement="bottom" :width="478" trigger="click"
|
|
||||||
class="mt-[8px]">
|
|
||||||
<div class="px-[18px] py-[8px]">
|
|
||||||
<p class="leading-[32px] text-[14px]">
|
|
||||||
您在官方应用市场购买任意一款应用,即可获得授权码。输入正确授权码认证通过后,即可支持在线升级和其它相关服务</p>
|
|
||||||
<div class="flex justify-end mt-[36px]">
|
|
||||||
<el-button class="w-[182px] !h-[48px]" plain @click="market">去应用市场逛逛</el-button>
|
|
||||||
<el-button class="w-[100px] !h-[48px]" plain
|
|
||||||
@click="getAuthCodeDialog.hide()">关闭</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<template #reference>
|
|
||||||
<el-button
|
|
||||||
class="w-[154px] !h-[48px] mt-[8px] !text-[var(--el-color-primary)] hover:!text-[var(--el-color-primary)] !bg-transparent"
|
|
||||||
plain type="primary">如何获取授权码?</el-button>
|
|
||||||
</template>
|
|
||||||
</el-popover>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<el-dialog v-model="authCodeApproveDialog" title="授权码认证" width="400px">
|
|
||||||
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
|
|
||||||
<el-card class="box-card !border-none" shadow="never">
|
|
||||||
<el-form-item prop="auth_code">
|
|
||||||
<el-input v-model="formData.auth_code" :placeholder="t('authCodePlaceholder')"
|
|
||||||
class="input-width" clearable size="large" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<div class="mt-[20px]">
|
|
||||||
<el-form-item prop="auth_secret">
|
|
||||||
<el-input v-model="formData.auth_secret" clearable
|
|
||||||
:placeholder="t('authSecretPlaceholder')" class="input-width"
|
|
||||||
size="large" />
|
|
||||||
</el-form-item>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-sm mt-[10px] text-info">{{ t('authInfoTips') }}</div>
|
|
||||||
|
|
||||||
<div class="mt-[20px]">
|
|
||||||
<el-button type="primary" class="w-full" size="large" :loading="saveLoading"
|
|
||||||
@click="save(formRef)">{{ t('confirm') }}</el-button>
|
|
||||||
</div>
|
|
||||||
<div class="mt-[10px] text-right">
|
|
||||||
<el-button type="primary" link @click="market">{{ t('notHaveAuth') }}</el-button>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-form>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
</div>
|
</div>
|
||||||
|
<el-dialog v-model="authCodeApproveDialog" title="授权码认证" width="400px">
|
||||||
|
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
|
||||||
|
<el-card class="box-card !border-none" shadow="never">
|
||||||
|
<el-form-item prop="auth_code">
|
||||||
|
<el-input v-model="formData.auth_code" :placeholder="t('authCodePlaceholder')" class="input-width"
|
||||||
|
clearable size="large" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div class="mt-[20px]">
|
||||||
|
<el-form-item prop="auth_secret">
|
||||||
|
<el-input v-model="formData.auth_secret" clearable :placeholder="t('authSecretPlaceholder')"
|
||||||
|
class="input-width" size="large" />
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-sm mt-[10px] text-info">{{ t('authInfoTips') }}</div>
|
||||||
|
|
||||||
|
<div class="mt-[20px]">
|
||||||
|
<el-button type="primary" class="w-full" size="large" :loading="saveLoading"
|
||||||
|
@click="save(formRef)">{{ t('confirm') }}</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="mt-[10px] text-right">
|
||||||
|
<el-button type="primary" link @click="market">{{ t('notHaveAuth') }}</el-button>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
<!-- 详情 -->
|
<!-- 详情 -->
|
||||||
<el-dialog v-model="appStoreShowDialog" :title="t('plugDetail')" width="500px" :destroy-on-close="true">
|
<el-dialog v-model="appStoreShowDialog" :title="t('plugDetail')" width="500px" :destroy-on-close="true">
|
||||||
<el-form :model="appStoreInfo" label-width="120px" ref="formRef" class="page-form">
|
<el-form :model="appStoreInfo" label-width="120px" ref="formRef" class="page-form">
|
||||||
@ -447,21 +332,18 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive, watch, computed, h } from 'vue'
|
import { ref, reactive, watch, h } from 'vue'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import { getAddonLocal, uninstallAddon, installAddon, preInstallCheck, cloudInstallAddon, getAddonInstalltask, getAddonCloudInstallLog, preUninstallCheck } from '@/app/api/addon'
|
import { getAddonLocal, uninstallAddon, installAddon, preInstallCheck, cloudInstallAddon, getAddonInstalltask, getAddonCloudInstallLog, preUninstallCheck } from '@/app/api/addon'
|
||||||
import { downloadVersion, getAuthinfo, setAuthinfo } from '@/app/api/module'
|
import { downloadVersion, getAuthinfo, setAuthinfo } from '@/app/api/module'
|
||||||
import { TabsPaneContext, ElMessageBox, ElNotification, FormInstance, FormRules } from 'element-plus'
|
import { ElMessageBox, ElNotification, FormInstance, FormRules } from 'element-plus'
|
||||||
import { img } from '@/utils/common'
|
import { img } from '@/utils/common'
|
||||||
import { Terminal, api as terminalApi } from 'vue-web-terminal'
|
import { Terminal, api as terminalApi } from 'vue-web-terminal'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
import storage from '@/utils/storage'
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const activeName = ref('installed')
|
const activeName = ref('installed')
|
||||||
const loading = ref<Boolean>(false)
|
const loading = ref<Boolean>(false)
|
||||||
const showType = ref('small')
|
|
||||||
const downloading = ref('')
|
const downloading = ref('')
|
||||||
const installAfterTips = ref<string[]>([])
|
const installAfterTips = ref<string[]>([])
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
@ -479,24 +361,6 @@ const downEvent = (param: Record<string, any>) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const installLabel = computed(() => {
|
|
||||||
let text = t('installLabel')
|
|
||||||
localList.value.installed.length && (text += ` (${localList.value.installed.length})`)
|
|
||||||
return text
|
|
||||||
})
|
|
||||||
|
|
||||||
const uninstalledLabel = computed(() => {
|
|
||||||
let text = t('uninstalledLabel')
|
|
||||||
localList.value.uninstalled.length && (text += ` (${localList.value.uninstalled.length})`)
|
|
||||||
return text
|
|
||||||
})
|
|
||||||
|
|
||||||
const allLabel = computed(() => {
|
|
||||||
let text = t('buyLabel')
|
|
||||||
localList.value.all.length && (text += ` (${localList.value.all.length})`)
|
|
||||||
return text
|
|
||||||
})
|
|
||||||
|
|
||||||
const authCode = ref('')
|
const authCode = ref('')
|
||||||
getAuthinfo().then(res => {
|
getAuthinfo().then(res => {
|
||||||
if (res.data.data && res.data.data.auth_code) {
|
if (res.data.data && res.data.data.auth_code) {
|
||||||
@ -508,6 +372,27 @@ getAuthinfo().then(res => {
|
|||||||
/**
|
/**
|
||||||
* 本地下载的插件列表
|
* 本地下载的插件列表
|
||||||
*/
|
*/
|
||||||
|
//input 筛选
|
||||||
|
const search_name = ref('')
|
||||||
|
//表格展示数据
|
||||||
|
const info = ref({
|
||||||
|
installed: [],
|
||||||
|
uninstalled: [],
|
||||||
|
all: [],
|
||||||
|
})
|
||||||
|
const query = () => {
|
||||||
|
if (search_name.value == '' || search_name.value == null) {
|
||||||
|
info.value.installed = localList.value.installed
|
||||||
|
info.value.uninstalled = localList.value.uninstalled
|
||||||
|
info.value.all = localList.value.all
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
info.value.installed = localList.value.installed.filter((el: any) => el.title.indexOf(search_name.value) != -1)
|
||||||
|
info.value.uninstalled = localList.value.uninstalled.filter((el: any) => el.title.indexOf(search_name.value) != -1)
|
||||||
|
info.value.all = localList.value.all.filter((el: any) => el.title.indexOf(search_name.value) != -1)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
const localList = ref({
|
const localList = ref({
|
||||||
installed: [],
|
installed: [],
|
||||||
uninstalled: [],
|
uninstalled: [],
|
||||||
@ -532,7 +417,7 @@ const localListFn = () => {
|
|||||||
if (data[i].is_download == true) localList.value.uninstalled.push(data[i])
|
if (data[i].is_download == true) localList.value.uninstalled.push(data[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
query()
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
@ -540,17 +425,6 @@ const localListFn = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
localListFn()
|
localListFn()
|
||||||
|
|
||||||
const handleClick = (tab: TabsPaneContext, event: Event) => {
|
|
||||||
// if (tab.paneName == 'buy' && localList.value.error != '') {
|
|
||||||
// ElMessage({
|
|
||||||
// message: localList.value.error,
|
|
||||||
// grouping: true,
|
|
||||||
// type: 'error'
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
const currAddon = ref('')
|
const currAddon = ref('')
|
||||||
|
|
||||||
// 安装面板弹窗
|
// 安装面板弹窗
|
||||||
@ -682,7 +556,7 @@ const authElMessageBox = () => {
|
|||||||
cancelButtonText: t('toNiucloud')
|
cancelButtonText: t('toNiucloud')
|
||||||
}
|
}
|
||||||
).then(() => {
|
).then(() => {
|
||||||
router.push({ path: '/app/authorize' })
|
authCodeApproveFn()
|
||||||
}).catch((action: string) => {
|
}).catch((action: string) => {
|
||||||
if (action === 'cancel') {
|
if (action === 'cancel') {
|
||||||
window.open('https://www.niucloud.com/product')
|
window.open('https://www.niucloud.com/product')
|
||||||
@ -765,6 +639,8 @@ const installShowDialogClose = (done: () => {}) => {
|
|||||||
).then(() => {
|
).then(() => {
|
||||||
done()
|
done()
|
||||||
}).catch(() => { })
|
}).catch(() => { })
|
||||||
|
} else if(installStep.value == 3){
|
||||||
|
location.reload();
|
||||||
} else done()
|
} else done()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -824,7 +700,7 @@ const save = async (formEl: FormInstance | undefined) => {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
saveLoading.value = false
|
saveLoading.value = false
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
location.reload();
|
location.reload();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@ -840,6 +716,17 @@ const goRouter = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
/* 多行超出隐藏 */
|
||||||
|
.multi-hidden {
|
||||||
|
white-space: normal;
|
||||||
|
word-break: break-all;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
.demo-tabs>.el-tabs__content {
|
.demo-tabs>.el-tabs__content {
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
color: #6b778c;
|
color: #6b778c;
|
||||||
@ -893,8 +780,13 @@ html.dark .table-head-bg {
|
|||||||
background: #141414;
|
background: #141414;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-alert .el-alert__title{
|
.el-alert .el-alert__title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-store {
|
||||||
|
height: calc(100vh - 120px);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -43,7 +43,7 @@
|
|||||||
<upload-image v-model="formData.front_end_logo" />
|
<upload-image v-model="formData.front_end_logo" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-card> -->
|
</el-card> -->
|
||||||
<el-card class="box-card !border-none" shadow="never" v-if="app_type == 'admin' ">
|
<el-card class="box-card !border-none" shadow="never" v-if="app_type == 'admin'">
|
||||||
<h3 class="panel-title !text-sm">{{ t('serviceInformation') }}</h3>
|
<h3 class="panel-title !text-sm">{{ t('serviceInformation') }}</h3>
|
||||||
<el-form-item :label="t('contactsTel')">
|
<el-form-item :label="t('contactsTel')">
|
||||||
<el-input v-model="formData.tel" :placeholder="t('contactsTelPlaceholder')" class="input-width" clearable maxlength="20" />
|
<el-input v-model="formData.tel" :placeholder="t('contactsTelPlaceholder')" class="input-width" clearable maxlength="20" />
|
||||||
@ -95,9 +95,9 @@ const formData = reactive<Record<string, string>>({
|
|||||||
front_end_name: '',
|
front_end_name: '',
|
||||||
front_end_logo: '',
|
front_end_logo: '',
|
||||||
icon: '',
|
icon: '',
|
||||||
wechat_code: '',
|
tel: '',
|
||||||
enterprise_wechat: '',
|
wechat_code: '',
|
||||||
tel: ''
|
enterprise_wechat: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const setFormData = async (id: number = 0) => {
|
const setFormData = async (id: number = 0) => {
|
||||||
|
|||||||
@ -1,33 +1,70 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="box-border px-[30px] pt-[60px]" v-loading="loading">
|
<div class="box-border px-[64px] pt-[64px]">
|
||||||
<div class="flex justify-between items-center">
|
<div class="font-600 text-[22px] text-[#222] mb-[32px] pl-[14px]">工具管理</div>
|
||||||
<div class="font-600 text-[20px] text-[#222]">工具管理</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-wrap mt-[28px]">
|
<div class="flex flex-wrap mt-[28px]">
|
||||||
<template v-for="(item, index) in menus" :key="index">
|
<div class="w-[256px] h-[260px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer" @click="toLink('/tools/addon')">
|
||||||
<div class="app-item w-[284px] box-border p-[15px] bg-[#fff] rounded-[8px] cursor-pointer mr-[24px] mb-[24px]" @click="toLink(item)">
|
<div class="flex-1 py-[19px] px-[24px] flex flex-col">
|
||||||
<div class="flex items-center">
|
<span class="text-[16px] text-[#222] font-bold">插件开发</span>
|
||||||
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto" size="40px" :title="item.meta.title" />
|
<p class="text-[13px] text-[#666] mt-[8px] multi-hidden">点击新建插件,生成插件后系统会生成对应插</p>
|
||||||
<img v-else class="w-[40px] h-[40px] rounded-[8px]" src="@/app/assets/images/app_store/app_store_default.png"/>
|
|
||||||
<div class="flex-1 font-600 text-[14px] text-[#222] ml-[12px]">{{ item.meta.title }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
<img src="@/app/assets/images/tools/addon_develop.png" class="w-[256px] h-[148px]" />
|
||||||
|
</div>
|
||||||
<el-empty v-if="!menus.length && !loading" class="mx-auto overview-empty">
|
<div class="w-[256px] h-[260px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer" @click="toLink('/tools/code')">
|
||||||
<template #image>
|
<div class="flex-1 py-[19px] px-[24px] flex flex-col">
|
||||||
<div class="w-[230px] mx-auto">
|
<span class="text-[16px] text-[#222] font-bold">代码生成</span>
|
||||||
<img src="@/app/assets/images/index/apply_empty.png" class="max-w-full" alt="">
|
<p class="text-[13px] text-[#666] mt-[8px] multi-hidden">代码生成</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
<img src="@/app/assets/images/tools/code.png" class="w-[256px] h-[148px]" />
|
||||||
<template #description>
|
</div>
|
||||||
<p class="flex items-center">
|
<div class="w-[256px] h-[260px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer" @click="toLink('/tools/list')">
|
||||||
<span>{{ t('descriptionLeft') }}</span>
|
<div class="flex-1 py-[19px] px-[24px] flex flex-col">
|
||||||
<el-link type="primary" @click="goRouter" class="mx-[5px]">{{ t('link') }}</el-link>
|
<span class="text-[16px] text-[#222] font-bold">数据字典</span>
|
||||||
<span>{{ t('descriptionRight') }}</span>
|
<p class="text-[13px] text-[#666] mt-[8px] multi-hidden">数据字典</p>
|
||||||
</p>
|
</div>
|
||||||
</template>
|
<img src="@/app/assets/images/tools/sys_dict_list.png" class="w-[256px] h-[148px]" />
|
||||||
</el-empty>
|
</div>
|
||||||
|
<div class="w-[256px] h-[260px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer" @click="toLink('/tools/update')">
|
||||||
|
<div class="flex-1 py-[19px] px-[24px] flex flex-col">
|
||||||
|
<span class="text-[16px] text-[#222] font-bold">更新缓存</span>
|
||||||
|
<p class="text-[13px] text-[#666] mt-[8px] multi-hidden">更新缓存</p>
|
||||||
|
</div>
|
||||||
|
<img src="@/app/assets/images/tools/tools_Update_cache.png" class="w-[256px] h-[148px]" />
|
||||||
|
</div>
|
||||||
|
<div class="w-[256px] h-[260px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer" @click="toLink('/tools/detection')">
|
||||||
|
<div class="flex-1 py-[19px] px-[24px] flex flex-col">
|
||||||
|
<span class="text-[16px] text-[#222] font-bold">环境监测</span>
|
||||||
|
<p class="text-[13px] text-[#666] mt-[8px] multi-hidden">环境监测</p>
|
||||||
|
</div>
|
||||||
|
<img src="@/app/assets/images/tools/tools_check_environment.png" class="w-[256px] h-[148px] cursor-pointer" />
|
||||||
|
</div>
|
||||||
|
<div class="w-[256px] h-[260px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer" @click="toLink('/tools/schedule')">
|
||||||
|
<div class="flex-1 py-[19px] px-[24px] flex flex-col">
|
||||||
|
<span class="text-[16px] text-[#222] font-bold">计划任务</span>
|
||||||
|
<p class="text-[13px] text-[#666] mt-[8px] multi-hidden">计划任务</p>
|
||||||
|
</div>
|
||||||
|
<img src="@/app/assets/images/tools/tools_schedule.png" class="w-[256px] h-[148px]" />
|
||||||
|
</div>
|
||||||
|
<div class="w-[256px] h-[260px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer" @click="toLink('/tools/admin')">
|
||||||
|
<div class="flex-1 py-[19px] px-[24px] flex flex-col">
|
||||||
|
<span class="text-[16px] text-[#222] font-bold">菜单管理</span>
|
||||||
|
<p class="text-[13px] text-[#666] mt-[8px] multi-hidden">菜单管理</p>
|
||||||
|
</div>
|
||||||
|
<img src="@/app/assets/images/tools/auth_menu.png" class="w-[256px] h-[148px]" />
|
||||||
|
</div>
|
||||||
|
<div class="w-[256px] h-[260px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer" @click="toLink('/tools/authorize')">
|
||||||
|
<div class="flex-1 py-[19px] px-[24px] flex flex-col">
|
||||||
|
<span class="text-[16px] text-[#222] font-bold">授权信息</span>
|
||||||
|
<p class="text-[13px] text-[#666] mt-[8px] multi-hidden">查看授权信息及重新认证授权</p>
|
||||||
|
</div>
|
||||||
|
<img src="@/app/assets/images/tools/app_auth.png" class="w-[256px] h-[148px]" />
|
||||||
|
</div>
|
||||||
|
<div class="w-[256px] h-[260px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer" @click="goRouter">
|
||||||
|
<div class="flex-1 py-[19px] px-[24px] flex flex-col">
|
||||||
|
<span class="text-[16px] text-[#222] font-bold">官方市场</span>
|
||||||
|
<p class="text-[13px] text-[#666] mt-[8px] multi-hidden">官方市场</p>
|
||||||
|
</div>
|
||||||
|
<img src="@/app/assets/images/tools/official_market.png" class="w-[256px] h-[148px]" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -41,60 +78,29 @@
|
|||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
import {findFirstValidRoute} from '@/router/routers'
|
import {findFirstValidRoute} from '@/router/routers'
|
||||||
import {UserFilled} from '@element-plus/icons-vue'
|
import {UserFilled} from '@element-plus/icons-vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
import useUserStore from '@/stores/modules/user'
|
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const toLink = (link)=>{
|
||||||
const loading = ref(true)
|
router.push(link)
|
||||||
const detail = reactive({
|
|
||||||
appList: []
|
|
||||||
})
|
|
||||||
const appLink: any = ref({})
|
|
||||||
|
|
||||||
const menus = computed(() => {
|
|
||||||
let obj = []
|
|
||||||
loading.value = true;
|
|
||||||
userStore.routers.forEach((item, index) => {
|
|
||||||
if (item.meta.key == 'tool' && item.children && item.children.length) {
|
|
||||||
item.children.forEach((childItem,childIndex) => {
|
|
||||||
if(childItem.meta.show == 1){
|
|
||||||
obj.push(childItem);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
loading.value = false;
|
|
||||||
return obj
|
|
||||||
})
|
|
||||||
|
|
||||||
const toLink = (data)=>{
|
|
||||||
router.push({ name: data.name })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const goRouter = () => {
|
const goRouter = () => {
|
||||||
window.open('https://www.niucloud.com/product')
|
window.open('https://www.niucloud.com/product')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped></style>
|
||||||
.main-container {
|
|
||||||
background: linear-gradient(180deg, rgba(253, 253, 253, 0.24) 0%, #FAFAFA 100%);
|
|
||||||
min-height: calc(100vh - 64px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.overview-top {
|
|
||||||
background-image: url('@/app/assets/images/index/overview.png');
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-item {
|
|
||||||
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.18);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<style>
|
<style>
|
||||||
.overview-empty .el-empty__image {
|
.tools-item-shadow{
|
||||||
width: auto !important;
|
box-shadow: 0px 0px 6px rgba(183, 183, 175, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
/* 多行超出隐藏 */
|
||||||
|
.multi-hidden {
|
||||||
|
word-break: break-all;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex border-t border-b main-wrap border-color w-full" :class="scene == 'select' ? 'h-[40vh]' : 'h-full'">
|
<div class="flex border-t border-b main-wrap border-color w-full" :class="scene == 'select' ? 'h-[430px]' : 'h-full'">
|
||||||
<!-- 分组 -->
|
<!-- 分组 -->
|
||||||
<div class="group-wrap w-[180px] p-[15px] h-full border-r border-color flex flex-col">
|
<div class="group-wrap w-[180px] p-[15px] h-full border-r border-color flex flex-col">
|
||||||
|
|
||||||
<el-input v-model="categoryParam.name" class="m-0" :placeholder="t('upload.attachmentCategoryPlaceholder')" clearable prefix-icon="Search" @input="getAttachmentCategoryList()"/>
|
<el-input v-model="categoryParam.name" class="m-0" :placeholder="t('upload.attachmentCategoryPlaceholder')" clearable prefix-icon="Search" @input="getAttachmentCategoryList()"/>
|
||||||
<div class="group-list flex-1 my-[10px]">
|
<div class="group-list flex-1 my-[10px]">
|
||||||
<el-scrollbar>
|
<el-scrollbar height="300px">
|
||||||
<div class="group-item p-[10px] leading-none text-xs rounded cursor-pointer" :class="{ active: attachmentParam.cate_id == 0 }" @click="attachmentParam.cate_id = 0">
|
<div class="group-item p-[10px] leading-none text-xs rounded cursor-pointer" :class="{ active: attachmentParam.cate_id == 0 }" @click="attachmentParam.cate_id = 0">
|
||||||
{{ t('selectPlaceholder') }}
|
{{ t('selectPlaceholder') }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -12,7 +12,8 @@
|
|||||||
<span class="cursor-pointer mr-[15px]" @click="goNiucloud">{{ t('niucloud') }}</span>
|
<span class="cursor-pointer mr-[15px]" @click="goNiucloud">{{ t('niucloud') }}</span>
|
||||||
<el-dropdown>
|
<el-dropdown>
|
||||||
<div class="userinfo flex h-full items-center">
|
<div class="userinfo flex h-full items-center">
|
||||||
<el-avatar :size="25" :icon="UserFilled" />
|
<el-avatar :size="25" :icon="UserFilled" v-if="!userStore.userInfo.head_img" />
|
||||||
|
<el-avatar :size="25" v-else :src="img(userStore.userInfo.head_img)" />
|
||||||
<div class="user-name pl-[8px] text-[#fff]">{{ userStore.userInfo.username }}</div>
|
<div class="user-name pl-[8px] text-[#fff]">{{ userStore.userInfo.username }}</div>
|
||||||
<icon name="element-ArrowDown" class="ml-[5px] !text-[#fff]" />
|
<icon name="element-ArrowDown" class="ml-[5px] !text-[#fff]" />
|
||||||
</div>
|
</div>
|
||||||
@ -53,10 +54,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { UserFilled } from '@element-plus/icons-vue'
|
||||||
import { computed, reactive, ref, onMounted, watch } from 'vue'
|
import { computed, reactive, ref, onMounted, watch } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
|
import { img } from '@/utils/common'
|
||||||
import {getEnv} from '@/app/api/sys'
|
import {getEnv} from '@/app/api/sys'
|
||||||
import { setUserInfo } from '@/app/api/personal'
|
import { setUserInfo } from '@/app/api/personal'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
@ -82,7 +85,7 @@ const goRouter = () => {
|
|||||||
|
|
||||||
// 跳转至开发者
|
// 跳转至开发者
|
||||||
const goDeveloperCenter = () => {
|
const goDeveloperCenter = () => {
|
||||||
router.push('/tools/addon')
|
router.push('/app_manage/tools')
|
||||||
}
|
}
|
||||||
|
|
||||||
const goNiucloud = () => {
|
const goNiucloud = () => {
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-container class="w-screen h-screen min-w-[1200px] flex flex-col">
|
<el-container class="w-screen h-screen min-w-[1200px] flex flex-col">
|
||||||
<layout-aside></layout-aside>
|
<layout-aside></layout-aside>
|
||||||
<el-container class="overview-top">
|
<el-container>
|
||||||
<el-header class="h-[60px]">
|
<el-header class="h-[60px]">
|
||||||
<layout-header></layout-header>
|
<layout-header></layout-header>
|
||||||
</el-header>
|
</el-header>
|
||||||
<el-main class="w-[1200px] m-auto">
|
<el-main class="p-0">
|
||||||
<el-scrollbar class="main-height">
|
<el-scrollbar class="main-height">
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
@ -23,11 +23,7 @@ import layoutAside from './components/aside/index.vue'
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.overview-top {
|
|
||||||
background-image: url('@/app/assets/images/index/overview.png');
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: cover;
|
|
||||||
}
|
|
||||||
.main-height{
|
.main-height{
|
||||||
height: calc(100vh - 120px);
|
height: calc(100vh - 120px);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,8 @@
|
|||||||
<div>
|
<div>
|
||||||
<el-dropdown @command="clickEvent" :tabindex="1">
|
<el-dropdown @command="clickEvent" :tabindex="1">
|
||||||
<div class="userinfo flex h-full items-center">
|
<div class="userinfo flex h-full items-center">
|
||||||
<el-avatar :size="25" :icon="UserFilled" />
|
<el-avatar :size="25" :icon="UserFilled" v-if="!userStore.userInfo.head_img" />
|
||||||
|
<el-avatar :size="25" v-else :src="img(userStore.userInfo.head_img)" />
|
||||||
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
||||||
<icon name="element-ArrowDown" class="ml-[5px]" />
|
<icon name="element-ArrowDown" class="ml-[5px]" />
|
||||||
</div>
|
</div>
|
||||||
@ -43,6 +44,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { UserFilled } from '@element-plus/icons-vue'
|
import { UserFilled } from '@element-plus/icons-vue'
|
||||||
|
import { img } from '@/utils/common'
|
||||||
import { computed, reactive, ref, onMounted, watch } from 'vue'
|
import { computed, reactive, ref, onMounted, watch } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
||||||
|
|||||||
@ -2,7 +2,8 @@
|
|||||||
<div>
|
<div>
|
||||||
<el-dropdown @command="clickEvent" :tabindex="1">
|
<el-dropdown @command="clickEvent" :tabindex="1">
|
||||||
<div class="userinfo flex h-full items-center">
|
<div class="userinfo flex h-full items-center">
|
||||||
<el-avatar :size="25" :icon="UserFilled" />
|
<el-avatar :size="25" :icon="UserFilled" v-if="!userStore.userInfo.head_img" />
|
||||||
|
<el-avatar :size="25" v-else :src="img(userStore.userInfo.head_img)" />
|
||||||
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
||||||
<icon name="element-ArrowDown" class="ml-[5px]" />
|
<icon name="element-ArrowDown" class="ml-[5px]" />
|
||||||
</div>
|
</div>
|
||||||
@ -40,6 +41,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { img } from '@/utils/common'
|
||||||
import { UserFilled } from '@element-plus/icons-vue'
|
import { UserFilled } from '@element-plus/icons-vue'
|
||||||
import { computed, reactive, ref, onMounted, watch } from 'vue'
|
import { computed, reactive, ref, onMounted, watch } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|||||||
@ -2,7 +2,8 @@
|
|||||||
<div>
|
<div>
|
||||||
<el-dropdown @command="clickEvent" :tabindex="1">
|
<el-dropdown @command="clickEvent" :tabindex="1">
|
||||||
<div class="userinfo flex h-full items-center">
|
<div class="userinfo flex h-full items-center">
|
||||||
<el-avatar :size="25" :icon="UserFilled" />
|
<el-avatar :size="25" :icon="UserFilled" v-if="!userStore.userInfo.head_img" />
|
||||||
|
<el-avatar :size="25" v-else :src="img(userStore.userInfo.head_img)" />
|
||||||
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
||||||
<icon name="element-ArrowDown" class="ml-[5px]" />
|
<icon name="element-ArrowDown" class="ml-[5px]" />
|
||||||
</div>
|
</div>
|
||||||
@ -46,6 +47,7 @@ import { computed, reactive, ref, onMounted, watch } from 'vue'
|
|||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
|
import { img } from '@/utils/common'
|
||||||
import {getEnv} from '@/app/api/sys'
|
import {getEnv} from '@/app/api/sys'
|
||||||
import { setUserInfo } from '@/app/api/personal'
|
import { setUserInfo } from '@/app/api/personal'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
|
|||||||
@ -1,17 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="m-[25px] w-[200px] bg-[#fff] aside-shadow app-aside-wrap">
|
<div class="mt-[20px] mb-[15px] mx-[10px] app-aside-wrap bg-[#fff]">
|
||||||
<el-menu :router="true" unique-opened="true" :default-active="String(route.name)">
|
<div class="flex flex-wrap items-center">
|
||||||
<template v-for="(item, index) in menus" :key="index">
|
<div v-for="(item, index) in menus" :key="index" :class="['border-[1px] border-solid my-[5px] border-[#E0E0E0] rounded-full py-[5px] px-[10px] cursor-pointer',{'mr-[20px]': index != menus.length-1},{'text-[#fff] bg-[#000] border-[#000]': item.name == route.name}]" @click="toLink(item)">
|
||||||
<el-menu-item v-if="item.meta.key != 'official_market'" @click="toLink(item)" :index="String(item.name)">
|
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto mr-[4px]" size="14px" :title="item.meta.title" />
|
||||||
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto mr-[6px]" size="16px" :title="item.meta.title" />
|
<span class="text-[14px]">{{ item.meta.title }}</span>
|
||||||
<span>{{ item.meta.title }}</span>
|
</div>
|
||||||
</el-menu-item>
|
</div>
|
||||||
<div class="el-menu-item" v-else @click="toLink(item)">
|
|
||||||
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto mr-[6px]" size="16px" :title="item.meta.title" />
|
|
||||||
<span class="text-[14px]">{{ item.meta.title }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-menu>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -52,9 +46,6 @@ import useUserStore from '@/stores/modules/user'
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.aside-shadow{
|
|
||||||
box-shadow: 0 0 10px 1px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
.app-aside-wrap{
|
.app-aside-wrap{
|
||||||
.el-menu-item{
|
.el-menu-item{
|
||||||
border-bottom: 1px solid #f1f1f1;
|
border-bottom: 1px solid #f1f1f1;
|
||||||
|
|||||||
@ -12,7 +12,8 @@
|
|||||||
<span class="cursor-pointer mr-[15px]" @click="goNiucloud">{{ t('niucloud') }}</span>
|
<span class="cursor-pointer mr-[15px]" @click="goNiucloud">{{ t('niucloud') }}</span>
|
||||||
<el-dropdown>
|
<el-dropdown>
|
||||||
<div class="userinfo flex h-full items-center">
|
<div class="userinfo flex h-full items-center">
|
||||||
<el-avatar :size="25" :icon="UserFilled" />
|
<el-avatar :size="25" :icon="UserFilled" v-if="!userStore.userInfo.head_img" />
|
||||||
|
<el-avatar :size="25" v-else :src="img(userStore.userInfo.head_img)" />
|
||||||
<div class="user-name pl-[8px] text-[#fff]">{{ userStore.userInfo.username }}</div>
|
<div class="user-name pl-[8px] text-[#fff]">{{ userStore.userInfo.username }}</div>
|
||||||
<icon name="element-ArrowDown" class="ml-[5px] !text-[#fff]" />
|
<icon name="element-ArrowDown" class="ml-[5px] !text-[#fff]" />
|
||||||
</div>
|
</div>
|
||||||
@ -26,7 +27,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog v-model="changePasswordDialog" title="修改密码" :before-close="handleClose">
|
<el-dialog v-model="changePasswordDialog" width="450px" title="修改密码" :before-close="handleClose">
|
||||||
<div>
|
<div>
|
||||||
<el-form :model="saveInfo" label-width="90px" ref="formRef" :rules="formRules" class="page-form">
|
<el-form :model="saveInfo" label-width="90px" ref="formRef" :rules="formRules" class="page-form">
|
||||||
<el-form-item :label="t('originalPassword')" prop="original_password">
|
<el-form-item :label="t('originalPassword')" prop="original_password">
|
||||||
@ -56,6 +57,7 @@ import { computed, reactive, ref, onMounted, watch } from 'vue'
|
|||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
|
import { img } from '@/utils/common'
|
||||||
import {getEnv} from '@/app/api/sys'
|
import {getEnv} from '@/app/api/sys'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
import { setUserInfo } from '@/app/api/personal'
|
import { setUserInfo } from '@/app/api/personal'
|
||||||
@ -80,7 +82,7 @@ const goRouter = () => {
|
|||||||
|
|
||||||
// 跳转至开发者
|
// 跳转至开发者
|
||||||
const goDeveloperCenter = () => {
|
const goDeveloperCenter = () => {
|
||||||
router.push('/tools/addon')
|
router.push('/app_manage/tools')
|
||||||
}
|
}
|
||||||
|
|
||||||
const goNiucloud = () => {
|
const goNiucloud = () => {
|
||||||
|
|||||||
@ -3,10 +3,10 @@
|
|||||||
<el-header class="h-[60px]">
|
<el-header class="h-[60px]">
|
||||||
<layout-header></layout-header>
|
<layout-header></layout-header>
|
||||||
</el-header>
|
</el-header>
|
||||||
<el-container class="overview-top">
|
<el-container class="flex flex-col px-[64px]">
|
||||||
<layout-aside></layout-aside>
|
<layout-aside></layout-aside>
|
||||||
|
|
||||||
<el-main class="p-0 box-shadow w-[1200px] m-[25px] ml-0 bg-[#fff]">
|
<el-main class="p-0 ml-0">
|
||||||
<el-scrollbar class="main-height">
|
<el-scrollbar class="main-height">
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
@ -30,9 +30,6 @@ import layoutAside from './components/aside/index.vue'
|
|||||||
background-size: cover;
|
background-size: cover;
|
||||||
}
|
}
|
||||||
.main-height{
|
.main-height{
|
||||||
height: calc(100vh - 120px);
|
height: calc(100vh - 175px);
|
||||||
}
|
|
||||||
.box-shadow{
|
|
||||||
box-shadow: 0 0 10px 1px rgba(151, 151, 151, 0.1);
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 3883393 */
|
font-family: "iconfont"; /* Project id 3883393 */
|
||||||
src: url('//at.alicdn.com/t/c/font_3883393_t7tf6zkctc.woff2?t=1697534072773') format('woff2'),
|
src: url('//at.alicdn.com/t/c/font_3883393_zbqffn9fec.woff2?t=1698204164945') format('woff2'),
|
||||||
url('//at.alicdn.com/t/c/font_3883393_t7tf6zkctc.woff?t=1697534072773') format('woff'),
|
url('//at.alicdn.com/t/c/font_3883393_zbqffn9fec.woff?t=1698204164945') format('woff'),
|
||||||
url('//at.alicdn.com/t/c/font_3883393_t7tf6zkctc.ttf?t=1697534072773') format('truetype');
|
url('//at.alicdn.com/t/c/font_3883393_zbqffn9fec.ttf?t=1698204164945') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,18 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.iconxiazai01:before {
|
||||||
|
content: "\ea38";
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconjingdiandingdan:before {
|
||||||
|
content: "\e6ea";
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconluxiandingdan:before {
|
||||||
|
content: "\e6eb";
|
||||||
|
}
|
||||||
|
|
||||||
.iconfapiaoguanli:before {
|
.iconfapiaoguanli:before {
|
||||||
content: "\e683";
|
content: "\e683";
|
||||||
}
|
}
|
||||||
|
|||||||