Преглед изворни кода

提供webview注入apptoken功能;完善锅炉检测录入页面按钮功能

yangguanjin пре 2 недеља
родитељ
комит
c2079d58a4

+ 1 - 1
env/.env.development

@@ -6,7 +6,7 @@ VITE_DELETE_CONSOLE = false
 VITE_SHOW_SOURCEMAP = true
 
 # VITE_SERVER_BASEURL = 'http://192.168.0.53:48080/appapi'
-VITE_SERVER_BASEURL = 'http://127.0.0.1:48080/appapi'
+VITE_SERVER_BASEURL = 'http://192.168.0.118:48080/appapi'
 
 # VITE_FILE_URL = 'https://youdao.hofo.co/dexdev'
 VITE_FILE_URL = 'http://192.168.0.53:9110/dexdev'

+ 113 - 0
index.html

@@ -22,5 +22,118 @@
   <body>
     <div id="app"><!--app-html--></div>
     <script type="module" src="/src/main.ts"></script>
+    <script>
+      var API_BASE = 'http://192.168.0.118:9000/appapi'
+
+      // 通用请求方法(带token)
+      function apiGet(path, params) {
+        var url = API_BASE + path
+        if (params) {
+          var qs = Object.keys(params).map(function(k) { return k + '=' + encodeURIComponent(params[k]) }).join('&')
+          url += '?' + qs
+        }
+        var token = window.localStorage.getItem('APP_ACCESS_TOKEN') || ''
+        return fetch(url, {
+          method: 'GET',
+          headers: {
+            'Content-Type': 'application/json',
+            'Authorization': 'Bearer ' + token,
+            'X-Tenant-Id': '1'
+          }
+        }).then(function(res) { return res.json() })
+      }
+
+      // 获取用户信息(参照login.vue fetchUserInfo)
+      function fetchUserInfo(userId) {
+        return apiGet('/system/auth/userinfo', { id: userId })
+          .then(function(res) {
+            console.log('[fetchUserInfo] Response:', JSON.stringify(res))
+            if (res.code === 0 && res.data) {
+              window.localStorage.setItem('APP_USER_INFO', JSON.stringify(res.data))
+              console.log('[fetchUserInfo] APP_USER_INFO saved')
+              // 获取部门成员列表
+              if (res.data.deptId) {
+                return fetchDeptMembers(res.data.deptId)
+              }
+            }
+          })
+          .catch(function(e) {
+            console.error('[fetchUserInfo] Failed:', e)
+          })
+      }
+
+      // 获取部门成员列表(参照login.vue fetchGetMemberByDeptApi)
+      function fetchDeptMembers(deptId) {
+        return apiGet('/bpm/user-group/user-list', { deptIds: deptId })
+          .then(function(res) {
+            console.log('[fetchDeptMembers] Response: ok')
+            if (res.code === 0 && res.data && res.data.length) {
+              window.localStorage.setItem('USER_LIST', JSON.stringify(res.data))
+            }
+          })
+          .catch(function(e) {
+            console.error('[fetchDeptMembers] Failed:', e)
+          })
+      }
+
+      // 通知Vue应用刷新store
+      function notifyAppRefresh(loginData) {
+        window.dispatchEvent(new CustomEvent('app-token-login', { detail: loginData }))
+      }
+
+      window.loginByAppToken = function (token) {
+        fetch(API_BASE + '/system/auth/loginByAppToken', {
+          method: 'POST',
+          headers: { 'Content-Type': 'application/json' },
+          body: JSON.stringify({ appToken: token })
+        })
+        .then(function (res) { return res.json() })
+        .then(function (res) {
+          console.log('[loginByAppToken] Response:', JSON.stringify(res))
+          if (res.code === 0 && res.data) {
+            // 存储 accessToken
+            window.localStorage.setItem('APP_ACCESS_TOKEN', res.data.accessToken)
+            console.log('[loginByAppToken] APP_ACCESS_TOKEN saved')
+            // 获取用户信息
+            if (res.data.userId) {
+              fetchUserInfo(res.data.userId).then(function() {
+                // 通知Vue应用刷新store
+                notifyAppRefresh({ accessToken: res.data.accessToken, userId: res.data.userId })
+              })
+            } else {
+              console.warn('[loginByAppToken] No userId in response')
+              notifyAppRefresh({ accessToken: res.data.accessToken })
+            }
+          } else {
+            console.error('[loginByAppToken] Login failed:', res.msg)
+          }
+        })
+        .catch(function (e) {
+          console.error('[loginByAppToken] Failed:', e)
+        })
+      }
+
+      window.saveToLocalStorage = function (jsonStr) {
+        try {
+          var data = JSON.parse(jsonStr)
+          if (data && typeof data === 'object') {
+            Object.keys(data).forEach(function (key) {
+              window.localStorage.setItem(key, typeof data[key] === 'object' ? JSON.stringify(data[key]) : String(data[key]))
+            })
+          }
+          console.log('[saveToLocalStorage] Success:', data)
+          // 写入成功后,取出token调用登录接口
+          var token = window.localStorage.getItem('token')
+          if (token) {
+            console.log('[saveToLocalStorage] Got token, calling loginByAppToken...')
+            window.loginByAppToken(token)
+          } else {
+            console.warn('[saveToLocalStorage] No token found in data')
+          }
+        } catch (e) {
+          console.error('[saveToLocalStorage] Failed:', e)
+        }
+      }
+    </script>
   </body>
 </html>

