Просмотр исходного кода

Merge remote-tracking branch 'origin/master'

ouyj 4 месяцев назад
Родитель
Сommit
06448be56b
35 измененных файлов с 2562 добавлено и 79 удалено
  1. 2 2
      .hbuilderx/launch.json
  2. 14 0
      api/index/index.uts
  3. 3 3
      api/order/detail.uts
  4. 34 2
      api/order/list.uts
  5. 27 20
      manifest.json
  6. 14 0
      pages.json
  7. 511 4
      pages/index/index.uvue
  8. 476 0
      pages/order/almostOverdue.uvue
  9. 30 6
      pages/order/detail/acceptIndex.uvue
  10. 36 9
      pages/order/detail/approveIndex.uvue
  11. 35 3
      pages/order/detail/index.uvue
  12. 36 10
      pages/order/index.uvue
  13. 483 0
      pages/order/overdue.uvue
  14. 0 3
      pages/profile/index.uvue
  15. 32 0
      types/order.uts
  16. 145 0
      uni_modules/android-keeplive/changelog.md
  17. 2 0
      uni_modules/android-keeplive/encrypt
  18. 109 0
      uni_modules/android-keeplive/package.json
  19. 490 0
      uni_modules/android-keeplive/readme.md
  20. 6 0
      uni_modules/android-keeplive/utssdk/app-android/config.json
  21. BIN
      uni_modules/android-keeplive/utssdk/app-android/index.uts
  22. BIN
      uni_modules/android-keeplive/utssdk/app-android/libs/cactus-release.aar
  23. BIN
      uni_modules/android-keeplive/utssdk/app-android/res/drawable/icon.png
  24. BIN
      uni_modules/android-keeplive/utssdk/app-harmony/index.uts
  25. 20 0
      uni_modules/android-keeplive/utssdk/app-harmony/module.json5
  26. 20 0
      uni_modules/android-keeplive/utssdk/app-harmony/resources/base/element/string.json
  27. BIN
      uni_modules/android-keeplive/utssdk/app-ios/KeepLive.swift
  28. BIN
      uni_modules/android-keeplive/utssdk/app-ios/Resources/main.mp3
  29. 3 0
      uni_modules/android-keeplive/utssdk/app-ios/config.json
  30. BIN
      uni_modules/android-keeplive/utssdk/app-ios/index.uts
  31. 18 0
      uni_modules/android-keeplive/utssdk/app-ios/info.plist
  32. BIN
      uni_modules/android-keeplive/utssdk/app-ios/info.zip
  33. 0 0
      uni_modules/android-keeplive/utssdk/interface.uts
  34. 1 0
      uni_modules/android-keeplive/utssdk/unierror.uts
  35. 15 17
      utils/request.uts

+ 2 - 2
.hbuilderx/launch.json

@@ -2,8 +2,8 @@
     "version" : "1.0",
     "configurations" : [
         {
-            "customPlaygroundType" : "device",
-            "playground" : "standard",
+            "customPlaygroundType" : "local",
+            "playground" : "custom",
             "type" : "uni-app:app-android"
         }
     ]

+ 14 - 0
api/index/index.uts

@@ -0,0 +1,14 @@
+/**
+ */
+import { request } from '../../utils/request'
+
+/**
+ * 获取通知消息
+ */
+export const getMyNotify = (userId: string): Promise<any> => {
+    let url = `/mobile/notify/${userId}`
+    return request({
+        url: url,
+        method: 'GET'
+    })
+}

+ 3 - 3
api/order/detail.uts

@@ -2,7 +2,7 @@
  * 工作台详情接口
  */
 import { request } from '../../utils/request'
-import type { acceptOrderInfo } from '../../types/order'
+import type { acceptOrderInfo, acceptOrderInfo2 } from '../../types/order'
 
 /**
  * 根据 ID 获取维保工单详情
@@ -27,7 +27,7 @@ export const getRepairOrderInfoById = (id: string): Promise<any> => {
 }
 
 // 接单(支持一次性选择处理人员和检修人员)
-export const acceptOrder = (gxtWorkOrder: acceptOrderInfo | null): Promise<any> => {
+export const acceptOrder = (gxtWorkOrder: acceptOrderInfo2 | null): Promise<any> => {
 	const plainObject = gxtWorkOrder != null ? JSON.parse(JSON.stringify(gxtWorkOrder)) : null;
 	const data: UTSJSONObject | null = plainObject as UTSJSONObject;
 	return request({
@@ -49,7 +49,7 @@ export const suspendOrder = (gxtWorkOrder: acceptOrderInfo | null): Promise<any>
 }
 
 // 审批
-export const approveOrder = (gxtWorkOrder: acceptOrderInfo | null): Promise<any> => {
+export const approveOrder = (gxtWorkOrder: acceptOrderInfo2 | null): Promise<any> => {
 	const plainObject = gxtWorkOrder != null ? JSON.parse(JSON.stringify(gxtWorkOrder)) : null;
 	const data: UTSJSONObject | null = plainObject as UTSJSONObject;
 	return request({

+ 34 - 2
api/order/list.uts

@@ -15,7 +15,6 @@ export const getOrderList = (page: number, rows: number, keyword: string | null,
     if (keyword != null && keyword.length > 0) {
         // 支持工单编号和风机编号查询
         url += `&keyword=${encodeURIComponent(keyword)}`
-        // url += `&pcsDeviceName=${encodeURIComponent(keyword)}`
     }
     // 添加状态筛选参数
     if (status != null && status.length > 0) {
@@ -25,4 +24,37 @@ export const getOrderList = (page: number, rows: number, keyword: string | null,
         url: url,
         method: 'GET'
     })
-}
+}
+/*
+ * 获取即将超时列表
+ * @param page 页码
+ * @param rows 每页数量
+ */
+export const almostOverdueList = (page: number, rows: number, keyword: string | null): Promise<any> => {
+    let url = `/mobile/order/almostOverdue?pageNum=${page}&pageSize=${rows}`
+	if (keyword != null && keyword.length > 0) {
+	    // 支持工单编号和风机编号查询
+	    url += `&keyword=${encodeURIComponent(keyword)}`
+	}
+    return request({
+        url: url,
+        method: 'GET'
+    })
+}
+
+/*
+ * 获取超时列表
+ * @param page 页码
+ * @param rows 每页数量
+ */
+export const overdueList = (page: number, rows: number, keyword: string | null): Promise<any> => {
+    let url = `/mobile/order/overdue?pageNum=${page}&pageSize=${rows}`
+	if (keyword != null && keyword.length > 0) {
+	    // 支持工单编号和风机编号查询
+	    url += `&keyword=${encodeURIComponent(keyword)}`
+	}
+    return request({
+        url: url,
+        method: 'GET'
+    })
+}

+ 27 - 20
manifest.json

@@ -1,9 +1,9 @@
 {
-	"name": "uniappx-init",
+	"name": "工效通APP",
 	"appid": "__UNI__1050C07",
-	"description": "uniappx框架,支持安卓和鸿蒙系统",
-	"versionName": "1.0.10",
-	"versionCode": "1010",
+	"description": "工效通任务管理平台",
+	"versionName": "1.1.2",
+	"versionCode": "112",
 	"uni-app-x": {},
 	"quickapp": {},
 	"mp-weixin": {
@@ -55,32 +55,39 @@
 		"distribute": {
 			"modules": {
 				"uni-map": {},
-				"uni-location": {},
-				"uni-push": {
-					"hms": {},
-					"oppo": {},
-					"vivo": {},
-					"xiaomi": {},
-					"meizu": {},
-					"honor": {},
-					"fcm": {}
-				}
+				"uni-location": {}
 			},
 			"icons": {
-				"hdpi": "",
-				"xhdpi": "",
-				"xxhdpi": "",
-				"xxxhdpi": ""
+				"hdpi": "E:/宇光同行/工效APP/app/logo72.png",
+				"xhdpi": "E:/宇光同行/工效APP/app/logo96.png",
+				"xxhdpi": "E:/宇光同行/工效APP/app/logo144.png",
+				"xxxhdpi": "E:/宇光同行/工效APP/app/logo192.png"
 			},
 			"splashScreens": {
-				"default": {}
+				"default": {
+					"xhdpi": "E:/宇光同行/工效APP/app/1.png",
+					"xxhdpi": "E:/宇光同行/工效APP/app/1.png",
+					"xxxhdpi": "E:/宇光同行/工效APP/app/1.png"
+				},
+				"icon": {
+					"xhdpi": "E:/宇光同行/工效APP/app/logo.png",
+					"xxhdpi": "E:/宇光同行/工效APP/app/logo.png",
+					"xxxhdpi": "E:/宇光同行/工效APP/app/logo.png"
+				},
+				"brand": {
+					"xhdpi": "E:/宇光同行/工效APP/app/logo72.png",
+					"xxhdpi": "E:/宇光同行/工效APP/app/logo96.png",
+					"xxxhdpi": "E:/宇光同行/工效APP/app/logo144.png"
+				}
 			},
 			"abiFilters": [
 				"armeabi-v7a",
 				"arm64-v8a",
 				"x86",
 				"x86_64"
-			]
+			],
+			"targetSdkVersion": "33",
+			"minSdkVersion": "21"
 		}
 	},
 	"app-ios": {

+ 14 - 0
pages.json

@@ -127,6 +127,20 @@
 				"navigationBarTitleText": "恢复",
 				"navigationStyle": "#custom"
 			}
