init
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
package com.sw.inbound.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.paint
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import com.sw.inbound.GlobalKey
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.ui.page.HomeScreen
|
||||
import com.sw.inbound.ui.page.LoginScreen
|
||||
import com.sw.inbound.ui.page.PurchaseOrderScreen
|
||||
import com.sw.inbound.ui.page.ReceiptProductScreen
|
||||
import com.sw.inbound.ui.page.SelfProcurementScreen
|
||||
import com.sw.inbound.ui.page.TestScreen
|
||||
import com.sw.inbound.ui.weight.GlobalLoading
|
||||
import com.sw.inbound.utils.SPUtil
|
||||
import com.sw.inbound.utils.ToastUtils
|
||||
|
||||
@Composable
|
||||
fun AppScreen(
|
||||
onBackRequest: () -> Unit
|
||||
) {
|
||||
val navController = rememberNavController()
|
||||
val currentBackStackEntry by navController.currentBackStackEntryAsState()
|
||||
var canBack by remember { mutableStateOf(false) }
|
||||
|
||||
// 拦截物理返回键
|
||||
// BackHandler(
|
||||
// onBack = {
|
||||
// val currentRoute = currentBackStackEntry?.destination?.route
|
||||
// Timber.d("BackHandler currentRouter = ${currentRoute}")
|
||||
// if (currentRoute == Screen.Home.route && !canBack) {
|
||||
// ToastUtils.showToast("再次点击退出")
|
||||
// canBack = true
|
||||
// } else if (currentRoute == Screen.Login.route) {
|
||||
// onBackRequest()
|
||||
// } else {
|
||||
// navController.popBackStack()
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
//
|
||||
// BackHandler(canBack) {
|
||||
// Timber.d("canBack = $canBack")
|
||||
// if (canBack) {
|
||||
// onBackRequest()
|
||||
// }
|
||||
// }
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.paint(painter = painterResource(R.mipmap.bg)),
|
||||
containerColor = Color.Transparent,
|
||||
content = { padding ->
|
||||
Box {
|
||||
// Image(
|
||||
// painter = painterResource(R.mipmap.bg),
|
||||
// contentDescription = null,
|
||||
// modifier = Modifier.fillMaxSize(),
|
||||
// contentScale = ContentScale.Crop
|
||||
// )
|
||||
|
||||
NavHost(padding, navController, onBackRequest)
|
||||
|
||||
}
|
||||
}
|
||||
)
|
||||
ToastUtils.ToastComposable()
|
||||
GlobalLoading() // 全局Loading
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NavHost(
|
||||
padding: PaddingValues,
|
||||
navController: NavHostController,
|
||||
onBackRequest: () -> Unit = {}
|
||||
) {
|
||||
val spUtil = SPUtil.getInstance()
|
||||
val token = spUtil.get(GlobalKey.KEY_TOKEN, "")!!
|
||||
NavHost(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding),
|
||||
navController = navController,
|
||||
startDestination = if (token.isEmpty()) Screen.Login.route else Screen.Home.route
|
||||
) {
|
||||
composable(Screen.Test.route) {
|
||||
TestScreen(modifier = Modifier, navController)
|
||||
}
|
||||
// 首页
|
||||
composable(Screen.Home.route) {
|
||||
HomeScreen(modifier = Modifier, navController, onBackRequest = onBackRequest)
|
||||
}
|
||||
// 登录
|
||||
composable(Screen.Login.route) {
|
||||
LoginScreen(modifier = Modifier, navController)
|
||||
}
|
||||
// 采购单入库
|
||||
composable(Screen.PurchaseOrder.route) {
|
||||
PurchaseOrderScreen(modifier = Modifier.fillMaxSize(), navController)
|
||||
}
|
||||
// 自采单
|
||||
composable(Screen.SelfProcurement.route) {
|
||||
SelfProcurementScreen(modifier = Modifier, navController)
|
||||
}
|
||||
// 收货
|
||||
composable(
|
||||
Screen.ReceiptProduct.route,
|
||||
arguments = listOf(
|
||||
navArgument(name = "id", builder = { type = NavType.IntType }),
|
||||
navArgument(name = "supplierId", builder = { type = NavType.IntType })
|
||||
)
|
||||
) { backStackEntry ->
|
||||
val id = backStackEntry.arguments?.getInt("id") ?: 0
|
||||
val supplierId = backStackEntry.arguments?.getInt("supplierId") ?: 0
|
||||
ReceiptProductScreen(modifier = Modifier, navController, id, supplierId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Screen(val route: String) {
|
||||
data object Home : Screen("home")
|
||||
data object Login : Screen("login")
|
||||
|
||||
// 采购单入库
|
||||
data object PurchaseOrder : Screen("purchase_order")
|
||||
|
||||
// 自采单入库
|
||||
data object SelfProcurement : Screen("self_procurement")
|
||||
|
||||
// 收货
|
||||
data object ReceiptProduct : Screen("receipt_product?id={id}&supplierId={supplierId}") {
|
||||
fun createRoute(id: Int, supplierId: Int) =
|
||||
"receipt_product?id=${id}&supplierId=${supplierId}"
|
||||
}
|
||||
|
||||
// 添加物品
|
||||
data object AddProduct : Screen("addProduct")
|
||||
data object Test : Screen("Test")
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.sw.inbound.ui.page
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.ui.Screen
|
||||
import com.sw.inbound.ui.weight.TopTitleBar
|
||||
import com.sw.inbound.viewmodel.UserViewModel
|
||||
import timber.log.Timber
|
||||
|
||||
@Composable
|
||||
fun HomeScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
navController: NavHostController = rememberNavController(),
|
||||
viewModel: UserViewModel = hiltViewModel<UserViewModel>(),
|
||||
onBackRequest: () -> Unit = {}
|
||||
) {
|
||||
val user by viewModel.user.collectAsState()
|
||||
|
||||
// 避免每次进入都获取字典类型
|
||||
LaunchedEffect(Unit) {
|
||||
Timber.d("LaunchedEffect(Unit)")
|
||||
viewModel.getInitInfo()
|
||||
}
|
||||
|
||||
BackHandler {
|
||||
onBackRequest()
|
||||
}
|
||||
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
TopTitleBar(user = user, onLogoutClick = {
|
||||
viewModel.logout()
|
||||
navController.navigate(Screen.Login.route) {
|
||||
popUpTo(Screen.Home.route) {
|
||||
inclusive = true
|
||||
}
|
||||
}
|
||||
})
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.width(595.dp)
|
||||
.height(477.dp)
|
||||
.clickable() {
|
||||
navController.navigate(Screen.PurchaseOrder.route)
|
||||
},
|
||||
painter = painterResource(R.mipmap.ic_order_purchase),
|
||||
contentDescription = "采购单入库"
|
||||
)
|
||||
Spacer(modifier = Modifier.width(15.dp))
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.width(595.dp)
|
||||
.height(477.dp)
|
||||
.clickable {
|
||||
navController.navigate(Screen.SelfProcurement.route)
|
||||
},
|
||||
painter = painterResource(R.mipmap.ic_order_self_procurement),
|
||||
contentDescription = "自采入库"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package com.sw.inbound.ui.page
|
||||
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.sw.inbound.GlobalData
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.ext.bold
|
||||
import com.sw.inbound.ext.textAlign
|
||||
import com.sw.inbound.ext.withSize
|
||||
import com.sw.inbound.ui.Screen
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
import com.sw.inbound.ui.weight.CustomButton
|
||||
import com.sw.inbound.utils.ToastUtils
|
||||
import com.sw.inbound.viewmodel.UserViewModel
|
||||
import timber.log.Timber
|
||||
|
||||
@Composable
|
||||
fun LoginScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
controller: NavController = rememberNavController(),
|
||||
viewModel: UserViewModel = hiltViewModel<UserViewModel>()
|
||||
) {
|
||||
var username by remember { mutableStateOf<String>("padAdmin") }
|
||||
var password by remember { mutableStateOf<String>("123123") }
|
||||
|
||||
// val user by viewModel.user.collectAsState()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
Timber.d(" user =")
|
||||
viewModel.user.collect {
|
||||
Timber.d(" user collect = ${it}")
|
||||
if (it != null) {
|
||||
GlobalData.user = it
|
||||
controller.navigate(Screen.Home.route) {
|
||||
Timber.d("登录成功,跳转到主界面")
|
||||
controller.popBackStack()
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (user != null){
|
||||
// controller.navigate(Screen.Home.route) {
|
||||
// controller.popBackStack()
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(text = "出入库管理", style = AppTypography.black141428TextStyle.withSize(60.sp).bold())
|
||||
Spacer(modifier = Modifier.height(91.dp))
|
||||
|
||||
UserInputView(value = username, placeholderValue = "请输入用户名", onValueChange = {
|
||||
username = it
|
||||
})
|
||||
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
|
||||
UserInputView(value = password, placeholderValue = "请输入密码", onValueChange = {
|
||||
password = it
|
||||
}, isPassword = true)
|
||||
|
||||
Spacer(modifier = Modifier.height(90.dp))
|
||||
CustomButton(
|
||||
modifier = modifier
|
||||
.width(885.dp)
|
||||
.height(120.dp),
|
||||
text = "登录",
|
||||
onClick = {
|
||||
if (username.isEmpty() || password.isEmpty()) {
|
||||
ToastUtils.showToast("用户名或密码不能为空")
|
||||
return@CustomButton
|
||||
}
|
||||
viewModel.login(username, password)
|
||||
// viewModel.test()
|
||||
},
|
||||
borderColor = colorResource(R.color.blue),
|
||||
textColor = colorResource(R.color.white),
|
||||
fontSize = 36.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun UserInputView(
|
||||
value: String,
|
||||
placeholderValue: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
isPassword: Boolean = false,
|
||||
isShowPassword: Boolean = false
|
||||
) {
|
||||
val backgroundColor = Color.White.copy(alpha = 0.37f)
|
||||
|
||||
TextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
modifier = Modifier
|
||||
.height(120.dp)
|
||||
.width(885.dp)
|
||||
.border(
|
||||
width = 2.dp,
|
||||
color = backgroundColor,
|
||||
shape = RoundedCornerShape(10.dp)
|
||||
),
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = backgroundColor,
|
||||
unfocusedContainerColor = backgroundColor,
|
||||
disabledContainerColor = backgroundColor,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent
|
||||
),
|
||||
// 密码输入相关设置
|
||||
visualTransformation = if (isPassword && !isShowPassword) {
|
||||
PasswordVisualTransformation()
|
||||
} else {
|
||||
VisualTransformation.None
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = if (isPassword) KeyboardType.Password else KeyboardType.Text,
|
||||
imeAction = if (isPassword) ImeAction.Done else ImeAction.Next
|
||||
),
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
textStyle = AppTypography.gray96a0aaTextStyle.withSize(30.sp).textAlign(TextAlign.Center),
|
||||
placeholder = {
|
||||
Text(
|
||||
text = placeholderValue,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center, // 占位符水平居中
|
||||
style = AppTypography.gray96a0aaTextStyle.textAlign(TextAlign.Center)
|
||||
)
|
||||
},
|
||||
singleLine = true // 确保单行输入(避免换行导致高度变化)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
package com.sw.inbound.ui.page
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.ext.dashedBorder
|
||||
import com.sw.inbound.ext.toFormattedString
|
||||
import com.sw.inbound.model.response.SupplierInfo
|
||||
import com.sw.inbound.ui.Screen
|
||||
import com.sw.inbound.ui.theme.AppTypography.blackTextStyle
|
||||
import com.sw.inbound.ui.theme.AppTypography.grayTextStyle
|
||||
import com.sw.inbound.ui.weight.BottomActionBar
|
||||
import com.sw.inbound.ui.weight.TopTitleBar
|
||||
import com.sw.inbound.viewmodel.ProductViewModel
|
||||
|
||||
@Preview(
|
||||
widthDp = 1920,
|
||||
heightDp = 1080,
|
||||
showBackground = true
|
||||
)
|
||||
@Composable
|
||||
fun PurchaseOrderScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
navController: NavHostController = rememberNavController(),
|
||||
viewModel: ProductViewModel = hiltViewModel<ProductViewModel>()
|
||||
) {
|
||||
val products by viewModel.supplierList.collectAsState()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.getOrderList()
|
||||
}
|
||||
|
||||
Column {
|
||||
TopTitleBar()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 10.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.bg_listview),
|
||||
contentDescription = "背景",
|
||||
modifier = Modifier
|
||||
.width(1900.dp)
|
||||
.height(880.dp),
|
||||
contentScale = ContentScale.FillBounds
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier.padding(
|
||||
start = 30.dp,
|
||||
end = 30.dp,
|
||||
top = 30.dp,
|
||||
bottom = 90.dp
|
||||
)
|
||||
) {
|
||||
if (products.isEmpty()) {
|
||||
PurchaseEmptyItem()
|
||||
} else {
|
||||
LazyRow(
|
||||
modifier = modifier
|
||||
// .paint(painterResource(R.mipmap.bg_listview))
|
||||
// .fillMaxSize()
|
||||
// .background(
|
||||
// color = Color(0x80FFFFFF),
|
||||
// shape = RoundedCornerShape(12.dp) // 圆角背景
|
||||
// )
|
||||
.padding(10.dp),
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(30.dp)
|
||||
) {
|
||||
items(items = products, key = { it!!.id }) {
|
||||
PurchaseOrderItem(it!!) {
|
||||
navController.navigate(
|
||||
Screen.ReceiptProduct.createRoute(
|
||||
it.id,
|
||||
it.supplierId
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BottomActionBar(
|
||||
modifier = Modifier, onLeftButtonClick = {
|
||||
navController.popBackStack()
|
||||
}, onRight2ButtonClick = {
|
||||
navController.navigate(Screen.SelfProcurement.route)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PurchaseEmptyItem() {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Image(painter = painterResource(R.mipmap.ic_empty), contentDescription = "暂无数据")
|
||||
Text(
|
||||
text = "暂无数据", style = TextStyle(
|
||||
fontSize = 30.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = colorResource(R.color.title)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PurchaseOrderItem(product: SupplierInfo, onItemClick: (SupplierInfo) -> Unit) {
|
||||
|
||||
val (receiptStatusStyle, statusLabel) = when (product.receiveStatus) {
|
||||
1 -> blackTextStyle to "已关闭"
|
||||
2 -> blackTextStyle to "已完成"
|
||||
3 -> blackTextStyle.copy(
|
||||
color = colorResource(R.color.red)
|
||||
) to "未收货"
|
||||
|
||||
4 -> blackTextStyle.copy(
|
||||
color = colorResource(R.color.origin)
|
||||
) to "部分收货"
|
||||
|
||||
else -> blackTextStyle to "已关闭"
|
||||
}
|
||||
|
||||
val itemSpace = 29.dp
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = Color.White.copy(alpha = 0.37f),
|
||||
shape = RoundedCornerShape(10.dp) // 圆角背景
|
||||
)
|
||||
.clickable {
|
||||
onItemClick(product)
|
||||
}
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(580.dp)
|
||||
.padding(horizontal = 30.dp, vertical = 30.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(0.dp)
|
||||
) {
|
||||
Text(
|
||||
text = product.supplierName,
|
||||
modifier = Modifier.padding(top = 25.dp),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = TextStyle(
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 30.sp,
|
||||
color = colorResource(R.color.black)
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(itemSpace))
|
||||
Text(
|
||||
text = "单号 ${product.receiveCode}",
|
||||
maxLines = 1,
|
||||
style = grayTextStyle
|
||||
)
|
||||
Spacer(modifier = Modifier.height(itemSpace))
|
||||
HorizontalDivider(
|
||||
thickness = 1.dp,
|
||||
color = colorResource(R.color.divider)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(40.dp))
|
||||
Text(
|
||||
text = "物品(项)",
|
||||
style = grayTextStyle
|
||||
)
|
||||
Spacer(modifier = Modifier.height(22.dp))
|
||||
Text(
|
||||
text = product.goodCount.toFormattedString(),
|
||||
style = TextStyle(
|
||||
color = colorResource(R.color.black),
|
||||
fontSize = 90.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(22.dp))
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.dashedBorder(
|
||||
strokeWidth = 2.dp,
|
||||
color = Color(0xFFBDC5CE),
|
||||
cornerRadiusDp = 10.dp
|
||||
)
|
||||
.padding(horizontal = 72.dp, vertical = 27.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(text = "采购日期", style = grayTextStyle)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(text = product.purchaseDate ?: "", style = blackTextStyle)
|
||||
}
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(text = "到货日期", style = grayTextStyle)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(text = product.receiveDate ?: "-", style = blackTextStyle)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(28.dp))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Row {
|
||||
Text("收货状态:", style = grayTextStyle)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(statusLabel, style = receiptStatusStyle)
|
||||
}
|
||||
|
||||
Row {
|
||||
Text("采购人:", style = grayTextStyle)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
|
||||
Text(product.receiveUser, style = blackTextStyle)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(itemSpace))
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(80.dp),
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(0xFF009632).copy(alpha = 1f),
|
||||
contentColor = colorResource(R.color.white)
|
||||
), onClick = {
|
||||
onItemClick(product)
|
||||
}) {
|
||||
Text(
|
||||
if (product.receiveStatus == 4) "部分收货" else "收货",
|
||||
style = TextStyle(fontWeight = FontWeight.Bold, fontSize = 30.sp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,613 @@
|
||||
package com.sw.inbound.ui.page
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.sw.inbound.GlobalData
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.ext.bold
|
||||
import com.sw.inbound.ext.toSafeFloat
|
||||
import com.sw.inbound.ext.withSize
|
||||
import com.sw.inbound.model.request.UploadInfo
|
||||
import com.sw.inbound.model.response.DictType
|
||||
import com.sw.inbound.model.response.GoodsInfo
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
import com.sw.inbound.ui.theme.AppTypography.black141428TextStyle
|
||||
import com.sw.inbound.ui.theme.AppTypography.gray96a0aaTextStyle
|
||||
import com.sw.inbound.ui.weight.BottomActionBar
|
||||
import com.sw.inbound.ui.weight.CustomDropdownTextField
|
||||
import com.sw.inbound.ui.weight.CustomSpinner
|
||||
import com.sw.inbound.ui.weight.CustomTextField
|
||||
import com.sw.inbound.ui.weight.IdentityView
|
||||
import com.sw.inbound.ui.weight.InputType
|
||||
import com.sw.inbound.ui.weight.ProductListView
|
||||
import com.sw.inbound.ui.weight.RowInputLayout
|
||||
import com.sw.inbound.ui.weight.TopTitleBar
|
||||
import com.sw.inbound.ui.weight.dialog.ReceiptTipDialog
|
||||
import com.sw.inbound.viewmodel.ReceiptViewModel
|
||||
import timber.log.Timber
|
||||
|
||||
@Composable
|
||||
fun ReceiptProductScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
controller: NavController = rememberNavController(),
|
||||
id: Int,
|
||||
supplierId: Int,
|
||||
viewModel: ReceiptViewModel = hiltViewModel<ReceiptViewModel>()
|
||||
) {
|
||||
val adjustState by viewModel.adjustState.collectAsState()
|
||||
val showDialog by viewModel.showReceiptDialog.collectAsState()
|
||||
val orders by viewModel.orders.collectAsState()
|
||||
val receiptResult by viewModel.receiptResult.collectAsState()
|
||||
|
||||
LaunchedEffect(receiptResult) {
|
||||
if (receiptResult) {
|
||||
controller.popBackStack()
|
||||
}
|
||||
}
|
||||
|
||||
Column(modifier = modifier) {
|
||||
TopTitleBar()
|
||||
Row(
|
||||
modifier = modifier
|
||||
.padding(30.dp)
|
||||
.weight(1f)
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.background(
|
||||
color = Color(0x80FFFFFF),
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
)
|
||||
.fillMaxWidth()
|
||||
.padding(30.dp)
|
||||
) {
|
||||
// 左侧列表
|
||||
ReceiptLeftView(modifier.weight(1f), viewModel, id)
|
||||
|
||||
// 未调整,显示右侧界面
|
||||
if (!adjustState) {
|
||||
Spacer(modifier = Modifier.width(30.dp))
|
||||
// 右侧编辑
|
||||
ReceiptRightView(modifier.width(580.dp), viewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
BottomActionBar(
|
||||
modifier = Modifier,
|
||||
right2ButtonText = "确认收货",
|
||||
onLeftButtonClick = {
|
||||
controller.popBackStack()
|
||||
},
|
||||
onRight2ButtonClick = {
|
||||
viewModel.updateReceiptDialog(true)
|
||||
})
|
||||
}
|
||||
|
||||
if (showDialog) {
|
||||
ReceiptTipDialog(isWarn = viewModel.hasWrongCount(), onCancelClick = {
|
||||
Timber.d("返回")
|
||||
viewModel.updateReceiptDialog(false)
|
||||
}, onConfirmClick = { isFull ->
|
||||
Timber.d(if (isFull) "确认收货" else "部分收货")
|
||||
viewModel.updateReceiptDialog(false)
|
||||
val uploadInfo = UploadInfo(id = id, receiveGoodsInfos = orders)
|
||||
if (isFull) {
|
||||
viewModel.confirmReceipt(uploadInfo)
|
||||
} else {
|
||||
uploadInfo.supplierId = supplierId
|
||||
viewModel.partialReceipt(uploadInfo)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ReceiptLeftView(
|
||||
modifier: Modifier,
|
||||
viewModel: ReceiptViewModel,
|
||||
id: Int
|
||||
) {
|
||||
val warehouseTypeList = GlobalData.warehouseTypeList // receiptViewModel.getStoreList()
|
||||
val currentPurchaseInfo by viewModel.currentPurchaseInfo.collectAsState()
|
||||
|
||||
LaunchedEffect(id) {
|
||||
viewModel.getReceiveDetail(id)
|
||||
}
|
||||
|
||||
currentPurchaseInfo?.let {
|
||||
Column(modifier) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Column {
|
||||
Text(
|
||||
"供应商:${currentPurchaseInfo?.supplierName}",
|
||||
style = black141428TextStyle.bold()
|
||||
)
|
||||
Spacer(modifier = Modifier.height(18.dp))
|
||||
Row {
|
||||
Text(
|
||||
"采购单号:${currentPurchaseInfo?.purCode}",
|
||||
style = gray96a0aaTextStyle.copy(fontSize = 20.sp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(120.dp))
|
||||
Text(
|
||||
"收货单号:${currentPurchaseInfo?.receiveCode}",
|
||||
style = gray96a0aaTextStyle.copy(fontSize = 20.sp)
|
||||
)
|
||||
}
|
||||
}
|
||||
CustomSpinner(
|
||||
items = warehouseTypeList,
|
||||
selectedItem = currentPurchaseInfo!!.warehouseName,
|
||||
onItemSelected = { value ->
|
||||
val currentPurchaseInfo1 = currentPurchaseInfo!!.copy()
|
||||
currentPurchaseInfo1.warehouseName = value.value
|
||||
viewModel.updateCurrentPurchaseInfo(currentPurchaseInfo1)
|
||||
viewModel.updateAllPurchaseStore(store = value)
|
||||
})
|
||||
}
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
|
||||
TabScreen(viewModel)
|
||||
// LazyColumn(
|
||||
// verticalArrangement = Arrangement.spacedBy(30.dp)
|
||||
// ) {
|
||||
// items(items = purchaseOrderList, key = { it.id }) {
|
||||
// ReceiptItem(it, modifier)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TabScreen(viewModel: ReceiptViewModel) {
|
||||
var selectedTabIndex by remember { mutableIntStateOf(0) }
|
||||
|
||||
val purchaseUnadjustedList by viewModel.unadjustedOrders.collectAsState()
|
||||
val purchaseAdjustList by viewModel.adjustedOrders.collectAsState()
|
||||
|
||||
val tabs =
|
||||
listOf("未调整(${purchaseUnadjustedList.size})", "已调整(${purchaseAdjustList.size})")
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = Color.White.copy(alpha = 0.37f),
|
||||
shape = RoundedCornerShape(10.dp) // 圆角背景
|
||||
)
|
||||
.fillMaxSize()
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 30.dp), // 左上角对齐
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
|
||||
) {
|
||||
tabs.forEachIndexed { index, title ->
|
||||
val selected = selectedTabIndex == index
|
||||
Tab(
|
||||
selected = selected,
|
||||
onClick = { selectedTabIndex = index },
|
||||
modifier = Modifier
|
||||
.width(150.dp)
|
||||
// .wrapContentWidth()
|
||||
.padding(start = if (index == 1) 30.dp else 0.dp),
|
||||
selectedContentColor = Color(0xFF0032C8),
|
||||
unselectedContentColor = Color(0xFF14141E)
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = if (selected) AppTypography.BlueTextStyle else AppTypography.black141428TextStyle.bold(),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(vertical = 12.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 30.dp),
|
||||
thickness = 1.dp,
|
||||
color = colorResource(R.color.divider)
|
||||
)
|
||||
|
||||
when (selectedTabIndex) {
|
||||
// 未调整列表
|
||||
0 -> {
|
||||
UnadjustedView(purchaseUnadjustedList, viewModel)
|
||||
viewModel.updateAdjustState(false)
|
||||
}
|
||||
// 已调整列表
|
||||
1 -> {
|
||||
AdjustedView(viewModel)
|
||||
viewModel.updateAdjustState(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UnadjustedView(purchaseOrderList: List<GoodsInfo>, viewModel: ReceiptViewModel) {
|
||||
val checkedItem by viewModel.selectedItem.collectAsState()
|
||||
// 未调整view
|
||||
ProductListView(
|
||||
modifier = Modifier.padding(horizontal = 30.dp),
|
||||
productList = purchaseOrderList,
|
||||
checkedItem = checkedItem,
|
||||
onItemCheckedClick = {
|
||||
viewModel.updateSelectedItem(it)
|
||||
})
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AdjustedView(viewModel: ReceiptViewModel) {
|
||||
// 已调整view
|
||||
val purchaseAdjustList by viewModel.adjustedOrders.collectAsState()
|
||||
|
||||
LazyColumn(
|
||||
verticalArrangement = Arrangement.spacedBy(0.dp)
|
||||
) {
|
||||
items(items = purchaseAdjustList, key = { it.goodId!! }) {
|
||||
// ReceiptItem(it)
|
||||
AdjustedViewItem(it, viewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AdjustedViewItem(purchaseOrder: GoodsInfo, viewModel: ReceiptViewModel) {
|
||||
val warehouseTypeList = GlobalData.warehouseTypeList // viewModel.getStoreList()
|
||||
|
||||
Column(modifier = Modifier.padding(horizontal = 30.dp)) {
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 30.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(purchaseOrder.goodNameStr, style = AppTypography.blackTextStyle)
|
||||
Row {
|
||||
Text("采购量:", style = gray96a0aaTextStyle)
|
||||
Text(
|
||||
"${purchaseOrder.receiveCountStr}${purchaseOrder.unitNameStr}",
|
||||
style = black141428TextStyle
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 30.dp)
|
||||
) {
|
||||
AdjustedRowInputLayout(
|
||||
label = "单价", value = purchaseOrder.recUnitPriceTaxInStr,
|
||||
onValueChange = {
|
||||
viewModel.updatePurchaseItem(
|
||||
purchaseOrder = purchaseOrder.copy(
|
||||
recUnitPriceTaxIn = it.toSafeFloat()
|
||||
)
|
||||
)
|
||||
}, inputType = InputType.Decimal
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Text(text = "元", style = AppTypography.gray96a0aaTextStyle)
|
||||
Spacer(modifier = Modifier.width(50.dp))
|
||||
Text(text = "x", style = AppTypography.black141428TextStyle.bold())
|
||||
Spacer(modifier = Modifier.width(50.dp))
|
||||
AdjustedRowInputLayout(
|
||||
label = "实收", value = purchaseOrder.receivedNumStr,
|
||||
onValueChange = {
|
||||
viewModel.updatePurchaseItem(
|
||||
purchaseOrder = purchaseOrder.copy(
|
||||
receivedNum = it.toSafeFloat()
|
||||
)
|
||||
)
|
||||
}, inputType = InputType.Decimal
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Text(text = purchaseOrder.unitNameStr, style = AppTypography.gray96a0aaTextStyle)
|
||||
Spacer(modifier = Modifier.width(50.dp))
|
||||
Text(text = "=", style = AppTypography.black141428TextStyle.bold())
|
||||
Spacer(modifier = Modifier.width(50.dp))
|
||||
AdjustedRowInputLayout(
|
||||
label = "金额", value = purchaseOrder.recPriceExItemStr,
|
||||
onValueChange = {
|
||||
viewModel.updatePurchaseItem(
|
||||
purchaseOrder = purchaseOrder.copy(
|
||||
recPriceExItem = it.toSafeFloat()
|
||||
)
|
||||
)
|
||||
}, inputType = InputType.Decimal
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Text(text = "元", style = AppTypography.gray96a0aaTextStyle)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
AdjustedRowInputLayout(
|
||||
label = "仓库",
|
||||
value = purchaseOrder.warehouseNameStr,
|
||||
dropdownItems = warehouseTypeList,
|
||||
onValueChange = { value ->
|
||||
purchaseOrder.let {
|
||||
viewModel.updatePurchaseItem(
|
||||
purchaseOrder.copy(
|
||||
warehouseName = value,
|
||||
warehouseId = warehouseTypeList.find { it.value == value }?.id ?: 0
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
HorizontalDivider(thickness = 1.dp, color = colorResource(R.color.divider))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AdjustedRowInputLayout(
|
||||
label: String,
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
dropdownItems: List<DictType> = emptyList(),
|
||||
textAlign: TextAlign = TextAlign.Center,
|
||||
spinnerTextAlign: TextAlign = TextAlign.Start,
|
||||
trailingLabel: String? = null,
|
||||
inputType: InputType = InputType.Text
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.height(60.dp)
|
||||
// .fillMaxWidth()
|
||||
// .padding(horizontal = 30.dp)
|
||||
,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(label, style = AppTypography.gray96a0aaTextStyle)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
if (dropdownItems.isEmpty()) {
|
||||
CustomTextField(
|
||||
modifier = Modifier.width(180.dp),
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
textAlign = textAlign,
|
||||
trailingLabel = trailingLabel, inputType = inputType
|
||||
)
|
||||
} else {
|
||||
CustomDropdownTextField(
|
||||
modifier = Modifier.width(300.dp),
|
||||
value = value,
|
||||
dropdownItems = dropdownItems,
|
||||
onValueChange = onValueChange,
|
||||
textAlign = spinnerTextAlign
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ReceiptRightView(modifier: Modifier = Modifier, viewModel: ReceiptViewModel) {
|
||||
val searchResultList by viewModel.searchListItems.collectAsState()
|
||||
val selectedItem by viewModel.selectedItem.collectAsState()
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(
|
||||
color = Color.White.copy(alpha = 0.37f),
|
||||
shape = RoundedCornerShape(10.dp) // 圆角背景
|
||||
)
|
||||
.padding(horizontal = 30.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
if (selectedItem == null) {
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
IdentityView(list = searchResultList, showSearchView = false, onOptionSelected = {})
|
||||
} else {
|
||||
ReceiptProductEditView(viewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 收货界面右侧编辑
|
||||
*/
|
||||
@Composable
|
||||
private fun ReceiptProductEditView(
|
||||
viewModel: ReceiptViewModel,
|
||||
onConfirmClick: () -> Unit = {},
|
||||
onCancelClick: () -> Unit = {}
|
||||
) {
|
||||
val selectedItem by viewModel.selectedItem.collectAsState()
|
||||
val warehouseTypeList = GlobalData.warehouseTypeList
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
|
||||
DisposableEffect(lifecycleOwner) {
|
||||
Timber.d("开始传感器采集")
|
||||
viewModel.startSensorScale()
|
||||
onDispose {
|
||||
Timber.d("停止传感器采集")
|
||||
viewModel.stopSensorScale()
|
||||
}
|
||||
}
|
||||
|
||||
selectedItem?.let {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight()
|
||||
.padding(top = 20.dp, bottom = 20.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(20.dp)
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
text = selectedItem?.goodName ?: "-",
|
||||
style = AppTypography.black141428TextStyle.bold().withSize(30.sp),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
HorizontalDivider(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(),
|
||||
thickness = 1.dp,
|
||||
color = colorResource(R.color.divider)
|
||||
)
|
||||
|
||||
RowInputLayout(
|
||||
label = "仓库",
|
||||
value = selectedItem!!.warehouseNameStr,
|
||||
dropdownItems = warehouseTypeList,
|
||||
onValueChange = { value ->
|
||||
selectedItem?.let {
|
||||
viewModel.updateSelectedItem(
|
||||
selectedItem!!.copy(
|
||||
warehouseName = value,
|
||||
warehouseId =
|
||||
warehouseTypeList.find { it.value == value }?.id ?: 0
|
||||
// storeList.indexOf(value)
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
HorizontalDivider(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(),
|
||||
thickness = 1.dp,
|
||||
color = colorResource(R.color.divider)
|
||||
)
|
||||
|
||||
RowInputLayout(
|
||||
label = "收货数量",
|
||||
value = selectedItem!!.receivedNumStr,
|
||||
onValueChange = { value ->
|
||||
viewModel.updateCountInputState(value.isNotEmpty())
|
||||
selectedItem?.let {
|
||||
viewModel.updateSelectedItem(selectedItem!!.copy(receivedNum = value.toSafeFloat()))
|
||||
}
|
||||
},
|
||||
trailingLabel = selectedItem?.unitName,
|
||||
inputType = InputType.Decimal,
|
||||
isInitUpdate = true
|
||||
)
|
||||
|
||||
RowInputLayout(
|
||||
label = "收货单价",
|
||||
value = selectedItem!!.recUnitPriceTaxInStr,
|
||||
trailingLabel = "元",
|
||||
onValueChange = { value ->
|
||||
selectedItem?.let {
|
||||
viewModel.updateSelectedItem(selectedItem!!.copy(recUnitPriceTaxIn = value.toSafeFloat()))
|
||||
}
|
||||
}, inputType = InputType.Decimal
|
||||
)
|
||||
RowInputLayout(
|
||||
label = "收货金额",
|
||||
value = selectedItem!!.recPriceExItemStr,
|
||||
trailingLabel = "元",
|
||||
onValueChange = { value ->
|
||||
selectedItem?.let {
|
||||
viewModel.updateSelectedItem(selectedItem!!.copy(recPriceExItem = value.toSafeFloat()))
|
||||
}
|
||||
}, inputType = InputType.Decimal
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 30.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(text = "物品重量", style = AppTypography.black141428TextStyle)
|
||||
CustomTextField(
|
||||
modifier = Modifier
|
||||
.width(290.dp)
|
||||
.height(60.dp),
|
||||
value = selectedItem!!.goodsWeightStr, onValueChange = {},
|
||||
enabled = false,
|
||||
isInitUpdate = true,
|
||||
textAlign = TextAlign.End,
|
||||
trailingLabel = selectedItem!!.goodsWeightUnitStr,
|
||||
inputType = InputType.Decimal
|
||||
)
|
||||
}
|
||||
|
||||
HorizontalDivider(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(),
|
||||
thickness = 1.dp,
|
||||
color = colorResource(R.color.divider)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceAround,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(80.dp)
|
||||
) {
|
||||
Image(modifier = Modifier.clickable {
|
||||
viewModel.updateSelectedItem(null)
|
||||
}, painter = painterResource(R.mipmap.ic_btn_back), contentDescription = "返回")
|
||||
Image(modifier = Modifier.clickable {
|
||||
viewModel.updatePurchaseItem(purchaseOrder = selectedItem!!.copy(isAdjusted = true))
|
||||
viewModel.updateSelectedItem(null)
|
||||
}, painter = painterResource(R.mipmap.ic_btn_confirm), contentDescription = "确定")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,758 @@
|
||||
package com.sw.inbound.ui.page
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.sw.inbound.GlobalData
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.ext.bold
|
||||
import com.sw.inbound.ext.dashedBorder
|
||||
import com.sw.inbound.ext.isValidAmount
|
||||
import com.sw.inbound.ext.medium
|
||||
import com.sw.inbound.ext.toFormattedString
|
||||
import com.sw.inbound.ext.toSafeBigDecimal
|
||||
import com.sw.inbound.ext.toSafeDouble
|
||||
import com.sw.inbound.ext.toSafeFloat
|
||||
import com.sw.inbound.ext.withColor
|
||||
import com.sw.inbound.ext.withSize
|
||||
import com.sw.inbound.model.request.PurchaseWarehouseParam
|
||||
import com.sw.inbound.model.response.DictType
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
import com.sw.inbound.ui.theme.Black_141428
|
||||
import com.sw.inbound.ui.weight.BottomActionBar
|
||||
import com.sw.inbound.ui.weight.CameraCaptureLayout
|
||||
import com.sw.inbound.ui.weight.CustomButton
|
||||
import com.sw.inbound.ui.weight.CustomDropdownTextField
|
||||
import com.sw.inbound.ui.weight.CustomOutlinedButton
|
||||
import com.sw.inbound.ui.weight.CustomSpinner
|
||||
import com.sw.inbound.ui.weight.CustomTextField
|
||||
import com.sw.inbound.ui.weight.IdentityView
|
||||
import com.sw.inbound.ui.weight.InputType
|
||||
import com.sw.inbound.ui.weight.RowInputLayout
|
||||
import com.sw.inbound.ui.weight.SelfProcurementListItem
|
||||
import com.sw.inbound.ui.weight.TopTitleBar
|
||||
import com.sw.inbound.utils.ToastUtils
|
||||
import com.sw.inbound.viewmodel.SelfProcurementViewModel
|
||||
import timber.log.Timber
|
||||
|
||||
@Preview(
|
||||
widthDp = 1920,
|
||||
heightDp = 1080,
|
||||
showBackground = true
|
||||
)
|
||||
@Composable
|
||||
fun SelfProcurementScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
controller: NavController = rememberNavController(),
|
||||
viewModel: SelfProcurementViewModel = hiltViewModel<SelfProcurementViewModel>()
|
||||
) {
|
||||
val showDialog by viewModel.showAddProductDialog.collectAsState()
|
||||
val addToWarehouseResult by viewModel.addToWarehouseResult.collectAsState()
|
||||
|
||||
LaunchedEffect(addToWarehouseResult) {
|
||||
if (addToWarehouseResult) {
|
||||
controller.popBackStack()
|
||||
}
|
||||
}
|
||||
|
||||
Column(modifier = modifier) {
|
||||
TopTitleBar(title = "自采入库")
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 20.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.bg_listview),
|
||||
contentDescription = "背景",
|
||||
modifier = Modifier
|
||||
.width(1900.dp)
|
||||
.height(880.dp),
|
||||
contentScale = ContentScale.FillBounds
|
||||
)
|
||||
ContentView(viewModel)
|
||||
}
|
||||
BottomActionBar(onLeftButtonClick = {
|
||||
controller.popBackStack()
|
||||
}, showRight1Button = true, right1ButtonText = "清空物品", onRight1ButtonClick = {
|
||||
viewModel.clearPurchaseOrders()
|
||||
}, right2ButtonText = "提交入库", onRight2ButtonClick = {
|
||||
viewModel.addToWarehouse()
|
||||
})
|
||||
}
|
||||
|
||||
if (showDialog) {
|
||||
AddProductDialog(
|
||||
onDismiss = { viewModel.updateAddProductDialog(false) },
|
||||
modifier = Modifier,
|
||||
onCancelClick = {
|
||||
viewModel.updateAddProductDialog(false)
|
||||
viewModel.cleanGoodsAddParam()
|
||||
},
|
||||
onConfirmClick = {
|
||||
viewModel.addGoodsInfo()
|
||||
}
|
||||
) {
|
||||
// 弹窗内容
|
||||
DialogContentView(modifier, viewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContentView(
|
||||
viewModel: SelfProcurementViewModel,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(20.dp)
|
||||
) {
|
||||
ContentLeftView(viewModel)
|
||||
ContentRightView(modifier = Modifier.weight(1f), viewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContentLeftView(
|
||||
viewModel: SelfProcurementViewModel
|
||||
) {
|
||||
val warehouseList = GlobalData.warehouseTypeList // productViewModel.getStoreList()
|
||||
val productList by viewModel.purchaseList.collectAsState()
|
||||
val globalWarehouseName by viewModel.globalWarehouse.collectAsState() // remember { mutableStateOf<String>("选择仓库") }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(793.dp)
|
||||
.padding(30.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(text = "物品(项)", style = AppTypography.black141428TextStyle.bold())
|
||||
CustomSpinner(
|
||||
modifier = Modifier
|
||||
.height(70.dp)
|
||||
.width(240.dp),
|
||||
items = warehouseList,
|
||||
selectedItem = globalWarehouseName.value,
|
||||
onItemSelected = {
|
||||
// globalWarehouseName = it
|
||||
viewModel.updateGlobalWarehouse(it)
|
||||
})
|
||||
}
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
SelfProcurementListItem(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.background(
|
||||
color = Color.White.copy(alpha = 0.37f),
|
||||
shape = RoundedCornerShape(10.dp) // 圆角背景
|
||||
), productList = productList, showClose = true, onCloseClick = {
|
||||
viewModel.removePurchaseOrder(it.goodsId)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ContentRightView(
|
||||
modifier: Modifier,
|
||||
viewModel: SelfProcurementViewModel
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.width(1037.dp)
|
||||
.fillMaxHeight()
|
||||
.padding(top = 30.dp, end = 30.dp, bottom = 30.dp)
|
||||
.background(
|
||||
color = Color.White.copy(alpha = 0.37f),
|
||||
shape = RoundedCornerShape(10.dp) // 圆角背景
|
||||
)
|
||||
) {
|
||||
// 商品识别
|
||||
ProductIdentification(viewModel)
|
||||
Image(
|
||||
painter = painterResource(R.mipmap.bg_divider),
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(30.dp),
|
||||
contentDescription = ""
|
||||
)
|
||||
SelfProductEditView(viewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ProductIdentification(viewModel: SelfProcurementViewModel) {
|
||||
val searchResultList by viewModel.searchListItems.collectAsState()
|
||||
val selectItem by viewModel.selectedItem.collectAsState()
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(457.dp)
|
||||
.fillMaxHeight()
|
||||
.padding(30.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
// 菜品识别
|
||||
IdentityView(list = searchResultList, showSearchView = true, onSearchClick = {
|
||||
viewModel.searchGoodsInfoList(it)
|
||||
}, onOptionSelected = {
|
||||
viewModel.updateSelectedItemWithSearch(it)
|
||||
})
|
||||
}
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(40.dp)
|
||||
.clickable {
|
||||
viewModel.updateAddProductDialog(true)
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Image(painter = painterResource(R.mipmap.ic_add), contentDescription = "添加")
|
||||
Spacer(modifier = Modifier.width(11.dp))
|
||||
Text(text = "快速添加", style = AppTypography.BlueTextStyle.medium())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DialogContentView(
|
||||
modifier: Modifier,
|
||||
viewModel: SelfProcurementViewModel
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier.fillMaxSize()
|
||||
) {
|
||||
Text(
|
||||
text = "新增物品", style = TextStyle().bold().withSize(36.sp).withColor(
|
||||
Black_141428
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(56.dp))
|
||||
HorizontalDivider(thickness = 1.dp, color = colorResource(R.color.divider))
|
||||
Spacer(modifier = Modifier.height(58.dp))
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
// 采集窗口
|
||||
CameraCaptureLayout(modifier = Modifier.width(428.dp), onCancelClick = {
|
||||
|
||||
}, onConfirmClick = {
|
||||
|
||||
})
|
||||
Spacer(modifier = Modifier.width(60.dp))
|
||||
// 右侧输入窗口
|
||||
|
||||
DialogRightEditView(viewModel)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(60.dp))
|
||||
HorizontalDivider(thickness = 1.dp, color = colorResource(R.color.divider))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DialogRightEditView(viewModel: SelfProcurementViewModel) {
|
||||
val itemTypeList = GlobalData.goodsTypeList
|
||||
val unitTypeList = GlobalData.unitTypeList
|
||||
val storageTypeList = GlobalData.storageTypeList
|
||||
val goodsAddParam by viewModel.goodsAddParam.collectAsState()
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.spacedBy(29.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(60.dp)
|
||||
) {
|
||||
ColumnInputText(
|
||||
modifier = Modifier
|
||||
.width(474.dp),
|
||||
label = "物品名称",
|
||||
value = goodsAddParam.goodNameSr,
|
||||
onValueChange = {
|
||||
viewModel.updateGoodsAddParam(goodsAddParam.copy(goodName = it))
|
||||
})
|
||||
ColumnInputText(
|
||||
modifier = Modifier.width(474.dp),
|
||||
label = "物品编码(服务生成)",
|
||||
value = "",
|
||||
onValueChange = {
|
||||
// viewModel.updateFormState(formState.copy(goodCode = it))
|
||||
})
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(60.dp)
|
||||
) {
|
||||
ColumnInputText(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.width(474.dp),
|
||||
label = "物品类型",
|
||||
dropdownItems = itemTypeList,
|
||||
value = goodsAddParam.goodsTypeStr,
|
||||
onValueChange = { value ->
|
||||
viewModel.updateGoodsAddParam(
|
||||
goodsAddParam.copy(
|
||||
goodType =
|
||||
itemTypeList.find { it.value == value }?.id ?: 0
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
ColumnInputText(
|
||||
modifier = Modifier.width(474.dp),
|
||||
label = "储存方式",
|
||||
dropdownItems = storageTypeList,
|
||||
value = goodsAddParam.storageTypeStr,
|
||||
onValueChange = { value ->
|
||||
viewModel.updateGoodsAddParam(
|
||||
goodsAddParam.copy(
|
||||
storageType = storageTypeList.find { it.value == value }?.id ?: 0
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(60.dp)
|
||||
) {
|
||||
ColumnInputText(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.width(474.dp),
|
||||
label = "净材率",
|
||||
value = goodsAddParam.netRateStr,
|
||||
inputType = InputType.Decimal,
|
||||
onValueChange = {
|
||||
viewModel.updateGoodsAddParam(goodsAddParam.copy(netRate = it.toSafeFloat()))
|
||||
})
|
||||
ColumnInputText(
|
||||
modifier = Modifier.width(474.dp),
|
||||
value = goodsAddParam.unitIdStr,
|
||||
label = "库存单位",
|
||||
dropdownItems = unitTypeList,
|
||||
onValueChange = { value ->
|
||||
viewModel.updateGoodsAddParam(
|
||||
goodsAddParam.copy(
|
||||
unitId = unitTypeList.find { it.value == value }?.id ?: 0
|
||||
)
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Column {
|
||||
Text(text = "采购单位", style = AppTypography.black141428TextStyle)
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.height(92.dp)
|
||||
.fillMaxWidth()
|
||||
.dashedBorder()
|
||||
.padding(vertical = 16.dp, horizontal = 26.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text("1", style = AppTypography.black141428TextStyle.bold())
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
CustomDropdownTextField(
|
||||
modifier = Modifier.width(200.dp),
|
||||
value = goodsAddParam.purchaseUnitStr,
|
||||
dropdownItems = unitTypeList,
|
||||
placeholderValue = "请选择",
|
||||
onValueChange = { value ->
|
||||
viewModel.updateGoodsAddParam(
|
||||
goodsAddParam.copy(
|
||||
purchaseUnit = unitTypeList.find { it.value == value }?.id
|
||||
?: 0
|
||||
)
|
||||
)
|
||||
})
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
Text(text = "=", style = AppTypography.gray96a0aaTextStyle)
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
CustomTextField(
|
||||
modifier = Modifier.width(200.dp),
|
||||
value = goodsAddParam.purchaseValue.toFormattedString(),
|
||||
placeholderValue = "请录入",
|
||||
onValueChange = {
|
||||
viewModel.updateGoodsAddParam(goodsAddParam.copy(purchaseValue = it.toSafeFloat()))
|
||||
}, inputType = InputType.Decimal
|
||||
)
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
Text(goodsAddParam.unitIdStr, style = AppTypography.gray96a0aaTextStyle)
|
||||
|
||||
Spacer(modifier = Modifier.width(111.dp))
|
||||
|
||||
Text("单价", style = AppTypography.black141428TextStyle)
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
CustomTextField(
|
||||
modifier = Modifier.width(200.dp),
|
||||
placeholderValue = "请录入",
|
||||
value = goodsAddParam.purchasePriceStr, onValueChange = {
|
||||
if (it.isValidAmount()) {
|
||||
viewModel.updateGoodsAddParam(goodsAddParam.copy(purchasePrice = it.toSafeBigDecimal()))
|
||||
}
|
||||
}, inputType = InputType.Decimal, hasNext = false
|
||||
)
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
Text("元", style = AppTypography.gray96a0aaTextStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun ColumnInputText(
|
||||
modifier: Modifier = Modifier,
|
||||
label: String,
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit = {},
|
||||
dropdownItems: List<DictType> = emptyList(),
|
||||
trailingLabel: String? = null, inputType: InputType = InputType.Text
|
||||
) {
|
||||
val placeholder = if (dropdownItems.isEmpty()) "请录入" else "请选择"
|
||||
Column(modifier = modifier) {
|
||||
Text(label, style = AppTypography.black141428TextStyle)
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
if (dropdownItems.isEmpty()) {
|
||||
CustomTextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
placeholderValue = placeholder,
|
||||
trailingLabel = trailingLabel,
|
||||
inputType = inputType
|
||||
)
|
||||
} else {
|
||||
CustomDropdownTextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
dropdownItems = dropdownItems,
|
||||
placeholderValue = placeholder,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AddProductDialog(
|
||||
modifier: Modifier = Modifier,
|
||||
onCancelClick: () -> Unit,
|
||||
onConfirmClick: () -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
Dialog(
|
||||
onDismissRequest = onDismiss,
|
||||
properties = DialogProperties(
|
||||
usePlatformDefaultWidth = false, // 不使用平台默认宽度
|
||||
decorFitsSystemWindows = false // 允许内容延伸到系统窗口后面
|
||||
)
|
||||
) {
|
||||
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.padding(start = 60.dp, end = 60.dp, bottom = 40.dp) // 设置弹窗距离边框60dp
|
||||
.wrapContentSize(),
|
||||
shape = RoundedCornerShape(30.dp),
|
||||
color = Color.White,
|
||||
shadowElevation = 0.dp
|
||||
) {
|
||||
ToastUtils.ToastComposable()
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(start = 152.dp, end = 152.dp, top = 56.dp, bottom = 30.dp),
|
||||
) {
|
||||
// 主要内容区域
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
) {
|
||||
content()
|
||||
}
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.End
|
||||
) {
|
||||
CustomOutlinedButton(
|
||||
modifier = modifier
|
||||
.width(300.dp)
|
||||
.height(100.dp),
|
||||
text = "取消",
|
||||
fontSize = 36.sp,
|
||||
onClick = onCancelClick
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
|
||||
CustomButton(
|
||||
modifier = modifier
|
||||
.width(300.dp)
|
||||
.height(100.dp),
|
||||
text = "确定",
|
||||
onClick = onConfirmClick,
|
||||
borderColor = colorResource(R.color.blue),
|
||||
textColor = colorResource(R.color.white),
|
||||
fontSize = 36.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品编辑
|
||||
*/
|
||||
@Composable
|
||||
private fun SelfProductEditView(
|
||||
viewModel: SelfProcurementViewModel,
|
||||
) {
|
||||
val selectedItem by viewModel.selectedItem.collectAsState()
|
||||
val storeList = GlobalData.warehouseTypeList
|
||||
var unitTypeList = emptyList<DictType>() // 界面中会重新获取
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
|
||||
LaunchedEffect(selectedItem) {
|
||||
Timber.d("界面显示")
|
||||
if (selectedItem == null) {
|
||||
viewModel.updateSelectedItem(purchaseOrder = PurchaseWarehouseParam())
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(lifecycleOwner) {
|
||||
Timber.d("开始传感器采集")
|
||||
viewModel.startSensorScale()
|
||||
onDispose {
|
||||
Timber.d("停止传感器采集")
|
||||
viewModel.stopSensorScale()
|
||||
}
|
||||
}
|
||||
|
||||
selectedItem?.let {
|
||||
unitTypeList = selectedItem!!.unitDictTypeList
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight()
|
||||
.padding(top = 20.dp, bottom = 20.dp, end = 20.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(20.dp)
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
text = selectedItem!!.goodsNameStr,
|
||||
style = AppTypography.black141428TextStyle.bold().withSize(30.sp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
RowInputLayout(
|
||||
label = "仓库",
|
||||
value = selectedItem!!.warehouseNameStr,
|
||||
dropdownItems = storeList,
|
||||
onValueChange = { value ->
|
||||
selectedItem.let {
|
||||
viewModel.updateSelectedItem(
|
||||
selectedItem!!.copy(
|
||||
// warehouseName = value,
|
||||
warehouseId = storeList.find { it.value == value }?.id ?: 0
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
RowInputLayout(
|
||||
label = "采购单位",
|
||||
value = selectedItem!!.unitNameStr,
|
||||
dropdownItems = unitTypeList,
|
||||
onValueChange = { value ->
|
||||
val selectUnitType =
|
||||
selectedItem!!.unitList!!.find { it.purchaseUnitName == value }
|
||||
if (selectUnitType != null) {
|
||||
viewModel.updateSelectedItem(
|
||||
selectedItem!!.copy(
|
||||
unitName = value,
|
||||
buyToInventoryValue = selectUnitType.buyToInventoryValue ?: "",
|
||||
goodPurId = selectUnitType.businessUnitId?.toInt() ?: 0,
|
||||
selectUnitType = selectUnitType
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
RowInputLayout(
|
||||
label = "采购数量",
|
||||
value = selectedItem!!.goodsCountStr,
|
||||
inputType = InputType.Decimal,
|
||||
isInitUpdate = true,
|
||||
onValueChange = { value ->
|
||||
Timber.d("采购数量 onValueChange value = $value")
|
||||
viewModel.updateCountInputState(value.isNotEmpty())
|
||||
selectedItem.let {
|
||||
viewModel.updateSelectedItem(selectedItem!!.copy(goodsCount = value.toSafeDouble()))
|
||||
}
|
||||
},
|
||||
trailingLabel = selectedItem!!.unitName,
|
||||
)
|
||||
|
||||
RowInputLayout(
|
||||
label = "采购单价",
|
||||
value = selectedItem!!.goodsUnitPriceStr,
|
||||
inputType = InputType.Decimal,
|
||||
trailingLabel = "元",
|
||||
onValueChange = { value ->
|
||||
selectedItem.let {
|
||||
viewModel.updateSelectedItem(selectedItem!!.copy(goodsUnitPrice = value.toSafeDouble()))
|
||||
}
|
||||
})
|
||||
RowInputLayout(
|
||||
label = "采购金额",
|
||||
value = selectedItem!!.goodsPriceStr,
|
||||
inputType = InputType.Decimal,
|
||||
trailingLabel = "元",
|
||||
onValueChange = { value ->
|
||||
selectedItem.let {
|
||||
viewModel.updateSelectedItem(selectedItem!!.copy(goodsPrice = value.toSafeDouble()))
|
||||
}
|
||||
})
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 30.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(text = "物品重量", style = AppTypography.black141428TextStyle)
|
||||
CustomTextField(
|
||||
modifier = Modifier
|
||||
.width(290.dp)
|
||||
.height(60.dp),
|
||||
value = selectedItem!!.goodsWeightStr,
|
||||
onValueChange = { },
|
||||
enabled = false,
|
||||
isInitUpdate = true,
|
||||
textAlign = TextAlign.End,
|
||||
trailingLabel = selectedItem!!.goodsWeightUnitStr,
|
||||
leadingIcon = {
|
||||
Button(
|
||||
onClick = {},
|
||||
modifier = Modifier
|
||||
.padding(0.dp)
|
||||
.fillMaxHeight(),
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
border = BorderStroke(2.dp, color = Color.White),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color.White,
|
||||
contentColor = Black_141428
|
||||
),
|
||||
) { Text(text = "累计", style = AppTypography.black141428TextStyle) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(40.dp))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(30.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(80.dp)
|
||||
) {
|
||||
CustomOutlinedButton(
|
||||
modifier = Modifier
|
||||
.width(245.dp)
|
||||
.height(80.dp),
|
||||
text = "取消",
|
||||
fontSize = 30.sp,
|
||||
textColor = colorResource(R.color.green),
|
||||
borderColor = colorResource(R.color.green),
|
||||
onClick = {
|
||||
viewModel.updateSelectedItem(null)
|
||||
})
|
||||
CustomButton(
|
||||
modifier = Modifier
|
||||
.width(245.dp)
|
||||
.height(80.dp),
|
||||
text = "确定",
|
||||
fontSize = 30.sp,
|
||||
borderColor = colorResource(R.color.green),
|
||||
onClick = {
|
||||
if (selectedItem == null) return@CustomButton
|
||||
val errInfo = selectedItem!!.hasNullField()
|
||||
if (errInfo != null) {
|
||||
ToastUtils.showToast(errInfo)
|
||||
return@CustomButton
|
||||
}
|
||||
viewModel.addPurchaseItem(selectedItem!!)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.sw.inbound.ui.page
|
||||
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation.NavHostController
|
||||
|
||||
|
||||
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
|
||||
@Composable
|
||||
fun TestScreen(modifier: Modifier.Companion, navController: NavHostController) {
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.sw.inbound.ui.theme
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.sw.inbound.R
|
||||
|
||||
object AppTypography {
|
||||
val gray96a0aaTextStyle: TextStyle
|
||||
@Composable get() = TextStyle(
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color(0xFF96A0AA)
|
||||
)
|
||||
|
||||
val black141428TextStyle: TextStyle
|
||||
@Composable get() = TextStyle(
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Black_141428
|
||||
)
|
||||
|
||||
val grayTextStyle: TextStyle
|
||||
@Composable
|
||||
get() = TextStyle(
|
||||
color = colorResource(R.color.gray),
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
val blackTextStyle: TextStyle
|
||||
@Composable
|
||||
get() = TextStyle(
|
||||
color = colorResource(R.color.black),
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
|
||||
val BlueTextStyle: TextStyle
|
||||
@Composable
|
||||
get() = TextStyle(
|
||||
color = colorResource(R.color.blue),
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.sw.inbound.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val Purple80 = Color(0xFFD0BCFF)
|
||||
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||
val Pink80 = Color(0xFFEFB8C8)
|
||||
|
||||
val Purple40 = Color(0xFF6650a4)
|
||||
val PurpleGrey40 = Color(0xFF625b71)
|
||||
val Pink40 = Color(0xFF7D5260)
|
||||
|
||||
val Black_141428 = Color(0xFF141428)
|
||||
val Gray_A0A0B4 = Color(0XffA0A0B4)
|
||||
val Gray_DCDCF0 = Color(0xFFDCDCF0)
|
||||
val Gray_96A0AA = Color(0xFF96A0AA)
|
||||
val GrayDivider = Color(0XFFDCDCF0)
|
||||
|
||||
val Green_009632 = Color(0xFF009632)
|
||||
val Blue_0032C8 = Color(0xFF0032C8)
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.sw.inbound.ui.theme
|
||||
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Purple80,
|
||||
secondary = PurpleGrey80,
|
||||
tertiary = Pink80
|
||||
)
|
||||
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Purple40,
|
||||
secondary = PurpleGrey40,
|
||||
tertiary = Pink40
|
||||
|
||||
/* Other default colors to override
|
||||
background = Color(0xFFFFFBFE),
|
||||
surface = Color(0xFFFFFBFE),
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.White,
|
||||
onTertiary = Color.White,
|
||||
onBackground = Color(0xFF1C1B1F),
|
||||
onSurface = Color(0xFF1C1B1F),
|
||||
*/
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun InboundTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
// Dynamic color is available on Android 12+
|
||||
dynamicColor: Boolean = true,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colorScheme = when {
|
||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||
}
|
||||
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.sw.inbound.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
// Set of Material typography styles to start with
|
||||
val Typography = Typography(
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
/* Other default text styles to override
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
*/
|
||||
)
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.sw.inbound.R
|
||||
|
||||
@Composable
|
||||
fun BottomActionBar(
|
||||
leftText: String = "返回",
|
||||
right1ButtonText: String = "清空物品",
|
||||
right2ButtonText: String = "新增收货",
|
||||
showRight1Button: Boolean = false,
|
||||
onLeftButtonClick: () -> Unit,
|
||||
onRight1ButtonClick: () -> Unit = {},
|
||||
onRight2ButtonClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 30.dp, end = 30.dp, bottom = 20.dp)
|
||||
.height(100.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
// 左侧图标+文字
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.clickable {
|
||||
onLeftButtonClick()
|
||||
}
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.mipmap.ic_home),
|
||||
contentDescription = "返回",
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(17.dp))
|
||||
Text(
|
||||
text = leftText,
|
||||
style = TextStyle(
|
||||
color = colorResource(R.color.black),
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 30.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Row {
|
||||
if (showRight1Button) {
|
||||
CustomOutlinedButton(
|
||||
modifier = modifier
|
||||
.width(300.dp)
|
||||
.height(100.dp),
|
||||
text = right1ButtonText,
|
||||
fontSize = 36.sp,
|
||||
onClick = onRight1ButtonClick
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
}
|
||||
CustomButton(
|
||||
modifier = modifier
|
||||
.width(300.dp)
|
||||
.height(100.dp),
|
||||
text = right2ButtonText,
|
||||
onClick = onRight2ButtonClick,
|
||||
borderColor = colorResource(R.color.blue),
|
||||
textColor = colorResource(R.color.white),
|
||||
fontSize = 36.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import android.net.Uri
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import androidx.camera.core.ImageCapture
|
||||
import androidx.camera.core.ImageCaptureException
|
||||
import androidx.camera.view.CameraController
|
||||
import androidx.camera.view.LifecycleCameraController
|
||||
import androidx.camera.view.PreviewView
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import coil.compose.AsyncImage
|
||||
import com.sw.inbound.GlobalData
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.ext.dashedBorder
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
import com.sw.inbound.utils.FileUtils
|
||||
import com.sw.inbound.utils.ToastUtils
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
|
||||
@Composable
|
||||
fun CameraCaptureLayout(
|
||||
modifier: Modifier = Modifier,
|
||||
onCancelClick: () -> Unit = {},
|
||||
onConfirmClick: () -> Unit = {}
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
var showCamera by remember { mutableStateOf(false) }
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
var photoUri by remember { mutableStateOf<Uri?>(null) }
|
||||
|
||||
// CameraX 控制器
|
||||
val cameraController = remember {
|
||||
LifecycleCameraController(context).apply {
|
||||
setEnabledUseCases(
|
||||
CameraController.IMAGE_CAPTURE or
|
||||
CameraController.VIDEO_CAPTURE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.width(428.dp)
|
||||
.padding(16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(24.dp)
|
||||
) {
|
||||
if (showCamera) {
|
||||
// CameraPreview()
|
||||
// 摄像头预览
|
||||
CameraPreview(
|
||||
modifier = Modifier
|
||||
.width(428.dp)
|
||||
.height(321.dp), controller = cameraController
|
||||
)
|
||||
} else {
|
||||
if (photoUri == null) {
|
||||
// 图片预览区域
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(321.dp)
|
||||
.dashedBorder(strokeWidth = 2.dp, cornerRadiusDp = 15.dp)
|
||||
.clickable {
|
||||
showCamera = true
|
||||
},
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.mipmap.ic_camera),
|
||||
contentDescription = "默认图片",
|
||||
modifier = Modifier
|
||||
.width(96.dp)
|
||||
.height(76.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Text(
|
||||
"图片采集",
|
||||
style = AppTypography.grayTextStyle.copy(color = Color(0xFFB4B4C8))
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(321.dp)
|
||||
.dashedBorder(strokeWidth = 2.dp, cornerRadiusDp = 15.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
AsyncImage(
|
||||
model = photoUri,
|
||||
contentDescription = "照片",
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.End
|
||||
) {
|
||||
CustomOutlinedButton(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.height(80.dp),
|
||||
text = "取消",
|
||||
fontSize = 30.sp,
|
||||
borderColor = colorResource(R.color.green),
|
||||
textColor = colorResource(R.color.green),
|
||||
onClick = {
|
||||
Timber.d("点击取消")
|
||||
showCamera = true
|
||||
photoUri?.let {
|
||||
FileUtils.deleteFileWithUri(context, photoUri!!)
|
||||
}
|
||||
photoUri = null
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
|
||||
CustomButton(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.height(80.dp),
|
||||
text = "采集",
|
||||
onClick = {
|
||||
Timber.d("点击采集")
|
||||
if (!showCamera) {
|
||||
ToastUtils.showToast("请先开启图片预览")
|
||||
return@CustomButton
|
||||
}
|
||||
val executor = ContextCompat.getMainExecutor(context)
|
||||
val cacheDir = context.cacheDir
|
||||
val photoFile = File.createTempFile(
|
||||
"IMG_${System.currentTimeMillis()}",
|
||||
".jpg",
|
||||
cacheDir
|
||||
)
|
||||
|
||||
val cacheOutputOptions =
|
||||
ImageCapture.OutputFileOptions.Builder(photoFile).build()
|
||||
cameraController.takePicture(
|
||||
cacheOutputOptions,
|
||||
executor,
|
||||
object : ImageCapture.OnImageSavedCallback {
|
||||
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
||||
val savedUri = outputFileResults.savedUri ?: Uri.fromFile(photoFile)
|
||||
photoUri = savedUri
|
||||
Timber.d("photoUri = $photoUri")
|
||||
Toast.makeText(context, "照片已保存", Toast.LENGTH_SHORT).show()
|
||||
showCamera = false
|
||||
GlobalData.imageUri = photoUri
|
||||
}
|
||||
|
||||
override fun onError(exception: ImageCaptureException) {
|
||||
GlobalData.imageUri = null
|
||||
Toast.makeText(
|
||||
context,
|
||||
"拍照失败: ${exception.message}",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
})
|
||||
},
|
||||
borderColor = colorResource(R.color.green),
|
||||
textColor = colorResource(R.color.white),
|
||||
fontSize = 30.sp,
|
||||
showButtonIcon = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 生命周期管理
|
||||
DisposableEffect(lifecycleOwner) {
|
||||
Timber.d("cameraController 释放")
|
||||
cameraController.bindToLifecycle(lifecycleOwner)
|
||||
onDispose { }
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun CameraContent(modifier: Modifier, cameraController: LifecycleCameraController) {
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
|
||||
Box(
|
||||
modifier = modifier,
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
//在Compose中使用View系统中的PreviewView
|
||||
AndroidView(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
factory = { context ->
|
||||
PreviewView(context).apply {
|
||||
//设置布局宽度和高度占据全屏
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
//设置背景颜色
|
||||
setBackgroundColor(android.graphics.Color.BLACK)
|
||||
//设置渲染的实现模式
|
||||
implementationMode = PreviewView.ImplementationMode.COMPATIBLE
|
||||
//设置缩放方式
|
||||
scaleType = PreviewView.ScaleType.FILL_START
|
||||
}.also {
|
||||
it.controller = cameraController
|
||||
cameraController.bindToLifecycle(lifecycleOwner)
|
||||
}
|
||||
},
|
||||
onReset = {},
|
||||
onRelease = {
|
||||
Timber.d("cameraController.unbind()")
|
||||
cameraController.unbind()
|
||||
}
|
||||
)
|
||||
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(30.dp),
|
||||
painter = painterResource(R.mipmap.ic_scan),
|
||||
contentDescription = "扫描"
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.camera.view.LifecycleCameraController
|
||||
import androidx.camera.view.PreviewView
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import com.sw.inbound.R
|
||||
|
||||
@Composable
|
||||
fun CameraPreview(
|
||||
controller: LifecycleCameraController,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
Box(modifier = modifier) {
|
||||
AndroidView(
|
||||
factory = { ctx ->
|
||||
PreviewView(ctx).apply {
|
||||
this.controller = controller
|
||||
scaleType = PreviewView.ScaleType.FILL_CENTER // 控制预览缩放
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(30.dp),
|
||||
painter = painterResource(R.mipmap.ic_scan),
|
||||
contentDescription = "扫描"
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import android.Manifest
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.PermissionState
|
||||
import com.google.accompanist.permissions.isGranted
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import com.google.accompanist.permissions.shouldShowRationale
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Preview
|
||||
@Composable
|
||||
fun CameraScreen() {
|
||||
val cameraPermissionState =
|
||||
rememberPermissionState(permission = Manifest.permission.CAMERA)
|
||||
LaunchedEffect(key1 = Unit) {
|
||||
if (!cameraPermissionState.status.isGranted && !cameraPermissionState.status.shouldShowRationale) {
|
||||
cameraPermissionState.launchPermissionRequest()
|
||||
}
|
||||
}
|
||||
|
||||
if (cameraPermissionState.status.isGranted) {
|
||||
//接受拍照的授权
|
||||
// CameraContent()
|
||||
} else {
|
||||
//未授权,显示未授权的界面
|
||||
NoPermissionScreen(cameraPermissionState)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
fun NoPermissionScreen(cameraPermissionState: PermissionState) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
val message = if (cameraPermissionState.status.shouldShowRationale) {
|
||||
"未获取照相机权限导致无法使用照相机功能"
|
||||
} else {
|
||||
"请授权照相机的权限"
|
||||
}
|
||||
Text(message)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Button(onClick = {
|
||||
cameraPermissionState.launchPermissionRequest()
|
||||
}) {
|
||||
Text("请求授权")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.sw.inbound.R
|
||||
|
||||
@Composable
|
||||
fun CustomOutlinedButton(
|
||||
text: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
textColor: Color = colorResource(R.color.blue),
|
||||
borderColor: Color = Color.Blue,
|
||||
cornerRadius: Dp = 8.dp,
|
||||
borderWidth: Dp = 1.dp,
|
||||
fontWeight: FontWeight = FontWeight.Bold,
|
||||
fontSize: TextUnit = 24.sp
|
||||
) {
|
||||
OutlinedButton(
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
shape = RoundedCornerShape(cornerRadius),
|
||||
border = BorderStroke(borderWidth, color = borderColor),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = textColor
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
style = TextStyle(
|
||||
fontWeight = fontWeight,
|
||||
fontSize = fontSize,
|
||||
color = textColor
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CustomButton(
|
||||
text: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
textColor: Color = colorResource(R.color.white),
|
||||
borderColor: Color = colorResource(R.color.green),
|
||||
cornerRadius: Dp = 8.dp,
|
||||
borderWidth: Dp = 1.dp,
|
||||
fontWeight: FontWeight = FontWeight.Bold,
|
||||
fontSize: TextUnit = 24.sp,
|
||||
showButtonIcon: Boolean = false
|
||||
) {
|
||||
Button(
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
shape = RoundedCornerShape(cornerRadius),
|
||||
border = BorderStroke(borderWidth, color = borderColor),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = borderColor,
|
||||
contentColor = textColor
|
||||
)
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
if (showButtonIcon) {
|
||||
Image(
|
||||
painter = painterResource(R.mipmap.ic_camera_small),
|
||||
contentDescription = "采集"
|
||||
)
|
||||
Spacer(modifier = Modifier.width(13.dp))
|
||||
}
|
||||
|
||||
Text(
|
||||
text = text,
|
||||
style = TextStyle(
|
||||
fontWeight = fontWeight,
|
||||
fontSize = fontSize,
|
||||
color = textColor
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MenuAnchorType.Companion.PrimaryNotEditable
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.model.response.DictType
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
import com.sw.inbound.ui.theme.Black_141428
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun CustomDropdownTextField(
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
dropdownItems: List<DictType>,
|
||||
modifier: Modifier = Modifier,
|
||||
placeholderValue: String = "请选择",
|
||||
textAlign: TextAlign = TextAlign.Start,
|
||||
textStyle: TextStyle? = null,
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
var newTextStyle = textStyle
|
||||
?: LocalTextStyle.current.copy(
|
||||
color = Black_141428,
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
textAlign = textAlign
|
||||
)
|
||||
|
||||
ExposedDropdownMenuBox(
|
||||
modifier = modifier,
|
||||
expanded = expanded,
|
||||
onExpandedChange = { expanded = it },
|
||||
) {
|
||||
TextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
readOnly = true,
|
||||
textStyle = newTextStyle,
|
||||
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
trailingIcon = {
|
||||
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
|
||||
},
|
||||
colors = ExposedDropdownMenuDefaults.textFieldColors(
|
||||
focusedContainerColor = Color.Transparent,
|
||||
unfocusedContainerColor = Color.Transparent,
|
||||
disabledContainerColor = Color.Transparent,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
unfocusedIndicatorColor = Color.Transparent
|
||||
),
|
||||
placeholder = {
|
||||
Text(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
text = placeholderValue, style = AppTypography.gray96a0aaTextStyle.copy(
|
||||
textAlign = textAlign
|
||||
)
|
||||
)
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(Color.Transparent)
|
||||
.border(
|
||||
width = 2.dp,
|
||||
color = colorResource(R.color.border_line),
|
||||
shape = RoundedCornerShape(10.dp)
|
||||
)
|
||||
.menuAnchor(PrimaryNotEditable, true)
|
||||
)
|
||||
|
||||
ExposedDropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
dropdownItems.forEach { item ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = item.value, style = AppTypography.black141428TextStyle) },
|
||||
onClick = {
|
||||
onValueChange(item.value)
|
||||
expanded = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
import timber.log.Timber
|
||||
|
||||
@Composable
|
||||
fun CustomSearchView(onValueChange: (String) -> Unit = {}, onSearchClick: (String) -> Unit) {
|
||||
var searchText by remember { mutableStateOf("") }
|
||||
val borderColor = Color(0xFFDCDCF0)
|
||||
val focusManager = LocalFocusManager.current
|
||||
// 搜索框
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(60.dp)
|
||||
.border(
|
||||
width = 2.dp,
|
||||
color = borderColor,
|
||||
shape = RoundedCornerShape(10.dp) // 圆角边框
|
||||
)
|
||||
.background(Color.Transparent) // 透明背景
|
||||
) {
|
||||
TextField(
|
||||
value = searchText,
|
||||
onValueChange = {
|
||||
searchText = it
|
||||
onValueChange
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(end = 25.dp), // 为图标留出空间
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = Color.Transparent,
|
||||
unfocusedContainerColor = Color.Transparent,
|
||||
disabledContainerColor = Color.Transparent,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent
|
||||
),
|
||||
placeholder = {
|
||||
Text("输入物品名称", style = AppTypography.gray96a0aaTextStyle)
|
||||
},
|
||||
singleLine = true,
|
||||
textStyle = AppTypography.black141428TextStyle,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
imeAction = ImeAction.Search
|
||||
),
|
||||
keyboardActions = KeyboardActions(onSearch = {
|
||||
focusManager.clearFocus()
|
||||
onSearchClick(searchText)
|
||||
}),
|
||||
trailingIcon = {
|
||||
Image(
|
||||
painter = painterResource(R.mipmap.ic_search),
|
||||
contentDescription = "搜索",
|
||||
modifier = Modifier
|
||||
.width(32.dp)
|
||||
.height(32.dp)
|
||||
.clickable {
|
||||
Timber.d("搜索点击")
|
||||
onSearchClick(searchText)
|
||||
}
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material3.MenuAnchorType.Companion.PrimaryNotEditable
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.model.response.DictType
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun CustomSpinner(
|
||||
items: List<DictType>,
|
||||
selectedItem: String,
|
||||
onItemSelected: (DictType) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
ExposedDropdownMenuBox(
|
||||
expanded = expanded,
|
||||
onExpandedChange = { expanded = !expanded },
|
||||
modifier = modifier.background(
|
||||
color = Color(0x80FFFFFF),
|
||||
shape = RoundedCornerShape(10.dp) // 圆角背景
|
||||
)
|
||||
) {
|
||||
TextField(
|
||||
value = selectedItem,
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
textStyle = TextStyle(
|
||||
color = Color.White,
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
),
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
trailingIcon = {
|
||||
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
|
||||
},
|
||||
colors = ExposedDropdownMenuDefaults.textFieldColors(
|
||||
focusedContainerColor = colorResource(R.color.blue),
|
||||
unfocusedContainerColor = colorResource(R.color.blue),
|
||||
disabledContainerColor = colorResource(R.color.blue),
|
||||
focusedTextColor = Color.White,
|
||||
unfocusedTextColor = Color.White,
|
||||
cursorColor = Color.White,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
focusedLabelColor = Color.White.copy(alpha = 0.8f),
|
||||
unfocusedLabelColor = Color.White.copy(alpha = 0.8f),
|
||||
focusedTrailingIconColor = Color.White,
|
||||
unfocusedTrailingIconColor = Color.White
|
||||
),
|
||||
modifier = Modifier.menuAnchor(PrimaryNotEditable, true)
|
||||
)
|
||||
|
||||
ExposedDropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
modifier = Modifier
|
||||
.background(colorResource(R.color.blue))
|
||||
.exposedDropdownSize(matchTextFieldWidth = true)
|
||||
) {
|
||||
items.forEach { item ->
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(
|
||||
text = item.value,
|
||||
style = TextStyle(
|
||||
color = Color.White,
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
),
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
onItemSelected(item)
|
||||
expanded = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusDirection
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.sw.inbound.ext.isValidFloat
|
||||
import com.sw.inbound.ext.isValidNumber
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
import com.sw.inbound.ui.theme.Black_141428
|
||||
import com.sw.inbound.ui.theme.Gray_DCDCF0
|
||||
import timber.log.Timber
|
||||
|
||||
//@Preview(showBackground = true)
|
||||
//@Composable
|
||||
//fun testTextField() {
|
||||
// Column(verticalArrangement = Arrangement.spacedBy(10.dp), modifier = Modifier.padding(20.dp)) {
|
||||
// CustomTextField(value = "123", onValueChange = {}, textAlign = TextAlign.Start)
|
||||
// CustomTextField(value = "", onValueChange = {}, textAlign = TextAlign.Start)
|
||||
// CustomTextField(value = "", onValueChange = {}, textAlign = TextAlign.End)
|
||||
// CustomTextField(
|
||||
// value = "123",
|
||||
// onValueChange = {},
|
||||
// textAlign = TextAlign.End,
|
||||
// trailingLabel = "克"
|
||||
// )
|
||||
// CustomTextField(
|
||||
// enabled = false,
|
||||
// modifier = Modifier
|
||||
// .height(60.dp),
|
||||
// value = "123",
|
||||
// onValueChange = {},
|
||||
// textAlign = TextAlign.End,
|
||||
// leadingIcon =
|
||||
// {
|
||||
// Button(
|
||||
// onClick = {},
|
||||
// modifier = Modifier
|
||||
// .padding(0.dp)
|
||||
// .fillMaxHeight(),
|
||||
// shape = RoundedCornerShape(10.dp),
|
||||
// border = BorderStroke(2.dp, color = Color.White),
|
||||
// colors = ButtonDefaults.buttonColors(
|
||||
// containerColor = Color.White,
|
||||
// contentColor = Black_141428
|
||||
// ),
|
||||
// ) { Text(text = "累计", style = AppTypography.black141428TextStyle) }
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
enum class InputType {
|
||||
Text, // 字符串
|
||||
Number, // 数字
|
||||
Decimal // 浮点
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CustomTextField(
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
modifier: Modifier = Modifier.height(60.dp),
|
||||
placeholderValue: String = "请录入",
|
||||
trailingLabel: String? = null,
|
||||
textAlign: TextAlign = TextAlign.Start,
|
||||
textStyle: TextStyle? = null,
|
||||
leadingIcon: @Composable (() -> Unit)? = null,
|
||||
enabled: Boolean = true,
|
||||
inputType: InputType = InputType.Text,
|
||||
hasNext: Boolean = true,
|
||||
isInitUpdate: Boolean = false,
|
||||
keyboardOptions: KeyboardOptions? = null,
|
||||
keyboardActions: KeyboardActions? = null
|
||||
) {
|
||||
val containerColor = if (enabled) Color.Transparent else Gray_DCDCF0
|
||||
// var inputValue by remember { mutableStateOf(value) }
|
||||
var isUserInput by remember { mutableStateOf(false) }
|
||||
var inputValue by remember(if (isInitUpdate && !isUserInput) value else null) {
|
||||
mutableStateOf(value)
|
||||
}
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
fun onEditingComplete() {
|
||||
Timber.d("onEditingComplete inputValue = $inputValue")
|
||||
onValueChange(inputValue)
|
||||
}
|
||||
|
||||
var newTextStyle = textStyle
|
||||
?: LocalTextStyle.current.copy(
|
||||
color = Black_141428,
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
textAlign = textAlign
|
||||
)
|
||||
Box(modifier = modifier) {
|
||||
TextField(
|
||||
enabled = enabled,
|
||||
value = inputValue,
|
||||
textStyle = newTextStyle,
|
||||
onValueChange = { newValue ->
|
||||
Timber.d("onValueChange newValue = $newValue")
|
||||
isUserInput = newValue.isNotEmpty()
|
||||
when (inputType) {
|
||||
InputType.Number -> {
|
||||
if (newValue.isEmpty() || newValue.isValidNumber()) {
|
||||
inputValue = newValue
|
||||
onEditingComplete()
|
||||
}
|
||||
}
|
||||
|
||||
InputType.Decimal -> {
|
||||
if (newValue.isEmpty() || newValue.isValidFloat()) {
|
||||
inputValue = newValue
|
||||
onEditingComplete()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
inputValue = newValue
|
||||
onEditingComplete()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(Color.Transparent)
|
||||
.border(
|
||||
width = 2.dp,
|
||||
color = Gray_DCDCF0,
|
||||
shape = RoundedCornerShape(10.dp)
|
||||
)
|
||||
.onFocusChanged(onFocusChanged = { focusState ->
|
||||
{
|
||||
onEditingComplete()
|
||||
}
|
||||
}),
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = Color.Transparent,
|
||||
unfocusedContainerColor = Color.Transparent,
|
||||
disabledContainerColor = containerColor,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent
|
||||
),
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
placeholder = {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight()
|
||||
.wrapContentHeight(Alignment.CenterVertically),
|
||||
text = placeholderValue,
|
||||
textAlign = textAlign,
|
||||
style = AppTypography.gray96a0aaTextStyle
|
||||
)
|
||||
},
|
||||
leadingIcon = leadingIcon,
|
||||
trailingIcon = trailingLabel?.let { label ->
|
||||
{
|
||||
Text(
|
||||
text = trailingLabel,
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.wrapContentHeight(Alignment.CenterVertically),
|
||||
style = AppTypography.gray96a0aaTextStyle
|
||||
)
|
||||
}
|
||||
},
|
||||
keyboardOptions = keyboardOptions
|
||||
?: KeyboardOptions.Default.copy(imeAction = if (hasNext) ImeAction.Next else ImeAction.Done),
|
||||
keyboardActions = keyboardActions ?: KeyboardActions(onNext = {
|
||||
focusManager.moveFocus(focusDirection = FocusDirection.Next)
|
||||
onEditingComplete()
|
||||
}, onDone = {
|
||||
focusManager.clearFocus()
|
||||
onEditingComplete()
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import com.sw.inbound.network.LoadingState
|
||||
|
||||
@Composable
|
||||
fun GlobalLoading() {
|
||||
if (LoadingState.isLoading) {
|
||||
Dialog(
|
||||
onDismissRequest = {},
|
||||
properties = DialogProperties(
|
||||
dismissOnBackPress = false,
|
||||
dismissOnClickOutside = false
|
||||
)
|
||||
) {
|
||||
Column {
|
||||
CircularProgressIndicator(modifier = Modifier)
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Text(text = "请稍等...")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.camera.view.CameraController
|
||||
import androidx.camera.view.LifecycleCameraController
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import com.sw.inbound.ext.medium
|
||||
import com.sw.inbound.model.response.SearchGoodsInfo
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
|
||||
/**
|
||||
* 菜品识别组件
|
||||
*/
|
||||
@Composable
|
||||
fun IdentityView(
|
||||
list: List<SearchGoodsInfo.Record>,
|
||||
showSearchView: Boolean = false,
|
||||
onSearchClick: (String) -> Unit = {},
|
||||
onOptionSelected: (SearchGoodsInfo.Record) -> Unit = {},
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
// CameraX 控制器
|
||||
val cameraController = remember {
|
||||
LifecycleCameraController(context).apply {
|
||||
setEnabledUseCases(CameraController.IMAGE_CAPTURE)
|
||||
bindToLifecycle(lifecycleOwner)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
CameraPreview(
|
||||
modifier = Modifier
|
||||
.width(397.dp)
|
||||
.height(298.dp),
|
||||
controller = cameraController
|
||||
)
|
||||
if (showSearchView) {
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
CustomSearchView(onSearchClick = onSearchClick)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
if (showSearchView) {
|
||||
SingleSelectButtonGroup(
|
||||
modifier = Modifier
|
||||
.height(64.dp)
|
||||
.width(192.dp), options = list,
|
||||
onOptionSelected = onOptionSelected
|
||||
)
|
||||
} else {
|
||||
SingleSelectButtonGroup(
|
||||
modifier = Modifier
|
||||
.height(70.dp)
|
||||
.width(215.dp),
|
||||
options = list,
|
||||
horizontalSpacing = 30.dp,
|
||||
verticalSpacing = 20.dp,
|
||||
onOptionSelected = onOptionSelected,
|
||||
unSelectedTextStyle = AppTypography.blackTextStyle.medium()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sw.inbound.model.response.DictType
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
|
||||
/**
|
||||
* 横向输入框 包含左侧文件+右侧输入框
|
||||
*/
|
||||
@Composable
|
||||
fun RowInputLayout(
|
||||
label: String,
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
dropdownItems: List<DictType>? = null,
|
||||
hasNext: Boolean = true,
|
||||
inputType: InputType = InputType.Text,
|
||||
trailingLabel: String? = null,
|
||||
keyboardOptions: KeyboardOptions? = null,
|
||||
keyboardActions: KeyboardActions? = null,
|
||||
isInitUpdate: Boolean = false
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.height(60.dp)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 30.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(label, style = AppTypography.black141428TextStyle)
|
||||
// Spacer(modifier = Modifier.width(67.dp))
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
if (dropdownItems == null) {
|
||||
CustomTextField(
|
||||
modifier = Modifier.width(290.dp),
|
||||
value = value, onValueChange = onValueChange,
|
||||
textAlign = TextAlign.End,
|
||||
trailingLabel = trailingLabel,
|
||||
hasNext = hasNext,
|
||||
inputType = inputType,
|
||||
keyboardOptions = keyboardOptions,
|
||||
keyboardActions = keyboardActions,
|
||||
isInitUpdate = isInitUpdate
|
||||
)
|
||||
} else {
|
||||
CustomDropdownTextField(
|
||||
modifier = Modifier.width(290.dp),
|
||||
value = value,
|
||||
dropdownItems = dropdownItems,
|
||||
onValueChange = onValueChange,
|
||||
textAlign = TextAlign.End
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.ext.bold
|
||||
import com.sw.inbound.model.response.GoodsInfo
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
import com.sw.inbound.ui.theme.Gray_DCDCF0
|
||||
|
||||
|
||||
@Composable
|
||||
fun ProductListView(
|
||||
modifier: Modifier = Modifier,
|
||||
productList: List<GoodsInfo>,
|
||||
checkedItem: GoodsInfo? = null,
|
||||
onItemCheckedClick: (GoodsInfo) -> Unit = {},
|
||||
showClose: Boolean = false,
|
||||
onCloseClick: (GoodsInfo) -> Unit = {},
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
// .padding(horizontal = 30.dp)
|
||||
) {
|
||||
// 左侧列表标题
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(30.dp)
|
||||
) {
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = "名称",
|
||||
style = AppTypography.gray96a0aaTextStyle.bold(),
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.width(100.dp),
|
||||
text = "单价(元)",
|
||||
style = AppTypography.gray96a0aaTextStyle.bold()
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.width(100.dp),
|
||||
text = "数量",
|
||||
style = AppTypography.gray96a0aaTextStyle.bold()
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.width(110.dp),
|
||||
text = "金额(元)",
|
||||
style = AppTypography.gray96a0aaTextStyle.bold()
|
||||
)
|
||||
if (showClose) {
|
||||
Spacer(modifier = Modifier.width(78.dp))
|
||||
}
|
||||
}
|
||||
// Spacer(modifier = Modifier.height(31.dp))
|
||||
HorizontalDivider(thickness = 1.dp, color = colorResource(R.color.divider))
|
||||
// Spacer(modifier = Modifier.height(31.dp))
|
||||
// 左侧列表
|
||||
LazyColumn() {
|
||||
items(items = productList, key = { it.goodId!! }) { it ->
|
||||
|
||||
val checkedBg =
|
||||
if (it.goodId == checkedItem?.goodId) Gray_DCDCF0 else Color.Transparent
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.background(color = checkedBg)
|
||||
.padding(30.dp)
|
||||
.clickable {
|
||||
onItemCheckedClick(it)
|
||||
}, verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = it.goodNameStr,
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.width(100.dp),
|
||||
text = it.recUnitPriceTaxInStr,
|
||||
style = AppTypography.blackTextStyle
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.width(100.dp),
|
||||
text = "${it.receiveCountStr}${it.unitNameStr}",
|
||||
style = AppTypography.blackTextStyle
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.width(110.dp),
|
||||
text = it.recPriceExItemStr,
|
||||
style = AppTypography.blackTextStyle
|
||||
)
|
||||
if (showClose) {
|
||||
Spacer(modifier = Modifier.width(30.dp))
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.clickable {
|
||||
onCloseClick(it)
|
||||
},
|
||||
painter = painterResource(R.mipmap.ic_delete),
|
||||
contentDescription = "删除"
|
||||
)
|
||||
}
|
||||
}
|
||||
// Spacer(modifier = Modifier.height(33.dp))
|
||||
// if (productList.indexOf(it) != productList.lastIndex)
|
||||
HorizontalDivider(
|
||||
thickness = 1.dp,
|
||||
color = colorResource(R.color.divider)
|
||||
)
|
||||
// Spacer(modifier = Modifier.height(33.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CustomSingleRightText(
|
||||
modifier: Modifier,
|
||||
text: String,
|
||||
style: TextStyle = AppTypography.blackTextStyle,
|
||||
textAlign: TextAlign = TextAlign.End
|
||||
) {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
textAlign = textAlign,
|
||||
style = style,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.ext.bold
|
||||
import com.sw.inbound.model.request.PurchaseWarehouseParam
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
import com.sw.inbound.ui.theme.Gray_DCDCF0
|
||||
|
||||
|
||||
@Composable
|
||||
fun SelfProcurementListItem(
|
||||
modifier: Modifier = Modifier,
|
||||
productList: List<PurchaseWarehouseParam>,
|
||||
checkedItem: PurchaseWarehouseParam? = null,
|
||||
onItemCheckedClick: (PurchaseWarehouseParam) -> Unit = {},
|
||||
showClose: Boolean = false,
|
||||
onCloseClick: (PurchaseWarehouseParam) -> Unit = {},
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
// .padding(horizontal = 30.dp)
|
||||
) {
|
||||
// 左侧列表标题
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(30.dp)
|
||||
) {
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = "名称",
|
||||
style = AppTypography.gray96a0aaTextStyle.bold(),
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.width(100.dp),
|
||||
text = "单价(元)",
|
||||
style = AppTypography.gray96a0aaTextStyle.bold()
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.width(100.dp),
|
||||
text = "数量",
|
||||
style = AppTypography.gray96a0aaTextStyle.bold()
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.width(110.dp),
|
||||
text = "金额(元)",
|
||||
style = AppTypography.gray96a0aaTextStyle.bold()
|
||||
)
|
||||
if (showClose) {
|
||||
Spacer(modifier = Modifier.width(78.dp))
|
||||
}
|
||||
}
|
||||
// Spacer(modifier = Modifier.height(31.dp))
|
||||
HorizontalDivider(thickness = 1.dp, color = colorResource(R.color.divider))
|
||||
// Spacer(modifier = Modifier.height(31.dp))
|
||||
// 左侧列表
|
||||
LazyColumn() {
|
||||
items(items = productList, key = { it.goodsId }) { it ->
|
||||
|
||||
val checkedBg =
|
||||
if (it.goodsId == checkedItem?.goodsId) Gray_DCDCF0 else Color.Transparent
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.background(color = checkedBg)
|
||||
.padding(30.dp)
|
||||
.clickable {
|
||||
onItemCheckedClick(it)
|
||||
}, verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = it.goodsNameStr,
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.width(100.dp),
|
||||
text = it.goodsUnitPriceStr,
|
||||
style = AppTypography.blackTextStyle
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.width(100.dp),
|
||||
text = "${it.goodsCountStr}${it.unitNameStr}",
|
||||
style = AppTypography.blackTextStyle
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
CustomSingleRightText(
|
||||
modifier = Modifier.width(110.dp),
|
||||
text = it.goodsPriceStr,
|
||||
style = AppTypography.blackTextStyle
|
||||
)
|
||||
if (showClose) {
|
||||
Spacer(modifier = Modifier.width(30.dp))
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.clickable {
|
||||
onCloseClick(it)
|
||||
},
|
||||
painter = painterResource(R.mipmap.ic_delete),
|
||||
contentDescription = "删除"
|
||||
)
|
||||
}
|
||||
}
|
||||
// Spacer(modifier = Modifier.height(33.dp))
|
||||
// if (productList.indexOf(it) != productList.lastIndex)
|
||||
HorizontalDivider(
|
||||
thickness = 1.dp,
|
||||
color = colorResource(R.color.divider)
|
||||
)
|
||||
// Spacer(modifier = Modifier.height(33.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CustomSingleRightText(
|
||||
modifier: Modifier,
|
||||
text: String,
|
||||
style: TextStyle = AppTypography.blackTextStyle,
|
||||
textAlign: TextAlign = TextAlign.End
|
||||
) {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
textAlign = textAlign,
|
||||
style = style,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sw.inbound.model.response.SearchGoodsInfo
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun testSingleGroup() {
|
||||
val list = mutableListOf<SearchGoodsInfo.Record>()
|
||||
list.add(SearchGoodsInfo.Record(goodsName = "胶东大白菜胶东大白菜胶东大白菜胶东大白菜"))
|
||||
for (i in 1..20) {
|
||||
list.add(SearchGoodsInfo.Record(goodsName = "胶东大白菜$i"))
|
||||
}
|
||||
|
||||
// val list = arrayListOf<String>(
|
||||
// "胶东大白菜",
|
||||
// "玉田尖白菜1",
|
||||
// "玉田尖白菜2",
|
||||
// "玉田尖白菜3",
|
||||
// "玉田尖白菜4"
|
||||
// )
|
||||
// SingleSelectButtonGroup(list)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SingleSelectButtonGroup(
|
||||
options: List<SearchGoodsInfo.Record>,
|
||||
modifier: Modifier = Modifier,
|
||||
onOptionSelected: (SearchGoodsInfo.Record) -> Unit,
|
||||
horizontalSpacing: Dp = 13.dp,
|
||||
verticalSpacing: Dp = 13.dp,
|
||||
unSelectedTextStyle: TextStyle = AppTypography.gray96a0aaTextStyle
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
var selectedOption by remember { mutableStateOf(options.firstOrNull() ?: "") }
|
||||
|
||||
// 定义颜色
|
||||
val selectedColor = Color(0xFFD9E3F9) // 选中颜色 #D9E3F9
|
||||
val unselectedColor = Color(0xFFDCDCF0) // 未选中颜色 #DCDCF0
|
||||
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(2), // 每行2列
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(horizontalSpacing), // 水平间距13dp
|
||||
verticalArrangement = Arrangement.spacedBy(verticalSpacing) // 垂直间距13dp
|
||||
) {
|
||||
items(items = options) { option ->
|
||||
Box(
|
||||
modifier = modifier
|
||||
.border(
|
||||
width = 2.dp,
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
color = if (option == selectedOption) selectedColor else unselectedColor,
|
||||
)
|
||||
.clip(RoundedCornerShape(10.dp))
|
||||
.background(if (option == selectedOption) selectedColor else Color.Transparent)
|
||||
.clickable {
|
||||
selectedOption = option
|
||||
onOptionSelected(option)
|
||||
},
|
||||
contentAlignment = Alignment.Center
|
||||
// .padding(vertical = 20.dp) // 垂直内边距
|
||||
) {
|
||||
Text(
|
||||
text = option.goodsNameStr,
|
||||
style = if (option == selectedOption) AppTypography.BlueTextStyle else unSelectedTextStyle,
|
||||
modifier = Modifier
|
||||
// .width(192.dp)
|
||||
// .height(64.dp)
|
||||
.wrapContentWidth()
|
||||
.padding(horizontal = 10.dp), // 水平内边距
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
softWrap = false
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.sw.inbound.ui.weight
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.ext.medium
|
||||
import com.sw.inbound.model.response.User
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
import com.sw.inbound.utils.DateTimeUtils
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Preview(
|
||||
widthDp = 1920,
|
||||
heightDp = 1080,
|
||||
showBackground = true
|
||||
)
|
||||
@Composable
|
||||
fun TopTitleBar(
|
||||
modifier: Modifier = Modifier,
|
||||
title: String = "采购单入库",
|
||||
user: User? = null,
|
||||
onLogoutClick: () -> Unit = {}
|
||||
) {
|
||||
var currentTime by remember { mutableStateOf(DateTimeUtils.getChineseDateString()) }
|
||||
|
||||
// 每秒更新一次时间
|
||||
LaunchedEffect(Unit) {
|
||||
while (true) {
|
||||
delay(1000) // 1秒间隔
|
||||
currentTime = DateTimeUtils.getChineseDateString()
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 60.dp, end = 60.dp, top = 22.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = TextStyle(
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = colorResource(R.color.title),
|
||||
fontSize = 36.sp
|
||||
),
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
if (user != null) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.height(60.dp)
|
||||
.clickable {
|
||||
onLogoutClick()
|
||||
}) {
|
||||
Text(text = user.name ?: "用户", style = AppTypography.blackTextStyle.medium())
|
||||
Spacer(modifier = Modifier.width(21.dp))
|
||||
Image(
|
||||
modifier = Modifier.size(60.dp),
|
||||
painter = painterResource(R.mipmap.ic_logout),
|
||||
contentDescription = "退出"
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Text(
|
||||
modifier = Modifier.combinedClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
onLogoutClick()
|
||||
}
|
||||
),
|
||||
text = currentTime,
|
||||
style = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = colorResource(R.color.black),
|
||||
fontSize = 24.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package com.sw.inbound.ui.weight.dialog
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import com.sw.inbound.R
|
||||
import com.sw.inbound.ext.bold
|
||||
import com.sw.inbound.ext.withColor
|
||||
import com.sw.inbound.ext.withSize
|
||||
import com.sw.inbound.ui.theme.AppTypography
|
||||
import com.sw.inbound.ui.weight.CustomButton
|
||||
import com.sw.inbound.ui.weight.CustomOutlinedButton
|
||||
|
||||
@Composable
|
||||
fun ReceiptTipDialog(
|
||||
modifier: Modifier = Modifier,
|
||||
isWarn: Boolean = false,
|
||||
onCancelClick: () -> Unit,
|
||||
onConfirmClick: (Boolean) -> Unit,
|
||||
onDismiss: () -> Unit = {},
|
||||
) {
|
||||
Dialog(
|
||||
onDismissRequest = onDismiss,
|
||||
properties = DialogProperties(
|
||||
usePlatformDefaultWidth = false, // 不使用平台默认宽度
|
||||
decorFitsSystemWindows = false // 允许内容延伸到系统窗口后面
|
||||
)
|
||||
) {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.width(1190.dp)
|
||||
.height(840.dp)
|
||||
.wrapContentSize(),
|
||||
shape = RoundedCornerShape(30.dp),
|
||||
color = Color.White,
|
||||
shadowElevation = 0.dp
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(30.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Image(
|
||||
painter = if (isWarn) painterResource(R.mipmap.ic_tip_warn) else painterResource(
|
||||
R.mipmap.ic_tip_success
|
||||
), contentDescription = "提示"
|
||||
)
|
||||
Spacer(modifier = Modifier.height(60.dp))
|
||||
Text(
|
||||
text = if (isWarn) "收货数量与采购量不一致" else "核对无误,确认收货",
|
||||
style = AppTypography.black141428TextStyle.bold().withSize(48.sp)
|
||||
)
|
||||
if (isWarn) {
|
||||
Spacer(modifier = Modifier.height(29.dp))
|
||||
Text(
|
||||
text = "请确认实际收货数量,或选择部分收货处理",
|
||||
style = AppTypography.black141428TextStyle.withColor(
|
||||
color = Color(0xFF999999)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
HorizontalDivider(thickness = 1.dp, color = colorResource(R.color.divider))
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.End
|
||||
) {
|
||||
CustomOutlinedButton(
|
||||
modifier = modifier
|
||||
.width(180.dp)
|
||||
.height(90.dp),
|
||||
text = "返回",
|
||||
fontSize = 36.sp,
|
||||
onClick = onCancelClick
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
if (isWarn) {
|
||||
CustomButton(
|
||||
modifier = modifier
|
||||
.width(260.dp)
|
||||
.height(90.dp),
|
||||
text = "部分收货",
|
||||
onClick = {
|
||||
onConfirmClick(false)
|
||||
},
|
||||
borderColor = colorResource(R.color.green),
|
||||
textColor = colorResource(R.color.white),
|
||||
fontSize = 36.sp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
}
|
||||
|
||||
CustomButton(
|
||||
modifier = modifier
|
||||
.width(260.dp)
|
||||
.height(90.dp),
|
||||
text = "确定收货",
|
||||
onClick = {
|
||||
onConfirmClick(true)
|
||||
},
|
||||
borderColor = colorResource(R.color.blue),
|
||||
textColor = colorResource(R.color.white),
|
||||
fontSize = 36.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user