import {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import moment from "moment"; import {ProCard} from '@ant-design/pro-components'; import {Button, Checkbox, Descriptions, Divider, message, Tag} from 'antd' import {styled} from 'styled-components' import {CheckCardList} from '../../components/CheckCardList.jsx'; import {TreeMenu} from '../../components/TreeMenu'; import {MoreOutlined} from '@ant-design/icons' import {DomainForm} from "../ModalManage/components/DomainForm"; import {ActionIcon} from "../../components/ActionIcon"; import {IndexCreator} from "./components/IndexCreator"; import {IndexDetail} from "./components/IndexDetail"; import {DEFINE_TYPE, FORM_TYPE, SEN_COLOR_LEVEL, SENSITIVE, STATUS_COLOR_LEVEL} from "./constants"; import {IndexFilterForm} from "./components/IndexFilterForm"; import {AUTH_TYPE, PUBLISH_TYPE, STATUS_TYPE, TYPE_ENUM} from "../../constants"; import {ACTION_TYPES} from "../../components/WorkFlow/constants"; import {AuthorizationPanel} from "./components/AuthorizationPanel"; import {VolumeAuthPanel} from "./components/VolumeAuthPanel"; import {useAppDispatch, useAppSelector} from "../../../redux/configureStore"; import {selectDomains, selectIndexLibs} from "../MainPage/slice/selectors"; import {bizConditionToSQL} from "../../../utils/listTools"; import { batchPublish, batchRoleAuth, batchUnPublish, createDomain, createMetric, deleteMetric, getAuthList, getDomains, getIndexByConditions, getIndexDetail, getPersistenceConfig, getRoles, persistenceConfig, queryDimensions, roleAuthDelete, roleAuthGrant, updateMetric } from "../MainPage/slice/thunks"; import useI18NPrefix from "../../hooks/useI18NPrefix"; // TODO // 1.指标SQL创建AS中文, // 2.创建指标退出时SQL字段配置重置, // 5.批量设置、指标应用权限 // 8.派生指标自动带入来自指标的维度 export const IndexDefine = () => { const t = useI18NPrefix('global'); const dispatch = useAppDispatch(); /** 打开主题域表单 */ const [domainModalOpen, setDomainModalOpen] = useState(false); /** 指标创建表单对话框打开状态 */ const [openCreator, setOpenCreator] = useState(false); /** 指标卡片详情 */ const [openDetail,setOpenDetail] = useState(false); /** 授权面板 */ const [openAuth,setOpenAuth] = useState(false); /** 指标批量授权 */ const [openIndexAuth,setOpenIndexAuth] = useState(false); /** 当前主题名称 */ const [subTile,setSubTitle] = useState(t("title.baseInfo")); /** 筛选的Ref */ const filterRef = useRef(null); /** 卡片列表的Ref,用于全选*/ const cardListRef = useRef(null); /** 数据缓存*/ const commonRef = useRef({ treeSelect: { id:0, name:t("title.models") }, indexCreator:{}, indexDetail:{}, datatype:'', metricSelect:{} }); /** 主题域 */ const domains = useAppSelector(selectDomains); /** 指标列表 */ const indexLib = useAppSelector(selectIndexLibs); useEffect(()=>{ /** 获取主题域 */ dispatch(getDomains()); dispatch(getRoles({})); },[]); /** 右键打开情景框 */ const onRightClick=useCallback(({event})=>{ event.preventDefault(); },[]); /** 右键情景框选择后回调 */ const onRightSelect = (event)=>{ if (event.key==='update'){ setDomainModalOpen(true) } if (event.key==='auth'){ commonRef.current.datatype = TYPE_ENUM.DOMAIN setOpenAuth(true) } }; /** 主题域表单提交-取消 */ const handelDomainFormCancel=useCallback(()=>{ setDomainModalOpen(false) },[]); /** 主题域表单-打开 */ // const handelDomainFormOpen=useCallback(()=>{ // setDomainModalOpen(true) // },[]); /** 主题域表单--提交 */ const domainFormSubmit = useCallback((values) => { const {parentId} = values; const params = { ...values, parentId: parentId ? parentId : 0 } dispatch( createDomain({ params, resolve(){ message.success(t("validation.success")); dispatch(getDomains()); setDomainModalOpen(false); } }) ); },[]); /** 左侧主题树目录 */ const buildTree = useMemo(()=>{ const items = [ { key: 'update', label: t("operation.update") }, { key: 'auth', label: t("operation.auth") }, { key: 'remove', label: t("operation.remove") } ]; function insertKey(arr) { let temp = []; for (const i in arr) { const record = arr[i]; const {children} = record; let item = { key: record.id, title:, data: record, isLeaf: children?.length===0, } if (children?.length>0) { item.children = insertKey(children) } temp.push(item) } return temp } return insertKey(domains) },[domains]); /** 侧边栏主题域钩子 */ const onSelect = useCallback((keys, info) => { const {node} = info; if (commonRef.current.treeSelect?.id!==node?.data?.id){ dispatch(getIndexByConditions({ params:{ domainIds: keys, current:1, pageSize:999 }, })) commonRef.current.treeSelect=node.data; } },[]); /** 侧边栏主题域搜索钩子 */ const onSearch = useCallback(() => {},[]); /** 筛选表单提交 */ const onFilterFormFinish = useCallback((filter)=>{ dispatch(getIndexByConditions({ params:{ domainIds: [commonRef.current.treeSelect.id], ...filter, current:1, pageSize:999 }, })) },[]); /** 选择创建模式-回调 */ const onModelSelect = useCallback((info) => { //setOpenCreator(true) if (commonRef.current.treeSelect.id){ commonRef.current.indexCreator.type=info.value commonRef.current.indexCreator.sensitiveLevel="0" commonRef.current.indexCreator.invokeMethod='AUTO' commonRef.current.indexCreator.decimalPlaces = 2 commonRef.current.indexCreator.domainId = commonRef.current.treeSelect.id commonRef.current.indexCreator.dataFormatType = 'DECIMAL' setOpenCreator(true) }else{ message.error(t("validation.domain")) } }, []); /** 指标创建表单-提交 */ const onCreatorFinish = useCallback((values)=>{ try { const { id,domainId,type,decimalPlaces,relateDimension,dateDimId, measure,operations,sensitiveLevel,filters,formIndex,incrementPeriod, invokeMethod, periodId,runCycleCode,measureExpr, way, startTime,syncToBI } = values; let drillDownDimensions = []; if (relateDimension){ dateDimId && drillDownDimensions.push({ dimensionId:dateDimId, necessary:false, inheritedFromModel:false }) relateDimension.forEach(v=> drillDownDimensions.push({ dimensionId:v, necessary:false, inheritedFromModel:false })) } const bizCondition = bizConditionToSQL(filters); // 部分字段需再次处理 let params = { ...values, alias:values?.name, sensitiveLevel:parseInt(sensitiveLevel), typeEnum:TYPE_ENUM.METRIC, dataFormat:{ needMultiply100:false, decimalPlaces:decimalPlaces?decimalPlaces:2, }, relateDimension:{ drillDownDimensions }, metricDefineType:DEFINE_TYPE[type], statisticsPeriod:periodId } // 派生指标 if (type===FORM_TYPE.DERIVED.value){ const formIndexObj=JSON.parse(formIndex); params.operations=formIndexObj?.operations params.ext = {filters} params.metricDefineByMeasureParams={ measures:[ { agg:formIndexObj?.operations, bizName:formIndexObj.bizName, constraint:measureExpr.expr||bizCondition, } ], expr:formIndexObj.expr, filterSql:"" } } // 派生指标 if (type!==FORM_TYPE.COMPOSITE.value) { params.metricDefineByMetricParams = {} } // 原子指标 if (type===FORM_TYPE.ATOMIC.value) { if (measureExpr.expr){ params.metricDefineType='CUSTOM' params.metricDefineByMeasureParams = {} params.metricDefineByFieldParams = { fields:measureExpr.metrics.map(item=>({fieldName:item.bizName,agg:'SUM'})), expr:measureExpr.expr, filterSql:"" } }else { params.metricDefineByMeasureParams={ measures:[ { agg:operations, bizName:measure, constraint:"", } ], expr:measure, filterSql:"" } } } // 更新、创建指标 if (id){ dispatch(updateMetric({ params, resolve({id}){ if (id){ message.success(t("validation.success")); dispatch(getIndexByConditions({ params:{ domainIds: [domainId], current:1, pageSize:999 }, })) dispatch(persistenceConfig({ params:{ metricId:id, runCycleCode, tableName:'index_metric_'+id, defaultConfig:JSON.stringify({ unit:1, period:incrementPeriod, type:invokeMethod, startTime, way, syncToBI }), } })) setOpenCreator(false) } } })) }else { dispatch(createMetric({ params, resolve({id}){ if (id){ message.success(t("validation.success")); dispatch(getIndexByConditions({ params:{ domainIds: [commonRef.current.treeSelect.id], current:1, pageSize:999 }, })) dispatch(persistenceConfig({ params:{ metricId:id, runCycleCode, tableName:'index_metric_'+id, defaultConfig:JSON.stringify({ metricTypeDefaultConfig:{ timeDefaultConfig:{ timeMode:"RECENT", unit:1, period:incrementPeriod, type:invokeMethod, startTime, way } }, }), } })) setOpenCreator(false) } } })) } }catch (error) { throw error; } },[]); /** 双击打开详情 */ const onCardDoubleClick = useCallback((event)=>{ const {value,title,tag} = event; dispatch(getIndexDetail({ id:value, resolve(detail){ dispatch(queryDimensions({ params:{ ids:detail.drillDownDimensions.map(v=>v.dimensionId), }, resolve(data){ commonRef.current.indexDetail= { ...detail, title, tag, dimensions:data.list } setOpenDetail(true) } })) dispatch(getPersistenceConfig({ id:value, resolve(data){ commonRef.current.persistenceConfig = data } })) } })) },[]); /** 关闭详情 */ const onDetailClose = useCallback(()=>{ setOpenDetail(false) },[]); /** 查询指标 */ const getMetrics = (domainIds)=>{ dispatch(getIndexByConditions({ params:{ domainIds:[domainIds], current:1, pageSize:999 }, })) } /** 卡片Extra选项回调 */ const onExtraSelect =(event,item)=>{ const { id, domainId, title, tag, type, relateDimension, sensitiveLevel, metricDefineByMeasureParams, metricDefineByMetricParams, metricDefineType, dateDimId } = item; // 编辑指标 if (event.key==="update"){ let bizName if (type===FORM_TYPE.ATOMIC.value){ // 原子指标回显维度 if (metricDefineType==='MEASURE'){ const measureParams = metricDefineByMeasureParams.measures[0] bizName = measureParams.bizName } }else if (type===FORM_TYPE.COMPOSITE.value){ // 其他指标回显维度 const measureParams = metricDefineByMetricParams.metrics[0] bizName = measureParams.bizName } commonRef.current.indexCreator = { ...item, sensitiveLevel:`${sensitiveLevel}`, measure:bizName, relateDimension:relateDimension.drillDownDimensions.filter((item)=>item.dimensionId!==dateDimId).map(item=>item.dimensionId) } setOpenCreator(true) } // 指标授权 if (event.key==="auth"){ commonRef.current.datatype=TYPE_ENUM.METRIC; commonRef.current.metricSelect=item; setOpenAuth(true) } // 删除指标 if (event.key==="remove"){ dispatch(deleteMetric({ id, resolve(){ if (domainId){ dispatch(getIndexByConditions({ params:{ domainIds: [domainId], current:1, pageSize:999 }, })) } } })) } // 指标详情 if (event.key==="detail"){ dispatch(getIndexDetail({ id, resolve(data){ commonRef.current.indexDetail= {...data,title,tag} setOpenDetail(true) } })) } // 取消发布 if (event.key==="disPublish"){ dispatch(batchUnPublish({ params:{ ids:[id], type:"DELETE", }, resolve(){ getMetrics(domainId) message.success(t("validation.success")); } })) } // 发布指标 if (event.key==="publish"){ dispatch(batchPublish({ params:{ ids:[id], status:1, type:"ADD", }, resolve(data){ if (data){ getMetrics(domainId) message.success(t("validation.success")); }else { message.error(t("validation.failed")); } } })) } } /** 指标列表 */ const cardOption = useMemo(()=> (indexLib||[]).map((item)=>({ title: item.name, tag:FORM_TYPE[item.type], value:item.id, description:item.description, extra:[ item.isPublish?opt.key!=="publish":opt.key!=="disPublish")} onSelect={(event)=>onExtraSelect(event,item)} > ], content:( {item.domainName} {item.bizName} 无 {item.alias} {item.createdBy} {item.createdBy} {moment(item.createdAt).format('YYYY-MM-DD hh:mm:ss')} ) })),[indexLib]) /** 指标列表 */ const onCardSelect = useCallback((e)=>setSubTitle(e),[]) /** 创建指标面板-关闭 */ const handelCreatorClose = useCallback(() => { commonRef.current.indexCreator = {} setOpenCreator(false) }, []); /** 卡片选中 */ const onCardChecked = useCallback((list)=>{ commonRef.current.indexChosen = list.map(item=>({id:item.value,value:item.value,label:item.title})) },[]); /** 关闭授权面板 */ const onAuthPanelClose = useCallback(()=>setOpenAuth(false),[]) /** 关闭授权面板 */ const onIndexAuthPanelClose = useCallback(()=>setOpenIndexAuth(false),[]) /** 关闭授权面板 */ const onIndexAuthPanelOpen = useCallback(()=>setOpenIndexAuth(true),[]) /** 批量授权回调*/ const onAuthConfigChange=useCallback(()=>{},[]) /** 批量发布按钮回调*/ const onVolumePublish = useCallback(()=>{ const {indexChosen,treeSelect} = commonRef.current const params = { ids:indexChosen.map(item=>item.id), status:1, type:"ADD" } dispatch(batchPublish({ params, resolve(data){ if (data){ getMetrics(treeSelect.id) message.success(t("validation.success")); }else { message.error(t("validation.failed")); } } })) },[]) /** 获取主题域 */ const onGetAuthList = ()=>{ dispatch(getAuthList({ params:{ dataType:commonRef.current.datatype } })) } /** 主题域授权 */ const onDomainAuthFinish=useCallback((value)=>{ dispatch(roleAuthGrant({ params:value, resolve(){ onGetAuthList() } })) },[]) /** 删除授权 */ const onAuthDelete = useCallback((row)=>{ dispatch(roleAuthDelete({ id:row.roleId, resolve(){ onGetAuthList() } })) },[]) /** 指标批量授权 */ const onVolumeAuth=useCallback((value)=>{ let authType = []; if (value.version){ authType = authType.concat(AUTH_TYPE.ADMIN) } if (value.detail){ authType = authType.concat(AUTH_TYPE.VISIBLE) } if (value.publish){ authType = authType.concat(AUTH_TYPE.PUBLISH) } const params = { dataType: TYPE_ENUM.METRIC, dataIds: (value?.tags||[]).map(item=>item.value), roleIds: (value?.roles||[]).map(item=>item.value), authType, } dispatch(batchRoleAuth({params})) },[]) return ( {/** 主题域编辑面板 */} {/** 创建指标面板 */} {/** 指标明细面板 */} {/** 主题授权管理面板 */} {/** 指标批量授权面板 */} {/** 左侧的主题与目录 */} +{t("button.domainCreate")}} > {/** 主面板 */} {/** 筛选栏 */} cardListRef?.current?.onAllCheck(e.target.checked)}>全选 {t("button.batchAuth")} {t("button.batchPublish")} {/** 指标列表 */} {filterRef.current.onModelSelectOpen()}} /> ) } const Span = styled.span``; const CustomButton = styled(Button)` margin-left: 25px; `; const CustomCheckbox = styled(Checkbox)` margin-left: 25px; `; // const ExtraLink = styled.a` // font-size: ${p=>p.theme.fontSizeLG}px; // ` const CustomDescriptions = styled(Descriptions)` .ant-descriptions-item-content { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } `;