Enhance sample data download functionality and improve UI interaction
- Replaced direct download links with buttons for sample data downloads, improving user experience and interaction. - Implemented event listeners for the new download buttons to handle fiscal period parameters dynamically. - Updated the WorkbookTemplateService to include row data in the generated Excel files. - Added integration tests to verify that the correct fiscal period is used when downloading sample data.
This commit is contained in:
parent
087a274f47
commit
114c58737f
|
|
@ -434,9 +434,9 @@ function renderUploads() {
|
||||||
<div class="row actions">
|
<div class="row actions">
|
||||||
<button data-action="upload" ${isOperator() ? "" : "disabled"}>파일 업로드</button>
|
<button data-action="upload" ${isOperator() ? "" : "disabled"}>파일 업로드</button>
|
||||||
<button class="secondary" data-action="reload-uploads">내역 새로고침</button>
|
<button class="secondary" data-action="reload-uploads">내역 새로고침</button>
|
||||||
<a class="ghost" href="/sample-data/trial-balance-invalid.xlsx" download>오류 샘플</a>
|
<button class="ghost" data-action="download-sample" data-sample-code="trial-balance-invalid">오류 샘플</button>
|
||||||
<a class="ghost" href="/sample-data/trial-balance-valid.xlsx" download>정상 TB</a>
|
<button class="ghost" data-action="download-sample" data-sample-code="trial-balance-valid">정상 TB</button>
|
||||||
<a class="ghost" href="/sample-data/forecast-valid.xlsx" download>정상 Forecast</a>
|
<button class="ghost" data-action="download-sample" data-sample-code="forecast-valid">정상 Forecast</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
|
|
@ -604,14 +604,6 @@ function shellContent(content) {
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
<main class="main">
|
<main class="main">
|
||||||
<div class="topbar">
|
|
||||||
<div></div>
|
|
||||||
<div class="footer-links">
|
|
||||||
<a href="/sample-data/trial-balance-invalid.xlsx" download>오류 샘플</a>
|
|
||||||
<a href="/sample-data/trial-balance-valid.xlsx" download>정상 TB</a>
|
|
||||||
<a href="/sample-data/forecast-valid.xlsx" download>정상 Forecast</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
${content}
|
${content}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -836,6 +828,14 @@ function bindEvents() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll("[data-action='download-sample']").forEach((button) => {
|
||||||
|
button.addEventListener("click", () => {
|
||||||
|
const fiscalPeriod = document.getElementById("upload-period")?.value?.trim() || "2026-03";
|
||||||
|
const sampleCode = button.dataset.sampleCode;
|
||||||
|
window.location.href = `/api/uploads/samples/${sampleCode}/download?fiscalPeriod=${encodeURIComponent(fiscalPeriod)}`;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
document.querySelectorAll("[data-action='delete-upload']").forEach((button) => {
|
document.querySelectorAll("[data-action='delete-upload']").forEach((button) => {
|
||||||
button.addEventListener("click", async () => {
|
button.addEventListener("click", async () => {
|
||||||
if (!isOperator()) {
|
if (!isOperator()) {
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,13 @@ public class WorkbookTemplateService {
|
||||||
for (int index = 0; index < headers.size(); index++) {
|
for (int index = 0; index < headers.size(); index++) {
|
||||||
header.createCell(index).setCellValue(headers.get(index));
|
header.createCell(index).setCellValue(headers.get(index));
|
||||||
}
|
}
|
||||||
|
int rowIndex = 1;
|
||||||
|
for (List<String> rowValues : rows) {
|
||||||
|
Row row = dataSheet.createRow(rowIndex++);
|
||||||
|
for (int cellIndex = 0; cellIndex < rowValues.size(); cellIndex++) {
|
||||||
|
row.createCell(cellIndex).setCellValue(rowValues.get(cellIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
workbook.write(outputStream);
|
workbook.write(outputStream);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
@ -111,6 +113,23 @@ class UploadValidationIntegrationTest {
|
||||||
.andExpect(status().isForbidden());
|
.andExpect(status().isForbidden());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void sampleDownloadUsesRequestedFiscalPeriod() throws Exception {
|
||||||
|
MockHttpSession session = login("viewer", "demo1234");
|
||||||
|
|
||||||
|
MvcResult result = mockMvc.perform(get("/api/uploads/samples/trial-balance-valid/download")
|
||||||
|
.param("fiscalPeriod", "2026-04")
|
||||||
|
.session(session))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andReturn();
|
||||||
|
|
||||||
|
try (var workbook = WorkbookFactory.create(new ByteArrayInputStream(result.getResponse().getContentAsByteArray()))) {
|
||||||
|
var dataSheet = workbook.getSheet("DATA");
|
||||||
|
var firstDataRow = dataSheet.getRow(1);
|
||||||
|
org.junit.jupiter.api.Assertions.assertEquals("2026-04", firstDataRow.getCell(0).getStringCellValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private MockHttpSession login(String username, String password) throws Exception {
|
private MockHttpSession login(String username, String password) throws Exception {
|
||||||
MvcResult result = mockMvc.perform(post("/api/auth/login")
|
MvcResult result = mockMvc.perform(post("/api/auth/login")
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
|
|
||||||
|
|
@ -760,6 +760,14 @@ function bindEvents() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll("[data-action='download-sample']").forEach((button) => {
|
||||||
|
button.addEventListener("click", () => {
|
||||||
|
const fiscalPeriod = document.getElementById("upload-period")?.value?.trim() || "2026-03";
|
||||||
|
const sampleCode = button.dataset.sampleCode;
|
||||||
|
window.location.href = `/api/uploads/samples/${sampleCode}/download?fiscalPeriod=${encodeURIComponent(fiscalPeriod)}`;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
document.querySelectorAll("[data-action='delete-upload']").forEach((button) => {
|
document.querySelectorAll("[data-action='delete-upload']").forEach((button) => {
|
||||||
button.addEventListener("click", async () => {
|
button.addEventListener("click", async () => {
|
||||||
if (!isOperator()) {
|
if (!isOperator()) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue