Kaynağa Gözat

feat(theme): Add comprehensive theming system with theme context and table styling

- Implement ThemeContext and ThemeProvider for global theme management
- Add ThemeSwitcher component to toggle between light and dark themes
- Create centralized theme configuration with tokens and table-specific styles
- Add themed CSS variables for consistent styling across components
- Implement MinimalDocumentTable with minimal styling (horizontal lines only)
- Update DocumentManagement component with new themed styles and improved download handling
- Add DocumentManagement.css with CSS variable-based theme support
- Update EditorPanel and DocumentViewer components for theme compatibility
- Add comprehensive examples (MinimalTableExample, ThemeExample, TestMinimalStyle)
- Improve file download behavior using native browser download instead of window.open
- Support both light and dark theme variants with accessible color schemes
Zhang Yice 2 ay önce
ebeveyn
işleme
ab8f2d1c3a

+ 205 - 0
src/components/DocumentManagement/DocumentManagement.css

@@ -0,0 +1,205 @@
1
+/**
2
+ * Document Management Themed Styles
3
+ * 文档管理组件的主题化样式
4
+ * 
5
+ * 使用 CSS 变量实现主题切换,变量由 ThemeProvider 注入到 :root
6
+ */
7
+
8
+/* 表格容器 */
9
+.document-management-table {
10
+  font-family: var(--table-font-family);
11
+}
12
+
13
+/* Ant Design Table 覆盖样式 */
14
+.document-management-table .ant-table {
15
+  border-radius: var(--table-border-radius);
16
+  box-shadow: var(--table-box-shadow);
17
+  font-size: var(--table-body-font-size);
18
+  line-height: var(--table-line-height);
19
+}
20
+
21
+/* 表格边框 */
22
+.document-management-table .ant-table-container {
23
+  border: var(--table-border-width) solid var(--table-border-color);
24
+  border-radius: var(--table-border-radius);
25
+}
26
+
27
+/* ============================================
28
+   图二风格:移除竖线(当使用 minimal 主题时)
29
+   ============================================ */
30
+
31
+/* 移除所有单元格的右边框(竖线) */
32
+.document-management-table .ant-table-thead > tr > th,
33
+.document-management-table .ant-table-tbody > tr > td {
34
+  border-right: none !important;
35
+}
36
+
37
+/* 移除表头单元格之间的分隔线 */
38
+.document-management-table .ant-table-thead > tr > th::before {
39
+  display: none !important;
40
+}
41
+
42
+/* 移除表格容器的左右边框 */
43
+.document-management-table .ant-table-container {
44
+  border-left: none !important;
45
+  border-right: none !important;
46
+}
47
+
48
+/* 只保留横线边框 */
49
+.document-management-table .ant-table-wrapper {
50
+  border-top: var(--table-border-width) solid var(--table-border-color);
51
+  border-bottom: var(--table-border-width) solid var(--table-border-color);
52
+  border-left: none;
53
+  border-right: none;
54
+}
55
+
56
+/* 移除表格内部的竖线 */
57
+.document-management-table .ant-table-cell {
58
+  border-right: none !important;
59
+}
60
+
61
+/* 移除固定列的边框和阴影 */
62
+.document-management-table .ant-table-cell-fix-left,
63
+.document-management-table .ant-table-cell-fix-right {
64
+  border-right: none !important;
65
+  box-shadow: none !important;
66
+}
67
+
68
+/* 移除固定列分隔阴影 */
69
+.document-management-table .ant-table-ping-left .ant-table-cell-fix-left-last::after,
70
+.document-management-table .ant-table-ping-right .ant-table-cell-fix-right-first::after {
71
+  box-shadow: none !important;
72
+}
73
+
74
+/* ============================================
75
+   END 图二风格
76
+   ============================================ */
77
+
78
+/* 表头样式 */
79
+.document-management-table .ant-table-thead > tr > th {
80
+  background-color: var(--table-header-bg) !important;
81
+  color: var(--table-header-text) !important;
82
+  font-size: var(--table-header-font-size) !important;
83
+  font-weight: var(--table-header-font-weight) !important;
84
+  padding: var(--table-cell-padding-y) var(--table-cell-padding-x) !important;
85
+  height: var(--table-header-height);
86
+  border-bottom: calc(var(--table-border-width) * 2) solid var(--table-border-color) !important;
87
+}
88
+
89
+/* 表头边框 */
90
+.document-management-table .ant-table-thead > tr > th::before {
91
+  background-color: var(--table-border-color) !important;
92
+}
93
+
94
+/* 表格行样式 */
95
+.document-management-table .ant-table-tbody > tr {
96
+  background-color: var(--table-row-bg);
97
+  min-height: var(--table-min-row-height);
98
+  transition: var(--table-hover-transition);
99
+}
100
+
101
+/* 交替行背景(斑马纹) */
102
+.document-management-table .ant-table-tbody > tr:nth-child(even) {
103
+  background-color: var(--table-row-bg-alt);
104
+}
105
+
106
+/* 行悬停效果 */
107
+.document-management-table .ant-table-tbody > tr:hover > td {
108
+  background-color: var(--table-row-hover) !important;
109
+}
110
+
111
+/* 选中行样式 */
112
+.document-management-table .ant-table-tbody > tr.ant-table-row-selected > td {
113
+  background-color: var(--table-row-selected) !important;
114
+}
115
+
116
+/* 单元格样式 */
117
+.document-management-table .ant-table-tbody > tr > td {
118
+  color: var(--table-cell-text);
119
+  padding: var(--table-cell-padding-y) var(--table-cell-padding-x) !important;
120
+  border-bottom: var(--table-border-width) solid var(--table-border-color) !important;
121
+  font-size: var(--table-body-font-size);
122
+}
123
+
124
+/* 单元格内文字样式 */
125
+.document-management-table .ant-typography {
126
+  color: inherit;
127
+  font-size: inherit;
128
+}
129
+
130
+/* 次要文字颜色 */
131
+.document-management-table .ant-typography-secondary {
132
+  color: var(--table-text-secondary) !important;
133
+}
134
+
135
+/* 代码标签样式 */
136
+.document-management-table .ant-typography code {
137
+  font-size: var(--table-small-font-size) !important;
138
+}
139
+
140
+/* 标签样式 */
141
+.document-management-table .ant-tag {
142
+  font-size: var(--table-small-font-size) !important;
143
+}
144
+
145
+/* 操作按钮间距 */
146
+.document-management-table .ant-space-item {
147
+  margin-right: var(--table-action-spacing) !important;
148
+}
149
+
150
+.document-management-table .ant-space-item:last-child {
151
+  margin-right: 0 !important;
152
+}
153
+
154
+/* 操作按钮颜色 */
155
+.document-management-table .ant-btn-text:not(.ant-btn-dangerous) {
156
+  color: var(--table-action-primary);
157
+}
158
+
159
+.document-management-table .ant-btn-text:not(.ant-btn-dangerous):hover {
160
+  color: var(--table-action-primary);
161
+  opacity: 0.8;
162
+}
163
+
164
+.document-management-table .ant-btn-dangerous {
165
+  color: var(--table-action-danger) !important;
166
+}
167
+
168
+.document-management-table .ant-btn-dangerous:hover {
169
+  color: var(--table-action-danger) !important;
170
+  opacity: 0.8;
171
+}
172
+
173
+/* 分页器样式 */
174
+.document-management-table .ant-pagination {
175
+  margin-top: var(--table-margin);
176
+  font-size: var(--table-body-font-size);
177
+}
178
+
179
+/* 加载状态 */
180
+.document-management-table .ant-spin {
181
+  color: var(--table-action-primary);
182
+}
183
+
184
+/* 空状态 */
185
+.document-management-table .ant-empty-description {
186
+  color: var(--table-text-secondary);
187
+  font-size: var(--table-body-font-size);
188
+}
189
+
190
+/* 固定列阴影 */
191
+.document-management-table .ant-table-cell-fix-right {
192
+  background-color: inherit !important;
193
+}
194
+
195
+/* 响应式调整 */
196
+@media screen and (max-width: 768px) {
197
+  .document-management-table .ant-table-thead > tr > th,
198
+  .document-management-table .ant-table-tbody > tr > td {
199
+    padding: calc(var(--table-cell-padding-y) * 0.75) calc(var(--table-cell-padding-x) * 0.75) !important;
200
+  }
201
+  
202
+  .document-management-table .ant-table {
203
+    font-size: calc(var(--table-body-font-size) * 0.9);
204
+  }
205
+}

+ 95 - 17
src/components/DocumentManagement/DocumentManagement.tsx

@@ -10,6 +10,7 @@
10 10
  */
11 11
 
12 12
 import React, { useState, useEffect, useCallback } from 'react';
