!2306 功能:增加企业私有模型展示与管理

20230809
林伟强 1 year ago committed by ChenX
parent a11d62dfba
commit cdc238da32

@ -193,3 +193,13 @@ export const GalleryURL = {
//UE图纸分享
export const RenderShare = CURRENT_HOST + '/CAD-renderShare';
//私有企业库
export const PrivateModule = {
QueryModuleDirs: CURRENT_HOST + "/CAD-queryPriviteModuleDirs",//目录列表
CreateModuleDirs: CURRENT_HOST + "/CAD-createPrivteModuleDir",//创建目录
UpdateModuleDirs: CURRENT_HOST + "/CAD-updatePrivteModuleDir",//修改目录
DeleteModuleDirs: CURRENT_HOST + "/CAD-deletePrivateModuleDir",//删除目录
GetModuleList: CURRENT_HOST + "/CAD-privateModuleLists",//模型列表
UpdateModule: CURRENT_HOST + "/CAD-privateModuleUpdate"//修改模型信息
};

@ -1,9 +1,10 @@
import { Box3, Matrix3, Matrix4, Mesh, MeshPhongMaterial, MeshPhysicalMaterial, Object3D, Vector3 } from "three";
import { Box3, Group, Matrix3, Matrix4, Mesh, MeshPhongMaterial, MeshPhysicalMaterial, Object3D, Vector3 } from "three";
import { BoxLine } from "../../Add-on/testEntity/BoxLine";
import { ConverMaterial2, ParseBoxUrl, ParseFBXUrl, UE_FBX_LOADER } from "../../Add-on/testEntity/ParseMaterialImage";
import { HostApplicationServices } from "../../ApplicationServices/HostApplicationServices";
import { ColorMaterial } from "../../Common/ColorPalette";
import { DisposeThreeObj, Object3DRemoveAll } from "../../Common/Dispose";
import { Log, LogType } from "../../Common/Log";
import { UpdateDraw } from "../../Common/Status";
import { ObjectSnapMode } from "../../Editor/ObjectSnapMode";
import { Box3Ext } from "../../Geometry/Box";
@ -236,19 +237,37 @@ export class EntityRef extends Entity
IndexedDbStore.CADStore().then(async store =>
{
let array = await store.Get(StoreName.FBX, this.Url);
let needSave = false;
if (!array)
{
needSave = true;
let fbxurl = ParseFBXUrl(this._url);
let res = await fetch(fbxurl);
array = await res.arrayBuffer();
store.Put(StoreName.FBX, this.Url, array);
if (res.status === 200)
array = await res.arrayBuffer();
else
{
let errorMsg = "错误:网络异常或者服务端资源不存在!无法请求到服务器FBX资源:" + this._url;
Log(errorMsg, LogType.Error, [this]);
//TODO:模型请求失败 是不是应该做点什么 过会重试?
reportError(errorMsg);
return;
}
}
// let fbxUrl = require("./LOD_DEAA_0055.FBX").default;
// let res = await fetch(fbxUrl);
// array = await res.arrayBuffer();
let newObject = UE_FBX_LOADER.parse(array, UE_FBX_LOADER.path);
let newObject: Group;
try
{
newObject = UE_FBX_LOADER.parse(array, UE_FBX_LOADER.path);
} catch (error)
{
let errorMsg = "错误:FBX资源无法解析:" + this._url;
Log(errorMsg, LogType.Error, [this]);
reportError(new Error(errorMsg));
return;
}
if (needSave)
store.Put(StoreName.FBX, this.Url, array);
fbxloaded = true;
DisposeThreeObj(dObj);

@ -86,7 +86,7 @@ export interface Folder
{
dir_id: string;
dir_name: string;
create_date: string;
create_date?: string;
}
export interface UserFolder extends IResponseData
{
@ -98,3 +98,56 @@ export interface UserCollections extends IResponseData
modules: ModuleData[];
class: any;
}
export interface PrivateDirsParams
{
curr_page: number;
page_count: number;
order: string;
dir_id?: string;
name?: string;
sn?: string;
module_id?: string;
}
export interface PrivateDirs
{
dir_id: string;
dir_name: string;
dir_level?: string;
create_date?: string;
update_date?: string;
childs?: PrivateDirs[];
}
export interface PrivateModuleDirs extends IResponseData
{
dirs: PrivateDirs[];
}
export interface PrivateModuleItem
{
module_id: string;
dir_id: string;
name: string;
sn: String;
logo: string;
path: string;
dimension: string;
state: string;
create_date: string;
update_data: string;
comments: string;
}
export interface PrivateModuleList extends IResponseData
{
count: number;
modules: PrivateModuleItem[];
}
export enum ModuleType
{
Public = 0,//公有模型
Private = 1,//私有企业库模型
}

@ -1,6 +1,6 @@
.resourcePanel{
position : relative;
width : 300px;
width : 350px;
background: #ffffff;
box-sizing: border-box;
ul{
@ -38,7 +38,6 @@
margin : 10px 0;
display : flex;
justify-content : space-between;
padding : 0 5px;
align-items : center;
}
.resources{
@ -165,7 +164,6 @@
box-sizing: border-box;
position : absolute;
width : 300px;
box-sizing: border-box;
.radioGroup{
display : flex;
flex-direction: row;
@ -190,7 +188,7 @@
overflow-y : auto;
.pagination{
height : 50px;
width : 280px;
width : 100%;
z-index : 3;
box-sizing : border-box;
display : flex;
@ -234,8 +232,8 @@
margin-top: 10px;
position : relative;
.items{
width : 120px;
height : 120px;
width : 144px;
height : 144px;
position : relative;
margin-left : 10px;
margin-top : 10px;
@ -250,7 +248,7 @@
transition : opacity 0.1s ease-in 0s;
position : absolute;
box-sizing : border-box;
width : 120px;
width : 100%;
opacity : 0;
display : flex;
justify-content: space-between;
@ -412,6 +410,7 @@
flex-direction : column;
justify-content: space-around;
overflow-y : auto;
.bp3-navbar-group
{
width : 100%;
@ -508,3 +507,149 @@
padding-bottom : 10px;
}
}
.enterprise
{
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
.bp3-tree-node
{
.bp3-input
{
&:focus
{
border-radius: 0px;
border: 1px solid #eeeeee;
}
}
}
.navbarGroup
{
display: flex;
justify-content: space-between;
float: none;
}
.bp3-tree
{
flex: 1;
height: 100%;
>ul
{
height: 95%;
overflow-y: auto;
}
}
li
{
&:hover{
background: none !important;
}
}
.moduleList
{
height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
.moduleControl{
display: flex;
flex-direction:row-reverse;
align-items: center;
border-bottom: 1px solid #c3c4c5;
padding-bottom: 4px;
}
.itemList
{
width: 100%;
height: 100vh;
overflow-y: auto;
overflow-x: hidden;
box-sizing: border-box;
margin: 0px;
position: relative;
.items
{
float: none;
margin: 0
}
.moduleName
{
width: 144px;
>div
{
padding: 6px;
cursor: default;
}
}
}
.itemOptions
{
flex-direction: row-reverse;
}
}
.moduleItem
{
text-align: center;
padding: 4px;
padding-bottom: 0px;
border-radius: 2px;
display: inline-block;
margin-left: 10px;
margin-top: 10px;
}
.moduleSelected
{
background-color: #52aee7;
}
.privateDirName
{
height: auto;
}
.enterpriseOption{
.pagination{
height : 50px;
width : 100%;
z-index : 3;
box-sizing : border-box;
display : flex;
justify-content : center;
align-content : center;
padding : 0px 20px;
padding-top : 5px;
span{
display : block;
line-height: 30px;
font-size : 14px;
margin-left: -20px;
}
button {
>span {
transform: rotate(90deg);
}
}
button:nth-child(1){
left: 80px;
}
button:nth-child(2){
height : 30px;
position: absolute;
left : -90px;
}
}
}
}

@ -6,6 +6,7 @@ import Resource_By_Image from "./Resource_By_Image";
import Resource_CategoriesList from "./Resource_CategoriesList";
import Resource_ResourceList from "./Resource_ResourceList";
import Resource_Search from "./Resource_Search";
import Resoure_Enterprise from "./Resoure_Enterprise";
import ResourceStore from "./RsourceStore";
import UserCollect from "./UserCollect";
@ -16,6 +17,8 @@ export const ResourcePanelType = {
myCollect: Symbol("用户收藏"),
collectList: Symbol("收藏列表"),
resourceByImg: Symbol("按图搜索"),
enterpriseFolder: Symbol("企业库文件"),
enterpriseModule: Symbol("企业库模型")
};
@observer
export class ResourcePanel extends Component<{}, {}>
@ -36,6 +39,7 @@ export class ResourcePanel extends Component<{}, {}>
{Boolean(this.resourceStore.currentState === ResourcePanelType.resourceList) && <Resource_ResourceList />}
{Boolean(this.resourceStore.currentState === ResourcePanelType.myCollect) && <UserCollect />}
{Boolean(this.resourceStore.currentState === ResourcePanelType.resourceByImg) && <Resource_By_Image />}
{Boolean(this.resourceStore.currentState === ResourcePanelType.enterpriseFolder) && <Resoure_Enterprise />}
</Card>
</div>
);

@ -2,7 +2,7 @@ import { Spinner } from '@blueprintjs/core';
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import { ModuleData } from './ResourceInterfaces';
import { ResourceItem, R_Pagination } from './Resource_ResourceList';
import { R_Pagination, ResourceItem } from './Resource_ResourceList';
import ResourceStore, { pageCount } from './RsourceStore';
import { RenderNoResult } from './UserCollect';

@ -317,8 +317,6 @@ export default class Resource_ResourceList extends Component<{}, {}>
}
}
/**
*
* @param props

@ -109,6 +109,7 @@ export default class Resource_Search extends Component<{}, {}>
render()
{
const isEnterprise = [ResourcePanelType.enterpriseFolder, ResourcePanelType.enterpriseModule].includes(this.resourceStore.currentState);
return (
<>
<div className="header">
@ -125,7 +126,7 @@ export default class Resource_Search extends Component<{}, {}>
/>
}
<span>
{Boolean(this.resourceStore.currentState !== ResourcePanelType.myCollect) &&
{Boolean(![ResourcePanelType.myCollect, ResourcePanelType.enterpriseFolder].includes(this.resourceStore.currentState)) &&
<Popover position="auto" minimal>
<Button
small
@ -153,7 +154,7 @@ export default class Resource_Search extends Component<{}, {}>
</div>
</Popover>
}
{Boolean(this.resourceStore.currentState !== ResourcePanelType.myCollect) &&
{Boolean(![ResourcePanelType.myCollect, ResourcePanelType.enterpriseFolder].includes(this.resourceStore.currentState)) &&
// Boolean(this.resourceStore.currentState !== ResourcePanelType.resourceList) &&
<Popover position="auto" minimal
content={
@ -183,16 +184,32 @@ export default class Resource_Search extends Component<{}, {}>
/>
</Popover>
}
<Button small minimal
text="收藏"
rightIcon="star"
onClick={() =>
{
this.resourceStore.currentState = ResourcePanelType.myCollect;
this.resourceStore.collectType = ResourcePanelType.myCollect;
this.resourceStore.c = undefined;
}}
/>
{Boolean(this.resourceStore.currentState !== ResourcePanelType.enterpriseFolder) &&
<Button small minimal
text="收藏"
rightIcon="star"
onClick={() =>
{
this.resourceStore.currentState = ResourcePanelType.myCollect;
this.resourceStore.collectType = ResourcePanelType.myCollect;
this.resourceStore.c = undefined;
}}
/>
}
{Boolean(this.resourceStore.currentState !== ResourcePanelType.myCollect) &&
<Button
small
minimal
text="企业库"
rightIcon="briefcase"
onClick={() =>
{
this.resourceStore.currentState = ResourcePanelType.enterpriseFolder;
this.resourceStore.enterpriseType = ResourcePanelType.enterpriseFolder;
this.resourceStore.c = undefined;
}}
/>
}
</span>
<Button
icon="small-cross"
@ -223,12 +240,21 @@ export default class Resource_Search extends Component<{}, {}>
e.stopPropagation();
if (e.key === 'Enter')
{
const input = document.querySelector("#searchText") as HTMLInputElement;
if (this.resourceStore.currentState === ResourcePanelType.collectList || this.resourceStore.currentState === ResourcePanelType.myCollect)
{
const input = document.querySelector("#searchText") as HTMLInputElement;
this.resourceStore.SwitchFolder({ dir_id: "", dir_name: "全部" } as Folder, input.value.trim());
} else
}
else if ([ResourcePanelType.enterpriseFolder, ResourcePanelType.enterpriseModule].includes(this.resourceStore.currentState))
{
this.resourceStore.currentfolder = { dir_id: "", dir_name: "全部" };
this.resourceStore.privateModule.params.dir_id = "";
this.resourceStore.privateModule.params.curr_page = 1;
this.resourceStore.privateModule.params.name = input.value.trim();
this.resourceStore.enterpriseType = ResourcePanelType.enterpriseModule;
this.resourceStore.GetPrivateModule();
}
else
{
this.SearchPublicStore();
}
@ -247,29 +273,41 @@ export default class Resource_Search extends Component<{}, {}>
if (this.resourceStore.currentState === ResourcePanelType.collectList || this.resourceStore.currentState === ResourcePanelType.myCollect)
{
this.resourceStore.SwitchFolder({ dir_id: "", dir_name: "全部" } as Folder, input.value.trim());
} else
}
else if (isEnterprise)
{
this.resourceStore.currentfolder = { dir_id: "", dir_name: "全部" };
this.resourceStore.privateModule.params.dir_id = "";
this.resourceStore.privateModule.params.curr_page = 1;
this.resourceStore.privateModule.params.name = input.value.trim();
this.resourceStore.enterpriseType = ResourcePanelType.enterpriseModule;
this.resourceStore.GetPrivateModule();
}
else
{
this.SearchPublicStore();
}
}}
/>
</Tooltip>
<Tooltip
minimal
content={"图片搜索"}
position={Position.BOTTOM}
openOnTargetFocus={false}
>
<Button
small
{!isEnterprise &&
<Tooltip
minimal
icon='camera'
onClick={() =>
{
this.fileUploader.current?.click();
}}
/>
</Tooltip>
content={"图片搜索"}
position={Position.BOTTOM}
openOnTargetFocus={false}
>
<Button
small
minimal
icon='camera'
onClick={() =>
{
this.fileUploader.current?.click();
}}
/>
</Tooltip>
}
<input
ref={this.fileUploader}
type='file'
@ -290,7 +328,18 @@ export default class Resource_Search extends Component<{}, {}>
{
const input = document.querySelector("#searchText") as HTMLInputElement;
this.resourceStore.SwitchFolder({ dir_id: "", dir_name: "全部" } as Folder, input.value.trim());
} else
}
else if (isEnterprise)
{
const input = document.querySelector("#searchText") as HTMLInputElement;
this.resourceStore.currentfolder = { dir_id: "", dir_name: "全部" };
this.resourceStore.privateModule.params.dir_id = "";
this.resourceStore.privateModule.params.curr_page = 1;
this.resourceStore.privateModule.params.name = input.value.trim();
this.resourceStore.enterpriseType = ResourcePanelType.enterpriseModule;
this.resourceStore.GetPrivateModule();
}
else
{
this.SearchPublicStore();
}

@ -1,6 +1,6 @@
import { ResourceLibraryURL, UserCollection } from "../../../../Common/HostUrl";
import { PrivateModule, ResourceLibraryURL, UserCollection } from "../../../../Common/HostUrl";
import { Post, PostJson, RequestStatus } from "../../../../Common/Request";
import { Folder, ModuleDetail, ModuleList, RenderClassList, UserCollections, UserFolder } from "./ResourceInterfaces";
import { Folder, ModuleDetail, ModuleList, PrivateDirsParams, PrivateModuleDirs, PrivateModuleList, RenderClassList, UserCollections, UserFolder } from "./ResourceInterfaces";
export async function getClassList(class_type: number)
{
@ -47,3 +47,19 @@ export async function GetUserCollection(folder?: Folder, page?: string, pageCoun
if (response.err_code !== RequestStatus.Ok) return;
return response;
}
//私有企业库目录
export async function GetPrivateModuleDirs()
{
let response = await Post(PrivateModule.QueryModuleDirs) as PrivateModuleDirs;
if (response.err_code !== RequestStatus.Ok) return;
return response;
}
//私有企业库模型列表
export async function GetPrivateModuleList(query: PrivateDirsParams)
{
let response = await PostJson(PrivateModule.GetModuleList, { ...query }) as PrivateModuleList;
if (response.err_code !== RequestStatus.Ok) return;
return response;
}

@ -0,0 +1,587 @@
import { Button, Checkbox, Classes, ContextMenu, Dialog, ITreeNode, Icon, InputGroup, Intent, Menu, MenuItem, Navbar, NavbarGroup, NavbarHeading, NonIdealState, Popover, Position, Spinner, Tree, TreeNodeInfo } from '@blueprintjs/core';
import { observable } from 'mobx';
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import { PrivateModule } from '../../../../Common/HostUrl';
import { IResponseData, PostJson } from '../../../../Common/Request';
import { AppToaster } from '../../Toaster';
import { ModuleType, PrivateDirs, PrivateModuleItem } from './ResourceInterfaces';
import { ResourcePanelType } from './ResourcePanel';
import { GetCssObj, R_Pagination, RenderDetailImg } from './Resource_ResourceList';
import ResourceStore from './RsourceStore';
@observer
export default class Resoure_Enterprise extends Component<{}, {}>
{
resourceStore: ResourceStore = ResourceStore.GetInstance();
render()
{
return (
<div className='enterprise'>
{this.resourceStore.enterpriseType === ResourcePanelType.enterpriseFolder && <PrivateDirTree />}
{this.resourceStore.enterpriseType === ResourcePanelType.enterpriseModule && <PrivateModuleList />}
</div >
);
}
}
class EnterpriseInputGroup extends React.Component<{ defaultValue: string, placeholder: string, onSuccess: (value: string) => void, onCancel: () => void; className?: string, }, {}>
{
private onKeydown = async (e: React.KeyboardEvent<HTMLInputElement>) =>
{
e.stopPropagation();
if (e.key === 'Enter')
{
let { value } = e.target as HTMLInputElement;
await this.props.onSuccess(value);
}
else if (e.key === "Escape")
{
this.props.onCancel();
}
};
render()
{
return (
<>
<InputGroup
className={this.props.className}
defaultValue={this.props.defaultValue}
autoFocus
placeholder={this.props.placeholder}
onClick={(e) =>
{
e.stopPropagation();
}}
onKeyDown={(e) => this.onKeydown(e)}
onKeyUp={(e) => { e.currentTarget.value = e.currentTarget.value.replaceAll(' ', ''); }} //过滤空格
onBlur={(e) =>
{
let { value } = e.target;
if (value)
this.props.onSuccess(value);
else
this.props.onCancel();
}}
/>
</>
);
}
}
@observer
class PrivateDirTree extends Component<{ handMoveModule?: (id: string) => void; }, { nodes: ITreeNode[]; }> {
constructor(props)
{
super(props);
this.state = {
nodes: []
};
}
@observable currentInfo = { id: "", name: "" };
initNodes = async () =>
{
//初始化目录
this.setState({ nodes: this.ParseDirNodes(this.resourceStore.privateDirs, "0", true) });
};
async componentWillMount()
{
if (this.resourceStore.privateDirs.length)
this.initNodes();
else
{
await this.resourceStore.GetPrivateDir();
this.initNodes();
}
}
resourceStore: ResourceStore = ResourceStore.GetInstance();
SwitchFolder = (nodeData: ITreeNode) =>
{
const id = String(nodeData.id);
const label = String(nodeData.label);
if (this.props.handMoveModule)
{
this.props.handMoveModule(id);
return;
}
this.resourceStore.privateModule.params.curr_page = 1;
this.resourceStore.privateModule.params.dir_id = id;
this.resourceStore.enterpriseType = ResourcePanelType.enterpriseModule;
this.resourceStore.currentfolder = { dir_id: id, dir_name: label };
this.resourceStore.GetPrivateModule();
};
ParseDirNodes = (dirs: PrivateDirs[], defaultId: string, isRoot = true, renameId?: string, parent_id?: string) =>
{
let newNodes: ITreeNode[] = [];
if (isRoot)
{
newNodes = [
{
id: defaultId,
label: "未分类",
icon: "folder-close",
hasCaret: false,
}
];
}
for (let i = 0; i < dirs.length; i += 1)
{
const dir = dirs[i];
let tempCteateId = "";
if (parent_id && parent_id !== "0" && dir.dir_id === parent_id)//子节点新建文件夹
{
tempCteateId = String(new Date().getTime());
dir.childs.push({ dir_id: tempCteateId, dir_name: "", childs: [] });
}
let node: ITreeNode = {
id: dir.dir_id,
label: (renameId || parent_id) && (dir.dir_id === renameId || !dir.dir_name) ?//重命名和子节点新建文件夹
<EnterpriseInputGroup
className={"dirRename"}
defaultValue={dir.dir_name}
placeholder='请输入文件夹名称'
onSuccess={(value) =>
{
this.HandlePrivateDirName(value);
}}
onCancel={() =>
{
this.currentInfo = { id: "", name: "" };
if (parent_id && !dir.dir_name)
dirs.splice(i, 1);
this.initNodes();
}}
/>
: dir.dir_name,
icon: "folder-close",
hasCaret: dir.childs.length > 0,
isExpanded: dir.childs.length > 0,
childNodes: this.ParseDirNodes(dir.childs, defaultId, false, renameId, parent_id),
};
newNodes.push(node);
}
if (isRoot && parent_id === "0")//根节点新建文件夹
{
let createNode: ITreeNode = {
id: String(new Date().getTime()),
label:
<EnterpriseInputGroup
className={"dirRename"}
defaultValue={""}
placeholder='请输入文件夹名称'
onSuccess={(value) =>
{
this.HandlePrivateDirName(value);
}}
onCancel={() =>
{
this.currentInfo = { id: "", name: "" };
this.initNodes();
}}
/>
,
icon: "folder-close",
};
newNodes.push(createNode);
}
return newNodes;
};
HandleNodeCollapse = (nodeData: ITreeNode, isCollapse: boolean) =>
{
nodeData.isExpanded = !isCollapse;
this.setState(this.state);
};
RemoveFolder = async (id: string) =>
{
await PostJson(PrivateModule.DeleteModuleDirs, { dir_id: id });
await this.resourceStore.GetPrivateDir();
this.initNodes();
};
HandlePrivateDirName = async (newName: string) =>
{
newName = newName.trim();
if (newName === '' || newName === this.currentInfo?.name || !this.currentInfo.id)
{
this.initNodes();
return;
}
let res: IResponseData;
if (!this.currentInfo.name)
res = await PostJson(PrivateModule.CreateModuleDirs, { dir_name: newName, parent_dir_id: this.currentInfo.id });
else
res = await PostJson(PrivateModule.UpdateModuleDirs, { dir_id: this.currentInfo.id, dir_name: newName });
if (res.err_msg === 'success')
{
AppToaster.show({
message: "创建成功",
timeout: 2000,
intent: Intent.SUCCESS,
}, "Resoure_Enterprise");
}
await this.resourceStore.GetPrivateDir();
this.initNodes();
this.currentInfo = { id: "", name: "" };
};
ShowContextMenu = async (curNodeData: TreeNodeInfo, nodePath: number[], e: React.MouseEvent<HTMLElement> | MouseEvent) =>
{
e.preventDefault();
ContextMenu.show(
<Menu>
<MenuItem icon='folder-new' disabled={curNodeData.id === "0"} text='新建目录' onClick={() =>
{
if (nodePath.length >= 3)
{
AppToaster.show({
message: "只允许创建3层子目录",
timeout: 3000,
intent: Intent.WARNING
}, "Resoure_Enterprise");
return;
}
this.currentInfo = { id: curNodeData.id as string, name: "" };
this.setState({ nodes: this.ParseDirNodes(this.resourceStore.privateDirs, "0", true, undefined, curNodeData.id as string) });
}}
/>
<MenuItem icon='select' disabled={curNodeData.id === "0"} text='重命名' onClick={() =>
{
this.currentInfo = { id: curNodeData.id as string, name: curNodeData.label as string };
this.setState({ nodes: this.ParseDirNodes(this.resourceStore.privateDirs, "0", true, curNodeData.id as string) });
}}
/>
<MenuItem icon="trash" disabled={curNodeData.id === "0"} text="删除目录" onClick={() =>
{
this.RemoveFolder(curNodeData.id as string);
}}
/>
</Menu>,
{ left: e.clientX, top: e.clientY },
);
};
render()
{
return (
<>
{
!this.props.handMoveModule && <Navbar style={{ marginTop: "5px" }} >
<NavbarGroup className="navbarGroup">
<NavbarHeading >
</NavbarHeading>
<div>
<Button
title='新建文件夹'
minimal
icon='folder-new'
onClick={() =>
{
this.currentInfo = {
id: "0",
name: ""
};
this.setState({ nodes: this.ParseDirNodes(this.resourceStore.privateDirs, "0", true, undefined, "0") });
}} />
</div>
</NavbarGroup>
</Navbar>
}
<div style={{ maxHeight: this.props.handMoveModule ? "50vh" : "unset", overflow: "auto" }}>
<Tree
contents={this.state.nodes}
onNodeClick={this.SwitchFolder}
onNodeCollapse={(node) => this.HandleNodeCollapse(node, true)}
onNodeExpand={(node) => this.HandleNodeCollapse(node, false)}
onNodeContextMenu={!this.props.handMoveModule && this.ShowContextMenu}
className={Classes.ELEVATION_0}
/>
</div>
</>
);
}
}
@observer
class PrivateModuleList extends Component<{}, {}>
{
resourceStore: ResourceStore = ResourceStore.GetInstance();
@observable isBatch: boolean = false;
@observable moveModalVisible: boolean = false;
@observable currentInfo: PrivateModuleItem = undefined;
@observable selectedIds: Set<string> = new Set();
ShowModuleContextMenu = async (e: React.MouseEvent<HTMLDivElement>, module: PrivateModuleItem) =>
{
e.preventDefault();
ContextMenu.show(
<Menu>
{ //批量选择时不能重命名
!this.isBatch && <MenuItem icon='select' text='重命名' onClick={() =>
{
this.currentInfo = module;
}}
/>
}
<MenuItem icon="move" text="移动" onClick={() =>
{
this.moveModalVisible = true;
}}
/>
</Menu>,
{ left: e.clientX, top: e.clientY },
() => { if (!this.isBatch && !this.moveModalVisible) this.selectedIds.clear(); }
);
};
HandMoveModule = async (id: string) =>
{
if (id === this.resourceStore.privateModule.params.dir_id)
{
AppToaster.show({
message: "模型已处于当前目录下",
timeout: 2000,
intent: Intent.WARNING,
}, "Resoure_Enterprise");
return;
}
const res: IResponseData = await PostJson(PrivateModule.UpdateModule, { module_ids: Array.from(this.selectedIds), dir_id: id });
if (res.err_msg === 'success')
{
AppToaster.show({
message: "移动成功",
timeout: 2000,
intent: Intent.SUCCESS,
}, "Resoure_Enterprise");
this.resourceStore.GetPrivateModule();
}
this.moveModalVisible = false;
};
HandleRenameModule = async (value: string) =>
{
if (!value || this.currentInfo.name === value)
{
this.currentInfo = undefined;
return;
}
const res: IResponseData = await PostJson(PrivateModule.UpdateModule, { module_ids: [this.currentInfo.module_id], name: value, dir_id: this.currentInfo.dir_id });
if (res.err_msg === 'success')
{
AppToaster.show({
message: "重命名成功",
timeout: 2000,
intent: Intent.SUCCESS,
}, "Resoure_Enterprise");
this.resourceStore.GetPrivateModule();
}
this.currentInfo = undefined;
};
HandleCheckChange = (item: PrivateModuleItem) =>
{
const selectIds = this.selectedIds;
if (selectIds.has(item.module_id))
selectIds.delete(item.module_id);
else
selectIds.add(item.module_id);
};
HandlePageChange = async (page: number) =>
{
if (isNaN(page)) return;
if (page < 1 || page > this.resourceStore.privateModule.total) return;
this.resourceStore.resourceLoading = true;
this.resourceStore.privateModule.params.curr_page = page;
this.resourceStore.GetPrivateModule();
this.resourceStore.resourceLoading = false;
};
render(): React.ReactNode
{
const selectIds = this.selectedIds;
const { privateModule } = this.resourceStore;
return (
<div className="moduleList" >
<div className='header'>
<span>
<Button minimal small icon="arrow-left"
onClick={() =>
{
this.resourceStore.enterpriseType = ResourcePanelType.enterpriseFolder;
this.isBatch = false;
this.selectedIds.clear();
}}
/>
{this.resourceStore.currentfolder.dir_name}
</span>
</div>
<div className={"moduleControl"}>
<div className='delete'>
<Button icon="align-justify" title='批量选择' minimal
onClick={() =>
{
this.isBatch = !this.isBatch;
if (!this.isBatch)
selectIds.clear();
}}
/>
</div>
<Popover position={Position.BOTTOM_LEFT} minimal>
<Button minimal icon='sort' title='排序' />
<Menu className="orderPanel">
<MenuItem
icon={<Icon icon='sort-alphabetical' />}
text="按名称"
onClick={() =>
{
this.resourceStore.privateModule.params.order = 'name';
this.resourceStore.GetPrivateModule();
}}
/>
<MenuItem
text="按时间"
icon={<Icon icon='sort-numerical' />}
onClick={() =>
{
this.resourceStore.privateModule.params.order = 'create_date';
this.resourceStore.GetPrivateModule();
}}
/>
</Menu>
</Popover>
</div>
<div className="itemList">
{/* 加载中 */}
{this.resourceStore.privateModule.loading ? <Spinner />
:
this.resourceStore.privateModule.data.length
? this.resourceStore.privateModule.data.map((item: PrivateModuleItem) =>
{
return (
<div
key={item.module_id}
className={`moduleItem ${selectIds.has(item.module_id) ? "moduleSelected" : ""}`}
data-id={item.module_id}
onContextMenu={(e: React.MouseEvent<HTMLDivElement>) =>
{
if (!selectIds.has(item.module_id))
{
selectIds.clear();
selectIds.add(item.module_id);
}
this.ShowModuleContextMenu(e, item);
}}
>
<div
style={GetCssObj(item.logo, "120x120")}
className="items"
onClick={(e) =>
{
if (this.isBatch)
{
this.HandleCheckChange(item);
return;
}
if (item.state === "1")
this.resourceStore.WhenResourceDrag(e, item, ModuleType.Private);
else
AppToaster.show({
message: "模型已失效,请重新上传",
timeout: 3000,
intent: Intent.WARNING
}, "Resoure_Enterprise");
}}
>
<div className="itemOptions">
<Popover hoverCloseDelay={100} interactionKind='hover' minimal position='top' >
<Button minimal small icon='issue' />
<div className='moduleDetail'>
{RenderDetailImg(item.logo, "320x320")}
<span> {item.name}</span>
<span> id:{item.module_id}</span>
<span> :{item.dimension}</span>
</div>
</Popover>
</div>
<Checkbox
style={{
display: this.isBatch ? "block" : "none",
position: "absolute",
bottom: "0", right: "0"
}}
onChange={() => this.HandleCheckChange(item)}
checked={selectIds.has(item.module_id)}
/>
</div>
<div className='moduleName'>
{
this.currentInfo && this.currentInfo?.module_id === item.module_id ?
<EnterpriseInputGroup
defaultValue={item.name}
placeholder='请输入模型名称'
onSuccess={(value) =>
{
this.HandleRenameModule(value);
}}
onCancel={() =>
{
this.currentInfo = undefined;
}}
/>
:
<div>{item.name}</div>
}
</div>
</div>
);
})
:
!this.resourceStore.collectLoadgin && <NonIdealState
icon='inbox-search'
title="暂无数据"
/>
}
</div>
<div className='enterpriseOption'>
<R_Pagination
currentPage={privateModule.params.curr_page}
totalPage={privateModule.total}
HandlePageChange={this.HandlePageChange}
/>
</div>
{
this.moveModalVisible &&
<Dialog
isOpen={true}
onClose={() =>
{
this.moveModalVisible = false;
if (!this.isBatch)
this.selectedIds.clear();
}}
icon="move"
title="移动到目录"
canEscapeKeyClose
canOutsideClickClose
style={{ width: "30vw", maxHeight: "50vh" }}
>
<PrivateDirTree handMoveModule={this.HandMoveModule} />
</Dialog>
}
</div>
);
}
}

