import type { FormInstance } from 'antd'; import { Empty, Tabs } from 'antd'; import _ from 'lodash'; import type { Dispatch, Key, SetStateAction } from 'react'; import { createContext, useContext, useEffect, useMemo } from 'react'; import { useIntl, useRequest } from 'umi'; import { filterTreeByIds } from '../utils'; import { leafBuildTree, treeCreateId } from '../utils/array'; import { AppDetailContext, useCityList, useDomLayoutEffect, useFeatureTree, useFlagList, usePolicyList, useRoleList, } from '../utils/hooks'; import CityTab from './components/cityTab'; import FeatureTab from './components/featureTab'; import FlagTab from './components/flagTab'; import PolicyTab from './components/policyTab'; import RoleTab from './components/roleTab'; import { bindFilter, filterFeatureCityIds, formatFeatureFullList, formatFlagList, formatMergedVal, formatOptionEmptyList, formatOptionFullList, } from './util'; export type DetailProps = { /** 1为自己申请, 2为别人申请 */ type: number; open: boolean; id: number; tagKey?: string; setTagKey?: Dispatch>; form?: FormInstance; defaultFlagIds?: string[]; currentUser?: API.CurrentUser; initialValues?: any; /** operation: 运营端配置 multiple: 多应用申请 single: 单应用申请 */ useType?: 'multiple' | 'single' | 'operation'; featureCityIds?: API.FeatureCityId[]; setFeatureCityIds?: Dispatch>; /** 城市权限选中同步事件 */ onSyncCitySelect?: (v: any) => void; }; type ContextValueType = DetailProps & { detailData?: any }; export const DetailContext = createContext({ type: 0, open: false, id: 0, }); const Detail = (props: DetailProps) => { const { type, open, id: appId, tagKey, form, setTagKey, initialValues, useType, featureCityIds, setFeatureCityIds, defaultFlagIds, } = props; const { formatMessage } = useIntl(); const { isAllowApplyFeature, isAllowApplyFlag, isAllowApplyPolicy, isAllowApplyRole, isAllowApplyCity, applyOrder, defaultExpirationTime, } = useContext(AppDetailContext); const { roleList, refresh: rlRefresh } = useRoleList(appId, 1); const { featureTreeData, refresh: ftdRefresh } = useFeatureTree(appId, 1); const { policyList, refresh: plRefresh } = usePolicyList(appId, 1); const { cityList, refresh: cityRefresh } = useCityList(appId); const { flagList, refresh: flagRefresh } = useFlagList(appId, 1); const { data: detailData, refresh: detailRefresh } = useRequest( () => ({ url: '/goapi/app/myPermission/detail', method: 'POST', data: { appId }, }), { ready: Boolean(appId && open && useType !== 'operation'), refreshDeps: [appId, open, useType], }, ); const { featureTree, flagList: oldFlagList, policyList: oldPolicyList, roleList: oldRoleList, userCityList: oldCityList, featureCityIds: oldFeatureCityIds, } = detailData || {}; const { flags: initFlags, roles: initRoles, features: initFeatures, policies: initPolicies, cities: initCities, featureCityIds: initFeatureCityIds, } = initialValues || {}; const flagData = useMemo( () => formatFlagList(flagList, initFlags, useType), [flagList, initFlags, useType], ); const selectedRole = useMemo( () => oldRoleList?.filter((v: any) => bindFilter(v, useType)) || [], [oldRoleList, useType], ); const roleOptions = useMemo(() => { if (useType === 'multiple') { const roleIds = initRoles?.data?.map((v: any) => Number(v.id)) || []; return roleList?.filter((v: any) => roleIds.includes(v.id)); } return roleList?.map((v: any) => ({ ...v })); }, [initRoles, roleList, useType]); const selectedPolicy = useMemo(() => { return oldPolicyList?.filter((v: any) => bindFilter(v, useType)); }, [oldPolicyList, useType]); const filterFeatureTreeData = useMemo(() => { if (useType === 'multiple' && !_.isEmpty(featureTreeData)) { const featureIds = initFeatures?.data?.map((v: any) => Number(v.id)) || []; return filterTreeByIds(featureTreeData, featureIds); } return featureTreeData; }, [featureTreeData, initFeatures, useType]); const policyOptions = useMemo(() => { if (useType === 'multiple') { const policyIds = initPolicies?.data?.map((v: any) => Number(v.id)) || []; return policyList?.filter((v: any) => policyIds.includes(v.id)); } return policyList?.map((v: any) => ({ ...v })); }, [policyList, useType, initPolicies]); const cityOptions = useMemo(() => { const cityOps = treeCreateId(cityList); if (useType === 'multiple') { const cityIds: Key[] = initCities?.data?.map((v: any) => Number(v.id)) || []; return leafBuildTree(cityIds, cityOps); } return cityOps; }, [cityList, useType, initCities]); const isShowPolicy = useMemo( () => Boolean( useType === 'multiple' ? !_.isEmpty(policyOptions) && isAllowApplyPolicy : isAllowApplyPolicy, ), [isAllowApplyPolicy, policyOptions, useType], ); const isShowCity = useMemo( () => Boolean( useType === 'multiple' ? !_.isEmpty(cityOptions) && isAllowApplyCity : isAllowApplyCity, ), [cityOptions, isAllowApplyCity, useType], ); const isShowRoles = useMemo( () => Boolean( useType === 'multiple' ? !_.isEmpty(roleOptions) && isAllowApplyRole : isAllowApplyRole, ), [useType, roleOptions, isAllowApplyRole], ); const isShowFeature = useMemo( () => Boolean( useType === 'multiple' ? !_.isEmpty(filterFeatureTreeData) && isAllowApplyFeature : isAllowApplyFeature, ), [filterFeatureTreeData, isAllowApplyFeature, useType], ); const isShowFlag = useMemo( () => Boolean(useType === 'multiple' ? !_.isEmpty(flagData) && isAllowApplyFlag : isAllowApplyFlag), [flagData, isAllowApplyFlag, useType], ); const mergedValues = useMemo(() => { if (useType === 'operation') return initialValues; const baseValues = { features: { data: formatFeatureFullList(featureTree, useType) }, policies: { data: selectedPolicy }, roles: { data: selectedRole }, cities: { data: oldCityList?.map((v: any) => ({ ...v, id: v.cityId })) }, flags: formatOptionFullList( flagData, oldFlagList, useType, defaultFlagIds, defaultExpirationTime, ), role: undefined, }; if (type === 2) { baseValues.features.data = []; baseValues.policies.data = []; baseValues.roles.data = []; baseValues.cities.data = []; baseValues.flags = formatOptionEmptyList(flagData); } return _.isEmpty(initialValues) ? baseValues : formatMergedVal(baseValues, initialValues); }, [ defaultExpirationTime, defaultFlagIds, featureTree, flagData, initialValues, oldCityList, oldFlagList, selectedPolicy, selectedRole, type, useType, ]); useEffect(() => { if (open) { rlRefresh(); ftdRefresh(); plRefresh(); cityRefresh(); flagRefresh(); } }, [open, ftdRefresh, plRefresh, rlRefresh, cityRefresh, flagRefresh]); const renderOrder = useMemo(() => { const showMap = { 1: isShowFeature, 2: isShowRoles, 3: isShowFlag, 4: isShowPolicy, 5: isShowCity && useType !== 'operation', }; return applyOrder?.filter((k) => showMap[Number(k)] ?? true) ?? []; }, [applyOrder, isShowCity, isShowFeature, isShowFlag, isShowPolicy, isShowRoles, useType]); useEffect(() => { if (!tagKey || !renderOrder.includes(Number(tagKey))) { const [key] = renderOrder; if (key) setTagKey?.(String(key)); } }, [renderOrder, setTagKey, tagKey]); useDomLayoutEffect(() => { form?.setFieldsValue({ features: mergedValues.features, policies: mergedValues.policies, roles: mergedValues.roles, cities: mergedValues.cities, flags: mergedValues.flags, role: mergedValues.role, }); }, [mergedValues, form]); useEffect(() => { if (useType === 'operation') { setFeatureCityIds?.(initFeatureCityIds || []); } else if (useType === 'multiple') { const filterData = filterFeatureCityIds(initFeatureCityIds, oldFeatureCityIds); setFeatureCityIds?.([...(oldFeatureCityIds || []), ...filterData]); } }, [oldFeatureCityIds, initFeatureCityIds, setFeatureCityIds, useType]); if ( !isAllowApplyFeature && !isAllowApplyFlag && !isAllowApplyPolicy && !isAllowApplyRole && !isAllowApplyCity ) { return ( ); } const tabItemMap = { 1: () => { // 功能权限 return ( ); }, 2: () => { // 角色权限 return ( ); }, 3: () => { // 数据权限 return ( ); }, 4: () => { // 策略权限 return ( ); }, 5: () => { // 城市权限 // 单个应用权限申请暂时隐藏城市权限 return ( ); }, }; return ( {renderOrder.map((k) => tabItemMap[Number(k)]?.())} ); }; export default Detail;