+ 24 - 0
src/App.vue

@@ -2,6 +2,7 @@
 import { onLaunch, onShow, onHide, onLoad, onReady } from '@dcloudio/uni-app'
 import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
 import { useDictStore } from '@/store/dict'
+import { useUserStore } from '@/store/user'
 import { beforEach } from '@/router/index'
  // #ifdef APP-PLUS
 import appUpdate from "@/common/appUpdate";
@@ -16,6 +17,29 @@ export default {
     // 初始化字典数据
     useDictStore().setDictMap()
     // #endif
+
+    // 监听 index.html 中 appToken 登录完成事件,刷新 store
+    const handleTokenLogin = (e: any) => {
+      const detail = e.detail || {}
+      console.log('[App] 收到 app-token-login 事件:', detail)
+      const userStore = useUserStore()
+      // 重新从 localStorage 读取 token(initToken 内部调用 uni.getStorageSync)
+      // userStore.initToken()
+      // 读取 localStorage 中的用户信息写入 store
+      const userInfoStr = uni.getStorageSync('APP_USER_INFO')
+      if (userInfoStr) {
+        try {
+          const userInfo = typeof userInfoStr === 'string' ? JSON.parse(userInfoStr) : userInfoStr
+          userStore.setUserInfo({ ...userInfo, token: detail.accessToken })
+          console.log('[App] store 已刷新, token:', !!detail.accessToken)
+        } catch (err) {
+          console.error('[App] 解析 APP_USER_INFO 失败:', err)
+        }
+      }
+      // 只需监听一次
+      window.removeEventListener('app-token-login', handleTokenLogin)
+    }
+    window.addEventListener('app-token-login', handleTokenLogin)
   },
   onShow: function (options) {
     console.log('App Show')

+ 22 - 2
src/api/ApiRouter/taskOrder.ts

@@ -32,7 +32,8 @@ import {
   updatePipeTaskOrder,
   getPipeOrderForm,
   addPipeMajorIssues,
-  batchSuspendPipeOrderItem
+  batchSuspendPipeOrderItem,
+  cancelPipeInSpectProject
 } from '@/api/pipe/pipeTaskOrder'
 import {
   getBoilerTaskConfirmPage,
@@ -50,7 +51,8 @@ import {
   updateBoilerTaskOrder,
   getBoilerOrderForm,
   addBoilerMajorIssues,
-  batchSuspendBoilerOrderItem
+  batchSuspendBoilerOrderItem,
+  cancelBoilerInSpectProject
 } from '@/api/boiler/boilerTaskOrder'
 
 type Adapter = {
@@ -78,6 +80,7 @@ export enum TaskOrderFuncName {
   GetOrderForm,
   AddMajorIssues,
   BatchSuspendEquip,
+  BatchCancelReport,
 }
 
 // 接口注册表(按接口、设备类型调用对应接口)
@@ -399,6 +402,23 @@ const map = {
       reqFunction: batchSuspendBoilerOrderItem,
       outputAdapter: null,
     },
+  },
+  [TaskOrderFuncName.BatchCancelReport]: {
+    [EquipmentType.BOILER]: {
+      inputAdapter: null,
+      reqFunction: cancelBoilerInSpectProject,
+      outputAdapter: null,
+    },
+    [EquipmentType.PIPE]: {
+      inputAdapter: null,
+      reqFunction: cancelPipeInSpectProject,
+      outputAdapter: null,
+    },
+    [EquipmentType.CONTAINER]: {
+      inputAdapter: null,
+      reqFunction: cancelBoilerInSpectProject,
+      outputAdapter: null,
+    },
   }
 }
 

+ 1 - 1
src/api/boiler/boilerTaskOrder.ts

@@ -52,7 +52,7 @@ export const addInspectProject = (data: any) => {
 
 // 批量作废检验项目
 export const cancelBoilerInSpectProject = (data: any) => {
-  return httpDelete('/pressure2/boiler-task-order/boiler-order-item/report/batchCancel', data)
+  return httpDelete('/pressure2/boiler-task-order/boiler-order-item/report/batchCancel', null, data)
 }
 
 // 获取校核人

+ 4 - 0
src/api/index.ts

@@ -57,6 +57,10 @@ export const getReportTemplateDetail = (params: any) => {
   return httpGet('/pressure/report-template/get', params)
 }
 
+export const getPressure2ReportTemplateDetail = (params: any) => {
+  return httpGet('/pressure2/report-template/get', params)
+}
+
 export const getReportTemplateList = (params: any) => {
   return httpGet('/pressure/report-template/page', params)
 }

+ 1 - 1
src/api/pipe/pipeTaskOrder.ts

@@ -52,7 +52,7 @@ export const addInspectProject = (data: any) => {
 
 // 批量作废检验项目
 export const cancelPipeInSpectProject = (data: any) => {
-  return httpDelete('/pressure2/pipe-task-order/pipe-order-item/report/batchCancel', data)
+  return httpDelete('/pressure2/pipe-task-order/pipe-order-item/report/batchCancel', null, data)
 }
 
 // 获取校核人

+ 6 - 0
src/env.d.ts

@@ -31,3 +31,9 @@ interface ImportMetaEnv {
 interface ImportMeta {
   readonly env: ImportMetaEnv
 }
+
+interface Window {
+  ReactNativeWebView?: {
+    postMessage(message: string): void
+  }
+}

+ 3 - 3
src/interceptors/route.ts

@@ -37,9 +37,9 @@ const navigateToInterceptor = {
     if (hasLogin) {
       return true
     }
-    const redirectRoute = `${loginRoute}?redirect=${encodeURIComponent(url)}`
-    uni.navigateTo({ url: redirectRoute })
-    return false
+    // const redirectRoute = `${loginRoute}?redirect=${encodeURIComponent(url)}`
+    // uni.navigateTo({ url: redirectRoute })
+    return true
   },
 }
 

+ 13 - 28
src/pages/equipment/detail/components/BoilerInspectProject.vue

@@ -560,11 +560,10 @@ import { isCheckItemEditable, isAssignedToOthers } from '@/utils/equipmentPermis
 import {
   getApprovalDetail,
   getUserGroupUserList,
-  notVerifyPageApi,
-  addMajorIssuesApi,
+  pressure2NotVerifyPageApi,
 } from '@/api/task'
-import { getReportTemplateDetail } from '@/api'
-import { cancelBoilerInSpectProject } from '@/api/boiler/boilerTaskOrder'
+import { getReportTemplateDetail, getPressure2ReportTemplateDetail } from '@/api'
+import { cancelBoilerInSpectProject, addBoilerMajorIssues } from '@/api/boiler/boilerTaskOrder'
 import { updateBoilerTaskOrderItemReportConclusion } from '@/api/boiler/boilerTaskOrderReport'
 import TipsPopup from './inspectProjectComponent/TipsPopup.vue'
 import CalcCheckItemPopup from './inspectProject/component/calcCheckItemPopup.vue'
@@ -1161,10 +1160,10 @@ const handleAssociationOperation = (item: CheckItem) => {
 
 const showAddWorkInstructionPopup = async () => {
   try {
-    const result = await notVerifyPageApi({ type: '5', status: 200, pageNo: 1, pageSize: 9999 })
-    const list = (result?.data?.list || []).map((item: any) => ({
+    const result = await pressure2NotVerifyPageApi({ reportType: PressureReportType.WORKINSTRUCTION, status: 200, pageNo: 1, pageSize: 9999 })
+    const list = (result?.data || []).map((item: any) => ({
       ...item,
-      label: item.name || '',
+      label: item.tbName || '',
       value: item.id || '',
     }))
 
@@ -1201,29 +1200,15 @@ const handleConfirmTemplate = async () => {
   try {
     uni.showLoading({ title: '添加中...' })
 
-    const templateResult = await getReportTemplateDetail({ id: selectedTemplate.value.value })
-    const initTemplateJson = templateResult?.data?.reportDefaultJson
-      ? JSON.parse(templateResult?.data?.reportDefaultJson || '{}')
-      : {}
-
-    const defaultDataSource: Record<string, any> = {
-      ...initTemplateJson,
-      ...props.equipment,
-      prepareName: userInfo.value?.nickname || '',
-      prepareDate: dayjs().format('YYYY年MM月DD日'),
-    }
-
     const params = {
       orderId: props.orderId,
       orderItemId: props.orderItemId,
-      userGroupCategory: selectedTemplate.value?.userGroupCategory || '',
       templateId: selectedTemplate.value.value,
       prepareId: userInfo.value?.id || '',
       prepareName: userInfo.value?.nickname || '',
-      prepareJson: JSON.stringify(defaultDataSource),
     }
 
-    const result = await addMajorIssuesApi(params)
+    const result = await addBoilerMajorIssues(params)
 
     if (result.code !== 0) {
       uni.hideLoading()
@@ -1237,18 +1222,18 @@ const handleConfirmTemplate = async () => {
       uni.showToast({ title: '添加失败', icon: 'error' })
       return
     }
-
-    uni.hideLoading()
-    closeSelectTemplatePopup()
-    props.refreshDetail?.()
-
+    
     uni.navigateTo({
-      url: `/pages/equipment/detail/equipTestRecordEditor?userId=${userInfo.value?.id}&orderItemId=${props.orderItemId}&checkItemId=${newReportId}&templateId=${selectedTemplate.value.id}&equipCode=${props.equipment?.equipCode || ''}&useOnline=1&reportUrl=`,
+      url: `/pages/equipment/detail/equipCheckRecordEditor?userId=${userInfo.value?.id}&orderItemId=${props.orderItemId}&checkItemId=${newReportId}&templateId=${selectedTemplate.value.value}&equipCode=${props.equipment?.equipCode || ''}&useOnline=1&reportUrl=`,
     })
   } catch (error) {
     uni.hideLoading()
     console.error('添加指导书失败:', error)
     uni.showToast({ title: '添加指导书失败', icon: 'error' })
+  } finally {
+    uni.hideLoading()
+    closeSelectTemplatePopup()
+    props.refreshDetail?.()
   }
 }
 

+ 146 - 18
src/pages/equipment/detail/components/OtherReport.vue

@@ -61,15 +61,41 @@
       </view>
     </view>
 
-    <TipsPopup ref="tipsPopupRef" />
+    <view v-if="popupVisible" class="popup-overlay" @click="handlePopupCancel">
+      <view class="popup-content" @click.stop>
+        <view class="popup-header">
+          <text class="popup-title">作废项目</text>
+        </view>
+
+        <view class="popup-body">
+          <text class="popup-label">是否作废已选择的检验项目?</text>
+          <textarea
+            class="popup-textarea"
+            v-model="cancelReason"
+            placeholder="请输入作废理由"
+            :maxlength="200"
+          />
+        </view>
+
+        <view class="popup-footer">
+          <view class="popup-btn cancel-btn" @click="handlePopupCancel">
+            <text class="popup-btn-text">取消</text>
+          </view>
+          <view class="popup-btn confirm-btn" @click="handlePopupConfirm">
+            <text class="popup-btn-text confirm-btn-text">确定</text>
+          </view>
+        </view>
+      </view>
+    </view>
   </view>
 </template>
 
 <script lang="ts" setup>
 import { ref, watch, withDefaults } from 'vue'
 import { PressureReportType, PressureReportTypeMap } from '@/utils/dictMap'
-import TipsPopup from './inspectProjectComponent/TipsPopup.vue'
+import { useConfigStore } from '@/store/config'
 import eventBus from '@/utils/eventBus'
+import { requestFunc, TaskOrderFuncName } from '@/api/ApiRouter/taskOrder'
 
 interface ReportItem {
   id: string
@@ -93,6 +119,7 @@ interface Props {
   orderItemId?: string
 }
 
+const equipType = useConfigStore().getEquipType()
 const props = withDefaults(defineProps<Props>(), {
   otherReportList: () => [],
 })
@@ -102,10 +129,10 @@ const emit = defineEmits<{
   handleEditWorkInstruction: [item: ReportItem]
 }>()
 
-const tipsPopupRef = ref<any>(null)
+const popupVisible = ref(false)
+const cancelReason = ref('')
 const selectedProjects = ref<ReportItem[]>([])
 const selectAll = ref(false)
-const itemRefs = ref<Record<string, any>>({})
 
 const dataSource = ref<GroupItem[]>([])
 
@@ -180,22 +207,40 @@ const showDelReportPopup = () => {
     return
   }
 
-  tipsPopupRef.value?.show({
-    text: '是否作废已选择的检验项目?',
-    confirm: handleDelReport,
-  })
+  cancelReason.value = ''
+  popupVisible.value = true
 }
 
-const handleDelReport = async () => {
+const handlePopupCancel = () => {
+  popupVisible.value = false
+  cancelReason.value = ''
+}
+
+const handlePopupConfirm = () => {
+  if (!cancelReason.value.trim()) {
+    uni.showToast({ title: '请输入作废理由', icon: 'none' })
+    return
+  }
+
+  popupVisible.value = false
+  handleDelReport(cancelReason.value.trim())
+}
+
+const handleDelReport = async (reason: string) => {
   try {
     uni.showLoading({ title: '作废中...' })
+    const invalidItems =  selectedProjects.value.filter((item) => item.status !== 0)
+    if (invalidItems.length) {
+      uni.showToast({ title: '只能作废待提交的项目', icon: 'error' })
+      uni.hideLoading()
+      return
+    }
 
-    const cancelIds = selectedProjects.value.map((item) => item.id)
+    const cancelReportReq = selectedProjects.value.map((item) => ({ id: item.id, reason }))
     let result = null
 
     if (props.useOnline === '1') {
-      const { delReportApi } = await import('@/api/task')
-      const fetchResult = await delReportApi({ ids: cancelIds })
+      const fetchResult = await requestFunc(TaskOrderFuncName.BatchCancelReport, equipType, cancelReportReq)
       result = fetchResult.data
     } else {
       uni.showToast({ title: '离线模式暂不支持作废', icon: 'none' })
@@ -222,12 +267,6 @@ const handleDelReport = async () => {
 const initSelected = () => {
   selectAll.value = false
   selectedProjects.value = []
-
-  for (const key in itemRefs.value) {
-    if (itemRefs.value[key]?.setSelect) {
-      itemRefs.value[key].setSelect(false)
-    }
-  }
 }
 
 const showStatusTag = (item: ReportItem): boolean => {
@@ -245,6 +284,8 @@ const getStatusText = (item: ReportItem): string => {
         return '待提交'
       case 100:
         return '待批准'
+      case 200:
+        return '待批准'
       case 300:
         return '退回'
       default:
@@ -502,4 +543,91 @@ const handleViewDetail = async (item: ReportItem) => {
 .delete-btn {
   background-color: #ff4445;
 }
+
+.popup-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 9999;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: rgba(0, 0, 0, 0.5);
+}
+
+.popup-content {
+  width: 80%;
+  max-width: 320px;
+  overflow: hidden;
+  background-color: #fff;
+  border-radius: 8px;
+}
+
+.popup-header {
+  padding: 20px 15px 15px;
+  text-align: center;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.popup-title {
+  font-size: 18px;
+  font-weight: 600;
+  color: #333;
+}
+
+.popup-body {
+  padding: 20px 15px;
+}
+
+.popup-label {
+  font-size: 15px;
+  line-height: 1.5;
+  color: #666;
+}
+
+.popup-textarea {
+  width: 100%;
+  height: 80px;
+  padding: 10px;
+  margin-top: 12px;
+  font-size: 14px;
+  line-height: 1.5;
+  color: #333;
+  background-color: #f5f5f5;
+  border: 1px solid #e0e0e0;
+  border-radius: 4px;
+  box-sizing: border-box;
+}
+
+.popup-footer {
+  display: flex;
+  flex-direction: row;
+  border-top: 1px solid #f0f0f0;
+}
+
+.popup-btn {
+  flex: 1;
+  padding: 15px;
+  text-align: center;
+}
+
+.cancel-btn {
+  border-right: 1px solid #f0f0f0;
+}
+
+.popup-btn-text {
+  font-size: 16px;
+  color: #666;
+}
+
+.confirm-btn {
+  background-color: #fff;
+}
+
+.confirm-btn-text {
+  font-weight: 500;
+  color: #4B8CD9;
+}
 </style>

+ 3 - 1
src/pages/sign/index.vue

@@ -538,6 +538,8 @@ const submitConfirm = async () => {
     if (routeType.value === 'FWD') {
       params.receiverPhone = fwdInputPhone.value
       params.orderReportId = orderReportId.value
+    } else if (routeType.value === 'AQJC') {
+      params.securityCheckId = securityCheckId.value
     }
 
     const result: any = await requestFunc(SignFuncName.SubmitSign, equipType, params)
@@ -893,7 +895,7 @@ onMounted(() => {
   }
 
   .resign-btn {
-    background-color: #ffffff;
+    background-color: #e9e3e3;
     border-width: 2px;
     border-color: #000000;
     color: #000000;

+ 1 - 1
src/pages/taskOnline/TaskOnlineEquipmentList.vue

@@ -530,7 +530,7 @@ const createInform = async () => {
   }
 
   const selectedEquipment = selectedEquipments.value[0]
-  const majorIssue = selectedEquipment.reportDOList.find((item: any) => item.reportType == 500)
+  const majorIssue = selectedEquipment.orderItems[0].reportRespVOList.find((item: any) => item.reportType == 500)
   if (majorIssue) {
     return uni.showToast({ title: '该设备已添加了重大问题线索', icon: 'error' })
   }

+ 26 - 19
src/pages/user/index.vue

@@ -50,6 +50,7 @@
 
 <script lang="ts" setup>
 import { ref, onMounted } from 'vue'
+import { onShow } from '@dcloudio/uni-app'
 import { useUserStore } from '@/store/user'
 import { logout } from '@/api/login'
 import iconMap from '@/utils/imagesMap'
@@ -65,7 +66,7 @@ const systemInfo = uni.getSystemInfoSync()
 statusBarHeight.value = systemInfo.statusBarHeight || 20
 
 const userStore = useUserStore()
-const currentUserInfo = ref<Record<string, any>>({})
+const currentUserInfo = computed(() => userStore.userInfo)
 
 // 用户配置
 const userConfig = [
@@ -77,26 +78,27 @@ const userConfig = [
   // { label: '关于系统', field: 'version', type: 'text' },
 ]
 
-onMounted(() => {
-  loadUserInfo()
-})
+// onShow(() => {
+//   console.log('load user info')
+//   loadUserInfo()
+// })
 
 // 加载用户信息
-const loadUserInfo = () => {
-  try {
-    const userInfo = uni.getStorageSync('APP_USER_INFO')
-    if (userInfo) {
-      const info = { ...userInfo }
-      currentUserInfo.value = info
-    } else {
-      // 没有用户信息,跳转到登录页
-      uni.redirectTo({ url: '/pages/login/login' })
-    }
-  } catch (err) {
-    console.error('获取用户信息失败:', err)
-    uni.redirectTo({ url: '/pages/login/login' })
-  }
-}
+// const loadUserInfo = () => {
+//   try {
+//     const userInfo = uni.getStorageSync('APP_USER_INFO')
+//     if (userInfo) {
+//       const info = { ...JSON.parse(userInfo) }
+//       currentUserInfo.value = info
+//     } else {
+//       // 没有用户信息,跳转到登录页
+//       uni.redirectTo({ url: '/pages/login/login' })
+//     }
+//   } catch (err) {
+//     console.error('获取用户信息失败:', err)
+//     uni.redirectTo({ url: '/pages/login/login' })
+//   }
+// }
 
 // 获取图片 URL
 const getImage = (key: string) => {
@@ -124,6 +126,11 @@ const handleLogout = async () => {
     uni.removeStorageSync('APP_USER_INFO')
     uni.removeStorageSync('USER_LIST')
 
+    // 通知RN端也退出登录
+    if (window.ReactNativeWebView) {
+      window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'logout' }))
+    }
+
     // 跳转到登录页
     uni.reLaunch({ url: '/pages/login/login' })
   } catch (error) {

+ 6 - 5
src/router/index.ts

@@ -18,11 +18,12 @@ interface CacheRoute {
 export const beforEach = (to, from, next) => {
   try {
     const userInfo = uni.getStorageSync('APP_USER_INFO')
-    if (userInfo) {
-      next()
-    } else {
-      next({ path: loginPage })
-    }
+    // if (userInfo) {
+    //   next()
+    // } else {
+    //   next({ path: loginPage })
+    // }
+    next()
   } catch (err) {
     console.error('获取用户信息失败:', err)
     next({ path: loginPage })