liuxf 2 months ago
parent
commit
583567b922

File diff suppressed because it is too large
+ 6154 - 0
new-react-admin-ui/package-lock.json


+ 7 - 3
new-react-admin-ui/src/App.tsx

@@ -20,7 +20,7 @@ import DashboardList from '@/pages/dashboard/DashboardList';
 import OrderEdit from '@/pages/dashboard/OrderEdit';
 import DateBased from '@/pages/pastlogs/DateBased';
 import EstateExport from '@/pages/estate/export/index';
-
+import EstateExportHistory from '@/pages/estate/estateList/index';
 import { Layout } from '@/components/Layout';
 import ErrorPage from '@/pages/ErrorPage';
 
@@ -94,9 +94,13 @@ export const App = () => {
           name="label/usermanagements"
           list={usermanagementsList}
         />
+         <Resource
+          name="estate/exports"
+          list={EstateExport}
+         />
           <Resource
-              name="estate/exports"
-              list={EstateExport}
+              name="estate/estateLists"
+              list={EstateExportHistory}
           />
         <CustomRoutes noLayout>
           <Route path="/error" element={<ErrorPage />} />

+ 167 - 0
new-react-admin-ui/src/pages/estate/estateList/EstateExport.module.css

@@ -0,0 +1,167 @@
+.container {
+  width: 100%;
+  padding: 20px;
+  box-sizing: border-box;
+  font-family: 'Noto Sans JP', sans-serif;
+}
+
+.title {
+  font-size: 20px;
+  font-weight: 600;
+  color: #333;
+  margin-bottom: 24px;
+  border-bottom: 1px solid #eee;
+  padding-bottom: 8px;
+}
+
+.subtitle {
+  font-size: 16px;
+  font-weight: 500;
+  color: #444;
+  margin-bottom: 16px;
+}
+
+.underline {
+  height: 1px;
+  background-color: #eee;
+  margin-bottom: 16px;
+}
+
+/* 导出操作区 */
+.exportSection {
+  margin-bottom: 32px;
+  padding: 16px;
+  background-color: #f9f9f9;
+  border-radius: 8px;
+}
+
+.formGroup {
+  display: flex;
+  align-items: center;
+  gap: 24px;
+  flex-wrap: wrap;
+}
+
+.formItem {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.label {
+  font-size: 14px;
+  color: #555;
+  font-weight: 500;
+}
+
+.input {
+  padding: 8px 12px;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  font-size: 14px;
+  width: 160px;
+}
+
+.input:focus {
+  outline: none;
+  border-color: #4299e1;
+  box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.2);
+}
+
+.radioGroup {
+  display: flex;
+  gap: 16px;
+}
+
+.radioItem {
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  font-size: 14px;
+  color: #555;
+  cursor: pointer;
+}
+
+.radioLabel {
+  cursor: pointer;
+}
+
+.exportBtn {
+  padding: 8px 24px;
+  background-color: #4299e1;
+  color: white;
+  border: none;
+  border-radius: 4px;
+  font-size: 14px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: background-color 0.2s;
+}
+
+.exportBtn:hover {
+  background-color: #3182ce;
+}
+
+.disabledBtn {
+  background-color: #ccc;
+  cursor: not-allowed;
+}
+
+/* 历史列表区 */
+.historySection {
+  padding: 16px;
+  border: 1px solid #eee;
+  border-radius: 8px;
+}
+
+.gridContainer {
+  --ag-grid-size: 1px;
+  --ag-border-color: #eee;
+  --ag-header-background-color: #f5f5f5;
+  --ag-header-text-color: #444;
+  --ag-header-font-size: 14px;
+  --ag-row-height: 40px;
+  --ag-cell-font-size: 14px;
+  --ag-cell-padding: 0 12px;
+  --ag-header-height: 48px; /* 增加表头行高(默认可能偏小) */
+  --ag-header-cell-padding: 0 12px; /* 调整表头内边距(上下设为0避免挤压) */
+  --ag-header-line-height: 1.5; /* 文字行高,避免文字本身被截断  */
+}
+
+/* 加载状态 */
+.loading {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 300px;
+  font-size: 14px;
+  color: #666;
+}
+
+/* 空状态 */
+.emptyState {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 300px;
+  font-size: 14px;
+  color: #666;
+  background-color: #fafafa;
+  border-radius: 4px;
+}
+
+/* 响应式调整 */
+@media (max-width: 768px) {
+  .formGroup {
+    gap: 16px;
+  }
+
+  .input {
+    width: 140px;
+  }
+
+  .exportBtn {
+    width: 100%;
+    margin-top: 8px;
+  }
+}

+ 322 - 0
new-react-admin-ui/src/pages/estate/estateList/index.tsx

@@ -0,0 +1,322 @@
+import React, { useMemo, useState, useEffect, useCallback } from 'react';
+import { AgGridReact } from 'ag-grid-react';
+import {
+  ClientSideRowModelModule,
+  ColDef,
+  ModuleRegistry,
+  PaginationModule,
+  ValueFormatterParams,
+  GridReadyEvent,
+} from 'ag-grid-community';
+import styles from './EstateExport.module.css'; // 改为 CSS Modules
+
+// 1. 类型定义(补全接口,确保类型安全)
+export interface IEstateExportHistory {
+  id: string;
+  exportDate: string; // yyyymmdd 格式
+  exporter: string;   // 担当者名
+  exportContent: string; // 1:物件マスタCSV, 2:分析用CSV
+}
+
+// 2. AG Grid 模块注册(保持原有逻辑,补充注释)
+ModuleRegistry.registerModules([
+  PaginationModule,       // 分页模块
+  ClientSideRowModelModule // 客户端行模型(本地数据分页)
+]);
+
+// 3. 枚举与映射配置(保持原有,补充类型约束)
+export enum ExportContentType {
+  PROPERTY_MASTER = '1',
+  ANALYSIS = '2'
+}
+
+const EXPORT_CONTENT_MAP: Record<ExportContentType, string> = {
+  [ExportContentType.PROPERTY_MASTER]: '物件マスタCSV',
+  [ExportContentType.ANALYSIS]: '分析用CSV'
+};
+
+// 4. 工具函数(抽离通用逻辑,提高复用性)
+/**
+ * 日期格式验证(yyyymmdd)
+ * @param date - 待验证日期字符串
+ * @returns 验证结果
+ */
+const validateDate = (date: string): boolean => {
+  const regex = /^\d{8}$/;
+  if (!regex.test(date)) return false;
+
+  const year = parseInt(date.substring(0, 4), 10);
+  const month = parseInt(date.substring(4, 6), 10) - 1; // 月份从 0 开始
+  const day = parseInt(date.substring(6, 8), 10);
+
+  const validDate = new Date(year, month, day);
+  return (
+    validDate.getFullYear() === year &&
+    validDate.getMonth() === month &&
+    validDate.getDate() === day
+  );
+};
+
+/**
+ * 格式化日期显示(yyyymmdd → yyyy/mm/dd)
+ * @param date - 原始日期字符串
+ * @returns 格式化后的日期
+ */
+const formatDisplayDate = (date: string): string => {
+  if (!date || date.length !== 8) return '';
+  return `${date.slice(0, 4)}/${date.slice(4, 6)}/${date.slice(6, 8)}`;
+};
+
+const EstateExportHistory: React.FC = () => {
+  // 5. 状态管理(补充类型约束,初始化更合理)
+  const [baseDate, setBaseDate] = useState<string>('');
+  const [selectedContent, setSelectedContent] = useState<ExportContentType>(
+    ExportContentType.ANALYSIS
+  );
+  const [historyList, setHistoryList] = useState<IEstateExportHistory[]>([]);
+  const [isExporting, setIsExporting] = useState<boolean>(false);
+  const [gridApi, setGridApi] = useState<any>(null); // AG Grid API 实例
+  const [isLoading, setIsLoading] = useState<boolean>(true); // 列表加载状态
+
+  // 6. 样式配置(使用 CSS Modules,避免全局污染)
+  const containerStyle = useMemo(() => ({
+    width: '100%',
+    height: '300px',
+    borderRadius: '4px',
+    overflow: 'hidden'
+  }), []);
+
+  // 7. AG Grid 配置(优化默认列配置,补充缺失功能)
+  const defaultColDef = useMemo<ColDef>(() => ({
+    flex: 1,
+    minWidth: 120,
+    sortable: true, // 开启排序(提升体验)
+    filter: true,   // 开启筛选(提升体验)
+    resizable: true,
+    menuTabs: ['filterMenuTab'], // 只显示筛选菜单(简化操作)
+    cellStyle: { display: 'flex', alignItems: 'center' } // 单元格垂直居中
+  }), []);
+
+  const paginationPageSize = useMemo(() => 5, []); // 调整为每页 5 条(更合理)
+
+  // 8. 列定义(优化格式化逻辑,抽离为独立函数)
+  const columnDefs = useMemo<ColDef<IEstateExportHistory>[]>(() => [
+    {
+      headerName: '出力日付',
+      field: 'exportDate',
+      flex: 1.2,
+      valueFormatter: (params: ValueFormatterParams<IEstateExportHistory>) =>
+        formatDisplayDate(params.value),
+      sort: 'desc' // 默认按日期降序排序
+    },
+    {
+      headerName: '担当者',
+      field: 'exporter',
+      flex: 1,
+      filter: 'agTextColumnFilter',
+      filterParams: { matchContains: true } // 包含匹配(更灵活)
+    },
+    {
+      headerName: '出力内容',
+      field: 'exportContent',
+      flex: 1.5,
+      valueFormatter: (params: ValueFormatterParams<IEstateExportHistory>) =>
+        EXPORT_CONTENT_MAP[params.value as ExportContentType] || '不明',
+      filter: 'agSetColumnFilter', // 下拉筛选(更直观)
+      filterParams: {
+        values: Object.values(ExportContentType).map(key =>
+          EXPORT_CONTENT_MAP[key as ExportContentType]
+        ),
+        cellRenderer: (params: any) =>
+          EXPORT_CONTENT_MAP[params.value as ExportContentType] || '不明'
+      }
+    }
+  ], []);
+
+  // 9. 初始化数据(优化加载状态,模拟真实接口延迟)
+  useEffect(() => {
+    const fetchHistory = async () => {
+      try {
+        // 模拟接口请求延迟
+        await new Promise(resolve => setTimeout(resolve, 600));
+
+        const mockBackendData: IEstateExportHistory[] = [
+          { id: '1', exportDate: '20270812', exporter: 'BBBB', exportContent: ExportContentType.ANALYSIS },
+          { id: '2', exportDate: '20250814', exporter: 'AAAA', exportContent: ExportContentType.ANALYSIS },
+          { id: '3', exportDate: '20250813', exporter: 'AAAA', exportContent: ExportContentType.PROPERTY_MASTER },
+          { id: '4', exportDate: '20250812', exporter: 'CCCC', exportContent: ExportContentType.ANALYSIS },
+          { id: '5', exportDate: '20250811', exporter: 'DDDD', exportContent: ExportContentType.PROPERTY_MASTER },
+          { id: '6', exportDate: '20250810', exporter: 'AAAA', exportContent: ExportContentType.ANALYSIS },
+          { id: '7', exportDate: '20250809', exporter: 'BBBB', exportContent: ExportContentType.PROPERTY_MASTER },
+          { id: '8', exportDate: '20250808', exporter: 'CCCC', exportContent: ExportContentType.ANALYSIS },
+          { id: '9', exportDate: '20250807', exporter: 'DDDD', exportContent: ExportContentType.PROPERTY_MASTER },
+          { id: '10', exportDate: '20250806', exporter: 'AAAA', exportContent: ExportContentType.ANALYSIS },
+        ];
+
+        setHistoryList(mockBackendData);
+      } catch (error) {
+        console.error('履歴データの取得に失敗しました', error);
+        alert('履歴データの取得に失敗しました。再試行してください。');
+      } finally {
+        setIsLoading(false);
+      }
+    };
+
+    fetchHistory();
+  }, []);
+
+  // 10. Grid 初始化回调(保存 API 实例,用于后续操作)
+  const onGridReady = useCallback((params: GridReadyEvent<IEstateExportHistory>) => {
+    setGridApi(params.api);
+  }, []);
+
+  // 11. 导出处理逻辑(优化异步流程,增强用户反馈)
+  const handleExport = useCallback(async () => {
+    if (isExporting) return;
+
+    // 验证基準日
+    if (!baseDate) {
+      alert('基準日を入力してください');
+      return;
+    }
+
+    if (!validateDate(baseDate)) {
+      alert('基準日はyyyymmddの形式で正しい日付を入力してください');
+      return;
+    }
+
+    setIsExporting(true);
+
+    try {
+      // 模拟接口请求(实际项目中替换为 axios/fetch)
+      await new Promise(resolve => setTimeout(resolve, 800));
+
+      const newHistory: IEstateExportHistory = {
+        id: Date.now().toString(),
+        exportDate: baseDate,
+        exporter: '現在ユーザー',
+        exportContent: selectedContent
+      };
+
+      // 新增数据添加到列表顶部,并保持排序
+      setHistoryList(prev => [newHistory, ...prev].sort((a, b) =>
+        b.exportDate.localeCompare(a.exportDate)
+      ));
+
+      // 刷新 Grid 视图
+      gridApi?.refreshCells();
+      alert('エクスポートが完了しました');
+    } catch (error) {
+      console.error('エクスポートに失敗しました', error);
+      alert('エクスポートに失敗しました。再試行してください。');
+    } finally {
+      setBaseDate('');
+      setIsExporting(false);
+    }
+  }, [baseDate, selectedContent, isExporting, gridApi]);
+
+  // 12. 日期输入处理(限制输入格式,增强用户体验)
+  const handleDateChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
+    // 只允许输入数字,且长度不超过 8
+    const value = e.target.value.replace(/\D/g, '').slice(0, 8);
+    setBaseDate(value);
+  }, []);
+
+  return (
+    <div className={styles.container}>
+      <h2 className={styles.title}>エクスポート</h2>
+
+      {/* 导出操作区 */}
+      <div className={styles.exportSection}>
+        <h3 className={styles.subtitle}>エクスポート操作</h3>
+        <div className={styles.formGroup}>
+          <div className={styles.formItem}>
+            <label className={styles.label}>基準日</label>
+            <input
+              type="text"
+              className={styles.input}
+              placeholder="yyyymmdd"
+              value={baseDate}
+              onChange={handleDateChange}
+              maxLength={8}
+              disabled={isExporting}
+              aria-label="基準日入力"
+            />
+          </div>
+
+          <div className={styles.formItem}>
+            <label className={styles.label}>出力内容</label>
+            <div className={styles.radioGroup}>
+              <label className={styles.radioItem}>
+                <input
+                  type="radio"
+                  name="exportContent"
+                  value={ExportContentType.PROPERTY_MASTER}
+                  checked={selectedContent === ExportContentType.PROPERTY_MASTER}
+                  onChange={() => setSelectedContent(ExportContentType.PROPERTY_MASTER)}
+                  disabled={isExporting}
+                />
+                <span className={styles.radioLabel}>物件マスタCSV</span>
+              </label>
+              <label className={styles.radioItem}>
+                <input
+                  type="radio"
+                  name="exportContent"
+                  value={ExportContentType.ANALYSIS}
+                  checked={selectedContent === ExportContentType.ANALYSIS}
+                  onChange={() => setSelectedContent(ExportContentType.ANALYSIS)}
+                  disabled={isExporting}
+                />
+                <span className={styles.radioLabel}>分析用CSV</span>
+              </label>
+            </div>
+          </div>
+
+          <button
+            className={`${styles.exportBtn} ${isExporting ? styles.disabledBtn : ''}`}
+            onClick={handleExport}
+            disabled={isExporting}
+          >
+            {isExporting ? '処理中...' : '出力'}
+          </button>
+        </div>
+      </div>
+
+      {/* 导出历史区 */}
+      <div className={styles.historySection}>
+        <h3 className={styles.subtitle}>出力履歴</h3>
+        <div className={styles.underline}></div>
+
+        {isLoading ? (
+          // 加载状态
+          <div className={styles.loading}>
+            <span>履歴データを読み込んでいます...</span>
+          </div>
+        ) : historyList.length === 0 ? (
+          // 空状态
+          <div className={styles.emptyState}>
+            <span>出力履歴がありません</span>
+          </div>
+        ) : (
+          // AG Grid 表格
+          <div className={`ag-theme-alpine ${styles.gridContainer}`} style={containerStyle}>
+            <AgGridReact<IEstateExportHistory>
+              rowData={historyList}
+              columnDefs={columnDefs}
+              defaultColDef={defaultColDef}
+              pagination={true}
+              paginationPageSize={paginationPageSize}
+              paginationPageSizeSelector={[5, 10, 20]}
+              onGridReady={onGridReady}
+              animateRows={true}
+              suppressDragLeaveHidesColumns={true}
+              enableCellTextSelection={true}
+            />
+          </div>
+        )}
+      </div>
+    </div>
+  );
+};
+
+export default EstateExportHistory;

