import React, { useEffect, useRef, useState } from 'react'; import { Button, Form, message, Modal, Popconfirm, Radio, 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, MINI_USER_TYPE_MAP } from '@/domain/iMiniUser.ts'; import type IStore from '@/domain/iStore.ts'; import type ISupplier from '@/domain/iSupplier.ts'; import { getStoreOptions } from '@/api/customer/store.ts'; import { getSupplierOptions } from '@/api/customer/supplier.ts'; import { bindMiniUser, toggleMiniUserStatus } from '@/api/customer/miniUser.ts'; import AuthButton from '@/components/AuthButton'; const { Title, Text } = Typography; interface BindFormValues { type: number; store_id?: number; supplier_id?: number; } /** * 小程序用户管理(用户由小程序登录自动生成,后台只做绑定与状态管理) */ const MiniUserPage: React.FC = () => { const tableRef = useRef>(null); const [stores, setStores] = useState([]); const [suppliers, setSuppliers] = 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 ?? [])); getSupplierOptions().then((res) => setSuppliers(res.data.data ?? [])); }, []); const openBind = (record: IMiniUser) => { setBindTarget(record); bindForm.setFieldsValue({ type: record.type && record.type > 0 ? record.type : undefined, store_id: record.store_id || undefined, supplier_id: record.supplier_id || undefined, }); setBindOpen(true); }; const handleBind = async (values: BindFormValues) => { if (!bindTarget?.id) { return; } setBindLoading(true); try { await bindMiniUser(bindTarget.id, { type: values.type, store_id: values.type === 1 ? values.store_id : undefined, supplier_id: values.type === 2 ? values.supplier_id : undefined, }); 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: 'type', valueType: 'select', fieldProps: { options: [ { value: 0, label: '待绑定' }, { value: 1, label: '门店' }, { value: 2, label: '供应商' }, ], }, render: (_, record) => { const item = MINI_USER_TYPE_MAP[record.type ?? 0]; return {item?.text}; }, align: 'center', }, { title: '绑定主体', dataIndex: 'bound_name', hideInSearch: true, render: (_, record) => { if (record.type === 1) { return {record.store?.name ?? `门店#${record.store_id}`}; } if (record.type === 2) { return ( {record.supplier?.name ?? `供应商#${record.supplier_id}`} ); } return 待后台绑定; }, }, { 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 ?? 从未登录, }, ]; 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" > prev.type !== cur.type}> {({ getFieldValue }) => { const type = getFieldValue('type'); if (type === 1) { return ( ({ label: s.name, value: s.id }))} /> ); } return null; }} ); }; export default MiniUserPage;