Bläddra i källkod

Merge remote-tracking branch 'origin/master'

ouyj 4 månader sedan
förälder
incheckning
5526c1c9f4

+ 14 - 9
api/user/list.uts

@@ -20,12 +20,17 @@ export const getUserList = (deptId: any): Promise<any> => {
     })
 }
 
-// /**
-//  * 获取所有用户列表(用于负责人选择)
-//  */
-// export const getUserList = (): Promise<any> => {
-//     return request({
-//         url: '/system/user/listNoPermi?status=0',
-//         method: 'GET'
-//     })
-// }
+/**
+ * 获取所有用户列表(用于负责人选择)
+ */
+export const getLeaderList = (deptId: any): Promise<any> => {
+	let url = `/gxt/leader/listLeader?status=0`
+	if (deptId != null ) {
+	    // 支持工单编码和风机编号查询
+	    url += `&deptId=${deptId}`
+	}
+    return request({
+        url: url,
+        method: 'GET'
+    })
+}

+ 93 - 55
pages/index/index.uvue

@@ -37,12 +37,6 @@
 				</view>
 			</view>
 
-            <!-- 支流出库流量图表 -->
-           <!-- <view class="chart-section">
-                <text class="section-title">支流出库流量 (m³/s)</text>
-                <flow-chart />
-            </view> -->
-
 			<!-- <view>
 				<button @click="handlePush">通知</button>
 			</view> -->
@@ -437,7 +431,7 @@
 		        keep.requestIgnoreBatteryOptimizations();
 		    }
 		}
-		
+
 		// keep.wifilock();
 		// 稳定定时器 需要的用户使用(默认定时器1 )
 		const is_time = uni.getStorageSync("notify_key")
@@ -559,7 +553,7 @@
 			console.error('处理超时工单点击事件失败:', e)
 		}
 	}
-	
+
 	const registerPush =() =>{
 		console.log("获取CID")
 		uni.getPushClientId({
@@ -628,7 +622,7 @@
     .page-container {
         position: relative;
         flex: 1;
-        padding-top: env(safe-area-inset-top);
+        // padding-top: env(safe-area-inset-top);
 		background-color: #e8f0f9;
     }
 
@@ -654,8 +648,9 @@
     .page-content {
         position: relative;
         flex: 1;
+		margin-top: 30rpx;
         margin-bottom: 150rpx;
-        padding: 20rpx;
+        // padding: 20rpx;
         z-index: 10;
     }
 
@@ -684,7 +679,8 @@
     }
 
 	.section-title-container {
-		padding: 20rpx 30rpx 10rpx 30rpx;
+		margin-top: 20rpx;
+		padding: 20rpx 30rpx;
 	}
 
 	.section-header {
@@ -710,53 +706,89 @@
 	.db-view{
 		display: flex;
 		flex-direction: row;
-		// justify-content: space-between;
-		justify-content: flex-start;
-		margin-bottom: 10rpx;
-		// gap: 20rpx;
-
-		.db-box{
+		justify-content: space-between; // 或 space-around
+		align-items: center;
+		padding: 0 20rpx; // 可选:避免贴边
+
+		// .db-box{
+		// 	background-color: #fff;
+		// 	width:200rpx;
+		// 	height: 200rpx;
+		// 	justify-content: center;
+		// 	align-items: center;
+		// 	margin-left: 28rpx;
+		// 	border-radius: 5px;
+		// 	.db-text{
+		// 		margin-top: 10rpx;
+		// 		font-size:10px;
+		// 	}
+		// 	.db-center-1{
+		// 		justify-content: center;
+		// 		align-items: center;
+		// 		background-color: #DBEAFE;
+		// 		border-radius: 200px;
+		// 		width:100rpx;
+		// 		height:100rpx;
+		// 		position: relative;
+		// 	}
+		// 	.db-center-2{
+		// 		justify-content: center;
+		// 		align-items: center;
+		// 		background-color: #DCFCE7;
+		// 		border-radius: 200px;
+		// 		width:100rpx;
+		// 		height:100rpx;
+		// 		position: relative;
+		// 	}
+		// 	.db-center-3{
+		// 		justify-content: center;
+		// 		align-items: center;
+		// 		background-color: #F3E8FF;
+		// 		border-radius: 200px;
+		// 		width:100rpx;
+		// 		height:100rpx;
+		// 	}
+		// }
+		.db-box {
 			background-color: #fff;
-			width:200rpx;
-			height: 200rpx;
+			// 删除固定宽高 ↓
+			// width: 200rpx;
+			// height: 200rpx;
+		
+			flex: 1;                // ✅ 关键:平均分空间
+			display: flex;
+			flex-direction: column; // 垂直排列:图标在上,文字在下
 			justify-content: center;
 			align-items: center;
-			margin-left: 28rpx;
+			margin: 0 10rpx;        // 左右间距(替代原来的 margin-left)
 			border-radius: 5px;
-			.db-text{
-				margin-top: 10rpx;
-				font-size:10px;
-			}
-			.db-center-1{
-				justify-content: center;
-				align-items: center;
-				background-color: #DBEAFE;
-				border-radius: 200px;
-				width:100rpx;
-				height:100rpx;
-				position: relative;
+			padding: 30rpx 10rpx;   // 可选:增加内边距使内容不拥挤
+		
+			.db-text {
+				margin-top: 16rpx;   // 图标与文字间距
+				font-size: 24rpx;    // 建议用 rpx,10px 太小了
+				color: #333;
 			}
-			.db-center-2{
+		
+			.db-center-1,
+			.db-center-2,
+			.db-center-3 {
+				display: flex;
 				justify-content: center;
 				align-items: center;
-				background-color: #DCFCE7;
-				border-radius: 200px;
-				width:100rpx;
-				height:100rpx;
+				width: 100rpx;
+				height: 100rpx;
+				border-radius: 50rpx; 
 				position: relative;
 			}
-			.db-center-3{
-				justify-content: center;
-				align-items: center;
-				background-color: #F3E8FF;
-				border-radius: 200px;
-				width:100rpx;
-				height:100rpx;
-			}
+		
+			.db-center-1 { background-color: #DBEAFE; }
+			.db-center-2 { background-color: #DCFCE7; }
+			.db-center-3 { background-color: #F3E8FF; }
 		}
 		.db-image{
-			width:20px;
-			height:20px;
+			width:50rpx;
+			height:50rpx;
 		}
 	}
 
@@ -766,17 +798,23 @@
 		top: 35rpx;
 		right: 35rpx;
 		background-color: #ff4d4f;
-		border-radius: 20rpx;
-		width: 40rpx;
+		border-radius: 40rpx;
+		min-width: 40rpx;
 		height: 40rpx;
+		display: flex; // 启用 Flexbox 布局
+		justify-content: center; // 水平居中
+		align-items: center;     // 垂直居中
+		box-sizing: border-box;  // 确保 padding 不影响整体尺寸
+		padding: 0 12rpx; 
+		.count {
+			// line-height: 40rpx;
+			font-size: 26rpx;
+			// text-align: center;
+			color: #ffffff;
+		}
 
 	}
-	.count {
-		line-height: 40rpx;
-		font-size: 26rpx;
-		text-align: center;
-		color: #ffffff;
-	}
+	
 
 	.list-item {
 		margin: 0 30rpx 24rpx 30rpx;

+ 7 - 5
pages/order/detail/acceptIndex.uvue

@@ -80,7 +80,7 @@
 			<!-- 工作负责人选择 -->
 			<view class="info-section">
 			    <view class="section-title">
-			        <text class="section-title-text">工作负责人</text>
+			        <text class="section-title-text">工作负责人<text style="color: red;">*</text></text>
 			    </view>
 			    <view class="info-card">
 			        <view class="form-item">
@@ -88,7 +88,9 @@
 			            <view class="form-picker" @click="showLeaderPicker = true">
 			                <view class="picker-display">
 			                    <text v-if="selectedTeamLeaderName" class="selected-value">{{ selectedTeamLeaderName }}</text>
-			                    <text v-else class="placeholder">请选择工作负责人</text>
+								<text v-else class="placeholder">
+									请选择工作负责人
+								</text>
 			                    <text class="arrow">▼</text>
 			                </view>
 			            </view>
@@ -178,7 +180,7 @@
     import { getOrderInfoById, getRepairOrderInfoById, acceptOrder } from '../../../api/order/detail'
 	import type { SysDictData } from '../../../types/dict'
 	import { getDictDataByType } from '../../../api/dict/index'
-	import { getUserList } from '../../../api/user/list'
+	import { getLeaderList } from '../../../api/user/list'
 	import type { UserInfo } from '../../../types/user'
 	import {checkPermi} from '../../../utils/storage'
 
@@ -239,7 +241,7 @@
 	const loadTeamLeaderList = async (): Promise<void> => {
 	    try {
 			const deptId = detailData.value.gxtCenterId
-	        const result = await getUserList(-1)
+	        const result = await getLeaderList(-1)
 	        const resultObj = result as UTSJSONObject
 
 	        if (resultObj['code'] == 200) {
@@ -777,7 +779,7 @@
 	}
 
 	.modal-body {
-	    // max-height: 800rpx;
+	    max-height: 800rpx;
 		min-height: 800rpx;
 	}
 

+ 3 - 3
pages/order/detail/approveIndex.uvue

@@ -75,7 +75,7 @@
 
 			<view class="info-section">
 			    <view class="section-title">
-			        <text class="section-title-text">审批意见</text>
+			        <text class="section-title-text">审批意见<text style="color: red;">*</text></text>
 			    </view>
 			    <view class="info-card">
 			        <view class="form-item">
@@ -135,7 +135,7 @@
     import { getOrderInfoById, getRepairOrderInfoById, approveOrder } from '../../../api/order/detail'
 	import type { SysDictData } from '../../../types/dict'
 	import { getDictDataByType } from '../../../api/dict/index'
-	import { getUserList } from '../../../api/user/list'
+	import { getLeaderList } from '../../../api/user/list'
 	import type { UserInfo } from '../../../types/user'
 	import {checkPermi} from '../../../utils/storage'
 
@@ -195,7 +195,7 @@
 	const loadTeamLeaderList = async (): Promise<void> => {
 	    try {
 			const deptId = detailData.value.gxtCenterId
-	        const result = await getUserList(deptId)
+	        const result = await getLeaderList(deptId)
 	        const resultObj = result as UTSJSONObject
 
 	        if (resultObj['code'] == 200) {

+ 7 - 26
pages/order/detail/resetIndex.uvue

@@ -64,12 +64,12 @@
 			<!-- 工作负责人选择 -->
 			<view class="info-section">
 			    <!-- <view class="section-title">
-			        <text class="section-title-text">退回类型</text>
+			        <text class="section-title-text">复位方式</text>
 			    </view> -->
 			    <view class="info-card">
 			        <view class="info-item">
 						<view class="info-label">
-							<text class="form-label required">复位方式</text>
+							<text class="form-label required">复位方式<text style="color: red;">*</text></text>
 						</view>
 						<view class="info-value">
 						    <view class="form-picker" @click="showReasonPicker = true">
@@ -81,21 +81,6 @@
 						    </view>
 						</view>
 					</view>
-					<view class="info-item">
-						<view class="info-label">
-							<text class="form-label required">真实故障原因</text>
-						</view>
-						<view class="info-value">
-							 <textarea
-								class="reject-reason-textarea"
-								placeholder="请输入真实故障原因"
-								v-model="realFailureReason"
-								maxlength="500"
-								:show-confirm-bar="false"
-								auto-height
-							></textarea>
-						</view>
-					</view>
 			    </view>
 			</view>
 
@@ -142,7 +127,6 @@
     import { getOrderInfoById, getRepairOrderInfoById, resetAndStart } from '../../../api/order/detail'
 	import type { SysDictData } from '../../../types/dict'
 	import { getDictDataByType } from '../../../api/dict/index'
-	import { getUserList } from '../../../api/user/list'
 	import type { UserInfo } from '../../../types/user'
 	import {checkPermi} from '../../../utils/storage'
 
@@ -158,9 +142,8 @@
 	const model = ref<string>('')
 	const acceptTime = ref<string>('')
 	const resetMethod = ref<string>('')
-	const realFailureReason = ref<string>("")
 	const returnTypeLabel = ref<string>("")
-	
+
 	const teamLeaderName = ref<string>("")
 	// 添加字典加载状态
 	const dictLoaded = ref<boolean>(false)
@@ -172,7 +155,7 @@
 	}
 
 	// 选中的挂起原因
-	
+
 	const selectedReasonIndex = ref<number>(-1)
 	const returnTypeOptions = ref<PickerOption[]>([])
 	const showReasonPicker = ref<boolean>(false)
@@ -240,7 +223,7 @@
 			})
 			return
 		}
-		
+
 		if (isDealing.value || hasDealed.value) return // 双重保险
 		isDealing.value = true
 		const subOrder = {
@@ -249,10 +232,9 @@
 			workOrderProjectNo: workOrderProjectNo.value,
 			workOrderStatus: workOrderStatus.value,
 			resetMethod: resetMethod.value,
-			realFailureReason: realFailureReason.value,
 			repairMethod: "2"
 		} as UTSJSONObject
-		
+
 		try {
 			const result = await resetAndStart(subOrder)
 			const resultObj = result as UTSJSONObject
@@ -297,7 +279,7 @@
     const loadDetail = async (id: string, orderType?: string): Promise<void> => {
         try {
             loading.value = true
-			
+
 			await dictList()
 
             let result: any;
@@ -326,7 +308,6 @@
 				model.value = (data['model'] as string | null) ?? ''
 				acceptTime.value = (data['acceptTime'] as string | null) ?? ''
 				resetMethod.value = (data['resetMethod'] as string | null) ?? ''
-				realFailureReason.value = (data['realFailureReason'] as string | null) ?? ''
 				if (returnTypeOptions.value.length > 0 && resetMethod.value != '') {
 					// 循环匹配
 				    for (const option of returnTypeOptions.value) {

+ 2 - 2
pages/order/detail/resumeIndex.uvue

@@ -95,7 +95,7 @@
     import { getOrderInfoById, getRepairOrderInfoById, resumeOrder } from '../../../api/order/detail'
 	import type { SysDictData } from '../../../types/dict'
 	import { getDictDataByType } from '../../../api/dict/index'
-	import { getUserList } from '../../../api/user/list'
+	import { getLeaderList } from '../../../api/user/list'
 	import type { UserInfo } from '../../../types/user'
 	import {checkPermi} from '../../../utils/storage'
 
@@ -169,7 +169,7 @@
 	const loadTeamLeaderList = async (): Promise<void> => {
 	    try {
 			const deptId = detailData.value.gxtCenterId
-	        const result = await getUserList(deptId)
+	        const result = await getLeaderList(deptId)
 	        const resultObj = result as UTSJSONObject
 
 	        if (resultObj['code'] == 200) {

+ 2 - 3
pages/order/detail/returnIndex.uvue

@@ -69,7 +69,7 @@
 			    <view class="info-card">
 			        <view class="info-item">
 						<view class="info-label">
-							<text class="form-label required">退回类型</text>
+							<text class="form-label required">退回类型<text style="color: red;">*</text></text>
 						</view>
 						<view class="info-value">
 						    <view class="form-picker" @click="showReasonPicker = true">
@@ -83,7 +83,7 @@
 					</view>
 					<view class="info-item">
 						<view class="info-label">
-							<text class="form-label required">退回原因</text>
+							<text class="form-label required">退回原因<text style="color: red;">*</text></text>
 						</view>
 						<view class="info-value">
 							 <textarea
@@ -142,7 +142,6 @@
     import { getOrderInfoById, getRepairOrderInfoById, returnRepairOrder } from '../../../api/order/detail'
 	import type { SysDictData } from '../../../types/dict'
 	import { getDictDataByType } from '../../../api/dict/index'
-	import { getUserList } from '../../../api/user/list'
 	import type { UserInfo } from '../../../types/user'
 	import {checkPermi} from '../../../utils/storage'
 

+ 1 - 2
pages/order/detail/suspendIndex.uvue

@@ -64,7 +64,7 @@
 			<!-- 工作负责人选择 -->
 			<view class="info-section">
 			    <view class="section-title">
-			        <text class="section-title-text">挂起原因</text>
+			        <text class="section-title-text">挂起原因<text style="color: red;">*</text></text>
 			    </view>
 			    <view class="info-card">
 			        <view class="form-item">
@@ -145,7 +145,6 @@
     import { getOrderInfoById, getRepairOrderInfoById, suspendOrder } from '../../../api/order/detail'
 	import type { SysDictData } from '../../../types/dict'
 	import { getDictDataByType } from '../../../api/dict/index'
-	import { getUserList } from '../../../api/user/list'
 	import type { UserInfo } from '../../../types/user'
 	import {checkPermi} from '../../../utils/storage'
 

+ 152 - 122
pages/order/index.uvue

@@ -52,9 +52,6 @@
                 <view class="list-item">
                     <view class="item-container">
                         <view class="item-header">
-                            <!-- <image class="location-icon" src="/static/images/workbench/list/2.png" mode="aspectFit"></image>
-                            <text class="item-title">{{ getOrderType(item) }}</text>
-                            <text class="detail-link">类型 ›</text> -->
 							<text class="item-title">{{ getWorkOrderProjectNo(item) }}-{{ getPcsDeviceName(item) }}{{ getOrderType(item) }}</text>
 							<text class="status-tag" :class="getStatusClass(item)">{{ getWorkOrderStatus(item) }}</text>
                         </view>
@@ -62,43 +59,6 @@
 							<view class="info-label">
 								<text class="text-gray">{{ getDisplayTime(item) }}</text>
 							</view>
-							<view class="info-value">
-								<!-- <button
-									v-if="getOrderStatus(item) == 'assigned' && canHandleOrder(item,'')"
-									class="btn-primary info-value"
-									@click.stop="handleItemClick(item,'')"
-									>
-									接单
-								</button>
-								<button
-									v-else-if="getOrderStatus(item) == 'to_approve' && canHandleOrder(item,'')"
-									class="btn-primary info-value"
-									@click.stop="handleItemClick(item,'')"
-									>
-									审批
-								</button>
-								<button
-									v-else-if="getOrderStatus(item) == 'suspended' && canHandleOrder(item,'')"
-									class="btn-primary info-value"
-									@click.stop="handleItemClick(item,'')"
-									>
-									恢复
-								</button>
-								<button
-									v-else-if="getOrderStatus(item) == 'return' && canHandleOrder(item,'acceptReturn')"
-									class="btn-primary info-value"
-									@click.stop="handleItemClick(item,'acceptReturn')"
-									>
-									退回
-								</button>
-								<button
-									v-if="getOrderStatus(item) == 'assigned' && canHandleOrder(item,'acceptReturn')"
-									class="btn-primary info-value"
-									@click.stop="handleItemClick(item,'acceptReturn')"
-									>
-									退回
-								</button> -->
-							</view>
 						</view>
 						<view class="btn-group">
 							<view
@@ -172,8 +132,10 @@ import type { acceptOrderInfo } from '../../types/order'
 import type { SysDictData, DictDataResponse } from '../../types/dict'
 import { getOrderList } from '../../api/order/list'
 import { getDictDataByType } from '../../api/dict/index'
-import {checkPermi} from '../../utils/storage'
+import {checkPermi, getUserInfo} from '../../utils/storage'
 
+	const userId = ref<string>("")
+	const roles = ref<string>('')
     // 列表数据
     const dataList = ref<acceptOrderInfo[]>([])
     let keyword = ref<string>("")
@@ -186,6 +148,12 @@ import {checkPermi} from '../../utils/storage'
 	let currentStatus = ref<string>('') // 添加状态管理
     const statusDictList = ref<SysDictData[]>([]) // 工单状态字典列表
 
+	// 添加防重复请求的标志位(参考score/pending.uvue的实现)
+	const isSearching = ref<boolean>(false)
+	// 添加防重复刷新的标志
+	const isRefreshing = ref<boolean>(false)
+	// 添加刷新时间戳,用于防抖
+	const lastRefreshTime = ref<number>(0)
 	// 添加字典加载状态
 	const dictLoaded = ref<boolean>(false)
 	// 待处理工单加载
@@ -267,26 +235,38 @@ const statusConfig: StatusItem[] = [
 
 	let loadCount = 0
     // 加载列表数据
-    const loadData = async (isRefresh: boolean | null): Promise<void> => {
+    const loadData = async (isRefresh: boolean | null, disablePullDown: boolean | null): Promise<void> => {
 		const id = ++loadCount
-		console.log(`【loadData #${id}】开始, isRefresh=${isRefresh}`)
+		console.log(`【loadData #${id}】开始, isRefresh=${isRefresh}, disablePullDown=${disablePullDown}`)
 
+        // 防止重复请求的核心机制(参考score/pending.uvue的实现)
         if (loading.value) {
-            // 如果正在加载,直接重置刷新状态
-            refreshing.value = false
+            // 确保刷新状态最终被重置,防止卡死
+            if (isRefresh != true) {
+                refreshing.value = false;
+            }
             return
         }
 
-        try {
-            loading.value = true
+        const shouldRefresh = isRefresh != null ? isRefresh : false
+        const shouldDisablePullDown = disablePullDown != null ? disablePullDown : false
+
+        loading.value = true
+        if (shouldRefresh && !shouldDisablePullDown) {
+            page.value = 1
+            refreshing.value = true
+        } else if (shouldRefresh && shouldDisablePullDown) {
+            // 状态切换时,重置页码但不触发动画
+            page.value = 1
+            // 即使禁用下拉刷新,也要确保刷新状态最终被重置
+            refreshing.value = false
+        } else {
+            // 对于加载更多操作,不需要显示下拉刷新状态
+            refreshing.value = false;
+        }
 
+        try {
             // 处理默认值
-            const shouldRefresh = isRefresh != null ? isRefresh : false
-
-            if (shouldRefresh) {
-                page.value = 1
-            }
-            // 调用 API,传递关键字参数
             const searchKeyword = keyword.value.length > 0 ? keyword.value : null
 
             const result = await getOrderList(page.value, pageSize, searchKeyword, currentStatus.value)
@@ -361,26 +341,16 @@ const statusConfig: StatusItem[] = [
             })
         } finally {
             loading.value = false
-            // #ifdef WEB
-            // Web 平台立即重置
-            refreshing.value = false
-            // #endif
-            // #ifndef WEB
-            // App 平台延迟重置刷新状态,确保 UI 更新
-            setTimeout(() => {
-                refreshing.value = false
-            }, 100)
-            // #endif
+            // 确保刷新状态能结束(参考score/pending.uvue的实现)
+            if (shouldRefresh) {
+                refreshing.value = false;
+                // 使用setTimeout确保状态彻底重置
+                setTimeout(() => {
+                    isRefreshing.value = false;
+                }, 50);
+            }
         }
-
-        // #ifdef WEB
-        // Web 平台额外确保重置
-        refreshing.value = false
-        // #endif
     }
-
-
-
     // 辅助函数:从 any 类型提取属性
     const getOrderType = (item: any | null): string => {
         if (item == null) return ''
@@ -485,38 +455,102 @@ const statusConfig: StatusItem[] = [
 
     // 切换状态
     const switchStatus = (status: string): void => {
+        // 添加防重复调用检查(参考score/pending.uvue的实现)
+        if (loading.value) {
+            return;
+        }
+
+        // 添加防重复请求检查
+        if (isSearching.value) {
+            return
+        }
+
+        isSearching.value = true
         currentStatus.value = status
         page.value = 1
-        loadData(true)
+        loadData(true, true) // 第二个参数为true表示禁用下拉刷新动画
+
+        // 延迟重置标志位,确保请求发送后才允许下一次搜索
+        setTimeout(() => {
+            isSearching.value = false
+        }, 100)
     }
 
     // 下拉刷新
     const handleRefresh = async (): Promise<void> => {
-        refreshing.value = true
-        await loadData(true as boolean | null)
+        console.log("handleRefresh被触发")
+        console.log("loading.value===",loading.value)
+        console.log("isRefreshing.value===",isRefreshing.value)
+
+        // 防抖处理,避免频繁触发(参考score/pending.uvue的实现)
+        const now = Date.now();
+        if (now - lastRefreshTime.value < 1000) {
+            refreshing.value = false;
+            return;
+        }
+        lastRefreshTime.value = now;
 
-    }
+        // 添加防重复调用检查
+        if (loading.value || isRefreshing.value) {
+            // 如果已经在加载或正在刷新,直接重置刷新状态
+            refreshing.value = false;
+            return;
+        }
+
+        console.log("loading.value1===",loading.value)
+        console.log("isRefreshing.value1===",isRefreshing.value)
+        // 设置刷新标志
+        isRefreshing.value = true;
+
+        try {
+            await loadData(true, false); // 使用默认的下拉刷新行为
+        } catch (error) {
+            console.error('刷新失败:', error);
+            refreshing.value = false;
+            isRefreshing.value = false;
+        }
 
+        // 确保在一定时间后重置刷新标志,防止意外情况
+        setTimeout(() => {
+            isRefreshing.value = false
+        }, 100) // 延迟重置,确保状态完全更新
+    }
     // 加载更多
     const loadMore = (): void => {
         if (!hasMore.value || loading.value) {
             return
         }
         page.value++
-        loadData(false as boolean | null)
+        loadData(false, false)
     }
 
     // 搜索
     const handleSearch = (): void => {
+        // 添加防重复调用检查(参考score/pending.uvue的实现)
+        if (loading.value) {
+            return;
+        }
+
+        // 添加防重复请求检查
+        if (isSearching.value) {
+            return
+        }
+
+        isSearching.value = true
         page.value = 1
-        loadData(true as boolean | null)
+        loadData(true, true) // 状态切换时禁用下拉刷新动画
+
+        // 延迟重置标志位,确保请求发送后才允许下一次搜索
+        setTimeout(() => {
+            isSearching.value = false
+        }, 100)
     }
 
 	const handleSearchOnBlur = (): void => {
 		handleSearch()
 	}
 
-	// 方法:判断当前工单是否显示操作按钮(基于 orderType)
+	// 方法:判断当前工单是否显示操作按钮
 	const canHandleOrder = (item: any | null, buttonType: string | ''): boolean => {
 	  if (item == null) return false
 	  let permit: string[] = []
@@ -528,21 +562,20 @@ const statusConfig: StatusItem[] = [
 		  // 接单
 		  permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:accept'] : ['gxt:repairOrder:accept']
 	  } else if(orderItem.workOrderStatus == 'to_finish') {
-		  if(buttonType != '' && buttonType == "suspend") {
+		  if(buttonType != '' && buttonType == "suspend" && (orderItem.teamLeaderId == parseInt(userId.value) || roles.value.includes("管理员"))) {
 			  // 挂起
 			  permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:suspend'] : ['gxt:repairOrder:suspend']
-		  } else if(buttonType != '' && buttonType == "return" && orderItem.orderType == 1) {
+		  } else if(buttonType != '' && buttonType == "return" && orderItem.orderType == 1 && (orderItem.teamLeaderId == parseInt(userId.value) || roles.value.includes("管理员"))) {
 			  // 退回
 			  permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:return'] : ['gxt:repairOrder:return']
-		  } else if(buttonType != '' && buttonType == "finalize" && orderItem.orderType == 1) {
+		  } else if(buttonType != '' && buttonType == "finalize" && orderItem.orderType == 1 && (orderItem.teamLeaderId == parseInt(userId.value) || roles.value.includes("管理员"))) {
 			  // 复启
 			  permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:finalize'] : ['gxt:repairOrder:finalize']
 		  }
-	  	
 	  } else if(orderItem.workOrderStatus == 'to_approve') {
 	  	// 审批
 	  	permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:approve'] : ['gxt:repairOrder:approve']
-	  } else if(orderItem.workOrderStatus == 'suspended') {
+	  } else if(orderItem.workOrderStatus == 'suspended' && (orderItem.teamLeaderId == parseInt(userId.value) || roles.value.includes("管理员"))) {
 	  	// 恢复
 	  	permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:resume'] : ['gxt:repairOrder:resume']
 	  } else if(orderItem.workOrderStatus == 'return') {
@@ -619,7 +652,7 @@ const statusConfig: StatusItem[] = [
 		}
 
     }
-	
+
 	// 点击列表项
 	const handleView = (item: any | null): void => {
 	    if (item == null) return
@@ -627,7 +660,7 @@ const statusConfig: StatusItem[] = [
 		uni.navigateTo({
 			url: `/pages/order/detail/index?id=${orderItem.id}&orderType=${orderItem.orderType}`
 		})
-	
+
 	}
 
     // 查看工单详情
@@ -641,14 +674,36 @@ const statusConfig: StatusItem[] = [
 
     // 清空搜索
     const clearSearch = (): void => {
+        // 添加防重复调用检查(参考score/pending.uvue的实现)
+        if (loading.value) {
+            return;
+        }
+
+        // 添加防重复请求检查
+        if (isSearching.value) {
+            return
+        }
+
+        isSearching.value = true
         keyword.value = ""
         page.value = 1
-        loadData(true)
+        loadData(true, true) // 状态切换时禁用下拉刷新动画
+
+        // 延迟重置标志位,确保请求发送后才允许下一次搜索
+        setTimeout(() => {
+            isSearching.value = false
+        }, 100)
     }
 
 	// 初始化
 	// onMounted(() => {
 	onLoad((options: any) => {
+		const userInfo = getUserInfo()
+		if (userInfo != null) {
+			const userIdStr = userInfo['userId'].toString()
+			userId.value = userIdStr
+			roles.value = userInfo['roleNames'].toString()
+		}
 	    const params = options as UTSJSONObject
 		const isDeal = params['isDeal'] as string | null
 		if(isDeal != null) {
@@ -659,7 +714,7 @@ const statusConfig: StatusItem[] = [
 		// currentStatus.value = getFirstVisibleStatus()
 		currentStatus.value = 'all'
 
-	    loadData(true as boolean | null)
+	    loadData(true, true) // 首次加载时禁用下拉刷新动画
 
 		// 监听首页切换状态事件
 		uni.$on('switchOrderStatus', (status: string) => {
@@ -667,25 +722,22 @@ const statusConfig: StatusItem[] = [
 		})
 
 		// 监听接单成功的事件,刷新列表
-		uni.$on('refreshOrderList', () => {
-			page.value = 1
-			loadData(true)
-		})
-
+    uni.$on('refreshOrderList', () => {
+     page.value = 1
+     loadData(true, false)
+    })
 	})
 
     // 组件卸载前清理事件监听
     onBeforeUnmount(() => {
         refreshing.value = false
         loading.value = false
+        isRefreshing.value = false
 
 		// 移除事件监听
 		uni.$off('refreshOrderList',{})
 		uni.$off('switchOrderStatus',{})
-    })
-
-
-</script>
+    })</script>
 
 <style lang="scss">
     .list-page {
@@ -763,30 +815,6 @@ const statusConfig: StatusItem[] = [
         padding: 30rpx;
     }
 
-    .item-header {
-        flex-direction: row;
-        align-items: center;
-        margin-bottom: 16rpx;
-
-        .location-icon {
-            width: 32rpx;
-            height: 32rpx;
-            margin-right: 8rpx;
-        }
-
-        .item-title {
-            flex: 1;
-            font-size: 32rpx;
-            color: #333333;
-            font-weight: bold;
-        }
-
-        .detail-link {
-            font-size: 28rpx;
-            color: #999999;
-        }
-    }
-
     .item-address {
         font-size: 26rpx;
         color: #999999;
@@ -813,13 +841,14 @@ const statusConfig: StatusItem[] = [
   flex-direction: row;
   align-items: flex-start;
   margin-bottom: 16rpx;
+  justify-content: space-between; /* 主轴两端对齐 */
 
   .item-title {
     font-size: 30rpx;
     color: #333333;
     font-weight: bold;
     flex-wrap: wrap;
-    flex: 0 1 80%;
+    flex: 0 1 75%;
     min-width: 0;
   }
 
@@ -856,7 +885,8 @@ const statusConfig: StatusItem[] = [
 	border-radius: 20rpx;
 	font-size: 24rpx;
 	white-space: nowrap;
-	margin-left: 50rpx;
+	// margin-left: 50rpx;
+	// justify-content: flex-end;
 	border: 1rpx solid;
 }
 

+ 220 - 78
pages/order/overdue.uvue

@@ -18,7 +18,7 @@
             :hasMore="hasMore"
             @refresh="handleRefresh"
             @loadMore="loadMore"
-            @itemClick="handleItemClick"
+            @itemClick="handleView"
         >
             <template #default="{ item, index }">
                 <view class="list-item">
@@ -31,15 +31,22 @@
 							<view class="info-label">
 								<text class="text-gray">{{ getCreateTime(item) }}</text>
 							</view>
-							<view class="info-value">
-								<view
-									v-if="canHandleOrder(item)"
-									class="btn-primary info-value"
-									@click.stop="handleItemClick(item)"
-									>
-									<text class="btn-text">接单</text>
-								</view>
-								</view>
+						</view>
+						<view class="btn-group">
+							<view
+								v-if="getOrderStatus(item) == 'assigned' && canHandleOrder(item,'accept')"
+								class="btn-primary info-value"
+								@click.stop="handleItemClick(item,'')"
+								>
+								<text class="btn-text">接单</text>
+							</view>
+							<view
+								v-if="getOrderStatus(item) == 'assigned' && canHandleOrder(item,'acceptReturn')"
+								class="btn-primary info-value"
+								@click.stop="handleItemClick(item,'acceptReturn')"
+								>
+								<text class="btn-text">退回</text>
+							</view>
 						</view>
                     </view>
                 </view>
@@ -69,14 +76,34 @@ import {checkPermi} from '../../utils/storage'
 
 	// 添加字典加载状态
 	const dictLoaded = ref<boolean>(false)
+
+	// 添加防重复请求的标志位
+	const isSearching = ref<boolean>(false)
+	// 添加防重复刷新的标志
+	const isRefreshing = ref<boolean>(false)
+	// 添加刷新时间戳,用于防抖
+	const lastRefreshTime = ref<number>(0)
 	
+	const getOrderStatus = (item: any | null): string => {
+		if (item == null) return ''
+		const orderItem = item as acceptOrderInfo
+		return orderItem.workOrderStatus ?? ''
+	}
+
 	// 方法:判断当前工单是否显示操作按钮(基于 orderType)
-	const canHandleOrder = (item: any | null): boolean => {
+	const canHandleOrder = (item: any | null, buttonType: string | ''): boolean => {
 	    if (item == null) return false
 	    let permit: string[] = []
 	    const orderItem = item as acceptOrderInfo
-	    // 接单
-	  	permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:accept'] : ['gxt:repairOrder:accept']
+	    if(orderItem.workOrderStatus == 'assigned' && buttonType != '' && buttonType == "acceptReturn" && orderItem.orderType == 1) {
+			// 接单退回
+			permit = ['gxt:repairOrder:acceptReturn']
+	    } else if(orderItem.workOrderStatus == 'assigned' && buttonType != '' && buttonType == "accept") {
+			// 接单
+			permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:accept'] : ['gxt:repairOrder:accept']
+	    } else {
+			return false
+		}
 	    return checkPermi(permit)
 	}
 
@@ -122,24 +149,49 @@ import {checkPermi} from '../../utils/storage'
 	}
 
     // 加载列表数据
-    const loadData = async (isRefresh: boolean | null): Promise<void> => {
+    const loadData = async (isRefresh: boolean | null, disablePullDown: boolean): Promise<void> => {
+        // 防止重复请求的核心机制
         if (loading.value) {
-            // 如果正在加载,直接重置刷新状态
-            refreshing.value = false
+            // 确保刷新状态最终被重置,防止卡死
+            if (isRefresh != true) {
+                refreshing.value = false;
+            }
             return
         }
 
-        try {
-            loading.value = true
+        const shouldRefresh = isRefresh != null ? isRefresh : false
+
+        loading.value = true
+        let refreshTimeout: number | null = null;
+        
+        if (shouldRefresh && !disablePullDown) {
+            page.value = 1
+            refreshing.value = true
+            
+            // 添加超时机制,确保刷新动画不会一直显示
+            refreshTimeout = setTimeout(() => {
+                if (refreshing.value) {
+                    refreshing.value = false;
+                    isRefreshing.value = false;
+                    console.log("刷新超时,强制结束刷新状态");
+                    uni.showToast({
+                        title: '刷新超时',
+                        icon: 'none'
+                    });
+                }
+            }, 10000); // 10秒超时
+        } else if (shouldRefresh && disablePullDown) {
+            // 状态切换时,重置页码但不触发动画
+            page.value = 1
+            // 即使禁用下拉刷新,也要确保刷新状态最终被重置
+            refreshing.value = false
+        } else {
+            // 对于加载更多操作,不需要显示下拉刷新状态
+            refreshing.value = false;
+        }
 
+        try {
             // 处理默认值
-            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)
@@ -208,22 +260,20 @@ import {checkPermi} from '../../utils/storage'
             })
         } finally {
             loading.value = false
-            // #ifdef WEB
-            // Web 平台立即重置
-            refreshing.value = false
-            // #endif
-            // #ifndef WEB
-            // App 平台延迟重置刷新状态,确保 UI 更新
-            setTimeout(() => {
-                refreshing.value = false
-            }, 100)
-            // #endif
+            // 清除超时定时器
+            if (refreshTimeout != null) {
+                clearTimeout(refreshTimeout);
+            }
+            // 确保刷新状态能结束
+            if (shouldRefresh) {
+                refreshing.value = false;
+                // 使用setTimeout确保状态彻底重置
+                setTimeout(() => {
+                    isRefreshing.value = false;
+                    refreshing.value = false; // 再次确保刷新状态被重置
+                }, 50);
+            }
         }
-
-        // #ifdef WEB
-        // Web 平台额外确保重置
-        refreshing.value = false
-        // #endif
     }
 
     // 辅助函数:从 any 类型提取属性
@@ -280,8 +330,65 @@ import {checkPermi} from '../../utils/storage'
 
     // 下拉刷新
     const handleRefresh = async (): Promise<void> => {
-        refreshing.value = true
-        await loadData(true as boolean | null)
+        console.log("handleRefresh被触发")
+        console.log("loading.value===",loading.value)
+        console.log("isRefreshing.value===",isRefreshing.value)
+
+        // 防抖处理,避免频繁触发
+        const now = Date.now();
+        if (now - lastRefreshTime.value < 1000) {
+            console.log("刷新操作过于频繁,忽略本次触发");
+            refreshing.value = false;
+            return;
+        }
+        lastRefreshTime.value = now;
+
+        // 添加防重复调用检查
+        if (loading.value || isRefreshing.value) {
+            // 如果已经在加载或正在刷新,直接重置刷新状态
+            refreshing.value = false;
+            return;
+        }
+
+        console.log("loading.value1===",loading.value)
+        console.log("isRefreshing.value1===",isRefreshing.value)
+        // 设置刷新标志
+        isRefreshing.value = true;
+        refreshing.value = true; // 确保刷新状态被设置
+        
+        // 添加超时机制,确保刷新动画不会一直显示
+        const refreshTimeout = setTimeout(() => {
+            if (refreshing.value || isRefreshing.value) {
+                refreshing.value = false;
+                isRefreshing.value = false;
+                console.log("刷新超时,强制结束刷新状态");
+                uni.showToast({
+                    title: '刷新超时',
+                    icon: 'none'
+                });
+            }
+        }, 10000); // 10秒超时
+
+        try {
+            await loadData(true, false); // 使用默认的下拉刷新行为
+        } catch (error) {
+            console.error('刷新失败:', error);
+            // 发生异常时确保刷新状态被重置
+            refreshing.value = false;
+            isRefreshing.value = false;
+        } finally {
+            // 清除超时定时器
+            clearTimeout(refreshTimeout);
+            // 确保刷新状态最终被重置
+            refreshing.value = false;
+            isRefreshing.value = false;
+        }
+
+        // 额外的保险机制,确保在一定时间后重置刷新标志
+        setTimeout(() => {
+            refreshing.value = false;
+            isRefreshing.value = false;
+        }, 200) // 延迟重置,确保状态完全更新
     }
 
     // 加载更多
@@ -290,48 +397,100 @@ import {checkPermi} from '../../utils/storage'
             return
         }
         page.value++
-        loadData(false as boolean | null)
+        loadData(false, false) // 加载更多时不涉及下拉刷新动画
     }
 
     // 搜索
     const handleSearch = (): void => {
+        // 添加防重复调用检查
+        if (loading.value) {
+            return;
+        }
+
+        // 添加防重复请求检查
+        if (isSearching.value) {
+            return
+        }
+
+        isSearching.value = true
         page.value = 1
-		console.log("======搜索=====" + keyword.value)
-        loadData(true as boolean | null)
+        loadData(true, true) // 状态切换时禁用下拉刷新动画
+
+        // 延迟重置标志位,确保请求发送后才允许下一次搜索
+        setTimeout(() => {
+            isSearching.value = false
+        }, 100)
     }
 
     // 点击列表项
-    const handleItemClick = (item: any | null): void => {
+    const handleItemClick = (item: any | null, buttonType: string | ''): void => {
         if (item == null) return
         const orderItem = item as acceptOrderInfo
-		// 跳转到工单详情页
+		if(orderItem.workOrderStatus == 'assigned') {
+			if(buttonType != '' && buttonType == "acceptReturn") {
+				// 跳转到退回页面
+				uni.navigateTo({
+					url: `/pages/order/detail/returnIndex?id=${orderItem.id}&orderType=${orderItem.orderType}`
+				})
+			} else {
+				// 跳转到接单页面
+				uni.navigateTo({
+				    url: `/pages/order/detail/acceptIndex?id=${orderItem.id}&orderType=${orderItem.orderType}`
+				})
+			}
+		}
+    }
+	
+	// 点击列表项
+	const handleView = (item: any | null): void => {
+	    if (item == null) return
+	    const orderItem = item as acceptOrderInfo
 		uni.navigateTo({
-		    url: `/pages/order/detail/acceptIndex?id=${orderItem.id}&orderType=${orderItem.orderType}`
+			url: `/pages/order/detail/index?id=${orderItem.id}&orderType=${orderItem.orderType}`
 		})
-    }
+	
+	}
 
     // 清空搜索
     const clearSearch = (): void => {
+        // 添加防重复调用检查
+        if (loading.value) {
+            return;
+        }
+
+        // 添加防重复请求检查
+        if (isSearching.value) {
+            return
+        }
+
+        isSearching.value = true
         keyword.value = ""
         page.value = 1
-        loadData(true)
+        loadData(true, true) // 状态切换时禁用下拉刷新动画
+
+        // 延迟重置标志位,确保请求发送后才允许下一次搜索
+        setTimeout(() => {
+            isSearching.value = false
+        }, 100)
     }
 
 	// 初始化
 	onMounted(() => {
 	    loadStatusDictList()
-	    loadData(true as boolean | null)
+	    loadData(true as boolean | null, false)
 		// 监听接单成功的事件,刷新列表
 		uni.$on('refreshOrderList', () => {
 			page.value = 1
-			loadData(true)
+			loadData(true, false)
 		})
 	})
 
     // 组件卸载前清理事件监听
     onBeforeUnmount(() => {
+        // 确保所有状态都被重置
         refreshing.value = false
         loading.value = false
+        isRefreshing.value = false
 		// 移除事件监听
 		uni.$off('refreshOrderList',{})
     })
@@ -385,35 +544,18 @@ import {checkPermi} from '../../utils/storage'
         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;
+  justify-content: space-between;
 
   .item-title {
     font-size: 30rpx;
     color: #333333;
     font-weight: bold;
     flex-wrap: wrap;
-    flex: 0 1 80%;
+    flex: 0 1 75%;
     min-width: 0;
   }
 
@@ -449,7 +591,7 @@ import {checkPermi} from '../../utils/storage'
 	border-radius: 20rpx;
 	font-size: 24rpx;
 	white-space: nowrap;
-	margin-left: 20rpx;
+	// margin-left: 20rpx;
 	border: 1rpx solid;
 }
 
@@ -519,10 +661,10 @@ import {checkPermi} from '../../utils/storage'
 	}
 }
 
-// /* 超时 */
-// .status-overdue {
-// 	background-color: #fff2f0;
-// 	color: #ff4d4f;
-// 	border-color: #ffccc7;
-// }
+.btn-group {
+  flex-direction: row;
+  align-items: center;
+  justify-content: flex-end;
+  margin-top: 20rpx;
+}
 </style>

+ 428 - 228
pages/order/pendingOrder.uvue

@@ -18,7 +18,7 @@
             :hasMore="hasMore"
             @refresh="handleRefresh"
             @loadMore="loadMore"
-            @itemClick="handleItemClick"
+            @itemClick="handleView"
         >
             <template #default="{ item, index }">
                 <view class="list-item">
@@ -31,35 +31,63 @@
 							<view class="info-label">
 								<text class="text-gray">{{ getDisplayTime(item) }}</text>
 							</view>
-							<view class="info-value">
-								<view
-									v-if="getOrderStatus(item) == 'assigned' && canHandleOrder(item)"
-									class="btn-primary info-value"
-									@click.stop="handleItemClick(item)"
-									>
-									<text class="btn-text">接单</text>
-								</view>
-								<view
-									v-else-if="getOrderStatus(item) == 'to_approve' && canHandleOrder(item)"
-									class="btn-primary info-value"
-									@click.stop="handleItemClick(item)"
-									>
-									<text class="btn-text">审批</text>
-								</view>
-								<!-- <button
-									v-else-if="getOrderStatus(item) == 'to_finish' && canHandleOrder(item)"
-									class="btn-primary info-value"
-									@click.stop="handleItemClick(item)"
-									>
-									挂起
-								</button> -->
-								<view
-									v-else-if="getOrderStatus(item) == 'suspended' && canHandleOrder(item)"
-									class="btn-primary info-value"
-									@click.stop="handleItemClick(item)"
-									>
-									<text class="btn-text">恢复</text>
-								</view>
+						</view>
+						<view class="btn-group">
+							<view
+								v-if="getOrderStatus(item) == 'assigned' && canHandleOrder(item,'accept')"
+								class="btn-primary info-value"
+								@click.stop="handleItemClick(item,'')"
+								>
+								<text class="btn-text">接单</text>
+							</view>
+							<view
+								v-if="getOrderStatus(item) == 'to_approve' && canHandleOrder(item,'')"
+								class="btn-primary info-value"
+								@click.stop="handleItemClick(item,'')"
+								>
+								<text class="btn-text">审批</text>
+							</view>
+							<view
+								v-if="getOrderStatus(item) == 'suspended' && canHandleOrder(item,'')"
+								class="btn-primary info-value"
+								@click.stop="handleItemClick(item,'')"
+								>
+								<text class="btn-text">恢复</text>
+							</view>
+							<view
+								v-if="getOrderStatus(item) == 'return' && canHandleOrder(item,'acceptReturn')"
+								class="btn-primary info-value"
+								@click.stop="handleItemClick(item,'acceptReturn')"
+								>
+								<text class="btn-text">退回</text>
+							</view>
+							<view
+								v-if="getOrderStatus(item) == 'assigned' && canHandleOrder(item,'acceptReturn')"
+								class="btn-primary info-value"
+								@click.stop="handleItemClick(item,'acceptReturn')"
+								>
+								<text class="btn-text">退回</text>
+							</view>
+							<view
+								v-if="getOrderStatus(item) == 'to_finish' && canHandleOrder(item, 'return')"
+								class="btn-primary info-value"
+								@click.stop="handleItemClick(item, 'return')"
+								>
+								<text class="btn-text">退回</text>
+							</view>
+							<view
+								v-if="getOrderStatus(item) == 'to_finish' && canHandleOrder(item, 'suspend')"
+								class="btn-primary info-value"
+								@click.stop="handleItemClick(item, 'suspend')"
+								>
+								<text class="btn-text">挂起</text>
+							</view>
+							<view
+								v-if="getOrderStatus(item) == 'to_finish' && canHandleOrder(item, 'finalize')"
+								class="btn-primary info-value"
+								@click.stop="handleItemClick(item, 'finalize')"
+								>
+								<text class="btn-text">复启</text>
 							</view>
 						</view>
                     </view>
@@ -75,7 +103,10 @@ import type { acceptOrderInfo } from '../../types/order'
 import type { SysDictData } from '../../types/dict'
 import { pendingList } from '../../api/order/list'
 import { getDictDataByType } from '../../api/dict/index'
-import {checkPermi} from '../../utils/storage'
+import {checkPermi, getUserInfo} from '../../utils/storage'
+
+	const userId = ref<string>("")
+	const roles = ref<string>('')
 
     // 列表数据
     const dataList = ref<acceptOrderInfo[]>([])
@@ -90,34 +121,55 @@ import {checkPermi} from '../../utils/storage'
 
 	// 添加字典加载状态
 	const dictLoaded = ref<boolean>(false)
-	
+
+	// 添加防重复请求的标志位
+	const isSearching = ref<boolean>(false)
+	// 添加防重复刷新的标志
+	const isRefreshing = ref<boolean>(false)
+	// 添加刷新时间戳,用于防抖
+	const lastRefreshTime = ref<number>(0)
+
 	const getOrderStatus = (item: any | null): string => {
 		if (item == null) return ''
 		const orderItem = item as acceptOrderInfo
 		return orderItem.workOrderStatus ?? ''
 	}
-	
+
 	// 方法:判断当前工单是否显示操作按钮(基于 orderType)
-	const canHandleOrder = (item: any | null): boolean => {
+	const canHandleOrder = (item: any | null, buttonType: string | ''): boolean => {
 	  if (item == null) return false
 	  let permit: string[] = []
 	  const orderItem = item as acceptOrderInfo
-	  if(orderItem.workOrderStatus == 'assigned') {
-	  	// 接单
-	  	permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:accept'] : ['gxt:repairOrder:accept']
-	  // } else if(orderItem.workOrderStatus == 'to_finish') {
-	  // 	// 挂起
-	  // 	permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:suspend'] : ['gxt:repairOrder:suspend']
+	  if(orderItem.workOrderStatus == 'assigned' && buttonType != '' && buttonType == "acceptReturn" && orderItem.orderType == 1) {
+	  			// 接单退回
+	  			permit = ['gxt:repairOrder:acceptReturn']
+	  } else if(orderItem.workOrderStatus == 'assigned' && buttonType != '' && buttonType == "accept") {
+	  		  // 接单
+	  		  permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:accept'] : ['gxt:repairOrder:accept']
+	  } else if(orderItem.workOrderStatus == 'to_finish') {
+	  		  if(buttonType != '' && buttonType == "suspend" && (orderItem.teamLeaderId == parseInt(userId.value) || roles.value.includes("管理员"))) {
+	  			  // 挂起
+	  			  permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:suspend'] : ['gxt:repairOrder:suspend']
+	  		  } else if(buttonType != '' && buttonType == "return" && orderItem.orderType == 1 && (orderItem.teamLeaderId == parseInt(userId.value) || roles.value.includes("管理员"))) {
+	  			  // 退回
+	  			  permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:return'] : ['gxt:repairOrder:return']
+	  		  } else if(buttonType != '' && buttonType == "finalize" && orderItem.orderType == 1 && (orderItem.teamLeaderId == parseInt(userId.value) || roles.value.includes("管理员"))) {
+	  			  // 复启
+	  			  permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:finalize'] : ['gxt:repairOrder:finalize']
+	  		  }
 	  } else if(orderItem.workOrderStatus == 'to_approve') {
 	  	// 审批
 	  	permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:approve'] : ['gxt:repairOrder:approve']
-	  } else if(orderItem.workOrderStatus == 'suspended') {
+	  } else if(orderItem.workOrderStatus == 'suspended' && (orderItem.teamLeaderId == parseInt(userId.value) || roles.value.includes("管理员"))) {
 	  	// 恢复
 	  	permit = orderItem.orderType == 2 ? ['gxt:maintenance:order:resume'] : ['gxt:repairOrder:resume']
-	  } else {
-		  return false
+	  } else if(orderItem.workOrderStatus == 'return') {
+	  	// 接单退回
+	  	permit = ['gxt:repairOrder:acceptReturn']
+	  }
+	   else {
+	  		  return false
 	  }
-	  
 	  // const orderType = (item as acceptOrderInfo).orderType
 	  return checkPermi(permit)
 	}
@@ -164,23 +216,50 @@ import {checkPermi} from '../../utils/storage'
 	}
 
     // 加载列表数据
-    const loadData = async (isRefresh: boolean | null): Promise<void> => {
+    const loadData = async (isRefresh: boolean | null, disablePullDown: boolean | null): Promise<void> => {
+        // 防止重复请求的核心机制
         if (loading.value) {
-            // 如果正在加载,直接重置刷新状态
-            refreshing.value = false
+            // 确保刷新状态最终被重置,防止卡死
+            if (isRefresh != true) {
+                refreshing.value = false;
+            }
             return
         }
 
-        try {
-            loading.value = true
+        const shouldRefresh = isRefresh != null ? isRefresh : false
+        const disablePull = disablePullDown != null ? disablePullDown : false
+
+        loading.value = true
+        let refreshTimeout: number | null = null;
+        
+        if (shouldRefresh && !disablePull) {
+            page.value = 1
+            refreshing.value = true
+            
+            // 添加超时机制,确保刷新动画不会一直显示
+            refreshTimeout = setTimeout(() => {
+                if (refreshing.value) {
+                    refreshing.value = false;
+                    isRefreshing.value = false;
+                    console.log("刷新超时,强制结束刷新状态");
+                    uni.showToast({
+                        title: '刷新超时',
+                        icon: 'none'
+                    });
+                }
+            }, 10000); // 10秒超时
+        } else if (shouldRefresh && disablePull) {
+            // 状态切换时,重置页码但不触发动画
+            page.value = 1
+            // 即使禁用下拉刷新,也要确保刷新状态最终被重置
+            refreshing.value = false
+        } else {
+            // 对于加载更多操作,不需要显示下拉刷新状态
+            refreshing.value = false;
+        }
 
+        try {
             // 处理默认值
-            const shouldRefresh = isRefresh != null ? isRefresh : false
-
-            if (shouldRefresh) {
-                page.value = 1
-            }
-            // 调用 API,传递关键字参数
             const searchKeyword = keyword.value.length > 0 ? keyword.value : null
 
             const result = await pendingList(page.value, pageSize, searchKeyword)
@@ -249,22 +328,20 @@ import {checkPermi} from '../../utils/storage'
             })
         } finally {
             loading.value = false
-            // #ifdef WEB
-            // Web 平台立即重置
-            refreshing.value = false
-            // #endif
-            // #ifndef WEB
-            // App 平台延迟重置刷新状态,确保 UI 更新
-            setTimeout(() => {
-                refreshing.value = false
-            }, 100)
-            // #endif
+            // 清除超时定时器
+            if (refreshTimeout != null) {
+                clearTimeout(refreshTimeout);
+            }
+            // 确保刷新状态能结束
+            if (shouldRefresh) {
+                refreshing.value = false;
+                // 使用setTimeout确保状态彻底重置
+                setTimeout(() => {
+                    isRefreshing.value = false;
+                    refreshing.value = false; // 再次确保刷新状态被重置
+                }, 50);
+            }
         }
-
-        // #ifdef WEB
-        // Web 平台额外确保重置
-        refreshing.value = false
-        // #endif
     }
 
     // 辅助函数:从 any 类型提取属性
@@ -285,12 +362,12 @@ import {checkPermi} from '../../utils/storage'
         const orderInfoItem = item as acceptOrderInfo
         return orderInfoItem.pcsDeviceName
     }
-	
+
 	// 根据状态显示不同的时间
 	const getDisplayTime = (item: any | null): string|null => {
 		if (item == null) return null
 		const orderInfoItem = item as acceptOrderInfo
-	
+
 		// 如果是"待接单"状态,显示派单时间
 		if (orderInfoItem.workOrderStatus == 'assigned') {
 			return '下发时间:' + orderInfoItem.assignTime
@@ -308,7 +385,7 @@ import {checkPermi} from '../../utils/storage'
 		} else if(orderInfoItem.workOrderStatus == 'completed') {
 			return '结单时间:' + orderInfoItem.updateTime
 		}
-	
+
 		// 默认显示创建时间
 		return '创建时间:' + orderInfoItem.createTime
 	}
@@ -343,8 +420,63 @@ import {checkPermi} from '../../utils/storage'
 
     // 下拉刷新
     const handleRefresh = async (): Promise<void> => {
-        refreshing.value = true
-        await loadData(true as boolean | null)
+        console.log("handleRefresh被触发")
+        console.log("loading.value===",loading.value)
+        console.log("isRefreshing.value===",isRefreshing.value)
+
+        // 防抖处理,避免频繁触发
+        const now = Date.now();
+        if (now - lastRefreshTime.value < 1000) {
+            console.log("刷新操作过于频繁,忽略本次触发");
+            refreshing.value = false;
+            return;
+        }
+        lastRefreshTime.value = now;
+
+        // 添加防重复调用检查
+        if (loading.value || isRefreshing.value) {
+            // 如果已经在加载或正在刷新,直接重置刷新状态
+            refreshing.value = false;
+            return;
+        }
+
+        console.log("loading.value1===",loading.value)
+        console.log("isRefreshing.value1===",isRefreshing.value)
+        // 设置刷新标志
+        isRefreshing.value = true;
+        refreshing.value = true; // 确保刷新状态被设置
+        
+        // 添加超时机制,确保刷新动画不会一直显示
+        const refreshTimeout = setTimeout(() => {
+            if (refreshing.value || isRefreshing.value) {
+                refreshing.value = false;
+                isRefreshing.value = false;
+                console.log("刷新操作超时,重置刷新状态");
+                uni.showToast({
+                    title: '刷新超时',
+                    icon: 'none'
+                });
+            }
+        }, 10000);
+
+        try {
+            await loadData(true, false); // 使用默认的下拉刷新行为
+        } catch (error) {
+            console.error('刷新失败:', error);
+            refreshing.value = false;
+            isRefreshing.value = false;
+        } finally {
+            clearTimeout(refreshTimeout);
+            // 确保刷新状态最终被重置
+            refreshing.value = false;
+            isRefreshing.value = false;
+        }
+
+        // 额外的保险机制,确保在一定时间后重置刷新标志
+        setTimeout(() => {
+            refreshing.value = false;
+            isRefreshing.value = false;
+        }, 200) // 延迟重置,确保状态完全更新
     }
 
     // 加载更多
@@ -353,23 +485,74 @@ import {checkPermi} from '../../utils/storage'
             return
         }
         page.value++
-        loadData(false as boolean | null)
+        loadData(false, false) // 加载更多时不涉及下拉刷新动画
     }
 
     // 搜索
     const handleSearch = (): void => {
+        // 添加防重复调用检查
+        if (loading.value) {
+            return;
+        }
+
+        // 添加防重复请求检查
+        if (isSearching.value) {
+            return
+        }
+
+        isSearching.value = true
         page.value = 1
-        loadData(true as boolean | null)
+        loadData(true, true) // 状态切换时禁用下拉刷新动画
+
+        // 延迟重置标志位,确保请求发送后才允许下一次搜索
+        setTimeout(() => {
+            isSearching.value = false
+        }, 100)
     }
+	
+	// 点击列表查看
+	const handleView = (item: any | null): void => {
+	    if (item == null) return
+	    const orderItem = item as acceptOrderInfo
+		uni.navigateTo({
+			url: `/pages/order/detail/index?id=${orderItem.id}&orderType=${orderItem.orderType}`
+		})
+	
+	}
 
     // 点击列表项
-    const handleItemClick = (item: any | null): void => {
+    const handleItemClick = (item: any | null, buttonType: string | ''): void => {
         if (item == null) return
         const orderItem = item as acceptOrderInfo
 		if(orderItem.workOrderStatus == 'assigned') {
-			uni.navigateTo({
-			    url: `/pages/order/detail/acceptIndex?id=${orderItem.id}&orderType=${orderItem.orderType}`
-			})
+			if(buttonType != '' && buttonType == "acceptReturn") {
+				// 跳转到退回页面
+				uni.navigateTo({
+					url: `/pages/order/detail/returnIndex?id=${orderItem.id}&orderType=${orderItem.orderType}`
+				})
+			} else {
+				// 跳转到接单页面
+				uni.navigateTo({
+				    url: `/pages/order/detail/acceptIndex?id=${orderItem.id}&orderType=${orderItem.orderType}`
+				})
+			}
+		} else if(orderItem.workOrderStatus == 'to_finish') {
+			if(buttonType != '' && buttonType == "suspend") {
+				// 跳转到待结单页面
+				uni.navigateTo({
+					url: `/pages/order/detail/suspendIndex?id=${orderItem.id}&orderType=${orderItem.orderType}`
+				})
+			} else if(buttonType != '' && buttonType == "return") {
+				// 跳转到退回页面
+				uni.navigateTo({
+					url: `/pages/order/detail/returnIndex?id=${orderItem.id}&orderType=${orderItem.orderType}`
+				})
+			} else if(buttonType != '' && buttonType == "finalize") {
+				// 跳转到复启页面
+				uni.navigateTo({
+					url: `/pages/order/detail/resetIndex?id=${orderItem.id}&orderType=${orderItem.orderType}`
+				})
+			}
 		} else if(orderItem.workOrderStatus == 'to_approve') {
 			// 跳转到待审批页面
 			uni.navigateTo({
@@ -380,36 +563,65 @@ import {checkPermi} from '../../utils/storage'
 			uni.navigateTo({
 			    url: `/pages/order/detail/resumeIndex?id=${orderItem.id}&orderType=${orderItem.orderType}`
 			})
+		} else if(orderItem.workOrderStatus == 'return') {
+			// 跳转到退回页面
+			uni.navigateTo({
+			    url: `/pages/order/detail/returnIndex?id=${orderItem.id}&orderType=${orderItem.orderType}`
+			})
 		} else {
 			uni.navigateTo({
-			    url: `/pages/order/detail/index?id=${orderItem.id}&orderType=${orderItem.orderType}`
+				url: `/pages/order/detail/index?id=${orderItem.id}&orderType=${orderItem.orderType}`
 			})
 		}
-		
+
     }
 
     // 清空搜索
     const clearSearch = (): void => {
+        // 添加防重复调用检查
+        if (loading.value) {
+            return;
+        }
+
+        // 添加防重复请求检查
+        if (isSearching.value) {
+            return
+        }
+
+        isSearching.value = true
         keyword.value = ""
         page.value = 1
-        loadData(true)
+        loadData(true, true) // 状态切换时禁用下拉刷新动画
+
+        // 延迟重置标志位,确保请求发送后才允许下一次搜索
+        setTimeout(() => {
+            isSearching.value = false
+        }, 100)
     }
 
 	// 初始化
 	onMounted(() => {
+		const userInfo = getUserInfo()
+		if (userInfo != null) {
+			const userIdStr = userInfo['userId'].toString()
+			userId.value = userIdStr
+			roles.value = userInfo['roleNames'].toString()
+		}
 	    loadStatusDictList()
-	    loadData(true as boolean | null)
+	    loadData(true, false)
 		// 监听接单成功的事件,刷新列表
 		uni.$on('refreshOrderList', () => {
 			page.value = 1
-			loadData(true)
+			loadData(true, false)
 		})
 	})
 
     // 组件卸载前清理事件监听
     onBeforeUnmount(() => {
+        // 确保所有状态都被重置
         refreshing.value = false
         loading.value = false
+        isRefreshing.value = false
 		// 移除事件监听
 		uni.$off('refreshOrderList',{})
     })
@@ -463,154 +675,142 @@ import {checkPermi} from '../../utils/storage'
         padding: 30rpx;
     }
 
-    .item-header {
-        flex-direction: row;
-        align-items: center;
-        margin-bottom: 16rpx;
+	.item-header {
+	  flex-direction: row;
+	  align-items: flex-start;
+	  margin-bottom: 16rpx;
+	  justify-content: space-between;
+
+	  .item-title {
+		font-size: 30rpx;
+		color: #333333;
+		font-weight: bold;
+		flex-wrap: wrap;
+		flex: 0 1 75%;
+		min-width: 0;
+	  }
 
-        .item-title {
-            flex: 1;
-            font-size: 32rpx;
-            color: #333333;
-            font-weight: bold;
-        }
+	  .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;
+	  }
 
-        .detail-link {
-            font-size: 28rpx;
-            color: #999999;
-        }
-    }
+	  .info-value {
+		font-size: 26rpx;
+	  }
+	}
+	.text-gray{
+	  font-size: 26rpx;
+	  color: #666;
+	}
 
-.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-return {
-	background-color: #fff2f0;
-	color: #ff4d4f;
-	border-color: #ffccc7;
-}
-
-/* 退回 */
-.status-accept_return {
-	background-color: #fff2f0;
-	color: #ff4d4f;
-	border-color: #ffccc7;
-}
-
-.btn-primary {
-	z-index: 999;
-	border-radius: 10rpx;
-	font-size: 24rpx;
-	// white-space: nowrap;
-	margin-left: 20rpx;
-	background-color: #165DFF;
-	line-height: 45rpx;
-	color: #ffffff;
-	.btn-text{
-		color: #ffffff;
+	.status-tag {
+		padding: 8rpx 20rpx;
+		border-radius: 20rpx;
 		font-size: 24rpx;
-		padding: 5px 15px;
+		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-return {
+		background-color: #fff2f0;
+		color: #ff4d4f;
+		border-color: #ffccc7;
+	}
+
+	/* 退回 */
+	.status-accept_return {
+		background-color: #fff2f0;
+		color: #ff4d4f;
+		border-color: #ffccc7;
+	}
+
+	.btn-primary {
+		z-index: 999;
+		border-radius: 10rpx;
+		font-size: 24rpx;
+		// white-space: nowrap;
+		margin-left: 20rpx;
+		background-color: #165DFF;
+		line-height: 45rpx;
+		color: #ffffff;
+		.btn-text{
+			color: #ffffff;
+			font-size: 24rpx;
+			padding: 5px 15px;
+		}
+	}
+	.btn-group {
+	  flex-direction: row;
+	  align-items: center;
+	  justify-content: flex-end;
+	  margin-top: 20rpx;
+	}
 // /* 超时 */
 // .status-overdue {
 // 	background-color: #fff2f0;

+ 23 - 23
pages/score/index.uvue

@@ -215,7 +215,7 @@
     const isRefreshing = ref<boolean>(false)
     // 添加刷新时间戳,用于防抖
     const lastRefreshTime = ref<number>(0)
-    
+
     // 添加防抖定时器
     let searchTimer: number | null = null
 
@@ -514,12 +514,12 @@
 	  showDatePicker.value = false
 	  showDatePickerPopup.value = false
 	  selectedMonth.value = 'custom'
-	  
+
       // 添加防重复调用检查
       if (loading.value) {
         return;
       }
-      
+
 	  getStatistics()
 	}
 
@@ -622,18 +622,18 @@
       if (loading.value) {
         return;
       }
-      
+
       // 添加防抖和防止重复请求
       if (isSearching.value) {
         return
       }
-      
+
       const timer = searchTimer
       if (timer != null) {
         clearTimeout(timer)
         searchTimer = null
       }
-      
+
       searchTimer = setTimeout(() => {
         isSearching.value = true
         loadData(true, true); // 添加true参数表示这是筛选条件变化触发的加载,应禁用下拉刷新
@@ -649,18 +649,18 @@
       if (loading.value) {
         return;
       }
-      
+
       // 添加防抖和防止重复请求
       if (isSearching.value) {
         return
       }
-      
+
       const timer = searchTimer
       if (timer != null) {
         clearTimeout(timer)
         searchTimer = null
       }
-      
+
       searchKeyword.value = ""
       searchTimer = setTimeout(() => {
         isSearching.value = true
@@ -677,18 +677,18 @@
       if (loading.value) {
         return;
       }
-      
+
       // 添加防止重复请求
       if (isSearching.value) {
         return
       }
-      
+
       const timer = searchTimer
       if (timer != null) {
         clearTimeout(timer)
         searchTimer = null
       }
-      
+
       statusFilter.value = status
       searchTimer = setTimeout(() => {
         isSearching.value = true
@@ -706,18 +706,18 @@
       if (loading.value) {
         return;
       }
-      
+
 	  // 添加防止重复请求
 	  if (isSearching.value) {
 	    return
 	  }
-	  
+
       const timer = searchTimer
       if (timer != null) {
         clearTimeout(timer)
         searchTimer = null
       }
-      
+
       selectedMonth.value = month
       searchTimer = setTimeout(() => {
         getStatistics()
@@ -736,7 +736,7 @@
       console.log("handleRefresh被触发")
       console.log("loading.value===",loading.value)
       console.log("isRefreshing.value===",isRefreshing.value)
-      
+
       // 防抖处理,避免频繁触发
       const now = Date.now();
       if (now - lastRefreshTime.value < 1000) {
@@ -745,7 +745,7 @@
         return;
       }
       lastRefreshTime.value = now;
-      
+
       // 添加防重复调用检查
       if (loading.value || isRefreshing.value) {
         // 如果已经在加载或正在刷新,直接重置刷新状态
@@ -756,9 +756,9 @@
         console.log("isRefreshing.value1===",isRefreshing.value)
       // 设置刷新标志
       isRefreshing.value = true;
-      
+
       loadData(true); // 使用默认的下拉刷新行为
-      
+
       // 确保在一定时间后重置刷新标志,防止意外情况
       setTimeout(() => {
         isRefreshing.value = false
@@ -814,7 +814,7 @@
       getStatistics()
       dictLoaded.value = true
     })
-    
+
     // 组件销毁时清除定时器
     onBeforeUnmount(() => {
       const timer = searchTimer
@@ -822,7 +822,7 @@
         clearTimeout(timer)
         searchTimer = null
       }
-      
+
       // 如果组件销毁前还有未完成的刷新操作,确保状态被重置
       loading.value = false;
       refreshing.value = false;
@@ -925,7 +925,7 @@
 }
 
 .month-filter {
-  padding: 6rpx 16rpx;
+  padding: 6rpx 14rpx;
   margin-left: 12rpx;
   font-size: 24rpx;
   border-radius: 24rpx;
@@ -1049,7 +1049,7 @@
 
   .status-text {
     font-size: 24rpx;
-    padding: 4rpx 12rpx;
+    padding: 4rpx 10rpx;
     border-radius: 24rpx;
     background-color: #f2f3f5;
     color: #666;

+ 198 - 124
pages/score/pending.uvue

@@ -16,100 +16,6 @@
       </view>
     </view>
 
-    <!-- 工单评分状态筛选 -->
-    <!-- <view class="status-bar">
-      <view class="status-box">
-        <text
-          class="status-txt"
-          :class="{ 'status-sel': statusFilter === '' }"
-          @click="filterByStatus('')"
-        >
-          全部
-        </text>
-        <text
-          class="status-txt"
-          :class="{ 'status-sel': statusFilter === 'to_self' }"
-          @click="filterByStatus('to_self')"
-        >
-          待自评
-        </text>
-        <text
-          class="status-txt"
-          :class="{ 'status-sel': statusFilter === 'to_re' }"
-          @click="filterByStatus('to_re')"
-        >
-          待复评
-        </text>
-        <text
-          class="status-txt"
-          :class="{ 'status-sel': statusFilter === 'to_confirm' }"
-          @click="filterByStatus('to_confirm')"
-        >
-          待确认
-        </text>
-        <text
-          class="status-txt"
-          :class="{ 'status-sel': statusFilter === 'to_final' }"
-          @click="filterByStatus('to_final')"
-        >
-          待终评
-        </text>
-      </view>
-    </view> -->
-
-    <!-- 工分统计 -->
-    <!-- <view class="stats-section">
-      <view class="stats-header">
-        <text class="stats-title">{{ monthTitle }}月度工分</text>
-        <view class="month-filters">
-          <text
-            class="month-filter"
-            :class="{ 'month-filter-sel': selectedMonth === 'prev' }"
-            @click="changeMonth('prev')"
-          >
-            上月
-          </text>
-          <text
-            class="month-filter"
-            :class="{ 'month-filter-sel': selectedMonth === 'current' }"
-            @click="changeMonth('current')"
-          >
-            本月
-          </text>
-          <text
-            class="month-filter"
-            :class="{ 'month-filter-sel': selectedMonth === 'custom' }"
-            @click="showCustomDatePicker"
-          >
-            自定义
-          </text>
-        </view>
-      </view> -->
-
-      <!-- 统计数据 -->
-      <!-- <view class="stats-content">
-        <view class="total-score">
-          <text class="score-value">{{ totalScore }}分</text>
-          <text class="score-label">{{ monthTitle }}总工分</text>
-        </view>
-
-        <view class="score-breakdown">
-          <view class="breakdown-item">
-            <text class="breakdown-label">维保工分</text>
-            <text class="breakdown-value">{{ maintenanceScore }}分</text>
-          </view>
-          <view class="breakdown-item">
-            <text class="breakdown-label">维修工分</text>
-            <text class="breakdown-value">{{ repairScore }}分</text>
-          </view>
-          <view v-if="rank !== null && totalRankingUsers !== null" class="breakdown-item">
-            <text class="breakdown-label">排名</text>
-            <text class="breakdown-value">{{ rank }}/{{ totalRankingUsers }}</text>
-          </view>
-        </view>
-      </view>
-    </view> -->
-
     <!-- 工单评分列表 -->
     <common-list
       :dataList="orderList"
@@ -133,14 +39,13 @@
               <view class="info-label">
                 <text class="text-gray">{{ getWorkOrderTypeInfo(item) }}</text>
               </view>
-              <view class="info-value-row">
+              <!-- <view class="info-value-row">
                 <text v-if="getPropertyValue(item, 'score') !== ''" class="score-text">{{ formatNumber(parseFloat(getPropertyValue(item, 'score'))) }}</text>
-                <!-- <text class="status-text">{{ getOrderStatusText(getPropertyValue(item, 'scoreStatus')) }}</text> -->
-              </view>
-            </view>
+              </view> -->
+			</view>
 			<view class="info-row">
 			  <view class="info-label">
-			    <text class="text-gray">工作结束时间: {{ formatDate(getPropertyValue(item, 'assignTime')) }}</text>
+			    <text class="text-gray">工作结束时间: {{ formatDate(getPropertyValue(item, 'realEndTime')) }}</text>
 			  </view>
 			</view>
           </view>
@@ -182,19 +87,17 @@
       </l-date-time-picker>
     </l-popup>
 
-    <!-- 底部 TabBar -->
-    <!-- <custom-tabbar :current="3" /> -->
   </view>
 </template>
 
 <script setup lang="uts">
-    import { ref, computed, onMounted } from 'vue'
+    import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
     import { listOrderScores, getOrderScoreStatistics, listMyRate } from '@/api/score/index'
     import { getDictDataByType } from '@/api/dict/index'
     import type { SysDictData } from '@/types/dict'
 
     // 数据状态
-    let searchKeyword = ref<string>('')
+    const searchKeyword = ref<string>('')
     const statusFilter = ref<string>('')
     const selectedMonth = ref<string>('current')
     const loading = ref<boolean>(false)
@@ -209,6 +112,16 @@
     const totalRankingUsers = ref<number | null>(null)
     const customDate = ref<string>('')
 
+    // 防止重复请求的标志位
+    const isSearching = ref<boolean>(false)
+    // 添加防重复刷新的标志
+    const isRefreshing = ref<boolean>(false)
+    // 添加刷新时间戳,用于防抖
+    const lastRefreshTime = ref<number>(0)
+
+    // 添加防抖定时器
+    let searchTimer: number | null = null
+
     // 弹窗显示状态
     const showDatePickerPopup = ref<boolean>(false)
     const showDatePicker = ref<boolean>(false)
@@ -504,21 +417,40 @@
 	  showDatePicker.value = false
 	  showDatePickerPopup.value = false
 	  selectedMonth.value = 'custom'
+
+      // 添加防重复调用检查
+      if (loading.value) {
+        return;
+      }
+
 	  getStatistics()
 	}
 
     // 方法
-    function loadData(isRefresh: boolean) {
-      const shouldRefresh = isRefresh
-
-      if (loading.value && !shouldRefresh) {
+    function loadData(isRefresh: boolean, disablePullDown = false) {
+      // 防止重复请求的核心机制 - 参考工单页面的简单有效方式
+      if (loading.value) {
+        // 确保刷新状态最终被重置,防止卡死
+        if (!isRefresh) {
+          refreshing.value = false;
+        }
         return
       }
 
+      const shouldRefresh = isRefresh !== false
+
       loading.value = true
-      if (shouldRefresh) {
+      if (shouldRefresh && !disablePullDown) {
         currentPage.value = 1
         refreshing.value = true
+      } else if (shouldRefresh && disablePullDown) {
+        // 筛选条件变化时,重置页码但不触发下拉刷新
+        currentPage.value = 1
+        // 即使禁用下拉刷新,也要确保刷新状态最终被重置
+        refreshing.value = false
+      } else {
+        // 对于加载更多操作,不需要显示下拉刷新状态
+        refreshing.value = false;
       }
 
       // Convert 'current' and 'prev' values to actual date strings
@@ -567,36 +499,136 @@
         }
 
         hasMore.value = orderList.value.length < responseTotal
-        loading.value = false
-        refreshing.value = false
-      }).catch(() => {
-        loading.value = false
-        refreshing.value = false
+      }).catch((error) => {
+        console.error('获取工单列表失败:', error);
+        // 出错时也需要重置刷新状态
+        if (shouldRefresh) {
+          refreshing.value = false;
+          isRefreshing.value = false;
+        }
+      }).finally(() => {
+        // 无论成功还是失败,都重置所有加载状态
+        loading.value = false;
+        // 确保刷新状态最终被重置
+        if (shouldRefresh) {
+          refreshing.value = false;
+          // 使用setTimeout确保状态彻底重置
+          setTimeout(() => {
+            isRefreshing.value = false;
+          }, 50);
+        }
       })
     }
 
     function handleSearch() {
-      loadData(true)
+      // 添加防重复调用检查
+      if (loading.value) {
+        return;
+      }
+
+      // 添加防抖和防止重复请求
+      if (isSearching.value) {
+        return
+      }
+
+      const timer = searchTimer
+      if (timer != null) {
+        clearTimeout(timer)
+        searchTimer = null
+      }
+
+      searchTimer = setTimeout(() => {
+        isSearching.value = true
+        loadData(true, true); // 添加true参数表示这是筛选条件变化触发的加载,应禁用下拉刷新
+        // 延迟重置标志位,确保请求发送后才允许下一次搜索
+        setTimeout(() => {
+          isSearching.value = false
+        }, 100)
+      }, 300)
     }
 
     function clearSearch() {
+      // 添加防重复调用检查
+      if (loading.value) {
+        return;
+      }
+
+      // 添加防抖和防止重复请求
+      if (isSearching.value) {
+        return
+      }
+
+      const timer = searchTimer
+      if (timer != null) {
+        clearTimeout(timer)
+        searchTimer = null
+      }
+
       searchKeyword.value = ""
-      loadData(true)
+      searchTimer = setTimeout(() => {
+        isSearching.value = true
+        loadData(true, true); // 添加true参数表示这是筛选条件变化触发的加载,应禁用下拉刷新
+        // 延迟重置标志位,确保请求发送后才允许下一次搜索
+        setTimeout(() => {
+          isSearching.value = false
+        }, 100)
+      }, 300)
     }
 
     function filterByStatus(status: string) {
+      // 添加防重复调用检查
+      if (loading.value) {
+        return;
+      }
+
+      // 添加防止重复请求
+      if (isSearching.value) {
+        return
+      }
+
+      const timer = searchTimer
+      if (timer != null) {
+        clearTimeout(timer)
+        searchTimer = null
+      }
+
       statusFilter.value = status
-      loadData(true)
-      getStatistics()
+      searchTimer = setTimeout(() => {
+        isSearching.value = true
+        loadData(true, true); // 添加true参数表示这是筛选条件变化触发的加载,应禁用下拉刷新
+        getStatistics()
+        // 延迟重置标志位,确保请求发送后才允许下一次搜索
+        setTimeout(() => {
+          isSearching.value = false
+        }, 100)
+      }, 300)
     }
 
-    function changeMonth(month: string) {
+	function changeMonth(month: string) {
+	  // 添加防重复调用检查
+      if (loading.value) {
+        return;
+      }
+
+	  // 添加防止重复请求
+	  if (isSearching.value) {
+	    return
+	  }
+
+      const timer = searchTimer
+      if (timer != null) {
+        clearTimeout(timer)
+        searchTimer = null
+      }
+
       selectedMonth.value = month
-      //loadData(true)
-      getStatistics()
-    }
+      searchTimer = setTimeout(() => {
+        getStatistics()
+      }, 300)
+	}
 
     function loadMore() {
+      console.log("loadMore被触发")
       if (!hasMore.value || loading.value) return
 
       currentPage.value++
@@ -604,7 +636,36 @@
     }
 
     function handleRefresh() {
-      loadData(true)
+      console.log("handleRefresh被触发")
+      console.log("loading.value===",loading.value)
+      console.log("isRefreshing.value===",isRefreshing.value)
+
+      // 防抖处理,避免频繁触发
+      const now = Date.now();
+      if (now - lastRefreshTime.value < 1000) {
+        console.log("刷新操作过于频繁,忽略本次触发");
+        refreshing.value = false;
+        return;
+      }
+      lastRefreshTime.value = now;
+
+      // 添加防重复调用检查
+      if (loading.value || isRefreshing.value) {
+        // 如果已经在加载或正在刷新,直接重置刷新状态
+        refreshing.value = false;
+        return;
+      }
+      console.log("loading.value1===",loading.value)
+        console.log("isRefreshing.value1===",isRefreshing.value)
+      // 设置刷新标志
+      isRefreshing.value = true;
+
+      loadData(true); // 使用默认的下拉刷新行为
+
+      // 确保在一定时间后重置刷新标志,防止意外情况
+      setTimeout(() => {
+        isRefreshing.value = false
+      }, 100) // 延迟重置,确保状态完全更新
     }
 
     // 点击列表项
@@ -656,6 +717,20 @@
       getStatistics()
       dictLoaded.value = true
     })
+
+    // 组件销毁时清除定时器
+    onBeforeUnmount(() => {
+      const timer = searchTimer
+      if (timer != null) {
+        clearTimeout(timer)
+        searchTimer = null
+      }
+
+      // 如果组件销毁前还有未完成的刷新操作,确保状态被重置
+      loading.value = false;
+      refreshing.value = false;
+      isRefreshing.value = false;
+    })
 </script>
 
 <style lang="scss">
@@ -720,7 +795,7 @@
     font-size: 28rpx;
   }
 
-  .status-sel {
+  .stauts-sel {
     background-color: #007AFF;
     color: #fff;
   }
@@ -1010,4 +1085,3 @@
   border-color: #c2e7b0;
 }
 </style>
-

+ 12 - 12
pages/worktime/index.uvue

@@ -551,7 +551,7 @@ function handleSearch() {
   if (loading.value) {
     return;
   }
-  
+
   loadData(true, true); // 添加true参数表示这是筛选条件变化触发的加载,应禁用下拉刷新
   getStatistics()
 }
@@ -575,7 +575,7 @@ function filterByOrderType(type: string) {
   if (loading.value) {
     return;
   }
-  
+
   orderTypeFilter.value = type;
   loadData(true, true); // 添加true参数表示这是筛选条件变化触发的加载,应禁用下拉刷新
   getStatistics();
@@ -587,7 +587,7 @@ function changeTimeRange(range: string) {
   if (loading.value) {
     return;
   }
-  
+
   timeRange.value = range;
   loadData(true, true); // 添加true参数表示这是筛选条件变化触发的加载,应禁用下拉刷新
   getStatistics();
@@ -607,7 +607,7 @@ function changeTimeRangeWithCheck(range: string) {
     return;
   }
   changeTimeRange(range);
-} 
+}
 
 function loadMore() {
 	console.log("loadMore被触发")
@@ -621,7 +621,7 @@ function handleRefresh() {
 	console.log("handleRefresh被触发")
 	console.log("loading.value===",loading.value)
 	console.log("isRefreshing.value===",isRefreshing.value)
-	
+
 	// 防抖处理,避免频繁触发
 	const now = Date.now();
 	if (now - lastRefreshTime.value < 1000) {
@@ -630,7 +630,7 @@ function handleRefresh() {
 		return;
 	}
 	lastRefreshTime.value = now;
-	
+
   // 添加防重复调用检查
   if (loading.value || isRefreshing.value) {
     // 如果已经在加载或正在刷新,直接重置刷新状态
@@ -641,9 +641,9 @@ function handleRefresh() {
   	console.log("isRefreshing.value1===",isRefreshing.value)
   // 设置刷新标志
   isRefreshing.value = true;
-  
+
   loadData(true); // 使用默认的下拉刷新行为
-  
+
   // 确保在一定时间后重置刷新标志,防止意外情况
   setTimeout(() => {
     isRefreshing.value = false
@@ -689,12 +689,12 @@ function confirmCustomDate() {
 
   closeDatePicker()
   timeRange.value = 'custom'
-  
+
   // 添加防重复调用检查
   if (loading.value) {
     return;
   }
-  
+
   loadData(true, true); // 添加true参数表示这是筛选条件变化触发的加载,应禁用下拉刷新
   getStatistics()
 }
@@ -895,7 +895,7 @@ onBeforeUnmount(() => {
   flex: 1;
 
   .status-txt {
-    padding: 8px 12px;
+    padding: 8px 10px;
     text-align: center;
     margin-right: 12rpx;
     border-radius: 36rpx;
@@ -936,7 +936,7 @@ onBeforeUnmount(() => {
 }
 
 .time-filter {
-  padding: 6rpx 16rpx;
+  padding: 6rpx 14rpx;
   margin-left: 12rpx;
   font-size: 24rpx;
   border-radius: 24rpx;

+ 2 - 2
utils/request.uts

@@ -13,8 +13,8 @@ export type RequestConfig = {
 };
 
 // 基础 URL
-const BASE_URL = "http://192.168.110.105:8080";
-// const BASE_URL = "http://222.243.138.146:5095";
+// const BASE_URL = "http://192.168.110.105:8080";
+const BASE_URL = "http://222.243.138.146:5095";
 // const BASE_URL = "http://10.170.129.135:8089";
 
 /**