+ 0 - 19
new-react-admin-ui/src/pages/estate/export/index.tsx

@@ -10,7 +10,6 @@ import {
 
 import './EstateExport.css';
 import { IEstateExportHistory} from '@/types/estateExport';
-import { useFetchJson } from "./useFetchJson";
 
 // 1. 注册AG Grid模块(确保分页功能生效)
 ModuleRegistry.registerModules([
@@ -30,13 +29,6 @@ const EXPORT_CONTENT_MAP = {
   [ExportContentType.ANALYSIS]: '分析用CSV'
 };
 
-// // 3. 类型定义(适配后台返回格式:exportContent为1/2)
-// interface ExportHistory {
-//   id: string;
-//   exportDate: string;
-//   exporter: string;
-//   exportContent: string; // 后台返回值:'1' 或 '2'
-// }
 
 const EstateExport: React.FC = () => {
   // 4. 样式缓存(性能优化)
@@ -57,17 +49,6 @@ const EstateExport: React.FC = () => {
   const [selectedContent, setSelectedContent] = useState<string>(ExportContentType.ANALYSIS); // 默认选中分析用
   const [historyList, setHistoryList] = useState<IEstateExportHistory[]>([]);
   const [isExporting, setIsExporting] = useState(false); // 防止重复提交
-  // const {  data: fetchedHistory = [], loading  } = useFetchJson<IEstateExportHistory[]>(
-  //     '/estate-export-history.json' // 本地JSON文件路径(与index.tsx同级)
-  // );
-
-  // // 3. 初始化数据:当接口返回数据后,同步到状态中
-  // useEffect(() => {
-  //   // 仅在接口返回数据时更新状态(避免初始空数组覆盖)
-  //   if (fetchedHistory.length > 0) {
-  //     setHistoryList(fetchedHistory);
-  //   }
-  // }, [fetchedHistory]); // 依赖接口返回的 data 变化
 
   // 7. 初始化数据(模拟后台返回:exportContent为1/2)
   useEffect(() => {

+ 11 - 119
new-react-admin-ui/yarn.lock

@@ -495,26 +495,14 @@
   resolved "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.5.0.tgz"
   integrity sha512-LGb8t8i6M2ZtS3Drn3GbTI1DVhDY6FJ9crEey2lZ0aN2EMZo8IZBZj9wRf4vqbZHaWjsYgtbOnJw5V8UWbmK2Q==
 
-"@mui/core-downloads-tracker@^7.3.4":
-  version "7.3.4"
-  resolved "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.4.tgz"
-  integrity sha512-BIktMapG3r4iXwIhYNpvk97ZfYWTreBBQTWjQKbNbzI64+ULHfYavQEX2w99aSWHS58DvXESWIgbD9adKcUOBw==
-
-"@mui/icons-material@^5.16.12 || ^6.0.0 || ^7.0.0":
-  version "7.3.4"
-  resolved "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.4.tgz"
-  integrity sha512-9n6Xcq7molXWYb680N2Qx+FRW8oT6j/LXF5PZFH3ph9X/Rct0B/BlLAsFI7iL9ySI6LVLuQIVtrLiPT82R7OZw==
-  dependencies:
-    "@babel/runtime" "^7.28.4"
-
-"@mui/icons-material@^6.1.9":
+"@mui/icons-material@^5.16.12 || ^6.0.0 || ^7.0.0", "@mui/icons-material@^6.1.9":
   version "6.5.0"
   resolved "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.5.0.tgz"
   integrity sha512-VPuPqXqbBPlcVSA0BmnoE4knW4/xG6Thazo8vCLWkOKusko6DtwFV6B665MMWJ9j0KFohTIf3yx2zYtYacvG1g==
   dependencies:
     "@babel/runtime" "^7.26.0"
 
-"@mui/material@^5.15.14 || ^6.0.0 || ^7.0.0", "@mui/material@^6.1.9", "@mui/material@^6.5.0":
+"@mui/material@^5.15.14 || ^6.0.0 || ^7.0.0", "@mui/material@^5.16.12 || ^6.0.0 || ^7.0.0", "@mui/material@^6.1.9", "@mui/material@^6.5.0":
   version "6.5.0"
   resolved "https://registry.npmjs.org/@mui/material/-/material-6.5.0.tgz"
   integrity sha512-yjvtXoFcrPLGtgKRxFaH6OQPtcLPhkloC0BML6rBG5UeldR0nPULR/2E2BfXdo5JNV7j7lOzrrLX2Qf/iSidow==
@@ -532,24 +520,6 @@
     react-is "^19.0.0"
     react-transition-group "^4.4.5"
 
-"@mui/material@^5.16.12 || ^6.0.0 || ^7.0.0", "@mui/material@^7.3.4":
-  version "7.3.4"
-  resolved "https://registry.npmjs.org/@mui/material/-/material-7.3.4.tgz"
-  integrity sha512-gEQL9pbJZZHT7lYJBKQCS723v1MGys2IFc94COXbUIyCTWa+qC77a7hUax4Yjd5ggEm35dk4AyYABpKKWC4MLw==
-  dependencies:
-    "@babel/runtime" "^7.28.4"
-    "@mui/core-downloads-tracker" "^7.3.4"
-    "@mui/system" "^7.3.3"
-    "@mui/types" "^7.4.7"
-    "@mui/utils" "^7.3.3"
-    "@popperjs/core" "^2.11.8"
-    "@types/react-transition-group" "^4.4.12"
-    clsx "^2.1.1"
-    csstype "^3.1.3"
-    prop-types "^15.8.1"
-    react-is "^19.1.1"
-    react-transition-group "^4.4.5"
-
 "@mui/private-theming@^6.4.9":
   version "6.4.9"
   resolved "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.9.tgz"
@@ -559,15 +529,6 @@
     "@mui/utils" "^6.4.9"
     prop-types "^15.8.1"
 
-"@mui/private-theming@^7.3.3":
-  version "7.3.3"
-  resolved "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.3.tgz"
-  integrity sha512-OJM+9nj5JIyPUvsZ5ZjaeC9PfktmK+W5YaVLToLR8L0lB/DGmv1gcKE43ssNLSvpoW71Hct0necfade6+kW3zQ==
-  dependencies:
-    "@babel/runtime" "^7.28.4"
-    "@mui/utils" "^7.3.3"
-    prop-types "^15.8.1"
-
 "@mui/styled-engine@^6.5.0":
   version "6.5.0"
   resolved "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.5.0.tgz"
@@ -580,19 +541,7 @@
     csstype "^3.1.3"
     prop-types "^15.8.1"
 
-"@mui/styled-engine@^7.3.3":
-  version "7.3.3"
-  resolved "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.3.tgz"
-  integrity sha512-CmFxvRJIBCEaWdilhXMw/5wFJ1+FT9f3xt+m2pPXhHPeVIbBg9MnMvNSJjdALvnQJMPw8jLhrUtXmN7QAZV2fw==
-  dependencies:
-    "@babel/runtime" "^7.28.4"
-    "@emotion/cache" "^11.14.0"
-    "@emotion/serialize" "^1.3.3"
-    "@emotion/sheet" "^1.4.0"
-    csstype "^3.1.3"
-    prop-types "^15.8.1"
-
-"@mui/system@^5.15.14 || ^6.0.0 || ^7.0.0", "@mui/system@^6.5.0":
+"@mui/system@^5.15.14 || ^6.0.0 || ^7.0.0", "@mui/system@^5.15.20 || ^6.0.0 || ^7.0.0", "@mui/system@^6.5.0":
   version "6.5.0"
   resolved "https://registry.npmjs.org/@mui/system/-/system-6.5.0.tgz"
   integrity sha512-XcbBYxDS+h/lgsoGe78ExXFZXtuIlSBpn/KsZq8PtZcIkUNJInkuDqcLd2rVBQrDC1u+rvVovdaWPf2FHKJf3w==
@@ -606,27 +555,6 @@
     csstype "^3.1.3"
     prop-types "^15.8.1"
 
-"@mui/system@^5.15.20 || ^6.0.0 || ^7.0.0", "@mui/system@^7.3.3":
-  version "7.3.3"
-  resolved "https://registry.npmjs.org/@mui/system/-/system-7.3.3.tgz"
-  integrity sha512-Lqq3emZr5IzRLKaHPuMaLBDVaGvxoh6z7HMWd1RPKawBM5uMRaQ4ImsmmgXWtwJdfZux5eugfDhXJUo2mliS8Q==
-  dependencies:
-    "@babel/runtime" "^7.28.4"
-    "@mui/private-theming" "^7.3.3"
-    "@mui/styled-engine" "^7.3.3"
-    "@mui/types" "^7.4.7"
-    "@mui/utils" "^7.3.3"
-    clsx "^2.1.1"
-    csstype "^3.1.3"
-    prop-types "^15.8.1"
-
-"@mui/types@^7.4.7":
-  version "7.4.7"
-  resolved "https://registry.npmjs.org/@mui/types/-/types-7.4.7.tgz"
-  integrity sha512-8vVje9rdEr1rY8oIkYgP+Su5Kwl6ik7O3jQ0wl78JGSmiZhRHV+vkjooGdKD8pbtZbutXFVTWQYshu2b3sG9zw==
-  dependencies:
-    "@babel/runtime" "^7.28.4"
-
 "@mui/types@^7.4.8":
   version "7.4.8"
   resolved "https://registry.npmjs.org/@mui/types/-/types-7.4.8.tgz"
@@ -639,19 +567,7 @@
   resolved "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz"
   integrity sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==
 
-"@mui/utils@^5.15.20 || ^6.0.0 || ^7.0.0":
-  version "7.3.3"
-  resolved "https://registry.npmjs.org/@mui/utils/-/utils-7.3.3.tgz"
-  integrity sha512-kwNAUh7bLZ7mRz9JZ+6qfRnnxbE4Zuc+RzXnhSpRSxjTlSTj7b4JxRLXpG+MVtPVtqks5k/XC8No1Vs3x4Z2gg==
-  dependencies:
-    "@babel/runtime" "^7.28.4"
-    "@mui/types" "^7.4.7"
-    "@types/prop-types" "^15.7.15"
-    clsx "^2.1.1"
-    prop-types "^15.8.1"
-    react-is "^19.1.1"
-
-"@mui/utils@^6.4.9":
+"@mui/utils@^5.15.20 || ^6.0.0 || ^7.0.0", "@mui/utils@^6.4.9":
   version "6.4.9"
   resolved "https://registry.npmjs.org/@mui/utils/-/utils-6.4.9.tgz"
   integrity sha512-Y12Q9hbK9g+ZY0T3Rxrx9m2m10gaphDuUMgWxyV5kNJevVxXYCLclYUCC9vXaIk1/NdNDTcW2Yfr2OGvNFNmHg==
@@ -1050,35 +966,6 @@ acorn-jsx@^5.3.2:
   resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz"
   integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==
 
-ag-charts-community@12.3.1:
-  version "12.3.1"
-  resolved "https://registry.npmjs.org/ag-charts-community/-/ag-charts-community-12.3.1.tgz"
-  integrity sha512-uRaUFmCl8e0Y3KxjaHUYlkCPS5OtwtfTChkdpoZuBKDXqerCPTjPu+uvlun3rYUSYxScwVf2LZCI0Hfw4Vc+WQ==
-  dependencies:
-    ag-charts-core "12.3.1"
-    ag-charts-locale "12.3.1"
-    ag-charts-types "12.3.1"
-
-ag-charts-core@12.3.1:
-  version "12.3.1"
-  resolved "https://registry.npmjs.org/ag-charts-core/-/ag-charts-core-12.3.1.tgz"
-  integrity sha512-711UJ0fXengb8+4PEW4nlzWDowmbYymPcjW2eJWHRzzvttUf14hnh+wP/l/s3EGVgYkEHe9vkXFwmeOJUlkC0Q==
-  dependencies:
-    ag-charts-types "12.3.1"
-
-ag-charts-enterprise@12.3.1:
-  version "12.3.1"
-  resolved "https://registry.npmjs.org/ag-charts-enterprise/-/ag-charts-enterprise-12.3.1.tgz"
-  integrity sha512-2sQIwLfksRTcI4JVRjgQkyGq6z68UVTO/I91HKmtpukrQLsW/o0TzzHmgTtVJOXd9yO9gx2KWa2DMg0+FKdXEQ==
-  dependencies:
-    ag-charts-community "12.3.1"
-    ag-charts-core "12.3.1"
-
-ag-charts-locale@12.3.1:
-  version "12.3.1"
-  resolved "https://registry.npmjs.org/ag-charts-locale/-/ag-charts-locale-12.3.1.tgz"
-  integrity sha512-dCn7oHh3xLI576FT514aBedNQgtb5zwh/Gcj7jHvjOWYRnfH8kaekZzLzntITA6dF6E78okJfoI7CUCbYduQ4Q==
-
 ag-charts-types@12.3.1:
   version "12.3.1"
   resolved "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-12.3.1.tgz"
@@ -1657,7 +1544,12 @@ fastq@^1.6.0:
   dependencies:
     reusify "^1.0.4"
 
-fdir@^6.4.4, fdir@^6.5.0:
+fdir@^6.4.4:
+  version "6.5.0"
+  resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz"
+  integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==
+
+fdir@^6.5.0:
   version "6.5.0"
   resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz"
   integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==
@@ -2640,7 +2532,7 @@ react-is@^16.7.0:
   resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
   integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
 
-"react-is@^18.0.0 || ^19.0.0", "react-is@^18.2.0 || ^19.0.0", react-is@^19.0.0, react-is@^19.1.1, react-is@^19.2.0:
+"react-is@^18.0.0 || ^19.0.0", "react-is@^18.2.0 || ^19.0.0", react-is@^19.0.0, react-is@^19.2.0:
   version "19.2.0"
   resolved "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz"
   integrity sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==