This commit is contained in:
ylj20011123 2025-08-19 18:59:39 +08:00
parent a6692879e0
commit f0ab72c78b
2 changed files with 387 additions and 108 deletions

View File

@ -32,16 +32,17 @@
<view class="dateSelector"> <view class="dateSelector">
<view class="dateBox"> <view class="dateBox">
<view class="centerDateBox"> <view class="centerDateBox">
<image class="arrowIcon" src="https://eshangtech.com/cyy_DIB/leftArrowIcon.png" <view class="arrowBtn" @tap="handleChangeDate(2)">
@click="handleChangeDate(2)" /> <image class="arrowIcon" src="https://eshangtech.com/cyy_DIB/leftArrowIcon.png" />
</view>
<view class="center"> <view class="center">
<text class="date-text">{{ selectDate ? $util.cutDate(new Date(selectDate), 'YYYY-MM') : <text class="date-text">{{ selectDate ? $util.cutDate(new Date(selectDate), 'YYYY-MM') :
"" ""
}}</text> }}</text>
<!-- <text class="date-icon">📅</text> -->
</view> </view>
<image class="arrowIcon" src="https://eshangtech.com/cyy_DIB/rightArrowIcon.png" <view class="arrowBtn" @tap="handleChangeDate(1)">
@click="handleChangeDate(1)" /> <image class="arrowIcon" src="https://eshangtech.com/cyy_DIB/rightArrowIcon.png" />
</view>
</view> </view>
</view> </view>
@ -172,10 +173,12 @@
</view> </view>
</view> </view>
<!-- 空数据状态 --> <!-- 空数据状态 - 只有在已加载完成且真的没有数据时才显示 -->
<view class="emptyState" v-if="attendanceStatisticsData.length === 0 && !loading"> <view class="emptyState" v-if="attendanceStatisticsData.length === 0 && !loading && hasLoaded">
<view class="emptyIcon">📊</view>
<text class="emptyText">暂无考勤数据</text> <text class="emptyText">暂无考勤数据</text>
<text class="emptyDesc">请选择其他时间或服务区查看</text> <text class="emptyDesc">请选择其他时间或服务区查看</text>
<!-- <button class="retryBtn" @tap="retryLoad" type="primary" size="mini">重新加载</button> -->
</view> </view>
</view> </view>
@ -200,7 +203,9 @@ export default {
attendanceStatisticsData: [], attendanceStatisticsData: [],
isFirst: true, isFirst: true,
seatInfo: {}, seatInfo: {},
loading: false loading: false,
hasLoaded: false, //
retryCount: 0
} }
}, },
onLoad() { onLoad() {
@ -224,6 +229,19 @@ export default {
return name ? name.charAt(0).toUpperCase() : '?' return name ? name.charAt(0).toUpperCase() : '?'
}, },
//
retryLoad() {
if (this.retryCount < 3) {
this.retryCount++
this.handleGetData(this.serviceInfo.SERVERPART_NAME)
} else {
uni.showToast({
title: '多次重试失败,请检查网络连接',
icon: 'none'
})
}
},
// //
formatDuration(minutes) { formatDuration(minutes) {
if (!minutes || minutes <= 0) return '' if (!minutes || minutes <= 0) return ''
@ -286,7 +304,11 @@ export default {
"content-type": "application/x-www-form-urlencoded", "content-type": "application/x-www-form-urlencoded",
}, },
success(res) { success(res) {
resolve(res.data.data) if (res.data && res.data.data) {
resolve(res.data.data)
} else {
reject(new Error('数据格式错误'))
}
}, },
fail(err) { fail(err) {
reject(err) reject(err)
@ -303,7 +325,7 @@ export default {
}) })
} }
this.attendanceStatisticsData = list this.attendanceStatisticsData = list
console.log('最终数据:', this.attendanceStatisticsData) this.hasLoaded = true //
} catch (error) { } catch (error) {
console.error('获取考勤数据失败:', error) console.error('获取考勤数据失败:', error)
uni.showToast({ uni.showToast({
@ -359,7 +381,7 @@ export default {
}, },
// //
async handleChangeDate(type) { async handleChangeDate(type) {
this.attendanceStatisticsData = [] //
// type 1 2 // type 1 2
// iOS 2025-08-15 2025/08/15 // iOS 2025-08-15 2025/08/15
const cur = new Date((this.selectDate || '').replace(/-/g, '/')); const cur = new Date((this.selectDate || '').replace(/-/g, '/'));
@ -376,6 +398,7 @@ export default {
const d = String(last.getDate()).padStart(2, '0'); const d = String(last.getDate()).padStart(2, '0');
this.selectDate = `${y}-${m}-${d}`; this.selectDate = `${y}-${m}-${d}`;
this.retryCount = 0 //
await this.handleGetData(this.serviceInfo.SERVERPART_NAME) await this.handleGetData(this.serviceInfo.SERVERPART_NAME)
}, },
} }
@ -509,9 +532,19 @@ export default {
// border: 2rpx solid #27B35F; // border: 2rpx solid #27B35F;
// background: rgba(255, 255, 255, .15); // background: rgba(255, 255, 255, .15);
.arrowIcon { .arrowBtn {
width: 40rpx; display: flex;
height: 40rpx; align-items: center;
justify-content: center;
width: 60rpx;
height: 60rpx;
border-radius: 50%;
// background: rgba(39, 178, 95, 0.1);
.arrowIcon {
width: 40rpx;
height: 40rpx;
}
} }
.center { .center {
@ -740,7 +773,6 @@ export default {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex-wrap: wrap; flex-wrap: wrap;
// gap: 24rpx 16rpx;
.statItem { .statItem {
display: flex; display: flex;
@ -870,26 +902,45 @@ export default {
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 120rpx 40rpx; padding: 80rpx 40rpx;
text-align: center;
background: #fff;
border-radius: 16rpx;
margin-bottom: 32rpx;
box-shadow: @shadow;
.emptyIcon { .emptyIcon {
width: 120rpx; font-size: 80rpx;
height: 120rpx; margin-bottom: 24rpx;
margin-bottom: 32rpx;
opacity: 0.6; opacity: 0.6;
} }
.emptyText { .emptyText {
font-size: 32rpx; font-size: 32rpx;
color: @muted; color: #2c3e50;
font-weight: 600;
margin-bottom: 16rpx; margin-bottom: 16rpx;
} }
.emptyDesc { .emptyDesc {
font-size: 24rpx; font-size: 24rpx;
color: #bbb; color: #666;
text-align: center;
line-height: 1.5; line-height: 1.5;
margin-bottom: 32rpx;
}
.retryBtn {
background: @primary;
color: #fff;
border: none;
border-radius: 24rpx;
padding: 16rpx 32rpx;
font-size: 24rpx;
font-weight: 600;
&::after {
border: none;
}
} }
} }
} }

View File

@ -27,16 +27,17 @@
<view class="selectorRow"> <view class="selectorRow">
<view class="dateBox"> <view class="dateBox">
<view class="centerDateBox"> <view class="centerDateBox">
<image class="arrowIcon" src="https://eshangtech.com/cyy_DIB/leftArrowIcon.png" <view class="arrowBtn" @tap="handleChangeDate(2)">
@click="handleChangeDate(2)" /> <image class="arrowIcon" src="https://eshangtech.com/cyy_DIB/leftArrowIcon.png" />
</view>
<view class="center"> <view class="center">
<text class="date-text">{{ selectDate ? $util.cutDate(new Date(selectDate), 'YYYY-MM') : <text class="date-text">{{ selectDate ? $util.cutDate(new Date(selectDate), 'YYYY-MM') :
"" ""
}}</text> }}</text>
<!-- <text class="date-icon">📅</text> --> </view>
<view class="arrowBtn" @tap="handleChangeDate(1)">
<image class="arrowIcon" src="https://eshangtech.com/cyy_DIB/rightArrowIcon.png" />
</view> </view>
<image class="arrowIcon" src="https://eshangtech.com/cyy_DIB/rightArrowIcon.png"
@click="handleChangeDate(1)" />
</view> </view>
</view> </view>
@ -61,14 +62,41 @@
<view v-if="selectedEmployee" class="employeeDetail"> <view v-if="selectedEmployee" class="employeeDetail">
<view class="employeeCard"> <view class="employeeCard">
<view class="employeeInfo"> <view class="employeeInfo">
<view class="employeeName">{{ selectedEmployee.userName }}</view> <view class="avatar">{{ getFirstChar(selectedEmployee.userName) }}</view>
<view class="employeeJob">{{ selectedEmployee.psnJob }}</view> <view class="basicInfo">
<image class="phoneIcon" src="https://eshangtech.com/cyy_DIB/phoneIcon.png" /> <view class="nameRow">
<view class="employeePhone">{{ selectedEmployee.phone }}</view> <image class="personIcon" src="https://eshangtech.com/cyy_DIB/personIcon.png"></image>
<view class="employeeName">{{ selectedEmployee.userName || '-' }}</view>
</view>
<view class="phoneRow">
<image class="phoneIcon" src="https://eshangtech.com/cyy_DIB/phoneLabelIcon.png">
</image>
<view class="employeePhone">{{ selectedEmployee.phone || '-' }}</view>
</view>
</view>
<view class="jobInfo">
<view class="employeeJob" v-if="selectedEmployee.psnJob">{{ selectedEmployee.psnJob }}
</view>
</view>
</view> </view>
</view> </view>
</view> </view>
<!-- 空状态提示 - 只有在已加载完成且真的没有数据时才显示 -->
<view v-if="!loading && hasLoaded && userList.length === 0" class="emptyState">
<view class="emptyIcon">📋</view>
<view class="emptyText">暂无员工数据</view>
<view class="emptyDesc">请检查服务区设置或联系管理员</view>
<button class="retryBtn" @tap="retryLoad" type="primary" size="mini">重新加载</button>
</view>
<!-- 员工无排班数据提示 - 只有在已加载完成且真的没有数据时才显示 -->
<view v-if="!loading && hasLoaded && userList.length > 0 && !selectedEmployee" class="emptySchedule">
<view class="emptyIcon">📅</view>
<view class="emptyText">暂无排班数据</view>
<view class="emptyDesc">该员工在当前月份暂无排班安排</view>
</view>
<!-- 日历格式排班表 --> <!-- 日历格式排班表 -->
<view v-if="selectedEmployee" class="calendarRoster"> <view v-if="selectedEmployee" class="calendarRoster">
<view class="weekHeader"> <view class="weekHeader">
@ -126,7 +154,10 @@ export default {
selectUser: "",// selectUser: "",//
isFirst: true, isFirst: true,
monthDays: [], monthDays: [],
firstDayOfWeek: "" firstDayOfWeek: "",
loading: false,
retryCount: 0,
hasLoaded: false, //
} }
}, },
computed: { computed: {
@ -171,14 +202,28 @@ export default {
} }
}, },
methods: { methods: {
//
getFirstChar(name) {
return name ? name.charAt(0).toUpperCase() : '?'
},
//
retryLoad() {
if (this.retryCount < 3) {
this.retryCount++
this.loadRosterData(this.serviceInfo.SERVERPART_NAME)
} else {
uni.showToast({
title: '多次重试失败,请检查网络连接',
icon: 'none'
})
}
},
handleGetNewMonthData() { handleGetNewMonthData() {
const year = this.currentYear const year = this.currentYear
const month = this.currentMonth const month = this.currentMonth
console.log('yearyearyear', year);
console.log('monthmonthmonthmonth', month);
const daysInMonth = new Date(year, month + 1, 0).getDate() const daysInMonth = new Date(year, month + 1, 0).getDate()
const today = new Date() const today = new Date()
const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}` const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`
@ -233,8 +278,10 @@ export default {
this.currentMonth = last.getMonth() // 使 this.currentMonth = last.getMonth() // 使
this.handleGetNewMonthData() this.handleGetNewMonthData()
this.retryCount = 0 //
this.handleGetCurrentUserScheduleInfo() // selectedEmployee
await this.handleGetCurrentUserScheduleInfo()
}, },
// //
handleBack() { handleBack() {
@ -242,75 +289,149 @@ export default {
}, },
// //
handleEmployeeChange(e) { handleEmployeeChange(e) {
console.log('eee', e); const selectedIndex = Number(e.detail.value)
if (selectedIndex >= 0 && selectedIndex < this.userList.length) {
this.selectedEmployeeIndex = Number(e.detail.value) this.selectedEmployeeIndex = selectedIndex
this.selectUser = this.userList && this.userList.length > 0 ? this.userList[this.selectedEmployeeIndex] : "" this.selectUser = this.userList[selectedIndex]
//
this.handleGetCurrentUserScheduleInfo() this.handleGetCurrentUserScheduleInfo()
}
}, },
// //
async loadRosterData(SERVERPART_NAME) { async loadRosterData(SERVERPART_NAME) {
// if (!SERVERPART_NAME) {
uni.showToast({
title: '请先选择服务区',
icon: 'none'
})
return
}
this.loading = true
let req = { let req = {
bsessionKey: "0B30475A94674D608022885F7763959B", bsessionKey: "0B30475A94674D608022885F7763959B",
workTime: new Date(this.selectDate).getTime(), workTime: new Date(this.selectDate).getTime(),
saName: SERVERPART_NAME || "",// saName: SERVERPART_NAME,
phone: "",// phone: "",
} }
uni.showLoading({ uni.showLoading({
title: "加载中..." title: "加载中..."
}) })
const data = await new Promise((resolve, reject) => { try {
uni.request({ const data = await new Promise((resolve, reject) => {
url: "https://fwqznxj.yciccloud.com:9081/ynjt/pushManage/queryUserSchedule", uni.request({
method: "POST", url: "https://fwqznxj.yciccloud.com:9081/ynjt/pushManage/queryUserSchedule",
data: req, method: "POST",
header: { data: req,
"content-type": "application/x-www-form-urlencoded", header: {
}, "content-type": "application/x-www-form-urlencoded",
success(res) { },
resolve(res.data.data) success(res) {
}, if (res.data && res.data.data) {
resolve(res.data.data)
} else {
reject(new Error('数据格式错误'))
}
},
fail(err) {
reject(err)
}
});
}); });
});
uni.hideLoading()
console.log('人员列表', data); const userList = Array.isArray(data) ? data : []
this.userList = userList
this.selectedEmployeeIndex = 0
this.selectUser = userList.length > 0 ? userList[0] : null
this.userList = data if (userList.length > 0) {
this.selectedEmployeeIndex = 0 await this.handleGetCurrentUserScheduleInfo()
this.selectUser = data && data.length > 0 ? data[0] : "" } else {
console.log('this.selectUserthis.selectUserthis.selectUser', this.selectUser); this.selectedEmployee = null
uni.showToast({
title: '当前服务区暂无员工',
icon: 'none'
})
}
await this.handleGetCurrentUserScheduleInfo() //
this.hasLoaded = true
} catch (error) {
console.error('加载排班数据失败:', error)
this.userList = []
this.selectedEmployee = null
uni.showToast({
title: error.message || '加载失败,请重试',
icon: 'none'
})
} finally {
this.loading = false
uni.hideLoading()
}
}, },
// //
async handleGetCurrentUserScheduleInfo() { async handleGetCurrentUserScheduleInfo() {
this.selectedEmployee = null if (!this.selectUser || !this.selectUser.phone) {
//
if (this.hasLoaded) {
this.selectedEmployee = null
}
return
}
let req = { let req = {
bsessionKey: "20ED2B50179D4877853C4DED45D8179E", bsessionKey: "20ED2B50179D4877853C4DED45D8179E",
date: new Date(this.selectDate).getTime(), date: new Date(this.selectDate).getTime(),
phone: this.selectUser.phone phone: this.selectUser.phone
} }
const data = await new Promise((resolve, reject) => {
uni.request({
url: "https://fwqznxj.yciccloud.com:9081/ynjt/pushManage/queryWorkDetails",
method: "POST",
data: req,
header: {
"content-type": "application/x-www-form-urlencoded",
},
success(res) {
resolve(res.data.data)
},
});
});
console.log('datadatadatadatadata', data); try {
this.selectedEmployee = data[0] const data = await new Promise((resolve, reject) => {
uni.request({
url: "https://fwqznxj.yciccloud.com:9081/ynjt/pushManage/queryWorkDetails",
method: "POST",
data: req,
header: {
"content-type": "application/x-www-form-urlencoded",
},
success(res) {
if (res.data && res.data.data && Array.isArray(res.data.data) && res.data.data.length > 0) {
resolve(res.data.data)
} else {
resolve(null)
}
},
fail(err) {
reject(err)
}
});
});
if (data && data.length > 0) {
this.selectedEmployee = data[0]
} else {
this.selectedEmployee = null
//
if (this.hasLoaded) {
uni.showToast({
title: '该员工暂无排班信息',
icon: 'none'
})
}
}
//
this.hasLoaded = true
} catch (error) {
console.error('获取排班信息失败:', error)
this.selectedEmployee = null
uni.showToast({
title: '获取排班信息失败',
icon: 'none'
})
}
} }
} }
} }
@ -443,9 +564,19 @@ export default {
// border: 2rpx solid #27B35F; // border: 2rpx solid #27B35F;
// background: rgba(255, 255, 255, .15); // background: rgba(255, 255, 255, .15);
.arrowIcon { .arrowBtn {
width: 40rpx; display: flex;
height: 40rpx; align-items: center;
justify-content: center;
width: 60rpx;
height: 60rpx;
border-radius: 50%;
// background: rgba(39, 178, 95, 0.1);
.arrowIcon {
width: 40rpx;
height: 40rpx;
}
} }
.center { .center {
@ -489,39 +620,87 @@ export default {
.employeeCard { .employeeCard {
background: #fff; background: #fff;
border-radius: 12rpx; border-radius: 16rpx;
padding: 16rpx 24rpx; padding: 24rpx;
box-shadow: @shadow; box-shadow: @shadow;
border: 1px solid rgba(39, 178, 95, 0.08);
.employeeInfo { .employeeInfo {
display: flex; display: flex;
align-items: center; align-items: flex-start;
justify-content: space-between;
.employeeName { .avatar {
font-size: 28rpx; width: 72rpx;
font-weight: 600; height: 72rpx;
color: #333; border-radius: 50%;
margin-right: 24rpx; background: @primary;
} color: #fff;
.employeeJob {
font-size: 24rpx; font-size: 24rpx;
color: @primary; font-weight: 700;
background: rgba(39, 178, 95, 0.1); display: flex;
padding: 0 16rpx; align-items: center;
border-radius: 20rpx; justify-content: center;
margin-right: 24rpx; margin-right: 24rpx;
flex-shrink: 0;
} }
.phoneIcon { .basicInfo {
width: 24rpx; flex: 1;
height: 24rpx; display: flex;
margin-right: 8rpx; flex-direction: column;
gap: 12rpx;
margin-top: 4rpx;
.nameRow {
display: flex;
align-items: center;
.personIcon {
width: 24rpx;
height: 24rpx;
margin-right: 8rpx;
}
.employeeName {
font-size: 28rpx;
font-weight: 600;
color: #2c3e50;
line-height: 1.3;
}
}
.phoneRow {
display: flex;
align-items: center;
.phoneIcon {
width: 24rpx;
height: 24rpx;
margin-right: 8rpx;
}
.employeePhone {
font-size: 24rpx;
color: #666;
line-height: 1.3;
}
}
} }
.employeePhone { .jobInfo {
font-size: 24rpx; display: flex;
color: #666; align-items: flex-start;
margin-top: 4rpx;
.employeeJob {
font-size: 22rpx;
color: @primary;
background: rgba(39, 178, 95, 0.1);
padding: 6rpx 12rpx;
border-radius: 16rpx;
font-weight: 500;
}
} }
} }
} }
@ -577,7 +756,7 @@ export default {
} }
&.today { &.today {
background-color: rgba(39, 178, 95, 0.1); background-color: rgba(39, 178, 95, 0.15);
border: 2rpx solid @primary; border: 2rpx solid @primary;
} }
@ -621,6 +800,55 @@ export default {
} }
} }
/* 空状态样式 */
.emptyState,
.emptySchedule {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80rpx 40rpx;
text-align: center;
background: #fff;
border-radius: 16rpx;
margin-bottom: 32rpx;
box-shadow: @shadow;
.emptyIcon {
font-size: 80rpx;
margin-bottom: 24rpx;
opacity: 0.6;
}
.emptyText {
font-size: 32rpx;
color: #2c3e50;
font-weight: 600;
margin-bottom: 16rpx;
}
.emptyDesc {
font-size: 24rpx;
color: #666;
line-height: 1.5;
margin-bottom: 32rpx;
}
.retryBtn {
background: @primary;
color: #fff;
border: none;
border-radius: 24rpx;
padding: 16rpx 32rpx;
font-size: 24rpx;
font-weight: 600;
&::after {
border: none;
}
}
}
} }
} }
</style> </style>