!2116 新增:右侧工具栏材质面板显示模式

pull/2115/MERGE
黄诗津 2 years ago committed by ChenX
parent b6ad900edb
commit 50a7fe47cf

@ -10,6 +10,7 @@ import { AnyObject } from '../../Store/BoardInterface';
import { ScaleImages } from '../Template/ScaleImages'; import { ScaleImages } from '../Template/ScaleImages';
import { RenderBackGroundImg } from '../ToolBar/ResourceLibrary/Resource_ResourceList'; import { RenderBackGroundImg } from '../ToolBar/ResourceLibrary/Resource_ResourceList';
export interface IDataListProps export interface IDataListProps
{ {
dataList: any[]; dataList: any[];
@ -20,6 +21,7 @@ export interface IDataListProps
renderOtherElement?: (data) => JSX.Element; renderOtherElement?: (data) => JSX.Element;
selectData: Set<string>; selectData: Set<string>;
showInfos: boolean; showInfos: boolean;
isSmaller?: boolean;
dbclickImg?: (data: AnyObject) => void; dbclickImg?: (data: AnyObject) => void;
dragStart?: (data: AnyObject) => void; dragStart?: (data: AnyObject) => void;
preview?: boolean; preview?: boolean;
@ -44,13 +46,14 @@ export class DataList extends React.Component<IDataListProps> {
activeId: "", activeId: "",
style: {}, style: {},
hintClassName: "", hintClassName: "",
canDrag: true canDrag: true,
isSmaller: false,
}; };
private currentData: any; private currentData: any;
renderBigData = () => renderBigData = () =>
{ {
return ( return (
<> <ul className={"mat-list fileList"}>
{ {
this.props.dataList.map(data => this.props.dataList.map(data =>
{ {
@ -154,13 +157,23 @@ export class DataList extends React.Component<IDataListProps> {
url={this.props.isFromResource ? RenderBackGroundImg(this.currentData.logo, "320x320") : this.currentData.logo ?? this.currentData.path} url={this.props.isFromResource ? RenderBackGroundImg(this.currentData.logo, "320x320") : this.currentData.logo ?? this.currentData.path}
/> />
} }
</> </ul>
); );
}; };
renderSmall = () => renderSmall = () =>
{ {
return ( return (
<> <>
{
this.props.dataList.length > 0 && !this.props.isSmaller &&
<div className="info-header">
<div><span></span></div>
<div><span></span></div>
<div><span></span></div>
<div><span></span></div>
</div>
}
<ul className={"mat-list data-list-info"}>
{ {
this.props.dataList.map(data => this.props.dataList.map(data =>
{ {
@ -172,7 +185,11 @@ export class DataList extends React.Component<IDataListProps> {
onMouseDown={(e) => this.handleMouseDown(e, data)} onMouseDown={(e) => this.handleMouseDown(e, data)}
onMouseUp={(e) => this.handleMouseUp(e, data)} onMouseUp={(e) => this.handleMouseUp(e, data)}
> >
<div draggable="true" style={{ padding: "5px 0", height: 50, display: "grid", gridTemplateColumns: "50px 1fr" }}> <div
onDragStart={() => this.handleDragStart(data)}
draggable="true"
style={{ padding: "5px 0", height: 50, display: "grid", gridTemplateColumns: "50px 1fr" }}
>
{ {
this.props.isSvg ? this.props.isSvg ?
<> <>
@ -200,6 +217,8 @@ export class DataList extends React.Component<IDataListProps> {
</> </>
} }
</div> </div>
{!this.props.isSmaller &&
<>
<div> <div>
{data.update_date ?? data.create_date} {data.update_date ?? data.create_date}
</div> </div>
@ -213,10 +232,12 @@ export class DataList extends React.Component<IDataListProps> {
this.props.renderButtons && this.props.renderButtons(data) this.props.renderButtons && this.props.renderButtons(data)
} }
</div> </div>
</>}
</li> </li>
); );
}) })
} }
</ul>
</> </>
); );
}; };
@ -229,22 +250,7 @@ export class DataList extends React.Component<IDataListProps> {
style={this.props.style ?? {}} style={this.props.style ?? {}}
onMouseDown={(e) => this.handleMouseDown(e, {})} onMouseDown={(e) => this.handleMouseDown(e, {})}
> >
{ {this.props.showInfos ? this.renderSmall() : this.renderBigData()}
this.props.showInfos && this.props.dataList.length > 0 &&
<div className="info-header">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
}
<ul
className={`mat-list ${this.props.showInfos ? "data-list-info" : "fileList"}`}
>
{
this.props.showInfos ? this.renderSmall() : this.renderBigData()
}
</ul>
</div> </div>
); );
} }

@ -0,0 +1,144 @@
.material-explorer {
height: 100%;
display: flex;
flex-direction: column;
.material-config {
height: 20px;
display: flex;
justify-content: flex-end;
}
.right-material-param {
padding-bottom: 5px;
flex-grow: 1;
flex-basis: 200px;
overflow: hidden;
.material-param {
margin-bottom: 3px;
}
.setsplit();
.my-material-param {
margin-top: 2px;
display: flex;
flex-direction: column;
.material-search {
height: 34px;
input {
width: 99%;
}
}
.material-params {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
border: 1px solid #ccc;
.img-tree {
height: 40%;
width: 100%;
padding: 0;
overflow: auto;
.bp3-tree {
height: 100%;
padding-bottom: 10px;
box-shadow: none;
&>ul {
max-height: 95%;
overflow: auto;
}
.bp3-tree-node-content-1 {
padding-left: 10px;
}
}
}
.material-datalist {
width: 100%;
height: 60%;
overflow: visible;
position: relative;
display: flex;
flex-direction: column;
&> :nth-child(1) {
flex: 1;
}
.mat-list:first-child {
padding-bottom: 10px;
li {
cursor: pointer;
}
.look-mat {
user-select: none;
}
&>li {
text-align: center;
.hint:hover::before {
content: none;
}
&>.bp3-control {
left: 10px;
top: 10;
}
&>p {
margin-bottom: 0;
width: 100%;
}
}
}
.bp3-dialog-container {
position: fixed;
left: 0;
top: 0;
z-index: 30;
.bp3-dialog {
width: unset;
margin: 0;
padding: 0;
}
}
}
}
}
}
}
//split组件样式
.setsplit {
.gutter {
background-color: #999;
background-repeat: no-repeat;
background-position: 10%;
}
.gutter.gutter-vertical {
cursor: row-resize;
padding: auto;
border-radius: 20px;
}
.split {
width: 100%;
height: 100%;
}
}

@ -23,6 +23,7 @@ import { userConfigStore } from '../Store/UserConfigStore';
import { ApplyGoodInfo } from "./ApplyGoodInfo"; import { ApplyGoodInfo } from "./ApplyGoodInfo";
import { Asset } from './Asset'; import { Asset } from './Asset';
import { BoardModalType } from "./Board/BoardModalType"; import { BoardModalType } from "./Board/BoardModalType";
import './MaterialExplorer.less';
import { RightMaterial } from './SourceManage/RightMaterial'; import { RightMaterial } from './SourceManage/RightMaterial';
const rootStyle: React.CSSProperties = { const rootStyle: React.CSSProperties = {
@ -38,6 +39,7 @@ const rootStyle: React.CSSProperties = {
height: "100%", height: "100%",
paddingLeft: "10px", paddingLeft: "10px",
border: "1px solid #ccc",
}; };
/** /**
@ -180,8 +182,8 @@ export class MaterialExplorer extends React.Component<{ materialTable: MaterialT
render() render()
{ {
return ( return (
<> <div className='material-explorer'>
<div style={{ display: "flex", justifyContent: "flex-end" }}> <div className='material-config'>
<Checkbox <Checkbox
style={{ marginRight: 5, marginBottom: 3 }} style={{ marginRight: 5, marginBottom: 3 }}
label="亮显材质球" label="亮显材质球"
@ -212,7 +214,7 @@ export class MaterialExplorer extends React.Component<{ materialTable: MaterialT
await userConfigStore.SaveConfig(BoardModalType.UserConfig, userConfig); await userConfigStore.SaveConfig(BoardModalType.UserConfig, userConfig);
}} /> }} />
</div> </div>
<div id="MaterialParam"> <div className='right-material-param'>
<Split // <Split //
className="split" className="split"
direction="vertical" direction="vertical"
@ -221,7 +223,7 @@ export class MaterialExplorer extends React.Component<{ materialTable: MaterialT
gutterSize={3} gutterSize={3}
gutterAlign="center" gutterAlign="center"
> >
<div id="RightMaterialParam" ref={this._MaterialListPanelRef} className="bp3-card bp3-elevation-0" style={rootStyle} <div id="RightMaterialParam" ref={this._MaterialListPanelRef} className="material-param" style={rootStyle}
onContextMenu={(e) => onContextMenu={(e) =>
{ {
e.preventDefault(); e.preventDefault();
@ -263,7 +265,7 @@ export class MaterialExplorer extends React.Component<{ materialTable: MaterialT
<RightMaterial /> <RightMaterial />
</Split> </Split>
</div> </div>
</> </div>
); );
} }
handleCreateMaterial = () => handleCreateMaterial = () =>

@ -155,27 +155,3 @@
} }
} }
} }
#MaterialParam {
height : 96%;
width : 100%;
position: relative;
.gutter {
background-color : #999;
background-repeat : no-repeat;
background-position: 10%;
}
.gutter.gutter-vertical {
cursor : row-resize;
padding : auto;
border-radius: 20px;
margin-top : 4px;
}
.split {
width : 100%;
height: 100%;
}
}

@ -3,6 +3,7 @@ import hotkeys from 'hotkeys-js-ext';
import { action, observable, toJS } from 'mobx'; import { action, observable, toJS } from 'mobx';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import * as React from 'react'; import * as React from 'react';
import { end } from 'xaop';
import { ITempTagProps } from '../../../Add-on/Template/TemplateTagCommand'; import { ITempTagProps } from '../../../Add-on/Template/TemplateTagCommand';
import { app } from '../../../ApplicationServices/Application'; import { app } from '../../../ApplicationServices/Application';
import { arrayLast } from '../../../Common/ArrayExt'; import { arrayLast } from '../../../Common/ArrayExt';
@ -79,12 +80,13 @@ export interface ICommonPanelState
} }
export interface ICommonPanelProps export interface ICommonPanelProps
{ {
isRightMaterialPanel?: boolean;
defaultDirId: string; //根目录ID defaultDirId: string; //根目录ID
renderNav?: () => JSX.Element; //渲染导航栏
renderMenuItems?: () => JSX.Element; //渲染右键菜单项
canDelete?: boolean; //是否可以删除数据 canDelete?: boolean; //是否可以删除数据
deleteUrl: string; //删除后端URL deleteUrl: string; //删除后端URL
getUrl: string; //获取数据URL getUrl: string; //获取数据URL
renderNav?: () => JSX.Element; //渲染导航栏
renderMenuItems?: () => JSX.Element; //渲染右键菜单项
clickTree?: () => void; clickTree?: () => void;
delete?: (data) => void; delete?: (data) => void;
canOrder?: boolean; //可以排序 canOrder?: boolean; //可以排序
@ -130,11 +132,11 @@ export class CommonPanel extends React.Component<ICommonPanelProps, ICommonPanel
}; };
static CurrentDirCache: Map<string, IDirectoryProps> = new Map(); static CurrentDirCache: Map<string, IDirectoryProps> = new Map();
private ColResizeEl = React.createRef<HTMLDivElement>(); private ColResizeEl = React.createRef<HTMLDivElement>();
private selectContainer = React.createRef<HTMLDivElement>();
private startHandleDir = observable.box(false); //开始操作目录,重命名or新建 private startHandleDir = observable.box(false); //开始操作目录,重命名or新建
private timeId = null; //搜索时的定时器 private timeId = null; //搜索时的定时器
private dataList = observable([]); private dataList = observable([]);
private _dragId = ""; private _dragId = "";
private selectContainer: HTMLElement;
private selectTool: SelectDataTool; private selectTool: SelectDataTool;
private idKey: string; private idKey: string;
private copyIds = new Set(); private copyIds = new Set();
@ -160,6 +162,7 @@ export class CommonPanel extends React.Component<ICommonPanelProps, ICommonPanel
@observable searchedDirs: IDirectoryProps[] = []; @observable searchedDirs: IDirectoryProps[] = [];
@observable isSmallScreen = !!(window.innerWidth < 1080);; @observable isSmallScreen = !!(window.innerWidth < 1080);;
handleOpenDrawer = observable.box(false); handleOpenDrawer = observable.box(false);
_Events: Function[] = [];
private LoadingDataPromise: () => void; private LoadingDataPromise: () => void;
constructor(props) constructor(props)
@ -224,14 +227,32 @@ export class CommonPanel extends React.Component<ICommonPanelProps, ICommonPanel
{ {
window.addEventListener('resize', this.GetScreenSize, false); window.addEventListener('resize', this.GetScreenSize, false);
this.touchEventEditor = new TouchEventEditor(this.selectContainer); this.touchEventEditor = new TouchEventEditor(this.selectContainer.current);
this.touchEventEditor.LongTouchEvent = (el, options) => this.touchEventEditor.LongTouchEvent = (el, options) =>
{ {
options.bubbles = true; options.bubbles = true;
el.dispatchEvent(new MouseEvent("mousedown", options)); el.dispatchEvent(new MouseEvent("mousedown", options));
}; };
this.selectTool = new SelectDataTool(this.selectContainer); if (this.props.isRightMaterialPanel)
{
//如果有通知修改,那么我们刷新这个
this._Events.push(end(CommonPanelEventBus.GetInstance(), CommonPanelEventBus.GetInstance().UpdateEvent, (url: string, isdelete?: boolean) =>
{
if (url === this.props.getUrl)
{
if (isdelete)
{
Object.assign(this.currentDir, { id: this.props.defaultDirId, path: "", pathNum: [] });
CommonPanel.CurrentDirCache.delete(this.props.defaultDirId);
}
this.loadingData();
}
}));
}
else
{
this.selectTool = new SelectDataTool(this.selectContainer.current);
this.selectTool.SelectCallBack = (els: HTMLElement[]) => this.selectTool.SelectCallBack = (els: HTMLElement[]) =>
{ {
if (!els) //组件已经被卸载了 if (!els) //组件已经被卸载了
@ -249,22 +270,31 @@ export class CommonPanel extends React.Component<ICommonPanelProps, ICommonPanel
}; };
if (this.selectContainer && this.props.copyUrl) if (this.selectContainer.current && this.props.copyUrl)
{ {
document.addEventListener('keydown', this.handleKeydown); document.addEventListener('keydown', this.handleKeydown);
} }
}
this.loadingData(); this.loadingData();
} }
componentWillUnmount() componentWillUnmount()
{ {
window.removeEventListener('resize', this.GetScreenSize, false); window.removeEventListener('resize', this.GetScreenSize, false);
this.touchEventEditor.Destory(); this.touchEventEditor.Destory();
if (this.props.isRightMaterialPanel)
{
this._Events.forEach(f => f());
this._Events.length = 0;
}
else
{
this.selectTool.Destory(); this.selectTool.Destory();
}
this.LoadingDataPromise = null; this.LoadingDataPromise = null;
localStorage.setItem("showInfos_" + this.props.defaultDirId, this.showInfos ? "1" : "0"); localStorage.setItem("showInfos_" + this.props.defaultDirId, this.showInfos ? "1" : "0");
if (this.selectContainer && this.props.copyUrl) if (this.selectContainer.current && this.props.copyUrl)
{ {
document.removeEventListener('keydown', this.handleKeydown); document.removeEventListener('keydown', this.handleKeydown);
} }
@ -554,7 +584,7 @@ export class CommonPanel extends React.Component<ICommonPanelProps, ICommonPanel
<div <div
className="bp3-card img-lib" className="bp3-card img-lib"
onDragStart={this.handleDragStart} onDragStart={this.handleDragStart}
ref={el => this.selectContainer = el} ref={this.selectContainer}
style={this.props.maxDirLength === 0 ? { width: "100%" } : {}} style={this.props.maxDirLength === 0 ? { width: "100%" } : {}}
> >
{ {
@ -589,9 +619,82 @@ export class CommonPanel extends React.Component<ICommonPanelProps, ICommonPanel
</div> </div>
); );
}; };
private renderRightMaterialPanel = (() =>
{
return (
<div className="my-material-param">
<div className="material-search">
<input
disabled={this.props.defaultDirId === DirectoryId.HistoryDit}
className="bp3-input"
placeholder="搜索材质..."
type="search"
value={this.state.searchStr}
onKeyDown={(e) => { e.stopPropagation(); }}
onChange={(e) => this.handleSearch(e)}
/>
</div>
<div className="material-params">
<DirTreeComponent
nodes={this.state.nodes}
currentDir={this.currentDir}
isPreventDrag={true}
canDrag={false}
maxDirLength={this.props.maxDirLength}
defaultDirId={this.props.defaultDirId}
onNodeClick={this.onNodeClick}
onNodeContainerClick={this.onNodeContainerClick}
onClickTree={this.props.clickTree}
/>
<div
className="bp3-card material-datalist"
ref={this.selectContainer}
>
{
React.Children.map(this.props.children, child =>
child && React.cloneElement(child as React.DetailedReactHTMLElement<any, any>,
{
dataList: this.dataList,
currentDir: this.currentDir,
getData: this.handleGetData,
select: this.handleSelectData,
selectIds: this.selectIds,
showInfos: this.showInfos,
})
)
}
{
this.pageData.count > this.pageData.pageCount &&
<Pagination
getImgListFun={this.handleGetData}
pageData={this.pageData}
maxCount={3}
/>
}
<div className='showinfos' style={{ position: "absolute", right: 0, bottom: 0 }}>
<Button
icon="align-justify"
intent={this.showInfos ? Intent.SUCCESS : "none"}
onClick={() => this.showInfos = true}
/>
<Button
icon="layout-grid"
intent={!this.showInfos ? Intent.SUCCESS : "none"}
onClick={() => this.showInfos = false}
/>
</div>
</div>
</div>
</div>
);
}
);
render() render()
{ {
return ( return (
this.props.isRightMaterialPanel ?
this.renderRightMaterialPanel()
:
<> <>
<Card <Card
className="texturePanel" className="texturePanel"
@ -855,7 +958,7 @@ export class CommonPanel extends React.Component<ICommonPanelProps, ICommonPanel
className: data.dir_id, className: data.dir_id,
hasCaret: false, hasCaret: false,
childNodes: [], childNodes: [],
secondaryLabel: <Button minimal icon='menu' className='dirmenu'></Button>, ...this.GetSecondaryLabel()
}); });
return true; return true;
} }
@ -1076,6 +1179,10 @@ export class CommonPanel extends React.Component<ICommonPanelProps, ICommonPanel
} }
} }
}; };
private GetSecondaryLabel = () =>
{
return { secondaryLabel: this.props.isRightMaterialPanel ? "" : <Button minimal icon='menu' className='dirmenu'></Button> };
};
//分析目录转换为ui节点数 //分析目录转换为ui节点数
private parseNodes = (dirs: any) => private parseNodes = (dirs: any) =>
@ -1090,7 +1197,7 @@ export class CommonPanel extends React.Component<ICommonPanelProps, ICommonPanel
hasCaret: dir.childs.length > 0, hasCaret: dir.childs.length > 0,
className: dir.dir_id, //为了识别这个元素的目录id className: dir.dir_id, //为了识别这个元素的目录id
childNodes: this.parseNodes(dir.childs), childNodes: this.parseNodes(dir.childs),
secondaryLabel: <Button minimal icon='menu' className='dirmenu'></Button> ...this.GetSecondaryLabel()
}; };
newNodes.push(node); newNodes.push(node);
} }

@ -15,14 +15,14 @@ const PUSHDOWN = "push-down";
export interface DirIds export interface DirIds
{ {
dir_id: string, dir_id: string;
pre_dir_id: string, pre_dir_id: string;
next_dir_id: string, next_dir_id: string;
parent_dir_id: string, parent_dir_id: string;
} }
interface DirTreeEvent interface DirTreeEvent
{ {
onClickTree?: () => void, onClickTree?: () => void;
onNodeClick?: (isReLoad?: boolean, isSecondaryLabel?: boolean) => void; //点击目录节点事件 onNodeClick?: (isReLoad?: boolean, isSecondaryLabel?: boolean) => void; //点击目录节点事件
onNodeContainerClick?: () => void; //点击空白容器事件 onNodeContainerClick?: () => void; //点击空白容器事件
onMoveToDir?: (targetId: string) => void; //移动其他元素到目录事件 onMoveToDir?: (targetId: string) => void; //移动其他元素到目录事件
@ -37,8 +37,8 @@ interface DirTreeCall
interface DirTreeState interface DirTreeState
{ {
currentDir: IDirectoryProps, currentDir: IDirectoryProps;
prevCurrentDirId: string, prevCurrentDirId: string;
isContextMenuOpen: boolean; //是否打开右键菜单 isContextMenuOpen: boolean; //是否打开右键菜单
nodes: TreeNodeInfo[]; //目录节点 nodes: TreeNodeInfo[]; //目录节点
defaultDirName: string; //新目录名字 defaultDirName: string; //新目录名字
@ -47,14 +47,13 @@ interface DirTreeState
interface DirTreeProps extends DirTreeEvent, DirTreeCall interface DirTreeProps extends DirTreeEvent, DirTreeCall
{ {
renderMenuItems?: () => JSX.Element, //渲染右键菜单项 renderMenuItems?: () => JSX.Element; //渲染右键菜单项
currentDirProps?: IDirectoryProps, defaultDirId?: string;
defaultDirId?: string, nodes: TreeNodeInfo[];
nodes: TreeNodeInfo[], maxDirLength?: number;
maxDirLength?: number, isPreventDrag?: boolean;
isPreventDrag?: boolean, currentDir?: IDirectoryProps;
currentDir?: IDirectoryProps, canDrag?: boolean;
curNodeData?: TreeNodeInfo;
} }
@observer @observer
export class DirTreeComponent extends React.Component<DirTreeProps, DirTreeState> export class DirTreeComponent extends React.Component<DirTreeProps, DirTreeState>
@ -62,6 +61,7 @@ export class DirTreeComponent extends React.Component<DirTreeProps, DirTreeState
static defaultProps: Partial<DirTreeProps> = { static defaultProps: Partial<DirTreeProps> = {
maxDirLength: 1, maxDirLength: 1,
defaultDirId: "", defaultDirId: "",
canDrag: true,
}; };
private _moveDirId = ""; private _moveDirId = "";
private _moveElement: HTMLElement; private _moveElement: HTMLElement;
@ -220,7 +220,6 @@ export class DirTreeComponent extends React.Component<DirTreeProps, DirTreeState
{ {
this.forEachNode(this.props.nodes, n => (n.isSelected = false)); this.forEachNode(this.props.nodes, n => (n.isSelected = false));
curNodeData.isSelected = true; curNodeData.isSelected = true;
// this.setState(this.state);
}; };
//展开折叠目录 //展开折叠目录
@ -240,8 +239,11 @@ export class DirTreeComponent extends React.Component<DirTreeProps, DirTreeState
if (!this.treeEl.current) return; if (!this.treeEl.current) return;
this.nodeEls = Array.from(this.treeEl.current.querySelectorAll(".bp3-tree-node-content")); this.nodeEls = Array.from(this.treeEl.current.querySelectorAll(".bp3-tree-node-content"));
if (this.props.canDrag)
{
for (let el of this.nodeEls) for (let el of this.nodeEls)
el.draggable = true; el.draggable = true;
}
return true; return true;
}; };
@ -305,6 +307,7 @@ export class DirTreeComponent extends React.Component<DirTreeProps, DirTreeState
} }
}; };
//重命名目录
private handleRenameDir = async (curNodeData: TreeNodeInfo) => private handleRenameDir = async (curNodeData: TreeNodeInfo) =>
{ {
let isSuccess = this.props.handleRenameDir && (await this.props.handleRenameDir(curNodeData, false)); let isSuccess = this.props.handleRenameDir && (await this.props.handleRenameDir(curNodeData, false));
@ -715,6 +718,7 @@ export class DirTreeComponent extends React.Component<DirTreeProps, DirTreeState
this.upDateCurrentDir(this.defultCurrentDir); this.upDateCurrentDir(this.defultCurrentDir);
} }
if (!this.props.renderMenuItems) return;
if (!this.props.renderMenuItems()) return; if (!this.props.renderMenuItems()) return;
if (this.props.maxDirLength === 0 && !nodePath) return; if (this.props.maxDirLength === 0 && !nodePath) return;
ContextMenu.show( ContextMenu.show(
@ -753,14 +757,19 @@ export class DirTreeComponent extends React.Component<DirTreeProps, DirTreeState
}; };
componentDidMount() componentDidMount()
{ {
//监听右键其他位置
if (this.treeEl.current) if (this.treeEl.current)
{ {
this.treeEl.current.addEventListener('mousedown', this.handleTreeMouseDown); this.treeEl.current.addEventListener('mousedown', this.handleTreeMouseDown);
if (this.props.canDrag)
{
this.treeEl.current.draggable = false;
this.treeEl.current.addEventListener('dragstart', this.handleDirDragStart); this.treeEl.current.addEventListener('dragstart', this.handleDirDragStart);
this.treeEl.current.addEventListener('dragenter', this.handleDragEnter); this.treeEl.current.addEventListener('dragenter', this.handleDragEnter);
this.treeEl.current.addEventListener('dragover', this.handleDirDragOver); this.treeEl.current.addEventListener('dragover', this.handleDirDragOver);
this.treeEl.current.addEventListener('dragleave', this.handleDirDragLeave); this.treeEl.current.addEventListener('dragleave', this.handleDirDragLeave);
this.treeEl.current.addEventListener("drop", this.handleMoveFiles);
this.treeEl.current.addEventListener('dragend', this.handleDirDragEnd);
}
this.touchEventEditor = new TouchEventEditor(this.treeEl.current); this.touchEventEditor = new TouchEventEditor(this.treeEl.current);
this.touchEventEditor.LongTouchEvent = (el: HTMLElement, options: MouseEventInit) => this.touchEventEditor.LongTouchEvent = (el: HTMLElement, options: MouseEventInit) =>
{ {
@ -772,22 +781,23 @@ export class DirTreeComponent extends React.Component<DirTreeProps, DirTreeState
} }
}; };
} }
document.addEventListener("drop", this.handleMoveFiles);
document.addEventListener('dragend', this.handleDirDragEnd);
} }
componentWillUnmount() componentWillUnmount()
{ {
if (this.treeEl.current) if (this.treeEl.current)
{ {
this.treeEl.current.removeEventListener('mousedown', this.handleTreeMouseDown); this.treeEl.current.removeEventListener('mousedown', this.handleTreeMouseDown);
if (this.props.canDrag)
{
this.treeEl.current.removeEventListener('dragstart', this.handleDirDragStart); this.treeEl.current.removeEventListener('dragstart', this.handleDirDragStart);
this.treeEl.current.removeEventListener('dragenter', this.handleDragEnter); this.treeEl.current.removeEventListener('dragenter', this.handleDragEnter);
this.treeEl.current.removeEventListener('dragover', this.handleDirDragOver); this.treeEl.current.removeEventListener('dragover', this.handleDirDragOver);
this.treeEl.current.removeEventListener('dragleave', this.handleDirDragLeave); this.treeEl.current.removeEventListener('dragleave', this.handleDirDragLeave);
this.treeEl.current.removeEventListener("drop", this.handleMoveFiles);
this.treeEl.current.removeEventListener('dragend', this.handleDirDragEnd);
}
this.touchEventEditor.Destory(); this.touchEventEditor.Destory();
} }
document.removeEventListener("drop", this.handleMoveFiles);
document.removeEventListener('dragend', this.handleDirDragEnd);
} }
componentDidUpdate(prevProps: Readonly<DirTreeProps>, prevState: Readonly<DirTreeState>, snapshot?: any): void componentDidUpdate(prevProps: Readonly<DirTreeProps>, prevState: Readonly<DirTreeState>, snapshot?: any): void

@ -174,15 +174,19 @@ export class MaterialList extends React.Component<IImgListProps, {}> {
this.readyMtl = null; this.readyMtl = null;
} }
else else
for (let i = 0; i < 5; i++)
{ {
if (el === document.getElementById("RightMaterialParam")) while (true)
{
if (el.id === "RightMaterialParam")
{ {
await this.applyMtl(this.readyMtl); await this.applyMtl(this.readyMtl);
break; break;
} }
else else
el = el.parentElement; el = el.parentElement;
if (el === null || el.classList.contains("material-explorer"))
break;
}
} }
}; };
private applyMtl = async (data: { material_id: string; name: string; }) => private applyMtl = async (data: { material_id: string; name: string; }) =>
@ -190,7 +194,7 @@ export class MaterialList extends React.Component<IImgListProps, {}> {
this.readyMtl = data; this.readyMtl = data;
let mtl = app.Database.MaterialTable.GetAt(data.name); let mtl = app.Database.MaterialTable.GetAt(data.name);
if (!mtl) if (!mtl)
this.coverMtl(); this.coverMtl(false);
else else
this.handleOpen(); this.handleOpen();
}; };
@ -209,7 +213,7 @@ export class MaterialList extends React.Component<IImgListProps, {}> {
} }
this.handleClose(); this.handleClose();
}; };
private coverMtl = async () => private coverMtl = async (isCover: boolean = true) =>
{ {
CommandWrap(async () => CommandWrap(async () =>
{ {
@ -226,12 +230,12 @@ export class MaterialList extends React.Component<IImgListProps, {}> {
this.readyMtl = null; this.readyMtl = null;
AppToaster.show({ AppToaster.show({
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
message: "图纸覆盖成功", message: `图纸${isCover ? "覆盖" : "应用"}成功`,
timeout: 1000 timeout: 1000
}); });
} }
this.handleClose(); this.handleClose();
}, "材质覆盖"); }, `材质${isCover ? "覆盖" : "应用"}`);
}; };
private applyEntity = (data: { material_id: string; name: string; }) => private applyEntity = (data: { material_id: string; name: string; }) =>
{ {
@ -314,6 +318,7 @@ export class MaterialList extends React.Component<IImgListProps, {}> {
dragStart={this.handleDragStart} dragStart={this.handleDragStart}
selectData={this.props.selectIds} selectData={this.props.selectIds}
hintClassName="hint editor-lint" hintClassName="hint editor-lint"
isSmaller={this.props.isRightToolbar}
canDrag canDrag
renderButtons={(data) => <> renderButtons={(data) => <>
{ {

@ -19,6 +19,7 @@ export class Pagination extends React.Component<IPaginationProps, { startPage: n
private maxCount: number; private maxCount: number;
private _timeId: NodeJS.Timeout = null; private _timeId: NodeJS.Timeout = null;
private isReset: boolean = true; //通过搜索时需要重置状态渲染页面
constructor(props) constructor(props)
{ {
super(props); super(props);
@ -33,7 +34,8 @@ export class Pagination extends React.Component<IPaginationProps, { startPage: n
const { pageData, getImgListFun } = this.props; const { pageData, getImgListFun } = this.props;
const pages = Math.ceil(pageData.count / pageData.pageCount); const pages = Math.ceil(pageData.count / pageData.pageCount);
let lis: JSX.Element[] = []; let lis: JSX.Element[] = [];
for (let i = this.state.startPage; i < this.state.startPage + this.maxCount; i++) let startPage = this.isReset ? 1 : this.state.startPage;
for (let i = startPage; i < startPage + this.maxCount; i++)
{ {
if (i > pages) if (i > pages)
break; break;
@ -41,15 +43,17 @@ export class Pagination extends React.Component<IPaginationProps, { startPage: n
<li <li
key={i} key={i}
className={pageData.currentPage === i ? "active" : ""} className={pageData.currentPage === i ? "active" : ""}
onClick={ onClick={() =>
() =>
{ {
this.isReset = false;
let n = Math.ceil(pageData.currentPage / this.maxCount) - 1;
this.setState({ startPage: 1 + n * this.maxCount });
getImgListFun({ curr_page: i }); getImgListFun({ curr_page: i });
} }}
}
>{i}</li> >{i}</li>
); );
} }
this.isReset = true;
return lis; return lis;
}; };
private handleChangePage = (isNext = true) => private handleChangePage = (isNext = true) =>
@ -67,6 +71,7 @@ export class Pagination extends React.Component<IPaginationProps, { startPage: n
{ {
const { pageData, getImgListFun } = this.props; const { pageData, getImgListFun } = this.props;
let n = Math.ceil(pageData.currentPage / this.maxCount) - 1; let n = Math.ceil(pageData.currentPage / this.maxCount) - 1;
this.isReset = false;
this.setState({ startPage: 1 + n * this.maxCount }); this.setState({ startPage: 1 + n * this.maxCount });
getImgListFun({ curr_page: pageData.currentPage }); getImgListFun({ curr_page: pageData.currentPage });
}; };

@ -6,8 +6,8 @@ import { DirectoryId } from '../../../Common/Request';
import { PhysicalMaterialRecord } from '../../../DatabaseServices/PhysicalMaterialRecord'; import { PhysicalMaterialRecord } from '../../../DatabaseServices/PhysicalMaterialRecord';
import { userConfig } from '../../../Editor/UserConfig'; import { userConfig } from '../../../Editor/UserConfig';
import { MaterialContainer } from '../MaterialContainer'; import { MaterialContainer } from '../MaterialContainer';
import { CommonPanel } from './CommonPanel';
import { MaterialList } from './MaterialList'; import { MaterialList } from './MaterialList';
import { RightMaterialPanel } from './RightMaterialPanel';
import './TexturePanel.less'; import './TexturePanel.less';
const smallIcon: React.CSSProperties = { const smallIcon: React.CSSProperties = {
@ -31,9 +31,11 @@ export class RightMaterial extends React.Component<{}>
render() render()
{ {
return ( return (
<RightMaterialPanel <CommonPanel
defaultDirId={DirectoryId.MaterialDir} defaultDirId={DirectoryId.MaterialDir}
getUrl={MaterialUrls.get} getUrl={MaterialUrls.get}
deleteUrl={MaterialUrls.delete}
isRightMaterialPanel={true}
> >
<MaterialList <MaterialList
startCreateMat={this.startCreateMat} startCreateMat={this.startCreateMat}
@ -48,7 +50,7 @@ export class RightMaterial extends React.Component<{}>
isOpen={this.startCreateMat} isOpen={this.startCreateMat}
/> />
} }
</RightMaterialPanel> </CommonPanel>
); );
} }
} }

@ -1,396 +0,0 @@
import { Classes, ITreeNode, Tree } from "@blueprintjs/core";
import hotkeys from "hotkeys-js-ext";
import { action, observable } from "mobx";
import { observer } from "mobx-react";
import React from "react";
import { end } from "xaop";
import { app } from "../../../ApplicationServices/Application";
import { arrayLast } from "../../../Common/ArrayExt";
import { DirUrl } from "../../../Common/HostUrl";
import { MouseKey } from "../../../Common/KeyEnum";
import { DirectoryId, PostJson, RequestStatus } from "../../../Common/Request";
import { CommonPanelEventBus } from "./CommonPanel";
import { Pagination } from "./Pagination";
import './RightMyMaterialPanel.less';
export interface IDirectoryProps
{
id: DirectoryId | string;
path: string;
pathNum: number[];
}
interface ICommonPanelState
{
nodes: ITreeNode[]; //目录节点
defaultDirName: string; //新目录名字
updateNode: ITreeNode; //需要更新的目录节点
}
interface ICommonPanelProps
{
defaultDirId: string; //根目录ID
getUrl: string; //获取数据URL
dirNameFilter?: string[];
}
@observer
export class RightMaterialPanel extends React.Component<ICommonPanelProps, ICommonPanelState>
{
constructor(props)
{
super(props);
this.state = {
nodes: [],
defaultDirName: "",
updateNode: undefined,
};
this._CurrentDir.id = DirectoryId.MaterialDir;
this._IdKey = "material_id";
}
static CurrentDirCache: Map<string, IDirectoryProps> = new Map();
@observable _DataList = [];
@observable _SelectIds = new Set<string>();
@observable _CurrentDir: IDirectoryProps = {
id: DirectoryId.None,
path: "",
pathNum: []
};
@observable _PageData = { //分页数据
count: 0,
currentPage: 1,
pageCount: 15
};
@observable _SearchStr = "";//搜索材质名
_IdKey: string;
_Events: Function[] = [];
_Tree: HTMLElement; //目录数元素
_TimeId = null; //搜索时的定时器
get IsCtrlDown()
{
return app.Editor.ModalManage.IsCtrlDown || hotkeys.ctrl;
}
componentDidMount()
{
//监听右键其他位置
if (this._Tree)
{
this._Tree.addEventListener('mousedown', this._HandleTreeMouseDown);
}
this._LoadingData();
//如果有通知修改,那么我们刷新这个
this._Events.push(end(CommonPanelEventBus.GetInstance(), CommonPanelEventBus.GetInstance().UpdateEvent, (url: string, isdelete?: boolean) =>
{
if (url === this.props.getUrl)
{
if (isdelete)
{
Object.assign(this._CurrentDir, { id: this.props.defaultDirId, path: "", pathNum: [] });
RightMaterialPanel.CurrentDirCache.delete(this.props.defaultDirId);
}
this._LoadingData();
}
}));
}
componentWillUnmount()
{
if (this._Tree)
{
this._Tree.removeEventListener('mousedown', this._HandleTreeMouseDown);
}
this._Events.forEach(f => f());
this._Events.length = 0;
}
render()
{
return (
<div id="RightMyMaterialPanel" style={{ position: "relative" }}>
<div className="searchMaterial">
<input
disabled={this.props.defaultDirId === DirectoryId.HistoryDit}
className="bp3-input"
placeholder="搜索材质..."
type="search"
defaultValue={this._SearchStr}
onKeyDown={(e) => { e.stopPropagation(); }}
onChange={(e) => this._HandleSearch(e)}
/>
</div>
<div className="materialParams">
<div
className="bp3-card img-tree"
ref={c => this._Tree = c}
>
<Tree
contents={this.state.nodes}
onNodeClick={this._HandleNodeClick}
onNodeCollapse={(node) => this._HandleNodeCollapse(node, true)}
onNodeExpand={(node) => this._HandleNodeCollapse(node, false)}
className={Classes.ELEVATION_0}
/>
</div>
<div
className="bp3-card img-lib"
>
{
React.Children.map(this.props.children, child =>
child && React.cloneElement(child as React.DetailedReactHTMLElement<any, any>,
{
dataList: this._DataList,
currentDir: this._CurrentDir,
getData: this._HandleGetData,
select: this._HandleSelectData,
selectIds: this._SelectIds,
})
)
}
{
this._PageData.count > this._PageData.pageCount &&
<Pagination
getImgListFun={this._HandleGetData}
pageData={this._PageData}
maxCount={3}
/>
}
</div>
</div>
</div>
);
}
_HandleSelectData = (e: React.MouseEvent<HTMLInputElement>, data) =>
{
const id = data[this._IdKey];
const selectIds = this._SelectIds;
if (e.button === MouseKey.Left)
{
if (!this.IsCtrlDown)
selectIds.clear();
}
else
{
if (!this.IsCtrlDown && !selectIds.has(id))
selectIds.clear();
}
if (this.IsCtrlDown)
{
if (selectIds.has(id))
selectIds.delete(id);
else
selectIds.add(id);
}
else
selectIds.add(id);
};
//选中目录亮显
_SelectNode = (nodeData: ITreeNode, isSelected?: boolean) =>
{
this._ForEachNode(this.state.nodes, n => (n.isSelected = false));
nodeData.isSelected = true;
this.setState(this.state);
};
//点击目录
_HandleNodeClick = async (nodeData: ITreeNode, _nodePath: number[]) =>
{
const isReLoad = nodeData.id !== this._CurrentDir.id;
this._GetCurrentDir(nodeData.id, _nodePath);
this._SelectIds.clear();
if (isReLoad)
await this._HandleGetData();
this._SelectNode(nodeData);
};
//去掉其他节点被选择状态
_ForEachNode(nodes: ITreeNode[], callback: (node: ITreeNode) => void)
{
if (nodes == null)
{
return;
}
for (const node of nodes)
{
callback(node);
this._ForEachNode(node.childNodes, callback);
}
}
//获取当前目录路径
_GetCurrentDir = (dirId: React.ReactText, nodePath: number[]) =>
{
let path = "";
let childNodes: ITreeNode[];
for (let i of nodePath)
{
let node: ITreeNode;
if (!childNodes)
{
node = this.state.nodes[i];
}
else
{
node = childNodes[i];
}
path += node.label + "/";
childNodes = node.childNodes;
}
Object.assign(this._CurrentDir, { id: dirId, path, pathNum: nodePath });
RightMaterialPanel.CurrentDirCache.set(this.props.defaultDirId, { id: dirId as DirectoryId, path, pathNum: nodePath });
};
//分析目录转换为ui节点数
_ParseNodes = (dirs: any) =>
{
let newNodes: ITreeNode[] = [];
for (let dir of dirs)
{
let node: ITreeNode = {
id: dir.dir_id,
label: dir.dir_name,
icon: "folder-close",
hasCaret: dir.childs.length > 0,
className: dir.dir_id, //为了识别这个元素的目录id
childNodes: this._ParseNodes(dir.childs),
};
newNodes.push(node);
}
return newNodes;
};
//展开折叠目录
_HandleNodeCollapse = (nodeData: ITreeNode, isCollapse: boolean) =>
{
nodeData.isExpanded = !isCollapse;
this.setState(this.state);
};
/**
*
* name-,curr_page-,dir_id:id
* desc
*/
@action
_HandleGetData = async (queryData?: { dir_id?: string, name?: string, curr_page?: number; }) =>
{
let query: any;
query = {
dir_id: this._CurrentDir.id,
curr_page: 1,
page_count: this._PageData.pageCount,
name: this._SearchStr,
};
//若不传入数据,用默认查询数据.
if (queryData)
{
Object.assign(query, queryData);
}
this._PageData.currentPage = query.curr_page;
if (query.name && query.dir_id === this.props.defaultDirId)
query.dir_id = DirectoryId.None;
let data = await PostJson(this.props.getUrl, query);
if (data.err_code === RequestStatus.Ok && Number(data.count))
{
let dataList: any[];
dataList = data.images || data.materials || data.toplines || data.files || data.modules || [];
dataList.forEach(d => d.isChecked = false);
this._DataList = dataList;
}
else
this._DataList.length = 0;
this._PageData.count = parseInt(data.count);
this._SelectIds.clear();
};
//点击节点容器的动作
_HandleTreeMouseDown = (e: MouseEvent) =>
{
let el = e.target as HTMLElement;
if (e.button === MouseKey.Left)
{
if (el.classList.contains('bp3-tree'))
{
this._ForEachNode(this.state.nodes, n => (n.isSelected = false));
if (this._CurrentDir.id !== this.props.defaultDirId)
{
Object.assign(this._CurrentDir, { id: this.props.defaultDirId, path: "", pathNum: [] });
RightMaterialPanel.CurrentDirCache.set(this.props.defaultDirId, { id: this.props.defaultDirId as DirectoryId, path: "", pathNum: [] });
this._HandleGetData();
}
}
}
};
_LoadingData = async () =>
{
let data = await PostJson(DirUrl.query, { dir_type: this.props.defaultDirId });
if (data.err_code === RequestStatus.Ok)
{
let dirs = data.dirs as { dir_name: string; }[];
if (this.props.dirNameFilter)
{
dirs = dirs.filter(dir =>
{
return this.props.dirNameFilter.some(s => dir.dir_name.includes(s));
});
}
this.setState({ nodes: this._ParseNodes(dirs) });
}
let currentDirProps = RightMaterialPanel.CurrentDirCache.get(this.props.defaultDirId);
if (currentDirProps)
{
this._LoadCurrentNode(currentDirProps);
}
await this._HandleGetData();
setTimeout(() =>
{
if (currentDirProps?.pathNum?.length && this._Tree)
{
let treeRoot = this._Tree.children[0].children[0];
treeRoot.scrollTop = arrayLast(currentDirProps.pathNum) * 30;
}
}, 100);
};
_LoadCurrentNode = (currentDirProps: IDirectoryProps) =>
{
let node: ITreeNode;
for (let n of currentDirProps.pathNum)
{
if (!node)
{
node = this.state.nodes[n];
}
else
node = node.childNodes[n];
if (!node) return;
if (node.childNodes.length)
node.isExpanded = true;
}
if (node)
{
this._SelectNode(node, true);
Object.assign(this._CurrentDir, currentDirProps);
}
};
_HandleSearch = async (e: React.ChangeEvent<HTMLInputElement>) =>
{
this._SearchStr = e.currentTarget.value;
if (this._TimeId)
clearTimeout(this._TimeId);
this._TimeId = setTimeout(async () =>
{
await this._HandleGetData();
}, 500);
};
}

@ -1,96 +0,0 @@
#RightMyMaterialPanel {
height : 100px;
padding: 0;
.searchMaterial{
margin: 2px 0 0 0;
height: 34px;
input{
width: 100%;
}
}
.materialParams{
height: calc(100% - 34px);
.img-tree {
height : 40%;
width : 100%;
padding : 0;
overflow: auto;
.bp3-tree {
height : 100%;
padding-bottom: 10px;
box-shadow: none;
&>ul {
max-height: 95%;
overflow : auto;
}
.bp3-tree-node-content-1 {
padding-left: 10px;
}
}
}
.img-lib {
width : 100%;
height : 60%;
padding : 0 10px;
overflow : visible;
position : relative;
display : flex;
flex-direction: column;
&>:nth-child(1){
flex: 1;
}
.mat-list:first-child {
padding-bottom: 10px;
li {
cursor: pointer;
}
.look-mat {
user-select: none;
}
&>li {
text-align: center;
.hint:hover::before {
content : none;
}
&>.bp3-control {
left: 10px;
top : 10;
}
&>p {
margin-bottom: 0;
width : 100%;
}
}
}
.bp3-dialog-container {
position: fixed;
left : 0;
top : 0;
z-index : 30;
.bp3-dialog {
width : unset;
margin : 0;
padding: 0;
}
}
}
}
}

@ -57,23 +57,31 @@
} }
#data-list { #data-list {
overflow: scroll;
height: 100%;
.info-header { .info-header {
display: flex; display: flex;
padding: 5px 0; padding: 5px 0;
:nth-child(-n + 2) { &>:first-child {
span {
margin-left: 50px;
}
}
&>:nth-child(-n + 2) {
flex: 3 3 0%; flex: 3 3 0%;
} }
:nth-child(n + 3) { &>:nth-child(n + 3) {
flex: 2 2 0%; flex: 2 2 0%;
} }
} }
overflow: scroll;
height: 100%;
.data-list-info { .data-list-info {
margin-top: 0;
&>li { &>li {
display: flex; display: flex;
align-items: center; align-items: center;

Loading…
Cancel
Save