@ -35,19 +35,24 @@ import { PromptBlock } from "../../../DynamicPrompt/PromptBlock";
import { ApplyGoodInfo } from "../../ApplyGoodInfo";
import { InsertTemplateByBasePoint } from "../../Template/InsertTemplateByBasePoint";
import { AppToaster } from "../../Toaster";
import { Folder, ModuleData, ModuleSource, ResourceBrands, ResourceClass, ResourceParams, ResType } from "./ResourceInterfaces";
import { Folder, ModuleData, ModuleSource, ModuleType, PrivateDirs, PrivateDirsParams, PrivateModuleItem, ResType, ResourceBrands, ResourceClass, ResourceParams } from "./ResourceInterfaces";
import { ResourcePanelType } from "./ResourcePanel";
import { getClassList, getModuleDetail, getModuleList, GetUserCollectDir, GetUserCollection } from "./ResourcesData";
import { RenderBackGroundImg } from "./Resource_ResourceList";
import { GetPrivateModuleDirs, GetPrivateModuleList, GetUserCollectDir, GetUserCollection, getClassList, getModuleDetail, getModuleList } from "./ResourcesData";
export const pageCount: string = '20';
export default class ResourceStore
{
constructor()
//更新账号内所有库
InitAllModulesFolder()
{
this.InitClassList(this.class_type);
this.InitUserCollectDir(this.folderSort);
this.GetPrivateDir();
this.GetPrivateModule();
this.currentState = ResourcePanelType.publicLibrary;
}
class_type: number = 1;
@observable modulesList: ModuleData[] = []; //模型列表
@observable resourceClass: ResourceClass[] = []; //所有的分类
@ -61,7 +66,7 @@ export default class ResourceStore
styleParams?: ResourceParams, //菜单的风格
} = { otherParams: [], barndsParams: [] };
@observable levelThreeMenu: ResourceClass[] = []; //三级菜单
@observable currentState: Symbol = ResourcePanelType.publicLibrary; //当前的类别是什么
@observable currentState: symbol = ResourcePanelType.publicLibrary; //当前的类别是什么
@observable totalPage: number; //总页数
@observable currentPage: number = 1; //当前页数
@observable userFolder: Folder[] = []; //收藏文件夹
@ -79,9 +84,31 @@ export default class ResourceStore
@observable userCollectionCurrPage: number = 1; //收藏文件夹单曲页
@observable userCollectionTotalPage: number = 1; //收藏文件夹总页数
@observable classes: { class_id: string, class_name: string; }[] = [];//筛选类目
@observable collectType: Symbol = ResourcePanelType.myCollect; //在文件夹目录还是模型目录
@observable collectType: symbol = ResourcePanelType.myCollect; //在文件夹目录还是模型目录
@observable currentfolder: Folder;
@observable collectLoadgin: boolean;
@observable privateDirs: PrivateDirs[] = []; //私有目录
@observable privateModule: { //私有企业库模型管理
params: PrivateDirsParams;
total: number;
data: PrivateModuleItem[];
loading: boolean;
} = {
params: {
curr_page: 1,
page_count: 20,
order: "create_date",
dir_id: "",
name: "",
sn: "",
module_id: ""
},
total: 0,
data: [],
loading: true,
};
@observable enterpriseType: Symbol = ResourcePanelType.enterpriseFolder;
/**
* @description ,,
*/
@ -111,9 +138,23 @@ export default class ResourceStore
* @param {ModuleData} module ,
* @description canvas
*/
RenderMoudle = async (module: ModuleData) =>
RenderMoudle = async (module: ModuleData | PrivateModuleItem, type: ModuleType) =>
{
let module_detail = await getModuleDetail(module.module_id);
let module_detail: {
module_id?: string;
path?: string;
source?: ModuleSource;
type?: ResType;
} = {};
if (type === ModuleType.Private)
{
module_detail = {
module_id: module.module_id,
path: (module as PrivateModuleItem).path,
};
}
else
module_detail = await getModuleDetail(module.module_id);
if (!module_detail) return;
let isDoor = false;//是门
@ -428,7 +469,7 @@ export default class ResourceStore
* @param module ,
* @description
*/
WhenResourceDrag = async (event: React.MouseEvent, module: ModuleData) =>
WhenResourceDrag = async (event: React.MouseEvent, module: ModuleData | PrivateModuleItem, type: ModuleType = ModuleType.Public) =>
{
if (event.currentTarget !== event.target) return;
let dragDiv = event.target as HTMLDivElement; //[资源]
@ -447,8 +488,8 @@ export default class ResourceStore
let offsetX = dragDiv.offsetLeft; //计算[资源]的偏移量
let offsetY = dragDiv.offsetTop;
cloneDiv.style.left = offsetX - 10 + "px"; //设置[被拖元素]的起始位置
cloneDiv.style.top = offsetY - 10 + "px";
cloneDiv.style.left = offsetX + "px"; //设置[被拖元素]的起始位置
cloneDiv.style.top = offsetY + "px";
this.removeFn = begin(app.Editor.KeyCtrl, app.Editor.KeyCtrl.OnKeyDown, (e: KeyboardEvent) =>
@ -480,7 +521,7 @@ export default class ResourceStore
{
try
{
this.RenderMoudle(module);
this.RenderMoudle(module, type);
} catch (e) { }
containerDiv.removeChild(cloneDiv);
this.removeFn();
@ -496,7 +537,7 @@ export default class ResourceStore
{
try
{
this.RenderMoudle(module);
this.RenderMoudle(module, type);
} catch (e) { }
}
containerDiv.removeChild(cloneDiv);
@ -752,4 +793,30 @@ export default class ResourceStore
this._SingleInstance = new ResourceStore();
return this._SingleInstance;
}
@action
GetPrivateDir = async () =>//企业库文件夹列表
{
let res = await GetPrivateModuleDirs();
if (res)
this.privateDirs = res.dirs;
};
@action
GetPrivateModule = async () =>//企业库模型列表
{
this.collectType = ResourcePanelType.enterpriseModule;
this.privateModule.loading = true;
GetPrivateModuleList(this.privateModule.params)
.then((res) =>
{
this.privateModule.data = res.modules || [];
const total = Math.ceil(res.count / 20);
this.privateModule.total = total > 0 ? total : 1;
})
.finally(() =>
{
this.privateModule.loading = false;
});
};
}

@ -17,8 +17,8 @@ import { AppToaster } from '../../Toaster';
import Pagination2 from './Pagination2/Pagination2';
import { Folder, ModuleData } from './ResourceInterfaces';
import { ResourcePanelType } from './ResourcePanel';
import { getModuleDetail, GetUserCollection } from './ResourcesData';
import { GetCssObj, RenderDetailImg } from './Resource_ResourceList';
import { GetUserCollection, getModuleDetail } from './ResourcesData';
import ResourceStore from './RsourceStore';
export const RenderNoResult = () =>
@ -152,6 +152,20 @@ export default class UserCollect extends Component<{}, {}>
);
this.isShowContextMenu = true;
};
HandleCheckChange = (item: ModuleData) =>
{
if (this.batchDelete.indexOf(item.collect_id) !== -1)
{
this.batchDelete.splice(this.batchDelete.indexOf(item.collect_id), 1);
}
else
{
this.batchDelete.push(item.collect_id);
}
};
render()
{
return (
@ -226,6 +240,11 @@ export default class UserCollect extends Component<{}, {}>
}}
onMouseDown={(e) =>
{
if (this.isBatch)
{
this.HandleCheckChange(item);
return;
}
if (item.type === '1')
this.resourceStore.WhenResourceDrag(e, item);
}}
@ -274,14 +293,7 @@ export default class UserCollect extends Component<{}, {}>
}}
onChange={() =>
{
if (this.batchDelete.indexOf(item.collect_id) !== -1)
{
this.batchDelete.splice(this.batchDelete.indexOf(item.collect_id), 1);
}
else
{
this.batchDelete.push(item.collect_id);
}
this.HandleCheckChange(item);
}}
/>
</div>

@ -266,7 +266,7 @@ export class UserConfigStore extends Singleton
this.InitDoorWindowPanelStore();
RoomBaseParamsStore.GetSingleInstance();
ResourceStore.GetInstance();
ResourceStore.GetInstance().InitAllModulesFolder();
await this.InitCustomCmd();
await LimitCommand();

Loading…
Cancel
Save