新增个人轮班 MVP:左上角胶囊显示班/休
新增 ShiftPattern 数据模型,以锚点日期 + 循环序列描述周期性轮班,与法定调休完全独立。 默认配置 2026-05-15 起 [班,班,休,休] 4 天周期,DayCell 左上角渲染胶囊角标。
This commit is contained in:
parent
f63b57eef1
commit
ecf4cf601e
@ -77,6 +77,19 @@ class CalendarViewModel(
|
||||
var yearViewYear by mutableStateOf(today.year)
|
||||
internal set
|
||||
|
||||
/**
|
||||
* 个人轮班。与法定节假日完全独立,不受调休影响。
|
||||
* MVP 默认:2026-05-15 起,2 班 2 休循环。后续接入设置页与持久化。
|
||||
*/
|
||||
var shiftPattern: ShiftPattern? by mutableStateOf(
|
||||
ShiftPattern(
|
||||
anchorDate = LocalDate(2026, 5, 15),
|
||||
cycle = listOf(ShiftKind.WORK, ShiftKind.WORK, ShiftKind.OFF, ShiftKind.OFF)
|
||||
)
|
||||
)
|
||||
|
||||
fun shiftKindAt(date: LocalDate): ShiftKind? = shiftPattern?.kindAt(date)
|
||||
|
||||
/**
|
||||
* 选中指定日期。
|
||||
*
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
package plus.rua.project
|
||||
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.daysUntil
|
||||
|
||||
/**
|
||||
* 个人轮班类型。仅区分上班与休息;后续可扩展早/中/晚班、休假等。
|
||||
*/
|
||||
enum class ShiftKind { WORK, OFF }
|
||||
|
||||
/**
|
||||
* 个人轮班周期。
|
||||
*
|
||||
* 与法定节假日完全独立:周期内某天是 WORK 还是 OFF,只看
|
||||
* `(date - anchorDate) mod cycle.size` 在 cycle 中的取值,不受任何节假日/调休影响。
|
||||
*
|
||||
* @param anchorDate 周期基准日,对应 cycle[0]
|
||||
* @param cycle 一个周期内的班次序列,例如 [WORK, WORK, OFF, OFF] 表示 "2 班 2 休"
|
||||
* @param name 方案名,用于后续多套方案场景
|
||||
*/
|
||||
data class ShiftPattern(
|
||||
val anchorDate: LocalDate,
|
||||
val cycle: List<ShiftKind>,
|
||||
val name: String = "默认"
|
||||
) {
|
||||
fun kindAt(date: LocalDate): ShiftKind? {
|
||||
if (cycle.isEmpty()) return null
|
||||
val diff = anchorDate.daysUntil(date)
|
||||
val size = cycle.size
|
||||
val idx = ((diff % size) + size) % size
|
||||
return cycle[idx]
|
||||
}
|
||||
}
|
||||
@ -22,6 +22,7 @@ import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.minus
|
||||
import kotlinx.datetime.number
|
||||
import kotlinx.datetime.plus
|
||||
import plus.rua.project.ShiftKind
|
||||
|
||||
/**
|
||||
* 月度日历网格页面,支持两阶段折叠动画。
|
||||
@ -50,6 +51,7 @@ fun CalendarMonthPage(
|
||||
collapseProgress: Float,
|
||||
rowHeightPx: Int,
|
||||
effectiveWeeks: Float,
|
||||
shiftKindAt: (LocalDate) -> ShiftKind?,
|
||||
onRowHeightMeasured: ((Int) -> Unit)? = null,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
@ -152,6 +154,7 @@ fun CalendarMonthPage(
|
||||
isCurrentMonth = dayData.isCurrentMonth,
|
||||
isSelected = dayData.date == selectedDate,
|
||||
isToday = dayData.date == today,
|
||||
shiftKind = shiftKindAt(dayData.date),
|
||||
onClick = { onDateClick(dayData.date) },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
@ -259,6 +259,7 @@ fun CalendarMonthView(
|
||||
}
|
||||
viewModel.selectDate(date)
|
||||
},
|
||||
shiftKindAt = { date -> viewModel.shiftKindAt(date) },
|
||||
modifier = pagerModifier
|
||||
)
|
||||
} else {
|
||||
@ -275,6 +276,7 @@ fun CalendarMonthView(
|
||||
collapseProgress = viewModel.collapseProgress,
|
||||
rowHeightPx = rowHeightPx,
|
||||
effectiveWeeks = effectiveWeeks,
|
||||
shiftKindAt = { date -> viewModel.shiftKindAt(date) },
|
||||
onRowHeightMeasured = { h ->
|
||||
if (h > 0) rowHeightPx = h
|
||||
},
|
||||
|
||||
@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.drop
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.number
|
||||
import plus.rua.project.ShiftKind
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
@ -42,6 +43,7 @@ fun CalendarPager(
|
||||
collapseProgress: Float,
|
||||
rowHeightPx: Int,
|
||||
effectiveWeeks: Float,
|
||||
shiftKindAt: (LocalDate) -> ShiftKind?,
|
||||
onRowHeightMeasured: ((Int) -> Unit)? = null,
|
||||
pagerState: PagerState,
|
||||
modifier: Modifier = Modifier
|
||||
@ -94,6 +96,7 @@ fun CalendarPager(
|
||||
collapseProgress = collapseProgress,
|
||||
rowHeightPx = rowHeightPx,
|
||||
effectiveWeeks = effectiveWeeks,
|
||||
shiftKindAt = shiftKindAt,
|
||||
onRowHeightMeasured = onRowHeightMeasured,
|
||||
modifier = Modifier.alpha(alpha)
|
||||
)
|
||||
|
||||
@ -36,6 +36,7 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.zIndex
|
||||
import com.tyme.solar.SolarDay
|
||||
import kotlinx.datetime.LocalDate
|
||||
import plus.rua.project.ShiftKind
|
||||
|
||||
enum class DayCellState {
|
||||
NORMAL, OTHER_MONTH, TODAY, SELECTED, SELECTED_TODAY
|
||||
@ -48,6 +49,7 @@ enum class DayCellState {
|
||||
* @param isCurrentMonth 是否属于当前显示月份
|
||||
* @param isSelected 是否为选中日期
|
||||
* @param isToday 是否为今天
|
||||
* @param shiftKind 个人轮班类型,左上角胶囊显示;null 表示不显示。与法定调休完全独立。
|
||||
* @param onClick 点击回调
|
||||
* @param modifier 外部布局修饰符
|
||||
*/
|
||||
@ -57,6 +59,7 @@ fun DayCell(
|
||||
isCurrentMonth: Boolean,
|
||||
isSelected: Boolean,
|
||||
isToday: Boolean,
|
||||
shiftKind: ShiftKind?,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
@ -243,6 +246,33 @@ fun DayCell(
|
||||
)
|
||||
}
|
||||
}
|
||||
if (shiftKind != null) {
|
||||
val shiftBgColor = if (shiftKind == ShiftKind.WORK) {
|
||||
MaterialTheme.colorScheme.primary
|
||||
} else {
|
||||
MaterialTheme.colorScheme.error
|
||||
}
|
||||
val shiftFgColor = if (shiftKind == ShiftKind.WORK) {
|
||||
MaterialTheme.colorScheme.onPrimary
|
||||
} else {
|
||||
MaterialTheme.colorScheme.onError
|
||||
}
|
||||
val shiftLabel = if (shiftKind == ShiftKind.WORK) "班" else "休"
|
||||
val shiftAlpha = if (isCurrentMonth) 1f else 0.38f
|
||||
Text(
|
||||
text = shiftLabel,
|
||||
color = shiftFgColor.copy(alpha = shiftAlpha),
|
||||
fontSize = 9.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
lineHeight = 9.sp,
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopStart)
|
||||
.zIndex(1f)
|
||||
.padding(top = 1.dp, start = 2.dp)
|
||||
.background(shiftBgColor.copy(alpha = shiftAlpha), CircleShape)
|
||||
.padding(horizontal = 2.dp)
|
||||
)
|
||||
}
|
||||
if (holidayBadge != null) {
|
||||
Text(
|
||||
text = holidayBadge,
|
||||
|
||||
@ -18,6 +18,7 @@ import kotlinx.datetime.DatePeriod
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.daysUntil
|
||||
import kotlinx.datetime.plus
|
||||
import plus.rua.project.ShiftKind
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
@ -35,6 +36,7 @@ fun WeekPager(
|
||||
today: LocalDate,
|
||||
onDateClick: (LocalDate) -> Unit,
|
||||
onWeekChanged: (LocalDate) -> Unit,
|
||||
shiftKindAt: (LocalDate) -> ShiftKind?,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val initialWeekMonday = remember { selectedDate.toWeekMonday() }
|
||||
@ -82,6 +84,7 @@ fun WeekPager(
|
||||
&& date.year == selectedDate.year,
|
||||
isSelected = date == selectedDate,
|
||||
isToday = date == today,
|
||||
shiftKind = shiftKindAt(date),
|
||||
onClick = { onDateClick(date) },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user