Jelajahi Sumber

✨ feat(client-detail): add follow-up and order records tabs

- add FollowUpRecordsTab component to display client follow-up records
- implement data fetching for follow-up records using react-query
- add OrderRecordsTab component to show client order information
- implement order data display with formatted currency and dates
- use Table component with proper column configurations for both tabs
yourname 8 bulan lalu
induk
melakukan
b827e79ef8

+ 87 - 0
src/client/admin/components/client-detail/FollowUpRecordsTab.tsx

@@ -0,0 +1,87 @@
+import React from 'react';
+import { Table, Tag } from 'antd';
+import { useQuery } from '@tanstack/react-query';
+import dayjs from 'dayjs';
+import { followUpRecordClient } from '@/client/api';
+import type { InferResponseType } from 'hono/client';
+
+type FollowUpRecordType = InferResponseType<typeof followUpRecordClient.$get, 200>['data'][0];
+
+interface FollowUpRecordsTabProps {
+  clientId: number;
+}
+
+const FollowUpRecordsTab: React.FC<FollowUpRecordsTabProps> = ({ clientId }) => {
+  const { data, isLoading } = useQuery({
+    queryKey: ['client-follow-up-records', clientId],
+    queryFn: async () => {
+      const res = await followUpRecordClient.$get({
+        query: {
+          page: 1,
+          pageSize: 100,
+          filters: JSON.stringify({ clientId }),
+        },
+      });
+      if (!res.ok) throw new Error('获取跟单记录失败');
+      const result = await res.json();
+      return result;
+    },
+    enabled: !!clientId,
+  });
+
+  const columns = [
+    {
+      title: '收录资源',
+      dataIndex: 'resourceName',
+      key: 'resourceName',
+      width: 200,
+      ellipsis: true,
+    },
+    {
+      title: '下次联系时间',
+      dataIndex: 'nextContactTime',
+      key: 'nextContactTime',
+      width: 160,
+      render: (text?: string) => text ? dayjs(text).format('YYYY-MM-DD HH:mm:ss') : '-',
+    },
+    {
+      title: '详细备注',
+      dataIndex: 'details',
+      key: 'details',
+      width: 300,
+      ellipsis: true,
+      render: (text?: string) => text || '-',
+    },
+    {
+      title: '创建时间',
+      dataIndex: 'createdAt',
+      key: 'createdAt',
+      width: 160,
+      render: (text: string) => dayjs(text).format('YYYY-MM-DD HH:mm:ss'),
+    },
+    {
+      title: '更新时间',
+      dataIndex: 'updatedAt',
+      key: 'updatedAt',
+      width: 160,
+      render: (text: string) => dayjs(text).format('YYYY-MM-DD HH:mm:ss'),
+    },
+  ];
+
+  return (
+    <div className="p-4">
+      <Table
+        columns={columns}
+        dataSource={data?.data || []}
+        rowKey="id"
+        loading={isLoading}
+        pagination={false}
+        scroll={{ x: 'max-content' }}
+        size="small"
+        bordered
+      />
+    </div>
+  );
+};
+
+export default FollowUpRecordsTab;

+ 120 - 0
src/client/admin/components/client-detail/OrderRecordsTab.tsx

@@ -0,0 +1,120 @@
+import React from 'react';
+import { Table, Tag } from 'antd';
+import { useQuery } from '@tanstack/react-query';
+import dayjs from 'dayjs';
+import { orderRecordClient } from '@/client/api';
+import type { InferResponseType } from 'hono/client';
+
+type OrderRecordType = InferResponseType<typeof orderRecordClient.$get, 200>['data'][0];
+
+interface OrderRecordsTabProps {
+  clientId: number;
+}
+
+const OrderRecordsTab: React.FC<OrderRecordsTabProps> = ({ clientId }) => {
+  const { data, isLoading } = useQuery({
+    queryKey: ['client-order-records', clientId],
+    queryFn: async () => {
+      const res = await orderRecordClient.$get({
+        query: {
+          page: 1,
+          pageSize: 100,
+          filters: JSON.stringify({ clientId }),
+        },
+      });
+      if (!res.ok) throw new Error('获取订单记录失败');
+      const result = await res.json();
+      return result;
+    },
+    enabled: !!clientId,
+  });
+
+  const columns = [
+    {
+      title: '订单编号',
+      dataIndex: 'orderNumber',
+      key: 'orderNumber',
+      width: 150,
+    },
+    {
+      title: '联系人',
+      dataIndex: ['linkman', 'name'],
+      key: 'linkman.name',
+      width: 100,
+      render: (text: string) => text || '-',
+    },
+    {
+      title: '下单日期',
+      dataIndex: 'orderDate',
+      key: 'orderDate',
+      width: 120,
+      render: (text: string) => dayjs(text).format('YYYY-MM-DD'),
+    },
+    {
+      title: '交单日期',
+      dataIndex: 'deliveryDate',
+      key: 'deliveryDate',
+      width: 120,
+      render: (text?: string) => text ? dayjs(text).format('YYYY-MM-DD') : '-',
+    },
+    {
+      title: '订单金额',
+      dataIndex: 'orderAmount',
+      key: 'orderAmount',
+      width: 120,
+      render: (amount: number) => `¥${amount?.toFixed(2) || '0.00'}`,
+    },
+    {
+      title: '预付款',
+      dataIndex: 'advancePayment',
+      key: 'advancePayment',
+      width: 120,
+      render: (amount: number) => `¥${amount?.toFixed(2) || '0.00'}`,
+    },
+    {
+      title: '订单状态',
+      dataIndex: 'orderStatus',
+      key: 'orderStatus',
+      width: 100,
+      render: (status: number) => {
+        const statusMap = {
+          0: { text: '未处理', color: 'orange' },
+          1: { text: '已完成', color: 'green' },
+        };
+        const config = statusMap[status as keyof typeof statusMap] || { text: '未知', color: 'default' };
+        return <Tag color={config.color}>{config.text}</Tag>;
+      },
+    },
+    {
+      title: '业务员',
+      dataIndex: ['user', 'name'],
+      key: 'user.name',
+      width: 100,
+      render: (text: string) => text || '-',
+    },
+    {
+      title: '创建时间',
+      dataIndex: 'createdAt',
+      key: 'createdAt',
+      width: 160,
+      render: (text: string) => dayjs(text).format('YYYY-MM-DD HH:mm:ss'),
+    },
+  ];
+
+  return (
+    <div className="p-4">
+      <Table
+        columns={columns}
+        dataSource={data?.data || []}
+        rowKey="id"
+        loading={isLoading}
+        pagination={false}
+        scroll={{ x: 'max-content' }}
+        size="small"
+        bordered
+      />
+    </div>
+  );
+};
+
+export default OrderRecordsTab;