import React, { useState } from ‘react’;
import {
Select,
DatePicker,
TimePicker,
Button,
Table,
Modal,
Form,
Input,
ConfigProvider,
Space,
message,
Spin,
} from ‘antd’;
import { FormOutlined, PlusCircleOutlined, MinusCircleOutlined } from ‘@ant-design/icons’;
import locale from ‘antd/locale/zh_CN’;
import dayjs, { Dayjs } from ‘dayjs’;
import ‘dayjs/locale/zh-cn’;
import { useSetPublish, useGetPublishHistory } from ‘./request’;
import type { PublishParams, PublishFormValues } from ‘@/types/autoPublish’;
import { PROJECT_NAMES, statusMap, envMap, typeMap, statusOption, envOption } from ‘./config’;
import { scriptsManagementService } from “@/api”;
import { useQueryClient } from ‘@tanstack/react-query’;
dayjs.locale(‘zh-cn’);
const AutoPublish: React.FC = () => {
const queryClient = useQueryClient();
const [pageSize] = useState(10);
const [currentPage, setCurrentPage] = useState(1);
const [selectEnv, setSelectEnv] = useState(1);
const [messageApi, contextHolder] = message.useMessage();
const [chooseDate, setChooseDate] = useState<Dayjs | null>(dayjs());
const [chooseTime, setChooseTime] = useState<Dayjs | null>(dayjs());
const [branchVersionFilter, setBranchVersionFilter] = useState<string | null>(null);
const [isModalVisible, setIsModalVisible] = useState(false);
const [form] = Form.useForm();
/**
* 获取历史数据
*/
const { data, isLoading } = useGetPublishHistory({
pageSize: pageSize.toString(),
page: currentPage.toString(),
});
const { data: versionData, isLoading: loading } = useGetPublishHistory({
pageSize: pageSize.toString(),
page: ‘1’,
branch_version: branchVersionFilter || ‘’,
//publish_env: 1,
//isFinal:1
});
const publishHistory = data?.data || [];
const dataByVersion = versionData?.data || [];
const total = data?.total || 0;
/** * 整合时间值 */ const handlePublishDate = (publishDate: Dayjs, publishTime: Dayjs) => { if (publishDate && publishTime) { const fullTime = publishDate .hour(publishTime.hour()) .minute(publishTime.minute()) .second(0); const formattedTime = fullTime.format('YYYY-MM-DD HH:mm:ss'); return formattedTime } } const { mutate } = useSetPublish(); /** * 新建发布 */ const newPublish = (publishEnv: number) => { setSelectEnv(publishEnv); setIsModalVisible(true); }; /** * 修改发布 */ const revisePublish = (record: PublishParams) => { const projects = record.product.map((item: any) => ({ productName: item.product_name, productTag: item.product_tag, })); // 解析发布时间 const publishTime = dayjs(record.publish_time); // 设置表单值 form.setFieldsValue({ projects: projects, branchVersion: record.branch_version, productEnv: record.publish_env.toString(), publishTime: record.publish_time, }); // 设置日期和时间选择器的值 setChooseDate(publishTime); setChooseTime(publishTime); setIsModalVisible(true); }; /** * 发布 */ const handleSubmit = (type: string) => { form.validateFields().then((values: PublishFormValues) => { if (!chooseDate || !chooseTime) { alert('请选择完整的日期和时间'); return; } const publishTime = handlePublishDate(chooseDate, chooseTime); const { projects, branchVersion, productEnv } = values; const publishType = type === 'schedule' ? 1 : 2; const publishStatus = 2; // 校验项目名称 let set = new Set(); for (let i = 0; i < projects.length; i++) { const productName = projects[i].productName; if (set.has(productName)) { messageApi.open({ type: 'warning', content: '项目名称重复了!', }); return } else { set.add(productName) } } const params = { product: projects.map((p) => ({ product_name: p.productName, product_tag: p.productTag, })), branch_version: branchVersion, publish_time: publishTime!, publish_user: 'admin', publish_status: publishStatus, publish_type: publishType, publish_env: Number(productEnv), }; console.log(`【${type}】提交数据:`, params); mutate(params, { onSuccess: () => { messageApi.open({ type: 'success', content: '发布成功!', }); // 刷新列表 queryClient.invalidateQueries({ queryKey: ['publishHistory'], }); }, onError: (data) => { messageApi.open({ type: 'error', content: data.message || '发布失败~请重试!', }); } }); setIsModalVisible(false); }); }; /** * 请求版本数据 */ const fetchVersionData = async (branchVersion: string) => { const params = { branch_version: branchVersion, page: '1', pageSize: '10' }; try { const data = await scriptsManagementService.getPublishHistory({ params }); console.log('获取到数据:', data); // 可选:手动更新缓存 queryClient.setQueryData(['publishHistory', 'v1', '1', '10'], data); } catch (error) { console.error('请求失败:', error); } }; /** * 按版本查询 */ // const getHistoryByVersion = (branchVersion: string) => { // setBranchVersionFilter(branchVersion); // } /** * 禁用今天之前的日期 */ const disabledDate = (current: Dayjs) => { return current < dayjs().startOf('day'); }; /** * 禁用此刻之前时间点 */ const disabledDateTime = (current: Dayjs | null) => { const now = dayjs(); if (!current) return {}; if (current.isSame(now, 'day')) { return { disabledHours: () => range(0, now.hour()), disabledMinutes: (selectedHour: number) => selectedHour === now.hour() ? range(0, now.minute()) : [], }; } return {}; }; const range = (start: number, end: number) => { const result = []; for (let i = start; i < end; i++) { result.push(i); } return result; }; /** * 分页控制器 */ const handlePageChange = (page: number) => { setCurrentPage(page); }; /** * 定义表格 */ const columns1 = [ { title: '发布时间', dataIndex: 'publish_time', key: 'publish_time', }, { title: '发布版本', dataIndex: 'branch_version', key: 'branch_version', }, { title: '发布状态', dataIndex: 'publish_status', key: 'publish_status', render: (status: number) => statusMap[status] || '未知类型', }, { title: '发布类型', dataIndex: 'publish_type', key: 'publish_type', render: (type: number) => typeMap[type] || '未知类型', }, { title: '发布环境', dataIndex: 'publish_env', key: 'publish_env', render: (text: number) => envMap[text] || '未知环境', }, { title: '编辑', key: 'edit', render: (_: any, record: PublishParams) => ( <FormOutlined onClick={() => revisePublish(record)} style={{ cursor: 'pointer' }} /> ), }, ]; const columns2 = [ { title: '项目名称', dataIndex: 'product_name', key: 'product_name', }, { title: 'Tag号', dataIndex: 'product_tag', key: 'product_tag', }, ]; if (isLoading || loading) { return <div style={{ textAlign: 'center', lineHeight: '500px' }}> <Spin tip="Loading">{<a>加载中...</a>}</Spin> </div> } return ( <div style={{ padding: '20px' }}> {contextHolder} {/* 控件 */} <div style={{ display: 'flex', justifyContent: 'flex-end', gap: '16px', marginBottom: '20px' }}> <div style={{ alignItems: 'center' }}> <span style={{ fontSize: '16px', marginLeft: '20px' }}>版本查询:</span> <Select options={publishHistory.map((item) => ({ label: item.branch_version, value: item.branch_version, }))} onChange={(value) => setBranchVersionFilter(value)} style={{ width: 120, marginLeft: '10px' }} allowClear /> </div> <div style={{ alignItems: 'center' }}> <span style={{ fontSize: '16px', marginLeft: '20px' }}>发布状态:</span> <Select options={statusOption} style={{ width: 120, marginLeft: '10px' }} allowClear /> </div> <div style={{ alignItems: 'center' }}> <span style={{ fontSize: '16px', marginLeft: '20px', fontWeight: 'bold' }}>新建发布:</span> <Select options={envOption} onChange={newPublish} style={{ width: 120, marginLeft: '10px' }} /> </div> {/* <Button type="primary" onClick={newPublish} style={{ backgroundColor: '#3662ec', marginLeft: '20px'}}> 新建发布 </Button> */} </div> {/* 表格 */} <Table columns={columns1} dataSource={branchVersionFilter ? dataByVersion : publishHistory} rowKey={(record) => record.branch_version} pagination={{ current: currentPage, pageSize: pageSize, total: total, onChange: handlePageChange, showSizeChanger: false, }} expandable={{ expandedRowRender: (record) => ( <Table columns={columns2} dataSource={record.product || []} pagination={false} style={{ width: 500 }} rowKey={(item, index) => index!} /> ), }} /> {/* 编辑模态框 */} <Modal title="项目信息" open={isModalVisible} width={700} onCancel={() => setIsModalVisible(false)} footer={[ <Button key="back" onClick={() => setIsModalVisible(false)}> 取消 </Button>, <Button key="schedule" type="primary" onClick={() => handleSubmit('schedule')}> 预约发布 </Button>, <Button key="publish" type="primary" onClick={() => handleSubmit('rightNow')}> 立即发布 </Button>, ]} > <Form form={form} layout="horizontal" labelCol={{ span: 5 }} wrapperCol={{ span: 10 }} initialValues={{ projects: [ { productName: undefined, productTag: '', }, ], }} > <Form.List name="projects"> {(fields, { add, remove }) => ( <> {fields.map(({ key, name, ...restField }) => ( <Space key={key} style={{ display: 'flex', marginBottom: 0 }} align="baseline"> <Form.Item {...restField} name={[name, 'productName']} label="项目名称" labelCol={{ span: 9 }} wrapperCol={{ span: 16 }} rules={[{ required: true, message: '请选择项目名称' }]} > <Select showSearch optionFilterProp="children" options={PROJECT_NAMES.map((name) => ({ label: name, value: name, }))} style={{ width: 250 }} /> </Form.Item> <Form.Item {...restField} name={[name, 'productTag']} label="Tag" labelCol={{ span: 10 }} wrapperCol={{ span: 50 }} rules={[{ required: true, message: '请输入 Tag' }]} > <Input /> </Form.Item> <MinusCircleOutlined onClick={() => remove(name)} /> </Space> ))} <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 16 }}> <Button type="dashed" onClick={() => add()} icon={<PlusCircleOutlined />} style={{ width: 200, height: 35, borderRadius: 6, display: 'flex', alignItems: 'center', justifyContent: 'center' }} > 添加项目 </Button> </div> </> )} </Form.List> <Form.Item label="选择版本" name="branchVersion" rules={[{ required: true }]}> <Input /> </Form.Item> <Form.Item label="选择环境" name="productEnv" rules={[{ required: true }]} initialValue={selectEnv}> <Select options={envOption} style={{ width: 150 }} disabled /> </Form.Item> <Form.Item label={ <span> <span style={{ fontSize: '18px', color: 'rgb(255, 141, 142)' }}>*</span> 选择时间 </span> } > <Space> <ConfigProvider locale={locale}> <DatePicker format="YYYY-MM-DD" value={chooseDate} disabledDate={disabledDate} onChange={(date) => setChooseDate(date ? dayjs(date) : null)} /> </ConfigProvider> <TimePicker format="HH:mm" value={chooseTime} disabledTime={() => disabledDateTime(chooseDate)} onChange={(time) => setChooseTime(time ? dayjs(time) : null)} /> </Space> </Form.Item> </Form> </Modal> </div> );
};
export default AutoPublish;
为什么下面这个下拉框值一改变,会全体更新,下拉框的值也回到了最初的状态?
方案一是使用useMemo(),方案二是避免不必要的重新请求