Переглянути джерело

Merge remote-tracking branch 'origin/master'

ouyj 4 місяців тому
батько
коміт
fabb8117d3

+ 26 - 0
api/user/info.uts

@@ -3,6 +3,8 @@
  */
 import { request } from '../../utils/request'
 import type { UserInfo } from '../../types/user'
+import { encryptAES } from '../../utils/crypto'
+import {getStoreIsKey} from '../../utils/storage'
 
 /**
  * 获取用户信息
@@ -25,3 +27,27 @@ export const updateUserInfo = (userInfo: UserInfo): Promise<boolean> => {
     })
 }
 
+/**
+ * 更新密码
+ */
+export const updatePassword = async (password: string, newPassword: string): Promise<any> => {
+	let dataForm = {
+		    newPassword: newPassword,
+		    oldPassword: password
+		};
+		
+	const isKey = getStoreIsKey();
+	if(isKey == "1"){
+		dataForm.newPassword = encryptAES(newPassword);
+		dataForm.oldPassword = encryptAES(password);
+	}
+	return request({
+        url: '/system/user/profile/updatePwd',
+        method: 'PUT',
+		header: {
+		  isToken: false,
+		  repeatSubmit: false
+		},
+        data: dataForm,
+    })
+}

+ 25 - 4
components/custom-tabbar/custom-tabbar.uvue

@@ -15,12 +15,25 @@
     // Props
     type Props = {
         current?: number
+		hide0:number
+		hide1:number
+		hide2:number
+		hide3:number
     }
 
     const props = withDefaults(defineProps<Props>(), {
-        current: 0
+        current: 0,
+		hide0:1,
+		hide1:1,
+		hide2:1,
+		hide3:1
     })
 
+	const hide0 = ref<number>(props.hide0)
+	const hide1 = ref<number>(props.hide1)
+	const hide2 = ref<number>(props.hide2)
+	const hide3 = ref<number>(props.hide3)
+	
     // Tab 列表配置
     type TabItem = {
         pagePath: string
@@ -28,8 +41,8 @@
         iconPath: string
         selectedIconPath: string
     }
