Просмотр исходного кода

✨ feat(home-icons): 实现图标文件选择功能

- 添加文件选择模态框,支持从已上传文件中选择图标
- 引入Image组件用于预览图标,添加UploadOutlined图标
- 集成fileClient API获取文件列表,支持图片文件筛选
- 实现文件选择功能,支持预览和选择已上传图片
- 优化文件ID输入框,改为只读并添加选择按钮
- 添加文件选择后的预览效果和状态提示
- 上传成功后自动刷新文件列表,提升用户体验
yourname 7 месяцев назад
Родитель
Сommit
d71804e1ba
1 измененных файлов с 157 добавлено и 9 удалено
  1. 157 9
      src/client/admin/pages/HomeIcons.tsx

+ 157 - 9
src/client/admin/pages/HomeIcons.tsx

@@ -1,8 +1,8 @@
 import React, { useState, useEffect } from 'react';
 import React, { useState, useEffect } from 'react';
-import { Table, Card, Tabs, Button, Space, Tag, Switch, Popconfirm, message, Modal, Form, Input, Select, Upload } from 'antd';
-import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined, LinkOutlined } from '@ant-design/icons';
+import { Table, Card, Tabs, Button, Space, Tag, Switch, Popconfirm, message, Modal, Form, Input, Select, Upload, Image } from 'antd';
+import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined, LinkOutlined, UploadOutlined } from '@ant-design/icons';
 import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
 import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
-import { homeIconClient } from '@/client/api';
+import { homeIconClient, fileClient } from '@/client/api';
 import type { HomeIcon } from '@/server/modules/home/home-icon.entity';
 import type { HomeIcon } from '@/server/modules/home/home-icon.entity';
 import type { File as FileType } from '@/server/modules/files/file.entity';
 import type { File as FileType } from '@/server/modules/files/file.entity';
 import type { InferResponseType, InferRequestType } from 'hono/client';
 import type { InferResponseType, InferRequestType } from 'hono/client';
@@ -157,10 +157,30 @@ const HomeIconsPage: React.FC = () => {
     }
     }
   };
   };
 
 
