Украл все, что можно, каким то чудом работает, сейчас буду норм переделывать под PDF

This commit is contained in:
Кашин Максим 2023-12-25 20:40:46 +04:00
parent 41d688791d
commit 61faa1af74
11 changed files with 313 additions and 1 deletions

View File

@ -5,6 +5,7 @@ import com.example.myapplication.api.rent.RentRemote
import com.example.myapplication.api.item.ItemFromBikeRemote
import com.example.myapplication.api.item.ItemRemote
import com.example.myapplication.api.item.ItemWithBikeRemote
import com.example.myapplication.api.report.ReportRemote
import com.example.myapplication.api.user.UserRemote
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
@ -23,6 +24,12 @@ import retrofit2.http.Path
import retrofit2.http.Query
interface MyServerService {
@GET("report")
suspend fun getReportInfo(
@Query("fromDate") fromDate: String,
@Query("toDate") toDate: String
): List<ReportRemote>
@GET("rents")
suspend fun getRents(): List<RentRemote>
@GET("users/{id}")

View File

@ -1,6 +1,7 @@
package com.example.myapplication.api.item
import com.example.myapplication.api.MyServerService
import com.example.myapplication.api.report.ReportRemote
import com.example.myapplication.database.entities.model.Item
import com.example.myapplication.database.entities.repository.OfflineRentItemRepository
import com.example.myapplication.database.entities.repository.OfflineItemRepository
@ -48,4 +49,8 @@ class RestItemRepository(
dbRentItemRepository.deleteItemsByUid(item.uid)
dbItemRepository.deleteItem(item)
}
suspend fun getReport(fromDate: String, toDate: String):List<ReportRemote>
{
return service.getReportInfo(fromDate,toDate)
}
}

View File

@ -0,0 +1,12 @@
package com.example.myapplication.api.report
import kotlinx.serialization.Serializable
@Serializable
data class ReportRemote(
val id: Int = 0,
val dateTime: Int = 0,
val weight: Double = 0.0,
val maxCount: Int = 0,
val bikeId: Int = 0
)

View File