-
-    const tabList: TabItem[] = [
+	const tabList: TabItem[] = [];
+    const tabList1: TabItem[] = [
         {
             pagePath: '/pages/index/index',
             text: '首页',
@@ -55,7 +68,15 @@
 		    selectedIconPath: '/static/images/custom-tabbar/66.png'
 		}
     ]
-
+	
+	const hideValues = [props.hide0, props.hide1, props.hide2, props.hide3]
+	for (let i = 0; i < tabList1.length; i++) {
+	    if (i < hideValues.length && hideValues[i] === 1) {
+	        // hide 值为 1 时显示,添加到 tabList
+	        tabList.push(tabList1[i])
+	    }
+	}
+	
     // 当前选中索引
     const currentIndex = ref<number>(props.current)
 

+ 4 - 4
manifest.json

@@ -2,8 +2,8 @@
 	"name": "工效通APP",
 	"appid": "__UNI__1050C07",
 	"description": "工效通任务管理平台",
-	"versionName": "1.2.7",
-	"versionCode": "127",
+	"versionName": "1.2.8",
+	"versionCode": "128",
 	"uni-app-x": {},
 	"quickapp": {},
 	"mp-weixin": {
@@ -53,9 +53,9 @@
 		],
 		"networkSecurityConfig": "@xml/network_security_config",
 		"distribute": {
-			"untrustedCa": "allow",  // 允许不受信任的CA证书
+			"untrustedCa": "allow", // 允许不受信任的CA证书
 			"ssl": {
-			  "verify": false  // 可选:不验证SSL证书
+				"verify": false // 可选:不验证SSL证书
 			},
 			"modules": {
 				"uni-map": {},

+ 7 - 0
pages.json

@@ -175,6 +175,13 @@
 				"navigationBarTitleText": "复启",
 				"navigationStyle": "#custom"
 			}
+		},
+		{
+			"path": "pages/profile/password/index",
+			"style": {
+				"navigationBarTitleText": "修改密码",
+				"navigationStyle": "#custom"
+			}
 		}
 	],
 	"globalStyle": {

+ 15 - 50
pages/index/index.uvue

@@ -121,7 +121,7 @@
         </scroll-view>
 
         <!-- 底部 TabBar -->
-        <custom-tabbar :current="0" />
+        <custom-tabbar :current="0" :hide0="tabbar[0]" :hide1="tabbar[1]" :hide2="tabbar[2]" :hide3="tabbar[3]"/>
     </view>
 </template>
 
@@ -153,6 +153,8 @@
 	// 	});
 	// };
 
+	const tabbar = [1,1,1,1]
+
     // 用户名
     const userName = ref<string>('用户')
 
@@ -706,56 +708,19 @@
 	.db-view{
 		display: flex;
 		flex-direction: row;
-		justify-content: space-between; // 或 space-around
+		justify-content: flex-start; // 或 space-around
+		// justify-content: 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: 216rpx; 
 			// 删除固定宽高 ↓
-			// width: 200rpx;
+			// max-width: 300rpx;
 			// height: 200rpx;
-		
-			flex: 1;                // ✅ 关键:平均分空间
+
+			// flex: 1;                // ✅ 关键:平均分空间
 			display: flex;
 			flex-direction: column; // 垂直排列:图标在上,文字在下
 			justify-content: center;
@@ -763,13 +728,13 @@
 			margin: 0 10rpx;        // 左右间距(替代原来的 margin-left)
 			border-radius: 5px;
 			padding: 30rpx 10rpx;   // 可选:增加内边距使内容不拥挤
-		
+
 			.db-text {
 				margin-top: 16rpx;   // 图标与文字间距
 				font-size: 24rpx;    // 建议用 rpx,10px 太小了
 				color: #333;
 			}
-		
+
 			.db-center-1,
 			.db-center-2,
 			.db-center-3 {
@@ -778,10 +743,10 @@
 				align-items: center;
 				width: 100rpx;
 				height: 100rpx;
-				border-radius: 50rpx; 
+				border-radius: 50rpx;
 				position: relative;
 			}
-		
+
 			.db-center-1 { background-color: #DBEAFE; }
 			.db-center-2 { background-color: #DCFCE7; }
 			.db-center-3 { background-color: #F3E8FF; }
@@ -805,7 +770,7 @@
 		justify-content: center; // 水平居中
 		align-items: center;     // 垂直居中
 		box-sizing: border-box;  // 确保 padding 不影响整体尺寸
-		padding: 0 12rpx; 
+		padding: 0 12rpx;
 		.count {
 			// line-height: 40rpx;
 			font-size: 26rpx;
@@ -814,7 +779,7 @@
 		}
 
 	}
-	
+
 
 	.list-item {
 		margin: 0 30rpx 24rpx 30rpx;

+ 11 - 2
pages/order/index.uvue

@@ -53,7 +53,8 @@
                     <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>
+							<text class="status-tag" :class="getStatusClass(item)" >{{ getWorkOrderStatus(item) }}</text>
+							<!-- <view class="status-view" :class="getStatusClass(item)"><text class="status-tag" :class="getStatusClass(item)" >{{ getWorkOrderStatus(item) }}</text></view> -->
                         </view>
 						<view class="info-row">
 							<view class="info-label">
@@ -122,7 +123,7 @@
                 </view>
             </template>
         </common-list>
-		<custom-tabbar :current="1" />
+		<custom-tabbar :current="1" :hide0="tabbar[0]" :hide1="tabbar[1]" :hide2="tabbar[2]" :hide3="tabbar[3]"/>
     </view>
 </template>
 
@@ -147,6 +148,8 @@ import {checkPermi, getUserInfo} from '../../utils/storage'
     const total = ref<number>(0)
 	let currentStatus = ref<string>('') // 添加状态管理
     const statusDictList = ref<SysDictData[]>([]) // 工单状态字典列表
+	
+	const tabbar = [1,1,1,1]
 
 	// 添加防重复请求的标志位(参考score/pending.uvue的实现)
 	const isSearching = ref<boolean>(false)
@@ -842,6 +845,7 @@ const statusConfig: StatusItem[] = [
   align-items: flex-start;
   margin-bottom: 16rpx;
   justify-content: space-between; /* 主轴两端对齐 */
+  min-height: 55rpx;
 
   .item-title {
     font-size: 30rpx;
@@ -880,6 +884,10 @@ const statusConfig: StatusItem[] = [
   color: #666;
 }
 
+.status-view {
+	border: 1rpx solid;
+	border-radius: 20rpx;
+}
 .status-tag {
 	padding: 8rpx 20rpx;
 	border-radius: 20rpx;
@@ -888,6 +896,7 @@ const statusConfig: StatusItem[] = [
 	// margin-left: 50rpx;
 	// justify-content: flex-end;
 	border: 1rpx solid;
+	
 }
 
 /* 待接单 */

+ 1 - 0
pages/order/overdue.uvue

@@ -549,6 +549,7 @@ import {checkPermi} from '../../utils/storage'
   align-items: flex-start;
   margin-bottom: 16rpx;
   justify-content: space-between;
+  min-height: 55rpx;
 
   .item-title {
     font-size: 30rpx;

+ 1 - 0
pages/order/pendingOrder.uvue

@@ -680,6 +680,7 @@ import {checkPermi, getUserInfo} from '../../utils/storage'
 	  align-items: flex-start;
 	  margin-bottom: 16rpx;
 	  justify-content: space-between;
+	  min-height: 55rpx;
 
 	  .item-title {
 		font-size: 30rpx;

+ 136 - 12
pages/profile/index.uvue

@@ -31,15 +31,27 @@
             <view class="contact-item">
                 <text class="contact-text">{{userRole}}</text>
             </view>
-
+			<view class="menu-section">
+				<view class="menu-item" @click="handlePassword()">
+					<image class="menu-icon" src="/static/images/profile/7.png" mode="aspectFit"></image>
+					<text class="menu-title">修改密码</text>
+					<text class="menu-arrow">›</text>
+				</view>
+				
+				<view class="menu-item" @longpress="handleVersionClick()">
+					<image class="menu-icon" src="/static/images/profile/5.png" mode="aspectFit"></image>
+					<text class="menu-title">{{version}}</text>
+					<text class="menu-arrow">›</text>
+				</view>
+			</view> 
             <!-- 功能菜单 -->
-            <view class="menu-section">
+            <!-- <view class="menu-section">
                 <view v-for="(item, index) in menuList" :key="index" class="menu-item" @click="handleMenuClick(item)">
-                    <image class="menu-icon" :src="item.icon" mode="aspectFit"></image>
-                    <text class="menu-title">{{ item.title }}</text>
+                    <image class="menu-icon" src="/static/images/profile/7.png" mode="aspectFit"></image>
+                    <text class="menu-title">修改密码</text>
                     <text class="menu-arrow">›</text>
                 </view>
-            </view>
+            </view> -->
 
             <!-- 注销账号 -->
             <view class="logout-wrapper">
@@ -56,6 +68,7 @@
     import { useAuth } from '../../composables/useAuth'
 	import { encryptAES, decryptAES } from '../../utils/crypto'
 	import { getIsKey } from '../../api/auth/login'
+	import { getBaseUrl } from '../../utils/request'
 	
     // @ts-ignore
     import manifest from '@/manifest.json'
@@ -87,22 +100,22 @@
     const menuList = ref<MenuItem[]>([
         {
             id: 1,
+            title: '修改密码',
+            icon: '/static/images/profile/7.png',
+            path: '/pages/profile/password/index'
+        },
+		{
+            id: 2,
             title: '关于版本',
             icon: '/static/images/profile/5.png',
             action: 'version'
         },
         {
-            id: 2,
+            id: 3,
             title: '关于我们',
             icon: '/static/images/profile/6.png',
             path: '/pages/profile/about/index'
         },
-        {
-            id: 3,
-            title: '隐私条款',
-            icon: '/static/images/profile/7.png',
-            path: '/pages/profile/privacy/index'
-        },
         {
             id: 4,
             title: '通用设置',
@@ -119,6 +132,18 @@
         })
     }
 
+	const handlePassword = (): void =>{
+		uni.navigateTo({
+		    url:"/pages/profile/password/index",
+		    fail: (err: any) => {
+		        uni.showToast({
+		            title: '功能开发中',
+		            icon: 'none'
+		        })
+		    }
+		})
+	}
+
     // 菜单点击
     const handleMenuClick = (item: MenuItem): void => {
         if (item.action == 'version') {
@@ -171,6 +196,105 @@
         })
     }
 
+	// 安装APK的单独函数
+	const installApkFile = (filePath: string): void => {
+	  uni.installApk({
+		filePath: filePath,
+		success: () => {
+		  console.log('安装成功');
+		  uni.showToast({
+			title: '安装成功',
+			icon: 'success'
+		  });
+		},
+		fail: (error) => {
+		  console.error('安装失败:', error);
+		  uni.showToast({
+			title: '安装失败',
+			icon: 'none'
+		  });
+		},
+		complete: (res) => {
+		  console.log('安装完成:', res);
+		}
+	  });
+	}
+	
+	
+	
+	const installApkWithProgress = (): void => {		
+	    // #ifdef APP-ANDROID
+			// 显示下载进度
+			uni.showLoading({
+				title: '下载中...',
+				mask: true
+			});
+			let donwloadUrl = '';
+			donwloadUrl = getBaseUrl() + '/prod-api/profile/app/gxt-release.apk'
+		
+			// 下载APK
+			const downloadTask = uni.downloadFile({
+				url: donwloadUrl,
+				filePath: `${uni.env.USER_DATA_PATH}/${Date.now()}_test.apk`, // 使用时间戳防止重名
+				success: (downloadRes) => {
+				uni.hideLoading();
+				if (downloadRes.statusCode == 200) {
+				// 确认安装
+					uni.showModal({
+					  title: '安装提示',
+					  content: '下载完成,是否立即安装?',
+					  success: (modalRes) => {
+						if (modalRes.confirm) {
+						  installApkFile(downloadRes.tempFilePath);
+						}
+					  }
+					});
+				} else {
+					uni.showToast({
+					  title: '下载失败',
+					  icon: 'error'
+					});
+				  }
+				},
+				fail: (error) => {
+				  uni.hideLoading();
+				  uni.showToast({
+					title: '下载失败',
+					icon: 'none'
+				  });
+				  console.error('下载失败:', error);
+				}
+			});
+	
+			// 监听下载进度
+			downloadTask.onProgressUpdate((res) => {
+				console.log('下载进度:', res.progress + '%');
+				// 如果需要,可以更新UI显示进度
+				uni.showLoading({
+					title: `下载中 ${res.progress}%`,
+					mask: true
+				});
+			});
+		// #endif
+		// #ifdef APP-HARMONY
+			uni.showToast({
+				title: '请登录PC端,扫描二维码下载并安装',
+				icon: 'none'
+			});
+		// #endif
+		// #ifdef APP-IOS
+			uni.showToast({
+				title: '请登录PC端,扫描二维码下载并安装',
+				icon: 'none'
+			});
+		// #endif
+	}
+	
+	// 菜单点击
+	const handleVersionClick = (): void => {
+	    installApkWithProgress();
+	}
+	
     // 初始化
     onMounted(() => {
         const userInfo = getUserInfo()

+ 258 - 0
pages/profile/password/index.uvue

@@ -0,0 +1,258 @@
+<template>
+    <view class="form-page">
+        <!-- 可滚动内容区域 -->
+        <scroll-view class="form-scroll" scroll-y="true">
+            <view class="form-container">
+               
+                <form-item label="密码" :required="formConfig.password.required" :error="formConfig.password.error">
+                    <l-input 
+						:type="showPassword ? 'text' : 'password'"
+                        class="form-input" 
+                        v-model="formData.password" 
+                        placeholder="请输入密码" 
+                        :maxlength="100" 
+                        :bordered="false"
+                         placeholderStyle="font-size: 14px;"
+                    />
+					<image class="eye-icon" :src="showPassword ? '/static/images/login/4.png' : '/static/images/login/3.png'" mode="aspectFit" @click="handleTogglePassword"></image>
+                </form-item>
+				<form-item label="新密码" :required="formConfig.newPassword.required" :error="formConfig.newPassword.error">
+                    <l-input 
+						:type="showNewPassword ? 'text' : 'password'"
+                        class="form-input" 
+                        v-model="formData.newPassword" 
+                        placeholder="请输入新密码" 
+                        :maxlength="100" 
+                        :bordered="false"
+                         placeholderStyle="font-size: 14px;"
+                    />
+					<image class="eye-icon" :src="showNewPassword ? '/static/images/login/4.png' : '/static/images/login/3.png'" mode="aspectFit" @click="handleToggleNewPassword"></image>
+                </form-item>
+				<form-item label="确认密码" :required="formConfig.confirmPassword.required" :error="formConfig.confirmPassword.error">
+				    <l-input 
+						:type="showConfirmPassword ? 'text' : 'password'"
+				        class="form-input" 
+				        v-model="formData.confirmPassword" 
+				        placeholder="请输入密码" 
+				        :maxlength="100" 
+				        :bordered="false"
+				         placeholderStyle="font-size: 14px;"
+				    />
+					<image class="eye-icon" :src="showConfirmPassword ? '/static/images/login/4.png' : '/static/images/login/3.png'" mode="aspectFit" @click="handleToggleConfirmPassword"></image>
+				</form-item>
+               
+            </view> 
+        </scroll-view>
+
+        <!-- 固定底部按钮 -->
+        <view class="footer">
+            <button class="submit-btn" :disabled="submitting" @click="handleSubmit">
+                <text class="submit-btn-text">{{ submitting ? "提交中..." : "提交" }}</text>
+            </button>
+        </view>
+    </view>
+</template>
+
+<script setup lang="uts">
+    import { ref } from 'vue'
+	import { updatePassword } from '../../../api/user/info'
+
+    const showPassword = ref<boolean>(false)
+	const showNewPassword = ref<boolean>(false)
+	const showConfirmPassword = ref<boolean>(false)
+	
+    // 表单 label 宽度统一配置
+    const labelWidth = '140rpx'
+	
+	// 切换密码显示/隐藏
+	const handleTogglePassword = (): void => {
+	    showPassword.value = !showPassword.value
+	}
+	
+	// 切换密码显示/隐藏
+	const handleToggleNewPassword = (): void => {
+	    showNewPassword.value = !showNewPassword.value
+	}
+	
+	// 切换密码显示/隐藏
+	const handleToggleConfirmPassword = (): void => {
+	    showConfirmPassword.value = !showConfirmPassword.value
+	}
+
+    // 表单数据类型
+    type FormDataType = {
+        password: string
+        newPassword: string
+        confirmPassword: string
+    }
+
+    // 表单数据
+    const formData = ref<FormDataType>({
+        password: '',
+        newPassword: '',
+        confirmPassword: ''
+    })
+
+    const submitting = ref<boolean>(false)
+
+    // 表单字段配置类型
+    type FormFieldConfig = {
+        required: boolean
+        error: string
+        errorMsg: string
+		errorValid: string
+    }
+
+    // 表单字段配置
+    type FormFieldsConfig = {
+        password: FormFieldConfig
+        newPassword: FormFieldConfig
+        confirmPassword: FormFieldConfig
+    }
+
+    // 表单配置
+    const formConfig = ref<FormFieldsConfig>({
+        password: {
+            required: true,
+            error: '',
+            errorMsg: '请输入密码',
+			errorValid: ''
+        },
+        newPassword: {
+            required: true,
+            error: '',
+            errorMsg: '请输入新密码',
+			errorValid: "2次密码不一样"
+        },
+        confirmPassword: {
+            required: true,
+            error: '',
+            errorMsg: '请输入确认密码',
+			errorValid: ''
+			
+        }
+    })
+
+    // 清空所有错误信息
+    const clearErrors = (): void => {
+        formConfig.value.password.error = ''
+        formConfig.value.newPassword.error = ''
+        formConfig.value.confirmPassword.error = ''
+    }
+
+    // 表单验证
+    const validateForm = (): boolean => {
+        // 清空之前的错误信息
+        clearErrors()
+
+        let isValid = true
+
+        if (formConfig.value.password.required && formData.value.password.length == 0) {
+            formConfig.value.password.error = formConfig.value.password.errorMsg
+            isValid = false
+        }
+		
+        if (formConfig.value.newPassword.required && formData.value.newPassword.length == 0) {
+            formConfig.value.newPassword.error = formConfig.value.newPassword.errorMsg
+            isValid = false
+        }
+		
+        if (formConfig.value.confirmPassword.required && formData.value.confirmPassword.length == 0) {
+            formConfig.value.confirmPassword.error = formConfig.value.confirmPassword.errorMsg
+            isValid = false
+        }
+		
+		if (formData.value.confirmPassword != formData.value.newPassword) {
+		    formConfig.value.newPassword.error = formConfig.value.newPassword.errorValid
+		    isValid = false
+		}
+        return isValid
+    }
+
+    // 提交表单
+    const handleSubmit = async (): Promise<void> => {
+        if (!validateForm()) {
+            return
+        }
+
+        try {
+            submitting.value = true
+
+            // 打印表单数据
+            console.log('表单数据:', formData.value)
+
+            // 模拟提交
+            await updatePassword(formData.value.password, formData.value.newPassword);
+
+            uni.showToast({
+                title: '提交成功',
+                icon: 'success'
+            })
+			setTimeout(() => {
+				uni.navigateBack()
+			}, 800)
+        } catch (e: any) {
+            uni.showToast({
+                title: e.message ?? '提交失败',
+                icon: 'none'
+            })
+        } finally {
+            submitting.value = false
+        }
+    }
+</script>
+
+<style lang="scss">
+    @import "@/static/css/form.scss";
+
+    .form-page {
+        flex: 1;
+        background-color: #e8f0f9;
+        flex-direction: column;
+
+        .form-scroll {
+            flex: 1;
+            padding: 30rpx;
+            padding-bottom: 20rpx;
+
+            .form-container {
+                background-color: #ffffff;
+                border-radius: 16rpx;
+                padding: 30rpx;
+            }
+        }
+
+        .footer {
+            padding: 20rpx 30rpx;
+            padding-bottom: 40rpx;
+
+            .submit-btn {
+                width: 100%;
+                height: 88rpx;
+                background-color: #007aff;
+                border-radius: 12rpx;
+                color: #ffffff !important;
+                
+                &:disabled {
+                    background-color: #cccccc;
+                }
+
+                .submit-btn-text {
+                    font-size: 32rpx;
+                    color: #ffffff !important;
+                    font-weight: bold;
+                }
+            }
+        }
+    }
+	
+	.eye-icon {
+	    position: absolute;
+	    right: 30rpx;
+	    top: 50%;
+	    transform: translateY(-50%);
+	    width: 40rpx;
+	    height: 40rpx;
+	}
+	
+</style>

+ 42 - 28
pages/score/index.uvue

@@ -69,27 +69,33 @@
       <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 class="month-tab">
+			  <text
+				class="month-filter"
+				:class="{ 'month-filter-sel': selectedMonth === 'prev' }"
+				@click="changeMonth('prev')"
+			  >
+				上月
+			  </text>
+			</view>
+			<view class="month-tab">
+			  <text
+				class="month-filter"
+				:class="{ 'month-filter-sel': selectedMonth === 'current' }"
+				@click="changeMonth('current')"
+			  >
+				本月
+			  </text>
+		  </view>
+		  <view class="month-tab">
+			  <text
+				class="month-filter"
+				:class="{ 'month-filter-sel': selectedMonth === 'custom' }"
+				@click="showCustomDatePicker"
+			  >
+				自定义
+			  </text>
+		  </view>
         </view>
       </view>
 
@@ -147,7 +153,7 @@
 			</view>
 			<view class="info-row">
 			  <view class="info-label">
-			    <text class="text-gray">工作结束时间: {{ formatDate(getPropertyValue(item, 'realEndTime')) }}</text>
+			    <text class="text-gray">工作结束时间: {{ getPropertyValue(item, 'realEndTime') }}</text>
 			  </view>
 			</view>
           </view>
@@ -190,7 +196,7 @@
     </l-popup>
 
     <!-- 底部 TabBar -->
-    <custom-tabbar :current="3" />
+    <custom-tabbar :current="3" :hide0="tabbar[0]" :hide1="tabbar[1]" :hide2="tabbar[2]" :hide3="tabbar[3]"/>
   </view>
 </template>
 
@@ -223,6 +229,8 @@
     // 添加刷新时间戳,用于防抖
     const lastRefreshTime = ref<number>(0)
 
+	const tabbar = [1,1,1,1]
+
     // 添加防抖定时器
     let searchTimer: number | null = null
 
@@ -929,16 +937,20 @@
 .month-filters {
   flex-direction: row;
   justify-content: flex-end;
+  display: flex;
+}
+
+.month-tab {
+	white-space: nowrap;
+	margin: 0 8rpx;
+	border-radius: 24rpx;
+	background-color: #f2f3f5;
 }
 
 .month-filter {
-  padding: 6rpx 14rpx;
-  margin-left: 12rpx;
+  padding: 6rpx 12rpx;
   font-size: 24rpx;
-  border-radius: 24rpx;
-  background-color: #f2f3f5;
   color: #666;
-  white-space: nowrap;
 }
 
 .month-filter-sel {
@@ -1076,6 +1088,7 @@
   padding: 40rpx;
   padding-bottom: 40rpx;
   margin-bottom: 150rpx; /* 提高弹窗,避免被底部导航栏遮挡 */
+  min-height: 600rpx;
 }
 
 .popup-header {
@@ -1093,6 +1106,7 @@
 .popup-actions {
   display: flex;
   flex-direction: row;
+  white-space: nowrap;
 }
 
 .cancel-btn {

+ 27 - 14
pages/worktime/index.uvue

@@ -48,13 +48,16 @@
       <view class="stats-header">
         <text class="stats-title">{{ timeRangeTitle }}工时统计</text>
         <view class="time-filters">
-          <text
-            class="time-filter"
-            :class="{ 'time-filter-sel': timeRange === 'week' }"
-            @click="changeTimeRange('week')"
-          >
-            本周
-          </text>
+			<view class="time-tab">
+			  <text
+				class="time-filter"
+				:class="{ 'time-filter-sel': timeRange === 'week' }"
+				@click="changeTimeRange('week')"
+			  >
+				本周
+			  </text>
+		  </view>
+		  <view class="time-tab">
           <text
             class="time-filter"
             :class="{ 'time-filter-sel': timeRange === 'month' }"
@@ -62,6 +65,8 @@
           >
             本月
           </text>
+		  </view>
+		  <view class="time-tab">
           <text
             class="time-filter"
             :class="{ 'time-filter-sel': timeRange === 'custom' }"
@@ -69,6 +74,7 @@
           >
             自定义
           </text>
+		  </view>
         </view>
       </view>
 
@@ -188,7 +194,7 @@
     </l-popup>
 
     <!-- 底部 TabBar -->
-    <custom-tabbar :current="2" />
+    <custom-tabbar :current="2" :hide0="tabbar[0]" :hide1="tabbar[1]" :hide2="tabbar[2]" :hide3="tabbar[3]"/>
   </view>
 </template>
 
@@ -226,6 +232,8 @@ const showEndDatePicker = ref<boolean>(false)
 const startDate = ref<string>('')
 const endDate = ref<string>('')
 
+const tabbar = [1,1,1,1]
+
 // 工单状态字典列表
 const statusDictList = ref<SysDictData[]>([])
 // 维保类型字典列表
@@ -895,7 +903,7 @@ onBeforeUnmount(() => {
   flex: 1;
 
   .status-txt {
-    padding: 8px 10px;
+    padding: 8px 14px;
     text-align: center;
     margin-right: 12rpx;
     border-radius: 36rpx;
@@ -935,14 +943,18 @@ onBeforeUnmount(() => {
   justify-content: flex-end;
 }
 
-.time-filter {
-  padding: 6rpx 14rpx;
-  margin-left: 12rpx;
-  font-size: 24rpx;
+.time-tab {
+  white-space: nowrap;
+  margin: 0 8rpx;
   border-radius: 24rpx;
   background-color: #f2f3f5;
+}
+
+.time-filter {
+  padding: 6rpx 12rpx;
+  // margin-left: 12rpx;
+  font-size: 24rpx;
   color: #666;
-  white-space: nowrap;
 }
 
 .time-filter-sel {
@@ -1141,6 +1153,7 @@ onBeforeUnmount(() => {
 .popup-actions {
   display: flex;
   flex-direction: row;
+  white-space: nowrap;
 }
 
 .cancel-btn {