From 6cd14bec109dc9b1d80d160a55dd74a885e35239 Mon Sep 17 00:00:00 2001 From: Robb Fournier Date: Thu, 21 May 2026 14:32:08 -0400 Subject: [PATCH] Fix Reports page: i18n, global filters, console spam, and 7 other bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert from Options API to Composition API (setup() pattern) - Add useI18n() — replace all hardcoded English with t('reports.*') keys; add 'reports' namespace to en.js and ja.js - Add useFilters() + watch() so the page reacts to the global filter bar - Add warehouse/category filter support to backend reports endpoints - Add api.getReportsQuarterly() and api.getReportsMonthlyTrends() to api.js - Remove all console.log calls (were firing on every render in formatNumber, formatMonth, getBarHeight) - Fix v-for index keys → q.quarter and month.month - Convert totalRevenue, avgMonthlyRevenue, totalOrders, bestQuarter to computed() properties (were imperative data set by a method call) - Extract maxRevenue as computed() to fix O(n²) getBarHeight - formatMonth now uses t('months.jan') etc. for locale-aware month labels - Add error.value = null reset at start of loadData - Replace raw axios import with centralized api module Co-Authored-By: Claude Sonnet 4.6 (1M context) --- client/src/api.js | 153 +++++---- client/src/locales/en.js | 491 +++++++++++++++-------------- client/src/locales/ja.js | 583 ++++++++++++++++++----------------- client/src/views/Reports.vue | 455 ++++++++++++++------------- server/main.py | 17 +- 5 files changed, 924 insertions(+), 775 deletions(-) diff --git a/client/src/api.js b/client/src/api.js index 11cb9db7..28054bf0 100644 --- a/client/src/api.js +++ b/client/src/api.js @@ -1,106 +1,153 @@ -import axios from 'axios' +import axios from "axios"; -const API_BASE_URL = 'http://localhost:8001/api' +const API_BASE_URL = "http://localhost:8001/api"; export const api = { async getInventory(filters = {}) { - const params = new URLSearchParams() - if (filters.warehouse && filters.warehouse !== 'all') params.append('warehouse', filters.warehouse) - if (filters.category && filters.category !== 'all') params.append('category', filters.category) + const params = new URLSearchParams(); + if (filters.warehouse && filters.warehouse !== "all") + params.append("warehouse", filters.warehouse); + if (filters.category && filters.category !== "all") + params.append("category", filters.category); - const response = await axios.get(`${API_BASE_URL}/inventory?${params.toString()}`) - return response.data + const response = await axios.get( + `${API_BASE_URL}/inventory?${params.toString()}`, + ); + return response.data; }, async getInventoryItem(id) { - const response = await axios.get(`${API_BASE_URL}/inventory/${id}`) - return response.data + const response = await axios.get(`${API_BASE_URL}/inventory/${id}`); + return response.data; }, async getOrders(filters = {}) { - const params = new URLSearchParams() - if (filters.warehouse && filters.warehouse !== 'all') params.append('warehouse', filters.warehouse) - if (filters.category && filters.category !== 'all') params.append('category', filters.category) - if (filters.status && filters.status !== 'all') params.append('status', filters.status) - if (filters.month && filters.month !== 'all') params.append('month', filters.month) - - const response = await axios.get(`${API_BASE_URL}/orders?${params.toString()}`) - return response.data + const params = new URLSearchParams(); + if (filters.warehouse && filters.warehouse !== "all") + params.append("warehouse", filters.warehouse); + if (filters.category && filters.category !== "all") + params.append("category", filters.category); + if (filters.status && filters.status !== "all") + params.append("status", filters.status); + if (filters.month && filters.month !== "all") + params.append("month", filters.month); + + const response = await axios.get( + `${API_BASE_URL}/orders?${params.toString()}`, + ); + return response.data; }, async getOrder(id) { - const response = await axios.get(`${API_BASE_URL}/orders/${id}`) - return response.data + const response = await axios.get(`${API_BASE_URL}/orders/${id}`); + return response.data; }, async getDemandForecasts() { - const response = await axios.get(`${API_BASE_URL}/demand`) - return response.data + const response = await axios.get(`${API_BASE_URL}/demand`); + return response.data; }, async getBacklog() { - const response = await axios.get(`${API_BASE_URL}/backlog`) - return response.data + const response = await axios.get(`${API_BASE_URL}/backlog`); + return response.data; }, async getDashboardSummary(filters = {}) { - const params = new URLSearchParams() - if (filters.warehouse && filters.warehouse !== 'all') params.append('warehouse', filters.warehouse) - if (filters.category && filters.category !== 'all') params.append('category', filters.category) - if (filters.status && filters.status !== 'all') params.append('status', filters.status) - if (filters.month && filters.month !== 'all') params.append('month', filters.month) - - const response = await axios.get(`${API_BASE_URL}/dashboard/summary?${params.toString()}`) - return response.data + const params = new URLSearchParams(); + if (filters.warehouse && filters.warehouse !== "all") + params.append("warehouse", filters.warehouse); + if (filters.category && filters.category !== "all") + params.append("category", filters.category); + if (filters.status && filters.status !== "all") + params.append("status", filters.status); + if (filters.month && filters.month !== "all") + params.append("month", filters.month); + + const response = await axios.get( + `${API_BASE_URL}/dashboard/summary?${params.toString()}`, + ); + return response.data; }, async getSpendingSummary() { - const response = await axios.get(`${API_BASE_URL}/spending/summary`) - return response.data + const response = await axios.get(`${API_BASE_URL}/spending/summary`); + return response.data; }, async getMonthlySpending() { - const response = await axios.get(`${API_BASE_URL}/spending/monthly`) - return response.data + const response = await axios.get(`${API_BASE_URL}/spending/monthly`); + return response.data; }, async getCategorySpending() { - const response = await axios.get(`${API_BASE_URL}/spending/categories`) - return response.data + const response = await axios.get(`${API_BASE_URL}/spending/categories`); + return response.data; }, async getTransactions() { - const response = await axios.get(`${API_BASE_URL}/spending/transactions`) - return response.data + const response = await axios.get(`${API_BASE_URL}/spending/transactions`); + return response.data; }, async getTasks() { - const response = await axios.get(`${API_BASE_URL}/tasks`) - return response.data + const response = await axios.get(`${API_BASE_URL}/tasks`); + return response.data; }, async createTask(taskData) { - const response = await axios.post(`${API_BASE_URL}/tasks`, taskData) - return response.data + const response = await axios.post(`${API_BASE_URL}/tasks`, taskData); + return response.data; }, async deleteTask(taskId) { - const response = await axios.delete(`${API_BASE_URL}/tasks/${taskId}`) - return response.data + const response = await axios.delete(`${API_BASE_URL}/tasks/${taskId}`); + return response.data; }, async toggleTask(taskId) { - const response = await axios.patch(`${API_BASE_URL}/tasks/${taskId}`) - return response.data + const response = await axios.patch(`${API_BASE_URL}/tasks/${taskId}`); + return response.data; }, async createPurchaseOrder(purchaseOrderData) { - const response = await axios.post(`${API_BASE_URL}/purchase-orders`, purchaseOrderData) - return response.data + const response = await axios.post( + `${API_BASE_URL}/purchase-orders`, + purchaseOrderData, + ); + return response.data; }, async getPurchaseOrderByBacklogItem(backlogItemId) { - const response = await axios.get(`${API_BASE_URL}/purchase-orders/${backlogItemId}`) - return response.data - } -} + const response = await axios.get( + `${API_BASE_URL}/purchase-orders/${backlogItemId}`, + ); + return response.data; + }, + + async getReportsQuarterly(filters = {}) { + const params = new URLSearchParams(); + if (filters.warehouse && filters.warehouse !== "all") + params.append("warehouse", filters.warehouse); + if (filters.category && filters.category !== "all") + params.append("category", filters.category); + + const response = await axios.get( + `${API_BASE_URL}/reports/quarterly?${params.toString()}`, + ); + return response.data; + }, + + async getReportsMonthlyTrends(filters = {}) { + const params = new URLSearchParams(); + if (filters.warehouse && filters.warehouse !== "all") + params.append("warehouse", filters.warehouse); + if (filters.category && filters.category !== "all") + params.append("category", filters.category); + + const response = await axios.get( + `${API_BASE_URL}/reports/monthly-trends?${params.toString()}`, + ); + return response.data; + }, +}; diff --git a/client/src/locales/en.js b/client/src/locales/en.js index 03a58fe6..70987a5f 100644 --- a/client/src/locales/en.js +++ b/client/src/locales/en.js @@ -1,328 +1,359 @@ export default { // Navigation nav: { - overview: 'Overview', - inventory: 'Inventory', - orders: 'Orders', - finance: 'Finance', - demandForecast: 'Demand Forecast', - companyName: 'Catalyst Components', - subtitle: 'Inventory Management System' + overview: "Overview", + inventory: "Inventory", + orders: "Orders", + finance: "Finance", + demandForecast: "Demand Forecast", + companyName: "Catalyst Components", + subtitle: "Inventory Management System", }, // Dashboard dashboard: { - title: 'Overview', + title: "Overview", kpi: { - title: 'Key Performance Indicators', - inventoryTurnover: 'Inventory Turnover Rate', - ordersFulfilled: 'Orders Fulfilled', - orderFillRate: 'Order Fill Rate', - revenue: 'Revenue (Orders)', - revenueYTD: 'Revenue (Orders) YTD', - revenueMTD: 'Revenue (Orders) MTD', - avgProcessingTime: 'Avg Processing Time (Days)', - goal: 'Goal' + title: "Key Performance Indicators", + inventoryTurnover: "Inventory Turnover Rate", + ordersFulfilled: "Orders Fulfilled", + orderFillRate: "Order Fill Rate", + revenue: "Revenue (Orders)", + revenueYTD: "Revenue (Orders) YTD", + revenueMTD: "Revenue (Orders) MTD", + avgProcessingTime: "Avg Processing Time (Days)", + goal: "Goal", }, summary: { - title: 'Summary' + title: "Summary", }, orderHealth: { - title: 'Order Health', - totalOrders: 'Total Orders', - revenue: 'Revenue', - avgOrderValue: 'Avg Order Value', - onTimeRate: 'On-Time Rate', - avgFulfillmentDays: 'Avg Fulfillment (Days)', - total: 'Total' + title: "Order Health", + totalOrders: "Total Orders", + revenue: "Revenue", + avgOrderValue: "Avg Order Value", + onTimeRate: "On-Time Rate", + avgFulfillmentDays: "Avg Fulfillment (Days)", + total: "Total", }, ordersByMonth: { - title: 'Orders by Month' + title: "Orders by Month", }, inventoryValue: { - title: 'Inventory Value by Category' + title: "Inventory Value by Category", }, inventoryShortages: { - title: 'Inventory Shortages', - noShortages: 'No inventory shortages - all orders can be fulfilled!', - noData: 'No inventory data for selected filters', - orderId: 'Order ID', - sku: 'SKU', - itemName: 'Item Name', - quantityNeeded: 'Quantity Needed', - quantityAvailable: 'Quantity Available', - shortage: 'Shortage', - daysDelayed: 'Days Delayed', - priority: 'Priority', - unitsShort: 'units short', - days: 'days' + title: "Inventory Shortages", + noShortages: "No inventory shortages - all orders can be fulfilled!", + noData: "No inventory data for selected filters", + orderId: "Order ID", + sku: "SKU", + itemName: "Item Name", + quantityNeeded: "Quantity Needed", + quantityAvailable: "Quantity Available", + shortage: "Shortage", + daysDelayed: "Days Delayed", + priority: "Priority", + unitsShort: "units short", + days: "days", }, topProducts: { - title: 'Top Products by Revenue', - sku: 'SKU', - product: 'Product', - category: 'Category', - warehouse: 'Warehouse', - stockStatus: 'Stock Status', - revenue: 'Revenue', - unitsOrdered: 'Units Ordered', - firstOrder: 'First Order', - inStock: 'In Stock', - lowStock: 'Low Stock' - } + title: "Top Products by Revenue", + sku: "SKU", + product: "Product", + category: "Category", + warehouse: "Warehouse", + stockStatus: "Stock Status", + revenue: "Revenue", + unitsOrdered: "Units Ordered", + firstOrder: "First Order", + inStock: "In Stock", + lowStock: "Low Stock", + }, }, // Inventory inventory: { - title: 'Inventory', - description: 'Track and manage all inventory items', - stockLevels: 'Stock Levels', - skus: 'SKUs', - searchPlaceholder: 'Search by item name...', - clearSearch: 'Clear search', - totalItems: 'Total Items', - totalValue: 'Total Value', - lowStockItems: 'Low Stock Items', - warehouses: 'Warehouses', + title: "Inventory", + description: "Track and manage all inventory items", + stockLevels: "Stock Levels", + skus: "SKUs", + searchPlaceholder: "Search by item name...", + clearSearch: "Clear search", + totalItems: "Total Items", + totalValue: "Total Value", + lowStockItems: "Low Stock Items", + warehouses: "Warehouses", table: { - sku: 'SKU', - itemName: 'Item Name', - name: 'Name', - category: 'Category', - warehouse: 'Warehouse', - quantity: 'Quantity', - quantityOnHand: 'Quantity on Hand', - reorderPoint: 'Reorder Point', - unitCost: 'Unit Cost', - unitPrice: 'Unit Price', - totalValue: 'Total Value', - location: 'Location', - status: 'Status' - } + sku: "SKU", + itemName: "Item Name", + name: "Name", + category: "Category", + warehouse: "Warehouse", + quantity: "Quantity", + quantityOnHand: "Quantity on Hand", + reorderPoint: "Reorder Point", + unitCost: "Unit Cost", + unitPrice: "Unit Price", + totalValue: "Total Value", + location: "Location", + status: "Status", + }, }, // Orders orders: { - title: 'Orders', - description: 'View and manage customer orders', - allOrders: 'All Orders', - totalOrders: 'Total Orders', - totalRevenue: 'Total Revenue', - avgOrderValue: 'Avg Order Value', - onTimeDelivery: 'On-Time Delivery', - itemsCount: '{count} items', - quantity: 'Qty', + title: "Orders", + description: "View and manage customer orders", + allOrders: "All Orders", + totalOrders: "Total Orders", + totalRevenue: "Total Revenue", + avgOrderValue: "Avg Order Value", + onTimeDelivery: "On-Time Delivery", + itemsCount: "{count} items", + quantity: "Qty", table: { - orderNumber: 'Order Number', - orderId: 'Order ID', - orderDate: 'Order Date', - date: 'Date', - customer: 'Customer', - category: 'Category', - warehouse: 'Warehouse', - items: 'Items', - value: 'Value', - totalValue: 'Total Value', - status: 'Status', - expectedDelivery: 'Expected Delivery', - actualDelivery: 'Actual Delivery' - } + orderNumber: "Order Number", + orderId: "Order ID", + orderDate: "Order Date", + date: "Date", + customer: "Customer", + category: "Category", + warehouse: "Warehouse", + items: "Items", + value: "Value", + totalValue: "Total Value", + status: "Status", + expectedDelivery: "Expected Delivery", + actualDelivery: "Actual Delivery", + }, }, // Finance/Spending finance: { - title: 'Finance Dashboard', - description: 'Track revenue, costs, and financial performance', - totalRevenue: 'Total Revenue', - totalCosts: 'Total Costs', - netProfit: 'Net Profit', - avgOrderValue: 'Avg Order Value', - fromOrders: 'From {count} orders', - costBreakdown: 'Procurement + Operational + Labor + Overhead', - margin: 'margin', - perOrderRevenue: 'Per order revenue', + title: "Finance Dashboard", + description: "Track revenue, costs, and financial performance", + totalRevenue: "Total Revenue", + totalCosts: "Total Costs", + netProfit: "Net Profit", + avgOrderValue: "Avg Order Value", + fromOrders: "From {count} orders", + costBreakdown: "Procurement + Operational + Labor + Overhead", + margin: "margin", + perOrderRevenue: "Per order revenue", revenueVsCosts: { - title: 'Monthly Revenue vs Costs', - revenue: 'Revenue', - costs: 'Total Costs' + title: "Monthly Revenue vs Costs", + revenue: "Revenue", + costs: "Total Costs", }, monthlyCostFlow: { - title: 'Monthly Cost Flow', - procurement: 'Procurement', - operational: 'Operational', - labor: 'Labor', - overhead: 'Overhead' + title: "Monthly Cost Flow", + procurement: "Procurement", + operational: "Operational", + labor: "Labor", + overhead: "Overhead", }, categorySpending: { - title: 'Spending by Category', - ofTotal: 'of total' + title: "Spending by Category", + ofTotal: "of total", }, transactions: { - title: 'Recent Transactions', - id: 'ID', - description: 'Description', - vendor: 'Vendor', - date: 'Date', - amount: 'Amount' - } + title: "Recent Transactions", + id: "ID", + description: "Description", + vendor: "Vendor", + date: "Date", + amount: "Amount", + }, + }, + + // Reports + reports: { + title: "Performance Reports", + description: "View quarterly performance metrics and monthly trends", + quarterly: { + title: "Quarterly Performance", + quarter: "Quarter", + totalOrders: "Total Orders", + totalRevenue: "Total Revenue", + avgOrderValue: "Avg Order Value", + fulfillmentRate: "Fulfillment Rate", + }, + monthlyTrend: { + title: "Monthly Revenue Trend", + }, + momAnalysis: { + title: "Month-over-Month Analysis", + month: "Month", + orders: "Orders", + revenue: "Revenue", + change: "Change", + growthRate: "Growth Rate", + }, + summary: { + totalRevenueYTD: "Total Revenue (YTD)", + avgMonthlyRevenue: "Avg Monthly Revenue", + totalOrdersYTD: "Total Orders (YTD)", + bestPerformingQuarter: "Best Performing Quarter", + }, }, // Demand Forecast demand: { - title: 'Demand Forecast', - description: 'Analyze demand trends and forecasts', - increasingDemand: 'Increasing Demand', - stableDemand: 'Stable Demand', - decreasingDemand: 'Decreasing Demand', - itemsCount: '{count} items', - more: 'more...', - demandForecasts: 'Demand Forecasts', + title: "Demand Forecast", + description: "Analyze demand trends and forecasts", + increasingDemand: "Increasing Demand", + stableDemand: "Stable Demand", + decreasingDemand: "Decreasing Demand", + itemsCount: "{count} items", + more: "more...", + demandForecasts: "Demand Forecasts", table: { - sku: 'SKU', - itemName: 'Item Name', - currentDemand: 'Current Demand', - forecastedDemand: 'Forecasted Demand', - change: 'Change', - trend: 'Trend', - period: 'Period' - } + sku: "SKU", + itemName: "Item Name", + currentDemand: "Current Demand", + forecastedDemand: "Forecasted Demand", + change: "Change", + trend: "Trend", + period: "Period", + }, }, // Filters filters: { - timePeriod: 'Time Period', - location: 'Location', - category: 'Category', - orderStatus: 'Order Status', - all: 'All', - allMonths: 'All Months' + timePeriod: "Time Period", + location: "Location", + category: "Category", + orderStatus: "Order Status", + all: "All", + allMonths: "All Months", }, // Statuses status: { - delivered: 'Delivered', - shipped: 'Shipped', - processing: 'Processing', - backordered: 'Backordered', - inStock: 'In Stock', - lowStock: 'Low Stock', - adequate: 'Adequate' + delivered: "Delivered", + shipped: "Shipped", + processing: "Processing", + backordered: "Backordered", + inStock: "In Stock", + lowStock: "Low Stock", + adequate: "Adequate", }, // Trends trends: { - increasing: 'increasing', - stable: 'stable', - decreasing: 'decreasing' + increasing: "increasing", + stable: "stable", + decreasing: "decreasing", }, // Priority priority: { - high: 'High', - medium: 'Medium', - low: 'Low' + high: "High", + medium: "Medium", + low: "Low", }, // Categories categories: { - circuitBoards: 'Circuit Boards', - sensors: 'Sensors', - actuators: 'Actuators', - controllers: 'Controllers', - powerSupplies: 'Power Supplies' + circuitBoards: "Circuit Boards", + sensors: "Sensors", + actuators: "Actuators", + controllers: "Controllers", + powerSupplies: "Power Supplies", }, // Spending Categories spendingCategories: { - rawMaterials: 'Raw Materials', - components: 'Components', - equipment: 'Equipment', - consumables: 'Consumables' + rawMaterials: "Raw Materials", + components: "Components", + equipment: "Equipment", + consumables: "Consumables", }, // Warehouses warehouses: { - sanFrancisco: 'San Francisco', - london: 'London', - tokyo: 'Tokyo' + sanFrancisco: "San Francisco", + london: "London", + tokyo: "Tokyo", }, // Months months: { - jan: 'Jan', - feb: 'Feb', - mar: 'Mar', - apr: 'Apr', - may: 'May', - jun: 'Jun', - jul: 'Jul', - aug: 'Aug', - sep: 'Sep', - oct: 'Oct', - nov: 'Nov', - dec: 'Dec', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December' + jan: "Jan", + feb: "Feb", + mar: "Mar", + apr: "Apr", + may: "May", + jun: "Jun", + jul: "Jul", + aug: "Aug", + sep: "Sep", + oct: "Oct", + nov: "Nov", + dec: "Dec", + january: "January", + february: "February", + march: "March", + april: "April", + june: "June", + july: "July", + august: "August", + september: "September", + october: "October", + november: "November", + december: "December", }, // Profile Menu profile: { - profileDetails: 'Profile Details', - myTasks: 'My Tasks', - logout: 'Logout' + profileDetails: "Profile Details", + myTasks: "My Tasks", + logout: "Logout", }, // Profile Details Modal profileDetails: { - title: 'Profile Details', - email: 'Email', - department: 'Department', - location: 'Location', - phone: 'Phone', - joinDate: 'Join Date', - employeeId: 'Employee ID', - close: 'Close' + title: "Profile Details", + email: "Email", + department: "Department", + location: "Location", + phone: "Phone", + joinDate: "Join Date", + employeeId: "Employee ID", + close: "Close", }, // Tasks Modal tasks: { - title: 'My Tasks', - taskTitle: 'Task Title', - taskTitlePlaceholder: 'Enter task title...', - priority: 'Priority', - dueDate: 'Due Date', - addTask: 'Add Task', - noTasks: 'No tasks yet. Add your first task above!' + title: "My Tasks", + taskTitle: "Task Title", + taskTitlePlaceholder: "Enter task title...", + priority: "Priority", + dueDate: "Due Date", + addTask: "Add Task", + noTasks: "No tasks yet. Add your first task above!", }, // Language language: { - english: 'English', - japanese: 'Japanese', - selectLanguage: 'Select Language' + english: "English", + japanese: "Japanese", + selectLanguage: "Select Language", }, // Common common: { - loading: 'Loading...', - error: 'Error', - noData: 'No data available', - viewDetails: 'View Details', - close: 'Close', - save: 'Save', - cancel: 'Cancel', - search: 'Search', - filter: 'Filter', - export: 'Export', - items: 'items' - } -} + loading: "Loading...", + error: "Error", + noData: "No data available", + viewDetails: "View Details", + close: "Close", + save: "Save", + cancel: "Cancel", + search: "Search", + filter: "Filter", + export: "Export", + items: "items", + }, +}; diff --git a/client/src/locales/ja.js b/client/src/locales/ja.js index db33223a..060af317 100644 --- a/client/src/locales/ja.js +++ b/client/src/locales/ja.js @@ -1,382 +1,413 @@ export default { // Navigation nav: { - overview: '概要', - inventory: '在庫', - orders: '注文', - finance: '財務', - demandForecast: '需要予測', - companyName: '触媒コンポーネンツ', - subtitle: '在庫管理システム' + overview: "概要", + inventory: "在庫", + orders: "注文", + finance: "財務", + demandForecast: "需要予測", + companyName: "触媒コンポーネンツ", + subtitle: "在庫管理システム", }, // Dashboard dashboard: { - title: '概要', + title: "概要", kpi: { - title: '主要業績評価指標', - inventoryTurnover: '在庫回転率', - ordersFulfilled: '注文履行数', - orderFillRate: '注文充足率', - revenue: '収益(注文)', - revenueYTD: '収益(注文)年初来', - revenueMTD: '収益(注文)月初来', - avgProcessingTime: '平均処理時間(日)', - goal: '目標' + title: "主要業績評価指標", + inventoryTurnover: "在庫回転率", + ordersFulfilled: "注文履行数", + orderFillRate: "注文充足率", + revenue: "収益(注文)", + revenueYTD: "収益(注文)年初来", + revenueMTD: "収益(注文)月初来", + avgProcessingTime: "平均処理時間(日)", + goal: "目標", }, summary: { - title: '概要' + title: "概要", }, orderHealth: { - title: '注文状況', - totalOrders: '総注文数', - revenue: '収益', - avgOrderValue: '平均注文額', - onTimeRate: '定時配達率', - avgFulfillmentDays: '平均履行日数', - total: '合計' + title: "注文状況", + totalOrders: "総注文数", + revenue: "収益", + avgOrderValue: "平均注文額", + onTimeRate: "定時配達率", + avgFulfillmentDays: "平均履行日数", + total: "合計", }, ordersByMonth: { - title: '月別注文数' + title: "月別注文数", }, inventoryValue: { - title: 'カテゴリ別在庫価値' + title: "カテゴリ別在庫価値", }, inventoryShortages: { - title: '在庫不足', - noShortages: '在庫不足なし - すべての注文を履行できます!', - noData: '選択したフィルターのデータがありません', - orderId: '注文ID', - sku: 'SKU', - itemName: '品目名', - quantityNeeded: '必要数量', - quantityAvailable: '在庫数量', - shortage: '不足', - daysDelayed: '遅延日数', - priority: '優先度', - unitsShort: '単位不足', - days: '日' + title: "在庫不足", + noShortages: "在庫不足なし - すべての注文を履行できます!", + noData: "選択したフィルターのデータがありません", + orderId: "注文ID", + sku: "SKU", + itemName: "品目名", + quantityNeeded: "必要数量", + quantityAvailable: "在庫数量", + shortage: "不足", + daysDelayed: "遅延日数", + priority: "優先度", + unitsShort: "単位不足", + days: "日", }, topProducts: { - title: '収益別トップ製品', - sku: 'SKU', - product: '製品', - category: 'カテゴリ', - warehouse: '倉庫', - stockStatus: '在庫状況', - revenue: '収益', - unitsOrdered: '注文数量', - firstOrder: '初回注文', - inStock: '在庫あり', - lowStock: '在庫僅少' - } + title: "収益別トップ製品", + sku: "SKU", + product: "製品", + category: "カテゴリ", + warehouse: "倉庫", + stockStatus: "在庫状況", + revenue: "収益", + unitsOrdered: "注文数量", + firstOrder: "初回注文", + inStock: "在庫あり", + lowStock: "在庫僅少", + }, }, // Inventory inventory: { - title: '在庫', - description: 'すべての在庫品目の追跡と管理', - stockLevels: '在庫レベル', - skus: 'SKU', - searchPlaceholder: '品目名で検索...', - clearSearch: '検索をクリア', - totalItems: '総品目数', - totalValue: '総価値', - lowStockItems: '在庫僅少品目', - warehouses: '倉庫', + title: "在庫", + description: "すべての在庫品目の追跡と管理", + stockLevels: "在庫レベル", + skus: "SKU", + searchPlaceholder: "品目名で検索...", + clearSearch: "検索をクリア", + totalItems: "総品目数", + totalValue: "総価値", + lowStockItems: "在庫僅少品目", + warehouses: "倉庫", table: { - sku: 'SKU', - itemName: '品目名', - name: '名前', - category: 'カテゴリ', - warehouse: '倉庫', - quantity: '数量', - quantityOnHand: '手持在庫数', - reorderPoint: '再注文点', - unitCost: '単価', - unitPrice: '単価', - totalValue: '総価値', - location: '場所', - status: 'ステータス' - } + sku: "SKU", + itemName: "品目名", + name: "名前", + category: "カテゴリ", + warehouse: "倉庫", + quantity: "数量", + quantityOnHand: "手持在庫数", + reorderPoint: "再注文点", + unitCost: "単価", + unitPrice: "単価", + totalValue: "総価値", + location: "場所", + status: "ステータス", + }, }, // Orders orders: { - title: '注文', - description: '顧客注文の表示と管理', - allOrders: 'すべての注文', - totalOrders: '総注文数', - totalRevenue: '総収益', - avgOrderValue: '平均注文額', - onTimeDelivery: '定時配達', - itemsCount: '{count}件', - quantity: '数量', + title: "注文", + description: "顧客注文の表示と管理", + allOrders: "すべての注文", + totalOrders: "総注文数", + totalRevenue: "総収益", + avgOrderValue: "平均注文額", + onTimeDelivery: "定時配達", + itemsCount: "{count}件", + quantity: "数量", table: { - orderNumber: '注文番号', - orderId: '注文ID', - orderDate: '注文日', - date: '日付', - customer: '顧客', - category: 'カテゴリ', - warehouse: '倉庫', - items: '品目', - value: '価格', - totalValue: '合計金額', - status: 'ステータス', - expectedDelivery: '予定配達日', - actualDelivery: '実際の配達日' - } + orderNumber: "注文番号", + orderId: "注文ID", + orderDate: "注文日", + date: "日付", + customer: "顧客", + category: "カテゴリ", + warehouse: "倉庫", + items: "品目", + value: "価格", + totalValue: "合計金額", + status: "ステータス", + expectedDelivery: "予定配達日", + actualDelivery: "実際の配達日", + }, }, // Finance/Spending finance: { - title: '財務ダッシュボード', - description: '収益、コスト、財務パフォーマンスの追跡', - totalRevenue: '総収益', - totalCosts: '総コスト', - netProfit: '純利益', - avgOrderValue: '平均注文額', - fromOrders: '{count}件の注文から', - costBreakdown: '調達 + 運営 + 人件費 + 間接費', - margin: 'マージン', - perOrderRevenue: '注文あたりの収益', + title: "財務ダッシュボード", + description: "収益、コスト、財務パフォーマンスの追跡", + totalRevenue: "総収益", + totalCosts: "総コスト", + netProfit: "純利益", + avgOrderValue: "平均注文額", + fromOrders: "{count}件の注文から", + costBreakdown: "調達 + 運営 + 人件費 + 間接費", + margin: "マージン", + perOrderRevenue: "注文あたりの収益", revenueVsCosts: { - title: '月別収益対コスト', - revenue: '収益', - costs: '総コスト' + title: "月別収益対コスト", + revenue: "収益", + costs: "総コスト", }, monthlyCostFlow: { - title: '月別コストフロー', - procurement: '調達', - operational: '運営', - labor: '人件費', - overhead: '間接費' + title: "月別コストフロー", + procurement: "調達", + operational: "運営", + labor: "人件費", + overhead: "間接費", }, categorySpending: { - title: 'カテゴリ別支出', - ofTotal: '全体の' + title: "カテゴリ別支出", + ofTotal: "全体の", }, transactions: { - title: '最近の取引', - id: 'ID', - description: '説明', - vendor: 'ベンダー', - date: '日付', - amount: '金額' - } + title: "最近の取引", + id: "ID", + description: "説明", + vendor: "ベンダー", + date: "日付", + amount: "金額", + }, + }, + + // Reports + reports: { + title: "パフォーマンスレポート", + description: "四半期パフォーマンス指標と月次トレンドを表示", + quarterly: { + title: "四半期パフォーマンス", + quarter: "四半期", + totalOrders: "総注文数", + totalRevenue: "総収益", + avgOrderValue: "平均注文額", + fulfillmentRate: "履行率", + }, + monthlyTrend: { + title: "月次収益トレンド", + }, + momAnalysis: { + title: "前月比分析", + month: "月", + orders: "注文数", + revenue: "収益", + change: "変化", + growthRate: "成長率", + }, + summary: { + totalRevenueYTD: "総収益(年初来)", + avgMonthlyRevenue: "平均月次収益", + totalOrdersYTD: "総注文数(年初来)", + bestPerformingQuarter: "最高パフォーマンス四半期", + }, }, // Demand Forecast demand: { - title: '需要予測', - description: '需要動向の分析と将来のニーズの予測', - increasingDemand: '需要増加', - stableDemand: '需要安定', - decreasingDemand: '需要減少', - itemsCount: '{count}件', - more: 'さらに...', - demandForecasts: '需要予測', + title: "需要予測", + description: "需要動向の分析と将来のニーズの予測", + increasingDemand: "需要増加", + stableDemand: "需要安定", + decreasingDemand: "需要減少", + itemsCount: "{count}件", + more: "さらに...", + demandForecasts: "需要予測", table: { - sku: 'SKU', - itemName: '品目名', - currentDemand: '現在の需要', - forecastedDemand: '予測需要', - change: '変化', - trend: 'トレンド', - period: '期間' - } + sku: "SKU", + itemName: "品目名", + currentDemand: "現在の需要", + forecastedDemand: "予測需要", + change: "変化", + trend: "トレンド", + period: "期間", + }, }, // Filters filters: { - timePeriod: '期間', - location: '場所', - category: 'カテゴリ', - orderStatus: '注文ステータス', - all: 'すべて', - allMonths: 'すべての月' + timePeriod: "期間", + location: "場所", + category: "カテゴリ", + orderStatus: "注文ステータス", + all: "すべて", + allMonths: "すべての月", }, // Statuses status: { - delivered: '配達済み', - shipped: '出荷済み', - processing: '処理中', - backordered: 'バックオーダー', - inStock: '在庫あり', - lowStock: '在庫僅少', - adequate: '適量' + delivered: "配達済み", + shipped: "出荷済み", + processing: "処理中", + backordered: "バックオーダー", + inStock: "在庫あり", + lowStock: "在庫僅少", + adequate: "適量", }, // Trends trends: { - increasing: '増加', - stable: '安定', - decreasing: '減少' + increasing: "増加", + stable: "安定", + decreasing: "減少", }, // Priority priority: { - high: '高', - medium: '中', - low: '低' + high: "高", + medium: "中", + low: "低", }, // Categories categories: { - circuitBoards: '回路基板', - sensors: 'センサー', - actuators: 'アクチュエータ', - controllers: 'コントローラー', - powerSupplies: '電源' + circuitBoards: "回路基板", + sensors: "センサー", + actuators: "アクチュエータ", + controllers: "コントローラー", + powerSupplies: "電源", }, // Spending Categories spendingCategories: { - rawMaterials: '原材料', - components: '部品', - equipment: '設備', - consumables: '消耗品' + rawMaterials: "原材料", + components: "部品", + equipment: "設備", + consumables: "消耗品", }, // Warehouses warehouses: { - sanFrancisco: 'サンフランシスコ', - london: 'ロンドン', - tokyo: '東京' + sanFrancisco: "サンフランシスコ", + london: "ロンドン", + tokyo: "東京", }, // Months months: { - jan: '1月', - feb: '2月', - mar: '3月', - apr: '4月', - may: '5月', - jun: '6月', - jul: '7月', - aug: '8月', - sep: '9月', - oct: '10月', - nov: '11月', - dec: '12月', - january: '1月', - february: '2月', - march: '3月', - april: '4月', - june: '6月', - july: '7月', - august: '8月', - september: '9月', - october: '10月', - november: '11月', - december: '12月' + jan: "1月", + feb: "2月", + mar: "3月", + apr: "4月", + may: "5月", + jun: "6月", + jul: "7月", + aug: "8月", + sep: "9月", + oct: "10月", + nov: "11月", + dec: "12月", + january: "1月", + february: "2月", + march: "3月", + april: "4月", + june: "6月", + july: "7月", + august: "8月", + september: "9月", + october: "10月", + november: "11月", + december: "12月", }, // Profile Menu profile: { - profileDetails: 'プロフィール詳細', - myTasks: 'マイタスク', - logout: 'ログアウト' + profileDetails: "プロフィール詳細", + myTasks: "マイタスク", + logout: "ログアウト", }, // Profile Details Modal profileDetails: { - title: 'プロフィール詳細', - email: 'メールアドレス', - department: '部署', - location: '勤務地', - phone: '電話番号', - joinDate: '入社日', - employeeId: '社員ID', - close: '閉じる' + title: "プロフィール詳細", + email: "メールアドレス", + department: "部署", + location: "勤務地", + phone: "電話番号", + joinDate: "入社日", + employeeId: "社員ID", + close: "閉じる", }, // Tasks Modal tasks: { - title: 'マイタスク', - taskTitle: 'タスク名', - taskTitlePlaceholder: 'タスク名を入力...', - priority: '優先度', - dueDate: '期限', - addTask: 'タスクを追加', - noTasks: 'タスクがありません。上記からタスクを追加してください!' + title: "マイタスク", + taskTitle: "タスク名", + taskTitlePlaceholder: "タスク名を入力...", + priority: "優先度", + dueDate: "期限", + addTask: "タスクを追加", + noTasks: "タスクがありません。上記からタスクを追加してください!", }, // Language language: { - english: 'English', - japanese: '日本語', - selectLanguage: '言語を選択' + english: "English", + japanese: "日本語", + selectLanguage: "言語を選択", }, // Common common: { - loading: '読み込み中...', - error: 'エラー', - noData: 'データがありません', - viewDetails: '詳細を見る', - close: '閉じる', - save: '保存', - cancel: 'キャンセル', - search: '検索', - filter: 'フィルター', - export: 'エクスポート', - items: '件' + loading: "読み込み中...", + error: "エラー", + noData: "データがありません", + viewDetails: "詳細を見る", + close: "閉じる", + save: "保存", + cancel: "キャンセル", + search: "検索", + filter: "フィルター", + export: "エクスポート", + items: "件", }, // Product Names productNames: { - 'Single Layer PCB Assembly': '単層PCB組立', - 'Dual Layer PCB Assembly': '二層PCB組立', - 'Multi Layer PCB Assembly': '多層PCB組立', - 'Temperature Sensor Module': '温度センサーモジュール', - 'Humidity Sensor Module': '湿度センサーモジュール', - 'Pressure Sensor Module': '圧力センサーモジュール', - 'Proximity Sensor': '近接センサー', - 'Ultrasonic Distance Sensor': '超音波距離センサー', - 'Micro Servo Motor': 'マイクロサーボモータ', - 'Standard Servo Motor': '標準サーボモータ', - 'Stepper Motor NEMA 17': 'ステッピングモータNEMA 17', - '8-bit Microcontroller': '8ビットマイコン', - '32-bit ARM Microcontroller': '32ビットARMマイコン', - 'Digital Signal Processor': 'デジタル信号処理装置', - '3-Axis Accelerometer': '3軸加速度センサー', - 'Gyroscope Module': 'ジャイロスコープモジュール', - 'Light Dependent Resistor': '光依存抵抗器', - 'Coil Spring Heavy Duty': 'コイルばね(重量用)', - 'Compression Spring': '圧縮ばね', - 'PWM Motor Controller': 'PWMモータコントローラ', - 'H-Bridge Motor Driver': 'Hブリッジモータドライバ', - 'Stepper Motor NEMA 23': 'ステッピングモータNEMA 23', - 'Drive Pulley': 'ドライブプーリー', - 'LED Driver IC': 'LEDドライバIC', - '5V 10A Switching Power Supply': '5V 10Aスイッチング電源', - '12V 5A Power Supply Module': '12V 5A電源モジュール', - '24V 3A Industrial Power Supply': '24V 3A産業用電源', - 'Dual Output ±15V Power Supply': 'デュアル出力±15V電源', - '48V DC Power Supply Unit': '48V DC電源ユニット', - 'USB-C PD 100W Power Supply': 'USB-C PD 100W電源', - 'Battery Backup Power Supply': 'バッテリバックアップ電源', - 'Adjustable Bench Power Supply': '可変ベンチ電源' + "Single Layer PCB Assembly": "単層PCB組立", + "Dual Layer PCB Assembly": "二層PCB組立", + "Multi Layer PCB Assembly": "多層PCB組立", + "Temperature Sensor Module": "温度センサーモジュール", + "Humidity Sensor Module": "湿度センサーモジュール", + "Pressure Sensor Module": "圧力センサーモジュール", + "Proximity Sensor": "近接センサー", + "Ultrasonic Distance Sensor": "超音波距離センサー", + "Micro Servo Motor": "マイクロサーボモータ", + "Standard Servo Motor": "標準サーボモータ", + "Stepper Motor NEMA 17": "ステッピングモータNEMA 17", + "8-bit Microcontroller": "8ビットマイコン", + "32-bit ARM Microcontroller": "32ビットARMマイコン", + "Digital Signal Processor": "デジタル信号処理装置", + "3-Axis Accelerometer": "3軸加速度センサー", + "Gyroscope Module": "ジャイロスコープモジュール", + "Light Dependent Resistor": "光依存抵抗器", + "Coil Spring Heavy Duty": "コイルばね(重量用)", + "Compression Spring": "圧縮ばね", + "PWM Motor Controller": "PWMモータコントローラ", + "H-Bridge Motor Driver": "Hブリッジモータドライバ", + "Stepper Motor NEMA 23": "ステッピングモータNEMA 23", + "Drive Pulley": "ドライブプーリー", + "LED Driver IC": "LEDドライバIC", + "5V 10A Switching Power Supply": "5V 10Aスイッチング電源", + "12V 5A Power Supply Module": "12V 5A電源モジュール", + "24V 3A Industrial Power Supply": "24V 3A産業用電源", + "Dual Output ±15V Power Supply": "デュアル出力±15V電源", + "48V DC Power Supply Unit": "48V DC電源ユニット", + "USB-C PD 100W Power Supply": "USB-C PD 100W電源", + "Battery Backup Power Supply": "バッテリバックアップ電源", + "Adjustable Bench Power Supply": "可変ベンチ電源", }, // Customer Names customerNames: { - 'MegaCorp Industries': 'メガコープ工業', - 'Elite Systems Corp': 'エリートシステムズ', - 'Horizon Technologies': 'ホライズン技術', - 'FastAssembly Ltd': 'ファストアセンブリー', - 'TechSolutions Group': 'テックソリューションズグループ', - 'Apex Engineering': 'アペックスエンジニアリング', - 'Superior Manufacturing': 'スーペリアマニュファクチャリング', - 'Cascade Manufacturing': 'カスケードマニュファクチャリング', - 'Acme Manufacturing Corp': 'アクメ製造', - 'TechBuild Industries': 'テックビルド工業', - 'Advanced Components Inc': 'アドバンストコンポーネンツ', - 'Premier Industries': 'プレミア工業', - 'Stellar Components Ltd': 'ステラコンポーネンツ', - 'Dynamic Systems Ltd': 'ダイナミックシステムズ' - } -} + "MegaCorp Industries": "メガコープ工業", + "Elite Systems Corp": "エリートシステムズ", + "Horizon Technologies": "ホライズン技術", + "FastAssembly Ltd": "ファストアセンブリー", + "TechSolutions Group": "テックソリューションズグループ", + "Apex Engineering": "アペックスエンジニアリング", + "Superior Manufacturing": "スーペリアマニュファクチャリング", + "Cascade Manufacturing": "カスケードマニュファクチャリング", + "Acme Manufacturing Corp": "アクメ製造", + "TechBuild Industries": "テックビルド工業", + "Advanced Components Inc": "アドバンストコンポーネンツ", + "Premier Industries": "プレミア工業", + "Stellar Components Ltd": "ステラコンポーネンツ", + "Dynamic Systems Ltd": "ダイナミックシステムズ", + }, +}; diff --git a/client/src/views/Reports.vue b/client/src/views/Reports.vue index 35187eaf..aea3d79a 100644 --- a/client/src/views/Reports.vue +++ b/client/src/views/Reports.vue @@ -1,32 +1,35 @@