import { message } from 'antd'; import { difference, flatten, forEach, intersectionWith, isArray, keys, values } from 'lodash'; import type { Dispatch, SetStateAction } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { request, useIntl, useRequest } from 'umi'; import { bindRequestOptions, updateOption } from '../server'; import { useGetAppId } from '../utils/hooks'; export async function fetchFlagAll(appId, isAllowApply) { const { data } = await request('/goapi/flag/all', { method: 'POST', data: { appId, fromApply: isAllowApply, }, }); return { data, success: true, }; } export interface BindDataOptions { activeKey: string | string[]; setActiveKey: Dispatch>; initFetch: () => Promise; loading: boolean; flagList?: any; selectMap: Record; getSelectOptions: (flagIds: number[] | number) => Promise; appId: number; dataMap: any; updateFn: (data: any, oldDataMap: any, formartFn: any) => Promise; reloadForm: () => void; title: string; refresh: () => Promise; } export interface IBindData { name?: string; type?: 'feature' | 'option' | 'policy' | 'user' | 'role'; // 选择类型 isAllowApply?: boolean; id?: number; form?: any; isHaveDate?: boolean; appIdCustomer?: number; } export const useBindData = ({ name = 'values', type, id, isHaveDate, form, isAllowApply = false, appIdCustomer, }: IBindData): BindDataOptions => { const { formatMessage } = useIntl(); const [activeKey, setActiveKey] = useState([]); const [loading, setLoading] = useState(true); const [dataMap, setDataMap] = useState({}); const [selectMap, setSelectMap] = useState>({}); const appUrlId = useGetAppId(); const appId = useMemo(() => appIdCustomer || appUrlId, [appIdCustomer, appUrlId]); const { data: flagData, refresh } = useRequest(() => fetchFlagAll(appId, 1), { refreshDeps: [appId], ready: Boolean(appId), }); const reloadForm = useCallback(() => { const ref = form?.setFieldsValue ? form : form?.current; const fields = {}; keys(selectMap)?.forEach?.((flagId) => { fields[`data${flagId}`] = { data: selectMap[flagId], }; }); ref?.setFieldsValue({ [name]: { ...ref?.getFieldValue(name), ...fields, }, }); }, [form, selectMap, name]); // 当点击某个flag的时候,请求这个flag下面的所有已经绑定了的options // 这里为什么不用判断当前的flagId是否已经请求过了,因为每次只能打开的时候,已经用diffrence判断过了,所以只有没出现的才放到这里去重新请求。 const getSelectOptions = useCallback( async (flagIds: number[] | number) => { if (!id) { setLoading(false); return; } setLoading(true); const flagIdsParam = isArray(flagIds) ? flagIds : [flagIds]; const resData = await bindRequestOptions( { appId: appIdCustomer ? appIdCustomer : appId }, { [`${type}Id`]: id, flagIds: flagIdsParam }, ); const tempData = {}; const tempSelect = {}; resData?.map((res, index) => { const flagId = flagIdsParam[index]; const { data: { list: activeList }, } = res; const obj = {}; const flagDataList = activeList?.map((item) => { obj[item.id] = { ...item, expiredAt: isHaveDate ? item.expiredAt * 1000 : undefined }; return { id: item.id, expiredAt: isHaveDate ? item.expiredAt * 1000 : undefined, }; }); tempData[flagId] = obj; tempSelect[flagId] = flagDataList; }); setDataMap({ ...dataMap, ...tempData, }); setSelectMap({ ...selectMap, ...tempSelect, }); setLoading(false); }, // eslint-disable-next-line react-hooks/exhaustive-deps [type, id, selectMap, form, dataMap, isHaveDate, name, appId, appIdCustomer], ); const updateFn = useCallback( async (data, olddataMap, formartFn) => { let dataMapKey = {}; forEach(keys(olddataMap), (key) => { dataMapKey = { ...dataMapKey, ...olddataMap[key], }; }); let iserror = false; const map = {}; let params: number[] = []; const newDataList: API.OptionListItem[] = []; // 把所有的值都拿出来 keys(data).map((key) => { if (data[key]?.error?.error) { iserror = true; message.error(data[key]?.error.message); } params = [ ...params, ...data[key]?.data?.map((val) => { newDataList.push(val); map[val.id] = formartFn(parseInt(val.id, 10), { [val.id]: { flagId: parseInt(key?.replace('data', ''), 10), expiredAt: isHaveDate ? val?.expiredAt : undefined, }, }); return parseInt(`${val.id}`, 10); }), ]; }); const oldParams: number[] = keys(dataMapKey)?.map((item) => parseInt(item, 10)); // 这是增加的 const addParams = difference(params, oldParams)?.map((item: number) => map[item]); // 这是减少的 const deleteParams = difference(oldParams, params)?.map((item) => formartFn(item, dataMapKey), ); // 这是需要更新的 const updateParams = intersectionWith( flatten(newDataList), flatten(values(dataMapKey)), (oldItem: any, newItem: any) => { if (!isHaveDate) { return false; } if (`${oldItem?.id}` === `${newItem?.id}`) { if (oldItem?.expiredAt !== newItem?.expiredAt) { return true; } } return false; }, ); if (iserror) return; // 更新绑定的值 await updateOption( `${type}_option`, [...addParams, ...updateParams?.map((p: API.OptionListItem) => map[p.id])], deleteParams, ); }, [isHaveDate, type], ); const initFetch = useCallback(async () => { if (flagData?.length === 0) return; // 默认开始就执行第一个flas的所有绑定的options。(因为可能数据量太大了) // getSelectOptions(flagList?.[0]?.id); // setActiveKey([`${flagList?.[0]?.id}`]); // 把所有的值都要请求过来。 getSelectOptions(flagData?.map((flag) => flag?.id) as number[]); }, [flagData, getSelectOptions]); useEffect(() => { reloadForm(); }, [reloadForm, selectMap]); useEffect(() => { setActiveKey( flagData ?.map((flag) => (isAllowApply ? (flag.isAllowApply ? `${flag?.id}` : '') : `${flag?.id}`)) ?.filter((item) => !!item) || [], ); }, [flagData, isAllowApply]); return { activeKey, setActiveKey, initFetch, loading, flagList: flagData, selectMap, getSelectOptions, appId: appIdCustomer ? appIdCustomer : appId, dataMap, updateFn, reloadForm, title: formatMessage({ id: `component.bind.data.title`, defaultMessage: '绑定数据' }), refresh, }; };