This commit is contained in:
owenchen committed 2026-10-23 15:15:53 +08:00
1 parent 6c86c59bdc
commit 31de6c4cd6
15 files changed
+1001 -666

No files matched your search

+21 -265
View File
@@ -7,7 +7,7 @@
*/
import { useLocale } from "uview-pro";
import { computed, ref } from "vue";
import { currentEndpoint, normalizeLanUrl, saveEndpoint, testEndpoint } from "@/common/apiEndpoint";
import { currentEndpoint } from "@/common/apiEndpoint";
import { APP_INFO } from "@/common/constant";
import { useAuthGuard, useThemeGradient, useThemeTokens } from "@/composables";
import { usePermission } from "@/permission/permission-context";
@@ -51,61 +51,36 @@ function goTheme(): void {
uni.navigateTo({ url: pageUrl("themePage") });
}
// ===== 访问线路(App 手动切换公网/内网直连;仅影响后续请求,不中断在途传输) =====
// ===== 访问线路(App 手动切换公网/内网直连;弹层组件与登录页共用) =====
const linePopupVisible = ref(false);
/** 当前生效线路(保存后刷新展示) */
const lineSetting = ref(currentEndpoint());
/** 弹层草稿:确认前不动真实线路,取消即作废 */
const lineModeDraft = ref<"wan" | "lan">("wan");
const lineLanDraft = ref("");
const lineTesting = ref(false);
const lineTestResult = ref<"" | "ok" | "fail">("");
/** 当前线路展示文案:公网 / 内网直连(附地址) */
/** 当前线路展示文案:公网(附自定义地址)/ 内网直连(附地址) */
const currentLineLabel = computed(() => {
const setting = lineSetting.value;
return setting.mode === "lan" ? `${t("MinePage.lineLan")} · ${setting.lanUrl}` : t("MinePage.lineWan");
if (setting.mode === "lan") {
return `${t("MinePage.lineLan")} · ${setting.lanUrl}`;
}
return setting.wanUrl ? `${t("MinePage.lineWan")} · ${setting.wanUrl}` : t("MinePage.lineWan");
});
/** 打开线路弹层:草稿回填当前设置,清掉上次测活结果 */
/** 打开线路弹层:草稿回填由组件内部完成,这里刷新展示快照并展开 */
function openLinePopup(): void {
const setting = currentEndpoint();
lineModeDraft.value = setting.mode;
lineLanDraft.value = setting.lanUrl;
lineTestResult.value = "";
lineSetting.value = currentEndpoint();
linePopupVisible.value = true;
}
/** 测试内网地址连通性:用 RSA 公钥接口探活(与登录首调同源) */
async function handleTestLine(): Promise<void> {
if (lineTesting.value) {
return;
}
const url = normalizeLanUrl(lineLanDraft.value);
if (!url) {
uni.showToast({ title: t("MinePage.lineInvalid"), icon: "none" });
return;
}
lineTesting.value = true;
lineTestResult.value = "";
const ok = await testEndpoint(url);
lineTesting.value = false;
lineTestResult.value = ok ? "ok" : "fail";
if (!ok) {
uni.showToast({ title: t("MinePage.lineTestFail"), icon: "none" });
}
}
/** 保存线路:内网模式地址必填且合法;生效只影响后续请求,各页切回时自然按新线路拉数据 */
function handleSaveLine(): void {
if (lineModeDraft.value === "lan" && !normalizeLanUrl(lineLanDraft.value)) {
uni.showToast({ title: t("MinePage.lineInvalid"), icon: "none" });
return;
}
saveEndpoint({ mode: lineModeDraft.value, lanUrl: lineLanDraft.value });
/** 弹层保存后回调:刷新展示;服务器真的变了 → 本地令牌对新服务器无意义,清登录态回登录页重新认证 */
function onLineSaved(payload: { changed: boolean }): void {
lineSetting.value = currentEndpoint();
linePopupVisible.value = false;
uni.showToast({ title: t("MinePage.lineSaved"), icon: "none" });
if (!payload.changed) {
uni.showToast({ title: t("MinePage.lineSaved"), icon: "none" });
return;
}
loginProfileStore.clearStorage();
uni.showToast({ title: t("MinePage.lineSavedRelogin"), icon: "none" });
setTimeout(() => uni.reLaunch({ url: pageUrl("login") }), 1200);
}
/** 进入「安全管理」枢纽页:权限体系等基础设定的聚合入口 */
@@ -303,77 +278,9 @@ async function handleLogout(): Promise<void> {
</view>
</view>
<!-- 访问线路弹层:公网/内网单选 + 内网地址手填 + 测连通(仅 App 有入口) -->
<!-- 访问线路弹层:与登录页共用的组件,改地址后由 onLineSaved 决定是否登出(仅 App 有入口) -->
<!-- #ifdef APP-PLUS -->
<u-popup :model-value="linePopupVisible" mode="bottom" round="24" @close="linePopupVisible = false">
<view class="line-sheet">
<text class="line-sheet__title">
{{ t("MinePage.accessLine") }}
</text>
<text class="line-sheet__hint">
{{ t("MinePage.lineHint") }}
</text>
<!-- 公网:默认线路,随时随地可用 -->
<view class="line-option" :class="{ 'line-option--active': lineModeDraft === 'wan' }"
@tap="lineModeDraft = 'wan'">
<view class="line-option__body">
<text class="line-option__name">
{{ t("MinePage.lineWan") }}
</text>
<text class="line-option__desc">
{{ t("MinePage.lineWanDesc") }}
</text>
</view>
<view class="line-option__radio" :class="{ 'line-option__radio--on': lineModeDraft === 'wan' }" />
</view>
<!-- 内网直连:需与服务器同局域网,地址手填 -->
<view class="line-option" :class="{ 'line-option--active': lineModeDraft === 'lan' }"
@tap="lineModeDraft = 'lan'">
<view class="line-option__body">
<text class="line-option__name">
{{ t("MinePage.lineLan") }}
</text>
<text class="line-option__desc">
{{ t("MinePage.lineLanDesc") }}
</text>
</view>
<view class="line-option__radio" :class="{ 'line-option__radio--on': lineModeDraft === 'lan' }" />
</view>
<!-- 内网地址:选中内网才展开;测连通用免鉴权的 RSA 公钥接口 -->
<view v-if="lineModeDraft === 'lan'" class="line-lan">
<input v-model="lineLanDraft" class="line-lan__input" :placeholder="t('MinePage.lineLanPlaceholder')"
placeholder-class="line-lan__ph">
<view class="line-lan__test" @tap="handleTestLine">
<text class="line-lan__test-text">
{{ lineTesting ? t("MinePage.lineTesting") : t("MinePage.lineTest") }}
</text>
</view>
</view>
<text v-if="lineModeDraft === 'lan' && lineTestResult === 'ok'" class="line-lan__result line-lan__result--ok">
{{ t("MinePage.lineTestOk") }}
</text>
<text v-else-if="lineModeDraft === 'lan' && lineTestResult === 'fail'"
class="line-lan__result line-lan__result--fail">
{{ t("MinePage.lineTestFail") }}
</text>
<view class="line-sheet__actions">
<view class="line-sheet__btn line-sheet__btn--ghost" @tap="linePopupVisible = false">
<text class="line-sheet__btn-text line-sheet__btn-text--ghost">
{{ t("MinePage.lineCancel") }}
</text>
</view>
<view class="line-sheet__btn line-sheet__btn--primary" @tap="handleSaveLine">
<text class="line-sheet__btn-text">
{{ t("MinePage.lineSave") }}
</text>
</view>
</view>
</view>
</u-popup>
<endpoint-setting-popup v-model="linePopupVisible" @saved="onLineSaved" />
<!-- #endif -->
</app-page>
</template>
@@ -492,156 +399,5 @@ async function handleLogout(): Promise<void> {
color: #1f2329;
}
/* ===== 访问线路弹层(底部抽屉,同 file-action-sheet 风格) ===== */
.line-sheet {
padding: 32rpx 24rpx calc(24rpx + env(safe-area-inset-bottom));
background-color: #f5f6f7;
}
.line-sheet__title {
font-size: 32rpx;
font-weight: 600;
color: #1f2329;
}
.line-sheet__hint {
display: block;
margin-top: 8rpx;
font-size: 24rpx;
color: #9aa0a6;
}
/* 单选行:白卡;选中态用内阴影描边(不改变布局尺寸) */
.line-option {
display: flex;
align-items: center;
margin-top: 20rpx;
padding: 24rpx;
border-radius: 20rpx;
background-color: #ffffff;
}
.line-option--active {
box-shadow: 0 0 0 2rpx var(--fg-primary, #ff7d1f) inset;
}
.line-option__body {
display: flex;
flex: 1;
flex-direction: column;
gap: 6rpx;
}
.line-option__name {
font-size: 28rpx;
font-weight: 600;
color: #1f2329;
}
.line-option__desc {
font-size: 24rpx;
color: #9aa0a6;
}
.line-option__radio {
box-sizing: border-box;
width: 36rpx;
height: 36rpx;
margin-left: 16rpx;
border: 2rpx solid #d4d7dc;
border-radius: 50%;
}
.line-option__radio--on {
border-color: var(--fg-primary, #ff7d1f);
background: radial-gradient(circle, var(--fg-primary, #ff7d1f) 0 42%, transparent 48%);
}
/* 内网地址:输入框 + 测试连接一行 */
.line-lan {
display: flex;
align-items: center;
gap: 16rpx;
margin-top: 20rpx;
}
.line-lan__input {
flex: 1;
height: 76rpx;
padding: 0 20rpx;
border-radius: 16rpx;
font-size: 26rpx;
color: #1f2329;
background-color: #ffffff;
}
.line-lan__ph {
color: #c0c4cc;
}
.line-lan__test {
display: flex;
align-items: center;
justify-content: center;
height: 76rpx;
padding: 0 24rpx;
border-radius: 16rpx;
background-color: #ffffff;
}
.line-lan__test-text {
font-size: 26rpx;
font-weight: 600;
color: var(--fg-primary, #ff7d1f);
}
.line-lan__result {
display: block;
margin-top: 12rpx;
font-size: 24rpx;
}
.line-lan__result--ok {
color: #52c41a;
}
.line-lan__result--fail {
color: #fa3534;
}
/* 底部双按钮:取消(描边)/ 保存(主题渐变) */
.line-sheet__actions {
display: flex;
gap: 20rpx;
margin-top: 32rpx;
}
.line-sheet__btn {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
height: 88rpx;
border-radius: 999rpx;
}
.line-sheet__btn--ghost {
border: 2rpx solid #d4d7dc;
background-color: #ffffff;
}
.line-sheet__btn--primary {
background: var(--fg-gradient, linear-gradient(135deg, #ff9a3d, #ff7d1f));
box-shadow: var(--fg-shadow, 0 6rpx 16rpx rgba(255, 125, 31, 0.35));
}
.line-sheet__btn-text {
font-size: 28rpx;
font-weight: 600;
color: #ffffff;
}
.line-sheet__btn-text--ghost {
color: #4e5969;
}
/* 访问线路弹层样式已随组件迁至 components/endpoint-setting-popup/endpoint-setting-popup.vue */
</style>