|
|
@@ -19,19 +19,23 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|
|
import androidx.compose.foundation.text.BasicTextField
|
|
|
import androidx.compose.foundation.text.KeyboardOptions
|
|
|
import androidx.compose.foundation.verticalScroll
|
|
|
+import androidx.compose.material3.Checkbox
|
|
|
import androidx.compose.material3.DropdownMenu
|
|
|
import androidx.compose.material3.DropdownMenuItem
|
|
|
import androidx.compose.material3.Icon
|
|
|
import androidx.compose.material3.LocalTextStyle
|
|
|
+import androidx.compose.material3.MaterialTheme
|
|
|
import androidx.compose.material3.RadioButton
|
|
|
import androidx.compose.material3.Text
|
|
|
import androidx.compose.runtime.Composable
|
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
|
import androidx.compose.runtime.getValue
|
|
|
import androidx.compose.runtime.key
|
|
|
+import androidx.compose.runtime.mutableStateListOf
|
|
|
import androidx.compose.runtime.mutableStateOf
|
|
|
import androidx.compose.runtime.remember
|
|
|
import androidx.compose.runtime.setValue
|
|
|
+import androidx.compose.runtime.snapshots.SnapshotStateList
|
|
|
import androidx.compose.ui.Alignment
|
|
|
import androidx.compose.ui.Modifier
|
|
|
import androidx.compose.ui.draw.clip
|
|
|
@@ -60,7 +64,7 @@ import kotlinx.serialization.json.Json
|
|
|
|
|
|
|
|
|
@Composable
|
|
|
-fun FormContainer(forms: List<FormField>, modifier: Modifier = Modifier) {
|
|
|
+fun FormContainer(forms: List<FormField>, onValueChange: (FormField) -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true) {
|
|
|
Column(modifier = modifier) {
|
|
|
forms.forEach { form ->
|
|
|
key(form.id) {
|
|
|
@@ -69,52 +73,96 @@ fun FormContainer(forms: List<FormField>, modifier: Modifier = Modifier) {
|
|
|
"input" -> FormInput(
|
|
|
form.label,
|
|
|
form.value,
|
|
|
- { form.value = it },
|
|
|
+ {
|
|
|
+ form.value = it
|
|
|
+ onValueChange(form)
|
|
|
+ },
|
|
|
form.placeholder,
|
|
|
required = form.required,
|
|
|
- enable = form.enabled
|
|
|
+ enable = form.enabled && enabled
|
|
|
)
|
|
|
// 多行文本输入
|
|
|
"textarea" -> FormTextarea(
|
|
|
form.label,
|
|
|
form.value,
|
|
|
- { form.value = it },
|
|
|
+ {
|
|
|
+ form.value = it
|
|
|
+ onValueChange(form)
|
|
|
+ },
|
|
|
form.placeholder,
|
|
|
required = form.required,
|
|
|
- enable = form.enabled
|
|
|
+ enable = form.enabled && enabled
|
|
|
)
|
|
|
// 选择器
|
|
|
"select" -> FormSelect(
|
|
|
form.label,
|
|
|
form.value,
|
|
|
form.options,
|
|
|
- { form.value = it },
|
|
|
+ {
|
|
|
+ form.value = it
|
|
|
+ onValueChange(form)
|
|
|
+ },
|
|
|
required = form.required,
|
|
|
- enable = form.enabled
|
|
|
+ enable = form.enabled && enabled,
|
|
|
+ multiSelect = form.multiSelect,
|
|
|
+ placeholder = form.placeholder
|
|
|
)
|
|
|
// 日期选择
|
|
|
"date" -> FormDateSelect(
|
|
|
form.label,
|
|
|
form.value,
|
|
|
- { form.value = it },
|
|
|
- required = form.required, enable = form.enabled
|
|
|
+ {
|
|
|
+ form.value = it
|
|
|
+ onValueChange(form)
|
|
|
+ },
|
|
|
+ required = form.required,
|
|
|
+ enable = form.enabled && enabled
|
|
|
)
|
|
|
// 起止日期选择
|
|
|
"daterange" -> FormDateRangeSelect(
|
|
|
form.label,
|
|
|
form.value,
|
|
|
- { form.value = it },
|
|
|
+ {
|
|
|
+ form.value = it
|
|
|
+ onValueChange(form)
|
|
|
+ },
|
|
|
placeholder = form.placeholder,
|
|
|
- enable = form.enabled
|
|
|
+ enable = form.enabled && enabled
|
|
|
+ )
|
|
|
+ // 时间选择器
|
|
|
+ "timepicker" -> FormTimeSelect(
|
|
|
+ form.label,
|
|
|
+ form.value,
|
|
|
+ {
|
|
|
+ form.value = it
|
|
|
+ onValueChange(form)
|
|
|
+ },
|
|
|
+ required = form.required,
|
|
|
+ enable = form.enabled && enabled
|
|
|
)
|
|
|
// 单选
|
|
|
"radio" -> FormRadio(
|
|
|
form.label,
|
|
|
form.value,
|
|
|
form.options,
|
|
|
- { form.value = it },
|
|
|
+ {
|
|
|
+ form.value = it
|
|
|
+ onValueChange(form)
|
|
|
+ },
|
|
|
+ required = form.required,
|
|
|
+ enable = form.enabled && enabled
|
|
|
+ )
|
|
|
+ // 多选
|
|
|
+ "checkbox" -> FormCheckbox(
|
|
|
+ form.label,
|
|
|
+ form.value,
|
|
|
+ form.options,
|
|
|
+ {
|
|
|
+ form.value = it
|
|
|
+ onValueChange(form)
|
|
|
+ },
|
|
|
required = form.required,
|
|
|
- enable = form.enabled
|
|
|
+ enable = form.enabled && enabled
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
@@ -149,7 +197,12 @@ fun FormInput(
|
|
|
.fillMaxWidth()
|
|
|
.height(40.dp), verticalAlignment = Alignment.CenterVertically
|
|
|
) {
|
|
|
- Text(label, fontSize = 14.sp, fontWeight = FontWeight.Bold, color = Text.copy(alpha = if (enable) 1f else 0.6f))
|
|
|
+ Text(
|
|
|
+ label,
|
|
|
+ fontSize = 14.sp,
|
|
|
+ fontWeight = FontWeight.Bold,
|
|
|
+ color = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
+ )
|
|
|
if (required) Text(
|
|
|
"*",
|
|
|
fontSize = 14.sp,
|
|
|
@@ -170,7 +223,7 @@ fun FormInput(
|
|
|
.border(1.dp, shape = RoundedCornerShape(6.dp), color = Color(0xFFE5E6EB))
|
|
|
.padding(horizontal = 10.dp),
|
|
|
singleLine = true,
|
|
|
- textStyle = LocalTextStyle.current.copy(fontSize = 14.sp, lineHeight = 18.sp),
|
|
|
+ textStyle = LocalTextStyle.current.copy(fontSize = 14.sp, lineHeight = 18.sp, color = Text.copy(alpha = if (enable) 1f else 0.6f)),
|
|
|
decorationBox = { innerTextField ->
|
|
|
Box(contentAlignment = Alignment.CenterStart) {
|
|
|
innerTextField()
|
|
|
@@ -215,7 +268,12 @@ fun FormTextarea(
|
|
|
.fillMaxWidth()
|
|
|
.height(40.dp), verticalAlignment = Alignment.CenterVertically
|
|
|
) {
|
|
|
- Text(label, fontSize = 14.sp, fontWeight = FontWeight.Bold, color = Text.copy(alpha = if (enable) 1f else 0.6f))
|
|
|
+ Text(
|
|
|
+ label,
|
|
|
+ fontSize = 14.sp,
|
|
|
+ fontWeight = FontWeight.Bold,
|
|
|
+ color = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
+ )
|
|
|
if (required) Text(
|
|
|
"*",
|
|
|
fontSize = 14.sp,
|
|
|
@@ -236,7 +294,7 @@ fun FormTextarea(
|
|
|
.border(1.dp, shape = RoundedCornerShape(6.dp), color = Color(0xFFE5E6EB))
|
|
|
.padding(10.dp)
|
|
|
.verticalScroll(rememberScrollState()),
|
|
|
- textStyle = LocalTextStyle.current.copy(fontSize = 14.sp, lineHeight = 18.sp),
|
|
|
+ textStyle = LocalTextStyle.current.copy(fontSize = 14.sp, lineHeight = 18.sp, color = Text.copy(alpha = if (enable) 1f else 0.6f)),
|
|
|
decorationBox = { innerTextField ->
|
|
|
Box(contentAlignment = Alignment.TopStart) {
|
|
|
innerTextField()
|
|
|
@@ -267,15 +325,33 @@ fun FormSelect(
|
|
|
value: List<String>,
|
|
|
options: List<FormOption>,
|
|
|
onSelectChange: (List<String>) -> Unit,
|
|
|
- placeholder: List<String> = listOf(""),
|
|
|
+ placeholder: List<String> = listOf(),
|
|
|
required: Boolean = false,
|
|
|
enable: Boolean = true,
|
|
|
+ multiSelect: Boolean = false,
|
|
|
) {
|
|
|
var expanded by remember { mutableStateOf(false) }
|
|
|
var width by remember { mutableStateOf(0) }
|
|
|
val density = LocalDensity.current
|
|
|
// 当前表单中的状态
|
|
|
- var opt by remember { mutableStateOf(options.find { it.value == value.getOrNull(0) }) }
|
|
|
+ val values = remember { mutableStateListOf<String>() }
|
|
|
+ LaunchedEffect(value) {
|
|
|
+ values.clear()
|
|
|
+ values.addAll(value)
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 转换数组列表
|
|
|
+ */
|
|
|
+ fun SnapshotStateList<String>.data2String(): String {
|
|
|
+ var datas = ""
|
|
|
+ this.forEachIndexed { index, value ->
|
|
|
+ val find = options.find { it.value == value }?.label ?: ""
|
|
|
+ datas += if (index == (this.size - 1)) find else "$find, "
|
|
|
+ }
|
|
|
+ return datas
|
|
|
+ }
|
|
|
+
|
|
|
Column(
|
|
|
Modifier
|
|
|
.fillMaxWidth()
|
|
|
@@ -287,7 +363,12 @@ fun FormSelect(
|
|
|
.fillMaxWidth()
|
|
|
.height(40.dp), verticalAlignment = Alignment.CenterVertically
|
|
|
) {
|
|
|
- Text(label, fontSize = 14.sp, fontWeight = FontWeight.Bold, color = Text.copy(alpha = if (enable) 1f else 0.6f))
|
|
|
+ Text(
|
|
|
+ label,
|
|
|
+ fontSize = 14.sp,
|
|
|
+ fontWeight = FontWeight.Bold,
|
|
|
+ color = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
+ )
|
|
|
if (required) Text(
|
|
|
"*",
|
|
|
fontSize = 14.sp,
|
|
|
@@ -306,16 +387,20 @@ fun FormSelect(
|
|
|
verticalAlignment = Alignment.CenterVertically
|
|
|
) {
|
|
|
Text(
|
|
|
- opt?.label ?: "请选择$label",
|
|
|
+ values.data2String()
|
|
|
+ .ifEmpty { (placeholder.getOrNull(0) ?: "").ifEmpty { "请选择$label" } },
|
|
|
color = Text.copy(alpha = if (enable) 1f else 0.6f),
|
|
|
fontSize = 14.sp,
|
|
|
lineHeight = 18.sp,
|
|
|
modifier = Modifier.weight(1f),
|
|
|
)
|
|
|
Icon(
|
|
|
- painter = painterResource(R.drawable.back), contentDescription = "", modifier = Modifier
|
|
|
+ painter = painterResource(R.drawable.back),
|
|
|
+ contentDescription = "",
|
|
|
+ modifier = Modifier
|
|
|
.rotate(if (expanded) -90f else 180f)
|
|
|
- .size(12.dp), tint = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
+ .size(12.dp),
|
|
|
+ tint = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
)
|
|
|
}
|
|
|
val widthDp = with(density) { width.toDp() }
|
|
|
@@ -332,11 +417,25 @@ fun FormSelect(
|
|
|
options.forEach { option ->
|
|
|
DropdownMenuItem(
|
|
|
modifier = Modifier.fillMaxWidth(),
|
|
|
- text = { Text(option.label) },
|
|
|
+ text = {
|
|
|
+ Text(
|
|
|
+ option.label,
|
|
|
+ color = if (values.contains(option.value)) MaterialTheme.colorScheme.primary else Text
|
|
|
+ )
|
|
|
+ },
|
|
|
onClick = {
|
|
|
- opt = option
|
|
|
- onSelectChange(listOf(option.value))
|
|
|
- expanded = false
|
|
|
+ if (multiSelect) {
|
|
|
+ if (values.contains(option.value)) {
|
|
|
+ values.remove(option.value)
|
|
|
+ } else {
|
|
|
+ values.add(option.value)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ values.clear()
|
|
|
+ values.add(option.value)
|
|
|
+ }
|
|
|
+ onSelectChange(values)
|
|
|
+ if (!multiSelect) expanded = false
|
|
|
}
|
|
|
)
|
|
|
}
|
|
|
@@ -374,7 +473,12 @@ fun FormRadio(
|
|
|
.fillMaxWidth()
|
|
|
.height(40.dp), verticalAlignment = Alignment.CenterVertically
|
|
|
) {
|
|
|
- Text(label, fontSize = 14.sp, fontWeight = FontWeight.Bold, color = Text.copy(alpha = if (enable) 1f else 0.6f))
|
|
|
+ Text(
|
|
|
+ label,
|
|
|
+ fontSize = 14.sp,
|
|
|
+ fontWeight = FontWeight.Bold,
|
|
|
+ color = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
+ )
|
|
|
if (required) Text(
|
|
|
"*",
|
|
|
fontSize = 14.sp,
|
|
|
@@ -398,7 +502,94 @@ fun FormRadio(
|
|
|
.padding(horizontal = 10.dp, vertical = 5.dp),
|
|
|
verticalAlignment = Alignment.CenterVertically
|
|
|
) {
|
|
|
- RadioButton(selected = text == item.value, onClick = null, modifier = Modifier.size(14.dp), enabled = enable)
|
|
|
+ RadioButton(
|
|
|
+ selected = text == item.value,
|
|
|
+ onClick = null,
|
|
|
+ modifier = Modifier.size(14.dp),
|
|
|
+ enabled = enable
|
|
|
+ )
|
|
|
+ Text(
|
|
|
+ text = item.label,
|
|
|
+ fontSize = 15.sp,
|
|
|
+ modifier = Modifier.padding(start = 10.dp),
|
|
|
+ color = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 表单单选组件
|
|
|
+ *
|
|
|
+ * @param label 标题
|
|
|
+ * @param value 当前选中
|
|
|
+ * @param options 可选列表
|
|
|
+ * @param onSelectChange 当前选中
|
|
|
+ */
|
|
|
+@OptIn(ExperimentalLayoutApi::class)
|
|
|
+@Composable
|
|
|
+fun FormCheckbox(
|
|
|
+ label: String,
|
|
|
+ value: List<String>,
|
|
|
+ options: List<FormOption>,
|
|
|
+ onSelectChange: (List<String>) -> Unit,
|
|
|
+ required: Boolean = false,
|
|
|
+ enable: Boolean = true,
|
|
|
+) {
|
|
|
+ val values = remember { mutableStateListOf<String>() }
|
|
|
+ LaunchedEffect(Unit) {
|
|
|
+ values.clear()
|
|
|
+ values.addAll(value)
|
|
|
+ }
|
|
|
+ Column(
|
|
|
+ Modifier
|
|
|
+ .fillMaxWidth()
|
|
|
+ .heightIn(max = 160.dp)
|
|
|
+ ) {
|
|
|
+ Row(
|
|
|
+ Modifier
|
|
|
+ .fillMaxWidth()
|
|
|
+ .height(40.dp), verticalAlignment = Alignment.CenterVertically
|
|
|
+ ) {
|
|
|
+ Text(
|
|
|
+ label,
|
|
|
+ fontSize = 14.sp,
|
|
|
+ fontWeight = FontWeight.Bold,
|
|
|
+ color = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
+ )
|
|
|
+ if (required) Text(
|
|
|
+ "*",
|
|
|
+ fontSize = 14.sp,
|
|
|
+ color = Color(0xFFFF4D4F).copy(alpha = if (enable) 1f else 0.6f),
|
|
|
+ modifier = Modifier.padding(start = 3.dp)
|
|
|
+ )
|
|
|
+ }
|
|
|
+ FlowRow(
|
|
|
+ Modifier
|
|
|
+ .fillMaxWidth()
|
|
|
+ .heightIn(max = 120.dp)
|
|
|
+ ) {
|
|
|
+ options.forEach { item ->
|
|
|
+ Row(
|
|
|
+ modifier = Modifier
|
|
|
+ .clip(RoundedCornerShape(12.dp))
|
|
|
+ .clickable(onClick = {
|
|
|
+ if (values.contains(item.value))
|
|
|
+ values.remove(item.value)
|
|
|
+ else values.add(item.value)
|
|
|
+ onSelectChange(values)
|
|
|
+ }, enabled = enable)
|
|
|
+ .padding(horizontal = 10.dp, vertical = 5.dp),
|
|
|
+ verticalAlignment = Alignment.CenterVertically
|
|
|
+ ) {
|
|
|
+ Checkbox(
|
|
|
+ checked = values.contains(item.value),
|
|
|
+ onCheckedChange = null,
|
|
|
+ modifier = Modifier.size(14.dp),
|
|
|
+ enabled = enable
|
|
|
+ )
|
|
|
Text(
|
|
|
text = item.label,
|
|
|
fontSize = 15.sp,
|
|
|
@@ -419,12 +610,30 @@ fun FormRadio(
|
|
|
* @param onSelectChange 当前选中
|
|
|
*/
|
|
|
@Composable
|
|
|
-fun FormDateSelect(label: String, value: List<String>, onSelectChange: (List<String>) -> Unit, required: Boolean = false, enable: Boolean = true) {
|
|
|
- var date by remember { mutableStateOf((value.getOrNull(0) ?: "").dateToTimestamp("yyyy/MM/dd HH:mm")) }
|
|
|
+fun FormDateSelect(
|
|
|
+ label: String,
|
|
|
+ value: List<String>,
|
|
|
+ onSelectChange: (List<String>) -> Unit,
|
|
|
+ required: Boolean = false,
|
|
|
+ enable: Boolean = true
|
|
|
+) {
|
|
|
+ var date by remember {
|
|
|
+ mutableStateOf(
|
|
|
+ (value.getOrNull(0) ?: "").dateToTimestamp("yyyy/MM/dd HH:mm")
|
|
|
+ )
|
|
|
+ }
|
|
|
val picker = CardDatePickerDialog.builder(LocalContext.current)
|
|
|
.setTitle("请选择日期")
|
|
|
.setDefaultTime(date)
|
|
|
- .setDisplayType(mutableListOf(DateTimeConfig.YEAR, DateTimeConfig.MONTH, DateTimeConfig.DAY, DateTimeConfig.HOUR, DateTimeConfig.MIN))
|
|
|
+ .setDisplayType(
|
|
|
+ mutableListOf(
|
|
|
+ DateTimeConfig.YEAR,
|
|
|
+ DateTimeConfig.MONTH,
|
|
|
+ DateTimeConfig.DAY,
|
|
|
+ DateTimeConfig.HOUR,
|
|
|
+ DateTimeConfig.MIN
|
|
|
+ )
|
|
|
+ )
|
|
|
.setPickerLayout(R.layout.date_picker)
|
|
|
.showBackNow(false)
|
|
|
.showFocusDateInfo(false)
|
|
|
@@ -445,7 +654,12 @@ fun FormDateSelect(label: String, value: List<String>, onSelectChange: (List<Str
|
|
|
.height(40.dp),
|
|
|
verticalAlignment = Alignment.CenterVertically
|
|
|
) {
|
|
|
- Text(label, fontSize = 14.sp, fontWeight = FontWeight.Bold, color = Text.copy(alpha = if (enable) 1f else 0.6f))
|
|
|
+ Text(
|
|
|
+ label,
|
|
|
+ fontSize = 14.sp,
|
|
|
+ fontWeight = FontWeight.Bold,
|
|
|
+ color = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
+ )
|
|
|
if (required) Text(
|
|
|
"*",
|
|
|
fontSize = 14.sp,
|
|
|
@@ -507,7 +721,12 @@ fun FormDateRangeSelect(
|
|
|
.height(40.dp),
|
|
|
verticalAlignment = Alignment.CenterVertically
|
|
|
) {
|
|
|
- Text(label, fontSize = 14.sp, fontWeight = FontWeight.Bold, color = Text.copy(alpha = if (enable) 1f else 0.6f))
|
|
|
+ Text(
|
|
|
+ label,
|
|
|
+ fontSize = 14.sp,
|
|
|
+ fontWeight = FontWeight.Bold,
|
|
|
+ color = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
+ )
|
|
|
if (required) Text(
|
|
|
"*",
|
|
|
fontSize = 14.sp,
|
|
|
@@ -533,7 +752,13 @@ fun FormDateRangeSelect(
|
|
|
CardDatePickerDialog.builder(ctx)
|
|
|
.setTitle("请选择开始日期")
|
|
|
.setDefaultTime(start)
|
|
|
- .setDisplayType(mutableListOf(DateTimeConfig.YEAR, DateTimeConfig.MONTH, DateTimeConfig.DAY))
|
|
|
+ .setDisplayType(
|
|
|
+ mutableListOf(
|
|
|
+ DateTimeConfig.YEAR,
|
|
|
+ DateTimeConfig.MONTH,
|
|
|
+ DateTimeConfig.DAY
|
|
|
+ )
|
|
|
+ )
|
|
|
.setPickerLayout(R.layout.date_range_picker)
|
|
|
.showBackNow(false)
|
|
|
.showFocusDateInfo(false)
|
|
|
@@ -548,7 +773,11 @@ fun FormDateRangeSelect(
|
|
|
lineHeight = 26.sp,
|
|
|
color = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
)
|
|
|
- Text("-", modifier = Modifier.padding(horizontal = 5.dp), color = Text.copy(alpha = if (enable) 1f else 0.6f))
|
|
|
+ Text(
|
|
|
+ "-",
|
|
|
+ modifier = Modifier.padding(horizontal = 5.dp),
|
|
|
+ color = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
+ )
|
|
|
Text(
|
|
|
end.format("yyyy/MM/dd"),
|
|
|
modifier = Modifier
|
|
|
@@ -560,7 +789,13 @@ fun FormDateRangeSelect(
|
|
|
CardDatePickerDialog.builder(ctx)
|
|
|
.setTitle("请选择结束日期")
|
|
|
.setDefaultTime(end)
|
|
|
- .setDisplayType(mutableListOf(DateTimeConfig.YEAR, DateTimeConfig.MONTH, DateTimeConfig.DAY))
|
|
|
+ .setDisplayType(
|
|
|
+ mutableListOf(
|
|
|
+ DateTimeConfig.YEAR,
|
|
|
+ DateTimeConfig.MONTH,
|
|
|
+ DateTimeConfig.DAY
|
|
|
+ )
|
|
|
+ )
|
|
|
.setPickerLayout(R.layout.date_range_picker)
|
|
|
.showBackNow(false)
|
|
|
.showFocusDateInfo(false)
|
|
|
@@ -580,6 +815,81 @@ fun FormDateRangeSelect(
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 表单时间选择组件
|
|
|
+ *
|
|
|
+ * @param label 标题
|
|
|
+ * @param value 当前选中
|
|
|
+ * @param onSelectChange 当前选中
|
|
|
+ */
|
|
|
+@Composable
|
|
|
+fun FormTimeSelect(
|
|
|
+ label: String,
|
|
|
+ value: List<String>,
|
|
|
+ onSelectChange: (List<String>) -> Unit,
|
|
|
+ required: Boolean = false,
|
|
|
+ enable: Boolean = true
|
|
|
+) {
|
|
|
+ var date by remember {
|
|
|
+ mutableStateOf((value.getOrNull(0) ?: "").dateToTimestamp("yyyy/MM/dd HH:mm:ss"))
|
|
|
+ }
|
|
|
+ val picker = CardDatePickerDialog.builder(LocalContext.current)
|
|
|
+ .setTitle("请选择时间")
|
|
|
+ .setDefaultTime(date)
|
|
|
+ .setDisplayType(
|
|
|
+ mutableListOf(DateTimeConfig.HOUR, DateTimeConfig.MIN)
|
|
|
+ )
|
|
|
+ .setPickerLayout(R.layout.date_picker)
|
|
|
+ .showBackNow(false)
|
|
|
+ .showFocusDateInfo(false)
|
|
|
+ .showDateLabel(false)
|
|
|
+ .setOnChoose { timestamp ->
|
|
|
+ date = timestamp
|
|
|
+ onSelectChange(listOf(timestamp.toString()))
|
|
|
+ }.build()
|
|
|
+
|
|
|
+ Column(
|
|
|
+ Modifier
|
|
|
+ .fillMaxWidth()
|
|
|
+ .heightIn(max = 90.dp)
|
|
|
+ ) {
|
|
|
+ Row(
|
|
|
+ Modifier
|
|
|
+ .fillMaxWidth()
|
|
|
+ .height(40.dp),
|
|
|
+ verticalAlignment = Alignment.CenterVertically
|
|
|
+ ) {
|
|
|
+ Text(
|
|
|
+ label,
|
|
|
+ fontSize = 14.sp,
|
|
|
+ fontWeight = FontWeight.Bold,
|
|
|
+ color = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
+ )
|
|
|
+ if (required) Text(
|
|
|
+ "*",
|
|
|
+ fontSize = 14.sp,
|
|
|
+ color = Color(0xFFFF4D4F).copy(alpha = if (enable) 1f else 0.6f),
|
|
|
+ modifier = Modifier.padding(start = 3.dp)
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ Text(
|
|
|
+ date.format("HH:mm"),
|
|
|
+ modifier = Modifier
|
|
|
+ .fillMaxWidth()
|
|
|
+ .height(46.dp)
|
|
|
+ .border(1.dp, shape = RoundedCornerShape(6.dp), color = Color(0xFFE5E6EB))
|
|
|
+ .clip(RoundedCornerShape(6.dp))
|
|
|
+ .clickable(onClick = { picker.show() }, enabled = enable)
|
|
|
+ .padding(10.dp),
|
|
|
+ fontSize = 14.sp,
|
|
|
+ lineHeight = 26.sp,
|
|
|
+ color = Text.copy(alpha = if (enable) 1f else 0.6f)
|
|
|
+ )
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* 将服务端返回的表单String JSON数组转化为可用的表单数据
|
|
|
*/
|