13
+import './DocumentManagement.css';
13 14
 import {
14 15
   Card,
15 16
   Table,
@@ -142,11 +143,27 @@ export const DocumentManagement: React.FC<DocumentManagementProps> = ({
142 143
         message.warning(result.warning, 5);
143 144
       }
144 145
 
145
-      // The downloadUrl is now properly formatted with base URL in the service
146
+      // 直接触发浏览器下载,而不是在新标签页打开
146 147
       if (result.downloadUrl) {
147
-        window.open(result.downloadUrl, '_blank');
148
+        // 创建隐藏的 a 标签来触发下载
149
+        const link = document.createElement('a');
150
+        link.href = result.downloadUrl;
151
+        link.download = result.fileName; // 设置下载文件名
152
+        link.style.display = 'none';
153
+        
154
+        // 添加到 DOM,触发点击,然后移除
155
+        document.body.appendChild(link);
156
+        link.click();
157
+        
158
+        // 延迟移除,确保下载开始
159
+        setTimeout(() => {
160
+          document.body.removeChild(link);
161
+        }, 100);
162
+        
163
+        console.log('[DocumentManagement] Word 文档下载已触发:', result.fileName);
148 164
       }
149 165
     } catch (error) {
166
+      console.error('[DocumentManagement] 导出失败:', error);
150 167
       message.error('导出失败: ' + (error instanceof Error ? error.message : '未知错误'));
151 168
     } finally {
152 169
       setExporting((prev) => ({ ...prev, [documentId]: false }));
@@ -304,21 +321,82 @@ export const DocumentManagement: React.FC<DocumentManagementProps> = ({
304 321
       )}
305 322
 
306 323
       {/* Table */}
307
-      <Table
308
-        columns={columns}
309
-        dataSource={documents}
310
-        rowKey="id"
311
-        loading={loading}
312
-        pagination={{
313
-          current: currentPage,
314
-          pageSize,
315
-          total,
316
-          showSizeChanger: false,
317
-          showTotal: (total) => `共 ${total} 个文档`,
318
-          onChange: (page) => setCurrentPage(page),
319
-        }}
320
-        scroll={{ x: 900 }}
321
-      />
324
+      <div className="document-management-table">
325
+        {/* 内联样式 - 强制移除竖线 */}
326
+        <style>{`
327
+          /* 移除所有竖线 - 最高优先级 */
328
+          .document-management-table .ant-table-thead > tr > th,
329
+          .document-management-table .ant-table-tbody > tr > td,
330
+          .document-management-table .ant-table-cell {
331
+            border-right: none !important;
332
+            border-left: none !important;
333
+          }
334
+          
335
+          /* 移除表头分隔线 */
336
+          .document-management-table .ant-table-thead > tr > th::before {
337
+            display: none !important;
338
+            width: 0 !important;
339
+            background: transparent !important;
340
+          }
341
+          
342
+          /* 移除容器边框 */
343
+          .document-management-table .ant-table-container {
344
+            border-left: none !important;
345
+            border-right: none !important;
346
+          }
347
+          
348
+          /* 移除固定列样式 */
349
+          .document-management-table .ant-table-cell-fix-left,
350
+          .document-management-table .ant-table-cell-fix-right {
351
+            border-right: none !important;
352
+            box-shadow: none !important;
353
+          }
354
+          
355
+          /* 移除固定列阴影 */
356
+          .document-management-table .ant-table-ping-left .ant-table-cell-fix-left-last::after,
357
+          .document-management-table .ant-table-ping-right .ant-table-cell-fix-right-first::after {
358
+            box-shadow: none !important;
359
+            display: none !important;
360
+          }
361
+          
362
+          /* 表格整体只保留横线 */
363
+          .document-management-table .ant-table-wrapper {
364
+            border-left: none !important;
365
+            border-right: none !important;
366
+          }
367
+          
368
+          /* 确保表格内部没有竖线 */
369
+          .document-management-table .ant-table {
370
+            border-left: none !important;
371
+            border-right: none !important;
372
+          }
373
+          
374
+          .document-management-table .ant-table table {
375
+            border-collapse: collapse !important;
376
+          }
377
+          
378
+          .document-management-table .ant-table-thead > tr > th,
379
+          .document-management-table .ant-table-tbody > tr > td {
380
+            border-left: 0 !important;
381
+            border-right: 0 !important;
382
+          }
383
+        `}</style>
384
+        <Table
385
+          columns={columns}
386
+          dataSource={documents}
387
+          rowKey="id"
388
+          loading={loading}
389
+          pagination={{
390
+            current: currentPage,
391
+            pageSize,
392
+            total,
393
+            showSizeChanger: false,
394
+            showTotal: (total) => `共 ${total} 个文档`,
395
+            onChange: (page) => setCurrentPage(page),
396
+          }}
397
+          scroll={{ x: 900 }}
398
+        />
399
+      </div>
322 400
 
323 401
       {/* View Document Modal */}
324 402
       <Modal

+ 181 - 0
src/components/DocumentManagement/MinimalDocumentTable.tsx

@@ -0,0 +1,181 @@
1
+/**
2
+ * Minimal Document Table Component
3
+ * 简洁文档表格组件 
4
+ */
5
+
6
+import React from 'react';
7
+import './MinimalTable.css';
8
+import { Table, Typography } from 'antd';
9
+import type { ColumnsType } from 'antd/es/table';
10
+
11
+const { Text, Paragraph } = Typography;
12
+
13
+/**
14
+ * 文档数据接口(简化版,适配图二的结构)
15
+ */
16
+interface DocumentRow {
17
+  key: string;
18
+  category: string;         // 分类(如:设计单位、审核意见、审核人等)
19
+  content1: string;         // 第一列内容
20
+  content2: string;         // 第二列内容
21
+  content3: string;         // 第三列内容
22
+}
23
+
24
+interface MinimalDocumentTableProps {
25
+  /** 表格数据 */
26
+  dataSource: DocumentRow[];
27
+  /** 是否加载中 */
28
+  loading?: boolean;
29
+  /** 自定义样式 */
30
+  style?: React.CSSProperties;
31
+  /** 是否显示边框 */
32
+  bordered?: boolean;
33
+}
34
+
35
+/**
36
+ * 简洁文档表格组件
37
+ */
38
+export const MinimalDocumentTable: React.FC<MinimalDocumentTableProps> = ({
39
+  dataSource,
40
+  loading = false,
41
+  style,
42
+  bordered = false,
43
+}) => {
44
+  /**
45
+   * 表格列定义
46
+   */
47
+  const columns: ColumnsType<DocumentRow> = [
48
+    {
49
+      title: '设计单位',
50
+      dataIndex: 'category',
51
+      key: 'category',
52
+      width: '12%',
53
+      render: (text: string) => (
54
+        <Text style={{ fontSize: 13, fontWeight: 500 }}>
55
+          {text}
56
+        </Text>
57
+      ),
58
+    },
59
+    {
60
+      title: '东河采油气管理区(东河储气库分公司)油气藏地质研究所',
61
+      dataIndex: 'content1',
62
+      key: 'content1',
63
+      width: '29%',
64
+      render: (text: string) => (
65
+        <Paragraph
66
+          style={{
67
+            margin: 0,
68
+            fontSize: 13,
69
+            lineHeight: 1.75,
70
+            whiteSpace: 'pre-wrap',
71
+          }}
72
+        >
73
+          {text}
74
+        </Paragraph>
75
+      ),
76
+    },
77
+    {
78
+      title: '东河采油气管理区(东河储气库分公司)油气藏地质研究所',
79
+      dataIndex: 'content2',
80
+      key: 'content2',
81
+      width: '29%',
82
+      render: (text: string) => (
83
+        <Paragraph
84
+          style={{
85
+            margin: 0,
86
+            fontSize: 13,
87
+            lineHeight: 1.75,
88
+            whiteSpace: 'pre-wrap',
89
+          }}
90
+        >
91
+          {text}
92
+        </Paragraph>
93
+      ),
94
+    },
95
+    {
96
+      title: '东河采油气管理区(东河储气库分公司)油气藏地质研究所',
97
+      dataIndex: 'content3',
98
+      key: 'content3',
99
+      width: '29%',
100
+      render: (text: string) => (
101
+        <Paragraph
102
+          style={{
103
+            margin: 0,
104
+            fontSize: 13,
105
+            lineHeight: 1.75,
106
+            whiteSpace: 'pre-wrap',
107
+          }}
108
+        >
109
+          {text}
110
+        </Paragraph>
111
+      ),
112
+    },
113
+  ];
114
+
115
+  return (
116
+    <div className="minimal-table" style={style}>
117
+      <Table
118
+        columns={columns}
119
+        dataSource={dataSource}
120
+        loading={loading}
121
+        pagination={false}
122
+        bordered={bordered}
123
+        size="middle"
124
+        showHeader={true}
125
+        scroll={{ x: 'max-content' }}
126
+      />
127
+    </div>
128
+  );
129
+};
130
+
131
+/**
132
+ * 示例数据生成函数
133
+ */
134
+export const generateSampleData = (): DocumentRow[] => {
135
+  return [
136
+    {
137
+      key: '1',
138
+      category: '设计单位',
139
+      content1: '东河采油气管理区(东河储气库分公司)油气藏地质研究所',
140
+      content2: '东河采油气管理区(东河储气库分公司)油气藏地质研究所',
141
+      content3: '东河采油气管理区(东河储气库分公司)油气藏地质研究所',
142
+    },
143
+    {
144
+      key: '2',
145
+      category: '审核意见',
146
+      content1: '说明:审核人要明确确表达"同意或不同意",不能只签名不签署意见;同时,如果对设计内容之外有相关要求,可以在这里强调一下。',
147
+      content2: '说明:审核人要明确确表达"同意或不同意",不能只签名不签署意见;同时,如果对设计内容之外有相关要求,可以在这里强调一下。',
148
+      content3: '说明:审核人要明确确表达"同意或不同意",不能只签名不签署意见;同时,如果对设计内容之外有相关要求,可以在这里强调一下。',
149
+    },
150
+    {
151
+      key: '3',
152
+      category: '审核人',
153
+      content1: '',
154
+      content2: '审核时间',
155
+      content3: '',
156
+    },
157
+    {
158
+      key: '4',
159
+      category: '审批意见',
160
+      content1: '说明:审核人要明确确表达"同意或不同意",不能只签名不签署意见;同时,如果对设计内容之外有相关要求,可以在这里强调一下。',
161
+      content2: '说明:审核人要明确确表达"同意或不同意",不能只签名不签署意见;同时,如果对设计内容之外有相关要求,可以在这里强调一下。',
162
+      content3: '说明:审核人要明确确表达"同意或不同意",不能只签名不签署意见;同时,如果对设计内容之外有相关要求,可以在这里强调一下。',
163
+    },
164
+    {
165
+      key: '5',
166
+      category: '审批人',
167
+      content1: '',
168
+      content2: '审批时间',
169
+      content3: '',
170
+    },
171
+    {
172
+      key: '6',
173
+      category: '主管部门审核意见',
174
+      content1: '(需油气开发审批的保留三级审核部分,常规措施由采油气管理区二级审核)这里需要明确哪些井作下作业设计需要到油气开发部?',
175
+      content2: '(需油气开发审批的保留三级审核部分,常规措施由采油气管理区二级审核)这里需要明确哪些井作下作业设计需要到油气开发部?',
176
+      content3: '(需油气开发审批的保留三级审核部分,常规措施由采油气管理区二级审核)这里需要明确哪些井作下作业设计需要到油气开发部?',
177
+    },
178
+  ];
179
+};
180
+
181
+export default MinimalDocumentTable;

+ 243 - 0
src/components/DocumentManagement/MinimalTable.css

@@ -0,0 +1,243 @@
1
+/**
2
+ * Minimal Table Styles 
3
+ * 简洁表格样式 - 只有横线,无竖线,紧凑布局
4
+ */
5
+
6
+/* 表格容器 */
7
+.minimal-table {
8
+  font-family: var(--table-font-family);
9
+  width: 100%;
10
+}
11
+
12
+/* 移除 Ant Design 默认的圆角和阴影 */
13
+.minimal-table .ant-table {
14
+  border-radius: 0;
15
+  box-shadow: none;
16
+  font-size: var(--table-body-font-size);
17
+  line-height: var(--table-line-height);
18
+}
19
+
20
+/* 移除表格容器边框和圆角 */
21
+.minimal-table .ant-table-container {
22
+  border: none !important;
23
+  border-radius: 0;
24
+}
25
+
26
+/* 表格边框 - 只保留顶部和底部 */
27
+.minimal-table .ant-table-container::before,
28
+.minimal-table .ant-table-container::after {
29
+  display: none;
30
+}
31
+
32
+/* 表格整体边框 */
33
+.minimal-table .ant-table-wrapper {
34
+  border-top: var(--table-border-width) solid var(--table-border-color);
35
+  border-bottom: var(--table-border-width) solid var(--table-border-color);
36
+}
37
+
38
+/* 表头样式 */
39
+.minimal-table .ant-table-thead > tr > th {
40
+  background-color: var(--table-header-bg) !important;
41
+  color: var(--table-header-text) !important;
42
+  font-size: var(--table-header-font-size) !important;
43
+  font-weight: var(--table-header-font-weight) !important;
44
+  padding: var(--table-cell-padding-y) var(--table-cell-padding-x) !important;
45
+  border-bottom: calc(var(--table-border-width) * 2) solid var(--table-border-color) !important;
46
+  border-right: none !important;
47
+  text-align: left;
48
+}
49
+
50
+/* 移除表头单元格之间的分隔线 */
51
+.minimal-table .ant-table-thead > tr > th::before {
52
+  display: none !important;
53
+}
54
+
55
+/* 移除表头排序图标附近的边框 */
56
+.minimal-table .ant-table-thead > tr > th.ant-table-column-has-sorters::before {
57
+  display: none !important;
58
+}
59
+
60
+/* 表格行样式 */
61
+.minimal-table .ant-table-tbody > tr {
62
+  background-color: var(--table-row-bg);
63
+  transition: var(--table-hover-transition);
64
+}
65
+
66
+/* 移除斑马纹效果 */
67
+.minimal-table .ant-table-tbody > tr:nth-child(even) {
68
+  background-color: var(--table-row-bg);
69
+}
70
+
71
+/* 行悬停效果 */
72
+.minimal-table .ant-table-tbody > tr:hover > td {
73
+  background-color: var(--table-row-hover) !important;
74
+}
75
+
76
+/* 单元格样式 */
77
+.minimal-table .ant-table-tbody > tr > td {
78
+  color: var(--table-cell-text);
79
+  padding: var(--table-cell-padding-y) var(--table-cell-padding-x) !important;
80
+  border-bottom: var(--table-border-width) solid var(--table-border-color) !important;
81
+  border-right: none !important;
82
+  font-size: var(--table-body-font-size);
83
+  vertical-align: top;
84
+  line-height: var(--table-line-height);
85
+}
86
+
87
+/* 最后一行不显示底部边框 */
88
+.minimal-table .ant-table-tbody > tr:last-child > td {
89
+  border-bottom: none !important;
90
+}
91
+
92
+/* 移除固定列的阴影效果 */
93
+.minimal-table .ant-table-cell-fix-left,
94
+.minimal-table .ant-table-cell-fix-right {
95
+  background-color: inherit !important;
96
+  box-shadow: none !important;
97
+}
98
+
99
+/* 单元格内文字样式 */
100
+.minimal-table .ant-typography {
101
+  color: inherit;
102
+  font-size: inherit;
103
+  margin-bottom: 0;
104
+}
105
+
106
+/* 次要文字颜色 */
107
+.minimal-table .ant-typography-secondary {
108
+  color: var(--table-text-secondary) !important;
109
+}
110
+
111
+/* 移除表格内部的所有竖线 */
112
+.minimal-table .ant-table-cell {
113
+  border-right: none !important;
114
+}
115
+
116
+/* 表格标题和内容的对齐 */
117
+.minimal-table .ant-table-thead > tr > th,
118
+.minimal-table .ant-table-tbody > tr > td {
119
+  text-align: left;
120
+}
121
+
122
+/* 标签样式 */
123
+.minimal-table .ant-tag {
124
+  font-size: var(--table-small-font-size) !important;
125
+  border: none;
126
+  margin: 0;
127
+}
128
+
129
+/* 代码样式 */
130
+.minimal-table .ant-typography code {
131
+  font-size: var(--table-small-font-size) !important;
132
+  background-color: var(--table-row-bg-alt);
133
+  border: var(--table-border-width) solid var(--table-border-color);
134
+  padding: 2px 6px;
135
+  border-radius: 3px;
136
+}
137
+
138
+/* 按钮组样式 */
139
+.minimal-table .ant-space {
140
+  gap: var(--table-action-spacing) !important;
141
+}
142
+
143
+/* 操作按钮颜色 */
144
+.minimal-table .ant-btn-text:not(.ant-btn-dangerous) {
145
+  color: var(--table-action-primary);
146
+}
147
+
148
+.minimal-table .ant-btn-text:not(.ant-btn-dangerous):hover {
149
+  color: var(--table-action-primary);
150
+  background-color: var(--table-row-hover);
151
+}
152
+
153
+.minimal-table .ant-btn-dangerous {
154
+  color: var(--table-action-danger) !important;
155
+}
156
+
157
+.minimal-table .ant-btn-dangerous:hover {
158
+  color: var(--table-action-danger) !important;
159
+  background-color: rgba(239, 68, 68, 0.1);
160
+}
161
+
162
+/* 分页器样式 */
163
+.minimal-table .ant-pagination {
164
+  margin-top: var(--table-margin);
165
+  font-size: var(--table-body-font-size);
166
+}
167
+
168
+/* 加载状态 */
169
+.minimal-table .ant-spin {
170
+  color: var(--table-action-primary);
171
+}
172
+
173
+/* 空状态 */
174
+.minimal-table .ant-empty-description {
175
+  color: var(--table-text-secondary);
176
+  font-size: var(--table-body-font-size);
177
+}
178
+
179
+/* 多行文本样式 */
180
+.minimal-table .ant-table-cell p {
181
+  margin: 0;
182
+  line-height: var(--table-line-height);
183
+}
184
+
185
+/* 表格内容行高 */
186
+.minimal-table .ant-table-tbody > tr > td {
187
+  line-height: 1.75;
188
+}
189
+
190
+/* 紧凑显示 - 移除不必要的间距 */
191
+.minimal-table .ant-table-thead th.ant-table-column-sort {
192
+  padding-right: var(--table-cell-padding-x) !important;
193
+}
194
+
195
+/* 移除固定列阴影 */
196
+.minimal-table .ant-table-ping-left .ant-table-cell-fix-left-last::after,
197
+.minimal-table .ant-table-ping-right .ant-table-cell-fix-right-first::after {
198
+  box-shadow: none !important;
199
+}
200
+
201
+/* 响应式调整 */
202
+@media screen and (max-width: 768px) {
203
+  .minimal-table .ant-table-thead > tr > th,
204
+  .minimal-table .ant-table-tbody > tr > td {
205
+    padding: calc(var(--table-cell-padding-y) * 0.75) calc(var(--table-cell-padding-x) * 0.75) !important;
206
+  }
207
+  
208
+  .minimal-table .ant-table {
209
+    font-size: calc(var(--table-body-font-size) * 0.9);
210
+  }
211
+}
212
+
213
+/* 表格列宽度自适应 */
214
+.minimal-table .ant-table-tbody > tr > td:first-child,
215
+.minimal-table .ant-table-thead > tr > th:first-child {
216
+  min-width: 120px;
217
+}
218
+
219
+/* 确保长文本换行 */
220
+.minimal-table .ant-table-cell {
221
+  word-break: break-word;
222
+  overflow-wrap: break-word;
223
+}
224
+
225
+/* 移除表格的外层边框线 */
226
+.minimal-table .ant-table-bordered .ant-table-container {
227
+  border: none !important;
228
+}
229
+
230
+/* 选中行样式 */
231
+.minimal-table .ant-table-tbody > tr.ant-table-row-selected > td {
232
+  background-color: var(--table-row-selected) !important;
233
+}
234
+
235
+/* Tooltip 样式 */
236
+.minimal-table .ant-tooltip {
237
+  font-size: var(--table-small-font-size);
238
+}
239
+
240
+/* Popconfirm 样式 */
241
+.minimal-table .ant-popconfirm {
242
+  font-size: var(--table-body-font-size);
243
+}

+ 1 - 0
src/components/DocumentManagement/index.ts

@@ -1,2 +1,3 @@
1 1
 export { DocumentManagement } from './DocumentManagement';
2
+export { MinimalDocumentTable, generateSampleData } from './MinimalDocumentTable';
2 3
 export { DocumentManagement as default } from './DocumentManagement';

+ 33 - 3
src/components/DocumentManagementLayout/DocumentManagementLayout.tsx

@@ -251,15 +251,30 @@ const DocumentManagementLayout: React.FC<DocumentManagementLayoutProps> = ({
251 251
       
252 252
       message.success(`导出成功: ${result.fileName}`);
253 253
       
254
-      // Open download URL in new tab
254
+      // 直接触发浏览器下载
255 255
       if (result.downloadUrl) {
256 256
         const baseUrl = import.meta.env.VITE_API_BASE_URL || 'http://192.168.0.195:8000';
257 257
         const fullUrl = result.downloadUrl.startsWith('http') 
258 258
           ? result.downloadUrl 
259 259
           : `${baseUrl}${result.downloadUrl}`;
260
-        window.open(fullUrl, '_blank');
260
+        
261
+        // 创建隐藏的 a 标签来触发下载
262
+        const link = document.createElement('a');
263
+        link.href = fullUrl;
264
+        link.download = result.fileName;
265
+        link.style.display = 'none';
266
+        
267
+        document.body.appendChild(link);
268
+        link.click();
269
+        
270
+        setTimeout(() => {
271
+          document.body.removeChild(link);
272
+        }, 100);
273
+        
274
+        console.log('[DocumentManagementLayout] Word 文档下载已触发:', result.fileName);
261 275
       }
262 276
     } catch (error) {
277
+      console.error('[DocumentManagementLayout] 导出失败:', error);
263 278
       message.error('导出失败: ' + (error instanceof Error ? error.message : '未知错误'));
264 279
     } finally {
265 280
       setLoading(false);
@@ -283,7 +298,22 @@ const DocumentManagementLayout: React.FC<DocumentManagementLayoutProps> = ({
283 298
     if (selectedRecordId) {
284 299
       const baseUrl = import.meta.env.VITE_API_BASE_URL || 'http://192.168.0.195:8000';
285 300
       const downloadUrl = `${baseUrl}/api/v1/export/records/${selectedRecordId}/download?userId=${encodeURIComponent(userId)}`;
286
-      window.open(downloadUrl, '_blank');
301
+      
302
+      // 创建隐藏的 a 标签来触发下载
303
+      const link = document.createElement('a');
304
+      link.href = downloadUrl;
305
+      link.download = `document-${selectedRecordId}.docx`; // 默认文件名
306
+      link.style.display = 'none';
307
+      
308
+      document.body.appendChild(link);
309
+      link.click();
310
+      
311
+      setTimeout(() => {
312
+        document.body.removeChild(link);
313
+      }, 100);
314
+      
315
+      message.success('下载已开始');
316
+      console.log('[DocumentManagementLayout] 下载已触发:', downloadUrl);
287 317
     }
288 318
   }, [selectedRecordId, userId]);
289 319
 

+ 36 - 8
src/components/DocumentViewer/DocumentViewer.tsx

@@ -202,14 +202,42 @@ export const DocumentViewer: React.FC<DocumentViewerProps> = ({
202 202
 
203 203
         return (
204 204
           <div key={block.id} id={block.id} style={{ marginBottom: '24px' }}>
205
-            <Table
206
-              columns={columns}
207
-              dataSource={dataSource}
208
-              pagination={false}
209
-              bordered
210
-              size="small"
211
-              style={{ fontSize: '13px' }}
212
-            />
205
+            {/* 内联样式 - 移除竖线 */}
206
+            <style>{`
207
+              /* 移除表格竖线 - 只保留横线 */
208
+              .document-viewer-table .ant-table-thead > tr > th,
209
+              .document-viewer-table .ant-table-tbody > tr > td {
210
+                border-right: none !important;
211
+                border-left: none !important;
212
+              }
213
+              
214
+              /* 移除表头分隔线 */
215
+              .document-viewer-table .ant-table-thead > tr > th::before {
216
+                display: none !important;
217
+              }
218
+              
219
+              /* 只保留横线 */
220
+              .document-viewer-table .ant-table-container {
221
+                border-left: none !important;
222
+                border-right: none !important;
223
+              }
224
+              
225
+              /* 表格整体样式 */
226
+              .document-viewer-table .ant-table {
227
+                border-left: none !important;
228
+                border-right: none !important;
229
+              }
230
+            `}</style>
231
+            <div className="document-viewer-table">
232
+              <Table
233
+                columns={columns}
234
+                dataSource={dataSource}
235
+                pagination={false}
236
+                bordered={false}
237
+                size="small"
238
+                style={{ fontSize: '13px' }}
239
+              />
240
+            </div>
213 241
           </div>
214 242
         );
215 243
       }

+ 18 - 2
src/components/EditorPanel/EditorPanel.tsx

@@ -277,11 +277,27 @@ export const EditorPanel: React.FC<EditorPanelProps> = ({
277 277
       
278 278
       message.success(`导出成功: ${result.fileName}`);
279 279
       
280
-      // The downloadUrl is now properly formatted with base URL in the service
280
+      // 直接触发浏览器下载,而不是在新标签页打开
281 281
       if (result.downloadUrl) {
282
-        window.open(result.downloadUrl, '_blank');
282
+        // 创建隐藏的 a 标签来触发下载
283
+        const link = document.createElement('a');
284
+        link.href = result.downloadUrl;
285
+        link.download = result.fileName; // 设置下载文件名
286
+        link.style.display = 'none';
287
+        
288
+        // 添加到 DOM,触发点击,然后移除
289
+        document.body.appendChild(link);
290
+        link.click();
291
+        
292
+        // 延迟移除,确保下载开始
293
+        setTimeout(() => {
294
+          document.body.removeChild(link);
295
+        }, 100);
296
+        
297
+        console.log('[EditorPanel] Word 文档下载已触发:', result.fileName);
283 298
       }
284 299
     } catch (error) {
300
+      console.error('[EditorPanel] 导出失败:', error);
285 301
       message.error('导出失败: ' + (error instanceof Error ? error.message : '未知错误'));
286 302
     } finally {
287 303
       setExporting(false);

+ 27 - 3
src/components/EditorPanel/WYSIWYGEditor.css

@@ -83,12 +83,12 @@
83 83
   line-height: 1.8;
84 84
 }
85 85
 
86
-/* Tables - Simple black border style (like Word default) */
86
+/* Tables - Completely borderless (无边框) */
87 87
 .mdx-editor-content table {
88 88
   width: 100%;
89 89
   margin-bottom: 20px;
90 90
   border-collapse: collapse;
91
-  border: 1px solid #000000;
91
+  border: none;                     /* 移除所有边框 */
92 92
   font-size: 13px;
93 93
 }
94 94
 
@@ -99,7 +99,7 @@
99 99
 .mdx-editor-content th,
100 100
 .mdx-editor-content td {
101 101
   padding: 8px 12px;
102
-  border: 1px solid #000000;
102
+  border: none;                     /* 移除所有边框 */
103 103
   text-align: left;
104 104
   vertical-align: top;
105 105
 }
@@ -120,6 +120,30 @@
120 120
   background-color: transparent;
121 121
 }
122 122
 
123
+/* 隐藏表格编辑按钮 */
124
+.mdx-editor-content table button,
125
+.mdx-editor-content [role="button"],
126
+.mdx-editor-content [class*="tableColumnEditor"],
127
+.mdx-editor-content [class*="tableEditor"] button,
128
+.mdx-editor-content [class*="iconButton"] {
129
+  display: none !important;
130
+}
131
+
132
+/* 隐藏表格单元格中的编辑控件 */
133
+.mdx-editor-content th button,
134
+.mdx-editor-content td button {
135
+  display: none !important;
136
+}
137
+
138
+/* 隐藏表格上方和单元格中的所有按钮 */
139
+.mdx-editor-content table + button,
140
+.mdx-editor-content table button {
141
+  display: none !important;
142
+  visibility: hidden !important;
143
+  opacity: 0 !important;
144
+  pointer-events: none !important;
145
+}
146
+
123 147
 /* Blockquotes */
124 148
 .mdx-editor-content blockquote {
125 149
   margin: 16px 0;

+ 102 - 0
src/components/ThemeSwitcher/ThemeSwitcher.tsx

@@ -0,0 +1,102 @@
1
+/**
2
+ * Theme Switcher Component
3
+ * 主题切换器组件 - 提供主题切换的 UI 控件
4
+ */
5
+
6
+import React from 'react';
7
+import { Select, Space, Typography } from 'antd';
8
+import { BgColorsOutlined } from '@ant-design/icons';
9
+import { useTheme } from '../../theme';
10
+import type { TableThemeType } from '../../theme';
11
+
12
+const { Text } = Typography;
13
+
14
+/**
15
+ * 主题显示名称映射
16
+ */
17
+const themeNames: Record<TableThemeType, string> = {
18
+  default: '默认主题',
19
+  dark: '暗色主题',
20
+  compact: '紧凑主题',
21
+  comfortable: '宽松主题',
22
+  minimal: '简洁主题',
23
+};
24
+
25
+/**
26
+ * 主题描述映射
27
+ */
28
+const themeDescriptions: Record<TableThemeType, string> = {
29
+  default: '标准的亮色主题,适合日常使用',
30
+  dark: '深色背景主题,护眼且现代',
31
+  compact: '紧凑布局,适合显示更多内容',
32
+  comfortable: '宽松布局,适合长时间阅读',
33
+  minimal: '简洁布局,只有横线无竖线',
34
+};
35
+
36
+interface ThemeSwitcherProps {
37
+  /** 是否显示为紧凑模式 */
38
+  compact?: boolean;
39
+  /** 是否显示描述 */
40
+  showDescription?: boolean;
41
+  /** 自定义样式 */
42
+  style?: React.CSSProperties;
43
+}
44
+
45
+/**
46
+ * 主题切换器组件
47
+ */
48
+export const ThemeSwitcher: React.FC<ThemeSwitcherProps> = ({
49
+  compact = false,
50
+  showDescription = false,
51
+  style,
52
+}) => {
53
+  const { currentThemeType, setTheme, availableThemes } = useTheme();
54
+
55
+  const handleThemeChange = (value: TableThemeType) => {
56
+    setTheme(value);
57
+  };
58
+
59
+  if (compact) {
60
+    return (
61
+      <Select
62
+        value={currentThemeType}
63
+        onChange={handleThemeChange}
64
+        style={{ width: 120, ...style }}
65
+        size="small"
66
+      >
67
+        {availableThemes.map((theme) => (
68
+          <Select.Option key={theme} value={theme}>
69
+            {themeNames[theme]}
70
+          </Select.Option>
71
+        ))}
72
+      </Select>
73
+    );
74
+  }
75
+
76
+  return (
77
+    <Space direction="vertical" style={style}>
78
+      <Space>
79
+        <BgColorsOutlined />
80
+        <Text strong>主题设置</Text>
81
+      </Space>
82
+      <Select
83
+        value={currentThemeType}
84
+        onChange={handleThemeChange}
85
+        style={{ width: 200 }}
86
+      >
87
+        {availableThemes.map((theme) => (
88
+          <Select.Option key={theme} value={theme}>
89
+            {themeNames[theme]}
90
+          </Select.Option>
91
+        ))}
92
+      </Select>
93
+      {showDescription && (
94
+        <Text type="secondary" style={{ fontSize: 12 }}>
95
+          {themeDescriptions[currentThemeType]}
96
+        </Text>
97
+      )}
98
+    </Space>
99
+  );
100
+};
101
+
102
+export default ThemeSwitcher;

+ 6 - 0
src/components/ThemeSwitcher/index.ts

@@ -0,0 +1,6 @@
1
+/**
2
+ * Theme Switcher Module Entry
3
+ */
4
+
5
+export { ThemeSwitcher } from './ThemeSwitcher';
6
+export { default } from './ThemeSwitcher';

+ 189 - 0
src/examples/MinimalTableExample.tsx

@@ -0,0 +1,189 @@
1
+/**
2
+ * Minimal Table Usage Example
3
+ * 简洁表格使用示例 - 展示图二风格的表格
4
+ */
5
+
6
+import React from 'react';
7
+import { Card, Space, Typography, Divider } from 'antd';
8
+import { ThemeProvider } from '../theme';
9
+import { ThemeSwitcher } from '../components/ThemeSwitcher';
10
+import { MinimalDocumentTable, generateSampleData } from '../components/DocumentManagement';
11
+
12
+const { Title, Paragraph, Text } = Typography;
13
+
14
+/**
15
+ * 基本使用示例
16
+ */
17
+export const BasicMinimalTableExample: React.FC = () => {
18
+  const sampleData = generateSampleData();
19
+
20
+  return (
21
+    <ThemeProvider initialTheme="minimal">
22
+      <div style={{ padding: 24, backgroundColor: '#f5f5f5', minHeight: '100vh' }}>
23
+        <Card>
24
+          <Space direction="vertical" style={{ width: '100%' }} size="large">
25
+            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
26
+              <Title level={3}>简洁表格示例(图二风格)</Title>
27
+              <ThemeSwitcher compact />
28
+            </div>
29
+            
30
+            <Paragraph>
31
+              这是一个简洁的表格样式,特点:
32
+              <ul>
33
+                <li>只有横线,没有竖线</li>
34
+                <li>白色背景,清爽简洁</li>
35
+                <li>紧凑的布局</li>
36
+                <li>适合文档类内容展示</li>
37
+              </ul>
38
+            </Paragraph>
39
+
40
+            <Divider />
41
+
42
+            <MinimalDocumentTable dataSource={sampleData} />
43
+          </Space>
44
+        </Card>
45
+      </div>
46
+    </ThemeProvider>
47
+  );
48
+};
49
+
50
+/**
51
+ * 对比示例:展示不同主题下的表格效果
52
+ */
53
+export const ThemeComparisonMinimalExample: React.FC = () => {
54
+  const sampleData = generateSampleData();
55
+
56
+  return (
57
+    <div style={{ padding: 24, backgroundColor: '#f5f5f5' }}>
58
+      <Space direction="vertical" style={{ width: '100%' }} size="large">
59
+        <Title level={2}>表格主题对比</Title>
60
+
61
+        {/* Default 主题 */}
62
+        <Card title="默认主题(有网格线)">
63
+          <ThemeProvider initialTheme="default">
64
+            <MinimalDocumentTable dataSource={sampleData.slice(0, 3)} />
65
+          </ThemeProvider>
66
+        </Card>
67
+
68
+        {/* Minimal 主题 */}
69
+        <Card title="简洁主题(只有横线)- 图二风格">
70
+          <ThemeProvider initialTheme="minimal">
71
+            <MinimalDocumentTable dataSource={sampleData.slice(0, 3)} />
72
+          </ThemeProvider>
73
+        </Card>
74
+
75
+        {/* Compact 主题 */}
76
+        <Card title="紧凑主题">
77
+          <ThemeProvider initialTheme="compact">
78
+            <MinimalDocumentTable dataSource={sampleData.slice(0, 3)} />
79
+          </ThemeProvider>
80
+        </Card>
81
+      </Space>
82
+    </div>
83
+  );
84
+};
85
+
86
+/**
87
+ * 自定义数据示例
88
+ */
89
+export const CustomDataExample: React.FC = () => {
90
+  // 自定义数据
91
+  const customData = [
92
+    {
93
+      key: '1',
94
+      category: '设计单位',
95
+      content1: '东河采油气管理区(东河储气库分公司)油气藏地质研究所',
96
+      content2: '东河采油气管理区(东河储气库分公司)油气藏地质研究所',
97
+      content3: '东河采油气管理区(东河储气库分公司)油气藏地质研究所',
98
+    },
99
+    {
100
+      key: '2',
101
+      category: '审核意见',
102
+      content1: '说明:审核人要明确确表达"同意或不同意",不能只签名不签署意见;同时,如果对设计内容之外有相关要求,可以在这里强调一下。',
103
+      content2: '说明:审核人要明确确表达"同意或不同意",不能只签名不签署意见;同时,如果对设计内容之外有相关要求,可以在这里强调一下。',
104
+      content3: '说明:审核人要明确确表达"同意或不同意",不能只签名不签署意见;同时,如果对设计内容之外有相关要求,可以在这里强调一下。',
105
+    },
106
+    {
107
+      key: '3',
108
+      category: '审核人',
109
+      content1: '',
110
+      content2: '审核时间',
111
+      content3: '',
112
+    },
113
+  ];
114
+
115
+  return (
116
+    <ThemeProvider initialTheme="minimal">
117
+      <div style={{ padding: 24 }}>
118
+        <Card>
119
+          <Space direction="vertical" style={{ width: '100%' }}>
120
+            <Title level={3}>自定义数据示例</Title>
121
+            <Text type="secondary">你可以根据实际需求定制数据结构</Text>
122
+            <Divider />
123
+            <MinimalDocumentTable dataSource={customData} />
124
+          </Space>
125
+        </Card>
126
+      </div>
127
+    </ThemeProvider>
128
+  );
129
+};
130
+
131
+/**
132
+ * 完整页面示例
133
+ */
134
+export const FullPageMinimalTableExample: React.FC = () => {
135
+  const sampleData = generateSampleData();
136
+
137
+  return (
138
+    <ThemeProvider initialTheme="minimal">
139
+      <div style={{ minHeight: '100vh', backgroundColor: '#ffffff' }}>
140
+        {/* 页面头部 */}
141
+        <div
142
+          style={{
143
+            padding: '16px 24px',
144
+            backgroundColor: '#ffffff',
145
+            borderBottom: '1px solid #d9d9d9',
146
+            display: 'flex',
147
+            justifyContent: 'space-between',
148
+            alignItems: 'center',
149
+          }}
150
+        >
151
+          <div>
152
+            <Title level={2} style={{ margin: 0 }}>
153
+              文档审核表
154
+            </Title>
155
+            <Text type="secondary">油气藏地质研究所审批流程</Text>
156
+          </div>
157
+          <ThemeSwitcher compact />
158
+        </div>
159
+
160
+        {/* 主内容区 */}
161
+        <div style={{ padding: '24px' }}>
162
+          <MinimalDocumentTable dataSource={sampleData} />
163
+        </div>
164
+
165
+        {/* 页脚 */}
166
+        <div
167
+          style={{
168
+            padding: '16px 24px',
169
+            textAlign: 'center',
170
+            borderTop: '1px solid #d9d9d9',
171
+            color: '#8c8c8c',
172
+            fontSize: 13,
173
+          }}
174
+        >
175
+          © 2024 东河采油气管理区 | 文档管理系统
176
+        </div>
177
+      </div>
178
+    </ThemeProvider>
179
+  );
180
+};
181
+
182
+/**
183
+ * 默认导出完整示例
184
+ */
185
+const MinimalTableExampleApp: React.FC = () => {
186
+  return <FullPageMinimalTableExample />;
187
+};
188
+
189
+export default MinimalTableExampleApp;

+ 247 - 0
src/examples/TestMinimalStyle.tsx

@@ -0,0 +1,247 @@
1
+/**
2
+ * Test Minimal Style
3
+ * 测试简洁风格(图二)是否生效
4
+ */
5
+
6
+import React from 'react';
7
+import { Card, Typography, Space, Divider } from 'antd';
8
+import { ThemeProvider } from '../theme';
9
+import { ThemeSwitcher } from '../components/ThemeSwitcher';
10
+
11
+const { Title, Paragraph, Text } = Typography;
12
+
13
+/**
14
+ * 测试页面 - 验证简洁风格
15
+ */
16
+export const TestMinimalStyle: React.FC = () => {
17
+  // 模拟数据
18
+  const testData = [
19
+    {
20
+      id: 'doc-001',
21
+      sessionId: 'sess-001-xxx',
22
+      createdAt: Date.now(),
23
+      updatedAt: Date.now(),
24
+    },
25
+    {
26
+      id: 'doc-002',
27
+      sessionId: 'sess-002-xxx',
28
+      createdAt: Date.now(),
29
+      updatedAt: Date.now(),
30
+    },
31
+    {
32
+      id: 'doc-003',
33
+      sessionId: 'sess-003-xxx',
34
+      createdAt: Date.now(),
35
+      updatedAt: Date.now(),
36
+    },
37
+  ];
38
+
39
+  return (
40
+    <div style={{ padding: 24, backgroundColor: '#f5f5f5', minHeight: '100vh' }}>
41
+      <Card>
42
+        <Space direction="vertical" style={{ width: '100%' }} size="large">
43
+          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
44
+            <Title level={2}>简洁表格样式测试</Title>
45
+            <ThemeSwitcher compact />
46
+          </div>
47
+
48
+          <Divider />
49
+
50
+          <Paragraph>
51
+            <Text strong>测试说明:</Text>
52
+          </Paragraph>
53
+          <ul>
54
+            <li>切换到 <Text code>minimal</Text> 主题,表格应该只有横线,无竖线</li>
55
+            <li>切换到 <Text code>default</Text> 主题,表格应该有网格线</li>
56
+            <li>如果样式没有生效,请刷新页面或重启开发服务器</li>
57
+          </ul>
58
+
59
+          <Divider />
60
+
61
+          {/* 使用原生 table 来演示效果 */}
62
+          <div>
63
+            <Title level={4}>原生 HTML 表格(参考效果)</Title>
64
+            <table style={{
65
+              width: '100%',
66
+              borderCollapse: 'collapse',
67
+              borderTop: '1px solid #d9d9d9',
68
+              borderBottom: '1px solid #d9d9d9',
69
+            }}>
70
+              <thead>
71
+                <tr>
72
+                  <th style={{
73
+                    padding: '12px 16px',
74
+                    textAlign: 'left',
75
+                    backgroundColor: '#ffffff',
76
+                    borderBottom: '2px solid #d9d9d9',
77
+                    borderRight: 'none',
78
+                    fontWeight: 600,
79
+                  }}>设计单位</th>
80
+                  <th style={{
81
+                    padding: '12px 16px',
82
+                    textAlign: 'left',
83
+                    backgroundColor: '#ffffff',
84
+                    borderBottom: '2px solid #d9d9d9',
85
+                    borderRight: 'none',
86
+                    fontWeight: 600,
87
+                  }}>内容1</th>
88
+                  <th style={{
89
+                    padding: '12px 16px',
90
+                    textAlign: 'left',
91
+                    backgroundColor: '#ffffff',
92
+                    borderBottom: '2px solid #d9d9d9',
93
+                    borderRight: 'none',
94
+                    fontWeight: 600,
95
+                  }}>内容2</th>
96
+                  <th style={{
97
+                    padding: '12px 16px',
98
+                    textAlign: 'left',
99
+                    backgroundColor: '#ffffff',
100
+                    borderBottom: '2px solid #d9d9d9',
101
+                    borderRight: 'none',
102
+                    fontWeight: 600,
103
+                  }}>内容3</th>
104
+                </tr>
105
+              </thead>
106
+              <tbody>
107
+                <tr>
108
+                  <td style={{
109
+                    padding: '12px 16px',
110
+                    borderBottom: '1px solid #d9d9d9',
111
+                    borderRight: 'none',
112
+                  }}>设计单位</td>
113
+                  <td style={{
114
+                    padding: '12px 16px',
115
+                    borderBottom: '1px solid #d9d9d9',
116
+                    borderRight: 'none',
117
+                  }}>东河采油气管理区(东河储气库分公司)油气藏地质研究所</td>
118
+                  <td style={{
119
+                    padding: '12px 16px',
120
+                    borderBottom: '1px solid #d9d9d9',
121
+                    borderRight: 'none',
122
+                  }}>东河采油气管理区(东河储气库分公司)油气藏地质研究所</td>
123
+                  <td style={{
124
+                    padding: '12px 16px',
125
+                    borderBottom: '1px solid #d9d9d9',
126
+                    borderRight: 'none',
127
+                  }}>东河采油气管理区(东河储气库分公司)油气藏地质研究所</td>
128
+                </tr>
129
+                <tr>
130
+                  <td style={{
131
+                    padding: '12px 16px',
132
+                    borderBottom: '1px solid #d9d9d9',
133
+                    borderRight: 'none',
134
+                  }}>审核意见</td>
135
+                  <td style={{
136
+                    padding: '12px 16px',
137
+                    borderBottom: '1px solid #d9d9d9',
138
+                    borderRight: 'none',
139
+                  }}>说明:审核人要明确确表达"同意或不同意",不能只签名不签署意见...</td>
140
+                  <td style={{
141
+                    padding: '12px 16px',
142
+                    borderBottom: '1px solid #d9d9d9',
143
+                    borderRight: 'none',
144
+                  }}>说明:审核人要明确确表达"同意或不同意",不能只签名不签署意见...</td>
145
+                  <td style={{
146
+                    padding: '12px 16px',
147
+                    borderBottom: '1px solid #d9d9d9',
148
+                    borderRight: 'none',
149
+                  }}>说明:审核人要明确确表达"同意或不同意",不能只签名不签署意见...</td>
150
+                </tr>
151
+                <tr>
152
+                  <td style={{
153
+                    padding: '12px 16px',
154
+                    borderBottom: '1px solid #d9d9d9',
155
+                    borderRight: 'none',
156
+                  }}>审核人</td>
157
+                  <td style={{
158
+                    padding: '12px 16px',
159
+                    borderBottom: '1px solid #d9d9d9',
160
+                    borderRight: 'none',
161
+                  }}></td>
162
+                  <td style={{
163
+                    padding: '12px 16px',
164
+                    borderBottom: '1px solid #d9d9d9',
165
+                    borderRight: 'none',
166
+                  }}>审核时间</td>
167
+                  <td style={{
168
+                    padding: '12px 16px',
169
+                    borderBottom: '1px solid #d9d9d9',
170
+                    borderRight: 'none',
171
+                  }}></td>
172
+                </tr>
173
+              </tbody>
174
+            </table>
175
+            <Text type="secondary" style={{ marginTop: 8, display: 'block' }}>
176
+              ☝️ 这是期望的效果:只有横线,没有竖线
177
+            </Text>
178
+          </div>
179
+
180
+          <Divider />
181
+
182
+          <div>
183
+            <Title level={4}>检查清单</Title>
184
+            <ol>
185
+              <li>
186
+                <Text strong>CSS 是否加载?</Text>
187
+                <Paragraph type="secondary">
188
+                  打开浏览器开发者工具 (F12) → Sources → 搜索 <Text code>DocumentManagement.css</Text>
189
+                </Paragraph>
190
+              </li>
191
+              <li>
192
+                <Text strong>CSS 变量是否生效?</Text>
193
+                <Paragraph type="secondary">
194
+                  开发者工具 → Console → 运行:
195
+                  <br />
196
+                  <Text code>getComputedStyle(document.documentElement).getPropertyValue('--table-border-color')</Text>
197
+                </Paragraph>
198
+              </li>
199
+              <li>
200
+                <Text strong>类名是否正确?</Text>
201
+                <Paragraph type="secondary">
202
+                  开发者工具 → Elements → 检查表格容器是否有 <Text code>document-management-table</Text> 类名
203
+                </Paragraph>
204
+              </li>
205
+              <li>
206
+                <Text strong>主题是否设置?</Text>
207
+                <Paragraph type="secondary">
208
+                  使用 ThemeSwitcher 切换到 <Text code>minimal</Text> 主题
209
+                </Paragraph>
210
+              </li>
211
+            </ol>
212
+          </div>
213
+
214
+          <Divider />
215
+
216
+          <div style={{
217
+            padding: 16,
218
+            backgroundColor: '#fff7e6',
219
+            border: '1px solid #ffd666',
220
+            borderRadius: 4,
221
+          }}>
222
+            <Text strong style={{ color: '#d46b08' }}>💡 重要提示:</Text>
223
+            <Paragraph style={{ marginTop: 8, marginBottom: 0 }}>
224
+              如果样式没有生效,请执行以下操作:<br />
225
+              1. <Text code>Ctrl + C</Text> 停止开发服务器<br />
226
+              2. <Text code>npm run dev</Text> 重新启动<br />
227
+              3. <Text code>Ctrl + Shift + R</Text> 强制刷新浏览器(清除缓存)
228
+            </Paragraph>
229
+          </div>
230
+        </Space>
231
+      </Card>
232
+    </div>
233
+  );
234
+};
235
+
236
+/**
237
+ * 在应用中使用的包装器
238
+ */
239
+export const TestMinimalStyleApp: React.FC = () => {
240
+  return (
241
+    <ThemeProvider initialTheme="minimal">
242
+      <TestMinimalStyle />
243
+    </ThemeProvider>
244
+  );
245
+};
246
+
247
+export default TestMinimalStyleApp;

+ 215 - 0
src/examples/ThemeExample.tsx

@@ -0,0 +1,215 @@
1
+/**
2
+ * Theme System Usage Example
3
+ * 主题系统使用示例
4
+ * 
5
+ * 展示如何在应用中集成和使用主题系统
6
+ */
7
+
8
+import React from 'react';
9
+import { Card, Space, Divider, Typography, Row, Col } from 'antd';
10
+import { ThemeProvider } from '../theme';
11
+import { ThemeSwitcher } from '../components/ThemeSwitcher';
12
+import { DocumentManagement } from '../components/DocumentManagement';
13
+
14
+const { Title, Paragraph, Text } = Typography;
15
+
16
+/**
17
+ * 示例:基本用法
18
+ */
19
+export const BasicThemeExample: React.FC = () => {
20
+  return (
21
+    <ThemeProvider initialTheme="default">
22
+      <Space direction="vertical" style={{ width: '100%', padding: 24 }} size="large">
23
+        <Card>
24
+          <Space direction="vertical" size="middle">
25
+            <Title level={3}>主题系统示例</Title>
26
+            <Paragraph>
27
+              使用 <Text code>ThemeProvider</Text> 包裹应用,即可启用主题系统。
28
+            </Paragraph>
29
+            <ThemeSwitcher showDescription />
30
+          </Space>
31
+        </Card>
32
+
33
+        <Card title="文档管理表格">
34
+          <DocumentManagement userId="demo-user" />
35
+        </Card>
36
+      </Space>
37
+    </ThemeProvider>
38
+  );
39
+};
40
+
41
+/**
42
+ * 示例:紧凑主题切换器
43
+ */
44
+export const CompactSwitcherExample: React.FC = () => {
45
+  return (
46
+    <ThemeProvider>
47
+      <Card
48
+        title="文档管理"
49
+        extra={<ThemeSwitcher compact />}
50
+      >
51
+        <DocumentManagement userId="demo-user" pageSize={10} />
52
+      </Card>
53
+    </ThemeProvider>
54
+  );
55
+};
56
+
57
+/**
58
+ * 示例:多主题对比
59
+ */
60
+export const ThemeComparisonExample: React.FC = () => {
61
+  const themes: Array<{ key: string; name: string; type: 'default' | 'dark' | 'compact' | 'comfortable' }> = [
62
+    { key: 'default', name: '默认主题', type: 'default' },
63
+    { key: 'dark', name: '暗色主题', type: 'dark' },
64
+    { key: 'compact', name: '紧凑主题', type: 'compact' },
65
+    { key: 'comfortable', name: '宽松主题', type: 'comfortable' },
66
+  ];
67
+
68
+  return (
69
+    <Space direction="vertical" style={{ width: '100%', padding: 24 }} size="large">
70
+      <Title level={2}>主题对比</Title>
71
+      <Paragraph>
72
+        以下展示了所有可用主题的效果对比。
73
+      </Paragraph>
74
+
75
+      <Row gutter={[16, 16]}>
76
+        {themes.map((theme) => (
77
+          <Col span={12} key={theme.key}>
78
+            <ThemeProvider initialTheme={theme.type}>
79
+              <Card title={theme.name}>
80
+                <div style={{ height: 400, overflow: 'auto' }}>
81
+                  <DocumentManagement 
82
+                    userId="demo-user" 
83
+                    pageSize={5} 
84
+                    showSessionFilter={false}
85
+                  />
86
+                </div>
87
+              </Card>
88
+            </ThemeProvider>
89
+          </Col>
90
+        ))}
91
+      </Row>
92
+    </Space>
93
+  );
94
+};
95
+
96
+/**
97
+ * 示例:自定义样式与主题集成
98
+ */
99
+export const CustomStyledExample: React.FC = () => {
100
+  return (
101
+    <ThemeProvider>
102
+      <div style={{ padding: 24 }}>
103
+        <Card>
104
+          <Space direction="vertical" style={{ width: '100%' }}>
105
+            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
106
+              <Title level={3}>自定义样式示例</Title>
107
+              <ThemeSwitcher compact />
108
+            </div>
109
+
110
+            <Divider />
111
+
112
+            {/* 使用 CSS 变量的自定义样式 */}
113
+            <div
114
+              style={{
115
+                backgroundColor: 'var(--table-row-bg)',
116
+                border: 'var(--table-border-width) solid var(--table-border-color)',
117
+                padding: 'var(--table-cell-padding-y) var(--table-cell-padding-x)',
118
+                borderRadius: 'var(--table-border-radius)',
119
+                color: 'var(--table-cell-text)',
120
+              }}
121
+            >
122
+              <Text>这个区块使用了主题的 CSS 变量</Text>
123
+            </div>
124
+
125
+            <Divider />
126
+
127
+            <DocumentManagement userId="demo-user" pageSize={8} />
128
+          </Space>
129
+        </Card>
130
+      </div>
131
+    </ThemeProvider>
132
+  );
133
+};
134
+
135
+/**
136
+ * 完整示例应用
137
+ */
138
+const ThemeExampleApp: React.FC = () => {
139
+  return (
140
+    <ThemeProvider>
141
+      <div style={{ minHeight: '100vh', backgroundColor: '#f0f2f5', padding: 24 }}>
142
+        <Space direction="vertical" style={{ width: '100%' }} size="large">
143
+          {/* 顶部栏 */}
144
+          <Card>
145
+            <Row justify="space-between" align="middle">
146
+              <Col>
147
+                <Title level={2} style={{ margin: 0 }}>文档管理系统</Title>
148
+              </Col>
149
+              <Col>
150
+                <Space>
151
+                  <Text>主题:</Text>
152
+                  <ThemeSwitcher compact />
153
+                </Space>
154
+              </Col>
155
+            </Row>
156
+          </Card>
157
+
158
+          {/* 主内容 */}
159
+          <Card>
160
+            <DocumentManagement 
161
+              userId="demo-user" 
162
+              showSessionFilter 
163
+              pageSize={20}
164
+            />
165
+          </Card>
166
+
167
+          {/* 统计卡片 */}
168
+          <Row gutter={16}>
169
+            <Col span={8}>
170
+              <Card
171
+                style={{
172
+                  backgroundColor: 'var(--table-header-bg)',
173
+                  borderColor: 'var(--table-border-color)',
174
+                }}
175
+              >
176
+                <Title level={4}>总文档数</Title>
177
+                <Title level={2} style={{ color: 'var(--table-action-primary)' }}>
178
+                  1,234
179
+                </Title>
180
+              </Card>
181
+            </Col>
182
+            <Col span={8}>
183
+              <Card
184
+                style={{
185
+                  backgroundColor: 'var(--table-header-bg)',
186
+                  borderColor: 'var(--table-border-color)',
187
+                }}
188
+              >
189
+                <Title level={4}>今日新增</Title>
190
+                <Title level={2} style={{ color: 'var(--table-action-primary)' }}>
191
+                  42
192
+                </Title>
193
+              </Card>
194
+            </Col>
195
+            <Col span={8}>
196
+              <Card
197
+                style={{
198
+                  backgroundColor: 'var(--table-header-bg)',
199
+                  borderColor: 'var(--table-border-color)',
200
+                }}
201
+              >
202
+                <Title level={4}>活跃会话</Title>
203
+                <Title level={2} style={{ color: 'var(--table-action-primary)' }}>
204
+                  89
205
+                </Title>
206
+              </Card>
207
+            </Col>
208
+          </Row>
209
+        </Space>
210
+      </div>
211
+    </ThemeProvider>
212
+  );
213
+};
214
+
215
+export default ThemeExampleApp;

+ 161 - 0
src/theme/ThemeContext.tsx

@@ -0,0 +1,161 @@
1
+/**
2
+ * Theme Context and Provider
3
+ * 主题上下文和提供器 - 提供全局主题管理和切换功能
4
+ */
5
+
6
+import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
7
+import type { TableTheme } from './types';
8
+import { tableThemes, type TableThemeType } from './tableTheme';
9
+
10
+/**
11
+ * 主题上下文类型
12
+ */
13
+interface ThemeContextType {
14
+  /** 当前表格主题 */
15
+  tableTheme: TableTheme;
16
+  /** 当前主题类型 */
17
+  currentThemeType: TableThemeType;
18
+  /** 切换主题 */
19
+  setTheme: (themeType: TableThemeType) => void;
20
+  /** 所有可用主题类型 */
21
+  availableThemes: TableThemeType[];
22
+}
23
+
24
+/**
25
+ * 主题上下文
26
+ */
27
+const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
28
+
29
+/**
30
+ * 本地存储键名
31
+ */
32
+const THEME_STORAGE_KEY = 'app-table-theme';
33
+
34
+/**
35
+ * 从本地存储加载主题
36
+ */
37
+const loadThemeFromStorage = (): TableThemeType => {
38
+  try {
39
+    const stored = localStorage.getItem(THEME_STORAGE_KEY);
40
+    if (stored && stored in tableThemes) {
41
+      return stored as TableThemeType;
42
+    }
43
+  } catch (error) {
44
+    console.warn('Failed to load theme from localStorage:', error);
45
+  }
46
+  return 'default';
47
+};
48
+
49
+/**
50
+ * 保存主题到本地存储
51
+ */
52
+const saveThemeToStorage = (themeType: TableThemeType) => {
53
+  try {
54
+    localStorage.setItem(THEME_STORAGE_KEY, themeType);
55
+  } catch (error) {
56
+    console.warn('Failed to save theme to localStorage:', error);
57
+  }
58
+};
59
+
60
+/**
61
+ * 主题提供器属性
62
+ */
63
+interface ThemeProviderProps {
64
+  children: React.ReactNode;
65
+  /** 初始主题类型(可选,默认从本地存储读取或使用 'default') */
66
+  initialTheme?: TableThemeType;
67
+}
68
+
69
+/**
70
+ * 主题提供器组件
71
+ */
72
+export const ThemeProvider: React.FC<ThemeProviderProps> = ({
73
+  children,
74
+  initialTheme,
75
+}) => {
76
+  const [currentThemeType, setCurrentThemeType] = useState<TableThemeType>(
77
+    initialTheme || loadThemeFromStorage()
78
+  );
79
+
80
+  const tableTheme = tableThemes[currentThemeType];
81
+
82
+  const setTheme = useCallback((themeType: TableThemeType) => {
83
+    setCurrentThemeType(themeType);
84
+    saveThemeToStorage(themeType);
85
+  }, []);
86
+
87
+  const availableThemes = Object.keys(tableThemes) as TableThemeType[];
88
+
89
+  // 应用 CSS 变量到 document root
90
+  useEffect(() => {
91
+    const root = document.documentElement;
92
+    const theme = tableTheme;
93
+
94
+    // 颜色变量
95
+    root.style.setProperty('--table-border-color', theme.colors.border);
96
+    root.style.setProperty('--table-header-bg', theme.colors.headerBg);
97
+    root.style.setProperty('--table-header-text', theme.colors.headerText);
98
+    root.style.setProperty('--table-row-bg', theme.colors.rowBg);
99
+    root.style.setProperty('--table-row-bg-alt', theme.colors.rowBgAlt);
100
+    root.style.setProperty('--table-row-hover', theme.colors.rowHover);
101
+    root.style.setProperty('--table-row-selected', theme.colors.rowSelected);
102
+    root.style.setProperty('--table-cell-text', theme.colors.cellText);
103
+    root.style.setProperty('--table-text-secondary', theme.colors.textSecondary);
104
+    root.style.setProperty('--table-action-primary', theme.colors.actionPrimary);
105
+    root.style.setProperty('--table-action-danger', theme.colors.actionDanger);
106
+
107
+    // 间距变量
108
+    root.style.setProperty('--table-cell-padding-y', theme.spacing.cellPaddingY);
109
+    root.style.setProperty('--table-cell-padding-x', theme.spacing.cellPaddingX);
110
+    root.style.setProperty('--table-margin', theme.spacing.tableMargin);
111
+    root.style.setProperty('--table-border-width', theme.spacing.borderWidth);
112
+    root.style.setProperty('--table-action-spacing', theme.spacing.actionSpacing);
113
+
114
+    // 字体变量
115
+    root.style.setProperty('--table-header-font-size', theme.typography.headerFontSize);
116
+    root.style.setProperty('--table-header-font-weight', String(theme.typography.headerFontWeight));
117
+    root.style.setProperty('--table-body-font-size', theme.typography.bodyFontSize);
118
+    root.style.setProperty('--table-small-font-size', theme.typography.smallFontSize);
119
+    root.style.setProperty('--table-line-height', String(theme.typography.lineHeight));
120
+    root.style.setProperty('--table-font-family', theme.typography.fontFamily);
121
+
122
+    // 布局变量
123
+    root.style.setProperty('--table-min-row-height', theme.layout.minRowHeight);
124
+    root.style.setProperty('--table-header-height', theme.layout.headerHeight);
125
+    root.style.setProperty('--table-column-min-width', theme.layout.columnMinWidth);
126
+    root.style.setProperty('--table-border-radius', theme.layout.borderRadius);
127
+    root.style.setProperty('--table-box-shadow', theme.layout.boxShadow);
128
+
129
+    // 动画变量
130
+    root.style.setProperty('--table-hover-transition', theme.animation.hoverTransition);
131
+    root.style.setProperty('--table-loading-duration', theme.animation.loadingDuration);
132
+  }, [tableTheme]);
133
+
134
+  const value: ThemeContextType = {
135
+    tableTheme,
136
+    currentThemeType,
137
+    setTheme,
138
+    availableThemes,
139
+  };
140
+
141
+  return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
142
+};
143
+
144
+/**
145
+ * 使用主题的 Hook
146
+ */
147
+export const useTheme = (): ThemeContextType => {
148
+  const context = useContext(ThemeContext);
149
+  if (!context) {
150
+    throw new Error('useTheme must be used within a ThemeProvider');
151
+  }
152
+  return context;
153
+};
154
+
155
+/**
156
+ * 使用表格主题的 Hook(简化版)
157
+ */
158
+export const useTableTheme = (): TableTheme => {
159
+  const { tableTheme } = useTheme();
160
+  return tableTheme;
161
+};

+ 41 - 0
src/theme/index.ts

@@ -0,0 +1,41 @@
1
+/**
2
+ * Theme Module Entry Point
3
+ * 主题模块入口 - 导出所有主题相关内容
4
+ */
5
+
6
+// 类型定义
7
+export type {
8
+  TableColors,
9
+  TableSpacing,
10
+  TableTypography,
11
+  TableLayout,
12
+  TableAnimation,
13
+  TableTheme,
14
+  AppTheme,
15
+} from './types';
16
+
17
+// 设计令牌
18
+export {
19
+  colorTokens,
20
+  spacingTokens,
21
+  fontSizeTokens,
22
+  fontWeightTokens,
23
+  lineHeightTokens,
24
+  borderRadiusTokens,
25
+  shadowTokens,
26
+  transitionTokens,
27
+  borderWidthTokens,
28
+} from './tokens';
29
+
30
+// 表格主题
31
+export {
32
+  defaultTableTheme,
33
+  darkTableTheme,
34
+  compactTableTheme,
35
+  comfortableTableTheme,
36
+  tableThemes,
37
+  type TableThemeType,
38
+} from './tableTheme';
39
+
40
+// 主题上下文和 Hooks
41
+export { ThemeProvider, useTheme, useTableTheme } from './ThemeContext';

+ 218 - 0
src/theme/tableTheme.ts

@@ -0,0 +1,218 @@
1
+/**
2
+ * Table Theme Configuration
3
+ * 表格主题配置 - 基于设计令牌构建具体的表格样式
4
+ */
5
+
6
+import type { TableTheme } from './types';
7
+import {
8
+  colorTokens,
9
+  spacingTokens,
10
+  fontSizeTokens,
11
+  fontWeightTokens,
12
+  lineHeightTokens,
13
+  borderRadiusTokens,
14
+  shadowTokens,
15
+  transitionTokens,
16
+  borderWidthTokens,
17
+} from './tokens';
18
+
19
+/**
20
+ * 默认(亮色)表格主题
21
+ */
22
+export const defaultTableTheme: TableTheme = {
23
+  colors: {
24
+    border: colorTokens.neutral[200],
25
+    headerBg: colorTokens.neutral[50],
26
+    headerText: colorTokens.neutral[800],
27
+    rowBg: '#ffffff',
28
+    rowBgAlt: colorTokens.neutral[50],
29
+    rowHover: colorTokens.primary[50],
30
+    rowSelected: colorTokens.primary[100],
31
+    cellText: colorTokens.neutral[700],
32
+    textSecondary: colorTokens.neutral[500],
33
+    actionPrimary: colorTokens.primary[600],
34
+    actionDanger: colorTokens.danger[500],
35
+  },
36
+  spacing: {
37
+    cellPaddingY: spacingTokens.md,
38
+    cellPaddingX: spacingTokens.lg,
39
+    tableMargin: spacingTokens.lg,
40
+    borderWidth: borderWidthTokens.base,
41
+    actionSpacing: spacingTokens.sm,
42
+  },
43
+  typography: {
44
+    headerFontSize: fontSizeTokens.md,
45
+    headerFontWeight: fontWeightTokens.semibold,
46
+    bodyFontSize: fontSizeTokens.base,
47
+    smallFontSize: fontSizeTokens.sm,
48
+    lineHeight: lineHeightTokens.normal,
49
+    fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
50
+  },
51
+  layout: {
52
+    minRowHeight: '48px',
53
+    headerHeight: '54px',
54
+    columnMinWidth: '100px',
55
+    borderRadius: borderRadiusTokens.md,
56
+    boxShadow: shadowTokens.sm,
57
+  },
58
+  animation: {
59
+    hoverTransition: `background-color ${transitionTokens.fast} ease`,
60
+    loadingDuration: transitionTokens.slow,
61
+  },
62
+};
63
+
64
+/**
65
+ * 暗色表格主题
66
+ */
67
+export const darkTableTheme: TableTheme = {
68
+  colors: {
69
+    border: colorTokens.neutral[700],
70
+    headerBg: colorTokens.neutral[800],
71
+    headerText: colorTokens.neutral[100],
72
+    rowBg: colorTokens.neutral[900],
73
+    rowBgAlt: colorTokens.neutral[800],
74
+    rowHover: colorTokens.primary[900],
75
+    rowSelected: colorTokens.primary[800],
76
+    cellText: colorTokens.neutral[200],
77
+    textSecondary: colorTokens.neutral[400],
78
+    actionPrimary: colorTokens.primary[400],
79
+    actionDanger: colorTokens.danger[400],
80
+  },
81
+  spacing: {
82
+    cellPaddingY: spacingTokens.md,
83
+    cellPaddingX: spacingTokens.lg,
84
+    tableMargin: spacingTokens.lg,
85
+    borderWidth: borderWidthTokens.base,
86
+    actionSpacing: spacingTokens.sm,
87
+  },
88
+  typography: {
89
+    headerFontSize: fontSizeTokens.md,
90
+    headerFontWeight: fontWeightTokens.semibold,
91
+    bodyFontSize: fontSizeTokens.base,
92
+    smallFontSize: fontSizeTokens.sm,
93
+    lineHeight: lineHeightTokens.normal,
94
+    fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
95
+  },
96
+  layout: {
97
+    minRowHeight: '48px',
98
+    headerHeight: '54px',
99
+    columnMinWidth: '100px',
100
+    borderRadius: borderRadiusTokens.md,
101
+    boxShadow: shadowTokens.lg,
102
+  },
103
+  animation: {
104
+    hoverTransition: `background-color ${transitionTokens.fast} ease`,
105
+    loadingDuration: transitionTokens.slow,
106
+  },
107
+};
108
+
109
+/**
110
+ * 紧凑表格主题(更小的间距和字体)
111
+ */
112
+export const compactTableTheme: TableTheme = {
113
+  ...defaultTableTheme,
114
+  spacing: {
115
+    cellPaddingY: spacingTokens.sm,
116
+    cellPaddingX: spacingTokens.md,
117
+    tableMargin: spacingTokens.md,
118
+    borderWidth: borderWidthTokens.base,
119
+    actionSpacing: spacingTokens.xs,
120
+  },
121
+  typography: {
122
+    ...defaultTableTheme.typography,
123
+    headerFontSize: fontSizeTokens.sm,
124
+    bodyFontSize: fontSizeTokens.sm,
125
+    smallFontSize: fontSizeTokens.xs,
126
+  },
127
+  layout: {
128
+    ...defaultTableTheme.layout,
129
+    minRowHeight: '36px',
130
+    headerHeight: '40px',
131
+  },
132
+};
133
+
134
+/**
135
+ * 宽松表格主题(更大的间距和字体)
136
+ */
137
+export const comfortableTableTheme: TableTheme = {
138
+  ...defaultTableTheme,
139
+  spacing: {
140
+    cellPaddingY: spacingTokens.lg,
141
+    cellPaddingX: spacingTokens.xl,
142
+    tableMargin: spacingTokens.xl,
143
+    borderWidth: borderWidthTokens.base,
144
+    actionSpacing: spacingTokens.md,
145
+  },
146
+  typography: {
147
+    ...defaultTableTheme.typography,
148
+    headerFontSize: fontSizeTokens.lg,
149
+    bodyFontSize: fontSizeTokens.md,
150
+    smallFontSize: fontSizeTokens.base,
151
+  },
152
+  layout: {
153
+    ...defaultTableTheme.layout,
154
+    minRowHeight: '56px',
155
+    headerHeight: '64px',
156
+  },
157
+};
158
+
159
+/**
160
+ * 简洁表格主题
161
+ */
162
+export const minimalTableTheme: TableTheme = {
163
+  colors: {
164
+    border: colorTokens.neutral[300],
165
+    headerBg: '#ffffff',
166
+    headerText: colorTokens.neutral[900],
167
+    rowBg: '#ffffff',
168
+    rowBgAlt: '#ffffff',
169
+    rowHover: colorTokens.neutral[50],
170
+    rowSelected: colorTokens.primary[50],
171
+    cellText: colorTokens.neutral[800],
172
+    textSecondary: colorTokens.neutral[600],
173
+    actionPrimary: colorTokens.primary[600],
174
+    actionDanger: colorTokens.danger[500],
175
+  },
176
+  spacing: {
177
+    cellPaddingY: spacingTokens.md,
178
+    cellPaddingX: spacingTokens.lg,
179
+    tableMargin: '0px',
180
+    borderWidth: borderWidthTokens.base,
181
+    actionSpacing: spacingTokens.sm,
182
+  },
183
+  typography: {
184
+    headerFontSize: fontSizeTokens.base,
185
+    headerFontWeight: fontWeightTokens.semibold,
186
+    bodyFontSize: fontSizeTokens.base,
187
+    smallFontSize: fontSizeTokens.sm,
188
+    lineHeight: lineHeightTokens.relaxed,
189
+    fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Microsoft YaHei", sans-serif',
190
+  },
191
+  layout: {
192
+    minRowHeight: 'auto',
193
+    headerHeight: 'auto',
194
+    columnMinWidth: '120px',
195
+    borderRadius: '0px',
196
+    boxShadow: 'none',
197
+  },
198
+  animation: {
199
+    hoverTransition: `background-color ${transitionTokens.fast} ease`,
200
+    loadingDuration: transitionTokens.slow,
201
+  },
202
+};
203
+
204
+/**
205
+ * 所有可用的表格主题
206
+ */
207
+export const tableThemes = {
208
+  default: defaultTableTheme,
209
+  dark: darkTableTheme,
210
+  compact: compactTableTheme,
211
+  comfortable: comfortableTableTheme,
212
+  minimal: minimalTableTheme,
213
+};
214
+
215
+/**
216
+ * 表格主题类型
217
+ */
218
+export type TableThemeType = keyof typeof tableThemes;

+ 147 - 0
src/theme/tokens.ts

@@ -0,0 +1,147 @@
1
+/**
2
+ * Design Tokens
3
+ * 基础设计令牌 - 可在多个主题间共享的基础值
4
+ */
5
+
6
+/**
7
+ * 颜色令牌
8
+ */
9
+export const colorTokens = {
10
+  // 中性色
11
+  neutral: {
12
+    50: '#fafafa',
13
+    100: '#f5f5f5',
14
+    200: '#e5e5e5',
15
+    300: '#d4d4d4',
16
+    400: '#a3a3a3',
17
+    500: '#737373',
18
+    600: '#525252',
19
+    700: '#404040',
20
+    800: '#262626',
21
+    900: '#171717',
22
+  },
23
+  // 主色
24
+  primary: {
25
+    50: '#eff6ff',
26
+    100: '#dbeafe',
27
+    200: '#bfdbfe',
28
+    300: '#93c5fd',
29
+    400: '#60a5fa',
30
+    500: '#3b82f6',
31
+    600: '#2563eb',
32
+    700: '#1d4ed8',
33
+    800: '#1e40af',
34
+    900: '#1e3a8a',
35
+  },
36
+  // 成功色
37
+  success: {
38
+    50: '#f0fdf4',
39
+    500: '#22c55e',
40
+    600: '#16a34a',
41
+  },
42
+  // 警告色
43
+  warning: {
44
+    50: '#fffbeb',
45
+    500: '#f59e0b',
46
+    600: '#d97706',
47
+  },
48
+  // 危险色
49
+  danger: {
50
+    50: '#fef2f2',
51
+    500: '#ef4444',
52
+    600: '#dc2626',
53
+  },
54
+};
55
+
56
+/**
57
+ * 间距令牌(基于 4px 网格)
58
+ */
59
+export const spacingTokens = {
60
+  xs: '4px',
61
+  sm: '8px',
62
+  md: '12px',
63
+  lg: '16px',
64
+  xl: '20px',
65
+  '2xl': '24px',
66
+  '3xl': '32px',
67
+  '4xl': '40px',
68
+};
69
+
70
+/**
71
+ * 字体大小令牌
72
+ */
73
+export const fontSizeTokens = {
74
+  xs: '11px',
75
+  sm: '12px',
76
+  base: '13px',
77
+  md: '14px',
78
+  lg: '16px',
79
+  xl: '18px',
80
+  '2xl': '20px',
81
+  '3xl': '24px',
82
+};
83
+
84
+/**
85
+ * 字重令牌
86
+ */
87
+export const fontWeightTokens = {
88
+  normal: 400,
89
+  medium: 500,
90
+  semibold: 600,
91
+  bold: 700,
92
+};
93
+
94
+/**
95
+ * 行高令牌
96
+ */
97
+export const lineHeightTokens = {
98
+  tight: 1.2,
99
+  normal: 1.5,
100
+  relaxed: 1.75,
101
+  loose: 2,
102
+};
103
+
104
+/**
105
+ * 圆角令牌
106
+ */
107
+export const borderRadiusTokens = {
108
+  none: '0',
109
+  sm: '2px',
110
+  base: '4px',
111
+  md: '6px',
112
+  lg: '8px',
113
+  xl: '12px',
114
+  full: '9999px',
115
+};
116
+
117
+/**
118
+ * 阴影令牌
119
+ */
120
+export const shadowTokens = {
121
+  none: 'none',
122
+  sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
123
+  base: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
124
+  md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
125
+  lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
126
+  xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
127
+};
128
+
129
+/**
130
+ * 过渡时长令牌
131
+ */
132
+export const transitionTokens = {
133
+  fast: '150ms',
134
+  base: '200ms',
135
+  slow: '300ms',
136
+  slower: '500ms',
137
+};
138
+
139
+/**
140
+ * 边框宽度令牌
141
+ */
142
+export const borderWidthTokens = {
143
+  none: '0',
144
+  thin: '1px',
145
+  base: '1px',
146
+  thick: '2px',
147
+};

+ 121 - 0
src/theme/types.ts

@@ -0,0 +1,121 @@
1
+/**
2
+ * Theme type definitions
3
+ * 定义主题系统的类型结构
4
+ */
5
+
6
+/**
7
+ * 表格颜色配置
8
+ */
9
+export interface TableColors {
10
+  /** 边框颜色 */
11
+  border: string;
12
+  /** 表头背景色 */
13
+  headerBg: string;
14
+  /** 表头文字颜色 */
15
+  headerText: string;
16
+  /** 行背景色 */
17
+  rowBg: string;
18
+  /** 交替行背景色(斑马纹) */
19
+  rowBgAlt: string;
20
+  /** 悬停行背景色 */
21
+  rowHover: string;
22
+  /** 选中行背景色 */
23
+  rowSelected: string;
24
+  /** 单元格文字颜色 */
25
+  cellText: string;
26
+  /** 次要文字颜色 */
27
+  textSecondary: string;
28
+  /** 操作按钮颜色 */
29
+  actionPrimary: string;
30
+  /** 危险操作颜色 */
31
+  actionDanger: string;
32
+}
33
+
34
+/**
35
+ * 表格间距配置
36
+ */
37
+export interface TableSpacing {
38
+  /** 单元格内边距(垂直) */
39
+  cellPaddingY: string;
40
+  /** 单元格内边距(水平) */
41
+  cellPaddingX: string;
42
+  /** 表格外边距 */
43
+  tableMargin: string;
44
+  /** 边框宽度 */
45
+  borderWidth: string;
46
+  /** 操作按钮间距 */
47
+  actionSpacing: string;
48
+}
49
+
50
+/**
51
+ * 表格字体配置
52
+ */
53
+export interface TableTypography {
54
+  /** 表头字号 */
55
+  headerFontSize: string;
56
+  /** 表头字重 */
57
+  headerFontWeight: string | number;
58
+  /** 内容字号 */
59
+  bodyFontSize: string;
60
+  /** 小字号(用于ID、标签等) */
61
+  smallFontSize: string;
62
+  /** 行高 */
63
+  lineHeight: string | number;
64
+  /** 字体族 */
65
+  fontFamily: string;
66
+}
67
+
68
+/**
69
+ * 表格布局配置
70
+ */
71
+export interface TableLayout {
72
+  /** 最小行高 */
73
+  minRowHeight: string;
74
+  /** 表头高度 */
75
+  headerHeight: string;
76
+  /** 列最小宽度 */
77
+  columnMinWidth: string;
78
+  /** 圆角 */
79
+  borderRadius: string;
80
+  /** 阴影 */
81
+  boxShadow: string;
82
+}
83
+
84
+/**
85
+ * 表格动画配置
86
+ */
87
+export interface TableAnimation {
88
+  /** 悬停过渡时间 */
89
+  hoverTransition: string;
90
+  /** 加载动画时长 */
91
+  loadingDuration: string;
92
+}
93
+
94
+/**
95
+ * 完整的表格主题配置
96
+ */
97
+export interface TableTheme {
98
+  /** 颜色系统 */
99
+  colors: TableColors;
100
+  /** 间距系统 */
101
+  spacing: TableSpacing;
102
+  /** 字体系统 */
103
+  typography: TableTypography;
104
+  /** 布局系统 */
105
+  layout: TableLayout;
106
+  /** 动画系统 */
107
+  animation: TableAnimation;
108
+}
109
+
110
+/**
111
+ * 应用主题配置(包含所有组件主题)
112
+ */
113
+export interface AppTheme {
114
+  /** 主题名称 */
115
+  name: string;
116
+  /** 表格主题 */
117
+  table: TableTheme;
118
+  // 未来可以扩展其他组件主题
119
+  // button?: ButtonTheme;
120
+  // form?: FormTheme;
121
+}