Files
KArtSell.Aegis/frontend/src/features/marketData/pages/MarketDataIngestion.vue.js
T
kjh2064 dfa1680a19
ci / backend (push) Failing after 0s
ci / static (push) Failing after 11s
ci / backend (pull_request) Failing after 1s
ci / static (pull_request) Failing after 12s
Build & Test with Secrets / build (pull_request) Failing after 2s
ci / publish (push) Has been cancelled
ci / frontend (push) Has been cancelled
Build & Test with Secrets / security-scan (pull_request) Has been cancelled
Build & Test with Secrets / notification (pull_request) Has been cancelled
Build & Test with Secrets / frontend (pull_request) Has been cancelled
ci / publish (pull_request) Has been cancelled
ci / frontend (pull_request) Has been cancelled
feat: align UI routes and menu with implemented screens
2026-08-06 01:39:33 +09:00

408 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ref, computed } from 'vue';
import { useRouter } from 'vue-router';
const router = useRouter();
const isLoading = ref(false);
const jobId = ref(null);
const form = ref({
dataSource: 'KRX',
fromDate: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
toDate: new Date().toISOString().split('T')[0],
});
const minDate = '2015-01-01'; // KRX historical data starts here
const maxDate = new Date().toISOString().split('T')[0]; // Today
const validationErrors = computed(() => {
const errors = [];
if (!form.value.fromDate)
errors.push('From Date is required');
if (!form.value.toDate)
errors.push('To Date is required');
if (form.value.fromDate && form.value.toDate) {
if (form.value.fromDate > form.value.toDate) {
errors.push('From Date must be before To Date');
}
if (form.value.toDate > maxDate) {
errors.push('To Date cannot be in the future');
}
}
return errors;
});
const daysCount = computed(() => {
if (!form.value.fromDate || !form.value.toDate)
return 0;
const from = new Date(form.value.fromDate);
const to = new Date(form.value.toDate);
return Math.ceil((to.getTime() - from.getTime()) / (1000 * 60 * 60 * 24));
});
const estimatedRows = computed(() => {
// KRX: ~2000 stocks × days
// OpenDart: ~200 quarterly filings
if (form.value.dataSource === 'KRX') {
return (daysCount.value * 2000).toLocaleString();
}
else if (form.value.dataSource === 'OpenDart') {
return (Math.ceil(daysCount.value / 90) * 200).toLocaleString();
}
return '0';
});
const setPreset = (preset) => {
const today = new Date();
const from = new Date();
if (preset === '1y')
from.setFullYear(from.getFullYear() - 1);
else if (preset === '2y')
from.setFullYear(from.getFullYear() - 2);
else if (preset === '5y')
from.setFullYear(from.getFullYear() - 5);
else if (preset === 'all')
from.setFullYear(2015);
form.value.fromDate = from.toISOString().split('T')[0];
form.value.toDate = today.toISOString().split('T')[0];
};
const triggerIngestion = async () => {
if (validationErrors.value.length > 0)
return;
isLoading.value = true;
try {
const response = await fetch('/api/market/ingest', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-KArtSell-User': 'ingestion-user',
'X-KArtSell-Role': 'DataAdmin',
},
body: JSON.stringify({
dataSource: form.value.dataSource,
fromDate: form.value.fromDate,
toDate: form.value.toDate,
}),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
jobId.value = data.jobId;
// Reset form after success
setTimeout(() => {
form.value.fromDate = new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
form.value.toDate = new Date().toISOString().split('T')[0];
jobId.value = null;
}, 5000);
}
catch (error) {
console.error('Ingestion error:', error);
alert(`Failed to trigger ingestion: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
finally {
isLoading.value = false;
}
};
const resetForm = () => {
form.value = {
dataSource: 'KRX',
fromDate: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
toDate: new Date().toISOString().split('T')[0],
};
jobId.value = null;
};
const __VLS_ctx = {
...{},
...{},
};
let __VLS_components;
let __VLS_intrinsics;
let __VLS_directives;
/** @type {__VLS_StyleScopedClasses['header']} */ ;
/** @type {__VLS_StyleScopedClasses['config-card']} */ ;
/** @type {__VLS_StyleScopedClasses['summary-card']} */ ;
/** @type {__VLS_StyleScopedClasses['error-card']} */ ;
/** @type {__VLS_StyleScopedClasses['success-card']} */ ;
/** @type {__VLS_StyleScopedClasses['form-group']} */ ;
/** @type {__VLS_StyleScopedClasses['form-group']} */ ;
/** @type {__VLS_StyleScopedClasses['form-group']} */ ;
/** @type {__VLS_StyleScopedClasses['preset-btn']} */ ;
/** @type {__VLS_StyleScopedClasses['summary-item']} */ ;
/** @type {__VLS_StyleScopedClasses['summary-item']} */ ;
/** @type {__VLS_StyleScopedClasses['error-card']} */ ;
/** @type {__VLS_StyleScopedClasses['error-card']} */ ;
/** @type {__VLS_StyleScopedClasses['error-card']} */ ;
/** @type {__VLS_StyleScopedClasses['error-card']} */ ;
/** @type {__VLS_StyleScopedClasses['success-card']} */ ;
/** @type {__VLS_StyleScopedClasses['success-card']} */ ;
/** @type {__VLS_StyleScopedClasses['job-info']} */ ;
/** @type {__VLS_StyleScopedClasses['job-info']} */ ;
/** @type {__VLS_StyleScopedClasses['btn-primary']} */ ;
/** @type {__VLS_StyleScopedClasses['btn-primary']} */ ;
/** @type {__VLS_StyleScopedClasses['btn-primary']} */ ;
/** @type {__VLS_StyleScopedClasses['btn-secondary']} */ ;
/** @type {__VLS_StyleScopedClasses['btn-secondary']} */ ;
/** @type {__VLS_StyleScopedClasses['btn-link']} */ ;
/** @type {__VLS_StyleScopedClasses['btn-link']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "market-data-ingestion" },
});
/** @type {__VLS_StyleScopedClasses['market-data-ingestion']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "header" },
});
/** @type {__VLS_StyleScopedClasses['header']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.h1, __VLS_intrinsics.h1)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.p, __VLS_intrinsics.p)({
...{ class: "subtitle" },
});
/** @type {__VLS_StyleScopedClasses['subtitle']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "content" },
});
/** @type {__VLS_StyleScopedClasses['content']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "config-card" },
});
/** @type {__VLS_StyleScopedClasses['config-card']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.h2, __VLS_intrinsics.h2)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "form-group" },
});
/** @type {__VLS_StyleScopedClasses['form-group']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.label, __VLS_intrinsics.label)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.select, __VLS_intrinsics.select)({
value: (__VLS_ctx.form.dataSource),
});
__VLS_asFunctionalElement1(__VLS_intrinsics.option, __VLS_intrinsics.option)({
value: "KRX",
});
__VLS_asFunctionalElement1(__VLS_intrinsics.option, __VLS_intrinsics.option)({
value: "OpenDart",
});
__VLS_asFunctionalElement1(__VLS_intrinsics.option, __VLS_intrinsics.option)({
value: "Stub",
});
__VLS_asFunctionalElement1(__VLS_intrinsics.p, __VLS_intrinsics.p)({
...{ class: "hint" },
});
/** @type {__VLS_StyleScopedClasses['hint']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.strong, __VLS_intrinsics.strong)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.strong, __VLS_intrinsics.strong)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "form-row" },
});
/** @type {__VLS_StyleScopedClasses['form-row']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "form-group" },
});
/** @type {__VLS_StyleScopedClasses['form-group']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.label, __VLS_intrinsics.label)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.input)({
type: "date",
min: (__VLS_ctx.minDate),
max: (__VLS_ctx.maxDate),
placeholder: "YYYY-MM-DD",
});
(__VLS_ctx.form.fromDate);
__VLS_asFunctionalElement1(__VLS_intrinsics.p, __VLS_intrinsics.p)({
...{ class: "hint" },
});
/** @type {__VLS_StyleScopedClasses['hint']} */ ;
(__VLS_ctx.minDate);
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "form-group" },
});
/** @type {__VLS_StyleScopedClasses['form-group']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.label, __VLS_intrinsics.label)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.input)({
type: "date",
min: (__VLS_ctx.form.fromDate || __VLS_ctx.minDate),
max: (__VLS_ctx.maxDate),
placeholder: "YYYY-MM-DD",
});
(__VLS_ctx.form.toDate);
__VLS_asFunctionalElement1(__VLS_intrinsics.p, __VLS_intrinsics.p)({
...{ class: "hint" },
});
/** @type {__VLS_StyleScopedClasses['hint']} */ ;
(__VLS_ctx.maxDate);
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "presets" },
});
/** @type {__VLS_StyleScopedClasses['presets']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.button, __VLS_intrinsics.button)({
...{ onClick: (...[$event]) => {
return (__VLS_ctx.setPreset('1y'));
// @ts-ignore
[form, form, form, form, minDate, minDate, minDate, maxDate, maxDate, maxDate, setPreset,];
} },
...{ class: "preset-btn" },
});
/** @type {__VLS_StyleScopedClasses['preset-btn']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.button, __VLS_intrinsics.button)({
...{ onClick: (...[$event]) => {
return (__VLS_ctx.setPreset('2y'));
// @ts-ignore
[setPreset,];
} },
...{ class: "preset-btn" },
});
/** @type {__VLS_StyleScopedClasses['preset-btn']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.button, __VLS_intrinsics.button)({
...{ onClick: (...[$event]) => {
return (__VLS_ctx.setPreset('5y'));
// @ts-ignore
[setPreset,];
} },
...{ class: "preset-btn" },
});
/** @type {__VLS_StyleScopedClasses['preset-btn']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.button, __VLS_intrinsics.button)({
...{ onClick: (...[$event]) => {
return (__VLS_ctx.setPreset('all'));
// @ts-ignore
[setPreset,];
} },
...{ class: "preset-btn" },
});
/** @type {__VLS_StyleScopedClasses['preset-btn']} */ ;
if (__VLS_ctx.validationErrors.length) {
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "error-card" },
});
/** @type {__VLS_StyleScopedClasses['error-card']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.h3, __VLS_intrinsics.h3)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.ul, __VLS_intrinsics.ul)({});
for (const [err, idx] of __VLS_vFor((__VLS_ctx.validationErrors))) {
__VLS_asFunctionalElement1(__VLS_intrinsics.li, __VLS_intrinsics.li)({
key: (idx),
});
(err);
// @ts-ignore
[validationErrors, validationErrors,];
}
}
if (!__VLS_ctx.validationErrors.length) {
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "summary-card" },
});
/** @type {__VLS_StyleScopedClasses['summary-card']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.h3, __VLS_intrinsics.h3)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "summary-grid" },
});
/** @type {__VLS_StyleScopedClasses['summary-grid']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "summary-item" },
});
/** @type {__VLS_StyleScopedClasses['summary-item']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
...{ class: "label" },
});
/** @type {__VLS_StyleScopedClasses['label']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
...{ class: "value" },
});
/** @type {__VLS_StyleScopedClasses['value']} */ ;
(__VLS_ctx.form.dataSource);
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "summary-item" },
});
/** @type {__VLS_StyleScopedClasses['summary-item']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
...{ class: "label" },
});
/** @type {__VLS_StyleScopedClasses['label']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
...{ class: "value" },
});
/** @type {__VLS_StyleScopedClasses['value']} */ ;
(__VLS_ctx.form.fromDate);
(__VLS_ctx.form.toDate);
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "summary-item" },
});
/** @type {__VLS_StyleScopedClasses['summary-item']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
...{ class: "label" },
});
/** @type {__VLS_StyleScopedClasses['label']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
...{ class: "value" },
});
/** @type {__VLS_StyleScopedClasses['value']} */ ;
(__VLS_ctx.daysCount);
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "summary-item" },
});
/** @type {__VLS_StyleScopedClasses['summary-item']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
...{ class: "label" },
});
/** @type {__VLS_StyleScopedClasses['label']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
...{ class: "value" },
});
/** @type {__VLS_StyleScopedClasses['value']} */ ;
(__VLS_ctx.estimatedRows);
}
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "actions" },
});
/** @type {__VLS_StyleScopedClasses['actions']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.button, __VLS_intrinsics.button)({
...{ onClick: (__VLS_ctx.triggerIngestion) },
disabled: (__VLS_ctx.isLoading || __VLS_ctx.validationErrors.length > 0),
...{ class: "btn-primary" },
});
/** @type {__VLS_StyleScopedClasses['btn-primary']} */ ;
if (!__VLS_ctx.isLoading) {
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({});
}
else {
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({});
}
__VLS_asFunctionalElement1(__VLS_intrinsics.button, __VLS_intrinsics.button)({
...{ onClick: (__VLS_ctx.resetForm) },
...{ class: "btn-secondary" },
});
/** @type {__VLS_StyleScopedClasses['btn-secondary']} */ ;
if (__VLS_ctx.jobId) {
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "success-card" },
});
/** @type {__VLS_StyleScopedClasses['success-card']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.h3, __VLS_intrinsics.h3)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
...{ class: "job-info" },
});
/** @type {__VLS_StyleScopedClasses['job-info']} */ ;
__VLS_asFunctionalElement1(__VLS_intrinsics.p, __VLS_intrinsics.p)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.strong, __VLS_intrinsics.strong)({});
(__VLS_ctx.jobId);
__VLS_asFunctionalElement1(__VLS_intrinsics.p, __VLS_intrinsics.p)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.strong, __VLS_intrinsics.strong)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.p, __VLS_intrinsics.p)({});
__VLS_asFunctionalElement1(__VLS_intrinsics.strong, __VLS_intrinsics.strong)({});
(new Date().toLocaleString());
__VLS_asFunctionalElement1(__VLS_intrinsics.p, __VLS_intrinsics.p)({
...{ class: "hint" },
});
/** @type {__VLS_StyleScopedClasses['hint']} */ ;
let __VLS_0;
/** @ts-ignore @type { | typeof __VLS_components.routerLink | typeof __VLS_components.RouterLink | typeof __VLS_components['router-link'] | typeof __VLS_components.routerLink | typeof __VLS_components.RouterLink | typeof __VLS_components['router-link']} */
routerLink;
// @ts-ignore
const __VLS_1 = __VLS_asFunctionalComponent1(__VLS_0, new __VLS_0({
to: "/ops/market-data-history",
...{ class: "btn-link" },
}));
const __VLS_2 = __VLS_1({
to: "/ops/market-data-history",
...{ class: "btn-link" },
}, ...__VLS_functionalComponentArgsRest(__VLS_1));
/** @type {__VLS_StyleScopedClasses['btn-link']} */ ;
const { default: __VLS_5 } = __VLS_3.slots;
// @ts-ignore
[form, form, form, validationErrors, validationErrors, daysCount, estimatedRows, triggerIngestion, isLoading, isLoading, resetForm, jobId, jobId,];
var __VLS_3;
}
// @ts-ignore
[];
const __VLS_export = (await import('vue')).defineComponent({});
export default {};