feat: 群认证

This commit is contained in:
chashaobao
2025-10-13 23:33:58 +08:00
parent 11f2624889
commit 4991720abb
10 changed files with 549 additions and 10 deletions

View File

@ -0,0 +1,206 @@
import { PlusOutlined } from '@ant-design/icons';
import { ActionType, ProColumns, ProFormInstance, ProFormSelect, ProFormText } from '@ant-design/pro-components';
import { ModalForm, PageContainer, ProTable } from '@ant-design/pro-components';
import '@umijs/max';
import { Button, message } from 'antd';
import { Select } from 'antd';
import { createStyles } from 'antd-style';
import dayjs from 'dayjs';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { CITY_OPTIONS } from '@/constants/city';
import { TIME_FORMAT } from '@/constants/global';
import { deleteCityOperator, getAllStaffList, getCityOpratorList, updateCityOperator } from '@/services/list';
const useStyles = createStyles(({ token }) => {
return {
img: {
width: 100,
height: 100,
},
delete: {
color: token.colorError,
},
button: {
marginRight: '8px',
},
};
});
const TableList: React.FC = () => {
const [updateModalOpen, handleUpdateModalOpen] = useState<boolean>(false);
const [currentRow, setCurrentRow] = useState<API.CityOperatorListItem>();
const actionRef = useRef<ActionType>();
const formRef = useRef<ProFormInstance>();
const [staffOptions, setStaffOptions] = useState<Array<{ label: string; value: number; isDefault: boolean }>>([]);
const defaultStaff = useMemo(() => {
return staffOptions.find(it => it.isDefault) || staffOptions[0];
}, [staffOptions]);
const { styles } = useStyles();
const getAllStaffOptions = async () => {
try {
const results = await getAllStaffList();
setStaffOptions(
results.map(it => ({
label: it.staffName,
isDefault: Boolean(it.isDefault),
value: it.id,
})),
);
} catch (e) {
} finally {
}
};
const handleDelete = async (id: number) => {
await deleteCityOperator(id);
message.success('操作成功');
actionRef.current?.reload();
};
useEffect(() => {
getAllStaffOptions();
}, []);
const columns: ProColumns<API.CityOperatorListItem>[] = [
{
title: '城市',
dataIndex: 'cityCode',
valueType: 'textarea',
render: (_text, record) => record.cityName,
renderFormItem() {
return (
<Select
showSearch
allowClear
options={CITY_OPTIONS}
filterOption={(input, option) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase())}
/>
);
},
},
{
title: '运营',
dataIndex: 'staffName',
valueType: 'textarea',
search: false,
},
{
title: '创建时间',
dataIndex: 'created',
valueType: 'dateTime',
renderText(created: string) {
return dayjs(created).format(TIME_FORMAT);
},
search: false,
},
{
title: '操作',
valueType: 'option',
render: (_, record) => (
<>
<a
key="config"
className={styles.button}
onClick={() => {
handleUpdateModalOpen(true);
setCurrentRow(record);
formRef.current?.setFieldsValue({
...record,
staff: {
label: record.staffName,
value: record.staffId,
},
city: {
label: record.cityName,
value: record.cityCode,
},
});
}}
>
</a>
<a key="delete" className={styles.delete} onClick={() => handleDelete(record.id)}>
</a>
</>
),
},
];
return (
<PageContainer>
<ProTable<API.CityOperatorListItem, API.PageParams>
headerTitle="查询表格"
actionRef={actionRef}
rowKey="key"
search={{ labelWidth: 120, collapsed: false, collapseRender: false }}
request={getCityOpratorList}
columns={columns}
toolBarRender={() => [
<Button
type="primary"
key="add"
icon={<PlusOutlined />}
onClick={() => {
handleUpdateModalOpen(true);
setCurrentRow(undefined);
formRef.current?.resetFields();
}}
>
</Button>,
]}
/>
<ModalForm
title={`${currentRow ? '修改' : '新增'}城市`}
width="400px"
formRef={formRef}
initialValues={{ staff: defaultStaff }}
open={updateModalOpen}
onOpenChange={handleUpdateModalOpen}
onFinish={async formData => {
const params: API.UpdateCityOperator = {
id: currentRow?.id,
staffId: formData.staff.value,
staffName: formData.staff.label,
cityCode: formData.city.value,
cityName: formData.city.label,
groupLink: formData.groupLink,
};
console.log('update confirm', formData, params);
try {
await updateCityOperator(params);
actionRef.current?.reload();
formRef.current?.resetFields();
} catch (e) {}
handleUpdateModalOpen(false);
}}
>
<ProFormSelect.SearchSelect
name="city"
mode="single"
label="所属城市"
options={CITY_OPTIONS}
rules={[{ required: true, message: '必填项' }]}
/>
<ProFormSelect.SearchSelect
mode="single"
name="staff"
label="运营"
options={staffOptions}
rules={[{ required: true, message: '必填项' }]}
/>
<ProFormText
name="groupLink"
label="进群链接"
rules={[
{ required: true, message: '必填项' },
{ message: '请输入链接', type: 'url' },
]}
/>
</ModalForm>
</PageContainer>
);
};
export default TableList;

