Files
boluo-admin-main/src/pages/table-list/city-operation/index.tsx
2026-01-28 19:47:44 +08:00

314 lines
9.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { PlusOutlined } from '@ant-design/icons';
import {
ActionType,
ProColumns,
ProFormInstance,
ProFormSelect,
ProFormText,
ProFormUploadButton,
ProFormDependency,
} 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 { uploadFileWx } from '@/services/file';
import {
deleteCityOperator,
getAllStaffList,
getCityOpratorList,
getProductList,
updateCityOperator,
} from '@/services/list';
const useStyles = createStyles(({ token }) => {
return {
img: {
width: 100,
height: 100,
},
delete: {
color: token.colorError,
},
button: {
marginRight: '8px',
},
};
});
const calcPrice = (productSpecId: string, specList: API.ProductSpecListItem[]) => {
const product = specList.find(o => o.productSpecId === productSpecId);
return { price: product?.showPrice, originalPrice: product?.originalPrice, sendCount: product?.count };
};
const TableList: React.FC = () => {
const [updateModalOpen, handleUpdateModalOpen] = useState<boolean>(false);
const [specList, setSpecList] = useState<API.ProductSpecListItem[]>([]);
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 specOptions = useMemo(
() =>
specList.map(it => ({
value: it.productSpecId,
label: it.title,
})),
[specList],
);
const getAllStaffOptions = async () => {
try {
const results = await getAllStaffList();
setStaffOptions(
results.map(it => ({
label: `${it.staffName}${it.isDefault ? ' (默认)' : ''}`,
isDefault: Boolean(it.isDefault),
value: it.id,
})),
);
} catch (e) {
} finally {
}
};
const getAllSpectList = async () => {
const list = await getProductList('GROUP_BATCH_PUSH');
setSpecList(list);
};
const handleDelete = async (id: number) => {
await deleteCityOperator(id);
message.success('操作成功');
actionRef.current?.reload();
};
const handleUpload = async (file: File) => {
const url = await uploadFileWx({ file, id: currentRow?.id });
return url;
};
useEffect(() => {
getAllStaffOptions();
getAllSpectList();
}, []);
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: '进群链接',
dataIndex: 'groupLink',
valueType: 'textarea',
search: false,
},
{
title: '企微好友二维码',
dataIndex: 'contactQrCode',
valueType: 'textarea',
copyable: true,
search: false,
render(_dom, { contactQrCode }) {
return contactQrCode ? <img className={styles.img} src={contactQrCode} alt="" /> : '-';
},
},
{
title: '进群二维码',
dataIndex: 'groupQrCode',
valueType: 'textarea',
copyable: true,
search: false,
render(_dom, { groupQrCode }) {
return groupQrCode ? <img className={styles.img} src={groupQrCode} alt="" /> : '-';
},
},
{
title: '可群发数量',
dataIndex: 'productSpecId',
valueType: 'textarea',
search: false,
renderText: productSpecId => calcPrice(productSpecId, specList).sendCount || '-',
},
{
title: '群代发价格',
dataIndex: 'productSpecId',
valueType: 'textarea',
search: false,
renderText: productSpecId => calcPrice(productSpecId, specList).price || '-',
},
{
title: '操作',
valueType: 'option',
render: (_, record) => (
<>
<a
key="config"
className={styles.button}
onClick={() => {
handleUpdateModalOpen(true);
setCurrentRow(record);
setTimeout(() => {
formRef.current?.setFieldsValue({
...record,
city: {
label: record.cityName,
value: record.cityCode,
},
qrCode: record.groupQrCode
? [
{
uid: `${record.id}_qrCode`,
name: `${record.cityName}_qrCode`,
status: 'done',
url: record.groupQrCode,
},
]
: undefined,
});
});
}}
>
</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={{ staffId: defaultStaff?.value }}
open={updateModalOpen}
onOpenChange={handleUpdateModalOpen}
onFinish={async formData => {
const params: API.UpdateCityOperator = {
id: currentRow?.id,
staffId: formData.staffId,
cityCode: formData.city.value,
cityName: formData.city.label,
groupLink: formData.groupLink,
productSpecId: formData.productSpecId,
groupQrCode: formData.qrCode[0].xhr ? formData.qrCode[0].xhr.responseURL : formData.qrCode[0].url,
};
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
mode="single"
name="staffId"
showSearch
label="运营"
options={staffOptions}
rules={[{ required: true, message: '必填项' }]}
/>
<ProFormText name="groupLink" label="进群链接" rules={[{ message: '请输入链接', type: 'url' }]} />
<ProFormUploadButton
name="qrCode"
label="进群二维码"
max={1}
accept="image/*"
rules={[{ required: true, message: '必填项' }]}
fieldProps={{
name: 'file',
}}
action={handleUpload}
/>
<ProFormSelect
mode="single"
name="productSpecId"
label="可群发数量"
options={specOptions}
rules={[{ required: true, message: '必填项' }]}
/>
<ProFormDependency name={['productSpecId']}>
{({ productSpecId }) =>
productSpecId ? (
<div>
{calcPrice(productSpecId, specList).price}{calcPrice(productSpecId, specList).originalPrice}
</div>
) : null
}
</ProFormDependency>
</ModalForm>
</PageContainer>
);
};
export default TableList;