Report is working.
This commit is contained in:
parent
2b69f0fc24
commit
0db26bb7a2
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="ModuleClassLoaderOverlays">
|
||||
<paths>
|
||||
<option value="C:\Users\egore\AppData\Local\Temp\overlay18388947515922838363" />
|
||||
<option value="C:\Users\egore\AppData\Local\Temp\overlay18323405549060409157" />
|
||||
<option value="C:\Users\egore\AppData\Local\Temp\overlay16485769531165389458" />
|
||||
<option value="C:\Users\egore\AppData\Local\Temp\overlay7802277587693817774" />
|
||||
<option value="C:\Users\egore\AppData\Local\Temp\overlay16197097467506260191" />
|
||||
</paths>
|
||||
</component>
|
||||
</module>
|
@ -68,6 +68,7 @@ import ru.ulstu.`is`.pmu.tanks.composeui.Account
|
||||
import ru.ulstu.`is`.pmu.tanks.composeui.Constructor
|
||||
import ru.ulstu.`is`.pmu.tanks.composeui.Hangar
|
||||
import ru.ulstu.`is`.pmu.tanks.composeui.NationList
|
||||
import ru.ulstu.`is`.pmu.tanks.composeui.Report
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@ -150,6 +151,7 @@ fun Navhost(
|
||||
Screen.Constructor.route,
|
||||
arguments = listOf(navArgument("id") { type = NavType.LongType })
|
||||
) { Constructor(navController) }
|
||||
composable(Screen.Report.route) { Report(navController) }
|
||||
composable(Screen.Hangar.route) { Hangar(navController) }
|
||||
composable(Screen.Account.route) { Account(navController) }
|
||||
}
|
||||
@ -261,6 +263,19 @@ fun MainNavbar(navController: NavController) {
|
||||
) {
|
||||
Text(text = "Добавить")
|
||||
}
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.width(200.dp)
|
||||
.height(50.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = CustomOrange,
|
||||
contentColor = CustomDark),
|
||||
onClick = {
|
||||
navController.navigate(Screen.Report.route)
|
||||
}
|
||||
) {
|
||||
Text("Отчёты")
|
||||
}
|
||||
}
|
||||
Navhost(navController)
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Create
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.Home
|
||||
import androidx.compose.material.icons.filled.Info
|
||||
import androidx.compose.material.icons.filled.List
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import ru.ulstu.`is`.pmu.R
|
||||
@ -38,6 +39,9 @@ enum class Screen(
|
||||
StudentView(
|
||||
"student-view/{id}", R.string.student_view_title, showInBottomBar = false
|
||||
),
|
||||
Report(
|
||||
"report", R.string.report, showInBottomBar = false
|
||||
),
|
||||
NATIONS("nations", R.string.nation, Icons.Filled.Create),
|
||||
EDIT_NATIONS("edit-nation/{id}", R.string.nation);
|
||||
|
||||
|
@ -7,5 +7,5 @@ object ApiRoutes {
|
||||
const val NATION = "nations"
|
||||
const val TANK = "tanks"
|
||||
const val USER_TANK = "users_tanks"
|
||||
const val NOT_USER_TANK = "notUserTanks"
|
||||
const val REPORT = "report"
|
||||
}
|
@ -15,10 +15,12 @@ import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.LevelRemote
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.NationRemote
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.ReportRemote
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.TankRemote
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.TankWithNationAndLevelRemote
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.UserRemote
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.UserTankCrossRefRemote
|
||||
import java.util.Date
|
||||
|
||||
interface ServerService {
|
||||
// :[USER]
|
||||
@ -145,6 +147,12 @@ interface ServerService {
|
||||
@Path("id") id: Long
|
||||
): TankRemote
|
||||
|
||||
@GET("${ApiRoutes.REPORT}")
|
||||
suspend fun getReportInfo(
|
||||
@Query("startDate") startDate: Date,
|
||||
@Query("endDate") endDate: Date
|
||||
): ReportRemote
|
||||
|
||||
// ![TANK]
|
||||
|
||||
// :[USER_TANK_CROSS_REF]
|
||||
@ -166,6 +174,7 @@ interface ServerService {
|
||||
|
||||
// ![USER_TANK_CROSS_REF]
|
||||
|
||||
|
||||
companion object {
|
||||
private const val BASE_URL = ApiRoutes.BASE
|
||||
|
||||
|
@ -0,0 +1,42 @@
|
||||
package ru.ulstu.`is`.pmu.tank.api.model
|
||||
|
||||
import com.application.ui.toBitmap
|
||||
import kotlinx.serialization.Serializable
|
||||
import ru.ulstu.`is`.pmu.tank.model.Report
|
||||
import ru.ulstu.`is`.pmu.tank.model.Tank
|
||||
|
||||
@Serializable
|
||||
data class ReportRemote(
|
||||
//tank part
|
||||
val id: Int = 0,
|
||||
val tankName: String = "",
|
||||
val price: Int = 0,
|
||||
val miniature: String = "",
|
||||
val tankLevel: Int = 0,
|
||||
val tankNation: String = "",
|
||||
val countTankPurchase: Int = 0,
|
||||
|
||||
//level part
|
||||
val level: Int = 0,
|
||||
val countLevelPurchase: Int = 0,
|
||||
|
||||
//nation part
|
||||
val nationName: String = "",
|
||||
val countNationPurchase: Int = 0,
|
||||
){ }
|
||||
|
||||
fun ReportRemote.toReport(): Report = Report(
|
||||
id = id,
|
||||
tankName = tankName,
|
||||
price = price,
|
||||
miniature = miniature.toBitmap(),
|
||||
tankLevel = tankLevel,
|
||||
tankNation = tankNation,
|
||||
countTankPurchase = countTankPurchase,
|
||||
|
||||
level = level,
|
||||
countLevelPurchase = countLevelPurchase,
|
||||
|
||||
nationName = nationName,
|
||||
countNationPurchase = countNationPurchase
|
||||
)
|
@ -7,15 +7,18 @@ import kotlinx.coroutines.flow.flatMapConcat
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import ru.ulstu.`is`.pmu.tank.api.ServerService
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.ReportRemote
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.UserTankCrossRefRemote
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.toLevel
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.toNation
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.toRemote
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.toReport
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.toTank
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.toTankWithNationAndLevel
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.toUserTankCrossRef
|
||||
import ru.ulstu.`is`.pmu.tank.model.Level
|
||||
import ru.ulstu.`is`.pmu.tank.model.Nation
|
||||
import ru.ulstu.`is`.pmu.tank.model.Report
|
||||
import ru.ulstu.`is`.pmu.tank.model.Tank
|
||||
import ru.ulstu.`is`.pmu.tank.model.TankWithNationAndLevel
|
||||
import ru.ulstu.`is`.pmu.tank.model.UserTankCrossRef
|
||||
@ -67,6 +70,10 @@ class RestTankRepository (
|
||||
return service.getTank(uid).toTank()
|
||||
}
|
||||
|
||||
suspend fun getReport(startDate: Date, endDate: Date): Report {
|
||||
return service.getReportInfo(startDate, endDate).toReport();
|
||||
}
|
||||
|
||||
override suspend fun getUserTanks(userId: Long): List<TankWithNationAndLevel> {
|
||||
val totalList: List<Tank> = getAll()
|
||||
val totalLevelList: List<Level> = service.getLevels().map { it.toLevel() }
|
||||
|
@ -0,0 +1,3 @@
|
||||
package ru.ulstu.`is`.pmu.tank.composeui
|
||||
|
||||
enum class ApiStatus { LOADING, ERROR, DONE }
|
@ -0,0 +1,47 @@
|
||||
package ru.ulstu.`is`.pmu.tank.composeui
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.launch
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
||||
open class MyViewModel : ViewModel() {
|
||||
var apiStatus by mutableStateOf(ApiStatus.DONE)
|
||||
private set
|
||||
|
||||
var apiError by mutableStateOf("")
|
||||
private set
|
||||
|
||||
fun runInScope(
|
||||
actionSuccess: suspend () -> Unit,
|
||||
actionError: suspend () -> Unit
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
apiStatus = ApiStatus.LOADING
|
||||
runCatching {
|
||||
actionSuccess()
|
||||
apiStatus = ApiStatus.DONE
|
||||
apiError = ""
|
||||
}.onFailure { e: Throwable ->
|
||||
when (e) {
|
||||
is IOException,
|
||||
is HttpException -> {
|
||||
actionError()
|
||||
apiStatus = ApiStatus.ERROR
|
||||
apiError = e.localizedMessage ?: e.toString()
|
||||
}
|
||||
|
||||
else -> throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun runInScope(actionSuccess: suspend () -> Unit) {
|
||||
runInScope(actionSuccess, actionError = {})
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package ru.ulstu.`is`.pmu.tank.composeui.edit
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.ReportRemote
|
||||
import ru.ulstu.`is`.pmu.tank.api.repository.RestTankRepository
|
||||
import ru.ulstu.`is`.pmu.tank.composeui.MyViewModel
|
||||
import ru.ulstu.`is`.pmu.tank.model.Report
|
||||
import java.util.Date
|
||||
|
||||
class ReportViewModel (private val tankRepository: RestTankRepository): MyViewModel()
|
||||
{
|
||||
var reportPageUiState by mutableStateOf(ReportPageUiState())
|
||||
private set
|
||||
|
||||
var reportResultPageUiState by mutableStateOf(ReportResultPageUiState())
|
||||
private set
|
||||
|
||||
fun onUpdate(reportDetails: ReportDetails)
|
||||
{
|
||||
reportPageUiState = ReportPageUiState(reportDetails = reportDetails,isEntryValid = validateInput(reportDetails))
|
||||
}
|
||||
private fun validateInput(uiState: ReportDetails = reportPageUiState.reportDetails): Boolean {
|
||||
Log.d("Checking",uiState.endDate.toString())
|
||||
return with(uiState) {
|
||||
startDate!=Date(0)
|
||||
&& endDate!=Date(0)
|
||||
&& startDate < endDate
|
||||
}
|
||||
}
|
||||
suspend fun getReport(){
|
||||
runInScope(
|
||||
actionSuccess = {
|
||||
val res = tankRepository.getReport(reportPageUiState.reportDetails.startDate, reportPageUiState.reportDetails.endDate)
|
||||
|
||||
Log.d("MAIN CHECKING", res.toString())
|
||||
|
||||
reportResultPageUiState = ReportResultPageUiState(res)
|
||||
},
|
||||
actionError = {
|
||||
reportResultPageUiState = ReportResultPageUiState()
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class ReportDetails(
|
||||
val startDate: Date = Date(0),
|
||||
val endDate: Date = Date(0)
|
||||
)
|
||||
|
||||
data class ReportPageUiState(
|
||||
val reportDetails: ReportDetails = ReportDetails(),
|
||||
val isEntryValid: Boolean = false
|
||||
)
|
||||
|
||||
data class ReportResultPageUiState(
|
||||
var resReport: Report? = null
|
||||
)
|
@ -52,7 +52,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun remoteKeysDao(): RemoteKeysDao
|
||||
|
||||
companion object {
|
||||
private const val DB_NAME: String = "23-db"
|
||||
private const val DB_NAME: String = "24-db"
|
||||
|
||||
@Volatile
|
||||
private var INSTANCE: AppDatabase? = null
|
||||
|
@ -0,0 +1,26 @@
|
||||
package ru.ulstu.`is`.pmu.tank.model
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import com.application.ui.getEmptyBitmap
|
||||
|
||||
data class Report (
|
||||
//tank part
|
||||
val id: Int,
|
||||
val tankName: String,
|
||||
val price: Int,
|
||||
val miniature: Bitmap,
|
||||
val tankLevel: Int,
|
||||
val tankNation: String,
|
||||
val countTankPurchase: Int,
|
||||
|
||||
//level part
|
||||
val level: Int,
|
||||
val countLevelPurchase: Int,
|
||||
|
||||
//nation part
|
||||
val nationName: String,
|
||||
val countNationPurchase: Int,
|
||||
) { }
|
@ -0,0 +1,231 @@
|
||||
package ru.ulstu.`is`.pmu.tanks.composeui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
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.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.DatePicker
|
||||
import androidx.compose.material3.DisplayMode
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberDatePickerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
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.graphics.asImageBitmap
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.TextUnitType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.application.ui.toBitmap
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.ulstu.`is`.pmu.tank.api.model.ReportRemote
|
||||
import ru.ulstu.`is`.pmu.tank.composeui.ApiStatus
|
||||
import ru.ulstu.`is`.pmu.tank.composeui.edit.ReportViewModel
|
||||
import ru.ulstu.`is`.pmu.tank.model.Report
|
||||
import ru.ulstu.`is`.pmu.tanks.composeui.image.CuteImage
|
||||
import ru.ulstu.`is`.pmu.ui.AppViewModelProvider
|
||||
import ru.ulstu.`is`.pmu.ui.theme.CustomRed
|
||||
import ru.ulstu.`is`.pmu.ui.theme.CustomYellow
|
||||
import java.util.Date
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Report (navController: NavController?,viewModel: ReportViewModel = viewModel(factory = AppViewModelProvider.Factory))
|
||||
{
|
||||
when (viewModel.apiStatus) {
|
||||
ApiStatus.DONE -> {
|
||||
val dateStateStart = rememberDatePickerState(initialDisplayMode = DisplayMode.Input)
|
||||
val dateStateEnd = rememberDatePickerState(initialDisplayMode = DisplayMode.Input)
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val reportResultPageState = viewModel.reportResultPageUiState
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
)
|
||||
{
|
||||
Text(
|
||||
text = "Начало периода",
|
||||
style = MaterialTheme.typography.headlineLarge
|
||||
)
|
||||
DatePicker(
|
||||
state = dateStateStart,
|
||||
)
|
||||
val selectedDateStart = dateStateStart.selectedDateMillis
|
||||
if (selectedDateStart != null) {
|
||||
val resultDate= Date(selectedDateStart)
|
||||
viewModel.onUpdate(viewModel.reportPageUiState.reportDetails.copy(startDate = resultDate))
|
||||
}
|
||||
else
|
||||
{
|
||||
viewModel.onUpdate(viewModel.reportPageUiState.reportDetails.copy(startDate = Date(0)))
|
||||
}
|
||||
Text(
|
||||
text = "Конец периода",
|
||||
style = MaterialTheme.typography.headlineLarge
|
||||
)
|
||||
DatePicker(
|
||||
state = dateStateEnd,
|
||||
)
|
||||
val selectedDateEnd = dateStateEnd.selectedDateMillis
|
||||
if (selectedDateEnd != null) {
|
||||
val resultDate = Date(selectedDateEnd)
|
||||
viewModel.onUpdate(viewModel.reportPageUiState.reportDetails.copy(endDate = resultDate))
|
||||
}
|
||||
else
|
||||
{
|
||||
viewModel.onUpdate(viewModel.reportPageUiState.reportDetails.copy(endDate = Date(0)))
|
||||
}
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Button(
|
||||
onClick = {coroutineScope.launch { viewModel.getReport() } },
|
||||
enabled = viewModel.reportPageUiState.isEntryValid,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(56.dp)
|
||||
.clip(RoundedCornerShape(8.dp)),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
CustomRed, Color.White, CustomYellow,
|
||||
CustomYellow
|
||||
),
|
||||
) {
|
||||
Text("Сформировать отчет")
|
||||
}
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
Text(
|
||||
text = "Результат",
|
||||
style = MaterialTheme.typography.headlineLarge
|
||||
)
|
||||
if(reportResultPageState.resReport != null){
|
||||
TableScreen(reportData = reportResultPageState.resReport!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ApiStatus.LOADING -> LoadingPlaceholder()
|
||||
else -> ErrorPlaceholder(
|
||||
message = viewModel.apiError,
|
||||
onBack = {
|
||||
navController?.popBackStack()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LoadingPlaceholder() {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(10.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
fontSize = TextUnit(value = 25F, type = TextUnitType.Sp),
|
||||
text = "Загрузка"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ErrorPlaceholder(message: String, onBack: () -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(10.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
fontSize = TextUnit(value = 20F, type = TextUnitType.Sp),
|
||||
text = message,
|
||||
color = Color(0xFFFF1744)
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(bottom = 10.dp))
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = { onBack() }
|
||||
) {
|
||||
Text("Назад")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RowScope.TableCell(
|
||||
text: String,
|
||||
weight: Float
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
Modifier
|
||||
.border(1.dp, Color.Black)
|
||||
.weight(weight)
|
||||
.padding(8.dp)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun TableScreen(reportData: Report) {
|
||||
|
||||
val column1Weight = .3f // 30%
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.padding(16.dp)) {
|
||||
|
||||
Row(Modifier.background(Color.Gray)) {
|
||||
TableCell(text = "Название танка:", weight = column1Weight)
|
||||
TableCell(text = "Стоимость танка:", weight = column1Weight)
|
||||
//TableCell(text = "Изображение:", weight = column1Weight)
|
||||
TableCell(text = "Уровень:", weight = column1Weight)
|
||||
TableCell(text = "Нация:", weight = column1Weight)
|
||||
TableCell(text = "Кол-во покупок:", weight = column1Weight)
|
||||
|
||||
TableCell(text = "Самый популярный уровень:", weight = column1Weight)
|
||||
TableCell(text = "Кол-во покупок:", weight = column1Weight)
|
||||
|
||||
TableCell(text = "Самая популярная нация:", weight = column1Weight)
|
||||
TableCell(text = "Кол-во покупок:", weight = column1Weight)
|
||||
}
|
||||
|
||||
// Here are all the lines of your table.
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
TableCell(text = reportData.tankName, weight = column1Weight)
|
||||
TableCell(text = reportData.price.toString(), weight = column1Weight)
|
||||
CuteImage(
|
||||
imageBitmap = reportData.miniature.asImageBitmap(),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
TableCell(text = reportData.tankLevel.toString(), weight = column1Weight)
|
||||
TableCell(text = reportData.tankNation, weight = column1Weight)
|
||||
TableCell(text = reportData.countTankPurchase.toString(), weight = column1Weight)
|
||||
TableCell(text = reportData.level.toString(), weight = column1Weight)
|
||||
TableCell(text = reportData.countLevelPurchase.toString(), weight = column1Weight)
|
||||
TableCell(text = reportData.nationName, weight = column1Weight)
|
||||
TableCell(text = reportData.countNationPurchase.toString(), weight = column1Weight)
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import ru.ulstu.`is`.pmu.TankApplication
|
||||
import ru.ulstu.`is`.pmu.tank.composeui.edit.LevelDropDownViewModel
|
||||
import ru.ulstu.`is`.pmu.tank.composeui.edit.NationDropDownViewModel
|
||||
import ru.ulstu.`is`.pmu.tank.composeui.edit.NationsListUiState
|
||||
import ru.ulstu.`is`.pmu.tank.composeui.edit.ReportViewModel
|
||||
import ru.ulstu.`is`.pmu.tank.composeui.edit.TankEditViewModel
|
||||
import ru.ulstu.`is`.pmu.tank.composeui.edit.UserEditViewModel
|
||||
import ru.ulstu.`is`.pmu.tank.composeui.edit.UsersTanksEditViewModel
|
||||
@ -41,6 +42,11 @@ object AppViewModelProvider {
|
||||
tankApplication().container.usersTanksRepository
|
||||
)
|
||||
}
|
||||
initializer {
|
||||
ReportViewModel(
|
||||
tankApplication().container.tankRestRepository
|
||||
)
|
||||
}
|
||||
initializer {
|
||||
LevelDropDownViewModel(tankApplication().container.levelRestRepository)
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
<string name="student_email">e-mail</string>
|
||||
<string name="tanks_main_title">Главная</string>
|
||||
<string name="student_view_title">Профиль студента</string>
|
||||
<string name="report">Отчёты</string>
|
||||
<string name="generator">Генератор</string>
|
||||
<string name="main_label">Список техники по:</string>
|
||||
<string name="t_34_85">T-34-85</string>
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "20-db",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"start": "json-server --watch data.json --host 0.0.0.0 -p 8079"
|
||||
"start": "json-server --watch data.json --middlewares ./reportRouter.js --host 0.0.0.0 -p 8079"
|
||||
},
|
||||
"dependencies": {
|
||||
},
|
||||
|
126
compose/server/reportRouter.js
Normal file
126
compose/server/reportRouter.js
Normal file
@ -0,0 +1,126 @@
|
||||
module.exports = (req, res, next) => {
|
||||
if (req.url.startsWith('/report') && req.method === 'GET') {
|
||||
const { startDate, endDate } = req.query;
|
||||
|
||||
try {
|
||||
delete require.cache[require.resolve('./data.json')];
|
||||
const data = require('./data.json');
|
||||
|
||||
const filteredPurchase = data.users_tanks.filter(purchase => {
|
||||
const purchaseDate = new Date(purchase.date);
|
||||
return purchaseDate >= new Date(startDate) && purchaseDate <= new Date(endDate);
|
||||
});
|
||||
|
||||
//ПОИСК САМОГО ПОПУЛЯРНОГО ТАНКА ЗА ПЕРИОД
|
||||
//список танков с кол-во их покупок
|
||||
let tankList = [];
|
||||
|
||||
filteredPurchase.forEach(purchase => {
|
||||
const tankId = purchase.tankId;
|
||||
|
||||
const tankInList = tankList.some(item => item.tankId === tankId);
|
||||
|
||||
if (tankInList) {
|
||||
tankList[tankList.findIndex(index => index.tankId === tankId)].count++;
|
||||
} else {
|
||||
tankList.push(
|
||||
{
|
||||
tankId: tankId,
|
||||
count: 1
|
||||
}
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
tankList.sort((a, b) => b.count - a.count);
|
||||
|
||||
//нашли самый популярный танк
|
||||
const supportTank = data.tanks.find(tank => tank.id === tankList[0].tankId);
|
||||
const supportLevel = data.levels.find(level => level.id === supportTank.levelId).level;
|
||||
const supportNation = data.nations.find(nation => nation.id === supportTank.levelId).nationName;
|
||||
|
||||
const popularTank = {
|
||||
id: supportTank.id,
|
||||
name: supportTank.name,
|
||||
price: supportTank.price,
|
||||
miniature: supportTank.miniature,
|
||||
level: supportLevel,
|
||||
nation: supportNation
|
||||
};
|
||||
|
||||
//ПОИСК САМЫХ ПОПУЛЯРНЫХ УРОВНЯ И НАЦИИ ЗА ПЕРИОД
|
||||
//список уроней и кол-во их покупок
|
||||
let levelList = [];
|
||||
|
||||
//список уроней и кол-во их покупок
|
||||
let nationList = [];
|
||||
|
||||
tankList.forEach(element => {
|
||||
const tank = data.tanks.find(tank => tank.id === element.tankId);
|
||||
|
||||
//смотрим, сколько раз танк был куплен, чтобы сразу прибавить к соответствующему уровню текущее кол-во
|
||||
const countCurrentTank = element.count;
|
||||
|
||||
const levelId = tank.levelId;
|
||||
const nationId = tank.nationId;
|
||||
|
||||
const levelInList = levelList.some(item => item.levelId === levelId);
|
||||
const nationInList = nationList.some(item => item.nationId === nationId);
|
||||
|
||||
if (levelInList) {
|
||||
levelList[levelList.findIndex(index => index.levelId === levelId)].count += countCurrentTank;
|
||||
} else {
|
||||
levelList.push(
|
||||
{
|
||||
levelId: levelId,
|
||||
count: countCurrentTank
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (nationInList) {
|
||||
nationList[nationList.findIndex(index => index.nationId === nationId)].count += countCurrentTank;
|
||||
} else {
|
||||
nationList.push(
|
||||
{
|
||||
nationId: nationId,
|
||||
count: countCurrentTank
|
||||
}
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
levelList.sort((a, b) => b.count - a.count);
|
||||
nationList.sort((a, b) => b.count - a.count);
|
||||
|
||||
//нашли самые популярные уровень и нацию
|
||||
const popularLevel = data.levels.find(level => level.id === levelList[0].levelId)
|
||||
const popularNation = data.nations.find(nation => nation.id === nationList[0].nationId)
|
||||
|
||||
finalDataReport = {
|
||||
id: popularTank.id,
|
||||
tankName: popularTank.name,
|
||||
price: popularTank.price,
|
||||
miniature: popularTank.miniature,
|
||||
tankLevel: popularTank.level,
|
||||
tankNation: popularTank.nation,
|
||||
countTankPurchase: tankList[0].count,
|
||||
|
||||
level: popularLevel.level,
|
||||
countLevelPurchase: levelList[0].count,
|
||||
|
||||
nationName: popularNation.nationName,
|
||||
countNationPurchase: nationList[0].count
|
||||
};
|
||||
|
||||
console.log(finalDataReport)
|
||||
|
||||
res.json(finalDataReport);
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
res.status(500).json({ message: 'Internal Server Error' });
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user