|
|
@@ -0,0 +1,381 @@
|
|
|
+<template>
|
|
|
+ <headerBar title="首页">
|
|
|
+
|
|
|
+ <template #title><div @click="handleSettingClick" v-log="{ describe: { action: '点击首页标题' } }">首页</div></template>
|
|
|
+ </headerBar>
|
|
|
+ <div
|
|
|
+ class="home-container"
|
|
|
+ v-loading="loading || !healthReady || !syncCompleted"
|
|
|
+ :element-loading-text="loadingText"
|
|
|
+ >
|
|
|
+ <!-- 背景图片 -->
|
|
|
+ <img src="@/assets/images/home/bg.png" alt="背景图片" class="background-image" />
|
|
|
+
|
|
|
+ <!-- 左侧图片区域 -->
|
|
|
+ <div class="image-container left-image" @click="goCheck" v-log="{ describe: { action: '点击拍照检查入口' } }">
|
|
|
+ <img src="@/assets/images/home/left.png" alt="拍摄产品并处理图像" class="zoom-on-hover" />
|
|
|
+ <div class="overlay-text">拍摄产品<br>并处理图像</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 右侧图片区域 -->
|
|
|
+ <div class="image-container right-image" @click="goShot" v-log="{ describe: { action: '点击仅处理图像入口' } }">
|
|
|
+ <img src="@/assets/images/home/right.png" alt="仅处理图像" class="zoom-on-hover" />
|
|
|
+ <div class="overlay-text" style="line-height: 80px;">仅处理图像</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import headerBar from "@/components/header-bar/index.vue";
|
|
|
+import { useRouter } from "vue-router";
|
|
|
+import configInfo from '@/stores/modules/config';
|
|
|
+import { ref, onMounted, onUnmounted, computed } from 'vue';
|
|
|
+import axios from 'axios';
|
|
|
+import client from "@/stores/modules/client";
|
|
|
+import icpList from '@/utils/ipc';
|
|
|
+import packageJson from '@/../../package.json';
|
|
|
+import { getRouterUrl } from '@/utils/appfun';
|
|
|
+import useUserInfo from "@/stores/modules/user";
|
|
|
+import tokenInfo from "@/stores/modules/token";
|
|
|
+
|
|
|
+const router = useRouter();
|
|
|
+const loading = ref(true);
|
|
|
+const healthReady = ref(false); // 程序是否已完成自检
|
|
|
+const syncLoading = ref(false); // 同步配置的loading状态
|
|
|
+const syncCompleted = ref(false); // 同步是否完成
|
|
|
+const loadingText = computed(() => {
|
|
|
+ if (!healthReady.value) {
|
|
|
+ return '程序启动中...';
|
|
|
+ }
|
|
|
+ if (!syncCompleted.value) {
|
|
|
+ return '正在同步配置...';
|
|
|
+ }
|
|
|
+ return '正在加载...';
|
|
|
+});
|
|
|
+
|
|
|
+// 用户状态管理 - 在 onMounted 中初始化
|
|
|
+let configInfoStore: any;
|
|
|
+let useUserInfoStore: any;
|
|
|
+let tokenInfoStore: any;
|
|
|
+
|
|
|
+// 版本检查相关
|
|
|
+const currentVersion = ref(packageJson.version);
|
|
|
+const latestVersion = ref('');
|
|
|
+const isLatest = ref(true);
|
|
|
+
|
|
|
+
|
|
|
+import socket from "@/stores/modules/socket";
|
|
|
+import {ElMessage} from "element-plus";
|
|
|
+// 初始化 WebSocket 状态管理
|
|
|
+const socketStore = socket();
|
|
|
+
|
|
|
+function socketConnect(){
|
|
|
+ socketStore.connectSocket();
|
|
|
+}
|
|
|
+
|
|
|
+const goCheck = async () => {
|
|
|
+ // 检查登录状态
|
|
|
+ if (!tokenInfoStore.getToken) {
|
|
|
+ useUserInfoStore.updateLoginShow(true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果正在同步,显示提示
|
|
|
+ if (syncLoading.value) {
|
|
|
+ console.log('正在同步配置,请稍候...');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果未同步完成,等待同步
|
|
|
+ if (!syncCompleted.value) {
|
|
|
+ ElMessage.error('等待配置同步完成');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ configInfoStore.updateAppModel(1);
|
|
|
+ router.push({
|
|
|
+ name: 'PhotographyCheck'
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const goShot = async () => {
|
|
|
+ // 检查登录状态
|
|
|
+ if (!tokenInfoStore.getToken) {
|
|
|
+ useUserInfoStore.updateLoginShow(true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果正在同步,显示提示
|
|
|
+ if (syncLoading.value) {
|
|
|
+ console.log('正在同步配置,请稍候...');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果未同步完成,等待同步
|
|
|
+ if (!syncCompleted.value) {
|
|
|
+ console.log('等待配置同步完成...');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ socketConnect();
|
|
|
+ configInfoStore.updateAppModel(2);
|
|
|
+ router.push({
|
|
|
+ name: 'PhotographyProcessImage'
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 健康检查函数
|
|
|
+const checkHealth = async () => {
|
|
|
+ loading.value = false;
|
|
|
+ try {
|
|
|
+ const healthUrl = configInfoStore?.appConfig?.pyapp ? 'http://'+configInfoStore?.appConfig?.pyapp+':7074' : 'http://127.0.0.1:7074'
|
|
|
+ const response = await axios.get(healthUrl);
|
|
|
+ if (response.status === 200) {
|
|
|
+ loading.value = false; // 健康检查成功,关闭 loading
|
|
|
+ healthReady.value = true;
|
|
|
+
|
|
|
+ // 健康检查成功后,如果用户已登录则执行数据同步
|
|
|
+ if (tokenInfoStore && tokenInfoStore.getToken) {
|
|
|
+ const token = tokenInfoStore.getToken;
|
|
|
+ if (token && token.trim() !== '') {
|
|
|
+ try {
|
|
|
+ syncLoading.value = true; // 开始同步
|
|
|
+ syncCompleted.value = false; // 重置同步状态
|
|
|
+
|
|
|
+ // 导入同步函数
|
|
|
+ const { syncAfterLogin } = await import('@/apis/setting');
|
|
|
+ await syncAfterLogin();
|
|
|
+ console.log('健康检查后数据同步成功');
|
|
|
+
|
|
|
+ syncCompleted.value = true; // 同步完成
|
|
|
+ } catch (syncError) {
|
|
|
+ console.error('健康检查后数据同步失败:', syncError);
|
|
|
+ syncCompleted.value = false; // 同步失败
|
|
|
+ // 同步失败不影响主流程
|
|
|
+ } finally {
|
|
|
+ syncLoading.value = false; // 结束同步loading
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 未登录状态,直接设置同步完成
|
|
|
+ syncCompleted.value = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 未登录状态,直接设置同步完成
|
|
|
+ syncCompleted.value = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('健康检查失败:', error);
|
|
|
+ healthReady.value = false;
|
|
|
+ setTimeout(() => {
|
|
|
+ checkHealth(); // 延迟检查
|
|
|
+ }, 2000);
|
|
|
+ // 可以在这里处理错误,例如显示错误提示
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const settingClickCount = ref(0);
|
|
|
+// 修改headerBar的点击处理函数
|
|
|
+function handleSettingClick() {
|
|
|
+ console.log('handleSettingClickhandleSettingClick')
|
|
|
+ settingClickCount.value++;
|
|
|
+
|
|
|
+ if (settingClickCount.value >= 5) {
|
|
|
+ openResourceDirectory()
|
|
|
+ settingClickCount.value = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ settingClickCount.value = 0;
|
|
|
+ }, 3000); // 3秒内未再次点击则重置计数器
|
|
|
+}
|
|
|
+
|
|
|
+function openResourceDirectory() {
|
|
|
+ const clientStore = client();
|
|
|
+ clientStore.ipc.removeAllListeners(icpList.utils.shellFun);
|
|
|
+ let params = {
|
|
|
+ action: 'openPath',
|
|
|
+ params: configInfoStore.appConfig.userDataPath.replaceAll('/', '\\')
|
|
|
+ };
|
|
|
+ clientStore.ipc.send(icpList.utils.shellFun, params);
|
|
|
+}
|
|
|
+
|
|
|
+// 版本号比较函数
|
|
|
+const compareVersions = (v1, v2) => {
|
|
|
+ const parts1 = v1.split('.').map(Number);
|
|
|
+ const parts2 = v2.split('.').map(Number);
|
|
|
+
|
|
|
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
|
+ const num1 = parts1[i] || 0;
|
|
|
+ const num2 = parts2[i] || 0;
|
|
|
+
|
|
|
+ if (num1 > num2) return 1;
|
|
|
+ if (num1 < num2) return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+};
|
|
|
+
|
|
|
+// 打开OTA窗口
|
|
|
+const openOTA = () => {
|
|
|
+ const { href } = router.resolve({
|
|
|
+ name: 'ota'
|
|
|
+ });
|
|
|
+
|
|
|
+ const clientStore = client();
|
|
|
+ clientStore.ipc.removeAllListeners(icpList.utils.openMain);
|
|
|
+ let params = {
|
|
|
+ title: '版本更新',
|
|
|
+ width: 900,
|
|
|
+ height: 700,
|
|
|
+ frame: true,
|
|
|
+ id: 'ota',
|
|
|
+ url: getRouterUrl(href)
|
|
|
+ };
|
|
|
+ clientStore.ipc.send(icpList.utils.openMain, params);
|
|
|
+};
|
|
|
+
|
|
|
+// 获取版本信息并检查更新
|
|
|
+const checkForUpdates = async () => {
|
|
|
+ try {
|
|
|
+ // 添加时间戳避免缓存问题
|
|
|
+ const timestamp = new Date().getTime();
|
|
|
+ const response = await axios.get('https://ossimg.valimart.net/frontend/html/zhihuiyin/version.json', {
|
|
|
+ params: {
|
|
|
+ _t: timestamp
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 确保 response.data 是 JSON 数据
|
|
|
+ let data;
|
|
|
+ if (typeof response.data === 'string') {
|
|
|
+ data = JSON.parse(response.data);
|
|
|
+ } else {
|
|
|
+ data = response.data;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data.length > 0) {
|
|
|
+ const latest = data[data.length - 1];
|
|
|
+ latestVersion.value = latest.version;
|
|
|
+
|
|
|
+ // 比较版本号
|
|
|
+ isLatest.value = compareVersions(currentVersion.value, latest.version) >= 0;
|
|
|
+
|
|
|
+ // 如果发现新版本,自动打开OTA窗口
|
|
|
+ if (!isLatest.value) {
|
|
|
+ openOTA();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('检查版本更新失败:', error);
|
|
|
+ // 静默处理错误,不影响用户体验
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// 监听登录成功事件
|
|
|
+const handleLoginSuccess = () => {
|
|
|
+ console.log('检测到登录成功,重新检查同步状态');
|
|
|
+ // 重新执行健康检查和同步
|
|
|
+ checkHealth();
|
|
|
+};
|
|
|
+
|
|
|
+// 在组件挂载时执行健康检查和版本检查
|
|
|
+onMounted(() => {
|
|
|
+ // 初始化 store
|
|
|
+ configInfoStore = configInfo();
|
|
|
+ useUserInfoStore = useUserInfo();
|
|
|
+ tokenInfoStore = tokenInfo();
|
|
|
+
|
|
|
+ // 监听登录成功事件
|
|
|
+ window.addEventListener('login-success', handleLoginSuccess);
|
|
|
+
|
|
|
+ checkHealth();
|
|
|
+ // 延迟执行版本检查,避免影响健康检查
|
|
|
+ setTimeout(() => {
|
|
|
+ checkForUpdates();
|
|
|
+ }, 1000);
|
|
|
+});
|
|
|
+
|
|
|
+// 组件卸载时清理事件监听器
|
|
|
+onUnmounted(() => {
|
|
|
+ window.removeEventListener('login-success', handleLoginSuccess);
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.home-container {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ height: calc(100vh - 30px);
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.background-image {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: cover;
|
|
|
+ z-index: -1;
|
|
|
+}
|
|
|
+
|
|
|
+.image-container {
|
|
|
+ position: absolute;
|
|
|
+ cursor: pointer;
|
|
|
+ width: 400px; /* 设置宽度 */
|
|
|
+ overflow: hidden;
|
|
|
+ // box-shadow: 0 4px 10px rgba(0, 0, 0, 0.6); /* 添加阴影效果 */
|
|
|
+ border-radius: 30px;
|
|
|
+ transition: transform 0.3s ease;
|
|
|
+
|
|
|
+ .zoom-on-hover {
|
|
|
+ transition: transform 0.3s ease;
|
|
|
+ width: 100%; /* 确保图片充满容器 */
|
|
|
+ height: 100%; /* 确保图片充满容器 */
|
|
|
+ object-fit: cover; /* 裁剪图片以适应容器 */
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.6);
|
|
|
+ transform: translateY(-55%);
|
|
|
+ transform:translateY(-55%) scale(1.05);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.left-image {
|
|
|
+ top: 50%;
|
|
|
+ right: 50%;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ margin-right: 50px;
|
|
|
+}
|
|
|
+
|
|
|
+.right-image {
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ margin-left: 50px;
|
|
|
+}
|
|
|
+
|
|
|
+.overlay-text {
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ color: white;
|
|
|
+ font-size: 24px;
|
|
|
+ text-align: center;
|
|
|
+ z-index: 1;
|
|
|
+ background-color: rgba(0, 0, 0, 0.5);
|
|
|
+ padding: 10px 40px;
|
|
|
+ line-height: 50px;
|
|
|
+ min-height: 80px;
|
|
|
+ min-width: 250px;
|
|
|
+}
|
|
|
+</style>
|