From 2617e1786c3fddc43b18df31c8236b97ce4ee60f Mon Sep 17 00:00:00 2001
From: zjk <852185829@qq.com>
Date: 星期五, 31 七月 2026 16:26:20 +0800
Subject: [PATCH] feat: 添加应用更新进度显示与安装权限

---
 components/admin/AdminConfigPanel.vue |   98 +++++++++++++++++++++++++++++++++++++------------
 1 files changed, 74 insertions(+), 24 deletions(-)

diff --git a/components/admin/AdminConfigPanel.vue b/components/admin/AdminConfigPanel.vue
index 53102ad..8e0864e 100644
--- a/components/admin/AdminConfigPanel.vue
+++ b/components/admin/AdminConfigPanel.vue
@@ -59,7 +59,7 @@
           </view>
           <view class="update-btn" @click="handleVersionUpdate">
             <image :src="updateBtnIcon" class="banner-btn-icon" mode="aspectFit"></image>
-            <text class="update-btn-text">{{ isUpdatingVersion ? '下载中...' : '立即更新' }}</text>
+            <text class="update-btn-text">{{ updateButtonText }}</text>
           </view>
         </view>
         <view class="update-banner" v-else>
@@ -172,7 +172,7 @@
 </template>
 
 <script setup>
-import { onMounted, ref } from 'vue';
+import { computed, onMounted, ref } from 'vue';
 import configPageIcon from '../../static/admin-pages/L2Nja.png';
 import machineIcon from '../../static/admin-pages/n83u2.png';
 import systemInfoIcon from '../../static/admin-pages/tLgNe.png';
@@ -190,7 +190,7 @@
 import { syncEmployeeVerifyList } from '../../api/employee';
 import { deactivateVisitMachine } from '../../api/device';
 import { getLatestVersion } from '../../api/visitorRecord';
-import { clearRequestServerConfig, getRequestServerConfig, setRequestServerConfig } from '../../utils/request';
+import { buildBaseUrl, clearRequestServerConfig, getRequestServerConfig, setRequestServerConfig } from '../../utils/request';
 import { syncAllPendingRecords } from '../../utils/syncEngine';
 import { downloadRemoteFileToLocal } from '../../utils/fs';
 
@@ -203,12 +203,30 @@
 const isLoggingOut = ref(false);
 const isManualSyncing = ref(false);
 const isUpdatingVersion = ref(false);
+const updateDownloadProgress = ref(-1);
+const isInstallingVersion = ref(false);
 const logoutHoldTimer = ref(null);
 
 const currentVersion = ref('v1.0.0');
 const latestVersion = ref('');
 const hasNewVersion = ref(false);
 const latestVersionInfo = ref(null);
+
+const updateButtonText = computed(() => {
+  if (!isUpdatingVersion.value) {
+    return '立即更新';
+  }
+
+  if (isInstallingVersion.value) {
+    return '安装中...';
+  }
+
+  if (updateDownloadProgress.value >= 0) {
+    return `下载中 ${updateDownloadProgress.value}%`;
+  }
+
+  return '下载中...';
+});
 
 const normalizeVersionNumber = (version = '') => {
   return String(version || '').trim().replace(/^[vV]/, '');
@@ -366,6 +384,24 @@
   });
 };
 
+const resolvePackageDownloadUrl = (packageUrl = '') => {
+  const normalizedPackageUrl = String(packageUrl || '').trim();
+  if (!normalizedPackageUrl) {
+    return '';
+  }
+
+  if (/^https?:\/\//.test(normalizedPackageUrl)) {
+    return normalizedPackageUrl;
+  }
+
+  const baseUrl = buildBaseUrl(getRequestServerConfig());
+  if (!baseUrl) {
+    return '';
+  }
+
+  return `${baseUrl}${normalizedPackageUrl.startsWith('/') ? normalizedPackageUrl : `/${normalizedPackageUrl}`}`;
+};
+
 const handleVersionUpdate = async () => {
   if (isUpdatingVersion.value) {
     return;
@@ -373,8 +409,9 @@
 
   const packageUrl = latestVersionInfo.value?.packageUrl || '';
   const packageName = latestVersionInfo.value?.packageName || 'visitor-update.apk';
+  const packageDownloadUrl = resolvePackageDownloadUrl(packageUrl);
 
-  if (!hasNewVersion.value || !packageUrl) {
+  if (!hasNewVersion.value || !packageDownloadUrl) {
     uni.showToast({
       title: '未获取到更新包地址',
       icon: 'none',
@@ -392,43 +429,56 @@
 
   try {
     isUpdatingVersion.value = true;
-    uni.showLoading({
-      title: '更新包下载中...',
-      mask: true,
-    });
+    updateDownloadProgress.value = 0;
+    isInstallingVersion.value = false;
+    let lastProgress = -1;
 
     const fileNamePrefix = String(packageName || 'visitor-update')
       .replace(/\.[^.]+$/, '')
       .replace(/[^a-zA-Z0-9_-]/g, '-') || 'visitor-update';
-    const localPackagePath = await downloadRemoteFileToLocal(packageUrl, {
+    const localPackagePath = await downloadRemoteFileToLocal(packageDownloadUrl, {
       directoryName: 'apk-updates',
       fileNamePrefix,
       fallbackExtension: 'apk',
+      onProgress: ({ progress }) => {
+        const safeProgress = Math.max(0, Math.min(100, Number(progress || 0)));
+        if (safeProgress === lastProgress) {
+          return;
+        }
+        lastProgress = safeProgress;
+        updateDownloadProgress.value = safeProgress;
+      },
     });
 
-    uni.hideLoading();
+    updateDownloadProgress.value = 100;
+    isInstallingVersion.value = true;
+    uni.showToast({
+      title: '下载完成,正在拉起安装',
+      icon: 'none',
+    });
 
-    plus.runtime.install(localPackagePath, {}, () => {
-      uni.showToast({
-        title: '安装包已打开,请按提示完成更新',
-        icon: 'none',
-      });
-    }, (error) => {
-      console.error('安装更新包失败:', error);
-      uni.showToast({
-        title: error?.message || '安装更新包失败',
-        icon: 'none',
+    await new Promise((resolve, reject) => {
+      plus.runtime.install(localPackagePath, {}, () => {
+        uni.showToast({
+          title: '安装包已打开,请按提示完成更新',
+          icon: 'none',
+        });
+        resolve();
+      }, (error) => {
+        reject(error);
       });
     });
   } catch (error) {
-    console.error('下载更新包失败:', error);
+    const actionText = isInstallingVersion.value ? '安装更新包失败' : '下载更新包失败';
+    console.error(`${actionText}:`, error);
     uni.showToast({
-      title: error?.message || '下载更新包失败',
+      title: error?.message || actionText,
       icon: 'none',
     });
   } finally {
-    uni.hideLoading();
     isUpdatingVersion.value = false;
+    updateDownloadProgress.value = -1;
+    isInstallingVersion.value = false;
   }
 };
 
@@ -439,7 +489,7 @@
 
   try {
     isManualSyncing.value = true;
-    
+
     // 强制触发员工档案全量同步,绕过缓存有效期
     try {
       await syncEmployeeVerifyList(true);

--
Gitblit v1.7.1