diff --git a/src/api/feedback.ts b/src/api/feedback.ts new file mode 100644 index 0000000..689089d --- /dev/null +++ b/src/api/feedback.ts @@ -0,0 +1,26 @@ +import request from './request'; +import type { ApiResponse, PaginatedResponse } from './request'; + +// 意见反馈类型 +export interface Feedback { + id: number; + user_phone: string; + user_nickname: string; + content: string; + contact: string; + created_at: string; +} + +// 获取反馈列表 +export const getFeedbacks = (params?: { + page?: number; + page_size?: number; + phone?: string; +}) => { + return request.get>>('/api/admin/feedbacks/', { params }); +}; + +// 获取反馈详情 +export const getFeedback = (id: number) => { + return request.get>(`/api/admin/feedbacks/${id}/`); +}; diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index 9207857..c67d8d2 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -17,6 +17,7 @@ import { MobileOutlined, UserOutlined, TeamOutlined, + MessageOutlined, LogoutOutlined, MenuFoldOutlined, MenuUnfoldOutlined, @@ -56,6 +57,11 @@ const menuItems = [ icon: , label: '管理员', }, + { + key: '/feedbacks', + icon: , + label: '意见反馈', + }, ]; const MainLayout: React.FC = () => { diff --git a/src/pages/Feedback/index.tsx b/src/pages/Feedback/index.tsx new file mode 100644 index 0000000..a42bd0b --- /dev/null +++ b/src/pages/Feedback/index.tsx @@ -0,0 +1,134 @@ +import React, { useRef, useState } from 'react'; +import { Button, message, Modal, Descriptions } from 'antd'; +import { ProTable } from '@ant-design/pro-components'; +import type { ProColumns, ActionType } from '@ant-design/pro-components'; +import { getFeedbacks } from '../../api/feedback'; +import type { Feedback } from '../../api/feedback'; + +const FeedbackPage: React.FC = () => { + const actionRef = useRef(null); + const [detailVisible, setDetailVisible] = useState(false); + const [currentRecord, setCurrentRecord] = useState(null); + + const handleView = (record: Feedback) => { + setCurrentRecord(record); + setDetailVisible(true); + }; + + const columns: ProColumns[] = [ + { + title: 'ID', + dataIndex: 'id', + width: 80, + search: false, + }, + { + title: '用户手机号', + dataIndex: 'user_phone', + width: 140, + render: (_, record) => { + const phone = record.user_phone; + return phone ? phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') : '-'; + }, + }, + { + title: '用户昵称', + dataIndex: 'user_nickname', + width: 120, + search: false, + ellipsis: true, + }, + { + title: '反馈内容', + dataIndex: 'content', + ellipsis: true, + search: false, + }, + { + title: '联系方式', + dataIndex: 'contact', + width: 140, + search: false, + render: (_, record) => record.contact || '-', + }, + { + title: '提交时间', + dataIndex: 'created_at', + valueType: 'dateTime', + width: 180, + search: false, + }, + { + title: '操作', + width: 80, + search: false, + render: (_, record) => ( + + ), + }, + ]; + + return ( + <> + + headerTitle="意见反馈" + rowKey="id" + actionRef={actionRef} + columns={columns} + cardBordered + request={async (params) => { + try { + const res = await getFeedbacks({ + page: params.current, + page_size: params.pageSize, + phone: params.user_phone, + }); + return { + data: res.data.items, + total: res.data.total, + success: true, + }; + } catch { + message.error('获取数据失败'); + return { data: [], total: 0, success: false }; + } + }} + pagination={{ + defaultPageSize: 10, + showSizeChanger: true, + }} + /> + setDetailVisible(false)} + footer={null} + width={600} + > + {currentRecord && ( + + + {currentRecord.user_phone} + + + {currentRecord.user_nickname || '-'} + + +
{currentRecord.content}
+
+ + {currentRecord.contact || '-'} + + + {currentRecord.created_at} + +
+ )} +
+ + ); +}; + +export default FeedbackPage; diff --git a/src/routes/index.tsx b/src/routes/index.tsx index d226a54..69a4b10 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -9,6 +9,7 @@ import BatchDetail from '../pages/Batch/Detail'; import DevicePage from '../pages/Device'; import UserPage from '../pages/User'; import AdminPage from '../pages/Admin'; +import FeedbackPage from '../pages/Feedback'; import { useAuthStore } from '../store/useAuthStore'; // 路由守卫组件 @@ -68,6 +69,10 @@ const router = createBrowserRouter([ path: 'admins', element: , }, + { + path: 'feedbacks', + element: , + }, ], }, {