@ -55,6 +55,7 @@ import com.example.myapplication.database.entities.composeui.CurrentUserViewMode
import com.example.myapplication.database.entities.composeui.LoginScreen
import com.example.myapplication.database.entities.composeui.RentList
import com.example.myapplication.database.entities.composeui.RentView
import com.example.myapplication.database.entities.composeui.ReportPage
import com.example.myapplication.database.entities.composeui.UserProfile
import com.example.myapplication.database.entities.composeui.edit.BikeEdit
import com.example.myapplication.database.entities.composeui.edit.ItemEdit
@ -190,6 +191,7 @@ fun Navhost(
composable(Screen.RentList.route) { RentList(navController, currentUserViewModel = currentUserViewModel) }
composable(Screen.Cart.route) { Cart(currentUserViewModel = currentUserViewModel) }
composable(Screen.UserProfile.route) { UserProfile(navController,isDarkTheme, dataStore, currentUserViewModel = currentUserViewModel) }
composable(Screen.Report.route) { ReportPage(navController = navController) }
composable(Screen.LoginScreen.route) { LoginScreen(navController) }
composable(
Screen.BikeEdit.route,

View File

@ -15,6 +15,9 @@ enum class Screen(
val icon: ImageVector = Icons.Filled.Favorite,
val showInBottomBar: Boolean = true
) {
Report(
"report", R.string.report
),
BikeList(
"Bike-list", R.string.Bike_main_title, Icons.Filled.Home
),

View File

@ -23,6 +23,11 @@ object AppViewModelProvider {
initializer {
BikeListViewModel(bikeApplication().container.bikeRestRepository)
}
initializer {
ReportViewModel(
bikeApplication().container.itemRestRepository,
)
}
initializer {
BikeEditViewModel(
this.createSavedStateHandle(),

View File

@ -0,0 +1,156 @@
package com.example.myapplication.database.entities.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.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
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.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.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.example.myapplication.R
import com.example.myapplication.api.report.ReportRemote
import kotlinx.coroutines.launch
import java.util.Date
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ReportPage (navController: NavController?, viewModel: ReportViewModel = viewModel(factory = AppViewModelProvider.Factory))
{
val dateStateStart = rememberDatePickerState(initialDisplayMode = DisplayMode.Input)
val dateStateEnd = rememberDatePickerState(initialDisplayMode = DisplayMode.Input)
val coroutineScope = rememberCoroutineScope()
val reportResultPageState = viewModel.reportResultPageUiState
Column(
modifier = Modifier
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
)
{
Text(
text = stringResource(id = R.string.startDate),
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 = stringResource(id = R.string.endDate),
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()
.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)
}
}
@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>) {
val column1Weight = .3f // 30%
val column2Weight = 1f // 30%
Column(
Modifier
.padding(16.dp)) {
Row(Modifier.background(Color.White)) {
TableCell(text = "ID", weight = column1Weight)
TableCell(text = "Товар", weight = column1Weight)
TableCell(text = "Кол-во", weight = column1Weight)
TableCell(text = "Цена", weight = column1Weight)
}
// Here are all the lines of your table.
reportData.forEach {
val (productId, productName, sellsAmount, sellsPrice) = it
Row(Modifier.fillMaxWidth()) {
TableCell(text = productId.toString(), weight = column1Weight)
TableCell(text = sellsAmount.toString(), weight = column1Weight)
TableCell(text = sellsPrice.toString(), weight = column1Weight)
}
}
/* Row(Modifier.fillMaxWidth()) {
TableCell(text = "Общая цена: " + reportData.map { x -> x.sellsPrice}.sum().toString(), weight = column2Weight)
}*/
}
}

View File

@ -0,0 +1,57 @@
package com.example.myapplication.database.entities.composeui
import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import com.example.myapplication.api.item.RestItemRepository
import com.example.myapplication.api.report.ReportRemote
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
class ReportViewModel(private val itemRespository: RestItemRepository): 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 {
Log.d("validateInput", uiState.endDate.toString())
return with(uiState) {
startDate != Date(0) && endDate != Date(0) && startDate < endDate
}
}
suspend fun getReport() {
val dateFormatter = SimpleDateFormat("yyyy", Locale.getDefault())
// Преобразование даты в строку в формате "yyyy"
val startDateQueryParam = dateFormatter.format(reportPageUiState.reportDetails.startDate)
val endDateQueryParam = dateFormatter.format(reportPageUiState.reportDetails.endDate)
// Вызов репозитория с отформатированными датами
val res = itemRespository.getReport(startDateQueryParam, endDateQueryParam)
reportResultPageUiState = ReportResultPageUiState(res)
}
}
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: List<ReportRemote> = emptyList()
)

View File

@ -285,7 +285,8 @@ fun UserProfile(
Button(
onClick = {
coroutineScope.launch {
createPdfFile(context = context, fileName = "отчет.pdf")
//createPdfFile(context = context, fileName = "отчет.pdf")
navController?.navigate(Screen.Report.route)
Log.d("context", "${context}")
}
},

View File

@ -6,6 +6,9 @@
<string name="Rent_view_title">Аренда</string>
<string name="Bike_name">Название</string>
<string name="Bike_description">Описание</string>
<string name="report">Отчет</string>
<string name="startDate">Дата начала</string>
<string name="endDate">Дата конца</string>
<string name="Bike_image">Изображение</string>
<string name="Cart_title">Подтверждение</string>
<string name="Rent_title">Аренда</string>

61
server/router.js Normal file
View File

@ -0,0 +1,61 @@
const data = require('./data.json');
module.exports = (req, res, next) => {
if (req.url.startsWith('/search') && req.method === 'GET') {
try {
const searchText = req.query.name;
const searched = data.products.filter(
(product) =>
(product.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 {
// Добавляем фильтрацию по полю dateTime
const fromDate = req.query.fromDate;
const toDate = req.query.toDate;
const filteredData = filterByDateTime(data.items, 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 для примера
function generateReport(items) {
// Ваш код для генерации отчета
return items.map((item) => ({
id: item.id,
dateTime: item.dateTime,
weight: item.weight,
maxCount: item.maxCount,
bikeId: item.bikeId
// Другие поля отчета, которые вам нужны
}));
}
// Функция для фильтрации по полю dateTime
function filterByDateTime(items, fromDate, toDate) {
if (!fromDate && !toDate) {
return items;
}
const filteredItems = items.filter((item) => {
const itemDate = item.dateTime;
return (!fromDate || itemDate >= fromDate) && (!toDate || itemDate <= toDate);
});
return filteredItems;
}