| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654 | /* * << * Davinci * == * Copyright (C) 2016 - 2017 EDP * == * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * >> */import {  call,  all,  put,  fork,  select,  takeLatest,  takeEvery} from 'redux-saga/effects'import omit from 'lodash/omit'import { ActionTypes } from './constants'import { DashboardActions, DashboardActionType } from './actions'import {  makeSelectCurrentDashboard,  makeSelectWidgets,  makeSelectItemRelatedWidget,  makeSelectItemInfo,  makeSelectCurrentItems} from './selectors'import {  makeSelectGlobalControlPanelFormValues,  makeSelectLocalControlPanelFormValues} from 'containers/ControlPanel/selectors'import { makeSelectFormedViews } from '../View/selectors'import {  getRequestParams,  getRequestBody,  getCurrentControlValues,  getUpdatedPagination,  getInitialPagination} from './util'import {  IDashboardDetailRaw,  IDashboardConfig,  IDashboardItemInfo,  IDashboard,  IQueryConditions,  IDataDownloadStatistic,  IDashboardItem} from './types'import {  IGlobalControlConditionsByItem,  IGlobalControlConditions,  ILocalControlConditions} from 'app/components/Control/types'import { IWidgetFormed } from '../Widget/types'import { IFormedViews } from '../View/types'import { DownloadTypes } from '../App/constants'import { dashboardConfigMigrationRecorder } from 'app/utils/migrationRecorders'import { ControlPanelTypes } from 'app/components/Control/constants'import { RenderType } from '../Widget/components/Widget'import { CancelTokenSource } from 'axios'import request from 'utils/request'import { errorHandler, getErrorMessage } from 'utils/util'import { message } from 'antd'import api from 'utils/api'import { operationWidgetProps } from 'components/DataDrill/abstract/widgetOperating'export function* getDashboardDetail(action: DashboardActionType) {  if (action.type !== ActionTypes.LOAD_DASHBOARD_DETAIL) {    return  }  const { dashboardDetailLoaded, loadDashboardDetailFail } = DashboardActions  const { portalId, dashboardId } = action.payload  try {    const result = yield call(      request,      `${api.portal}/${portalId}/dashboards/${dashboardId}`    )    const {      relations: items,      views,      config,      ...rest    } = result.payload as IDashboardDetailRaw    const parsedConfig: IDashboardConfig = JSON.parse(config || '{}')    const dashboard = {      ...rest,      config: dashboardConfigMigrationRecorder(parsedConfig)    }    const widgets: IWidgetFormed[] = yield select(makeSelectWidgets())    operationWidgetProps.widgetIntoPool(widgets)    const formedViews: IFormedViews = views.reduce((obj, view) => {      obj[view.id] = {        ...view,        model: JSON.parse(view.model || '{}'),        variable: JSON.parse(view.variable || '[]')      }      return obj    }, {})    yield put(dashboardDetailLoaded(dashboard, items, widgets, formedViews))  } catch (err) {    yield put(loadDashboardDetailFail())    errorHandler(err)  }}export function* addDashboardItems(action: DashboardActionType) {  if (action.type !== ActionTypes.ADD_DASHBOARD_ITEMS) {    return  }  const { dashboardItemsAdded, addDashboardItemsFail } = DashboardActions  const { portalId, items, resolve } = action.payload  try {    const result = yield call(request, {      method: 'post',      url: `${api.portal}/${portalId}/dashboards/${items[0].dashboardId}/widgets`,      data: items    })    const widgets: IWidgetFormed[] = yield select(makeSelectWidgets())    const formedViews: IFormedViews = yield select(makeSelectFormedViews())    yield put(dashboardItemsAdded(result.payload, widgets, formedViews))    resolve(result.payload)  } catch (err) {    yield put(addDashboardItemsFail())    errorHandler(err)  }}export function* editDashboardItem(action: DashboardActionType) {  if (action.type !== ActionTypes.EDIT_DASHBOARD_ITEM) {    return  }  const { dashboardItemEdited, editDashboardItemFail } = DashboardActions  const { portalId, item, resolve } = action.payload  try {    yield call(request, {      method: 'put',      url: `${api.portal}/${portalId}/dashboards/widgets`,      data: [item]    })    yield put(dashboardItemEdited(item))    resolve()  } catch (err) {    yield put(editDashboardItemFail())    errorHandler(err)  }}export function* editDashboardItems(action: DashboardActionType) {  if (action.type !== ActionTypes.EDIT_DASHBOARD_ITEMS) {    return  }  const { dashboardItemsEdited, editDashboardItemsFail } = DashboardActions  const { portalId, items } = action.payload  try {    yield call(request, {      method: 'put',      url: `${api.portal}/${portalId}/dashboards/widgets`,      data: items    })    yield put(dashboardItemsEdited(items))  } catch (err) {    yield put(editDashboardItemsFail())    errorHandler(err)  }}export function* deleteDashboardItem(action: DashboardActionType) {  if (action.type !== ActionTypes.DELETE_DASHBOARD_ITEM) {    return  }  const { dashboardItemDeleted, deleteDashboardItemFail } = DashboardActions  const { id, resolve } = action.payload  try {    yield call(request, {      method: 'delete',      url: `${api.portal}/dashboards/widgets/${id}`    })    yield put(dashboardItemDeleted(id))    if (resolve) {      resolve()    }  } catch (err) {    yield put(deleteDashboardItemFail())    errorHandler(err)  }}function* getData(  renderType: RenderType,  itemId: number,  queryConditions: Partial<IQueryConditions>,  cancelTokenSource: CancelTokenSource,  resetPagination?: boolean) {  const {    dashboardItemDataLoaded,    loadDashboardItemDataFail  } = DashboardActions  const itemInfo: IDashboardItemInfo = yield select((state) =>    makeSelectItemInfo()(state, itemId)  )  const relatedWidget: IWidgetFormed = yield select((state) =>    makeSelectItemRelatedWidget()(state, itemId)  )  const requestParams = getRequestParams(    relatedWidget,    itemInfo.queryConditions,    renderType === 'flush',    queryConditions  )  if (resetPagination) {    const initialPagination = getInitialPagination(relatedWidget)    if (initialPagination) {      const { pageNo, pageSize } = initialPagination      requestParams.pagination = {        ...requestParams.pagination,        pageNo,        pageSize      }    }  }  try {    const result = yield call(request, {      method: 'post',      url: `${api.view}/${relatedWidget.viewId}/getdata`,      data: getRequestBody(requestParams),      cancelToken: cancelTokenSource.token    })    result.payload = result.payload || {}    const { payload } = result    payload.resultList = payload.resultList || []    requestParams.pagination = getUpdatedPagination(      requestParams.pagination,      result.payload    )    yield put(      dashboardItemDataLoaded(        renderType,        itemId,        requestParams,        result.payload,        {          ...requestParams,          widget: relatedWidget        }      )    )  } catch (err) {    yield put(loadDashboardItemDataFail(itemId, getErrorMessage(err)))  }}export function* getDashboardItemData(action: DashboardActionType) {  if (action.type !== ActionTypes.LOAD_DASHBOARD_ITEM_DATA) {    return  }  const {    renderType,    itemId,    queryConditions,    cancelTokenSource  } = action.payload  yield getData(renderType, itemId, queryConditions, cancelTokenSource)}export function* getBatchDataWithControlValues(action: DashboardActionType) {  if (action.type !== ActionTypes.LOAD_BATCH_DATA_WITH_CONTROL_VALUES) {    return  }  const { type, itemId, formValues, cancelTokenSource } = action.payload  const formedViews: IFormedViews = yield select(makeSelectFormedViews())  const currentItems: IDashboardItem[] = yield select(makeSelectCurrentItems())  if (type === ControlPanelTypes.Global) {    const currentDashboard: IDashboard = yield select(      makeSelectCurrentDashboard()    )    const globalControlFormValues = yield select(      makeSelectGlobalControlPanelFormValues()    )    const globalControlConditionsByItem = getCurrentControlValues(      type,      currentDashboard.config.filters,      formedViews,      globalControlFormValues,      formValues,      currentItems    )    const globalControlConditionsByItemEntries: Array<[      string,      IGlobalControlConditions    ]> = Object.entries(      globalControlConditionsByItem as IGlobalControlConditionsByItem    )    while (globalControlConditionsByItemEntries.length) {      const [itemId, queryConditions] = globalControlConditionsByItemEntries[0]      yield fork(        getData,        'clear',        Number(itemId),        queryConditions,        cancelTokenSource,        true      )      globalControlConditionsByItemEntries.shift()    }  } else {    const relatedWidget: IWidgetFormed = yield select((state) =>      makeSelectItemRelatedWidget()(state, itemId)    )    const localControlFormValues = yield select((state) =>      makeSelectLocalControlPanelFormValues()(state, itemId)    )    const localControlConditions = getCurrentControlValues(      type,      relatedWidget.config.controls,      formedViews,      localControlFormValues,      formValues    )    yield getData(      'clear',      itemId,      localControlConditions as ILocalControlConditions,      cancelTokenSource,      true    )  }}function getDownloadInfo(  type: DownloadTypes,  itemId: number,  itemInfo: IDashboardItemInfo,  relatedWidget: IWidgetFormed,  formedViews: IFormedViews,  localControlFormValues: object,  globalControlConditions: IGlobalControlConditions): IDataDownloadStatistic {  const localControlConditions = getCurrentControlValues(    ControlPanelTypes.Local,    relatedWidget.config.controls,    formedViews,    localControlFormValues  )  const requestParams = getRequestParams(    relatedWidget,    itemInfo.queryConditions,    false,    {      ...globalControlConditions,      ...localControlConditions    }  )  const id = type === DownloadTypes.Dashboard ? itemId : relatedWidget.id  return {    id,    param: {      ...getRequestBody(requestParams),      flush: true,      pageNo: 0,      pageSize: 0    },    itemId,    widget: relatedWidget  }}export function* initiateDownloadTask(action: DashboardActionType) {  if (action.type !== ActionTypes.INITIATE_DOWNLOAD_TASK) {    return  }  const { DownloadTaskInitiated, initiateDownloadTaskFail } = DashboardActions  const { type, itemId } = action.payload  const currentDashboard: IDashboard = yield select(    makeSelectCurrentDashboard()  )  const formedViews: IFormedViews = yield select(makeSelectFormedViews())  const globalControlFormValues = yield select(    makeSelectGlobalControlPanelFormValues()  )  const currentItems = yield select(makeSelectCurrentItems())  const globalControlConditionsByItem: IGlobalControlConditionsByItem = getCurrentControlValues(    ControlPanelTypes.Global,    currentDashboard.config.filters,    formedViews,    globalControlFormValues,    null,    currentItems  )  let id = action.payload.id  const downloadInfo: IDataDownloadStatistic[] = []  if (type === DownloadTypes.Dashboard) {    const itemIds = currentItems.map((item) => item.id)    while (itemIds.length) {      const itemId = itemIds[0]      const globalControlConditions = globalControlConditionsByItem[itemId]      const itemInfo: IDashboardItemInfo = yield select((state) =>        makeSelectItemInfo()(state, itemId)      )      const relatedWidget: IWidgetFormed = yield select((state) =>        makeSelectItemRelatedWidget()(state, itemId)      )      const localControlFormValues = yield select((state) =>        makeSelectLocalControlPanelFormValues()(state, itemId)      )      downloadInfo.push(        getDownloadInfo(          type,          itemId,          itemInfo,          relatedWidget,          formedViews,          localControlFormValues,          globalControlConditions        )      )      itemIds.shift()    }  } else {    const itemInfo: IDashboardItemInfo = yield select((state) =>      makeSelectItemInfo()(state, itemId)    )    const relatedWidget: IWidgetFormed = yield select((state) =>      makeSelectItemRelatedWidget()(state, itemId)    )    const localControlFormValues = yield select((state) =>      makeSelectLocalControlPanelFormValues()(state, itemId)    )    id = relatedWidget.id    downloadInfo.push(      getDownloadInfo(        type,        itemId,        itemInfo,        relatedWidget,        formedViews,        localControlFormValues,        globalControlConditionsByItem[itemId]      )    )  }  try {    yield call(request, {      method: 'POST',      url: `${api.download}/submit/${type}/${id}`,      data: downloadInfo.map((d) => omit(d, 'widget', 'itemId'))    })    message.success('下载任务创建成功!')    yield put(DownloadTaskInitiated(type, downloadInfo, itemId))  } catch (err) {    yield put(initiateDownloadTaskFail(err, type, itemId))    errorHandler(err)  }}export function* getDashboardShareLink(action: DashboardActionType) {  if (action.type !== ActionTypes.LOAD_DASHBOARD_SHARE_LINK) {    return  }  const {    dashboardAuthorizedShareLinkLoaded,    dashboardShareLinkLoaded,    dashboardPasswordShareLinkLoaded,    loadDashboardShareLinkFail  } = DashboardActions  const {    id,    mode,    permission,    expired,    roles,    viewers  } = action.payload.params  let requestData = null  switch (mode) {    case 'AUTH':      requestData = { mode, expired, permission, roles, viewers }      break    case 'PASSWORD':    case 'NORMAL':      requestData = { mode, expired }      break    default:      break  }  try {    const result = yield call(request, {      method: 'post',      url: `${api.portal}/dashboards/${id}/share`,      data: requestData    })    const { token, password } = result.payload    switch (mode) {      case 'AUTH':        yield put(dashboardAuthorizedShareLinkLoaded(token))        break      case 'PASSWORD':        yield put(dashboardPasswordShareLinkLoaded(token, password))        break      case 'NORMAL':        yield put(dashboardShareLinkLoaded(token))        break      default:        break    }  } catch (err) {    yield put(loadDashboardShareLinkFail())    errorHandler(err)  }}export function* getWidgetShareLink(action: DashboardActionType) {  if (action.type !== ActionTypes.LOAD_WIDGET_SHARE_LINK) {    return  }  const {    widgetAuthorizedShareLinkLoaded,    widgetPasswordShareLinkLoaded,    widgetShareLinkLoaded,    loadWidgetShareLinkFail  } = DashboardActions  const {    id,    itemId,    mode,    expired,    permission,    roles,    viewers  } = action.payload.params  let requestData = null  switch (mode) {    case 'AUTH':      requestData = { mode, expired, permission, roles, viewers }      break    case 'PASSWORD':    case 'NORMAL':      requestData = { mode, expired }      break    default:      break  }  try {    const result = yield call(request, {      method: 'post',      url: `${api.widget}/${id}/share`,      data: requestData    })    const { token, password } = result.payload    switch (mode) {      case 'AUTH':        yield put(widgetAuthorizedShareLinkLoaded(token, itemId))        break      case 'PASSWORD':        yield put(widgetPasswordShareLinkLoaded(token, password, itemId))        break      case 'NORMAL':        yield put(widgetShareLinkLoaded(token, itemId))        break      default:        break    }  } catch (err) {    yield put(loadWidgetShareLinkFail(itemId))    errorHandler(err)  }}export function* getWidgetCsv(action: DashboardActionType) {  if (action.type !== ActionTypes.LOAD_WIDGET_CSV) {    return  }  const { widgetCsvLoaded, loadWidgetCsvFail } = DashboardActions  const { itemId, widgetId, requestParams } = action.payload  // @TODO combine widget static filters with local filters  const {    filters,    tempFilters,    linkageFilters,    globalFilters,    variables,    linkageVariables,    globalVariables,    ...rest  } = requestParams  try {    const path = yield call(request, {      method: 'post',      url: `${api.widget}/${widgetId}/excel`,      data: {        ...rest,        filters: filters          .concat(tempFilters)          .concat(linkageFilters)          .concat(globalFilters),        params: variables.concat(linkageVariables).concat(globalVariables)      }    })    yield put(widgetCsvLoaded(itemId))    location.href = path.payload    // location.href = `data:application/octet-stream,${encodeURIComponent(asyncData)}`  } catch (err) {    yield put(loadWidgetCsvFail(itemId))    errorHandler(err)  }}export default function* rootDashboardSaga() {  yield all([    takeLatest(ActionTypes.LOAD_DASHBOARD_DETAIL, getDashboardDetail),    takeEvery(ActionTypes.ADD_DASHBOARD_ITEMS, addDashboardItems),    takeEvery(ActionTypes.EDIT_DASHBOARD_ITEM, editDashboardItem),    takeEvery(ActionTypes.EDIT_DASHBOARD_ITEMS, editDashboardItems),    takeEvery(ActionTypes.DELETE_DASHBOARD_ITEM, deleteDashboardItem),    takeEvery(ActionTypes.LOAD_DASHBOARD_ITEM_DATA, getDashboardItemData),    takeEvery(      ActionTypes.LOAD_BATCH_DATA_WITH_CONTROL_VALUES,      getBatchDataWithControlValues    ),    takeEvery(ActionTypes.INITIATE_DOWNLOAD_TASK, initiateDownloadTask),    takeLatest(ActionTypes.LOAD_DASHBOARD_SHARE_LINK, getDashboardShareLink),    takeLatest(ActionTypes.LOAD_WIDGET_SHARE_LINK, getWidgetShareLink),    takeLatest(ActionTypes.LOAD_WIDGET_CSV, getWidgetCsv)  ])}
 |