fix(appstore): Handle redirection in app store (#8184)

This commit is contained in:
zhengkunwang 2025-03-18 18:07:01 +08:00 committed by GitHub
parent 727c6e6d32
commit be76d25b58
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 73 additions and 37 deletions

View file

@ -4,6 +4,7 @@ import (
"crypto" "crypto"
"encoding/json" "encoding/json"
"github.com/go-acme/lego/v4/providers/dns/clouddns" "github.com/go-acme/lego/v4/providers/dns/clouddns"
"github.com/go-acme/lego/v4/providers/dns/freemyip"
"github.com/go-acme/lego/v4/providers/dns/huaweicloud" "github.com/go-acme/lego/v4/providers/dns/huaweicloud"
"github.com/go-acme/lego/v4/providers/dns/rainyun" "github.com/go-acme/lego/v4/providers/dns/rainyun"
"github.com/go-acme/lego/v4/providers/dns/volcengine" "github.com/go-acme/lego/v4/providers/dns/volcengine"
@ -80,6 +81,7 @@ const (
RainYun DnsType = "RainYun" RainYun DnsType = "RainYun"
Volcengine DnsType = "Volcengine" Volcengine DnsType = "Volcengine"
HuaweiCloud DnsType = "HuaweiCloud" HuaweiCloud DnsType = "HuaweiCloud"
FreeMyIP DnsType = "FreeMyIP"
) )
type DNSParam struct { type DNSParam struct {
@ -211,6 +213,12 @@ func (c *AcmeClient) UseDns(dnsType DnsType, params string, websiteSSL model.Web
huaweiCloudConfig.PollingInterval = pollingInterval huaweiCloudConfig.PollingInterval = pollingInterval
huaweiCloudConfig.TTL = int32(ttl) huaweiCloudConfig.TTL = int32(ttl)
p, err = huaweicloud.NewDNSProviderConfig(huaweiCloudConfig) p, err = huaweicloud.NewDNSProviderConfig(huaweiCloudConfig)
case FreeMyIP:
freeMyIpConfig := freemyip.NewDefaultConfig()
freeMyIpConfig.Token = param.Token
freeMyIpConfig.PropagationTimeout = propagationTimeout
freeMyIpConfig.PollingInterval = pollingInterval
p, err = freemyip.NewDNSProviderConfig(freeMyIpConfig)
} }
if err != nil { if err != nil {
return err return err

View file

@ -162,7 +162,6 @@ const acceptParams = (params: DialogProps): void => {
detailName.value = params.detailName; detailName.value = params.detailName;
backupVisible.value = true; backupVisible.value = true;
status.value = params.status; status.value = params.status;
console.log(type);
search(); search();
}; };
const handleClose = () => { const handleClose = () => {

View file

@ -2,7 +2,7 @@
<div> <div>
<DialogPro v-model="open" :title="$t('app.checkTitle')" size="small"> <DialogPro v-model="open" :title="$t('app.checkTitle')" size="small">
<el-alert :closable="false" :title="$t('setting.systemIPWarning')" type="info"> <el-alert :closable="false" :title="$t('setting.systemIPWarning')" type="info">
<el-link icon="Position" @click="goRouter('/settings/panel')" type="primary"> <el-link icon="Position" @click="jumpToPath(router, '/settings/panel')" type="primary">
{{ $t('firewall.quickJump') }} {{ $t('firewall.quickJump') }}
</el-link> </el-link>
</el-alert> </el-alert>
@ -19,6 +19,7 @@ import { ref } from 'vue';
import { getSettingInfo } from '@/api/modules/setting'; import { getSettingInfo } from '@/api/modules/setting';
import i18n from '@/lang'; import i18n from '@/lang';
import { MsgError, MsgWarning } from '@/utils/message'; import { MsgError, MsgWarning } from '@/utils/message';
import { jumpToPath } from '@/utils/util';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
const router = useRouter(); const router = useRouter();
@ -56,9 +57,5 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
} }
}; };
const goRouter = async (path: string) => {
router.push({ path: path });
};
defineExpose({ acceptParams }); defineExpose({ acceptParams });
</script> </script>

View file

@ -207,6 +207,10 @@ export const DNSTypes = [
label: 'GoDaddy', label: 'GoDaddy',
value: 'Godaddy', value: 'Godaddy',
}, },
{
label: 'FreeMyIP',
value: 'FreeMyIP',
},
{ {
label: i18n.global.t('website.rainyun'), label: i18n.global.t('website.rainyun'),
value: 'RainYun', value: 'RainYun',

View file

@ -251,9 +251,7 @@ const checkTask = async () => {
try { try {
const res = await countExecutingTask(); const res = await countExecutingTask();
taskCount.value = res.data; taskCount.value = res.data;
} catch (error) { } catch (error) {}
console.error(error);
}
}; };
const openTask = () => { const openTask = () => {

View file

@ -42,9 +42,11 @@ router.beforeEach((to, from, next) => {
if (to.path === '/apps/all' && to.query.install != undefined) { if (to.path === '/apps/all' && to.query.install != undefined) {
return next(); return next();
} }
// if (to.query.uncached != undefined) { if (to.query.uncached != undefined) {
// return next(); const query = { ...to.query };
// } delete query.uncached;
return next({ path: to.path, query });
}
const activeMenuKey = 'cachedRoute' + (to.meta.activeMenu || ''); const activeMenuKey = 'cachedRoute' + (to.meta.activeMenu || '');
const cachedRoute = localStorage.getItem(activeMenuKey); const cachedRoute = localStorage.getItem(activeMenuKey);

View file

@ -776,3 +776,23 @@ export async function loadJson(lang: string): Promise<Object> {
throw new Error(`Language file not found: ${lang}`); throw new Error(`Language file not found: ${lang}`);
} }
} }
export const jumpToPath = (router: any, path: string) => {
router.push({ path: path, query: { uncached: 'true' } });
};
export const toLink = (link: string) => {
const ipv6Regex = /^https?:\/\/([a-f0-9:]+):(\d+)(\/?.*)?$/i;
try {
if (ipv6Regex.test(link)) {
const match = link.match(ipv6Regex);
if (match) {
const ipv6 = match[1];
const port = match[2];
const path = match[3] || '';
link = `${link.startsWith('https') ? 'https' : 'http'}://[${ipv6}]:${port}${path}`;
}
}
window.open(link, '_blank');
} catch (e) {}
};

View file

@ -24,7 +24,7 @@
</el-button> </el-button>
</div> </div>
<div class="inline"> <div class="inline">
<el-dropdown> <el-dropdown v-if="tags.length > 7">
<el-button <el-button
class="tag-button" class="tag-button"
:type="moreTag !== '' ? 'primary' : ''" :type="moreTag !== '' ? 'primary' : ''"

View file

@ -74,7 +74,12 @@
<template #title> <template #title>
<span class="flx-align-center"> <span class="flx-align-center">
{{ $t('app.installHelper') }} {{ $t('app.installHelper') }}
<el-link class="ml-5" icon="Position" @click="quickJump()" type="primary"> <el-link
class="ml-5"
icon="Position"
@click="jumpToPath(router, '/containers/setting')"
type="primary"
>
{{ $t('firewall.quickJump') }} {{ $t('firewall.quickJump') }}
</el-link> </el-link>
   
@ -103,6 +108,7 @@
<el-col :xs="3" :sm="3" :md="3" :lg="4" :xl="4"> <el-col :xs="3" :sm="3" :md="3" :lg="4" :xl="4">
<div class="icon"> <div class="icon">
<el-avatar <el-avatar
@click="openDetail(installed.appKey)"
shape="square" shape="square"
:size="66" :size="66"
:src="'data:image/png;base64,' + installed.icon" :src="'data:image/png;base64,' + installed.icon"
@ -257,7 +263,7 @@
placement="top-start" placement="top-start"
trigger="hover" trigger="hover"
v-if="installed.appType == 'website'" v-if="installed.appType == 'website'"
:width="260" :width="400"
> >
<template #reference> <template #reference>
<el-button plain icon="Promotion" size="small"> <el-button plain icon="Promotion" size="small">
@ -358,6 +364,7 @@
<AppIgnore ref="ignoreRef" @close="search" /> <AppIgnore ref="ignoreRef" @close="search" />
<ComposeLogs ref="composeLogRef" /> <ComposeLogs ref="composeLogRef" />
<TaskLog ref="taskLogRef" /> <TaskLog ref="taskLogRef" />
<Detail ref="detailRef" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -383,11 +390,12 @@ import AppIgnore from './ignore/index.vue';
import ComposeLogs from '@/components/log/compose/index.vue'; import ComposeLogs from '@/components/log/compose/index.vue';
import { App } from '@/api/interface/app'; import { App } from '@/api/interface/app';
import Status from '@/components/status/index.vue'; import Status from '@/components/status/index.vue';
import { getAge } from '@/utils/util'; import { getAge, jumpToPath, toLink } from '@/utils/util';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { MsgSuccess } from '@/utils/message'; import { MsgSuccess } from '@/utils/message';
import { toFolder } from '@/global/business'; import { toFolder } from '@/global/business';
import TaskLog from '@/components/log/task/index.vue'; import TaskLog from '@/components/log/task/index.vue';
import Detail from '@/views/app-store/detail/index.vue';
const data = ref<any>(); const data = ref<any>();
const loading = ref(false); const loading = ref(false);
@ -430,6 +438,7 @@ const activeName = ref(i18n.global.t('app.installed'));
const mode = ref('installed'); const mode = ref('installed');
const moreTag = ref(''); const moreTag = ref('');
const defaultLink = ref(''); const defaultLink = ref('');
const detailRef = ref();
const options = { const options = {
modifiers: [ modifiers: [
@ -443,6 +452,10 @@ const options = {
], ],
}; };
const openDetail = (key: string) => {
detailRef.value.acceptParams(key, 'install');
};
const sync = () => { const sync = () => {
ElMessageBox.confirm(i18n.global.t('app.syncAllAppHelper'), i18n.global.t('commons.button.sync'), { ElMessageBox.confirm(i18n.global.t('app.syncAllAppHelper'), i18n.global.t('commons.button.sync'), {
confirmButtonText: i18n.global.t('commons.button.confirm'), confirmButtonText: i18n.global.t('commons.button.confirm'),
@ -678,10 +691,6 @@ const isAppErr = (row: any) => {
return row.status.includes('Err') || row.status.includes('Error') || row.status.includes('UnHealthy'); return row.status.includes('Err') || row.status.includes('Error') || row.status.includes('UnHealthy');
}; };
const quickJump = () => {
router.push({ name: 'ContainerSetting' });
};
const openLog = (row: any) => { const openLog = (row: any) => {
switch (row.status) { switch (row.status) {
case 'Installing': case 'Installing':
@ -692,10 +701,6 @@ const openLog = (row: any) => {
} }
}; };
const toLink = (link: string) => {
window.open(link, '_blank');
};
const getConfig = async () => { const getConfig = async () => {
try { try {
const res = await getAppStoreConfig(); const res = await getAppStoreConfig();

View file

@ -47,7 +47,7 @@ interface DialogProps {
const acceptParams = (config: DialogProps): void => { const acceptParams = (config: DialogProps): void => {
form.defaultDomain = config.domain; form.defaultDomain = config.domain;
protocol.value; protocol.value = config.protocol;
drawerVisible.value = true; drawerVisible.value = true;
}; };

View file

@ -31,7 +31,7 @@
<el-link <el-link
style="font-size: 12px; margin-left: 5px" style="font-size: 12px; margin-left: 5px"
icon="Position" icon="Position"
@click="goRouter('/settings/safe')" @click="jumpToPath(router, '/settings/safe')"
type="primary" type="primary"
> >
{{ $t('firewall.quickJump') }} {{ $t('firewall.quickJump') }}
@ -49,19 +49,23 @@
<el-col :span="6"> <el-col :span="6">
<span>{{ $t('menu.website') }}</span> <span>{{ $t('menu.website') }}</span>
<div class="count"> <div class="count">
<span @click="goRouter('/websites')">{{ baseInfo?.websiteNumber }}</span> <span @click="jumpToPath(router, '/websites')">
{{ baseInfo?.websiteNumber }}
</span>
</div> </div>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<span>{{ $t('menu.database') }} - {{ $t('commons.table.all') }}</span> <span>{{ $t('menu.database') }} - {{ $t('commons.table.all') }}</span>
<div class="count"> <div class="count">
<span @click="goRouter('/databases')">{{ baseInfo?.databaseNumber }}</span> <span @click="jumpToPath(router, '/databases')">
{{ baseInfo?.databaseNumber }}
</span>
</div> </div>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<span>{{ $t('menu.cronjob') }}</span> <span>{{ $t('menu.cronjob') }}</span>
<div class="count"> <div class="count">
<span @click="goRouter('/cronjobs')"> <span @click="jumpToPath(router, '/cronjobs')">
{{ baseInfo?.cronjobNumber }} {{ baseInfo?.cronjobNumber }}
</span> </span>
</div> </div>
@ -69,7 +73,7 @@
<el-col :span="6"> <el-col :span="6">
<span>{{ $t('home.appInstalled') }}</span> <span>{{ $t('home.appInstalled') }}</span>
<div class="count"> <div class="count">
<span @click="goRouter('/apps/installed')"> <span @click="jumpToPath(router, '/apps/installed')">
{{ baseInfo?.appInstalledNumber }} {{ baseInfo?.appInstalledNumber }}
</span> </span>
</div> </div>
@ -266,7 +270,7 @@ import LicenseImport from '@/components/license-import/index.vue';
import CardWithHeader from '@/components/card-with-header/index.vue'; import CardWithHeader from '@/components/card-with-header/index.vue';
import i18n from '@/lang'; import i18n from '@/lang';
import { Dashboard } from '@/api/interface/dashboard'; import { Dashboard } from '@/api/interface/dashboard';
import { dateFormatForSecond, computeSize, computeSizeFromKBs, loadUpTime } from '@/utils/util'; import { dateFormatForSecond, computeSize, computeSizeFromKBs, loadUpTime, jumpToPath } from '@/utils/util';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { loadBaseInfo, loadCurrentInfo } from '@/api/modules/dashboard'; import { loadBaseInfo, loadCurrentInfo } from '@/api/modules/dashboard';
import { getIOOptions, getNetworkOptions } from '@/api/modules/host'; import { getIOOptions, getNetworkOptions } from '@/api/modules/host';
@ -382,10 +386,6 @@ const changeOption = async () => {
loadData(); loadData();
}; };
const goRouter = async (path: string) => {
router.push({ path: path });
};
const onLoadNetworkOptions = async () => { const onLoadNetworkOptions = async () => {
const res = await getNetworkOptions(); const res = await getNetworkOptions();
netOptions.value = res.data; netOptions.value = res.data;

View file

@ -221,7 +221,6 @@ const onSubmit = async () => {
handleClose(); handleClose();
MsgSuccess(i18n.global.t('commons.msg.operationSuccess')); MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
} catch (error) { } catch (error) {
console.error(error);
} finally { } finally {
loading.value = false; loading.value = false;
} }

View file

@ -88,7 +88,6 @@
> >
<el-input v-model.trim="account.authorization['apiKey']"></el-input> <el-input v-model.trim="account.authorization['apiKey']"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="API User" prop="authorization.apiUser" v-if="account.type === 'NameCheap'"> <el-form-item label="API User" prop="authorization.apiUser" v-if="account.type === 'NameCheap'">
<el-input v-model.trim="account.authorization['apiUser']"></el-input> <el-input v-model.trim="account.authorization['apiUser']"></el-input>
</el-form-item> </el-form-item>
@ -103,6 +102,11 @@
<el-input v-model.trim="account.authorization['token']"></el-input> <el-input v-model.trim="account.authorization['token']"></el-input>
</el-form-item> </el-form-item>
</div> </div>
<div v-if="account.type === 'FreeMyIP'">
<el-form-item label="Token" prop="authorization.token">
<el-input v-model.trim="account.authorization['token']"></el-input>
</el-form-item>
</div>
</el-form> </el-form>
</el-col> </el-col>
</el-row> </el-row>