Lab5 finish
This commit is contained in:
parent
053970541a
commit
7356ccb00b
@ -16,17 +16,10 @@ import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
import ru.ulstu.`is`.pmu.api.model.UserRemote
|
||||
import ru.ulstu.`is`.pmu.api.model.PetRemote
|
||||
import ru.ulstu.`is`.pmu.api.report.ReportRemote
|
||||
|
||||
|
||||
interface MyServerService {
|
||||
|
||||
@GET("report")
|
||||
suspend fun getReportInfo(
|
||||
@Query("fromDate") fromDate: String,
|
||||
@Query("toDate") toDate: String
|
||||
): List<ReportRemote>
|
||||
|
||||
@GET("users")
|
||||
suspend fun getUsers(): List<UserRemote>
|
||||
|
||||
|
@ -9,7 +9,6 @@ import kotlinx.coroutines.flow.Flow
|
||||
import ru.ulstu.`is`.pmu.api.MyServerService
|
||||
import ru.ulstu.`is`.pmu.api.model.toPet
|
||||
import ru.ulstu.`is`.pmu.api.model.toPetRemote
|
||||
import ru.ulstu.`is`.pmu.api.report.ReportRemote
|
||||
import ru.ulstu.`is`.pmu.api.user.RestUserRepository
|
||||
import ru.ulstu.`is`.pmu.common.AppContainer
|
||||
import ru.ulstu.`is`.pmu.common.PetRepository
|
||||
@ -83,9 +82,5 @@ class RestPetRepository(
|
||||
override suspend fun deletePet(pet: Pet) {
|
||||
service.deletePet(pet.uid).toPet()
|
||||
}
|
||||
suspend fun getReport(fromDate: String, toDate: String):List<ReportRemote>
|
||||
{
|
||||
return service.getReportInfo(fromDate,toDate)
|
||||
}
|
||||
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package ru.ulstu.`is`.pmu.api.report
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ReportRemote(
|
||||
val reportId: Int = 0,
|
||||
val petid: Int = 0,
|
||||
val petname: String = "",
|
||||
val birthday: String = "",
|
||||
val userid: Int = 0,
|
||||
val login: String = ""
|
||||
)
|
@ -10,7 +10,6 @@ import ru.ulstu.`is`.pmu.ui.pet.edit.PetEditViewModel
|
||||
import ru.ulstu.`is`.pmu.ui.pet.edit.UserDropDownViewModel
|
||||
import ru.ulstu.`is`.pmu.ui.pet.list.PetListViewModel
|
||||
import ru.ulstu.`is`.pmu.ui.pet.list.UserListViewModel
|
||||
import ru.ulstu.`is`.pmu.ui.pet.report.ReportViewModel
|
||||
|
||||
object AppViewModelProvider {
|
||||
val Factory = viewModelFactory {
|
||||
@ -30,11 +29,6 @@ object AppViewModelProvider {
|
||||
UserDropDownViewModel(petApplication().container.userRestRepository
|
||||
)
|
||||
}
|
||||
initializer {
|
||||
ReportViewModel(
|
||||
petApplication().container.petRestRepository,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,6 @@ import ru.ulstu.`is`.pmu.ui.pet.edit.PetEdit
|
||||
import ru.ulstu.`is`.pmu.ui.pet.list.PetList
|
||||
import ru.ulstu.`is`.pmu.ui.pet.list.PetUserList
|
||||
import ru.ulstu.`is`.pmu.ui.pet.list.UserList
|
||||
import ru.ulstu.`is`.pmu.ui.pet.report.ReportPage
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@ -104,7 +103,6 @@ fun Navhost(
|
||||
startDestination = Screen.PetList.route,
|
||||
modifier.padding(innerPadding)
|
||||
) {
|
||||
composable(Screen.Report.route) { ReportPage(navController = navController) }
|
||||
composable(Screen.PetList.route) { PetList(navController) }
|
||||
composable(Screen.UserList.route) { UserList(navController) }
|
||||
composable(
|
||||
|
@ -18,9 +18,6 @@ enum class Screen(
|
||||
PetList(
|
||||
"pet-list", R.string.list_pet, Icons.Filled.Home
|
||||
),
|
||||
Report(
|
||||
"report", R.string.report, Icons.Filled.Info
|
||||
),
|
||||
PetUserList(
|
||||
"pet-user-list/{id}", R.string.list_pet, showInBottomBar = false
|
||||
),
|
||||
@ -35,7 +32,6 @@ enum class Screen(
|
||||
val bottomBarItems = listOf(
|
||||
UserList,
|
||||
PetList,
|
||||
Report
|
||||
)
|
||||
|
||||
fun getItem(route: String): Screen? {
|
||||
|
@ -1,197 +0,0 @@
|
||||
package ru.ulstu.`is`.pmu.ui.pet.report
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Paint
|
||||
import android.graphics.pdf.PdfDocument
|
||||
import android.net.Uri
|
||||
import android.os.Environment
|
||||
import android.provider.MediaStore
|
||||
import android.widget.CalendarView
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
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.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
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.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import ru.ulstu.`is`.pmu.R
|
||||
import ru.ulstu.`is`.pmu.api.report.ReportRemote
|
||||
import ru.ulstu.`is`.pmu.common.AppViewModelProvider
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ReportPage (navController: NavController?, viewModel: ReportViewModel = viewModel(factory = AppViewModelProvider.Factory))
|
||||
{
|
||||
val context = LocalContext.current
|
||||
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val reportResultPageState = viewModel.reportResultPageUiState
|
||||
|
||||
// Здесь вы можете определить startDate и endDate
|
||||
val startDate = viewModel.reportPageUiState.reportDetails.startDate
|
||||
val endDate = viewModel.reportPageUiState.reportDetails.endDate
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
)
|
||||
{
|
||||
Text(
|
||||
text = stringResource(id = R.string.startDate),
|
||||
style = MaterialTheme.typography.headlineLarge
|
||||
)
|
||||
|
||||
CustomCalendarView(selectedDate = startDate) { selectedDate ->
|
||||
viewModel.onUpdate(viewModel.reportPageUiState.reportDetails.copy(startDate = selectedDate))
|
||||
}
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.endDate),
|
||||
style = MaterialTheme.typography.headlineLarge
|
||||
)
|
||||
|
||||
|
||||
|
||||
CustomCalendarView(selectedDate = endDate) { selectedDate ->
|
||||
viewModel.onUpdate(viewModel.reportPageUiState.reportDetails.copy(endDate = selectedDate))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Button(
|
||||
onClick = {coroutineScope.launch { viewModel.getReport()} },
|
||||
enabled = viewModel.reportPageUiState.isEntryValid,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp)
|
||||
.border(4.dp, MaterialTheme.colorScheme.onPrimary, shape = RoundedCornerShape(10.dp)),
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary)
|
||||
) {
|
||||
Text("Сформировать отчет")
|
||||
}
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
Text(
|
||||
text = "Результат",
|
||||
style = MaterialTheme.typography.headlineLarge
|
||||
)
|
||||
TableScreen(reportData = reportResultPageState.resReport)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
@Composable
|
||||
fun CustomCalendarView(
|
||||
selectedDate: Date,
|
||||
onDateSelected: (Date) -> Unit
|
||||
) {
|
||||
AndroidView(
|
||||
|
||||
modifier = Modifier.wrapContentSize(),
|
||||
factory = { context ->
|
||||
CalendarView(context).apply {
|
||||
// Настройка CalendarView
|
||||
val calendar = Calendar.getInstance()
|
||||
calendar.time = selectedDate
|
||||
|
||||
// Установка начальной выбранной даты
|
||||
date = calendar.timeInMillis
|
||||
|
||||
setOnDateChangeListener { _, year, month, dayOfMonth ->
|
||||
calendar.set(Calendar.YEAR, year)
|
||||
calendar.set(Calendar.MONTH, month)
|
||||
calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth)
|
||||
val newSelectedDate = calendar.time
|
||||
|
||||
// Установка новой выбранной даты
|
||||
date = calendar.timeInMillis
|
||||
|
||||
// Вызов колбэка для передачи выбранной даты в родительский компонент
|
||||
onDateSelected(newSelectedDate)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@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: List<ReportRemote>) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(16.dp)) {
|
||||
|
||||
Row(Modifier.background(Color.White)) {
|
||||
TableCell(text = "№", weight = 1f)
|
||||
TableCell(text = "Id питомца", weight = 1f)
|
||||
TableCell(text = "Имя", weight = 1f)
|
||||
TableCell(text = "Д/р", weight = 1f)
|
||||
TableCell(text = "Id хозяина", weight = 1f)
|
||||
TableCell(text = "Логин", weight = 1f)
|
||||
}
|
||||
|
||||
// Here are all the lines of your table.
|
||||
reportData.forEach {
|
||||
val (reportId, petid, petname, birthday, userid, login) = it
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
TableCell(text = reportId.toString(), weight = 1f)
|
||||
TableCell(text = petid.toString(), weight = 1f)
|
||||
TableCell(text = petname, weight = 1f)
|
||||
TableCell(text = birthday, weight = 1f)
|
||||
TableCell(text = userid.toString(), weight = 1f)
|
||||
TableCell(text = login, weight = 1f)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
package ru.ulstu.`is`.pmu.ui.pet.report
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import ru.ulstu.`is`.pmu.api.pet.RestPetRepository
|
||||
import ru.ulstu.`is`.pmu.api.report.ReportRemote
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
|
||||
class ReportViewModel(private val restPetRepository: RestPetRepository): ViewModel() {
|
||||
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 {
|
||||
return with(uiState) {
|
||||
startDate != Date(0) && endDate != Date(0) && startDate < endDate
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getReport() {
|
||||
|
||||
val startDateQueryParam = SimpleDateFormat("dd.MM.yyyy").format(reportPageUiState.reportDetails.startDate)
|
||||
val endDateQueryParam = SimpleDateFormat("dd.MM.yyyy").format(reportPageUiState.reportDetails.endDate)
|
||||
|
||||
// Вызов репозитория с отформатированными датами
|
||||
val res = restPetRepository.getReport(startDateQueryParam, endDateQueryParam)
|
||||
reportResultPageUiState = ReportResultPageUiState(res)
|
||||
}
|
||||
}
|
||||
|
||||
data class ReportDetails(
|
||||
val startDate: Date = Calendar.getInstance().time,
|
||||
val endDate: Date = Calendar.getInstance().time
|
||||
)
|
||||
|
||||
data class ReportPageUiState(
|
||||
val reportDetails: ReportDetails = ReportDetails(),
|
||||
val isEntryValid: Boolean = false
|
||||
)
|
||||
|
||||
data class ReportResultPageUiState(
|
||||
var resReport: List<ReportRemote> = emptyList()
|
||||
)
|
@ -2,7 +2,7 @@
|
||||
"name": "fake-db",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"start": "json-server --watch data.json --middlewares ./router.js --host 0.0.0.0 -p 8079"
|
||||
"start": "json-server --watch data.json --host 0.0.0.0 -p 8079"
|
||||
},
|
||||
"dependencies": {
|
||||
"pdfkit": "^0.14.0"
|
||||
|
@ -1,76 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = (req, res, next) => {
|
||||
const data = JSON.parse(fs.readFileSync(path.join(__dirname, 'data.json'), 'utf8'));
|
||||
|
||||
if (req.url.startsWith('/search') && req.method === 'GET') {
|
||||
try {
|
||||
const searchText = req.query.name;
|
||||
const searched = data.pets.filter(
|
||||
(pet) =>
|
||||
pet.name.toLowerCase().includes(searchText.toLowerCase())
|
||||
);
|
||||
return res.json(searched);
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
res.status(500).json({ message: 'Internal Server Error' });
|
||||
}
|
||||
} else if (req.url.startsWith('/report') && req.method === 'GET') {
|
||||
try {
|
||||
// Добавляем фильтрацию по дате рождения
|
||||
const fromDate = req.query.fromDate;
|
||||
const toDate = req.query.toDate;
|
||||
const filteredData = filterByBirthday(data.pets, fromDate, toDate);
|
||||
|
||||
// Возвращаем отфильтрованные данные в формате отчета
|
||||
const reportData = generateReport(filteredData);
|
||||
res.json(reportData);
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
return res.status(500).json({ message: 'Internal Server Error' });
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
// Функция generateReport для создания отчета с id
|
||||
function generateReport(pets) {
|
||||
return pets.map((pet, index) => ({
|
||||
reportId: index + 1, // Уникальный id отчета (можете использовать другую логику)
|
||||
petid: pet.id,
|
||||
petname: pet.name,
|
||||
birthday: pet.birthday,
|
||||
userid: pet.userId,
|
||||
login: getUserLogin(pet.userId)
|
||||
}));
|
||||
}
|
||||
|
||||
// Функция для фильтрации по дате рождения
|
||||
function filterByBirthday(pets, fromDate, toDate) {
|
||||
if (!fromDate && !toDate) {
|
||||
return pets;
|
||||
}
|
||||
|
||||
const filteredPets = pets.filter((pet) => {
|
||||
const petBirthday = parseDate(pet.birthday);
|
||||
return (!fromDate || petBirthday >= parseDate(fromDate)) &&
|
||||
(!toDate || petBirthday <= parseDate(toDate));
|
||||
});
|
||||
|
||||
return filteredPets;
|
||||
}
|
||||
|
||||
// Функция для парсинга даты из строки в формате "dd.MM.yyyy"
|
||||
function parseDate(dateString) {
|
||||
const [day, month, year] = dateString.split('.').map(Number);
|
||||
return new Date(year, month - 1, day);
|
||||
}
|
||||
|
||||
// Функция для получения логина пользователя по userId
|
||||
function getUserLogin(userId) {
|
||||
const data = JSON.parse(fs.readFileSync(path.join(__dirname, 'data.json'), 'utf8'));
|
||||
const user = data.users.find((user) => user.id === userId);
|
||||
return user ? user.login : 'Unknown';
|
||||
}
|
Loading…
Reference in New Issue
Block a user