Commit 935b6557 by zhaochengxiang

草稿右键

parent da25e043
import React, { useMemo } from 'react';
import { Button, Tooltip } from 'antd';
const FC = (props) => {
const { permissionKey, permissions, defaultPermission, disabled, tip, tooltipPlacement = 'top', ...restProps } = props;
const havePermission = useMemo(() => {
let _havePermission = true;
if (defaultPermission!==undefined && defaultPermission!==null) {
_havePermission = defaultPermission;
} else if (permissionKey) {
const index = (permissions||[]).findIndex(item => item === permissionKey);
_havePermission = (index !== -1);
}
return _havePermission;
}, [permissionKey, permissions, defaultPermission])
return (
<Tooltip title={tip} placement={tooltipPlacement}>
<Button disabled={!havePermission||disabled} {...restProps} />
</Tooltip>
)
}
export default FC;
\ No newline at end of file
import React, { useMemo } from 'react';
import { Tooltip, Menu } from 'antd';
const FC = (props) => {
const { permissionKey, permissions, defaultPermission, disabled, tip, children, ...restProps } = props;
const havePermission = useMemo(() => {
let _havePermission = true;
if (defaultPermission===false) {
_havePermission = defaultPermission;
} else if (permissionKey) {
const index = (permissions||[]).findIndex(item => item === permissionKey);
_havePermission = (index !== -1);
}
return _havePermission;
}, [permissionKey, permissions, defaultPermission])
return (
<Menu.Item disabled={!havePermission||disabled} {...restProps}>
<Tooltip title={tip}>
{children}
</Tooltip>
</Menu.Item>
)
}
export default FC;
\ No newline at end of file
import React, { useMemo } from 'react';
import { Tooltip } from 'antd';
import { Item as RcItem } from "react-contexify";
const FC = (props) => {
const { permissionKey, permissions, defaultPermission, disabled, tip, children, ...restProps } = props;
const havePermission = useMemo(() => {
let _havePermission = true;
if (defaultPermission===false) {
_havePermission = defaultPermission;
} else if (permissionKey) {
const index = (permissions||[]).findIndex(item => item === permissionKey);
_havePermission = (index !== -1);
}
return _havePermission;
}, [permissionKey, permissions, defaultPermission])
return (
<RcItem disabled={!havePermission||disabled} {...restProps}>
<Tooltip title={tip}>
{children}
</Tooltip>
</RcItem>
)
}
export default FC;
\ No newline at end of file
// @import (reference) "@/less" 只导入变量
@ant-prefix: foobar;
.ssetable {
.react-resizable{
position: relative;
background-clip: padding-box;
user-select: none;
}
.react-resizable-handle {
position: absolute;
width: 10px;
height: 100%;
bottom: 0;
right: -5px;
cursor: col-resize;
// background: red;
z-index: 999;
}
.@{ant-prefix}-table-thead > tr > th {
padding: 8px 8px !important;
white-space: nowrap;
text-overflow: ellipsis;
}
// .@{ant-prefix}-table-tbody > tr > td {
// padding: 12px 8px !important;
// }
.@{ant-prefix}-table-tbody > .@{ant-prefix}-table-measure-row > td {
padding: 0px !important;
}
.@{ant-prefix}-table-tbody > tr .@{ant-prefix}-table-row-selected > td {
background: #fff !important;
}
tr.@{ant-prefix}-table-expanded-row > td {
padding: 0 !important;
background: #fff !important;
}
tr.@{ant-prefix}-table-expanded-row {
.@{ant-prefix}-table {
margin: 0 !important;
}
}
.@{ant-prefix}-table-thead > tr > th {
background-color: #F2F5FC !important;
}
.@{ant-prefix}-table-thead > tr > th.highlight {
background-color: #FCEBED !important;
}
}
import React, { useEffect, useMemo, useRef, useState } from 'react'
import { PaginationProps, Table, TableColumnType, TableProps } from 'antd'
import type { SortOrder, ColumnGroupType, ColumnType } from 'antd/lib/table/interface'
import { Resizable } from 'react-resizable'
import ResizeObserver from 'rc-resize-observer'
import produce from 'immer'
import { nanoid } from 'nanoid'
import { getScrollbarWidth } from '..'
import { defaultPageSizeOptions } from '../hooks/page'
import ToolTip from './Tooltip'
import { Menu, useContextMenu } from 'react-contexify'
import { generateUUID } from ".."
import PermissionRcItem from './PermissionRcItem'
import 'react-contexify/dist/ReactContexify.css'
import './Table.less'
interface Props<RowType> {
width: number
maxHeight?: string | number
pageSize: number
pageNum: number
total: number
pageSizeOptions: string[] | number[]
onPaginate: PaginationProps["onChange"]
rowSelection?: TableProps<RowType>
bodyCell: any
extraColWidth?: number
menuData: string[]
menuPermissions: string[]
onMenuItemClick: Function
onRowClick: Function
shouldRowContextMenu: Function
}
const scrollbarWidth = getScrollbarWidth()
function FC<RowType extends object = any>({ width, maxHeight, pageSize, pageNum, total, pageSizeOptions, onPaginate, columns, bodyCell, extraColWidth = 0, menuData, menuPermissions, onMenuItemClick, onRowClick, shouldRowContextMenu, ...rest }: TableProps<RowType> & Props<RowType>) {
type Columns = typeof columns
const MENU_ID = generateUUID()
const [tableWidth, setTableWidth] = useState(0)
const { show, hideAll } = useContextMenu({
id: MENU_ID,
})
const paddingCol = useRef<TableColumnType<any>>({
key: 'padding',
width: 0,
render: () => undefined
})
const handleResize = (index: number) => (e: any, { size }: any) => {
setCols((prevCols) => {
const nextColumns = [...(prevCols ?? [])];
nextColumns[index] = {
...nextColumns[index],
width: size.width,
};
return nextColumns;
});
};
const [cols, setCols] = useState<Columns>()
useEffect(() => {
if (!!columns && tableWidth > 0) {
const contentWidth = getWidth(width ?? tableWidth,extraColWidth)
setDefaultWidth(columns, contentWidth)
paddingCol.current.width = 0
const newCols = columns
.map((col, index) => {
const render = getRender(col);
const colWidth = col.width ?? 100;
return {
ellipsis: true,
...col, /* colRef: createRef(), */ width: colWidth, render,
onHeaderCell: (column: any) => ({
width: column.width,
// colRef: column.colRef,
onResize: handleResize(index),
}),
};
})
setCols(newCols)
}
}, [columns, tableWidth, width, extraColWidth])
// add padding column
const cols1 = useMemo(() => !!cols ? [...cols, paddingCol.current] : undefined, [cols, pageSize, pageNum])
const scroll = useMemo(() => (maxHeight === undefined || total === 0 /* fix 暂无数据显示滚动条? */ ? { x: '100%' } : { y: maxHeight, x: '100%' /* 'max-content' 所有列显示全宽*/ }), [maxHeight, total])
const ref = useRef<HTMLDivElement>(null)
const [rightClickNode, setRightClickNode] = React.useState(undefined)
const handleContextMenu = (event, node) => {
show(event, {
position: {
x: event.clientX + 30,
y: event.clientY - 10
}
})
}
return (
<ResizeObserver
onResize={(size) => {
setTableWidth(size?.width)
}}
>
<Table
ref={ref}
className="ssetable"
size='middle'
rowKey="id" // could be overrided in rest.
showSorterTooltip={false}
columns={cols1}
pagination={{
pageSizeOptions: pageSizeOptions ?? defaultPageSizeOptions, showSizeChanger: true,
position: ['bottomCenter'], pageSize, current: pageNum, total, onChange: onPaginate,
showTotal: total => `共 ${total} 条`,
}}
components={{
body: {
cell: bodyCell ?? null
},
header: {
cell: ResizableTitle,
},
}}
onRow={(record, index) => {
return {
onClick: event => {
onRowClick?.(event, record)
},
onContextMenu: event => {
setRightClickNode(record)
if (shouldRowContextMenu?.(record)) {
handleContextMenu(event, record)
}
},
}
}}
scroll={scroll}
{...rest}
/>
<Menu id={MENU_ID}>
{
menuData?.map(item => <PermissionRcItem
key={item}
id={item}
disabled={rightClickNode?.[`${item}`]?.disabled}
tip={rightClickNode?.[`${item}`]?.tip}
permissions={rightClickNode?.permissions||menuPermissions}
permissionKey={item}
onClick={({ event }) => {
event?.stopPropagation()
hideAll()
onMenuItemClick?.(item, rightClickNode)
}}>
{item}
</PermissionRcItem>)
}
</Menu>
</ResizeObserver>
)
}
// 可变列宽
const ResizableTitle = (props: any) => {
const { onResize, width, ...restProps } = props;
if (!width) {
return <th {...restProps} />;
}
return (
<Resizable
width={width}
height={0}
handle={
<span
className="react-resizable-handle"
onClick={e => {
e.stopPropagation();
}}
/>
}
onResize={onResize}
draggableOpts={{ enableUserSelectHack: false }}
>
<th {...restProps} />
</Resizable>
);
};
function setDefaultWidth(columns: any[], width: number) {
let rowWidth = 0, count = 0
for (const col of columns) {
if (typeof col.width === 'number') {
rowWidth += col.width
} else {
count++
}
}
if (count > 0) {
const defaultW = (rowWidth > width ? 0 : width - rowWidth) / count
for (const col of columns) {
if (typeof col.width !== 'number') {
col.width = (defaultW < 100) ? 100 : defaultW
}
}
}
}
function getWidth(tableWidth: number, extraColWidth: number): number {
return tableWidth - scrollbarWidth - extraColWidth // scrollbar width, checkbox column
}
function getRender<T>(col: ColumnGroupType<T> | ColumnType<T>) {
return (value: any, record: T, index: number) => {
// 用户自定render
if (col.render) {
const rs = col.render(value, record, index)
if (typeof rs === 'string') {
return (<ToolTip msg={rs} defaultStyle />)
}
return rs
} else {
return (<ToolTip msg={value} defaultStyle />)
}
}
}
export default FC
export function getStringSorter<T>(k: keyof T) {
return (a: T, b: T, sortOrder?: SortOrder) => {
const aVal = a[k], bVal = b[k]
if (typeof aVal === 'string' && typeof bVal === 'string')
return aVal.localeCompare(bVal);
return 0
}
}
export function getNumberSorter<T>(k: keyof T) {
return (a: T, b: T, sortOrder?: SortOrder) => {
const aVal = a[k], bVal = b[k]
if (typeof aVal === 'number' && typeof bVal === 'number')
return aVal - bVal;
return 0
}
}
export function generateId<T = any>(data: T[], id = 'id') {
return produce(data, (draft) => {
draft?.forEach((row: any) => {
row[id] = nanoid()
})
})
}
export function generateIdFromArrayRow<T extends unknown[]>(data?: T[], id = 'id'): unknown[] | undefined {
return data?.map((row, i) => {
const obj: { [key: string]: unknown } = { [id]: nanoid() }
row.forEach((cell, j) => {
obj[j] = cell
})
return obj
})
}
export function filterRows<RowType = unknown>(rows: RowType[] | undefined, filter: (row: RowType) => boolean) {
if (rows) {
const matched = rows.filter(filter)
return matched
}
return rows
}
\ No newline at end of file
import React, { CSSProperties, HTMLAttributes, useEffect, useRef, useState } from "react";
import { Tooltip as Tooltip_, TooltipProps } from "antd";
import type { TooltipPlacement } from "antd/es/tooltip";
const DefaultStyle: CSSProperties = {
overflow: "hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
// backgroundColor: "red"
}
export default function ({ msg, defaultStyle, style, placement, children, ...rest }: { msg: string | JSX.Element, defaultStyle?: boolean, placement?: TooltipPlacement } & HTMLAttributes<any>) {
const wrapper = useRef<HTMLDivElement>(null);
const text = useRef<HTMLSpanElement>(null);
const [toolTip, setToolTip] = useState(false);
useEffect(() => {
const wrapperRect = wrapper.current!.getBoundingClientRect(),
textRect = text.current!.getBoundingClientRect();
if (wrapperRect.width < textRect.width) {
setToolTip(true);
}
}, [msg]);
const _text = (
<div
ref={wrapper}
style={defaultStyle ? { ...DefaultStyle, ...style } : style}
{...rest}
>
<span ref={text}>{children ?? msg}</span>
{/* {msg} */}
</div>
);
if (toolTip) {
return <Tooltip_ title={msg} placement={placement} /* color="#fff" overlayInnerStyle={{ color: '#000' }} */ >{_text}</Tooltip_>;
} else {
return _text;
}
}
export const Tooltip = ({ children, color, ...props }: TooltipProps) => {
return <Tooltip_ /* color="#fff" overlayInnerStyle={{ color: '#000' }} */ {...props} >{children}</Tooltip_>
}
\ No newline at end of file
import React from "react"
import { Tree } from "antd"
import { Menu, Item, useContextMenu } from 'react-contexify'
import { generateUUID } from ".."
import 'react-contexify/dist/ReactContexify.css';
const FC = ({ shouldRowContextMenu, menuData, onMenuItemClick, ...restProps }) => {
const MENU_ID = generateUUID()
const { show } = useContextMenu({
id: MENU_ID,
})
const [rightClickNode, setRightClickNode] = React.useState(undefined)
const handleContextMenu = (event, node) => {
show(event, {
position: {
x: event.clientX + 30,
y: event.clientY - 10
}
})
}
return (
<div>
<Tree
onRightClick={({event, node}) => {
setRightClickNode(node)
if (shouldRowContextMenu?.(node)) {
handleContextMenu(event, node)
}
}}
{...restProps}
/>
<Menu id={MENU_ID}>
{
menuData?.map(item => <Item key={item.id} id={item.id} onClick={() => onMenuItemClick?.(item.id, rightClickNode)}>{item.title}</Item>)
}
</Menu>
</div>
)
}
export default FC
\ No newline at end of file
import { AxiosResponse } from "axios"
export default function (res: AxiosResponse<any>) {
const blob = res.data
const headers = res.headers
let tempName = headers["content-disposition"]
?.split(";")?.[1]
?.split("filename=")?.[1]?.split(".")?.[0].replace(/"/g, "");
tempName = decodeURI(tempName);
// const blob = new Blob([content], { type: 'application/octet-stream' })
var url = (window.URL && window.URL.createObjectURL) ? window.URL.createObjectURL(blob) : window.webkitURL.createObjectURL(blob);
const link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.setAttribute('download', tempName); //or any other extension
document.body.appendChild(link);
link.click();
URL.revokeObjectURL(link.href) // 释放URL 对象
document.body.removeChild(link)
}
\ No newline at end of file
import { useState } from "react"
export interface Page {
pageSize: number
pageNum: number
}
export const defaultPageSize = 20
export const defaultPageSizeOptions = [10, 20, 50, 100]
export type PageSizeOptions = typeof defaultPageSizeOptions[number]
export const defaultPage = {
pageSize: defaultPageSize,
pageNum: 1
}
export function usePage(pageSize?: number): [Page, React.Dispatch<React.SetStateAction<Page>>, (pageNum: number) => void] {
const [page, setPage] = useState<Page>(() => ({
pageSize: pageSize ?? defaultPageSize, pageNum: 1,
}))
const gotoPage = (pageNum: number) => {
setPage(prev => ({ ...prev, pageNum }))
}
return [page, setPage, gotoPage]
}
export type PageType = ReturnType<typeof usePage>[0]
export function paginate<T>(list: T[] | undefined, page: Page) {
if (list) {
const { pageSize, pageNum } = page
const start = (pageNum - 1) * pageSize
const end = start + pageSize
return list.slice(start, end)
}
return list
}
\ No newline at end of file
......@@ -400,4 +400,27 @@ export function getDataModelerRole(user) {
export function isPostAsset(templateType) {
return templateType === 'post'
}
export function getScrollbarWidth() {
// Creating invisible container
const outer = document.createElement('div');
outer.style.visibility = 'hidden';
outer.style.overflow = 'scroll'; // forcing scrollbar to appear
outer.style.msOverflowStyle = 'scrollbar'; // needed for WinJS apps
document.body.appendChild(outer);
// Creating inner element and placing it in the container
const inner = document.createElement('div');
outer.appendChild(inner);
// Calculating difference between container's full width and the child width
const scrollbarWidth = (outer.offsetWidth - inner.offsetWidth);
// Removing temporary elements from the DOM
outer.parentNode?.removeChild(outer);
return scrollbarWidth;
}
\ No newline at end of file
......@@ -5,7 +5,7 @@ import { useDebounceEffect } from 'ahooks'
import { appId } from "../../../App"
import { dispatch } from '../../../model'
import Table from '../ResizeableTable'
import Table from '../../../util/Component/Table'
import { highlightSearchContentByTerms, isSzseEnv, showMessage } from "../../../util"
import { AssetItem } from "../AssetManage/Component/AssetTable"
import UpdateAsset from "../AssetManage/Component/AssetDetailDrawer"
......@@ -16,6 +16,17 @@ import ImportAsset from "./import"
// const specialCol = ['数据关键用户', '业务数据owner', 'it责任人', '创建人', '更新人']
const specialCol = ['创建人', '更新人']
const operationMap = {
view: '查看',
edit: '编辑',
delete: '删除',
distribute: '分配',
reDistribute: '转分配',
submit: '提交',
publish: '发布',
changeToPendingSubmit: '转为待提交',
}
const FC = (props) => {
const [loadingTemplates, setLoadingTemplates] = React.useState(false)
const [templates, setTemplates] = React.useState()
......@@ -45,6 +56,7 @@ const FC = (props) => {
visible: false,
items: undefined,
})
const [rightRow, setRightRow] = React.useState()
const [modal, contextHolder] = Modal.useModal();
......@@ -83,6 +95,16 @@ const FC = (props) => {
return (newSelectedRows??[]).length !== 0
}, [selectedRows, isAdmin])
const menuData = React.useMemo(() => {
const newMenuData = []
for (const key of rightRow?.allowActions??[]) {
if (operationMap[key]) {
newMenuData.push(operationMap[key])
}
}
return newMenuData
}, [rightRow])
const pathCol = {
title: '路径',
dataIndex: 'dirPath',
......@@ -370,6 +392,34 @@ const FC = (props) => {
})
}
const onRightDetailClick = () => {
setUpdateAssetParams({
visible: true,
id: rightRow?.id,
dirId: rightRow?.dirId,
})
}
const onRightMenuItemClick = (key, record) => {
if (key === '查看') {
onRightDetailClick()
} else if (key === '编辑') {
} else if (key === '删除') {
} else if (key === '分配') {
} else if (key === '转分配') {
} else if (key === '提交') {
} else if (key === '发布') {
} else if (key === '转为待提交') {
}
}
return (
<div style={{ backgroundColor: '#fff', height: '100%' }}>
<div className='flex p-3' style={{
......@@ -438,21 +488,24 @@ const FC = (props) => {
setSelectedRows(selectedRows)
}
}}
onRow={(record) => {
return {
onClick: (e) => {
setRow(record)
setUpdateAssetParams({
visible: true,
id: record?.id,
dirId: record?.dirId,
})
}
}
}}
rowClassName={(record, index) => {
return (record?.id === row?.id) ? 'yy-table-select-row' : ''
}}
shouldRowContextMenu={(record) => {
setRightRow(record)
let allowContextMenu = false
for (const key of (record.allowActions??[])) {
if (operationMap[key]) {
allowContextMenu = true
break
}
}
return allowContextMenu
}}
menuData={menuData}
menuPermissions={menuData}
onMenuItemClick={onRightMenuItemClick}
scroll={{ y: 'calc(100vh - 209px - 72px - 57px)' }}
/>
<Pagination
......
{
"compilerOptions": {
"target": "es2016",
"module": "esnext",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment