123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771 |
- 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:<ActionIcon trigger="contextMenu" items={items} children={record.title} onSelect={onRightSelect} tooltip="右键编辑"/>,
- 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:[
- <ActionIcon
- key={2}
- items={ACTION_TYPES.CHECK.filter(opt=>item.isPublish?opt.key!=="publish":opt.key!=="disPublish")}
- onSelect={(event)=>onExtraSelect(event,item)}
- >
- <Button type="link" ><MoreOutlined rotate={90} style={{fontSize:25}}/></Button>
- </ActionIcon>
- ],
- content:(
- <CustomDescriptions column={5}>
- <Descriptions.Item label={t("formItem.domain")}>{item.domainName}</Descriptions.Item>
- <Descriptions.Item label={t("formItem.metricCode")}>{item.bizName}</Descriptions.Item>
- <Descriptions.Item label={t("formItem.sensitiveLevel")} contentStyle={{color:SEN_COLOR_LEVEL[item.sensitiveLevel]}} children={SENSITIVE[item.sensitiveLevel]}/>
- <Descriptions.Item label={t("formItem.lastVersionNo")}>无</Descriptions.Item>
- <Descriptions.Item label={t("formItem.status")} contentStyle={{color:STATUS_COLOR_LEVEL[item.status]}} children={STATUS_TYPE[item.status]}/>
- <Descriptions.Item label={t("formItem.caliber")}>{item.alias}</Descriptions.Item>
- <Descriptions.Item label={t("formItem.director")}>{item.createdBy}</Descriptions.Item>
- <Descriptions.Item label={t("formItem.creator")}>{item.createdBy}</Descriptions.Item>
- <Descriptions.Item label={t("formItem.createDate")}>{moment(item.createdAt).format('YYYY-MM-DD hh:mm:ss')}</Descriptions.Item>
- <Descriptions.Item label={t("formItem.isPublish")} contentStyle={{color:STATUS_COLOR_LEVEL[item.isPublish]}} children={PUBLISH_TYPE[item.isPublish]}/>
- </CustomDescriptions>
- )
- })),[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 (
- <ProCard gutter={8} ghost>
- {/** 主题域编辑面板 */}
- <DomainForm
- open={domainModalOpen}
- onCancel={handelDomainFormCancel}
- onFinish={domainFormSubmit}
- values={commonRef.current.treeSelect}
- />
- {/** 创建指标面板 */}
- <IndexCreator
- handleCancel={handelCreatorClose}
- initialValues={commonRef.current.indexCreator}
- onFinish={onCreatorFinish}
- open={openCreator}
- />
- {/** 指标明细面板 */}
- <IndexDetail
- admin={true}
- title={t("title.metricDetail")}
- open={openDetail}
- onClose={onDetailClose}
- values={commonRef.current.indexDetail}
- persistence={commonRef.current.persistenceConfig}
- onCopy={onExtraSelect}
- />
- {/** 主题授权管理面板 */}
- <AuthorizationPanel
- type={commonRef.current.datatype}
- open={openAuth}
- onCancel={onAuthPanelClose}
- onDelete={onAuthDelete}
- onFinish={onDomainAuthFinish}
- values={
- commonRef.current.datatype===TYPE_ENUM.DOMAIN
- ? commonRef.current.treeSelect
- : commonRef.current.metricSelect
- }
- />
- {/** 指标批量授权面板 */}
- <VolumeAuthPanel
- open={openIndexAuth}
- onCancel={onIndexAuthPanelClose}
- onChange={onAuthConfigChange}
- onSubmit={onVolumeAuth}
- values={commonRef.current.indexChosen}
- />
- {/** 左侧的主题与目录 */}
- <ProCard
- bordered
- headerBordered
- colSpan="20%"
- title={t("title.domain")}
- style={{height:'85vh'}}
- // extra={<ExtraLink onClick={handelDomainFormOpen}>+{t("button.domainCreate")}</ExtraLink>}
- >
- <TreeMenu
- onRightClick={onRightClick}
- onSelect={onSelect}
- treeData={buildTree}
- onSearch={onSearch}
- />
- </ProCard>
- {/** 主面板 */}
- <ProCard bordered headerBordered title={subTile} bodyStyle={{height:'80vh',display:"flex",flexDirection:'column'}} style={{height:'85vh'}}>
- {/** 筛选栏 */}
- <div>
- <IndexFilterForm onModelSelect={onModelSelect} onFinish={onFilterFormFinish} ref={filterRef}/>
- <Span>
- <CustomCheckbox onChange={(e)=>cardListRef?.current?.onAllCheck(e.target.checked)}>全选</CustomCheckbox>
- <CustomButton onClick={onIndexAuthPanelOpen}>{t("button.batchAuth")}</CustomButton>
- <CustomButton onClick={onVolumePublish}>{t("button.batchPublish")}</CustomButton>
- </Span>
- <Divider style={{margin:'6px 0'}}/>
- </div>
- {/** 指标列表 */}
- <div style={{flexShrink: 1,overflow:"hidden"}}>
- <CheckCardList
- ref={cardListRef}
- type="checkBox"
- tooltip={t("placeholder.doubleClick")}
- options={cardOption}
- onSelect={onCardSelect}
- onDoubleClick={onCardDoubleClick}
- onChecked={onCardChecked}
- onCreate={()=>{filterRef.current.onModelSelectOpen()}}
- />
- </div>
- </ProCard>
- </ProCard>
- )
- }
- 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;
- }
- `;
|