123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- /*
- * <<
- * 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 React, { useEffect, useState, useCallback, useMemo } from 'react'
- import { useSelector, useDispatch } from 'react-redux'
- import { createStructuredSelector } from 'reselect'
- import { RouteComponentWithParams } from 'utils/types'
- import { makeSelectWidgets, makeSelectLoading } from './selectors'
- import { makeSelectCurrentProject } from 'containers/Projects/selectors'
- import { checkNameUniqueAction } from 'containers/App/actions'
- import { WidgetActions } from './actions'
- import Helmet from 'react-helmet'
- import { Link } from 'react-router-dom'
- import {
- Row,
- Col,
- Breadcrumb,
- Icon,
- Button,
- Table,
- Tooltip,
- Popconfirm
- } from 'antd'
- import { ButtonProps } from 'antd/lib/button'
- import { ColumnProps, SorterResult } from 'antd/lib/table'
- import Container, { ContainerTitle, ContainerBody } from 'components/Container'
- import Box from 'components/Box'
- import SearchFilterDropdown from 'app/components/SearchFilterDropdown'
- import CopyModal from './components/CopyModal'
- import utilStyles from 'assets/less/util.less'
- import { useTablePagination } from 'utils/hooks'
- import ModulePermission from 'containers/Account/components/checkModulePermission'
- import { initializePermission } from 'containers/Account/components/checkUtilPermission'
- import { IWidgetBase, IWidgetFormed } from './types'
- import widgetlibs from './config'
- import { IWidgetConfigBase } from './components/Widget'
- const mapStateToProps = createStructuredSelector({
- widgets: makeSelectWidgets(),
- loading: makeSelectLoading(),
- currentProject: makeSelectCurrentProject()
- })
- const columnTitle = {
- name: '组件名称',
- viewName: '数据资产名称'
- }
- const WidgetList: React.FC<RouteComponentWithParams> = (props) => {
- const dispatch = useDispatch()
- const tablePagination = useTablePagination(0)
- const { match, history } = props
- useEffect(() => {
- const projectId = +match.params.projectId
- if (projectId) {
- dispatch(WidgetActions.loadWidgets(projectId))
- }
- }, [])
- const { widgets, loading, currentProject } = useSelector(mapStateToProps)
- const onCheckName = useCallback(
- (widgetName: string, resolve: () => void, reject: (err: string) => void) =>
- dispatch(
- checkNameUniqueAction(
- 'widget',
- { name: widgetName, projectId: currentProject.id },
- resolve,
- reject
- )
- ),
- [currentProject]
- )
- const openCopyModal = useCallback(
- (widget: IWidgetBase) => () => {
- setCopyFromWidget(widget)
- setCopyModalVisible(true)
- },
- []
- )
- const copyWidget = useCallback((widget: IWidgetBase) => {
- dispatch(
- WidgetActions.copyWidget(widget, () => {
- setCopyModalVisible(false)
- })
- )
- }, [])
- const cancelCopy = useCallback(() => {
- setCopyModalVisible(false)
- }, [])
- const toWorkbench = useCallback(
- (widgetId?: number) => () => {
- sessionStorage.removeItem('editWidgetFromDashboard')
- const workbenchUrl = `/project/${match.params.projectId}/widget`
- history.push(widgetId ? `${workbenchUrl}/${widgetId}` : workbenchUrl)
- },
- []
- )
- const onDeleteWidget = useCallback(
- (widgetId: number) => () => {
- dispatch(WidgetActions.deleteWidget(widgetId))
- },
- []
- )
- const [filterText, setFilterText] = useState('')
- const [filterColumnKey, setFilterColumnKey] = useState('')
- const [tableSorter, setTableSorter] = useState<SorterResult<IWidgetBase>>(
- null
- )
- const [copyModalVisible, setCopyModalVisible] = useState(false)
- const [copyFromWidget, setCopyFromWidget] = useState<IWidgetBase>(null)
- const filterWidgets = useMemo(() => {
- if (!Array.isArray(widgets) || !widgets.length) {
- return []
- }
- const regex = new RegExp(filterText, 'gi')
- const filterWidgets = widgets.filter(
- (v) => v.name.match(regex) || v.viewName.match(regex) || v.description.match(regex)
- )
- return filterWidgets
- }, [filterText, widgets])
- const { widgetPermission, AdminButton, EditButton } = useMemo(
- () => ({
- widgetPermission: initializePermission(
- currentProject,
- 'widgetPermission'
- ),
- AdminButton: ModulePermission<ButtonProps>(
- currentProject,
- 'widget',
- true
- )(Button),
- EditButton: ModulePermission<ButtonProps>(
- currentProject,
- 'widget',
- false
- )(Button)
- }),
- [currentProject]
- )
- const searchWidget = useCallback((value: string, dataIndex: string) => {
- setFilterText(value)
- setFilterColumnKey(dataIndex)
- }, [])
- const getFilterProps = (dataIndex: string) => ({
- filterDropdown: ({ setSelectedKeys, selectedKeys }) => (
- <SearchFilterDropdown
- placeholder={columnTitle[dataIndex]}
- value={selectedKeys[0]}
- onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
- onSearch={() => searchWidget(selectedKeys[0], dataIndex)}
- />
- ),
- sortOrder: tableSorter && tableSorter.columnKey === dataIndex ? tableSorter.order : void 0,
- render: (text: string) => {
- const regex = new RegExp(`(${filterText})`, 'gi')
- return (filterText && filterColumnKey === dataIndex ? (
- <span
- dangerouslySetInnerHTML={{
- __html: text.replace(
- regex,
- `<span class='${utilStyles.highlight}'>$1</span>`
- )
- }}
- />
- ) : (
- text
- ))
- }
- })
- const mappingIcon = (widgetConfig: IWidgetConfigBase) => {
- const selectedChart = widgetConfig.selectedChart
- const mode = widgetlibs[widgetConfig.mode]
- return mode[selectedChart - 1].icon
- }
- const columns: Array<ColumnProps<IWidgetFormed>> = [
- {
- title: columnTitle.name,
- dataIndex: 'name',
- sorter: (a, b) => (a.name > b.name ? 1 : -1),
- ...getFilterProps('name'),
- render: (_, record) => (
- <div>
- <i className={`iconfont ${mappingIcon(record.config)}`}></i>
- <span style={{ marginLeft: 8 }}>{record.name}</span>
- </div>
- )
- },
- {
- title: columnTitle.viewName,
- dataIndex: 'viewName',
- sorter: (a, b) => (a.name > b.name ? 1 : -1),
- ...getFilterProps('viewName')
- },
- {
- title: '描述',
- dataIndex: 'description'
- }
- ]
- if (widgetPermission) {
- columns.push({
- title: '操作',
- key: 'action',
- align: 'center',
- width: 145,
- render: (_, record) => (
- <span className='ant-table-action-column'>
- <Tooltip title='复制'>
- <EditButton
- icon='copy'
- shape='circle'
- type='ghost'
- onClick={openCopyModal(record)}
- />
- </Tooltip>
- <Tooltip title='修改' trigger='hover'>
- <EditButton
- icon='edit'
- shape='circle'
- type='ghost'
- onClick={toWorkbench(record.id)}
- />
- </Tooltip>
- <Popconfirm
- title='确定删除?'
- placement='bottom'
- onConfirm={onDeleteWidget(record.id)}
- >
- <Tooltip title='删除'>
- <AdminButton icon='delete' shape='circle' type='ghost' />
- </Tooltip>
- </Popconfirm>
- </span>
- )
- })
- }
- const tableChange = useCallback(
- (_1, _2, sorter: SorterResult<IWidgetBase>) => {
- setTableSorter(sorter)
- },
- []
- )
- return (
- <>
- <Container>
- <Helmet title='可视化组件' />
- {
- !history?.location?.pathname?.includes('dataShareService') && <ContainerTitle>
- <Row>
- <Col span={24} className={utilStyles.shortcut}>
- <Breadcrumb className={utilStyles.breadcrumb}>
- <Breadcrumb.Item>
- <Link to=''>Widget</Link>
- </Breadcrumb.Item>
- </Breadcrumb>
- <Link to={`/account/organization/${currentProject.orgId}`}>
- <i className='iconfont icon-organization' />
- </Link>
- </Col>
- </Row>
- </ContainerTitle>}
- <ContainerBody>
- <Box>
- <Box.Header>
- <Box.Title>
- <Icon type='bars' />
- 可视化组件列表
- </Box.Title>
- <Box.Tools>
- <Tooltip placement='bottom' title='新增'>
- <AdminButton
- type='primary'
- icon='plus'
- onClick={toWorkbench()}
- />
- </Tooltip>
- </Box.Tools>
- </Box.Header>
- <Box.Body>
- <Row>
- <Col span={24}>
- <Table
- rowKey='id'
- bordered
- dataSource={filterWidgets}
- columns={columns}
- pagination={tablePagination}
- loading={loading}
- onChange={tableChange}
- />
- </Col>
- </Row>
- </Box.Body>
- </Box>
- </ContainerBody>
- </Container>
- <CopyModal
- visible={copyModalVisible}
- loading={false}
- fromWidget={copyFromWidget}
- onCheckUniqueName={onCheckName}
- onCopy={copyWidget}
- onCancel={cancelCopy}
- />
- </>
- )
- }
- export default WidgetList
|