Украл все, что можно, каким то чудом работает, сейчас буду норм переделывать под PDF
This commit is contained in:
parent
41d688791d
commit
61faa1af74
@ -5,6 +5,7 @@ import com.example.myapplication.api.rent.RentRemote
|
|||||||
import com.example.myapplication.api.item.ItemFromBikeRemote
|
import com.example.myapplication.api.item.ItemFromBikeRemote
|
||||||
import com.example.myapplication.api.item.ItemRemote
|
import com.example.myapplication.api.item.ItemRemote
|
||||||
import com.example.myapplication.api.item.ItemWithBikeRemote
|
import com.example.myapplication.api.item.ItemWithBikeRemote
|
||||||
|
import com.example.myapplication.api.report.ReportRemote
|
||||||
import com.example.myapplication.api.user.UserRemote
|
import com.example.myapplication.api.user.UserRemote
|
||||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -23,6 +24,12 @@ import retrofit2.http.Path
|
|||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
|
||||||
interface MyServerService {
|
interface MyServerService {
|
||||||
|
|
||||||
|
@GET("report")
|
||||||
|
suspend fun getReportInfo(
|
||||||
|
@Query("fromDate") fromDate: String,
|
||||||
|
@Query("toDate") toDate: String
|
||||||
|
): List<ReportRemote>
|
||||||
@GET("rents")
|
@GET("rents")
|
||||||
suspend fun getRents(): List<RentRemote>
|
suspend fun getRents(): List<RentRemote>
|
||||||
@GET("users/{id}")
|
@GET("users/{id}")
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.example.myapplication.api.item
|
package com.example.myapplication.api.item
|
||||||
|
|
||||||
import com.example.myapplication.api.MyServerService
|
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.model.Item
|
||||||
import com.example.myapplication.database.entities.repository.OfflineRentItemRepository
|
import com.example.myapplication.database.entities.repository.OfflineRentItemRepository
|
||||||
import com.example.myapplication.database.entities.repository.OfflineItemRepository
|
import com.example.myapplication.database.entities.repository.OfflineItemRepository
|
||||||
@ -48,4 +49,8 @@ class RestItemRepository(
|
|||||||
dbRentItemRepository.deleteItemsByUid(item.uid)
|
dbRentItemRepository.deleteItemsByUid(item.uid)
|
||||||
dbItemRepository.deleteItem(item)
|
dbItemRepository.deleteItem(item)
|
||||||
}
|
}
|
||||||
|
suspend fun getReport(fromDate: String, toDate: String):List<ReportRemote>
|
||||||
|
{
|
||||||
|
return service.getReportInfo(fromDate,toDate)
|
||||||
|
}
|
||||||
}
|
}
|
@ -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
|
||||||
|
)
|
@ -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.LoginScreen
|
||||||
import com.example.myapplication.database.entities.composeui.RentList
|
import com.example.myapplication.database.entities.composeui.RentList
|
||||||
import com.example.myapplication.database.entities.composeui.RentView
|
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.UserProfile
|
||||||
import com.example.myapplication.database.entities.composeui.edit.BikeEdit
|
import com.example.myapplication.database.entities.composeui.edit.BikeEdit
|
||||||
import com.example.myapplication.database.entities.composeui.edit.ItemEdit
|
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.RentList.route) { RentList(navController, currentUserViewModel = currentUserViewModel) }
|
||||||
composable(Screen.Cart.route) { Cart(currentUserViewModel = currentUserViewModel) }
|
composable(Screen.Cart.route) { Cart(currentUserViewModel = currentUserViewModel) }
|
||||||
composable(Screen.UserProfile.route) { UserProfile(navController,isDarkTheme, dataStore, 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.LoginScreen.route) { LoginScreen(navController) }
|
||||||
composable(
|
composable(
|
||||||
Screen.BikeEdit.route,
|
Screen.BikeEdit.route,
|
||||||
|
@ -15,6 +15,9 @@ enum class Screen(
|
|||||||
val icon: ImageVector = Icons.Filled.Favorite,
|
val icon: ImageVector = Icons.Filled.Favorite,
|
||||||
val showInBottomBar: Boolean = true
|
val showInBottomBar: Boolean = true
|
||||||
) {
|
) {
|
||||||
|
Report(
|
||||||
|
"report", R.string.report
|
||||||
|
),
|
||||||
BikeList(
|
BikeList(
|
||||||
"Bike-list", R.string.Bike_main_title, Icons.Filled.Home
|
"Bike-list", R.string.Bike_main_title, Icons.Filled.Home
|
||||||
),
|
),
|
||||||
|
@ -23,6 +23,11 @@ object AppViewModelProvider {
|
|||||||
initializer {
|
initializer {
|
||||||
BikeListViewModel(bikeApplication().container.bikeRestRepository)
|
BikeListViewModel(bikeApplication().container.bikeRestRepository)
|
||||||
}
|
}
|
||||||
|
initializer {
|
||||||
|
ReportViewModel(
|
||||||
|
bikeApplication().container.itemRestRepository,
|
||||||
|
)
|
||||||
|
}
|
||||||
initializer {
|
initializer {
|
||||||
BikeEditViewModel(
|
BikeEditViewModel(
|
||||||
this.createSavedStateHandle(),
|
this.createSavedStateHandle(),
|
||||||
|
@ -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)
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
@ -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()
|
||||||
|
)
|
@ -285,7 +285,8 @@ fun UserProfile(
|
|||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
createPdfFile(context = context, fileName = "отчет.pdf")
|
//createPdfFile(context = context, fileName = "отчет.pdf")
|
||||||
|
navController?.navigate(Screen.Report.route)
|
||||||
Log.d("context", "${context}")
|
Log.d("context", "${context}")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
<string name="Rent_view_title">Аренда</string>
|
<string name="Rent_view_title">Аренда</string>
|
||||||
<string name="Bike_name">Название</string>
|
<string name="Bike_name">Название</string>
|
||||||
<string name="Bike_description">Описание</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="Bike_image">Изображение</string>
|
||||||
<string name="Cart_title">Подтверждение</string>
|
<string name="Cart_title">Подтверждение</string>
|
||||||
<string name="Rent_title">Аренда</string>
|
<string name="Rent_title">Аренда</string>
|
||||||
|
61
server/router.js
Normal file
61
server/router.js
Normal 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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user