-  const handleUploadSuccess = (fileKey: string, fileUrl: string, file: FileType) => {
-    // 这里需要获取刚上传的文件ID
-    // 实际项目中,上传成功后应该返回文件ID
-    message.success('文件上传成功,请填写其他信息后提交');
+  const [fileModalVisible, setFileModalVisible] = useState(false);
+  
+  // 获取文件列表
+  const { data: filesData } = useQuery({
+    queryKey: ['files-for-selection'],
+    queryFn: async () => {
+      const response = await fileClient.$get({
+        query: { page: 1, pageSize: 50, keyword: 'image' }
+      });
+      if (response.status !== 200) throw new Error('获取文件列表失败');
+      return response.json();
+    }
+  });
+
+  const handleUploadSuccess = (fileKey: string, fileUrl: string, file: any) => {
+    message.success('文件上传成功!请在文件管理页面查看文件ID,然后选择文件');
+    // 刷新文件列表
+    queryClient.invalidateQueries({ queryKey: ['files-for-selection'] });
+  };
+
+  const handleSelectFile = (file: FileType) => {
+    form.setFieldsValue({ fileId: file.id });
+    setFileModalVisible(false);
+    message.success(`已选择文件: ${file.name}`);
   };
   };
 
 
   const columns = [
   const columns = [
@@ -324,9 +344,68 @@ const HomeIconsPage: React.FC = () => {
           <Form.Item
           <Form.Item
             name="fileId"
             name="fileId"
             label="图标文件"
             label="图标文件"
-            rules={[{ required: true, message: '请上传图标文件' }]}
+            rules={[{ required: true, message: '请选择图标文件' }]}
           >
           >
-            <Input type="number" placeholder="请输入文件ID" />
+            <div style={{ display: 'flex', gap: '8px' }}>
+              <Input
+                type="number"
+                placeholder="请选择或上传图标文件"
+                readOnly
+                style={{ flex: 1 }}
+              />
+              <Button
+                type="default"
+                icon={<EyeOutlined />}
+                onClick={() => setFileModalVisible(true)}
+              >
+                选择文件
+              </Button>
+            </div>
+          </Form.Item>
+
+          <Form.Item
+            noStyle
+            shouldUpdate={(prevValues, currentValues) => prevValues.fileId !== currentValues.fileId}
+          >
+            {({ getFieldValue }) => {
+              const fileId = getFieldValue('fileId');
+              const selectedFile = filesData?.data?.find((f: FileType) => f.id === fileId);
+              
+              return fileId && selectedFile ? (
+                <div style={{
+                  padding: '12px',
+                  backgroundColor: '#f6ffed',
+                  border: '1px solid #b7eb8f',
+                  borderRadius: '4px',
+                  marginBottom: '16px',
+                  display: 'flex',
+                  alignItems: 'center',
+                  gap: '12px'
+                }}>
+                  <Image
+                    src={selectedFile.path}
+                    alt={selectedFile.name}
+                    style={{ width: 60, height: 60, objectFit: 'cover', borderRadius: 4 }}
+                  />
+                  <div>
+                    <div style={{ fontWeight: 'bold' }}>{selectedFile.name}</div>
+                    <div style={{ color: '#666', fontSize: '12px' }}>ID: {selectedFile.id}</div>
+                  </div>
+                </div>
+              ) : (
+                <div style={{
+                  padding: '8px 12px',
+                  backgroundColor: '#fff7e6',
+                  border: '1px solid #ffd591',
+                  borderRadius: '4px',
+                  marginBottom: '16px'
+                }}>
+                  <span style={{ color: '#fa8c16', fontSize: '14px' }}>
+                    ⚠️ 请选择图标文件,支持上传新文件或从已有文件中选择
+                  </span>
+                </div>
+              );
+            }}
           </Form.Item>
           </Form.Item>
 
 
           <Form.Item
           <Form.Item
@@ -370,6 +449,75 @@ const HomeIconsPage: React.FC = () => {
           </Form.Item>
           </Form.Item>
         </Form>
         </Form>
       </Modal>
       </Modal>
+
+      {/* 文件选择模态框 */}
+      <Modal
+        title="选择图标文件"
+        open={fileModalVisible}
+        onCancel={() => setFileModalVisible(false)}
+        width={800}
+        footer={null}
+      >
+        <div style={{ marginBottom: 16 }}>
+          <Button
+            type="primary"
+            icon={<UploadOutlined />}
+            onClick={() => setFileModalVisible(false)}
+            style={{ marginRight: 8 }}
+          >
+            上传新文件
+          </Button>
+          <span style={{ color: '#666', fontSize: '12px' }}>
+            提示:先上传文件,然后从列表中选择
+          </span>
+        </div>
+
+        <div style={{ maxHeight: 400, overflowY: 'auto' }}>
+          {filesData?.data?.filter((f: FileType) => f.type?.startsWith('image/')).map((file: FileType) => (
+            <div
+              key={file.id}
+              style={{
+                display: 'flex',
+                alignItems: 'center',
+                padding: '12px',
+                border: '1px solid #f0f0f0',
+                borderRadius: '4px',
+                marginBottom: '8px',
+                cursor: 'pointer',
+                transition: 'all 0.3s'
+              }}
+              onClick={() => handleSelectFile(file)}
+              onMouseEnter={(e) => {
+                e.currentTarget.style.backgroundColor = '#f6ffed';
+                e.currentTarget.style.borderColor = '#b7eb8f';
+              }}
+              onMouseLeave={(e) => {
+                e.currentTarget.style.backgroundColor = '';
+                e.currentTarget.style.borderColor = '#f0f0f0';
+              }}
+            >
+              <Image
+                src={file.path}
+                alt={file.name}
+                style={{ width: 60, height: 60, objectFit: 'cover', borderRadius: 4, marginRight: 12 }}
+              />
+              <div style={{ flex: 1 }}>
+                <div style={{ fontWeight: 'bold', marginBottom: '4px' }}>{file.name}</div>
+                <div style={{ color: '#666', fontSize: '12px' }}>
+                  ID: {file.id} | 大小: {((file.size || 0) / 1024 / 1024).toFixed(2)}MB
+                </div>
+              </div>
+              <Button type="primary" size="small">选择</Button>
+            </div>
+          ))}
+        </div>
+
+        {(!filesData?.data || filesData.data.filter((f: FileType) => f.type?.startsWith('image/')).length === 0) && (
+          <div style={{ textAlign: 'center', padding: '40px', color: '#999' }}>
+            暂无图片文件,请先上传
+          </div>
+        )}
+      </Modal>
     </div>
     </div>
   );
   );
 };
 };