完善桌面端交互体验与发布检查
This commit is contained in:
@@ -70,16 +70,34 @@
|
||||
<h4>客户端与通知</h4>
|
||||
</div>
|
||||
<el-form-item v-if="isDesktop" label="系统通知">
|
||||
<el-switch
|
||||
v-model="desktopNotificationsEnabled"
|
||||
:loading="desktopNotificationLoading"
|
||||
@change="onDesktopNotificationChange"
|
||||
/>
|
||||
<span class="desktop-setting-hint">仅推送不含项目详情的文件更新提示</span>
|
||||
<div class="desktop-setting-stack">
|
||||
<div class="desktop-setting-row">
|
||||
<el-switch
|
||||
v-model="desktopNotificationsEnabled"
|
||||
:loading="desktopNotificationLoading"
|
||||
@change="onDesktopNotificationChange"
|
||||
/>
|
||||
<el-tag size="small" :type="notificationPermissionTagType">{{ notificationPermissionText }}</el-tag>
|
||||
</div>
|
||||
<span class="desktop-setting-hint">仅推送不含项目详情的文件更新提示</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="isDesktop && desktopUpdaterAvailable" label="桌面更新">
|
||||
<div class="desktop-setting-row">
|
||||
<el-button size="small" :loading="desktopUpdateChecking" @click="checkDesktopUpdateNow">
|
||||
检查更新
|
||||
</el-button>
|
||||
<span class="desktop-setting-hint">正式版本会按发布源检查签名更新</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="客户端信息">
|
||||
<div class="client-metadata">
|
||||
<code>{{ clientMetadataText }}</code>
|
||||
<div class="client-metadata-panel">
|
||||
<dl class="client-metadata-list">
|
||||
<template v-for="row in clientMetadataRows" :key="row.label">
|
||||
<dt>{{ row.label }}</dt>
|
||||
<dd>{{ row.value }}</dd>
|
||||
</template>
|
||||
</dl>
|
||||
<el-button size="small" @click="copyClientMetadata">复制</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
@@ -106,12 +124,18 @@ import {
|
||||
} from "../api/desktopNotifications";
|
||||
import { useAuthStore } from "../store/auth";
|
||||
import {
|
||||
clientRuntime,
|
||||
getAppMetadata,
|
||||
getDesktopServerUrl,
|
||||
getNotificationPermission,
|
||||
isDesktopUpdaterAvailable,
|
||||
isTauriRuntime,
|
||||
pickFiles,
|
||||
requestNotificationPermission,
|
||||
type NotificationPermissionState,
|
||||
} from "../runtime";
|
||||
import { triggerDesktopNotificationPoll } from "../session/desktopNotificationManager";
|
||||
import { checkDesktopUpdateAndPrompt } from "../session/desktopUpdateManager";
|
||||
import { TEXT, requiredMessage } from "../locales";
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -122,14 +146,29 @@ const emit = defineEmits<{
|
||||
const auth = useAuthStore();
|
||||
const isDesktop = isTauriRuntime();
|
||||
const clientMetadata = getAppMetadata();
|
||||
const clientMetadataText = [
|
||||
`${clientMetadata.clientType} ${clientMetadata.version}`,
|
||||
clientMetadata.platform,
|
||||
clientMetadata.channel,
|
||||
clientMetadata.commit,
|
||||
].join(" · ");
|
||||
const desktopCapabilities = clientRuntime.capabilities();
|
||||
const desktopUpdaterAvailable = isDesktopUpdaterAvailable();
|
||||
const clientMetadataRows = [
|
||||
{ label: "客户端", value: `${clientMetadata.clientType} ${clientMetadata.version}` },
|
||||
{ label: "平台", value: clientMetadata.platform },
|
||||
{ label: "构建通道", value: clientMetadata.channel },
|
||||
{ label: "提交", value: clientMetadata.commit },
|
||||
{ label: "服务器", value: getDesktopServerUrl() || "未配置" },
|
||||
{
|
||||
label: "能力",
|
||||
value: [
|
||||
desktopCapabilities.secureSessionStorage ? "安全会话" : "浏览器会话",
|
||||
desktopCapabilities.nativeFiles ? "原生文件" : "浏览器文件",
|
||||
desktopCapabilities.systemNotifications ? "系统通知" : "无系统通知",
|
||||
desktopCapabilities.automaticUpdates ? "自动更新" : "无自动更新",
|
||||
].join(" / "),
|
||||
},
|
||||
];
|
||||
const clientMetadataText = clientMetadataRows.map((row) => `${row.label}: ${row.value}`).join("\n");
|
||||
const desktopNotificationsEnabled = ref(false);
|
||||
const desktopNotificationLoading = ref(false);
|
||||
const desktopUpdateChecking = ref(false);
|
||||
const notificationPermission = ref<NotificationPermissionState>("unsupported");
|
||||
const formRef = ref<FormInstance>();
|
||||
const submitting = ref(false);
|
||||
const form = reactive({
|
||||
@@ -210,10 +249,26 @@ const loadProfile = async () => {
|
||||
|
||||
const loadDesktopNotificationSubscription = async () => {
|
||||
if (!isDesktop) return;
|
||||
notificationPermission.value = await getNotificationPermission().catch(() => "unsupported");
|
||||
const { data } = await getDesktopNotificationSubscription();
|
||||
desktopNotificationsEnabled.value = data.enabled;
|
||||
};
|
||||
|
||||
const notificationPermissionText = computed(() => {
|
||||
if (!isDesktop) return "不可用";
|
||||
if (notificationPermission.value === "granted") return "系统已允许";
|
||||
if (notificationPermission.value === "denied") return "系统已拒绝";
|
||||
if (notificationPermission.value === "prompt") return "等待授权";
|
||||
return "不可用";
|
||||
});
|
||||
|
||||
const notificationPermissionTagType = computed<"success" | "warning" | "danger" | "info">(() => {
|
||||
if (notificationPermission.value === "granted") return "success";
|
||||
if (notificationPermission.value === "denied") return "danger";
|
||||
if (notificationPermission.value === "prompt") return "warning";
|
||||
return "info";
|
||||
});
|
||||
|
||||
const onDesktopNotificationChange = async (value: string | number | boolean) => {
|
||||
if (!isDesktop || desktopNotificationLoading.value) return;
|
||||
desktopNotificationLoading.value = true;
|
||||
@@ -221,6 +276,7 @@ const onDesktopNotificationChange = async (value: string | number | boolean) =>
|
||||
const enable = Boolean(value);
|
||||
if (enable) {
|
||||
const permission = await requestNotificationPermission();
|
||||
notificationPermission.value = permission;
|
||||
if (permission !== "granted") {
|
||||
desktopNotificationsEnabled.value = false;
|
||||
ElMessage.warning("系统通知权限未开启,请在系统设置中允许 CTMS 通知");
|
||||
@@ -239,10 +295,24 @@ const onDesktopNotificationChange = async (value: string | number | boolean) =>
|
||||
};
|
||||
|
||||
const copyClientMetadata = async () => {
|
||||
if (!navigator.clipboard?.writeText) {
|
||||
ElMessage.warning("当前环境无法访问剪贴板");
|
||||
return;
|
||||
}
|
||||
await navigator.clipboard.writeText(clientMetadataText);
|
||||
ElMessage.success("客户端信息已复制");
|
||||
};
|
||||
|
||||
const checkDesktopUpdateNow = async () => {
|
||||
if (desktopUpdateChecking.value) return;
|
||||
desktopUpdateChecking.value = true;
|
||||
try {
|
||||
await checkDesktopUpdateAndPrompt({ notifyWhenCurrent: true });
|
||||
} finally {
|
||||
desktopUpdateChecking.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (!formRef.value) return;
|
||||
await formRef.value.validate(async (valid) => {
|
||||
@@ -419,25 +489,53 @@ watch(hasUnsavedChanges, (dirty) => emit("dirty-change", dirty), { immediate: tr
|
||||
border-top: 1px solid #e5ebf2;
|
||||
}
|
||||
|
||||
.desktop-setting-stack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.desktop-setting-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.desktop-setting-hint {
|
||||
margin-left: 12px;
|
||||
color: #7f92ad;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.client-metadata {
|
||||
.client-metadata-panel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.client-metadata code {
|
||||
overflow-wrap: anywhere;
|
||||
.client-metadata-list {
|
||||
display: grid;
|
||||
grid-template-columns: 76px minmax(0, 1fr);
|
||||
gap: 6px 10px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
color: #40566f;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.client-metadata-list dt {
|
||||
color: #7f92ad;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.client-metadata-list dd {
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.section-heading {
|
||||
margin-bottom: 18px;
|
||||
padding-left: 112px;
|
||||
|
||||
Reference in New Issue
Block a user