import React, { useEffect, useRef, useState } from 'react'; import { Button, Form, message, Modal, Popconfirm, Select, Space, Tag, Typography, } from 'antd'; import XinTable from '@/components/XinTable'; import type { XinTableColumn, XinTableInstance, XinTableProps, } from '@/components/XinTable/typings.ts'; import type IMiniUser from '@/domain/iMiniUser.ts'; import { MINI_USER_STATUS_MAP } from '@/domain/iMiniUser.ts'; import type IStore from '@/domain/iStore.ts'; import { getStoreOptions } from '@/api/customer/store.ts'; import { bindMiniUser, toggleMiniUserStatus } from '@/api/customer/miniUser.ts'; import AuthButton from '@/components/AuthButton'; const { Title, Text } = Typography; interface BindFormValues { store_id: number; } /** * 小程序用户管理(用户由小程序登录自动生成,后台只做绑定与状态管理) */ const MiniUserPage: React.FC = () => { const tableRef = useRef>(null); const [stores, setStores] = useState([]); // 绑定弹窗 const [bindOpen, setBindOpen] = useState(false); const [bindTarget, setBindTarget] = useState(null); const [bindLoading, setBindLoading] = useState(false); const [bindForm] = Form.useForm(); useEffect(() => { getStoreOptions().then((res) => setStores(res.data.data ?? [])); }, []); const openBind = (record: IMiniUser) => { setBindTarget(record); bindForm.setFieldsValue({ store_id: record.store_id || undefined, }); setBindOpen(true); }; const handleBind = async (values: BindFormValues) => { if (!bindTarget?.id) { return; } setBindLoading(true); try { await bindMiniUser(bindTarget.id, { store_id: values.store_id, }); message.success('绑定成功'); setBindOpen(false); await tableRef.current?.reload(); } finally { setBindLoading(false); } }; const handleToggleStatus = async (record: IMiniUser) => { await toggleMiniUserStatus(record.id!, record.status === 1 ? 0 : 1); message.success(record.status === 1 ? '已停用' : '已启用'); await tableRef.current?.reload(); }; const columns: XinTableColumn[] = [ { title: 'ID', dataIndex: 'id', hideInSearch: true, width: 70, align: 'center', }, { title: '昵称', dataIndex: 'nickname', valueType: 'text', hideInSearch: true, render: (_, record) => ( {record.avatar ? ( ) : null} {record.nickname || '-'} ), }, { title: '手机号', dataIndex: 'phone', valueType: 'text', hideInSearch: true, render: (_, record) => record.phone || 未绑定, }, { title: '绑定门店', dataIndex: 'store_id', hideInSearch: true, render: (_, record) => { return {record.store?.name ?? `门店#${record.store_id}`}; }, }, { title: '状态', dataIndex: 'status', valueType: 'select', fieldProps: { options: [ { value: 1, label: '正常' }, { value: 0, label: '停用' }, ], }, render: (_, record) => { const item = MINI_USER_STATUS_MAP[record.status ?? 1]; return {item?.text}; }, align: 'center', }, { title: '最后登录', dataIndex: 'last_login_at', hideInSearch: true, align: 'center', render: (_, record) => record.last_login_at ?? 从未登录, }, { title: '注册时间', dataIndex: 'created_at', hideInSearch: true, align: 'center', }, ]; const operateRender: XinTableProps['operateRender'] = (record) => [ , handleToggleStatus(record)} > , ]; const tableProps: XinTableProps = { api: '/customer/miniUser', columns, rowKey: 'id', accessName: 'customer.miniUser', tableRef, operateRender, // 无新增/编辑表单 formProps: false, }; return ( <>
小程序用户 用户由微信小程序登录自动创建;
{...tableProps} /> setBindOpen(false)} onOk={() => bindForm.submit()} confirmLoading={bindLoading} okText="确认绑定" destroyOnHidden > form={bindForm} layout="vertical" onFinish={handleBind} className="mt-4" >