868 lines
31 KiB
Vue
868 lines
31 KiB
Vue
<!-- 排班表 -->
|
||
<template>
|
||
<view class="main" :style="{ paddingTop: (menu.bottom + 28) + 'px' }">
|
||
<view class="summaryTab" :style="{ height: (menu.bottom + 14) + 'px' }">
|
||
<view class="leftArrow" :style="{ top: (menu.top + ((menu.height - 24) / 2)) + 'px' }">
|
||
<image class="img" src="https://eshangtech.com/ShopICO/ahyd-BID/commercial/navigation-left.svg"
|
||
@click="handleBack"></image>
|
||
<view class="picker" :style="{ top: (menu.bottom + 24) + 'px' }" @click="handleChangeService">
|
||
<view class="selectService">
|
||
<image class="img" src="https://eshangtech.com/ShopICO/ahyd-BID/commercial/fixed.svg"></image>
|
||
<view class="select">
|
||
<view class="content">
|
||
<view class="uni-input">{{ serviceInfo.SAName ? serviceInfo.SAName :
|
||
'' }}
|
||
</view>
|
||
<!-- <p class="area">{{ serviceInfo.SPREGIONTYPE_NAME ? serviceInfo.SPREGIONTYPE_NAME : '' }}
|
||
</p> -->
|
||
<image class="rightArrow"
|
||
src="https://eshangtech.com/ShopICO/ahyd-BID/commercial/rightArrow.svg"></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="rosterContent">
|
||
<!-- 月份和员工选择器 -->
|
||
<view class="selectorRow">
|
||
<view class="dateBox">
|
||
<view class="centerDateBox">
|
||
<view class="arrowBtn" @tap="handleChangeDate(2)">
|
||
<image class="arrowIcon" src="https://eshangtech.com/cyy_DIB/leftArrowIcon.png" />
|
||
</view>
|
||
<view class="center">
|
||
<text class="date-text">{{ selectDate ? $util.cutDate(new Date(selectDate), 'YYYY-MM') :
|
||
""
|
||
}}</text>
|
||
</view>
|
||
<view class="arrowBtn" @tap="handleChangeDate(1)">
|
||
<image class="arrowIcon" src="https://eshangtech.com/cyy_DIB/rightArrowIcon.png" />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
|
||
<!-- 员工选择器 -->
|
||
<view class="employeeSelector">
|
||
<picker @change="handleEmployeeChange" :value="selectedEmployeeIndex" :range="userList"
|
||
:range-key="'userName'">
|
||
<view class="employeePickerBox">
|
||
<view class="selectedEmployee">{{ userList[selectedEmployeeIndex] ?
|
||
userList[selectedEmployeeIndex].userName :
|
||
'请选择员工' }}
|
||
</view>
|
||
<image class="rightArrow"
|
||
src="https://eshangtech.com/ShopICO/ahyd-BID/commercial/rightArrow.svg"></image>
|
||
</view>
|
||
</picker>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 员工信息 -->
|
||
<view v-if="selectedEmployee" class="employeeDetail">
|
||
<view class="employeeCard">
|
||
<view class="employeeInfo">
|
||
<view class="avatar" v-if="!selectedEmployee.phone">{{ getFirstChar(selectedEmployee.userName) }}
|
||
</view>
|
||
<image class="avatar" v-else
|
||
:src="`https://fwqznxj.yciccloud.com:9081/fileDownloadApi/bsys/file/thumbnail/download/${selectedEmployee.phone}`" />
|
||
<view class="basicInfo">
|
||
<view class="nameRow">
|
||
<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 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 class="weekHeader">
|
||
<view v-for="(weekName, index) in weekNames" :key="index" class="weekHeaderItem"
|
||
:class="{ 'weekend': index === 0 || index === 6 }">
|
||
{{ weekName }}
|
||
</view>
|
||
</view>
|
||
|
||
<view class="calendarGrid">
|
||
<view v-for="(n, index) in firstDayOfWeek" :key="index" class="calendarCell empty"></view>
|
||
|
||
<view v-for="day in monthDays" :key="day.date" class="calendarCell" :class="{
|
||
'weekend': day.isWeekend,
|
||
'today': day.isToday
|
||
}">
|
||
<view class="dateNumber">{{ day.day }}</view>
|
||
<view class="scheduleInfo" :class="{
|
||
'work': selectedEmployee && selectedEmployee[`day${day.day}`] && !selectedEmployee[`day${day.day}`].toString().toLowerCase().includes('休'),
|
||
'rest': selectedEmployee && selectedEmployee[`day${day.day}`] && selectedEmployee[`day${day.day}`].toString().toLowerCase().includes('休'),
|
||
'empty': !selectedEmployee || !selectedEmployee[`day${day.day}`]
|
||
}">
|
||
{{ selectedEmployee && selectedEmployee[`day${day.day}`] ?
|
||
(selectedEmployee[`day${day.day}`].toString().toLowerCase().includes('休') ? '休' : '班') : ''
|
||
}}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
const now = new Date()
|
||
const currentYear = now.getFullYear()
|
||
const currentMonthIndex = now.getMonth()
|
||
const nowDay = this.$util.cutDate(new Date(), 'YYYY-MM-DD') // 有数据的最近日期
|
||
|
||
return {
|
||
menu: {},
|
||
selectDate: nowDay,// 选中的时间
|
||
serviceInfo: {},
|
||
currentYear: currentYear,
|
||
currentMonth: currentMonthIndex,
|
||
selectedEmployeeIndex: 0,
|
||
selectedEmployee: null,
|
||
weekNames: ['日', '一', '二', '三', '四', '五', '六'],
|
||
// 模拟排班数据,实际使用时从接口获取
|
||
rosterData: [],
|
||
userList: [],// 员工的数组
|
||
selectUser: "",//当前选择的员工
|
||
isFirst: true,
|
||
monthDays: [],
|
||
firstDayOfWeek: "",
|
||
loading: false,
|
||
retryCount: 0,
|
||
hasLoaded: false, // 是否已经完成过初始加载
|
||
}
|
||
},
|
||
computed: {
|
||
// 获取月份第一天是星期几 (0=周日, 1=周一, ..., 6=周六)
|
||
// firstDayOfWeek() {
|
||
// const firstDay = new Date(this.currentYear, this.currentMonth, 1)
|
||
// return firstDay.getDay()
|
||
// }
|
||
},
|
||
onLoad() {
|
||
this.menu = uni.getMenuButtonBoundingClientRect()
|
||
let currentService = uni.getStorageSync('currentService')
|
||
this.serviceInfo = currentService
|
||
this.handleGetNewMonthData()
|
||
// 加载排班数据
|
||
this.loadRosterData(currentService.SAName)
|
||
},
|
||
onShow() {
|
||
let currentService = uni.getStorageSync('currentService')
|
||
console.log('currentService', currentService);
|
||
|
||
// 防护:检查 currentService 是否有效
|
||
if (!currentService || (!currentService.SACode)) {
|
||
console.warn('currentService 为空或无效,跳过更新');
|
||
this.isFirst = false;
|
||
return;
|
||
}
|
||
|
||
// 获取统一的服务区ID
|
||
const currentServiceId = currentService.SACode;
|
||
const currentServiceName = currentService.SAName;
|
||
|
||
// 只有当服务区真正发生变化且不是首次加载时才更新
|
||
if (currentServiceId && currentServiceId !== this.serviceInfo.SACode && !this.isFirst) {
|
||
this.serviceInfo = currentService
|
||
this.rosterData = []
|
||
this.userList = []
|
||
this.selectUser = null
|
||
this.loadRosterData(currentServiceName)
|
||
} else {
|
||
this.isFirst = false;
|
||
}
|
||
},
|
||
methods: {
|
||
// 获取姓名首字符
|
||
getFirstChar(name) {
|
||
return name ? name.charAt(0).toUpperCase() : '?'
|
||
},
|
||
|
||
// 重试加载
|
||
retryLoad() {
|
||
if (this.retryCount < 3) {
|
||
this.retryCount++
|
||
this.loadRosterData(this.serviceInfo.SAName)
|
||
} else {
|
||
uni.showToast({
|
||
title: '多次重试失败,请检查网络连接',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
|
||
handleGetNewMonthData() {
|
||
const year = this.currentYear
|
||
const month = this.currentMonth
|
||
|
||
const daysInMonth = new Date(year, month + 1, 0).getDate()
|
||
const today = new Date()
|
||
const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`
|
||
|
||
const days = []
|
||
const weekTexts = ['日', '一', '二', '三', '四', '五', '六']
|
||
|
||
for (let day = 1; day <= daysInMonth; day++) {
|
||
const date = new Date(year, month, day)
|
||
const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`
|
||
const weekDay = date.getDay()
|
||
|
||
days.push({
|
||
day: day,
|
||
date: dateStr,
|
||
weekDay: weekDay,
|
||
weekText: weekTexts[weekDay],
|
||
isWeekend: weekDay === 0 || weekDay === 6,
|
||
isToday: dateStr === todayStr
|
||
})
|
||
}
|
||
|
||
this.monthDays = days
|
||
|
||
const firstDay = new Date(this.currentYear, this.currentMonth, 1)
|
||
this.firstDayOfWeek = firstDay.getDay()
|
||
},
|
||
handleChangeService() {
|
||
this.$util.toNextRoute("navigateTo", "/pages/map/index?type=attendanceStatus");
|
||
},
|
||
// 修改日期
|
||
async handleChangeDate(type) {
|
||
// type 1 加一天 2 减一天
|
||
// 兼容 iOS,把 2025-08-15 转成 2025/08/15
|
||
const cur = new Date((this.selectDate || '').replace(/-/g, '/'));
|
||
if (Number.isNaN(cur.getTime())) return;
|
||
|
||
// 1:加一月;2:减一月;其他:不变
|
||
const delta = type === 1 ? 1 : (type === 2 ? -1 : 0);
|
||
|
||
// 目标月份的最后一天:new Date(年, 目标月+1, 0)
|
||
const last = new Date(cur.getFullYear(), cur.getMonth() + delta + 1, 0);
|
||
|
||
const y = last.getFullYear();
|
||
const m = String(last.getMonth() + 1).padStart(2, '0');
|
||
const d = String(last.getDate()).padStart(2, '0');
|
||
|
||
this.selectDate = `${y}-${m}-${d}`;
|
||
|
||
// 修复:currentMonth应该是数字类型(0-11),而不是字符串
|
||
this.currentYear = y
|
||
this.currentMonth = last.getMonth() // 使用数字类型的月份索引
|
||
|
||
this.handleGetNewMonthData()
|
||
this.retryCount = 0 // 重置重试次数
|
||
|
||
// 月份切换时,不清空selectedEmployee,保持显示直到新数据加载完成
|
||
await this.handleGetCurrentUserScheduleInfo()
|
||
},
|
||
// 返回上一页
|
||
handleBack() {
|
||
uni.navigateBack()
|
||
},
|
||
// 员工选择变化
|
||
handleEmployeeChange(e) {
|
||
const selectedIndex = Number(e.detail.value)
|
||
if (selectedIndex >= 0 && selectedIndex < this.userList.length) {
|
||
this.selectedEmployeeIndex = selectedIndex
|
||
this.selectUser = this.userList[selectedIndex]
|
||
// 切换员工时,暂时保持当前状态,直到新数据加载完成
|
||
this.handleGetCurrentUserScheduleInfo()
|
||
}
|
||
},
|
||
|
||
// 加载排班数据
|
||
async loadRosterData(SERVERPART_NAME) {
|
||
if (!SERVERPART_NAME) {
|
||
uni.showToast({
|
||
title: '请先选择服务区',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
this.loading = true
|
||
let req = {
|
||
bsessionKey: "0B30475A94674D608022885F7763959B",
|
||
workTime: new Date(this.selectDate).getTime(),
|
||
saName: SERVERPART_NAME,
|
||
phone: "",
|
||
}
|
||
|
||
uni.showLoading({
|
||
title: "加载中..."
|
||
})
|
||
|
||
try {
|
||
const data = await new Promise((resolve, reject) => {
|
||
uni.request({
|
||
url: "https://fwqznxj.yciccloud.com:9081/ynjt/pushManage/queryUserSchedule",
|
||
method: "POST",
|
||
data: req,
|
||
header: {
|
||
"content-type": "application/x-www-form-urlencoded",
|
||
},
|
||
success(res) {
|
||
if (res.data && res.data.data) {
|
||
resolve(res.data.data)
|
||
} else {
|
||
reject(new Error('数据格式错误'))
|
||
}
|
||
},
|
||
fail(err) {
|
||
reject(err)
|
||
}
|
||
});
|
||
});
|
||
|
||
const userList = Array.isArray(data) ? data : []
|
||
this.userList = userList
|
||
this.selectedEmployeeIndex = 0
|
||
this.selectUser = userList.length > 0 ? userList[0] : null
|
||
|
||
if (userList.length > 0) {
|
||
await this.handleGetCurrentUserScheduleInfo()
|
||
} else {
|
||
this.selectedEmployee = null
|
||
uni.showToast({
|
||
title: '当前服务区暂无员工',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
|
||
// 标记已完成初始加载
|
||
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() {
|
||
if (!this.selectUser || !this.selectUser.phone) {
|
||
// 只有在已经完成过初始加载后才显示空状态
|
||
if (this.hasLoaded) {
|
||
this.selectedEmployee = null
|
||
}
|
||
return
|
||
}
|
||
let req = {
|
||
bsessionKey: "20ED2B50179D4877853C4DED45D8179E",
|
||
date: new Date(this.selectDate).getTime(),
|
||
phone: this.selectUser.phone
|
||
}
|
||
|
||
try {
|
||
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'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
|
||
<style lang="less" scoped>
|
||
@bg: #f8f9fa;
|
||
@muted: #666;
|
||
@card: #fff;
|
||
@shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
@primary: #27B25F;
|
||
@primary2: #4CCC7F;
|
||
@ok: #2ed573;
|
||
@warn: #ff9f43;
|
||
@danger: #ff4757;
|
||
|
||
.main {
|
||
width: 100vw;
|
||
min-height: 100vh;
|
||
background-color: #f0f2f3;
|
||
box-sizing: border-box;
|
||
padding-bottom: constant(safe-area-inset-bottom);
|
||
padding-bottom: env(safe-area-inset-bottom);
|
||
padding: 16rpx 32rpx 0;
|
||
|
||
.summaryTab {
|
||
position: fixed;
|
||
left: 0;
|
||
top: 0;
|
||
width: 100vw;
|
||
background-image: url("https://eshangtech.com/minTestImg/pageBg.png");
|
||
z-index: 99;
|
||
display: flex;
|
||
align-items: center;
|
||
box-sizing: border-box;
|
||
padding-bottom: 16px;
|
||
|
||
.leftArrow {
|
||
width: 100%;
|
||
height: 24px;
|
||
position: absolute;
|
||
z-index: 99999999999;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 32rpx;
|
||
|
||
.img {
|
||
width: 24px;
|
||
height: 24px;
|
||
margin-right: 8px;
|
||
z-index: 99;
|
||
}
|
||
|
||
.picker {
|
||
.selectService {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.img {
|
||
width: 40px;
|
||
height: 40px;
|
||
z-index: 2;
|
||
}
|
||
|
||
.select {
|
||
height: 32px;
|
||
background: #fff;
|
||
border-radius: 0 16px 16px 0;
|
||
transform: translateX(-40px);
|
||
box-sizing: border-box;
|
||
padding-left: 35px;
|
||
padding-right: 8rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.content {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.uni-input {
|
||
padding: 0;
|
||
background: transparent;
|
||
font-size: 28rpx;
|
||
font-family: PingFangSC-Semibold, PingFang SC;
|
||
font-weight: 600;
|
||
color: #160002;
|
||
}
|
||
|
||
.area {
|
||
font-size: 12px;
|
||
font-family: PingFangSC-Regular, PingFang SC;
|
||
font-weight: 400;
|
||
color: #786B6C;
|
||
line-height: 40px;
|
||
margin-left: 4px;
|
||
}
|
||
|
||
.rightArrow {
|
||
width: 12px;
|
||
height: 12px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.rosterContent {
|
||
width: 100%;
|
||
background-color: #fff;
|
||
box-sizing: border-box;
|
||
padding: 0 24rpx 8rpx;
|
||
border-radius: 8rpx;
|
||
|
||
/* 选择器行布局 */
|
||
.selectorRow {
|
||
display: flex;
|
||
gap: 24rpx;
|
||
padding: 24rpx 0;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.dateBox {
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.centerDateBox {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10rpx;
|
||
border-radius: 30rpx;
|
||
background-color: #fff;
|
||
// border: 2rpx solid #27B35F;
|
||
// background: rgba(255, 255, 255, .15);
|
||
|
||
.arrowBtn {
|
||
display: flex;
|
||
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 {
|
||
.date-text {
|
||
font-size: 28rpx;
|
||
font-weight: 700;
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
/* 员工选择器 */
|
||
.employeeSelector {
|
||
.employeePickerBox {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
// padding: 20rpx 24rpx;
|
||
// background: #f8f9fa;
|
||
border-radius: 30rpx;
|
||
// border: 2rpx solid #e0e0e0;
|
||
|
||
.selectedEmployee {
|
||
font-size: 24rpx;
|
||
font-weight: 400;
|
||
color: #000;
|
||
margin-right: 8rpx;
|
||
}
|
||
|
||
.rightArrow {
|
||
width: 26rpx;
|
||
height: 26rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 员工信息卡片 */
|
||
.employeeDetail {
|
||
margin-bottom: 32rpx;
|
||
|
||
.employeeCard {
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
padding: 24rpx;
|
||
box-shadow: @shadow;
|
||
border: 1px solid rgba(39, 178, 95, 0.08);
|
||
|
||
.employeeInfo {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
|
||
.avatar {
|
||
width: 72rpx;
|
||
height: 72rpx;
|
||
border-radius: 50%;
|
||
background: @primary;
|
||
color: #fff;
|
||
font-size: 24rpx;
|
||
font-weight: 700;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 24rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.basicInfo {
|
||
flex: 1;
|
||
display: flex;
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
|
||
.jobInfo {
|
||
display: flex;
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 日历格式排班表 */
|
||
.calendarRoster {
|
||
background: #fff;
|
||
border-radius: 12rpx;
|
||
// padding: 32rpx;
|
||
box-shadow: @shadow;
|
||
margin-bottom: 32rpx;
|
||
|
||
/* 星期标题 */
|
||
.weekHeader {
|
||
display: flex;
|
||
border-bottom: 2rpx solid #e0e0e0;
|
||
// margin-bottom: 16rpx;
|
||
|
||
.weekHeaderItem {
|
||
flex: 1;
|
||
text-align: center;
|
||
padding: 16rpx 0;
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
|
||
&.weekend {
|
||
color: @danger;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 日历网格 */
|
||
.calendarGrid {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
width: 100%;
|
||
|
||
.calendarCell {
|
||
width: 14.28%;
|
||
height: 120rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: 1rpx solid #f0f0f0;
|
||
box-sizing: border-box;
|
||
position: relative;
|
||
|
||
&.empty {
|
||
background-color: #fafafa;
|
||
}
|
||
|
||
&.today {
|
||
background-color: rgba(39, 178, 95, 0.15);
|
||
border: 2rpx solid @primary;
|
||
}
|
||
|
||
&.weekend {
|
||
.dateNumber {
|
||
// color: @danger;
|
||
}
|
||
}
|
||
|
||
.dateNumber {
|
||
font-size: 24rpx;
|
||
font-weight: 500;
|
||
color: #333;
|
||
margin-bottom: 4rpx;
|
||
}
|
||
|
||
.scheduleInfo {
|
||
font-size: 24rpx;
|
||
padding: 2rpx 4rpx;
|
||
border-radius: 4rpx;
|
||
font-weight: 500;
|
||
text-align: center;
|
||
line-height: 1;
|
||
|
||
&.work {
|
||
// background-color: #333;
|
||
color: #000;
|
||
}
|
||
|
||
&.rest {
|
||
// background-color: #f5f5f5;
|
||
// color: #999;
|
||
color: red;
|
||
}
|
||
|
||
&.empty {
|
||
visibility: hidden;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 空状态样式 */
|
||
.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> |