View File

@ -0,0 +1,185 @@
import { PlusOutlined } from '@ant-design/icons';
import { ActionType, ProColumns, ProFormInstance, ProFormText, ProFormUploadButton } from '@ant-design/pro-components';
import { ModalForm, PageContainer, ProTable } from '@ant-design/pro-components';
import '@umijs/max';
import { Button, message } from 'antd';
import { createStyles } from 'antd-style';
import dayjs from 'dayjs';
import React, { useRef, useState } from 'react';
import { TIME_FORMAT } from '@/constants/global';
import { uploadFile } from '@/services/file';
import { deleteStaff, getStaffList, setDefaultStaff, updateStaff } from '@/services/list';
const useStyles = createStyles(({ token }) => {
return {
img: {
width: 100,
height: 100,
},
delete: {
color: token.colorError,
},
button: {
marginRight: '8px',
},
};
});
const TableList: React.FC = () => {
const [updateModalOpen, handleUpdateModalOpen] = useState<boolean>(false);
const [currentRow, setCurrentRow] = useState<API.StaffListItem>();
const actionRef = useRef<ActionType>();
const formRef = useRef<ProFormInstance>();
const { styles } = useStyles();
const handleDefault = async (id: number) => {
await setDefaultStaff(id);
actionRef.current?.reload();
message.success('操作成功');
};
const handleDelete = async (id: number) => {
await deleteStaff(id);
actionRef.current?.reload();
message.success('操作成功');
};
const handleUpload = async (file: File) => {
const { url } = await uploadFile({ file, type: 'IMAGE' });
return url;
};
const columns: ProColumns<API.StaffListItem>[] = [
{
title: '昵称',
dataIndex: 'staffName',
valueType: 'textarea',
},
{
title: '二维码',
dataIndex: 'staffQrCode',
valueType: 'textarea',
copyable: true,
search: false,
render(_dom, { staffQrCode }) {
return <img className={styles.img} src={staffQrCode} alt="" />;
},
},
{
title: '默认',
dataIndex: 'isDefault',
valueType: 'textarea',
search: false,
renderText(isDefault) {
return isDefault ? '是' : '否';
},
},
{
title: '添加时间',
dataIndex: 'created',
valueType: 'dateTime',
renderText(created: string) {
return dayjs(created).format(TIME_FORMAT);
},
search: false,
},
{
title: '操作',
valueType: 'option',
render: (_, record) => (
<>
<a
key="config"
className={styles.button}
onClick={() => {
handleUpdateModalOpen(true);
setCurrentRow(record);
formRef.current?.setFieldsValue({
...record,
qrCode: [
{
uid: `${record.id}_qrCode`,
name: `${record.staffName}_qrCode`,
status: 'done',
url: record.staffQrCode,
},
],
});
}}
>
</a>
<a key="default" className={styles.button} onClick={() => handleDefault(record.id)}>
</a>
<a key="delete" className={styles.delete} onClick={() => handleDelete(record.id)}>
</a>
</>
),
},
];
return (
<PageContainer>
<ProTable<API.StaffListItem, API.PageParams>
headerTitle="查询表格"
actionRef={actionRef}
rowKey="key"
search={{ labelWidth: 120, collapsed: false, collapseRender: false }}
request={getStaffList}
columns={columns}
toolBarRender={() => [
<Button
type="primary"
key="add"
icon={<PlusOutlined />}
onClick={() => {
handleUpdateModalOpen(true);
setCurrentRow(undefined);
formRef.current?.resetFields();
}}
>
</Button>,
]}
/>
<ModalForm
title={`${currentRow ? '修改' : '新增'}运营`}
width="400px"
formRef={formRef}
open={updateModalOpen}
onOpenChange={handleUpdateModalOpen}
onFinish={async formData => {
const params: API.UpdateStaffParams = {
id: currentRow?.id,
isDefault: currentRow?.isDefault || 0,
staffName: formData?.staffName,
staffQrCode: formData.qrCode[0].xhr.responseURL,
};
console.log('update confirm', formData, params);
try {
await updateStaff(params);
actionRef.current?.reload();
formRef.current?.resetFields();
} catch (e) {}
handleUpdateModalOpen(false);
}}
>
<ProFormText name="staffName" label="昵称" rules={[{ required: true, message: '必填项' }]} />
<ProFormUploadButton
name="qrCode"
label="上传"
max={1}
accept="image/*"
rules={[{ required: true, message: '必填项' }]}
fieldProps={{
name: 'file',
}}
action={handleUpload}
/>
</ModalForm>
</PageContainer>
);
};
export default TableList;