spring
21 小时以前 6afb492942b17ebdb80f8e57af1b0df7ba5ee821
fix: 版本更新修改
已添加2个文件
已修改8个文件
333 ■■■■ 文件已修改
src/App.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/DownloadProgressMask.vue 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/el-progress.vue 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/config.js 47 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/login.vue 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/message.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/mine.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/works.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/versionUpgrade.js 95 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue
@@ -10,6 +10,7 @@
  import { confirmMessage } from "@/api/login.js";
  const showSplash = ref(true);
  onMounted(() => {
    setTimeout(() => {
      showSplash.value = false;
src/components/DownloadProgressMask.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,83 @@
<template>
  <view v-if="state.show" class="dpm-mask" @touchmove.stop.prevent @tap.stop>
    <view class="dpm-card" @tap.stop>
      <view class="dpm-title">{{ state.title }}</view>
      <ElProgress :percentage="state.progress" :stroke-width="12" :show-text="true" color="#0D867F" />
    </view>
  </view>
</template>
<script setup>
import { reactive, onUnmounted } from "vue";
import bus from "@/plugins/bus";
import ElProgress from "@/components/el-progress.vue";
const state = reactive({
  show: false,
  progress: 0,
  title: "更新包下载中...",
});
const handle = (payload = {}) => {
  if (!payload || typeof payload !== "object") return;
  if (payload.show === false) {
    state.show = false;
    state.progress = 0;
    state.title = "更新包下载中...";
    // ä¸‹è½½ç»“束:恢复 tabBar,避免底部不可点
    try { uni.showTabBar({ animation: false }); } catch (e) {}
    return;
  }
  if (payload.show === true) state.show = true;
  if (typeof payload.progress === "number" && Number.isFinite(payload.progress)) {
    state.progress = Math.max(0, Math.min(100, Math.floor(payload.progress)));
  }
  if (payload.title) state.title = String(payload.title);
  // ä¸‹è½½è¿›è¡Œä¸­ï¼šéšè—åŽŸç”Ÿ tabBar(原生层级高于页面遮罩,否则仍可点击)
  if (state.show) {
    try { uni.hideTabBar({ animation: false }); } catch (e) {}
  }
};
// äº‹ä»¶ç›‘听必须尽早注册(setup é˜¶æ®µå°±æ³¨å†Œï¼‰ï¼Œé¿å…ä¸‹è½½å¼€å§‹æ—¶è¿˜æœª mounted å¯¼è‡´é”™è¿‡é¦–次 show äº‹ä»¶
// bus.ts åŒåäº‹ä»¶åªèƒ½ç»‘定一次:先 off å† on,确保始终有效
try { bus.$off("versionUpgrade:downloadProgress"); } catch (e) {}
try { bus.$on("versionUpgrade:downloadProgress", handle); } catch (e) {}
onUnmounted(() => {
  try { bus.$off("versionUpgrade:downloadProgress"); } catch (e) {}
});
</script>
<style scoped lang="scss">
.dpm-mask {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 9999;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
}
.dpm-card {
  width: 620rpx;
  padding: 28rpx 28rpx 22rpx;
  background: #ffffff;
  border-radius: 20rpx;
  box-shadow: 0 12rpx 36rpx rgba(0, 0, 0, 0.18);
}
.dpm-title {
  text-align: center;
  font-size: 32rpx;
  font-weight: 600;
  color: rgba(0, 0, 0, 0.85);
  margin-bottom: 18rpx;
}
</style>
src/components/el-progress.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
<template>
  <view class="el-progress">
    <view class="el-progress-bar">
      <view class="el-progress-bar__outer" :style="{ height: `${strokeWidth}px` }">
        <view class="el-progress-bar__inner" :style="innerStyle" />
      </view>
    </view>
    <view v-if="showText" class="el-progress__text">{{ text }}</view>
  </view>
</template>
<script setup>
import { computed } from "vue";
const props = defineProps({
  percentage: { type: Number, default: 0 },
  strokeWidth: { type: Number, default: 10 },
  showText: { type: Boolean, default: true },
  color: { type: String, default: "#409EFF" },
});
const safePercent = computed(() => {
  const n = Number(props.percentage);
  if (!Number.isFinite(n)) return 0;
  return Math.max(0, Math.min(100, Math.floor(n)));
});
const innerStyle = computed(() => ({
  width: `${safePercent.value}%`,
  backgroundColor: props.color,
}));
const text = computed(() => `${safePercent.value}%`);
</script>
<style scoped>
.el-progress {
  width: 100%;
}
.el-progress-bar__outer {
  background-color: rgba(0, 0, 0, 0.08);
  border-radius: 100px;
  overflow: hidden;
}
.el-progress-bar__inner {
  height: 100%;
  border-radius: 100px;
  transition: width 0.15s ease;
}
.el-progress__text {
  margin-top: 10rpx;
  text-align: center;
  font-size: 26rpx;
  color: rgba(0, 0, 0, 0.55);
}
</style>
src/config.js
@@ -1,28 +1,29 @@
// åº”用全局配置
const config = {
  baseUrl: 'http://1.15.17.182:9003',
  fileUrl: 'http://1.15.17.182:9003',
   // åº”用信息
   appInfo: {
     // åº”用名称
     name: "ruoyi-app-vue3",
  baseUrl: "http://1.15.17.182:9003",
  fileUrl: "http://1.15.17.182:9002",
  // åº”用信息
  appInfo: {
    // åº”用名称
    name: "ruoyi-app-vue3",
    // åº”用版本(与 manifest.json çš„ versionName ä¿æŒä¸€è‡´ï¼‰
    version: "1.0.0",
     // åº”用logo
     logo: "/static/app-logo.png",
     // å®˜æ–¹ç½‘ç«™
     site_url: "http://ruoyi.vip",
     // æ”¿ç­–协议
     agreements: [{
         title: "隐私政策",
         url: "https://ruoyi.vip/protocol.html"
       },
       {
         title: "用户服务协议",
         url: "https://ruoyi.vip/protocol.html"
       }
     ]
   }
 }
    // åº”用logo
    logo: "/static/app-logo.png",
    // å®˜æ–¹ç½‘ç«™
    site_url: "http://ruoyi.vip",
    // æ”¿ç­–协议
    agreements: [
      {
        title: "隐私政策",
        url: "https://ruoyi.vip/protocol.html",
      },
      {
        title: "用户服务协议",
        url: "https://ruoyi.vip/protocol.html",
      },
    ],
  },
};
 export default config
export default config;
src/pages/index.vue
@@ -197,6 +197,7 @@
      <view class="bottom-space" />
    </scroll-view>
    <DownloadProgressMask />
  </view>
</template>
@@ -205,6 +206,7 @@
import { onShow } from "@dcloudio/uni-app";
import { analysisCustomerContractAmounts, getBusiness } from "@/api/viewIndex";
import { createVersionUpgradeChecker } from "@/utils/versionUpgrade";
import DownloadProgressMask from "@/components/DownloadProgressMask.vue";
const imgNum1 = "/static/images/index/num1.png";
const imgNum2 = "/static/images/index/num2.png";
src/pages/login.vue
@@ -264,18 +264,33 @@
    // #ifdef APP-PLUS
    try {
      // #ifdef APP-PLUS
      // @ts-ignore
      if (plus?.runtime?.version) {
      if (plus?.runtime?.getProperty) {
        // @ts-ignore
        versionName.value = plus.runtime.version;
        console.log("[login-version] å½“前环境=APP-PLUS,版本=", versionName.value);
        const appid = plus.runtime.appid;
        // @ts-ignore
        plus.runtime.getProperty(appid, (info) => {
          const v = info?.version || info?.versionName || "";
          if (v) {
            versionName.value = String(v);
            console.log("[login-version] å½“前环境=APP-PLUS,版本=", versionName.value);
          } else {
            console.log("[login-version] APP-PLUS èŽ·å–åˆ°çš„ç‰ˆæœ¬å­—æ®µä¸ºç©ºï¼Œä½¿ç”¨é»˜è®¤å€¼:", versionName.value);
          }
          console.log("[login-version] æœ€ç»ˆç‰ˆæœ¬å·:", versionName.value);
        });
      } else {
        console.log("[login-version] APP-PLUS çŽ¯å¢ƒä¸‹ç¼ºå°‘ getProperty,使用默认值:", versionName.value);
        console.log("[login-version] æœ€ç»ˆç‰ˆæœ¬å·:", versionName.value);
      }
      // #endif
    } catch (e) {
      // èŽ·å–å¤±è´¥æ—¶ä½¿ç”¨é»˜è®¤å€¼
      console.log("[login-version] APP-PLUS èŽ·å–ç‰ˆæœ¬å¤±è´¥:", e);
      console.log("[login-version] æœ€ç»ˆç‰ˆæœ¬å·:", versionName.value);
    }
    // #endif
    console.log("[login-version] æœ€ç»ˆç‰ˆæœ¬å·:", versionName.value);
    loadPassword();
    getUserLoginFacotryList();
src/pages/message.vue
@@ -60,6 +60,8 @@
        <text class="loading-more-text">加载更多...</text>
      </view>
    </scroll-view>
    <DownloadProgressMask />
  </view>
</template>
@@ -68,6 +70,7 @@
  import { onShow } from "@dcloudio/uni-app";
  import { listNotice, confirmMessage, getNoticeCount } from "@/api/login.js";
  import useUserStore from "@/store/modules/user";
  import DownloadProgressMask from "@/components/DownloadProgressMask.vue";
  // æ ‡ç­¾é¡µæ•°æ®
  const tabList = [
src/pages/mine.vue
@@ -73,6 +73,12 @@
        <view class="card-illu faq"></view>
      </view>
    </view> -->
    <view class="version-wrap">
      <text class="version-text">版本号:{{ version }}</text>
    </view>
    <DownloadProgressMask />
  </view>
</template>
@@ -81,6 +87,7 @@
import config from '@/config.js'
import { getUserProfile } from "@/api/system/user";
import useUserStore from '@/store/modules/user'
import DownloadProgressMask from "@/components/DownloadProgressMask.vue";
const userStore = useUserStore()
const name = userStore.name;
const roleName = userStore.roleName;
@@ -169,6 +176,19 @@
    /* #endif */
}
/* ç‰ˆæœ¬å· */
.version-wrap {
  width: 100%;
  text-align: center;
  margin-top: 18px;
  padding-bottom: 14px;
}
.version-text {
  font-size: 12px;
  color: #999;
}
/* é¡¶éƒ¨ä¸ªäººä¿¡æ¯å¡ */
.profile-card {
  display: flex;
src/pages/works.vue
@@ -264,6 +264,8 @@
        </up-grid>
      </view>
    </view>
    <DownloadProgressMask />
  </view>
</template>
@@ -273,6 +275,7 @@
  import { userLoginFacotryList } from "@/api/login";
  import { getProductWorkOrderById } from "@/api/productionManagement/productionReporting";
  import { createVersionUpgradeChecker } from "@/utils/versionUpgrade";
  import DownloadProgressMask from "@/components/DownloadProgressMask.vue";
  import modal from "@/plugins/modal";
  import useUserStore from "@/store/modules/user";
src/utils/versionUpgrade.js
@@ -1,5 +1,6 @@
import config from "@/config";
import { getAllVersion } from "@/api/viewIndex";
import bus from "@/plugins/bus";
function compareVersion(v1, v2) {
  const s1 = String(v1 || "").replace(/[^\d.]/g, "").split(".").map((n) => Number(n) || 0);
@@ -23,7 +24,7 @@
  return `${size}B`;
}
function getCurrentVersion(logPrefix) {
async function getCurrentVersion(logPrefix) {
  let currentVersion = config?.appInfo?.version || "1.0.0";
  console.log(`${logPrefix} å¼€å§‹èŽ·å–å½“å‰ç‰ˆæœ¬ï¼Œé»˜è®¤å€¼:`, currentVersion);
  // #ifdef MP-WEIXIN
@@ -40,12 +41,23 @@
  // #endif
  // #ifdef APP-PLUS
  try {
    // APP-PLUS ä¸‹ï¼Œplus.runtime.version ä¸æ˜¯ä¸šåŠ¡ç‰ˆæœ¬å·ï¼ˆç»å¸¸æ˜¯è¿è¡Œæ—¶/SDK版本),
    // è¿™é‡Œæ”¹ç”¨ getProperty å–系统层面的 app version。
    // @ts-ignore
    if (plus?.runtime?.version) {
    if (plus?.runtime?.getProperty) {
      // @ts-ignore
      currentVersion = plus.runtime.version;
      console.log(`${logPrefix} å½“前环境=APP-PLUS,版本=`, currentVersion);
      return currentVersion;
      const appid = plus.runtime.appid;
      const appInfo = await new Promise((resolve) => {
        // @ts-ignore
        plus.runtime.getProperty(appid, (info) => resolve(info || {}));
      });
      const v = appInfo?.version || appInfo?.versionName || appInfo?.appVersion || "";
      if (v) {
        currentVersion = String(v);
        console.log(`${logPrefix} å½“前环境=APP-PLUS,版本=`, currentVersion);
        return currentVersion;
      }
      console.log(`${logPrefix} APP-PLUS èŽ·å–åˆ°çš„ç‰ˆæœ¬å­—æ®µä¸ºç©ºï¼Œå°†ä½¿ç”¨é…ç½®ç‰ˆæœ¬:`, currentVersion);
    }
  } catch (e) {
    console.log(`${logPrefix} APP-PLUS èŽ·å–ç‰ˆæœ¬å¤±è´¥:`, e);
@@ -83,20 +95,46 @@
  // #endif
}
function downloadVersionPackage(url, logPrefix) {
  console.log(`${logPrefix} å¼€å§‹ä¸‹è½½æ›´æ–°åŒ…:`, url);
  uni.showLoading({ title: "更新包下载中..." });
  uni.downloadFile({
    url,
function buildFullDownloadUrl(rawUrl) {
  const u = String(rawUrl || "").trim();
  if (!u) return "";
  // å·²ç»æ˜¯ç»å¯¹åœ°å€ï¼Œç›´æŽ¥è¿”回
  if (/^https?:\/\//i.test(u)) return u;
  const base = String(config?.fileUrl || config?.baseUrl || "").replace(/\/+$/, "");
  const path = u.startsWith("/") ? u : `/${u}`;
  return `${base}${path}`;
}
function emitDownloadProgress(payload, logPrefix) {
  try {
    bus.$emit("versionUpgrade:downloadProgress", payload);
  } catch (e) {
    console.log(`${logPrefix} downloadProgress äº‹ä»¶æ´¾å‘失败:`, e);
  }
}
function downloadVersionPackage(url, logPrefix, fileSize) {
  const fullUrl = buildFullDownloadUrl(url);
  console.log(`${logPrefix} å¼€å§‹ä¸‹è½½æ›´æ–°åŒ…:`, { rawUrl: url, fullUrl });
  if (!fullUrl) {
    uni.showToast({ title: "更新附件地址无效", icon: "none" });
    return;
  }
  const totalSize = Number(fileSize);
  const hasTotalSize = Number.isFinite(totalSize) && totalSize > 0;
  console.log(`${logPrefix} ä¸‹è½½å¤§å°ä¿¡æ¯:`, { fileSize, totalSize, hasTotalSize });
  emitDownloadProgress({ show: true, progress: 0, title: "更新包下载中..." }, logPrefix);
  const task = uni.downloadFile({
    url: fullUrl,
    success: (res) => {
      console.log(`${logPrefix} ä¸‹è½½ç»“æžœ:`, res);
      uni.hideLoading();
      emitDownloadProgress({ show: false }, logPrefix);
      if (res.statusCode !== 200 || !res.tempFilePath) {
        console.log(`${logPrefix} ä¸‹è½½å¤±è´¥ï¼ŒçŠ¶æ€ç æˆ–ä¸´æ—¶è·¯å¾„å¼‚å¸¸`);
        uni.showToast({ title: "下载失败,请稍后重试", icon: "none" });
        return;
      }
      const lowerUrl = String(url || "").toLowerCase();
      const lowerUrl = String(fullUrl || "").toLowerCase();
      const isInstallPkg = lowerUrl.endsWith(".wgt") || lowerUrl.endsWith(".wgtu") || lowerUrl.endsWith(".apk");
      console.log(`${logPrefix} æ–‡ä»¶ç±»åž‹åˆ¤æ–­:`, { lowerUrl, isInstallPkg });
      if (isInstallPkg) {
@@ -114,10 +152,31 @@
    },
    fail: (err) => {
      console.log(`${logPrefix} ä¸‹è½½è¯·æ±‚失败:`, err);
      uni.hideLoading();
      emitDownloadProgress({ show: false }, logPrefix);
      uni.showToast({ title: "下载失败,请检查网络", icon: "none" });
    },
  });
  // ä¸‹è½½è¿›åº¦ï¼šéƒ¨åˆ†ç«¯ï¼ˆAPP/小程序)支持 onProgressUpdate
  try {
    if (task && typeof task.onProgressUpdate === "function") {
      task.onProgressUpdate((p) => {
        const downloadedSize = Number(p?.totalBytesWritten ?? p?.writtenBytes ?? p?.downloadedSize);
        const expectedSize = Number(p?.totalBytesExpectedToWrite ?? p?.totalBytesExpected ?? p?.totalSize);
        const denom = hasTotalSize ? totalSize : (Number.isFinite(expectedSize) && expectedSize > 0 ? expectedSize : 0);
        let progress = Number(p?.progress);
        if (!(Number.isFinite(progress) && progress >= 0 && progress <= 100) && denom > 0 && Number.isFinite(downloadedSize) && downloadedSize >= 0) {
          progress = (downloadedSize / denom) * 100;
        }
        if (!Number.isFinite(progress)) return;
        emitDownloadProgress({ show: true, progress, title: "更新包下载中..." }, logPrefix);
      });
    }
  } catch (e) {
    console.log(`${logPrefix} onProgressUpdate ç»‘定失败:`, e);
  }
}
async function checkAppVersionUpgrade(logPrefix, currentVersion) {
@@ -170,7 +229,7 @@
      return;
    }
    const firstFile = Array.isArray(first?.commonFileList) ? first.commonFileList[0] : null;
    const downloadUrl = firstFile?.url || "";
    const downloadUrl = firstFile?.url || firstFile?.downloadUrl || "";
    const fileSizeText = formatFileSize(firstFile?.fileSize);
    console.log(`${logPrefix} æ›´æ–°é™„件信息:`, {
      downloadUrl,
@@ -191,7 +250,7 @@
          uni.showToast({ title: "未找到更新附件地址", icon: "none" });
          return;
        }
        downloadVersionPackage(downloadUrl, logPrefix);
        downloadVersionPackage(downloadUrl, logPrefix, firstFile?.fileSize);
      },
    });
  } catch (e) {
@@ -204,7 +263,7 @@
  const logPrefix = options.logPrefix || "[version]";
  let lastVersionCheckAt = 0;
  const triggerVersionCheck = (from = "unknown") => {
  const triggerVersionCheck = async (from = "unknown") => {
    const now = Date.now();
    if (now - lastVersionCheckAt < throttleMs) {
      console.log(`${logPrefix} è·³è¿‡é‡å¤æ£€æŸ¥ï¼Œæ¥æº=${from}`);
@@ -212,8 +271,8 @@
    }
    lastVersionCheckAt = now;
    console.log(`${logPrefix} è§¦å‘版本检查,来源=${from}`);
    const currentVersion = getCurrentVersion(logPrefix);
    checkAppVersionUpgrade(logPrefix, currentVersion);
    const currentVersion = await getCurrentVersion(logPrefix);
    await checkAppVersionUpgrade(logPrefix, currentVersion);
  };
  return { triggerVersionCheck };