+		},
+		{
+			"path": "pages/order/overdue",
+			"style": {
+				"navigationBarTitleText": "超时工单",
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/order/almostOverdue",
+			"style": {
+				"navigationBarTitleText": "即将超时工单",
+				"navigationStyle": "custom"
+			}
 		}
 	],
 	"globalStyle": {

+ 511 - 4
pages/index/index.uvue

@@ -26,7 +26,8 @@
 					</view>
 					<text class="db-text">评分工单</text>
 				</view>
-				<view class="db-box">
+				<view class="db-box" @click="navigateToOverdueOrders">
+					<view v-if="overdueCount > 0" class="badge"><text class="count">{{ overdueCount }}</text></view>
 					<view class="db-block">
 						<view class="db-center-3">
 							<image class="db-image" src="/static/images/map/2.png"></image>
@@ -46,6 +47,76 @@
 				<button @click="handlePush">通知</button>
 			</view> -->
 
+			<!-- 即将超时工单列表 -->
+			<view class="section-title-container" v-if="almostOverdueListData.length > 0">
+				<view class="section-header">
+					<text class="section-title">即将超时工单</text>
+					<text class="view-all" @click="navigateToAlmostOverdueOrders">查看全部</text>
+				</view>
+			</view>
+			<common-list
+				v-if="almostOverdueListData.length > 0"
+				:dataList="almostOverdueListData.slice(0, 2)"
+				:loading="almostOverdueLoading"
+				:hasMore="false"
+				:refresherEnabled="false"
+				:itemKey="'id'"
+				@itemClick="handleAlmostOverdueItemClick"
+			>
+				<template #default="{ item }">
+					<view class="list-item">
+						<view class="item-container">
+							<view class="item-header">
+								<text class="item-title">{{ getPcsDeviceName(item) }}-{{ getStationName(item) }}</text>
+								<!-- <text class="status-tag status-assigned">{{ getWorkOrderStatus(item) }}</text> -->
+							</view>
+							<view class="info-row">
+								<text class="text-gray">工单编号:{{ getWorkOrderProjectNo(item) }}</text>
+								<text class="text-gray" :class="getRemarkClass(item)">{{ getRemark(item) }}</text>
+							</view>
+						</view>
+					</view>
+				</template>
+				<template #loadMore>
+					<view></view>
+				</template>
+			</common-list>
+
+			<!-- 超时工单列表 -->
+			<view class="section-title-container" v-if="overdueListData.length > 0">
+				<view class="section-header">
+					<text class="section-title">超时工单</text>
+					<text class="view-all" @click="navigateToOverdueOrders">查看全部</text>
+				</view>
+			</view>
+			<common-list
+				v-if="overdueListData.length > 0"
+				:dataList="overdueListData.slice(0, 2)"
+				:loading="overdueLoading"
+				:hasMore="false"
+				:refresherEnabled="false"
+				:itemKey="'id'"
+				@itemClick="handleOverdueItemClick"
+			>
+				<template #default="{ item }">
+					<view class="list-item">
+						<view class="item-container">
+							<view class="item-header">
+								<text class="item-title">{{ getPcsDeviceName(item) }}-{{ getStationName(item) }}</text>
+								<!-- <text class="status-tag status-suspended">{{ getWorkOrderStatus(item) }}</text> -->
+							</view>
+							<view class="info-row">
+								<text class="text-gray">工单编号:{{ getWorkOrderProjectNo(item) }}</text>
+								<text class="text-gray overdue-title">{{ getRemark(item) }}</text>
+							</view>
+						</view>
+					</view>
+				</template>
+				<template #loadMore>
+					<view></view>
+				</template>
+			</common-list>
+
         </scroll-view>
 
         <!-- 底部 TabBar -->
@@ -57,9 +128,85 @@
     import { ref, onMounted } from 'vue'
     import { getUserInfo } from '../../utils/storage'
     import FlowChart from '../../components/index/flow-chart/flow-chart.uvue'
-    import { getOrderList } from '../../api/order/list'
+    import { getOrderList, almostOverdueList, overdueList } from '../../api/order/list'
     import { listMobileOrderScores } from '../../api/score/index'
-
+	import type { SysDictData } from '../../types/dict'
+	import { getDictDataByType } from '../../api/dict/index'
+	// import {startKeepAlive,stopKeepAlive} from '@/uni_modules/ygtx-keepService'
+	// import { RequestOption } from '@/uni_modules/ygtx-keepService/utssdk/interface.uts';
+	import { getBaseUrl } from '../../utils/request'
+	import { KeepLive } from '@/uni_modules/android-keeplive'
+	import { getMyNotify } from '../../api/index/index'
+
+	// const handleStartKeepAlive = (userId: string) => {
+	// 	let notifyUrl = getBaseUrl() + "/mobile/notify";
+	// 	console.log("通知地址:" + notifyUrl)
+	// 	const requestOption:RequestOption = {
+	// 		requestUrl: notifyUrl, // 你的接口地址(必填)
+	// 		requestData: JSON.stringify({ method: "get", data: userId }), // 请求数据(字符串格式,必填)
+	// 		task_interval: 10000 // 任务间隔(毫秒,必填)
+	// 	  };
+	// 	startKeepAlive(requestOption,
+	// 	(res:any)=>{
+	// 		console.log(res)
+	// 	});
+	// };
+	
+	const handleKeepAlive = (userId: string)=>{
+		var keep=new KeepLive()
+		keep.setTitle("工效通")
+		keep.setContent("工效通正在运行")
+		// keep.setLargeIcon("icon");
+		keep.setSmallIcon("icon"); //图标名字  图标放在 插件下面的 uni_modules\android-keeplive\utssdk\app-android\res 文件夹下
+		keep.onAddBackgroundCallback(function(res:boolean){
+		    console.log("后台运行 "+res)
+		})
+		keep.onAddScrrenListenerCallback(function(res:boolean){
+		    console.log("屏幕开启状态 "+res)
+		})  
+		keep.setWakeLock(1,"keeptag");// 设置唤醒类型
+		keep.setAutoStartEnable(true)
+		keep.doStartApplicationWithPackageName("uni.app.UNI1050C07");
+		
+		if(!keep.checkAppNotification()){
+		    keep.onOpenNotificationSetting(function(res:boolean){
+		        keep.register();
+		        var ignoring=  keep.isIgnoringBatteryOptimizations();
+		        if(!ignoring){
+		            keep.requestIgnoreBatteryOptimizations();
+		        }
+		    })
+		}else{
+		    keep.register();
+		    var ignoring=  keep.isIgnoringBatteryOptimizations();
+		    if(!ignoring){
+		        keep.requestIgnoreBatteryOptimizations();
+		    }
+		}
+		
+		// keep.wifilock();
+		// 稳定定时器 需要的用户使用(默认定时器1 )
+		keep.onStartCSystemTimer(10,function(){
+		    console.log("onStartCSystemTimer ");
+			getMyNotify(userId).then((result:any) => {
+				const jsonData = JSON.stringify(result)
+				const respData = JSON.parse(jsonData) as UTSJSONObject
+				if (respData['code'] == 200 &&
+					respData.hasOwnProperty('data') && respData['data'] != null) {
+					const data = respData['data'] as UTSJSONObject
+					const title = data["title"] as string
+					const desc = data["desc"] as string
+					keep.setTitle(title);
+					keep.setContent(desc);
+					keep.updateNotification();
+				}
+			  }).catch((error) => {
+				console.error('Promise 执行失败:', error)
+			  });
+		    keep.acquire(1000);// 唤醒一秒钟
+		});
+	}
+	
     // 用户名
     const userName = ref<string>('用户')
 
@@ -69,6 +216,63 @@
 	// 待自评工单数量
 	const selfScoreCount = ref<number>(0)
 
+	// 超时工单数量
+	const overdueCount = ref<number>(0)
+
+	// 即将超时工单列表
+	const almostOverdueListData = ref<any[]>([])
+	const almostOverdueLoading = ref<boolean>(false)
+
+	// 超时工单列表
+	const overdueListData = ref<any[]>([])
+	const overdueLoading = ref<boolean>(false)
+	
+	// 维保类型字典列表
+	const inspectionTypeList = ref<SysDictData[]>([]) 
+	// 添加字典加载状态
+	const dictLoaded = ref<boolean>(false)
+	
+	// 获取工单状态字典列表
+	const loadStatusDictList = async (): Promise<void> => {
+	    try {
+	        const result = await getDictDataByType('gxt_inspection_type')
+	        const resultObj = result as UTSJSONObject
+	
+	        if (resultObj['code'] == 200) {
+	            const data = resultObj['data'] as any[]
+	            const dictData: SysDictData[] = []
+	
+	            if (data.length > 0) {
+	                for (let i = 0; i < data.length; i++) {
+	                    const item = data[i] as UTSJSONObject
+	                    // 只提取需要的字段
+	                    const dictItem: SysDictData = {
+							dictValue: item['dictValue'] as string | null,
+							dictLabel: item['dictLabel'] as string | null,
+							dictCode: null,
+							dictSort: null,
+							dictType: null,
+							cssClass: null,
+							listClass: null,
+							isDefault: null,
+							status: null,
+							default: null,
+							createTime: null,
+							remark: null
+						}
+	                    dictData.push(dictItem)
+	                }
+	            }
+	
+	            inspectionTypeList.value = dictData
+	            dictLoaded.value = true
+	        }
+	    } catch (e: any) {
+	        console.error('获取工单状态字典失败:', e.message)
+	        dictLoaded.value = true
+	    }
+	}
+
 	// 获取待接单数量
 	const loadAssignedCount = async (): Promise<void> => {
 	    try {
@@ -105,6 +309,57 @@
 	    }
 	}
 
+	// 获取超时工单数量
+	const loadOverdueCount = async (): Promise<void> => {
+	    try {
+	        const result = await overdueList(1, 1, '') // 只需要获取总数,不需要具体数据
+	        const resultObj = result as UTSJSONObject
+
+	        if (resultObj['code'] == 200) {
+	            const total = resultObj['total'] as number
+	            overdueCount.value = total
+	        }
+	    } catch (e: any) {
+	        console.error('获取超时工单数量失败:', e.message)
+	    }
+	}
+
+	// 获取即将超时工单列表
+	const loadAlmostOverdueList = async (): Promise<void> => {
+		try {
+			almostOverdueLoading.value = true
+			const result = await almostOverdueList(1, 2, '') // 获取前2条
+			const resultObj = result as UTSJSONObject
+
+			if (resultObj['code'] == 200) {
+				const rows = resultObj['rows'] as any[]
+				almostOverdueListData.value = rows
+			}
+		} catch (e: any) {
+			console.error('获取即将超时工单列表失败:', e.message)
+		} finally {
+			almostOverdueLoading.value = false
+		}
+	}
+
+	// 获取超时工单列表
+	const loadOverdueList = async (): Promise<void> => {
+		try {
+			overdueLoading.value = true
+			const result = await overdueList(1, 2, '') // 获取前2条
+			const resultObj = result as UTSJSONObject
+
+			if (resultObj['code'] == 200) {
+				const data = resultObj['rows'] as any[]
+				overdueListData.value = data
+			}
+		} catch (e: any) {
+			console.error('获取超时工单列表失败:', e.message)
+		} finally {
+			overdueLoading.value = false
+		}
+	}
+
 	// 跳转到待接单列表
 	const navigateToAssignedOrders = (): void => {
 		// 使用 redirectTo 而不是 switchTab,因为工单页面不是 tabBar 页面
@@ -130,6 +385,22 @@
 		// }, 500)
 	}
 
+	// 跳转到超时工单列表
+	const navigateToOverdueOrders = (): void => {
+		// 跳转到超时工单页面
+		uni.navigateTo({
+		    url: '/pages/order/overdue'
+		})
+	}
+
+	// 跳转到即将超时工单列表
+	const navigateToAlmostOverdueOrders = (): void => {
+		// 跳转到即将超时工单页面
+		uni.navigateTo({
+		    url: '/pages/order/almostOverdue'
+		})
+	}
+
 	const handleCreateChannel = (showToast : boolean) => {
 	  // #ifdef APP-ANDROID
 	  const manager = uni.getPushChannelManager()
@@ -212,12 +483,124 @@
 		handleCreateLocalNotification();
 	};
 
+	// 辅助函数:从 any 类型提取属性
+	const getWorkOrderProjectNo = (item: any | null): string | null => {
+		if (item == null) return ''
+		const orderInfoItem = item as UTSJSONObject
+		return orderInfoItem['workOrderProjectNo'] as string != null ? orderInfoItem['workOrderProjectNo'] as string : ''
+	}
+
+	const getPcsDeviceName = (item: any | null): string | null=> {
+		if (item == null) return ''
+		const orderInfoItem = item as UTSJSONObject
+		return orderInfoItem['pcsDeviceName'] as string != null ? orderInfoItem['pcsDeviceName'] as string : ''
+	}
+
+	const getStationName = (item: any | null): string | null=> {
+		if (item == null) return ''
+		const orderInfoItem = item as UTSJSONObject
+		return orderInfoItem['pcsStationName'] as string != null ? orderInfoItem['pcsStationName'] as string : ''
+	}
+
+	const getCreateTime = (item: any | null): string|null => {
+		if (item == null) return null
+		const orderInfoItem = item as UTSJSONObject
+		return orderInfoItem['createTime'] as string != null ? orderInfoItem['createTime'] as string : ''
+	}
+	const getRemark = (item: any | null): string|null => {
+		if (item == null) return null
+		const orderInfoItem = item as UTSJSONObject
+		return orderInfoItem['remark'] as string != null ? orderInfoItem['remark'] as string : ''
+	}
+	
+	// 根据剩余时间获取颜色类名
+	const getRemarkClass = (item: any | null): string => {
+		if (item == null) return ''
+		const orderInfoItem = item as UTSJSONObject
+		const remark = orderInfoItem['remark'] as string
+		
+		if (remark == null || remark.length === 0) return ''
+		
+		// 解析备注中的剩余时间(假设格式为包含数字和小时的字符串)
+		// 例如:"剩余时间:5小时" 或 "还剩10小时"
+		const timeMatch = remark.match(/(\d+(\.\d+)?)\s*(小时|时)/)
+		
+		if (timeMatch != null && timeMatch.length > 1 && timeMatch[1] != null) {
+			const hours = parseFloat(timeMatch[1] as string)
+			
+			if (hours < 6) {
+				return 'time-critical' // 红色
+			} else if (hours < 12) {
+				return 'time-warning' // 橙色
+			} else if (hours < 24) {
+				return 'time-notice' // 黄色
+			}
+		}
+		
+		return ''
+	}
+	
+	// 辅助函数:从 any 类型提取属性
+	const getOrderType = (item: any | null): string => {
+	    if (item == null) return ''
+	    const orderInfoItem = item as UTSJSONObject
+	    return orderInfoItem['orderType'] == 1?"维修工单":"维保工单";
+	}
+	
+	const getInspectionType = (item: any | null): string | null => {
+	    if (item == null) return ''
+	    const orderInfoItem = item as UTSJSONObject
+	    const rawStatus = orderInfoItem['inspectionType']
+	
+	    if (rawStatus==null) return ''
+		// 如果字典尚未加载,返回原始值
+		    if (!dictLoaded.value) {
+		        return rawStatus
+		    }
+	    // 查找字典中对应的标签
+	    const dictItem = inspectionTypeList.value.find(dict => dict.dictValue == rawStatus)
+	    return dictItem!=null ? dictItem.dictLabel : rawStatus
+	}
+
+	// 即将超时工单点击事件
+	const handleAlmostOverdueItemClick = (item: any, index: number): void => {
+		if (item == null) return
+		const orderItem = item as UTSJSONObject
+		try {
+			// 跳转到工单详情页
+			uni.navigateTo({
+			    url: `/pages/order/detail/index?id=${orderItem['id']}&orderType=${orderItem['orderType']}`
+			})
+		} catch (e) {
+			console.error('处理即将超时工单点击事件失败:', e)
+		}
+	}
+
+	// 超时工单点击事件
+	const handleOverdueItemClick = (item: any, index: number): void => {
+		if (item == null) return
+		const orderItem = item as UTSJSONObject
+		try {
+			// 跳转到工单详情页
+			uni.navigateTo({
+			    url: `/pages/order/detail/index?id=${orderItem['id']}&orderType=${orderItem['orderType']}`
+			})
+		} catch (e) {
+			console.error('处理超时工单点击事件失败:', e)
+		}
+	}
+
     // 初始化
     onMounted(() => {
         const userInfo = getUserInfo()
         if (userInfo != null) {
             const realName = userInfo['nickName'] as string | null
             userName.value = realName ?? '用户'
+			const userId = userInfo['userId']?.toString()
+			if(userId!=null){
+				console.log("监听:"+userId)
+				handleKeepAlive(userId)
+			}
         }
 
 		// 加载待接单数量
@@ -226,6 +609,15 @@
 		// 加载待自评工单数量
 		loadSelfScoreCount()
 
+		// 加载超时工单数量
+		loadOverdueCount()
+
+		// 加载即将超时工单列表
+		loadAlmostOverdueList()
+
+		// 加载超时工单列表
+		loadOverdueList()
+
 		// 监听工单状态更新事件
 		uni.$on('refreshAssignedCount', () => {
 			loadAssignedCount()
@@ -235,6 +627,11 @@
 		uni.$on('refreshSelfScoreCount', () => {
 			loadSelfScoreCount()
 		})
+		
+		// 监听超时工单状态更新事件
+		uni.$on('refreshOverdueCount', () => {
+			loadOverdueCount()
+		})
     })
 </script>
 
@@ -294,9 +691,24 @@
         font-size: 32rpx;
         color: #333333;
         font-weight: bold;
-        margin-bottom: 20rpx;
+        // margin-bottom: 20rpx;
     }
 
+	.section-title-container {
+		padding: 20rpx 30rpx 10rpx 30rpx;
+	}
+	
+	.section-header {
+		flex-direction: row;
+		justify-content: space-between;
+		align-items: center;
+	}
+	
+	.view-all {
+		font-size: 28rpx;
+		color: #165dff;
+	}
+
     /* 图表区域 */
     .chart-section {
         padding: 30rpx;
@@ -373,4 +785,99 @@
 		text-align: center;
 		color: #ffffff;
 	}
+
+	.list-item {
+		margin: 0 30rpx 24rpx 30rpx;
+		background-color: #ffffff;
+		border-radius: 16rpx;
+	}
+
+	.item-container {
+		padding: 30rpx;
+	}
+
+	.item-header {
+		flex-direction: row;
+		align-items: center;
+		margin-bottom: 16rpx;
+
+		.item-title {
+			flex: 1;
+			font-size: 32rpx;
+			color: #333333;
+			font-weight: bold;
+		}
+
+		.detail-link {
+			font-size: 28rpx;
+			color: #999999;
+		}
+	}
+
+	.btn-primary {
+		font-size: 14px;
+		background-color: #165DFF;
+		color: #ffffff;
+	}
+
+	.info-row {
+		flex-direction: row;
+		justify-content: space-between;
+		align-items: center;
+
+		.info-label {
+			font-size: 26rpx;
+			color: #666;
+		}
+
+		.info-value {
+			font-size: 26rpx;
+		}
+	}
+
+	.text-gray{
+		font-size: 26rpx;
+		color: #666;
+	}
+
+	/* 剩余时间颜色样式 */
+	.time-critical {
+		color: #ff4d4f; /* 红色 */
+	}
+
+	.time-warning {
+		color: #fa8c16; /* 橙色 */
+	}
+
+	.time-notice {
+		color: #faad14; /* 黄色 */
+	}
+
+	.status-tag {
+		padding: 8rpx 20rpx;
+		border-radius: 20rpx;
+		font-size: 24rpx;
+		white-space: nowrap;
+		margin-left: 20rpx;
+		border: 1rpx solid;
+	}
+
+	/* 已超时工单标题红色样式 */
+	.overdue-title {
+		color: #ff4d4f;
+	}
+
+	/* 待接单 */
+	.status-assigned {
+		background-color: #ebf5ff;
+		color: #409eff;
+		border-color: #d8ebff;
+	}
+
+	/* 已挂起 */
+	.status-suspended {
+		background-color: #fff2f0;
+		color: #ff4d4f;
+		border-color: #ffccc7;
+	}
 </style>

+ 476 - 0
pages/order/almostOverdue.uvue

@@ -0,0 +1,476 @@
+<template>
+	<uni-navbar-lite :showLeft=true title="即将超时工单"></uni-navbar-lite>
+    <view class="list-page">
+        <!-- 搜索栏 -->
+        <view class="search-bar">
+            <view class="search-box">
+                <image class="search-icon" src="/static/images/workbench/list/1.png" mode="aspectFit"></image>
+                <input class="search-input" type="text" placeholder="搜索工单编号、风机编号" v-model="keyword" @confirm="handleSearch" @blur="handleSearch" />
+                <text v-if="keyword.length > 0" class="clear-icon" @click="clearSearch">✕</text>
+            </view>
+        </view>
+
+        <!-- 列表内容 -->
+        <common-list
+            :dataList="dataList"
+            :loading="loading"
+            :refreshing="refreshing"
+            :hasMore="hasMore"
+            @refresh="handleRefresh"
+            @loadMore="loadMore"
+            @itemClick="handleItemClick"
+        >
+            <template #default="{ item, index }">
+                <view class="list-item">
+                    <view class="item-container">
+                        <view class="item-header">
+							<text class="item-title">{{ getWorkOrderProjectNo(item) }}-{{ getPcsDeviceName(item) }}{{ getOrderType(item) }}</text>
+							<text class="status-tag" :class="getStatusClass(item)">{{ getWorkOrderStatus(item) }}</text>
+                        </view>
+						<view class="info-row">
+							<view class="info-label">
+								<text class="text-gray">{{ getCreateTime(item) }}</text>
+							</view>
+						</view>
+                    </view>
+                </view>
+            </template>
+        </common-list>
+    </view>
+</template>
+
+<script setup lang="uts">
+import { ref, onBeforeUnmount, onMounted } from 'vue'
+import type { acceptOrderInfo } from '../../types/order'
+import type { SysDictData } from '../../types/dict'
+import { almostOverdueList } from '../../api/order/list'
+import { getDictDataByType } from '../../api/dict/index'
+
+    // 列表数据
+    const dataList = ref<acceptOrderInfo[]>([])
+    let keyword = ref<string>("")
+    const page = ref<number>(1)
+    const pageSize: number = 10
+    const hasMore = ref<boolean>(true)
+    const loading = ref<boolean>(false)
+    const refreshing = ref<boolean>(false)
+    const total = ref<number>(0)
+    const statusDictList = ref<SysDictData[]>([]) // 工单状态字典列表
+
+	// 添加字典加载状态
+	const dictLoaded = ref<boolean>(false)
+
+	// 获取工单状态字典列表
+	const loadStatusDictList = async (): Promise<void> => {
+	    try {
+	        const result = await getDictDataByType('gxt_work_order_status')
+	        const resultObj = result as UTSJSONObject
+
+	        if (resultObj['code'] == 200) {
+	            const data = resultObj['data'] as any[]
+	            const dictData: SysDictData[] = []
+
+	            if (data.length > 0) {
+	                for (let i = 0; i < data.length; i++) {
+	                    const item = data[i] as UTSJSONObject
+	                    // 只提取需要的字段
+	                    const dictItem: SysDictData = {
+							dictValue: item['dictValue'] as string | null,
+							dictLabel: item['dictLabel'] as string | null,
+							dictCode: null,
+							dictSort: null,
+							dictType: null,
+							cssClass: null,
+							listClass: null,
+							isDefault: null,
+							status: null,
+							default: null,
+							createTime: null,
+							remark: null
+						}
+	                    dictData.push(dictItem)
+	                }
+	            }
+
+	            statusDictList.value = dictData
+	            dictLoaded.value = true
+	        }
+	    } catch (e: any) {
+	        console.error('获取工单状态字典失败:', e.message)
+	        dictLoaded.value = true
+	    }
+	}
+
+    // 加载列表数据
+    const loadData = async (isRefresh: boolean | null): Promise<void> => {
+        if (loading.value) {
+            // 如果正在加载,直接重置刷新状态
+            refreshing.value = false
+            return
+        }
+
+        try {
+            loading.value = true
+
+            // 处理默认值
+            const shouldRefresh = isRefresh != null ? isRefresh : false
+
+            if (shouldRefresh) {
+                page.value = 1
+            }
+			console.log("searchKeyword===" + keyword.value)
+            // 调用 API,传递关键字参数
+            const searchKeyword = keyword.value.length > 0 ? keyword.value : null
+
+            const result = await almostOverdueList(page.value, pageSize, searchKeyword)
+
+            // 提取响应数据
+            const resultObj = result as UTSJSONObject
+            const code = resultObj['code'] as number
+            const responseData = resultObj['rows'] as any[]
+            const responseTotal = resultObj['total'] as number
+
+            if (code == 200) {
+                // 将 any[] 转换为 acceptOrderInfo[]
+                const newData: acceptOrderInfo[] = []
+                for (let i = 0; i < responseData.length; i++) {
+                    const item = responseData[i] as UTSJSONObject
+                    const orderItem: acceptOrderInfo = {
+						orderType: item['orderType'] as Number,
+                        id: item['id'] as Number,
+						teamLeaderId: item['teamLeaderId'] != null ? (item['teamLeaderId'] as Number) : 0,
+						acceptUserId: item['acceptUserId'] != null ? (item['acceptUserId'] as Number) : 0,
+                        teamLeaderName: item['teamLeaderName'] as string | null,
+                        acceptUserName: item['acceptUserName'] as string | null,
+                        acceptTime: item['acceptTime'] as string | null,
+                        assignTime: item['assignTime'] as string | null,
+                        assignUserName: item['assignUserName'] as string | null,
+                        status: (item['status']==null)?0:item['status'] as Number,
+                        workOrderProjectNo: item['workOrderProjectNo'] as string | null,
+                        workOrderStatus: item['workOrderStatus'] as string | null,
+                        gxtCenterId: item['gxtCenterId'] as Number | 0,
+                        gxtCenter: item['gxtCenter'] as string | null,
+                        pcsStationId: item['pcsStationId'] as Number | 0,
+                        pcsStationName: item['pcsStationName'] as string | null,
+                        pcsDeviceId: item['pcsDeviceId'] as Number | 0,
+                        pcsDeviceName: item['pcsDeviceName'] as string | null,
+                        brand: item['brand'] as string | null,
+                        model: item['model'] as string | null,
+                        createTime: item['createTime'] as string | null,
+						suspendReason: item['suspendReason'] as string | null,
+						rejectionReason: item['rejectionReason'] as string | null
+                    }
+                    newData.push(orderItem)
+                }
+
+                if (shouldRefresh) {
+                    dataList.value = newData
+                } else {
+                    dataList.value = [...dataList.value, ...newData]
+                }
+
+                total.value = responseTotal
+                hasMore.value = dataList.value.length < responseTotal
+            } else {
+                const msg = resultObj['msg'] as string | null
+                uni.showToast({
+                    title: msg ?? '加载失败',
+                    icon: 'none'
+                })
+            }
+
+        } catch (e: any) {
+            uni.showToast({
+                title: e.message ?? '加载失败',
+                icon: 'none'
+            })
+        } finally {
+            loading.value = false
+            // #ifdef WEB
+            // Web 平台立即重置
+            refreshing.value = false
+            // #endif
+            // #ifndef WEB
+            // App 平台延迟重置刷新状态,确保 UI 更新
+            setTimeout(() => {
+                refreshing.value = false
+            }, 100)
+            // #endif
+        }
+
+        // #ifdef WEB
+        // Web 平台额外确保重置
+        refreshing.value = false
+        // #endif
+    }
+
+    // 辅助函数:从 any 类型提取属性
+    const getOrderType = (item: any | null): string => {
+        if (item == null) return ''
+        const orderInfoItem = item as acceptOrderInfo
+        return orderInfoItem.orderType == 1?"维修工单":"维保工单";
+    }
+
+    const getWorkOrderProjectNo = (item: any | null): string | null => {
+        if (item == null) return ''
+        const orderInfoItem = item as acceptOrderInfo
+        return orderInfoItem.workOrderProjectNo
+    }
+
+    const getPcsDeviceName = (item: any | null): string | null=> {
+        if (item == null) return ''
+        const orderInfoItem = item as acceptOrderInfo
+        return orderInfoItem.pcsDeviceName
+    }
+
+	const getCreateTime = (item: any | null): string|null => {
+	    if (item == null) return null
+	    const orderInfoItem = item as acceptOrderInfo
+	    return orderInfoItem.createTime
+	}
+
+	const getWorkOrderStatus = (item: any | null): string | null => {
+	    if (item == null) return ''
+	    const orderInfoItem = item as acceptOrderInfo
+	    const rawStatus = orderInfoItem.workOrderStatus
+
+	    if (rawStatus==null) return ''
+
+		// 如果字典尚未加载,返回原始值
+		if (!dictLoaded.value) {
+		    return rawStatus
+		}
+
+	    // 查找字典中对应的标签
+	    const dictItem = statusDictList.value.find(dict => dict.dictValue == rawStatus)
+	    return dictItem!=null ? dictItem.dictLabel : rawStatus
+	}
+	
+	const getStatusClass = (item: any | null): string => {
+		if (item == null) return ''
+		const orderInfoItem = item as acceptOrderInfo
+		const rawStatus = orderInfoItem.workOrderStatus
+		if (rawStatus==null) return ''
+		// const status = rawStatus
+		// 返回对应的状态类名
+		return `status-${rawStatus}`
+	}
+
+    // 下拉刷新
+    const handleRefresh = async (): Promise<void> => {
+        refreshing.value = true
+        await loadData(true as boolean | null)
+    }
+
+    // 加载更多
+    const loadMore = (): void => {
+        if (!hasMore.value || loading.value) {
+            return
+        }
+        page.value++
+        loadData(false as boolean | null)
+    }
+
+    // 搜索
+    const handleSearch = (): void => {
+        page.value = 1
+		console.log("======搜索=====" + keyword.value)
+        loadData(true as boolean | null)
+    }
+
+    // 点击列表项
+    const handleItemClick = (item: any | null, index: number): void => {
+        if (item == null) return
+        const orderItem = item as acceptOrderInfo
+		// 跳转到工单详情页
+		uni.navigateTo({
+		    url: `/pages/order/detail/index?id=${orderItem.id}&orderType=${orderItem.orderType}`
+		})
+    }
+
+    // 清空搜索
+    const clearSearch = (): void => {
+        keyword.value = ""
+        page.value = 1
+        loadData(true)
+    }
+
+	// 初始化
+	onMounted(() => {
+	    loadStatusDictList()
+	    loadData(true as boolean | null)
+	})
+
+    // 组件卸载前清理事件监听
+    onBeforeUnmount(() => {
+        refreshing.value = false
+        loading.value = false
+    })
+</script>
+
+<style lang="scss">
+    .list-page {
+        flex: 1;
+        background-color: #e8f0f9;
+    }
+
+    .search-bar {
+        padding: 20rpx 30rpx;
+        background-color: #d7eafe;
+    }
+
+    .search-box {
+        flex-direction: row;
+        align-items: center;
+        height: 72rpx;
+        padding: 0 24rpx;
+        background-color: #f5f5f5;
+        border-radius: 36rpx;
+
+        .search-icon {
+            width: 32rpx;
+            height: 32rpx;
+            margin-right: 12rpx;
+        }
+
+        .search-input {
+            flex: 1;
+            font-size: 28rpx;
+            color: #333333;
+        }
+
+        .clear-icon {
+            margin-left: 12rpx;
+            font-size: 28rpx;
+            color: #999999;
+        }
+    }
+
+    .list-item {
+        margin: 24rpx 30rpx;
+        background-color: #ffffff;
+        border-radius: 16rpx;
+    }
+
+    .item-container {
+        padding: 30rpx;
+    }
+
+    .item-header {
+        flex-direction: row;
+        align-items: center;
+        margin-bottom: 16rpx;
+
+        .item-title {
+            flex: 1;
+            font-size: 32rpx;
+            color: #333333;
+            font-weight: bold;
+        }
+
+        .detail-link {
+            font-size: 28rpx;
+            color: #999999;
+        }
+    }
+
+.item-header {
+  flex-direction: row;
+  align-items: flex-start;
+  margin-bottom: 16rpx;
+
+  .item-title {
+    font-size: 30rpx;
+    color: #333333;
+    font-weight: bold;
+    flex-wrap: wrap;
+    flex: 0 1 80%;
+    min-width: 0;
+  }
+
+  .info-value {
+    font-size: 28rpx;
+    color: #999999;
+    margin-left: auto;
+    flex: 0 0 auto;
+    white-space: nowrap;
+  }
+}
+.info-row {
+  flex-direction: row;
+  justify-content: space-between;
+  align-items: center;
+
+  .info-label {
+    font-size: 26rpx;
+    color: #666;
+  }
+
+  .info-value {
+    font-size: 26rpx;
+  }
+}
+.text-gray{
+  font-size: 26rpx;
+  color: #666;
+}
+
+.status-tag {
+	padding: 8rpx 20rpx;
+	border-radius: 20rpx;
+	font-size: 24rpx;
+	white-space: nowrap;
+	margin-left: 20rpx;
+	border: 1rpx solid;
+}
+
+/* 待接单 */
+.status-assigned {
+	background-color: #ebf5ff;
+	color: #409eff;
+	border-color: #d8ebff;
+}
+
+
+/* 待结单 */
+.status-to_finish {
+	background-color: #fff7e6;
+	color: #fa8c16;
+	border-color: #ffd591;
+}
+
+/* 待审批 */
+.status-to_approve {
+	background-color: #fff7e6;
+	color: #fa8c16;
+	border-color: #ffd591;
+}
+
+/* 已挂起 */
+.status-suspended {
+	background-color: #fff2f0;
+	color: #ff4d4f;
+	border-color: #ffccc7;
+}
+
+/* 已完成 */
+.status-completed {
+	background-color: #f0f9eb;
+	color: #5cb87a;
+	border-color: #c2e7b0;
+}
+
+/* 待下发 */
+.status-to_issue {
+	background-color: #f4f4f5;
+	color: #909399;
+	border-color: #e9e9eb;
+}
+
+/* 已归档 */
+.status-archived {
+	background-color: #f0f9eb;
+	color: #5cb87a;
+	border-color: #c2e7b0;
+}
+</style>

+ 30 - 6
pages/order/detail/acceptIndex.uvue

@@ -39,7 +39,22 @@
 					    <text class="info-label">下发时间</text>
 					    <text class="info-value">{{ detailData.assignTime ?? '' }}</text>
 					</view>
-
+					<view class="info-item" v-if="detailData.orderType == 2">
+					    <text class="info-label">MIS工单编号</text>
+					    <text class="info-value">{{ detailData.misNo ?? '' }}</text>
+					</view>
+					<view class="info-item" v-if="detailData.orderType == 2">
+					    <text class="info-label">维保内容</text>
+					    <text class="info-value">{{ detailData.content ?? '' }}</text>
+					</view>
+					<view class="info-item" v-if="detailData.orderType == 1">
+					    <text class="info-label">故障代码</text>
+					    <text class="info-value">{{ detailData.faultCode ?? '' }}</text>
+					</view>
+					<view class="info-item" v-if="detailData.orderType == 1">
+					    <text class="info-label">故障信息</text>
+					    <text class="info-value">{{ detailData.faultBarcode ?? '' }}</text>
+					</view>
                 </view>
             </view>
 			<!-- <view class="info-section">
@@ -88,6 +103,7 @@
 			                @click="selectLeaderManually(index)"
 			            >
 			                <text class="option-text">{{ option.label }}</text>
+							<text class="option-text">{{ option.value }}</text>
 			                <text v-if="index === selectedTeamLeaderIndex" class="option-check">✓</text>
 			            </view>
 			        </scroll-view>
@@ -131,7 +147,7 @@
 
 <script setup lang="uts">
     import { ref } from 'vue'
-    import type { acceptOrderInfo } from '../../../types/order'
+    import type { acceptOrderInfo2 } from '../../../types/order'
     import type { WorkOrderFlow } from '../../../types/flow'
     import { getOrderInfoById, getRepairOrderInfoById, acceptOrder } from '../../../api/order/detail'
 	import type { SysDictData } from '../../../types/dict'
@@ -145,7 +161,7 @@
 	const dictLoaded = ref<boolean>(false)
 
 	// 详情数据
-	const detailData = ref<acceptOrderInfo>({
+	const detailData = ref<acceptOrderInfo2>({
 		orderType: 0,
 		id: 0,
 		teamLeaderId: 0,
@@ -169,7 +185,11 @@
 		createTime: null,
 		workOrderFlowList: null,
 		suspendReason: null,
-		rejectionReason: null
+		rejectionReason: null,
+		misNo: null,
+		content: null,
+		faultCode: null,
+		faultBarcode: null
 	})
 
 	// 选择器选项类型
@@ -402,7 +422,7 @@
                 }
 
                 // 转换数据
-                const orderDtail: acceptOrderInfo = {
+                const orderDtail: acceptOrderInfo2 = {
                     orderType: data['orderType'] as Number,
                     id: data['id'] as Number,
   					teamLeaderId: data['teamLeaderId'] != null ? (data['teamLeaderId'] as Number) : 0,
@@ -426,7 +446,11 @@
                     createTime: data['createTime'] as string | null,
                     workOrderFlowList: workOrderFlowList,
 					suspendReason: data['suspendReason'] as string | null,
-					rejectionReason: data['rejectionReason'] as string | null
+					rejectionReason: data['rejectionReason'] as string | null,
+					misNo: data['misNo'] as string | null,
+					content: data['content'] as string | null,
+					faultCode: data['faultCode'] as string | null,
+					faultBarcode: data['faultBarcode'] as string | null
                 }
                 detailData.value = orderDtail
 

+ 36 - 9
pages/order/detail/approveIndex.uvue

@@ -39,7 +39,26 @@
 					    <text class="info-label">下发时间</text>
 					    <text class="info-value">{{ detailData.assignTime ?? '' }}</text>
 					</view>
-
+					<view class="info-item" v-if="detailData.orderType == 2">
+					    <text class="info-label">MIS工单编号</text>
+					    <text class="info-value">{{ detailData.misNo ?? '' }}</text>
+					</view>
+					<view class="info-item" v-if="detailData.orderType == 2">
+					    <text class="info-label">维保内容</text>
+					    <text class="info-value">{{ detailData.content ?? '' }}</text>
+					</view>
+					<view class="info-item" v-if="detailData.orderType == 1">
+					    <text class="info-label">故障代码</text>
+					    <text class="info-value">{{ detailData.faultCode ?? '' }}</text>
+					</view>
+					<view class="info-item" v-if="detailData.orderType == 1">
+					    <text class="info-label">故障信息</text>
+					    <text class="info-value">{{ detailData.faultBarcode ?? '' }}</text>
+					</view>
+					<view class="info-item">
+					    <text class="info-label">挂起原因</text>
+					    <text class="info-value">{{ getSuspendReasonName(detailData.suspendReason) ?? '' }}</text>
+					</view>
                 </view>
             </view>
 			<!-- <view class="info-section">
@@ -110,7 +129,7 @@
 
 <script setup lang="uts">
     import { ref } from 'vue'
-    import type { acceptOrderInfo } from '../../../types/order'
+    import type { acceptOrderInfo2 } from '../../../types/order'
     import type { WorkOrderFlow } from '../../../types/flow'
     import { getOrderInfoById, getRepairOrderInfoById, approveOrder } from '../../../api/order/detail'
 	import type { SysDictData } from '../../../types/dict'
@@ -124,7 +143,7 @@
 	const dictLoaded = ref<boolean>(false)
 
 	// 详情数据
-	const detailData = ref<acceptOrderInfo>({
+	const detailData = ref<acceptOrderInfo2>({
 		orderType: 0,
 		id: 0,
 		teamLeaderId: 0,
@@ -148,7 +167,11 @@
 		createTime: null,
 		workOrderFlowList: null,
 		suspendReason: null,
-		rejectionReason: null
+		rejectionReason: null,
+		misNo: null,
+		content: null,
+		faultCode: null,
+		faultBarcode: null
 	})
 
 	// 选择器选项类型
@@ -207,7 +230,7 @@
 	// 获取工单状态字典列表
 	const loadStatusDictList = async (): Promise<void> => {
 	    try {
-	        const result = await getDictDataByType('gxt_repair_order_flow_action_type')
+	        const result = await getDictDataByType('gxt_order_suspend_reason')
 	        const resultObj = result as UTSJSONObject
 
 	        if (resultObj['code'] == 200) {
@@ -310,8 +333,8 @@
 
     const loading = ref<boolean>(false)
 
-	// 获取操作类型名称
-	const getActionTypeName = (item: string | null): string | null => {
+	// 获取挂起原因名称
+	const getSuspendReasonName = (item: string | null): string | null => {
 	    if (item == null) return ''
 	    // const orderInfoItem = item as orderInfo
 	    const rawStatus = item
@@ -383,7 +406,7 @@
                 }
 
                 // 转换数据
-                const orderDtail: acceptOrderInfo = {
+                const orderDtail: acceptOrderInfo2 = {
                     orderType: data['orderType'] as Number,
                     id: data['id'] as Number,
   					teamLeaderId: data['teamLeaderId'] != null ? (data['teamLeaderId'] as Number) : 0,
@@ -407,7 +430,11 @@
                     createTime: data['createTime'] as string | null,
                     workOrderFlowList: workOrderFlowList,
 					suspendReason: data['suspendReason'] as string | null,
-					rejectionReason: data['rejectionReason'] as string | null
+					rejectionReason: data['rejectionReason'] as string | null,
+					misNo: data['misNo'] as string | null,
+					content: data['content'] as string | null,
+					faultCode: data['faultCode'] as string | null,
+					faultBarcode: data['faultBarcode'] as string | null
                 }
                 detailData.value = orderDtail
 

+ 35 - 3
pages/order/detail/index.uvue

@@ -38,9 +38,10 @@
             <view class="info-section">
                 <view class="section-title">
                     <text class="section-title-text">工单流转</text>
+                    <text @click="toggleFlowList" v-if="detailData.workOrderFlowList != null && detailData.workOrderFlowList.length > 1" class="toggle-btn">{{ isFlowListExpanded ? '收起' : '展开' }}</text>
                 </view>
                 <view class="info-card" v-if="detailData.workOrderFlowList != null && detailData.workOrderFlowList.length > 0">
-                    <view class="flow-item" v-for="(flow, index) in detailData.workOrderFlowList" :key="index">
+                    <view class="flow-item" v-for="(flow, index) in displayedFlowList" :key="index">
                         <view class="flow-header">
                             <text class="flow-operator">{{ flow.operatorName ?? '未知操作人' }}</text>
                             <text class="flow-time">{{ flow.actionTime ?? '' }}</text>
@@ -65,7 +66,7 @@
 </template>
 
 <script setup lang="uts">
-    import { ref } from 'vue'
+    import { ref, computed } from 'vue'
     import type { acceptOrderInfo } from '../../../types/order'
     import type { WorkOrderFlow } from '../../../types/flow'
     import { getOrderInfoById, getRepairOrderInfoById } from '../../../api/order/detail'
@@ -146,6 +147,28 @@
 
     const loading = ref<boolean>(false)
 
+    // 控制工单流转列表是否展开
+    const isFlowListExpanded = ref<boolean>(false)
+    
+    // 计算显示的工单流转列表
+    const displayedFlowList = computed(() => {
+        if (detailData.value.workOrderFlowList == null) return []
+        
+        // 如果已经展开,则显示全部
+        if (isFlowListExpanded.value) {
+            return detailData.value.workOrderFlowList
+        }
+        
+        // 默认只显示最后一条
+        const length = detailData.value.workOrderFlowList.length
+        return length > 0 ? [detailData.value.workOrderFlowList[length - 1]] : []
+    })
+    
+    // 切换工单流转列表的展开/收起状态
+    const toggleFlowList = () => {
+        isFlowListExpanded.value = !isFlowListExpanded.value
+    }
+
 	// 获取操作类型名称
 	const getActionTypeName = (item: string | null): string | null => {
 	    if (item == null) return ''
@@ -155,7 +178,7 @@
 	    if (rawStatus==null) return ''
 
 		// 如果字典尚未加载,返回原始值
-		if (!dictLoaded.value) {
+		if (dictLoaded.value == false) {
 			return rawStatus
 		}
 
@@ -299,6 +322,9 @@
             position: relative;
             padding-left: 20rpx;
             margin-bottom: 20rpx;
+            flex-direction: row;
+            justify-content: space-between;
+            align-items: center;
 
             &::before {
                 // content: '';
@@ -317,6 +343,12 @@
                 font-weight: bold;
                 color: #333333;
             }
+
+            .toggle-btn {
+				padding-right: 20rpx;
+                font-size: 28rpx;
+                color: #165dff;
+            }
         }
 
         .info-card {

+ 36 - 10
pages/order/index.uvue

@@ -10,17 +10,27 @@
             </view>
         </view>
 
-		<view class="status-bar">
-			<scroll-view class="status-scroll" scroll-x="true" show-scrollbar="false">
-				<view class="status-box">
+		<view class="status-bar">			
+			<scroll-view class="scroll-view_H" direction="horizontal" show-scrollbar="false">
+				<view class="scroll-view-item_H uni-bg-red">
 					<text class="status-txt" :class="{'stauts-sel': currentStatus === ''}" @click="switchStatus('')">全部</text>
+				</view>
+				<view class="scroll-view-item_H uni-bg-green">
 					<text class="status-txt" :class="{'stauts-sel': currentStatus === 'assigned'}" @click="switchStatus('assigned')">待接单</text>
+				</view>
+				<view class="scroll-view-item_H">
 					<text class="status-txt" :class="{'stauts-sel': currentStatus === 'to_finish'}" @click="switchStatus('to_finish')">待结单</text>
+				</view>
+				<view class="scroll-view-item_H">
 					<text class="status-txt" :class="{'stauts-sel': currentStatus === 'to_approve'}" @click="switchStatus('to_approve')">待审批</text>
+				</view>
+				<view class="scroll-view-item_H">
 					<text class="status-txt" :class="{'stauts-sel': currentStatus === 'suspended'}" @click="switchStatus('suspended')">已挂起</text>
+				</view>
+				<view class="scroll-view-item_H">
 					<text class="status-txt" :class="{'stauts-sel': currentStatus === 'completed'}" @click="switchStatus('completed')">已完成</text>
 				</view>
-			</scroll-view>
+		  </scroll-view>
 		</view>
         <!-- 列表内容 -->
         <common-list
@@ -648,9 +658,6 @@ import { getDictDataByType } from '../../api/dict/index'
 	background-color: #fff7e6;
 	color: #fa8c16;
 	border-color: #ffd591;
-	// background-color: #fff2f0;
-	// color: #ff4d4f;
-	// border-color: #ffccc7;
 }
 
 /* 待审批 */
@@ -658,9 +665,6 @@ import { getDictDataByType } from '../../api/dict/index'
 	background-color: #fff7e6;
 	color: #fa8c16;
 	border-color: #ffd591;
-	// background-color: #f6ffed;
-	// color: #52c41a;
-	// border-color: #b7eb8f;
 }
 
 /* 已挂起 */
@@ -690,4 +694,26 @@ import { getDictDataByType } from '../../api/dict/index'
 	color: #5cb87a;
 	border-color: #c2e7b0;
 }
+.scroll-view_H {
+	width: 100%;
+	flex-direction: row;
+  }
+
+.scroll-view-item_H {
+  justify-content: center;
+  align-items: center;
+  
+  .status-txt{
+	padding: 8px 12px;
+	text-align: center;
+	margin-right: 12rpx;
+	border-radius: 36rpx;
+	background-color: #fff;
+	font-size: 28rpx;
+  }
+  .stauts-sel{
+	background-color: #007AFF;
+	color: #fff;
+  }
+}
 </style>

+ 483 - 0
pages/order/overdue.uvue

@@ -0,0 +1,483 @@
+<template>
+	<uni-navbar-lite :showLeft=true title="超时工单"></uni-navbar-lite>
+    <view class="list-page">
+        <!-- 搜索栏 -->
+        <view class="search-bar">
+            <view class="search-box">
+                <image class="search-icon" src="/static/images/workbench/list/1.png" mode="aspectFit"></image>
+                <input class="search-input" type="text" placeholder="搜索工单编号、风机编号" v-model="keyword" @confirm="handleSearch" @blur="handleSearch" />
+                <text v-if="keyword.length > 0" class="clear-icon" @click="clearSearch">✕</text>
+            </view>
+        </view>
+
+        <!-- 列表内容 -->
+        <common-list
+            :dataList="dataList"
+            :loading="loading"
+            :refreshing="refreshing"
+            :hasMore="hasMore"
+            @refresh="handleRefresh"
+            @loadMore="loadMore"
+            @itemClick="handleItemClick"
+        >
+            <template #default="{ item, index }">
+                <view class="list-item">
+                    <view class="item-container">
+                        <view class="item-header">
+							<text class="item-title">{{ getWorkOrderProjectNo(item) }}-{{ getPcsDeviceName(item) }}{{ getOrderType(item) }}</text>
+							<text class="status-tag" :class="getStatusClass(item)">{{ getWorkOrderStatus(item) }}</text>
+                        </view>
+						<view class="info-row">
+							<view class="info-label">
+								<text class="text-gray">{{ getCreateTime(item) }}</text>
+							</view>
+						</view>
+                    </view>
+                </view>
+            </template>
+        </common-list>
+    </view>
+</template>
+
+<script setup lang="uts">
+import { ref, onBeforeUnmount, onMounted } from 'vue'
+import type { acceptOrderInfo } from '../../types/order'
+import type { SysDictData } from '../../types/dict'
+import { overdueList } from '../../api/order/list'
+import { getDictDataByType } from '../../api/dict/index'
+
+    // 列表数据
+    const dataList = ref<acceptOrderInfo[]>([])
+    let keyword = ref<string>("")
+    const page = ref<number>(1)
+    const pageSize: number = 10
+    const hasMore = ref<boolean>(true)
+    const loading = ref<boolean>(false)
+    const refreshing = ref<boolean>(false)
+    const total = ref<number>(0)
+    const statusDictList = ref<SysDictData[]>([]) // 工单状态字典列表
+
+	// 添加字典加载状态
+	const dictLoaded = ref<boolean>(false)
+
+	// 获取工单状态字典列表
+	const loadStatusDictList = async (): Promise<void> => {
+	    try {
+	        const result = await getDictDataByType('gxt_work_order_status')
+	        const resultObj = result as UTSJSONObject
+
+	        if (resultObj['code'] == 200) {
+	            const data = resultObj['data'] as any[]
+	            const dictData: SysDictData[] = []
+
+	            if (data.length > 0) {
+	                for (let i = 0; i < data.length; i++) {
+	                    const item = data[i] as UTSJSONObject
+	                    // 只提取需要的字段
+	                    const dictItem: SysDictData = {
+							dictValue: item['dictValue'] as string | null,
+							dictLabel: item['dictLabel'] as string | null,
+							dictCode: null,
+							dictSort: null,
+							dictType: null,
+							cssClass: null,
+							listClass: null,
+							isDefault: null,
+							status: null,
+							default: null,
+							createTime: null,
+							remark: null
+						}
+	                    dictData.push(dictItem)
+	                }
+	            }
+
+	            statusDictList.value = dictData
+	            dictLoaded.value = true
+	        }
+	    } catch (e: any) {
+	        console.error('获取工单状态字典失败:', e.message)
+	        dictLoaded.value = true
+	    }
+	}
+
+    // 加载列表数据
+    const loadData = async (isRefresh: boolean | null): Promise<void> => {
+        if (loading.value) {
+            // 如果正在加载,直接重置刷新状态
+            refreshing.value = false
+            return
+        }
+
+        try {
+            loading.value = true
+
+            // 处理默认值
+            const shouldRefresh = isRefresh != null ? isRefresh : false
+
+            if (shouldRefresh) {
+                page.value = 1
+            }
+			console.log("searchKeyword===" + keyword.value)
+            // 调用 API,传递关键字参数
+            const searchKeyword = keyword.value.length > 0 ? keyword.value : null
+
+            const result = await overdueList(page.value, pageSize, searchKeyword)
+
+            // 提取响应数据
+            const resultObj = result as UTSJSONObject
+            const code = resultObj['code'] as number
+            const responseData = resultObj['rows'] as any[]
+            const responseTotal = resultObj['total'] as number
+
+            if (code == 200) {
+                // 将 any[] 转换为 acceptOrderInfo[]
+                const newData: acceptOrderInfo[] = []
+                for (let i = 0; i < responseData.length; i++) {
+                    const item = responseData[i] as UTSJSONObject
+                    const orderItem: acceptOrderInfo = {
+						orderType: item['orderType'] as Number,
+                        id: item['id'] as Number,
+						teamLeaderId: item['teamLeaderId'] != null ? (item['teamLeaderId'] as Number) : 0,
+						acceptUserId: item['acceptUserId'] != null ? (item['acceptUserId'] as Number) : 0,
+                        teamLeaderName: item['teamLeaderName'] as string | null,
+                        acceptUserName: item['acceptUserName'] as string | null,
+                        acceptTime: item['acceptTime'] as string | null,
+                        assignTime: item['assignTime'] as string | null,
+                        assignUserName: item['assignUserName'] as string | null,
+                        status: (item['status']==null)?0:item['status'] as Number,
+                        workOrderProjectNo: item['workOrderProjectNo'] as string | null,
+                        workOrderStatus: item['workOrderStatus'] as string | null,
+                        gxtCenterId: item['gxtCenterId'] as Number | 0,
+                        gxtCenter: item['gxtCenter'] as string | null,
+                        pcsStationId: item['pcsStationId'] as Number | 0,
+                        pcsStationName: item['pcsStationName'] as string | null,
+                        pcsDeviceId: item['pcsDeviceId'] as Number | 0,
+                        pcsDeviceName: item['pcsDeviceName'] as string | null,
+                        brand: item['brand'] as string | null,
+                        model: item['model'] as string | null,
+                        createTime: item['createTime'] as string | null,
+						suspendReason: item['suspendReason'] as string | null,
+						rejectionReason: item['rejectionReason'] as string | null
+                    }
+                    newData.push(orderItem)
+                }
+
+                if (shouldRefresh) {
+                    dataList.value = newData
+                } else {
+                    dataList.value = [...dataList.value, ...newData]
+                }
+
+                total.value = responseTotal
+                hasMore.value = dataList.value.length < responseTotal
+            } else {
+                const msg = resultObj['msg'] as string | null
+                uni.showToast({
+                    title: msg ?? '加载失败',
+                    icon: 'none'
+                })
+            }
+
+        } catch (e: any) {
+            uni.showToast({
+                title: e.message ?? '加载失败',
+                icon: 'none'
+            })
+        } finally {
+            loading.value = false
+            // #ifdef WEB
+            // Web 平台立即重置
+            refreshing.value = false
+            // #endif
+            // #ifndef WEB
+            // App 平台延迟重置刷新状态,确保 UI 更新
+            setTimeout(() => {
+                refreshing.value = false
+            }, 100)
+            // #endif
+        }
+
+        // #ifdef WEB
+        // Web 平台额外确保重置
+        refreshing.value = false
+        // #endif
+    }
+
+    // 辅助函数:从 any 类型提取属性
+    const getOrderType = (item: any | null): string => {
+        if (item == null) return ''
+        const orderInfoItem = item as acceptOrderInfo
+        return orderInfoItem.orderType == 1?"维修工单":"维保工单";
+    }
+
+    const getWorkOrderProjectNo = (item: any | null): string | null => {
+        if (item == null) return ''
+        const orderInfoItem = item as acceptOrderInfo
+        return orderInfoItem.workOrderProjectNo
+    }
+
+    const getPcsDeviceName = (item: any | null): string | null=> {
+        if (item == null) return ''
+        const orderInfoItem = item as acceptOrderInfo
+        return orderInfoItem.pcsDeviceName
+    }
+
+	const getCreateTime = (item: any | null): string|null => {
+	    if (item == null) return null
+	    const orderInfoItem = item as acceptOrderInfo
+	    return orderInfoItem.createTime
+	}
+
+	const getWorkOrderStatus = (item: any | null): string | null => {
+	    if (item == null) return ''
+	    const orderInfoItem = item as acceptOrderInfo
+	    const rawStatus = orderInfoItem.workOrderStatus
+
+	    if (rawStatus==null) return ''
+
+		// 如果字典尚未加载,返回原始值
+		if (!dictLoaded.value) {
+		    return rawStatus
+		}
+
+	    // 查找字典中对应的标签
+	    const dictItem = statusDictList.value.find(dict => dict.dictValue == rawStatus)
+	    return dictItem!=null ? dictItem.dictLabel : rawStatus
+	}
+	
+	const getStatusClass = (item: any | null): string => {
+		if (item == null) return ''
+		const orderInfoItem = item as acceptOrderInfo
+		const rawStatus = orderInfoItem.workOrderStatus
+		if (rawStatus==null) return ''
+		// const status = rawStatus
+		// 返回对应的状态类名
+		return `status-${rawStatus}`
+	}
+
+    // 下拉刷新
+    const handleRefresh = async (): Promise<void> => {
+        refreshing.value = true
+        await loadData(true as boolean | null)
+    }
+
+    // 加载更多
+    const loadMore = (): void => {
+        if (!hasMore.value || loading.value) {
+            return
+        }
+        page.value++
+        loadData(false as boolean | null)
+    }
+
+    // 搜索
+    const handleSearch = (): void => {
+        page.value = 1
+		console.log("======搜索=====" + keyword.value)
+        loadData(true as boolean | null)
+    }
+
+    // 点击列表项
+    const handleItemClick = (item: any | null, index: number): void => {
+        if (item == null) return
+        const orderItem = item as acceptOrderInfo
+		// 跳转到工单详情页
+		uni.navigateTo({
+		    url: `/pages/order/detail/index?id=${orderItem.id}&orderType=${orderItem.orderType}`
+		})
+    }
+
+    // 清空搜索
+    const clearSearch = (): void => {
+        keyword.value = ""
+        page.value = 1
+        loadData(true)
+    }
+
+	// 初始化
+	onMounted(() => {
+	    loadStatusDictList()
+	    loadData(true as boolean | null)
+	})
+
+    // 组件卸载前清理事件监听
+    onBeforeUnmount(() => {
+        refreshing.value = false
+        loading.value = false
+    })
+</script>
+
+<style lang="scss">
+    .list-page {
+        flex: 1;
+        background-color: #e8f0f9;
+    }
+
+    .search-bar {
+        padding: 20rpx 30rpx;
+        background-color: #d7eafe;
+    }
+
+    .search-box {
+        flex-direction: row;
+        align-items: center;
+        height: 72rpx;
+        padding: 0 24rpx;
+        background-color: #f5f5f5;
+        border-radius: 36rpx;
+
+        .search-icon {
+            width: 32rpx;
+            height: 32rpx;
+            margin-right: 12rpx;
+        }
+
+        .search-input {
+            flex: 1;
+            font-size: 28rpx;
+            color: #333333;
+        }
+
+        .clear-icon {
+            margin-left: 12rpx;
+            font-size: 28rpx;
+            color: #999999;
+        }
+    }
+
+    .list-item {
+        margin: 24rpx 30rpx;
+        background-color: #ffffff;
+        border-radius: 16rpx;
+    }
+
+    .item-container {
+        padding: 30rpx;
+    }
+
+    .item-header {
+        flex-direction: row;
+        align-items: center;
+        margin-bottom: 16rpx;
+
+        .item-title {
+            flex: 1;
+            font-size: 32rpx;
+            color: #333333;
+            font-weight: bold;
+        }
+
+        .detail-link {
+            font-size: 28rpx;
+            color: #999999;
+        }
+    }
+
+.item-header {
+  flex-direction: row;
+  align-items: flex-start;
+  margin-bottom: 16rpx;
+
+  .item-title {
+    font-size: 30rpx;
+    color: #333333;
+    font-weight: bold;
+    flex-wrap: wrap;
+    flex: 0 1 80%;
+    min-width: 0;
+  }
+
+  .info-value {
+    font-size: 28rpx;
+    color: #999999;
+    margin-left: auto;
+    flex: 0 0 auto;
+    white-space: nowrap;
+  }
+}
+.info-row {
+  flex-direction: row;
+  justify-content: space-between;
+  align-items: center;
+
+  .info-label {
+    font-size: 26rpx;
+    color: #666;
+  }
+
+  .info-value {
+    font-size: 26rpx;
+  }
+}
+.text-gray{
+  font-size: 26rpx;
+  color: #666;
+}
+
+.status-tag {
+	padding: 8rpx 20rpx;
+	border-radius: 20rpx;
+	font-size: 24rpx;
+	white-space: nowrap;
+	margin-left: 20rpx;
+	border: 1rpx solid;
+}
+
+/* 待接单 */
+.status-assigned {
+	background-color: #ebf5ff;
+	color: #409eff;
+	border-color: #d8ebff;
+}
+
+
+/* 待结单 */
+.status-to_finish {
+	background-color: #fff7e6;
+	color: #fa8c16;
+	border-color: #ffd591;
+}
+
+/* 待审批 */
+.status-to_approve {
+	background-color: #fff7e6;
+	color: #fa8c16;
+	border-color: #ffd591;
+}
+
+/* 已挂起 */
+.status-suspended {
+	background-color: #fff2f0;
+	color: #ff4d4f;
+	border-color: #ffccc7;
+}
+
+/* 已完成 */
+.status-completed {
+	background-color: #f0f9eb;
+	color: #5cb87a;
+	border-color: #c2e7b0;
+}
+
+/* 待下发 */
+.status-to_issue {
+	background-color: #f4f4f5;
+	color: #909399;
+	border-color: #e9e9eb;
+}
+
+/* 已归档 */
+.status-archived {
+	background-color: #f0f9eb;
+	color: #5cb87a;
+	border-color: #c2e7b0;
+}
+
+// /* 超时 */
+// .status-overdue {
+// 	background-color: #fff2f0;
+// 	color: #ff4d4f;
+// 	border-color: #ffccc7;
+// }
+</style>

+ 0 - 3
pages/profile/index.uvue

@@ -46,9 +46,6 @@
                 <text class="logout-btn" @click="handleLogout">注销账号</text>
             </view>
         </scroll-view>
-
-        <!-- 底部 TabBar -->
-        <custom-tabbar :current="4" />
     </view>
 </template>
 

+ 32 - 0
types/order.uts

@@ -69,3 +69,35 @@ export type acceptOrderInfo = {
 	suspendReason: string | null
 	rejectionReason: string | null
 }
+
+// 工单信息
+export type acceptOrderInfo2 = {
+	orderType: Number
+    id: Number
+	teamLeaderId: Number | 0
+    teamLeaderName: string | null
+	acceptUserId: Number | 0
+    acceptUserName: string | null
+    acceptTime: string | null
+    assignTime: string | null
+    assignUserName: string | null
+    status: Number
+    workOrderProjectNo: string | null
+    workOrderStatus: string | null
+    gxtCenterId: Number | 0
+    gxtCenter: string | null
+    pcsStationId: Number | 0
+    pcsStationName: string | null
+    pcsDeviceId: Number | 0
+    pcsDeviceName: string | null
+    brand: string | null
+    model: string | null
+    createTime: string | null
+    workOrderFlowList?: WorkOrderFlowList | null
+	suspendReason: string | null
+	rejectionReason: string | null
+	misNo: string | null
+	content: string | null
+	faultBarcode: string | null
+	faultCode: string | null
+}

+ 145 - 0
uni_modules/android-keeplive/changelog.md

@@ -0,0 +1,145 @@
+## 1.1.71(2025-11-20)
+优化
+## 1.1.70(2025-10-31)
+优化鸿蒙保活
+## 1.1.69(2025-10-27)
+优化已知问题
+## 1.1.68(2025-10-09)
+优化
+## 1.1.67(2025-09-28)
+修复so 16k 问题
+## 1.1.66(2025-09-11)
+优化已知问题
+## 1.1.65(2025-08-11)
+优化
+## 1.1.64(2025-07-28)
+优化
+## 1.1.63(2025-07-28)
+增加鸿蒙端
+## 1.1.62(2025-07-08)
+优化
+## 1.1.61(2025-07-08)
+优化
+## 1.1.60(2025-07-08)
+优化保活逻辑,修复已知问题
+## 1.1.59(2025-07-08)
+优化保活逻辑,修复已知问题
+## 1.1.58(2025-06-04)
+优化
+## 1.1.57(2025-05-20)
+优化
+## 1.1.56(2025-05-20)
+优化Android 
+## 1.1.55(2025-05-13)
+优化ios
+## 1.1.54(2025-05-13)
+优化iOS端
+## 1.1.53(2025-04-30)
+优化通知栏,其它优化
+## 1.1.52(2025-04-17)
+优化已知问题
+## 1.1.51(2025-04-15)
+优化
+## 1.1.50(2025-04-01)
+优化
+## 1.1.49(2025-03-14)
+优化
+## 1.1.48(2025-03-12)
+web 和微信小程序改uts 端优化
+## 1.1.47(2025-03-12)
+web 和微信小程序改uts 为js
+## 1.1.46(2025-03-11)
+优化
+## 1.1.45(2025-03-11)
+修复已知问题
+## 1.1.44(2025-03-07)
+新增通知栏角标设置 默认为关闭
+其它优化
+## 1.1.43(2025-03-04)
+修改插件名称
+## 1.1.38(2025-03-03)
+优化保活逻辑
+## 1.1.36(2025-02-26)
+优化iOS 端播放逻辑
+## 1.1.35(2025-02-24)
+优化
+## 1.1.34(2025-02-22)
+1.增加部分手机休眠的时候wifi 断开连接,使其保持连接
+2.ios端增加info。zip 需要的自行解压使用
+3.启动保活增加自动申请通知权限,无需再判断打开设置等
+## 1.1.32(2025-02-20)
+优化首次启动 部分手机卡顿问题
+## 1.1.31(2025-02-17)
+优化后台运行逻辑,增加程序后台活性
+## 1.1.30(2025-02-12)
+优化后台多进程保活
+## 1.1.29(2025-02-11)
+优化
+## 1.1.28(2025-02-11)
+优化
+## 1.1.27(2025-02-05)
+优化
+## 1.1.26(2025-02-03)
+优化
+## 1.1.25(2025-02-03)
+新增ios 端  
+## 1.1.23(2025-01-07)
+修复ios 端打包报错问题
+## 1.1.22(2025-01-06)
+修改已知问题
+## 1.1.21(2025-01-06)
+优化
+## 1.1.20(2025-01-02)
+修复取消全部定时器闪退问题
+## 1.1.19(2024-12-28)
+优化程序逻辑
+## 1.1.18(2024-12-22)
+优化
+## 1.1.17(2024-12-20)
+优化
+## 1.1.16(2024-12-19)
+去掉自启动权限
+## 1.1.15(2024-12-16)
+优化
+## 1.1.14(2024-12-13)
+防止后台录音时被释放
+## 1.1.13(2024-12-03)
+修复后台音乐bug
+## 1.1.12(2024-12-02)
+其它修改
+## 1.1.11(2024-11-30)
+修改出现编译错误问题
+## 1.1.10(2024-11-27)
+修复闪退
+## 1.1.9(2024-11-27)
+重复提交
+## 1.1.8(2024-11-27)
+新增唤醒cpu 功能
+## 1.1.7(2024-11-12)
+新增静默通知
+## 1.1.6(2024-11-04)
+增加web
+## 1.1.5(2024-11-02)
+修复已知问题
+## 1.1.4(2024-10-31)
+修改定时器小于60s 无法取消问题
+## 1.1.3(2024-10-31)
+增加全局保活
+## 1.1.2(2024-10-31)
+修复多个定时器错乱问题
+## 1.1.1(2024-10-30)
+修复已知问题
+## 1.0.6(2024-10-28)
+修复已知问题
+## 1.0.5(2024-10-28)
+修复编译出错问题
+## 1.0.4(2024-10-25)
+修改 回调函数已释放,不能再次执行问题
+## 1.0.3(2024-10-08)
+修复已知bug
+## 1.0.2(2024-09-26)
+修复已知bug
+## 1.0.1(2024-09-24)
+修复已知bug
+## 1.0.0(2024-09-19)
+初始化

+ 2 - 0
uni_modules/android-keeplive/encrypt

@@ -0,0 +1,2 @@
+Ső©źFáSë…›ŕe|Ţb¤Ý]ęQłgţT#‰9˛â—émšp@µWt߷̸’´jţФ
+˘©÷ĺc˱`çE,yŞS„Q]<A˙ŚŞcȨ Č‘&ńöiâßuŮ�F¶>ő2–ËĹĺVQ‹V6űŐví]†vÚÁsĐ ´÷(xÍťŘ0Š5Ó—Ľ-Wă2‡S

+ 109 - 0
uni_modules/android-keeplive/package.json

@@ -0,0 +1,109 @@
+{
+  "id": "android-keeplive",
+  "displayName": "安卓保活 ios保活 鸿蒙保活 保应用程序稳定后台运行(2025插件大赛二等奖)",
+  "version": "1.1.71",
+  "description": "android保活/ios保活/鸿蒙保活 为应用程序提供一个稳定的后台运行环境,为您的应用程序保驾护航,防止程序后台被杀,程序唤醒,息屏唤醒,增加程序活性,优化代码执行,保活稳定",
+  "keywords": [
+    "保活",
+    "安卓保活",
+    "",
+    "ios保活",
+    "Android保活",
+    "",
+    "稳定定时器"
+],
+  "repository": "",
+  "engines": {
+    "HBuilderX": "^3.99",
+    "uni-app": "^4.07",
+    "uni-app-x": "^4.07"
+  },
+  "dcloudext": {
+    "type": "uts",
+    "sale": {
+      "regular": {
+        "price": "19.99"
+      },
+      "sourcecode": {
+        "price": "666.66"
+      }
+    },
+    "contact": {
+      "qq": "1530948626"
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "插件不采集任何数据",
+      "permissions": "  <uses-permission android:name=\"android.permission.START_ACTIVITIES\" />\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n    <uses-permission android:name=\"android.permission.GET_TASKS\" />\n    <uses-permission android:name=\"android.permission.SCHEDULE_EXACT_ALARM\" />\n    <uses-permission android:name=\"android.permission.SET_ALARM\"/>\n    <uses-permission android:name=\"android.permission.USE_EXACT_ALARM\"/>\n    <uses-permission android:name=\"android.permission.SCHEDULE_EXACT_ALARM\" />\n    <uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\" />\n    <uses-permission android:name=\"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS\" />\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK\"/>"
+    },
+    "npmurl": "",
+    "darkmode": "√",
+    "i18n": "√",
+    "widescreen": "√"
+  },
+  "uni_modules": {
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "client": {
+        "uni-app": {
+          "vue": {
+            "vue2": "√",
+            "vue3": "√"
+          },
+          "web": {
+            "safari": "-",
+            "chrome": "-"
+          },
+          "app": {
+            "vue": "√",
+            "nvue": "√",
+            "android": {
+              "extVersion": "",
+              "minVersion": "21"
+            },
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "-",
+            "alipay": "-",
+            "toutiao": "-",
+            "baidu": "-",
+            "kuaishou": "-",
+            "jd": "-",
+            "harmony": "-",
+            "qq": "-",
+            "lark": "-"
+          },
+          "quickapp": {
+            "huawei": "-",
+            "union": "-"
+          }
+        },
+        "uni-app-x": {
+          "web": {
+            "safari": "-",
+            "chrome": "-"
+          },
+          "app": {
+            "android": {
+              "extVersion": "",
+              "minVersion": "21"
+            },
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "-"
+          }
+        }
+      },
+      "cloud": {
+        "tcb": "x",
+        "aliyun": "x",
+        "alipay": "x"
+      }
+    }
+  }
+}

+ 490 - 0
uni_modules/android-keeplive/readme.md

@@ -0,0 +1,490 @@
+# android-keeplive
+### 本插件支持uniapp/uniappx 双端
+ 长期维护,有任何问题请在插件群联系作者
+### 功能介绍和注意事项
+
+### 源码版本安卓端不包含aar文件源码,其它端包含所有源码
+
+#### 本插件为后台无声音乐保活,为推送蓝牙后台传数据等保驾护,增加程序存活率,防止程序进入后台后或者系统休眠后程序停止执行的问题(用本插件定时器1和定时器2可保证任何状态下准确执行)无定位需求直接集成即可,若需要定位则合并集成作者定位插件
+
+1.android/iOS端需要自定义基座
+
+2.ios 端若觉得效果不佳,可以解压ios 插件目录下的uni_modules\android-keeplive\utssdk\app-ios\info.zip 将info.plist 文件和uts 文件在同一个级别 文件(上架可能会困难一点)
+ 
+3.推荐android端合井使用作者一像素保活效果更佳[链接](https://ext.dcloud.net.cn/plugin?id=20324)
+
+
+#### Android端 其它增加存活机会方法
+1.最近任务给程序加锁,2.在系统设置启动项开启应用程序后台运行
+
+
+#### 插件测试使用方法
+1. 选择试用,绑定要试用的项目appid,
+
+2. 选择后下载到对应的本地项目,
+
+3. 按照文档 -》把插件引入项目(即 import { KeepLive } from '@/uni_modules/android-keeplive' 需要先引入),
+
+4. 发布-》云打包-》选择制作基座-》打包等基座制作完成 
+
+5. 运行 -》 运行到手机或模拟器-》运行到Androidapp基座-》选择使用自定义基座运行-》选择手机-》运行
+
+6. 若之前手机安装过基座需要先卸载之前的基座
+
+### 安卓默认通知id为 6234542
+
+###  uniappx
+~~~
+// #ifdef APP
+import { KeepLive } from '@/uni_modules/android-keeplive' // 放在页面导入的地方
+// #endif
+
+
+//<!-- ------------------------------下方代码需要放进方法中-------------------------------------------------- -->	
+// #ifdef APP
+var keep=new KeepLive();
+keep.setTitle("app");
+keep.setContent("app is runing");
+// keep.setLargeIcon("icon");
+keep.setSmallIcon("icon"); //图标名字  图标放在 插件下面的 uni_modules\android-keeplive\utssdk\app-android\res 文件夹下
+keep.onAddBackgroundCallback(function(res:boolean){
+	console.log("后台运行 "+res)
+	
+})
+keep.onAddScrrenListenerCallback(function(res:boolean){
+	console.log("屏幕开启状态 "+res)
+	
+})	
+keep.setWakeLock(1,"keeptag");// 设置唤醒类型
+keep.setAutoStartEnable(true)
+
+if(!keep.checkAppNotification()){
+	keep.onOpenNotificationSetting(function(res:boolean){
+		keep.register();
+		var ignoring=  keep.isIgnoringBatteryOptimizations();
+		if(!ignoring){
+			keep.requestIgnoreBatteryOptimizations();
+		}
+	})
+}else{
+	keep.register();
+	var ignoring=  keep.isIgnoringBatteryOptimizations();
+	if(!ignoring){
+		keep.requestIgnoreBatteryOptimizations();
+	}
+}
+// 稳定定时器 需要的用户使用(默认定时器1 )
+keep.onStartCSystemTimer(60,function(){
+	console.log("onStartCSystemTimer ");
+	keep.acquire(1000);// 唤醒一秒钟
+});
+// 需要插件增加程序后台运行能力的可以加下面代码 想程序始终保持活性(即稳定推送 scocket等)(体验好) 还是建议用户打开系统设置 启动项 后台运行
+//keep.wifilock();//部分手机可能会断
+// 定时器时间改成10秒 去掉上方的
+//keep.onStartCSystemTimer(10,function(){
+//	console.log("onStartCSystemTimer ");
+//	keep.acquire(1000);// 唤醒一秒钟
+//});
+// #endif
+~~~
+
+
+###  uniapp
+~~~
+// #ifdef APP
+import { KeepLive } from '@/uni_modules/android-keeplive' // 放在页面导入的地方
+// #endif
+
+
+//<!-- ------------------------------下方代码需要放进方法中-------------------------------------------------- -->	
+// #ifdef APP	
+var keep=new KeepLive();
+keep.setTitle("app");
+keep.setContent("app is runing");
+// keep.setLargeIcon("icon");
+keep.setSmallIcon("icon"); //图标名字  图标放在 插件下面的 res/drawable 文件夹下
+keep.onAddBackgroundCallback(function(res){
+	console.log("后台运行 "+res)
+	
+})
+keep.onAddScrrenListenerCallback(function(res){
+	console.log("屏幕开启状态 "+res)
+	
+})	
+keep.setWakeLock(1,"keeptag");// 设置唤醒类型
+
+keep.setAutoStartEnable(true)
+if(!keep.checkAppNotification()){
+	keep.onOpenNotificationSetting(function(res){
+		keep.register();
+		var ignoring=  keep.isIgnoringBatteryOptimizations();
+		if(!ignoring){
+			keep.requestIgnoreBatteryOptimizations();
+		}
+	})
+}else{
+	keep.register();
+	var ignoring=  keep.isIgnoringBatteryOptimizations();
+	if(!ignoring){
+		keep.requestIgnoreBatteryOptimizations();
+	}
+}
+
+keep.onStartCSystemTimer(60,function(){
+	console.log("onStartCSystemTimer ");
+		keep.acquire(1000);// 唤醒一秒钟
+});
+// 需要插件增加程序后台运行能力的可以加下面代码 想程序始终保持活性(即稳定推送 scocket等)(体验好) 还是建议用户打开系统设置 启动项 后台运行
+//keep.wifilock();//部分手机可能会断
+// 定时器时间改成3秒 去掉上方的
+//keep.onStartCSystemTimer(3,function(){
+//	console.log("onStartCSystemTimer ");
+//	keep.acquire(1000);// 唤醒一秒钟
+//});
+// #endif
+~~~
+
+
+
+### 需要gps定位用户 可合并作者定位插件(推荐使用作者定时器1 ,系统休眠后可执行)
+#### 
+[安卓 ios 鸿蒙 原生gps定位](https://ext.dcloud.net.cn/plugin?id=21745)
+
+[安卓ios 高德定位](https://ext.dcloud.net.cn/plugin?id=20916)
+
+[安卓腾讯定位](https://ext.dcloud.net.cn/plugin?id=20875)(后续支持ios)
+
+[安卓ios 百度定位](https://ext.dcloud.net.cn/plugin?id=20562)
+
+#### uniappx
+
+~~~
+// #ifdef APP
+import { isProviderEnabled, openLocSetting,  onStartLocs,LocData,stop,LocationData} from "@/uni_modules/xtf-gpslocation"
+// #endif
+// #ifdef APP
+// 停用后台播放音乐
+keep.setBackgroundMusicEnabled(false);
+
+// 后台定位则需要使用插件的定时器 息屏也能执行,自定定时器易休眠停止执行
+// 先启动定位
+var on=isProviderEnabled();// 是否开启gps
+if(on){
+	keep.onStartCSystemTimer(60,function(){
+onStartLocs({
+    backgroud:true,
+} as LocData,function(data:LocationData){
+    console.log(data)
+})
+	
+	});	
+}
+// #endif
+
+
+~~~
+
+#### uniapp
+
+~~~
+import { isProviderEnabled, openLocSetting,  onStartLocs,LocData,stop} from "@/uni_modules/xtf-gpslocation"
+
+
+// 停用后台播放音乐
+keep.setBackgroundMusicEnabled(false);
+
+// 后台定位则需要使用插件的定时器 息屏也能执行,自定定时器易休眠停止执行
+// 先启动定位
+var on=isProviderEnabled();// 是否开启gps
+if(on){
+	keep.onStartCSystemTimer(60,function(){
+onStartLocs({
+    backgroud:true,
+} ,function(res){
+    console.log(res)
+})
+	
+	});	
+}
+
+
+
+~~~
+
+### 注册开启运行
+
+#### register
+~~~
+keep.register();
+~~~
+
+### 重启
+
+#### restart
+~~~
+keep.restart();
+~~~
+
+### 取消运行
+
+#### unregister
+~~~
+keep.unregister();
+~~~
+
+### 是否运行
+#### isRunning
+return  boolean
+~~~
+var run=keep.isRunning();
+~~~
+### 判断通知权限是否开启(安卓有效,ios 无功能)
+#### checkAppNotification
+~~~
+var on=keep.checkAppNotification();
+~~~
+
+#### 打开应用通知设置(安卓有效,ios 无功能)
+#### goNotificationSetting
+~~~
+keep.goNotificationSetting();
+~~~
+#### 打开应用通知设置并返回状态(安卓有效,ios 无功能)
+uniappx
+~~~
+	keep.onOpenNotificationSetting(function(on:boolean){
+	
+	})
+~~~
+uniapp
+~~~
+	keep.onOpenNotificationSetting(function(on){
+	})
+~~~
+
+### 通过包名打开应用程序(安卓有效,ios 无功能)
+#### doStartApplicationWithPackageName
+参数1 应用包名 string 
+~~~
+keep.doStartApplicationWithPackageName("com.test");
+~~~
+
+
+### 开启应用省电后台运行 (安卓有效,ios 无功能)
+#### requestIgnoreBatteryOptimizations
+~~~
+keep.requestIgnoreBatteryOptimizations();
+~~~
+
+### 判断应用是否开启省电后台运行 (安卓有效,ios 无功能)
+#### isIgnoringBatteryOptimizations
+return  boolean 
+~~~
+var ignoring=  keep.isIgnoringBatteryOptimizations();
+~~~
+
+### 设置后台无声音乐是否开启 (安卓有效,ios 无功能)
+#### setBackgroundMusicEnabled
+参数1 boolean
+~~~
+keep.setBackgroundMusicEnabled(true);
+~~~
+
+
+
+### 是否隐藏通知栏 (弃用,后续删除)
+#### hideNotification(安卓有效,ios 无功能)
+参数1 boolean
+~~~
+keep.hideNotification(false);
+~~~
+### 静音通知
+#### setNotifaicationSoundEnable
+ 参数1 boolean
+ ~~~
+ keep.setNotifaicationSoundEnable(true);
+ ~~~
+
+ 
+### 设置通知栏 ChannelId 默认keeplive(安卓有效,ios 无功能)
+#### setChannelId
+参数1 string 
+ ~~~
+ keep.setChannelId("keeplive");
+ ~~~
+ 
+### 更新通知栏
+#### updateNotification
+ ~~~
+keep.setTitle("Test");
+keep.setContent("test runing");
+keep.updateNotification();
+ ~~~
+
+### 设置通知栏标题
+#### setTitle
+参数1 string 
+ ~~~
+ keep.setTitle("title");
+ ~~~
+
+### 设置通知栏内容
+#### setContent
+参数1 string 
+ ~~~
+ keep.setContent("msg");
+ ~~~
+### 设置通知重要性(安卓有效,ios 无功能)
+#### setChannelImportance
+参数1 number  0-4 低到高 
+~~~
+keep.setChannelImportance(3);
+~~~
+
+
+### 设置通知栏小图标(安卓有效,ios 无功能)
+#### setSmallIcon
+参数1 string   插件的res  drawable 目录下 名称
+
+~~~
+ keep.setSmallIcon("icon");
+
+~~~
+
+### 设置通知栏大图标(安卓有效,ios 无功能)
+#### setLargeIcon
+参数1 string   插件的res  drawable 目录下 名称
+~~~
+ keep.setLargeIcon("icon");
+
+~~~
+
+### 设置唤醒cpu类型(安卓有效,ios 无功能)
+#### setWakeLock
+参数1 number   
+1:保持CPU 运转,屏幕和键盘灯有可能是关闭的。
+
+参数2 string tag
+
+~~~
+keep.setWakeLock(1,"tag");
+~~~
+
+### 唤醒cpu  需先设置唤醒cpu 类型(安卓有效,ios 无功能)
+#### acquire
+参数1 number 时间
+
+~~~
+keep.acquire(-1);
+~~~
+### 释放cpu  需先设置唤醒cpu 类型(安卓有效,ios 无功能)
+####  releaseAcquire
+~~~
+keep.releaseAcquire();
+~~~
+
+
+### 后台背景音乐测试  启动保活之前调用 (安卓有效,ios 无功能)
+~~~
+keep.setMusicVol(0) // 0~1 范围
+keep.setMusicId("music")   // 将音乐放进  插件目录 /res/raw/music.mp3  
+~~~
+
+### 主动退出应用后台运行,相当于单击home (安卓有效,ios 无功能)
+~~~
+keep.toBackground();
+~~~
+
+
+### android 息屏准确执行定时器  (二者选择一个就可)
+
+#### 定时器1   android/iOS/ web 三端均可用无需判断平台
+~~~
+//开启定时器     60时间为秒
+ keep.onStartCSystemTimer(60,function(){
+	console.log("onStartCSystemTimer ")
+});
+	
+//keep.cancelCSystemTimer();// 取消定时器
+//keep.clearAllCTimer();  // 取消全部定时器
+~~~
+
+
+
+
+#### 定时器2 
+~~~
+// android 原生定时任何状态一秒误差, 开始时间 1000为1秒0是马上执行, 开启周期 65*1000, 循环时间 大于60s 精准有效 低于60秒偏差误差
+ keep.startAleraTask(0,65*1000,function(){
+   	console.log("onAleraTaskListener ")
+ }); 
+     
+   	//取消循环定时
+keep.cancleAleraTask()
+~~~
+
+
+<!-- #### 定时器3 (待测试) 推荐  android/iOS/ web 微信小程序四端可用无需判断平台
+~~~
+//开启定时器     3时间为秒
+ keep.startKeepClcokTimer(3,function(){
+	console.log("startCSystemTimer ")
+});
+	
+//keep.cancelKeepClcokTimer();// 取消定时器
+//keep.cancelAllKeepClcokTimer();  // 取消全部定时器
+~~~ -->
+
+### 获取插件存活时间
+~~~
+var liveTime=keep.getLiveTime();// 毫秒时间
+~~~
+
+
+### 隐藏最近任务(安卓有效,ios 无功能)
+参数1  boolean   true 为隐藏,false为显示
+~~~
+keep.hideRecentTask(true);// 隐藏
+~~~
+### 打开安卓系统应用设置 方便用户设置自启动(安卓有效,ios 无功能)
+~~~
+keep.goAndroidSystemAppSetting();
+~~~
+### 崩溃后重启 (原生Rom 有效 )
+~~~
+keep.setCrashRestartUIEnabled(true);
+~~~
+
+
+### 其它功能
+~~~
+android channel 为android通知栏通配置
+对使用插件app的新用户
+本插件的channelId 默认为keeplive channelName 默认为keeplive  默认为有声通知。首次调用keep.register()/keep.updateNotification() 这个channel 就会自定创建好,并且不可修改
+本插件可自定义channel 在调用keep.register()/keep.updateNotification()之前调用下面代码
+keep.setNotifaicationSoundEnable(false);
+keep.setChannelId("保活");
+keep.setChannelName("保活") //通知名称
+keep.register();//keep.updateNotification()/* 同样为调用即为创建,之后不可修改,但是可以添加新的, 调用其中一个即可,之后就一直按照新的配置发送通知*/
+
+~~~
+
+### 安卓部分手机wifi状态下,休眠的时候 wifi 会断开连接,可以调用下面的代码 使休眠的时候保持wifi 连接
+~~~
+keep.wifilock();// 休眠时锁定wifi
+
+~~~
+~~~
+keep.wifiunlock();// 休眠时取消锁定wifi
+~~~
+
+
+
+
+
+
+
+
+
+
+

+ 6 - 0
uni_modules/android-keeplive/utssdk/app-android/config.json

@@ -0,0 +1,6 @@
+{
+  "minSdkVersion": "19",
+  "dependencies": [
+	  "androidx.work:work-runtime:2.7.1"
+  ]
+}

BIN
uni_modules/android-keeplive/utssdk/app-android/index.uts


BIN
uni_modules/android-keeplive/utssdk/app-android/libs/cactus-release.aar


BIN
uni_modules/android-keeplive/utssdk/app-android/res/drawable/icon.png


BIN
uni_modules/android-keeplive/utssdk/app-harmony/index.uts


+ 20 - 0
uni_modules/android-keeplive/utssdk/app-harmony/module.json5

@@ -0,0 +1,20 @@
+{
+  "module": {
+    "name": "uni_modules__android_keeplive",
+    "type": "har",
+    "deviceTypes": [
+      "default",
+      "tablet",
+      "2in1"
+    ],
+    "requestPermissions": [
+		{
+		  "name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
+		  "reason": "$string:Harmony_keep_permission_reason",
+		  "usedScene": {
+		    "when": "always"
+		  }
+		}
+    ]
+  }
+}

+ 20 - 0
uni_modules/android-keeplive/utssdk/app-harmony/resources/base/element/string.json

@@ -0,0 +1,20 @@
+{
+  "string": [
+	{
+      "name": "Harmony_location_permission_reason",
+      "value": "获取位置信息需要访问定位权限"
+    },
+	{
+	  "name": "Harmony_net_permission_reason",
+	  "value": "获取位置信息需要访问网络权限"
+	},{
+	  "name": "Harmony_keep_permission_reason",
+	  "value": "需要后台运行以获取权限"
+	},
+	{
+	  "name": "Harmony_notification_permission_reason",
+	  "value": "用于发送通知"
+	}
+	
+  ]
+}

BIN
uni_modules/android-keeplive/utssdk/app-ios/KeepLive.swift


BIN
uni_modules/android-keeplive/utssdk/app-ios/Resources/main.mp3


+ 3 - 0
uni_modules/android-keeplive/utssdk/app-ios/config.json

@@ -0,0 +1,3 @@
+{
+  "deploymentTarget": "12"
+}

BIN
uni_modules/android-keeplive/utssdk/app-ios/index.uts


+ 18 - 0
uni_modules/android-keeplive/utssdk/app-ios/info.plist

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+  <dict>
+	<!-- 后台模式声明 -->
+	<key>UIBackgroundModes</key>
+	<array>
+	    <string>audio</string> <!-- 基础音频权限 -->
+		<string>fetch</string>  <!-- 后台数据获取 -->
+	</array>
+	 <key>NSUserNotificationsUsageDescription</key>
+	    <string>发送重要提醒和更新</string>
+	<!-- iOS 19+新增隐私声明 -->
+	<key>NSBackgroundAudioServicesEnabled</key>
+	<string>需要持续后台音频使应用持续运行</string>
+
+  </dict>
+</plist>

BIN
uni_modules/android-keeplive/utssdk/app-ios/info.zip


+ 0 - 0
uni_modules/android-keeplive/utssdk/interface.uts


+ 1 - 0
uni_modules/android-keeplive/utssdk/unierror.uts

@@ -0,0 +1 @@
+�YŽíð™"1¢M¯¶)

+ 15 - 17
utils/request.uts

@@ -14,7 +14,7 @@ export type RequestConfig = {
 
 // 基础 URL
 const BASE_URL = "http://192.168.110.105:8080";
-
+// const BASE_URL = "http://222.243.138.146:5095";
 /**
  * 获取基础 URL
  */
@@ -58,35 +58,33 @@ export const request = (config: RequestConfig): Promise<any> => {
             timeout: config.timeout ?? 30000,
             success: (res) => {
                 // 提取属性(any 类型不能直接访问属性)
-				console.log(res);
+				// console.log(res);
                 const statusCode = res.statusCode as number;
                 const resData = res.data;
 
                 if (statusCode == 200) {
                     // 将响应数据转换为 UTSJSONObject,然后手动提取属性
                     const result = resData as UTSJSONObject;
-                    const success = result["success"] as boolean | null;
-                    const status = result["status"] as number | null;
                     const code = result["code"] as number | null;
                     const msg = result["msg"] as string | null;
-
-                    // 判断是否成功
-                    // success 为 true 表示成功
-                    // 或者没有 success 字段但 code 为 200 也表示成功
-                    const isSuccess = success == true || (success == null && code == 200)
-                    
-                    if (isSuccess) {
-                        console.log(config.url, result);
+					// console.log("================"+ code)
+					
+                    if (code == 200) {
                         // 返回整个 result 对象
                         resolve(result as any);
-                    } else if (status != null && (status == 401 || status == 403)) {
-                        // Token 过期或无权限,跳转登录
-                        handleLoginRedirect();
-                        reject(new Error("登录已过期,请重新登录"));
-                    } else if (code != null && (code == 401 || code == 403)) {
+                    }else if (code != null && (code == 401)) {
                         // 有些接口使用 code 字段
                         handleLoginRedirect();
+						console.log(config.url, result);
                         reject(new Error("登录已过期,请重新登录"));
+                    }else if (code != null && (code == 403)) {
+                        // 有些接口使用 code 字段
+						const errorMsg = msg != null ? msg : "请求失败";
+						uni.showToast({
+						    title: config.url + errorMsg ,
+						    icon: 'success'
+						})
+                        resolve(result as any);
                     } else {
                         const errorMsg = msg != null ? msg : "请求失败";
                         reject(new Error(errorMsg));