feat(client): 实现用户数据隔离与设备绑定优化- 添加用户会话ID构建逻辑,确保数据按用户隔离- 优化设备绑定流程,支持设备状态更新和绑定时间同步- 实现用户缓存清理功能,仅清除当前用户的数据- 增强客户端账号删除逻辑,级联删除相关数据
- 调整设备在线查询逻辑,确保只返回活跃绑定的设备 - 优化试用期逻辑,精确计算过期时间和类型- 添加账号管理弹窗和相关状态注入 -修复跟卖精灵按钮加载状态显示问题 - 增强文件上传区域UI,显示选中文件名 - 调整分页组件样式,优化界面展示效果- 优化反馈日志存储路径逻辑,默认使用用户目录 - 移除冗余代码和无用导入,提升代码整洁度
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="version-info" @click="handleVersionClick">
|
||||
v{{ version || '-' }}
|
||||
<span v-if="hasNewVersion" class="update-badge"></span>
|
||||
</div>
|
||||
<el-dialog v-model="show" width="522px" :close-on-click-modal="false" align-center
|
||||
:class="['update-dialog', `stage-${stage}`]"
|
||||
:title="stage === 'downloading' ? `正在更新 ${appName}` : '软件更新'">
|
||||
@@ -101,16 +97,12 @@ import {ref, computed, onMounted, onUnmounted, watch} from 'vue'
|
||||
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||
import {updateApi} from '../../api/update'
|
||||
import {getSettings} from '../../utils/settings'
|
||||
import {getUsernameFromToken} from '../../utils/token'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean
|
||||
}>()
|
||||
const props = defineProps<{ modelValue: boolean }>()
|
||||
const emit = defineEmits<{ 'update:modelValue': [value: boolean] }>()
|
||||
|
||||
// 暴露方法给父组件调用
|
||||
defineExpose({
|
||||
checkForUpdatesNow
|
||||
})
|
||||
defineExpose({ checkForUpdatesNow })
|
||||
|
||||
const show = computed({
|
||||
get: () => props.modelValue,
|
||||
@@ -121,54 +113,40 @@ type Stage = 'check' | 'downloading' | 'completed'
|
||||
const stage = ref<Stage>('check')
|
||||
const appName = ref('我了个电商')
|
||||
const version = ref('')
|
||||
const hasNewVersion = ref(false) // 控制小红点显示
|
||||
const prog = ref({percentage: 0, current: '0 MB', total: '0 MB'})
|
||||
const info = ref({
|
||||
latestVersion: '2.4.8',
|
||||
downloadUrl: '',
|
||||
latestVersion: '',
|
||||
asarUrl: '',
|
||||
jarUrl: '',
|
||||
updateNotes: '',
|
||||
currentVersion: '',
|
||||
hasUpdate: false
|
||||
currentVersion: ''
|
||||
})
|
||||
|
||||
const SKIP_VERSION_KEY = 'skipped_version'
|
||||
const REMIND_LATER_KEY = 'remind_later_time'
|
||||
|
||||
async function autoCheck(silent = false) {
|
||||
async function checkUpdate(silent = false) {
|
||||
try {
|
||||
version.value = await (window as any).electronAPI.getJarVersion()
|
||||
const checkRes: any = await updateApi.checkUpdate(version.value)
|
||||
const result = checkRes?.data || checkRes
|
||||
const result = (await updateApi.checkUpdate(version.value))?.data
|
||||
|
||||
info.value = {
|
||||
currentVersion: result.currentVersion || version.value,
|
||||
latestVersion: result.latestVersion || version.value,
|
||||
asarUrl: result.asarUrl || '',
|
||||
jarUrl: result.jarUrl || '',
|
||||
updateNotes: result.updateNotes || ''
|
||||
}
|
||||
|
||||
if (!result.needUpdate) {
|
||||
hasNewVersion.value = false
|
||||
if (!silent) ElMessage.info('当前已是最新版本')
|
||||
return
|
||||
}
|
||||
|
||||
if (localStorage.getItem('skipped_version') === result.latestVersion) return
|
||||
|
||||
// 发现新版本,更新信息并显示小红点
|
||||
info.value = {
|
||||
currentVersion: result.currentVersion,
|
||||
latestVersion: result.latestVersion,
|
||||
downloadUrl: result.downloadUrl || '',
|
||||
asarUrl: result.asarUrl || '',
|
||||
jarUrl: result.jarUrl || '',
|
||||
updateNotes: result.updateNotes || '',
|
||||
hasUpdate: true
|
||||
}
|
||||
hasNewVersion.value = true
|
||||
const remindTime = localStorage.getItem('remind_later_time')
|
||||
if (remindTime && Date.now() < parseInt(remindTime)) return
|
||||
|
||||
const skippedVersion = localStorage.getItem(SKIP_VERSION_KEY)
|
||||
if (skippedVersion === result.latestVersion) return
|
||||
|
||||
const remindLater = localStorage.getItem(REMIND_LATER_KEY)
|
||||
if (remindLater && Date.now() < parseInt(remindLater)) return
|
||||
|
||||
const settings = getSettings()
|
||||
if (settings.autoUpdate) {
|
||||
await startAutoDownload()
|
||||
if (getSettings(getUsernameFromToken()).autoUpdate) {
|
||||
await downloadUpdate()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -180,95 +158,40 @@ async function autoCheck(silent = false) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleVersionClick() {
|
||||
async function checkForUpdatesNow() {
|
||||
if (stage.value === 'downloading' || stage.value === 'completed') {
|
||||
show.value = true
|
||||
return
|
||||
}
|
||||
|
||||
if (hasNewVersion.value) {
|
||||
stage.value = 'check'
|
||||
show.value = true
|
||||
} else {
|
||||
checkForUpdatesNow()
|
||||
}
|
||||
}
|
||||
|
||||
// 立即检查更新(供外部调用)
|
||||
async function checkForUpdatesNow() {
|
||||
await autoCheck(false)
|
||||
await checkUpdate(false)
|
||||
}
|
||||
|
||||
function skipVersion() {
|
||||
localStorage.setItem(SKIP_VERSION_KEY, info.value.latestVersion)
|
||||
localStorage.setItem('skipped_version', info.value.latestVersion)
|
||||
show.value = false
|
||||
}
|
||||
|
||||
function remindLater() {
|
||||
// 24小时后再提醒
|
||||
localStorage.setItem(REMIND_LATER_KEY, (Date.now() + 24 * 60 * 60 * 1000).toString())
|
||||
localStorage.setItem('remind_later_time', (Date.now() + 24 * 60 * 60 * 1000).toString())
|
||||
show.value = false
|
||||
}
|
||||
|
||||
async function start() {
|
||||
// 如果已经在下载或已完成,不重复执行
|
||||
if (stage.value === 'downloading') {
|
||||
if (stage.value !== 'check') {
|
||||
show.value = true
|
||||
return
|
||||
}
|
||||
|
||||
if (stage.value === 'completed') {
|
||||
show.value = true
|
||||
return
|
||||
}
|
||||
|
||||
if (!info.value.asarUrl && !info.value.jarUrl) {
|
||||
ElMessage.error('下载链接不可用')
|
||||
return
|
||||
}
|
||||
|
||||
stage.value = 'downloading'
|
||||
show.value = true
|
||||
prog.value = {percentage: 0, current: '0 MB', total: '0 MB'}
|
||||
|
||||
// 设置新的进度监听器(会自动清理旧的)
|
||||
;(window as any).electronAPI.onDownloadProgress((progress: any) => {
|
||||
prog.value = {
|
||||
percentage: progress.percentage || 0,
|
||||
current: progress.current || '0 MB',
|
||||
total: progress.total || '0 MB'
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
const response = await (window as any).electronAPI.downloadUpdate({
|
||||
asarUrl: info.value.asarUrl,
|
||||
jarUrl: info.value.jarUrl
|
||||
})
|
||||
|
||||
if (response.success) {
|
||||
stage.value = 'completed'
|
||||
prog.value.percentage = 100
|
||||
ElMessage.success('下载完成')
|
||||
show.value = true
|
||||
} else {
|
||||
ElMessage.error('下载失败: ' + (response.error || '未知错误'))
|
||||
stage.value = 'check'
|
||||
prog.value = {percentage: 0, current: '0 MB', total: '0 MB'}
|
||||
;(window as any).electronAPI.removeDownloadProgressListener()
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('下载失败')
|
||||
stage.value = 'check'
|
||||
prog.value = {percentage: 0, current: '0 MB', total: '0 MB'}
|
||||
;(window as any).electronAPI.removeDownloadProgressListener()
|
||||
}
|
||||
await downloadUpdate(true)
|
||||
}
|
||||
|
||||
async function startAutoDownload() {
|
||||
if (!info.value.asarUrl && !info.value.jarUrl) return
|
||||
async function downloadUpdate(showDialog = false) {
|
||||
if (!info.value.asarUrl && !info.value.jarUrl) {
|
||||
if (showDialog) ElMessage.error('下载链接不可用')
|
||||
return
|
||||
}
|
||||
|
||||
stage.value = 'downloading'
|
||||
if (showDialog) show.value = true
|
||||
prog.value = {percentage: 0, current: '0 MB', total: '0 MB'}
|
||||
|
||||
;(window as any).electronAPI.onDownloadProgress((progress: any) => {
|
||||
@@ -282,54 +205,45 @@ async function startAutoDownload() {
|
||||
try {
|
||||
const response = await (window as any).electronAPI.downloadUpdate({
|
||||
asarUrl: info.value.asarUrl,
|
||||
jarUrl: info.value.jarUrl
|
||||
jarUrl: info.value.jarUrl,
|
||||
latestVersion: info.value.latestVersion
|
||||
})
|
||||
|
||||
|
||||
if (response.success) {
|
||||
stage.value = 'completed'
|
||||
prog.value.percentage = 100
|
||||
show.value = true
|
||||
ElMessage.success('更新已下载完成,可以安装了')
|
||||
ElMessage.success(showDialog ? '下载完成' : '更新已下载完成,可以安装了')
|
||||
} else {
|
||||
stage.value = 'check'
|
||||
if (showDialog) ElMessage.error('下载失败: ' + (response.error || '未知错误'))
|
||||
;(window as any).electronAPI.removeDownloadProgressListener()
|
||||
}
|
||||
} catch (error) {
|
||||
stage.value = 'check'
|
||||
if (showDialog) ElMessage.error('下载失败')
|
||||
;(window as any).electronAPI.removeDownloadProgressListener()
|
||||
}
|
||||
}
|
||||
|
||||
async function cancelDownload() {
|
||||
try {
|
||||
;(window as any).electronAPI.removeDownloadProgressListener()
|
||||
await (window as any).electronAPI.cancelDownload()
|
||||
|
||||
stage.value = 'check'
|
||||
prog.value = {percentage: 0, current: '0 MB', total: '0 MB'}
|
||||
hasNewVersion.value = false
|
||||
show.value = false
|
||||
|
||||
ElMessage.info('已取消下载')
|
||||
} catch (error) {
|
||||
stage.value = 'check'
|
||||
prog.value = {percentage: 0, current: '0 MB', total: '0 MB'}
|
||||
hasNewVersion.value = false
|
||||
show.value = false
|
||||
}
|
||||
;(window as any).electronAPI.removeDownloadProgressListener()
|
||||
await (window as any).electronAPI.cancelDownload().catch(() => {})
|
||||
|
||||
stage.value = 'check'
|
||||
prog.value = {percentage: 0, current: '0 MB', total: '0 MB'}
|
||||
show.value = false
|
||||
ElMessage.info('已取消下载')
|
||||
}
|
||||
|
||||
async function installUpdate() {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
'安装过程中程序将自动重启,请确保已保存所有工作。确定要立即安装更新吗?',
|
||||
'确认安装',
|
||||
{
|
||||
confirmButtonText: '立即安装',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}
|
||||
)
|
||||
await ElMessageBox.confirm('安装过程中程序将自动重启,请确保已保存所有工作。确定要立即安装更新吗?', '确认安装', {
|
||||
confirmButtonText: '立即安装',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
|
||||
const response = await (window as any).electronAPI.installUpdate()
|
||||
if (response.success) {
|
||||
ElMessage.success('应用即将重启')
|
||||
@@ -342,25 +256,19 @@ async function installUpdate() {
|
||||
|
||||
async function clearDownloadedFiles() {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
'确定要清除已下载的更新文件吗?清除后需要重新下载。',
|
||||
'确认清除',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}
|
||||
)
|
||||
await ElMessageBox.confirm('确定要清除已下载的更新文件吗?清除后需要重新下载。', '确认清除', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
|
||||
const response = await (window as any).electronAPI.clearUpdateFiles()
|
||||
|
||||
if (response.success) {
|
||||
ElMessage.success('已清除下载文件')
|
||||
// 重置状态
|
||||
stage.value = 'check'
|
||||
prog.value = {percentage: 0, current: '0 MB', total: '0 MB'}
|
||||
hasNewVersion.value = false
|
||||
show.value = false
|
||||
ElMessage.success('已清除下载文件')
|
||||
} else {
|
||||
ElMessage.error('清除失败: ' + (response.error || '未知错误'))
|
||||
}
|
||||
@@ -373,13 +281,13 @@ onMounted(async () => {
|
||||
version.value = await (window as any).electronAPI.getJarVersion()
|
||||
const pendingUpdate = await (window as any).electronAPI.checkPendingUpdate()
|
||||
|
||||
if (pendingUpdate && pendingUpdate.hasPendingUpdate) {
|
||||
if (pendingUpdate?.hasPendingUpdate) {
|
||||
stage.value = 'completed'
|
||||
prog.value.percentage = 100
|
||||
return
|
||||
}
|
||||
|
||||
await autoCheck(true)
|
||||
await checkUpdate(true)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -390,45 +298,6 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.version-info {
|
||||
position: fixed;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
z-index: 1000;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
|
||||
.update-badge {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
right: -2px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: #f56c6c;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #fff;
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.update-dialog .el-dialog) {
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 24px 48px rgba(0, 0, 0, 0.15);
|
||||
|
||||
Reference in New Issue
Block a user