!2129 功能:酷家乐配置导入导出功能

pull/2090/MERGE
黄诗津 2 years ago committed by ChenX
parent 319f9f3fe9
commit 0cd83bbef4

@ -1,4 +1,6 @@
import { Button, Classes, Intent, Tab, Tabs } from "@blueprintjs/core";
import { observable } from "mobx";
import { observer } from "mobx-react";
import React from "react";
import { app } from "../../../ApplicationServices/Application";
import { BoardModalType } from "../../../UI/Components/Board/BoardModalType";
@ -12,8 +14,11 @@ import { KJLMaterialMap } from "./KJLMaterialMap";
export type KJLTabIds = 'config' | 'material';
@observer
export class KJLImportConfigModal extends React.Component<{ store: KJLImportConfigStore, tabId?: KJLTabIds; }>
{
private KJLMaterialMap = React.createRef<KJLMaterialMap>();
@observable currentTabId: KJLTabIds = this.props.tabId;
render()
{
let store = this.props.store;
@ -23,9 +28,20 @@ export class KJLImportConfigModal extends React.Component<{ store: KJLImportConf
close={() => { this.Cancle(); }}
store={store}
configType={Config_ModalType.ConfigListTagModal}
isImpExp={true}
configurationType="酷家乐配置"
type={BoardModalType.KJLImportConfig}
footerChildren={
<>
{
this.currentTabId === "material" &&
<Button
text="一键删除"
intent={Intent.DANGER}
disabled={!store.materialList.some(mtl => mtl.isRender === false) && store.materialList.some(mtl => mtl.isSelect === true) ? false : true}
onClick={() => { this.KJLMaterialMap.current.handleOnekeyDelete(); }}
/>
}
<Button
text="取消"
intent={Intent.DANGER}
@ -39,10 +55,11 @@ export class KJLImportConfigModal extends React.Component<{ store: KJLImportConf
animate={true}
id="KJLImportConfig"
className=" KJLImportConfig"
onChange={(e) => this.currentTabId = e as KJLTabIds}
defaultSelectedTabId={this.props.tabId ? this.props.tabId : "config"}
>
<Tab id="config" title="配置" panel={<KJLConfig store={store} />} />
<Tab id="material" title="材质" panel={<KJLMaterialMap store={store} />} />
<Tab id="material" title="材质" panel={<KJLMaterialMap store={store} ref={this.KJLMaterialMap} />} />
</Tabs>
</div>
</CommonModal>

@ -4,12 +4,14 @@ import PQueue from "p-queue";
import { MaterialUrls } from "../../../Common/HostUrl";
import { PostJson, RequestStatus } from "../../../Common/Request";
import { Singleton } from "../../../Common/Singleton";
import { CADFiler } from "../../../DatabaseServices/CADFiler";
import { IConfigOption } from "../../../UI/Components/Board/UserConfigComponent";
import { AppToaster } from "../../../UI/Components/Toaster";
import { IUiOption } from "../../../UI/Store/BoardInterface";
import { AnyObject, IUiOption } from "../../../UI/Store/BoardInterface";
import { IConfigStore } from "../../../UI/Store/BoardStore";
import { KJLUseName } from "./KJLConfig";
import { DefaultKJImportOption, KJLImportConfigOption } from "./KJLImportConfigOption";
import { deserializeKJLConfigData, serializeKJLConfigData } from "./SerializeKJLConfigData";
export interface MaterialOption
{
@ -25,22 +27,20 @@ interface ValueMapUiOption
m_uiEdgeValueMap: [string, string][];
m_uiDrillValueMap: [string, string][];
}
interface IKJLImportConfigOption extends KJLImportConfigOption
{
kjlUseName: KJLUseName.modelName;
}
export class KJLImportConfigStore extends Singleton implements IConfigStore
{
@observable configName: string = "默认";
@observable configsNames: string[] = [];
@observable m_Option: IKJLImportConfigOption = { ...DefaultKJImportOption, kjlUseName: KJLUseName.modelName };
@observable m_Option: KJLImportConfigOption = { ...DefaultKJImportOption };
kjlUseName: KJLUseName = KJLUseName.modelName;
@observable uiOption: IUiOption<ValueMapUiOption>;
@observable materialList: MaterialOption[] = [];
@observable selectAll = false;
private queue = new PQueue({ concurrency: 100 });
materialMap = new Map<string, Promise<{ materialName: string, url: string; }>>();
ImpExpSuffix = ".kjlm";
get UIOption()
{
@ -93,7 +93,19 @@ export class KJLImportConfigStore extends Singleton implements IConfigStore
newConfig.option = toJS(this.m_Option);
return newConfig;
}
UpdateOption(cof: IConfigOption<IKJLImportConfigOption>)
UpdateOption(cof: IConfigOption<KJLImportConfigOption>)
{
this.UpdataVersion(cof);
Object.assign(this.m_Option, cof.option);
if (this.uiOption)
this.uiOption = {
m_uiEdgeValueMap: this.ConvertUIData(this.m_Option.edgeValueMap),
m_uiDrillValueMap: this.ConvertUIData(this.m_Option.drillValueMap)
};
this.LoadMaterials();
}
UpdataVersion(cof: IConfigOption<KJLImportConfigOption>)
{
if (cof.option.version < 2)
{
@ -115,13 +127,6 @@ export class KJLImportConfigStore extends Singleton implements IConfigStore
cof.option.version = 5;
cof.option.drillValueMap = Array.from({ length: 20 }, () => [0, 0]);
}
Object.assign(this.m_Option, cof.option);
if (this.uiOption)
this.uiOption = {
m_uiEdgeValueMap: this.ConvertUIData(this.m_Option.edgeValueMap),
m_uiDrillValueMap: this.ConvertUIData(this.m_Option.drillValueMap)
};
this.LoadMaterials();
}
private ConvertUIData(obj: [number, number][])
{
@ -196,4 +201,41 @@ export class KJLImportConfigStore extends Singleton implements IConfigStore
res({ materialName, url });
});
};
async GetSerializeConfig(conf: IConfigOption<AnyObject>)
{
let file = new CADFiler();
file.Write(1);
file.Write(Object.keys(conf).length);
for (let name in conf)
{
if (conf.hasOwnProperty(name))
{
file.Write(name);
this.UpdataVersion(conf[name]); //更新版本
serializeKJLConfigData(file, conf[name].option);
}
}
return file.Data;
}
async GetDeserializeConfig(data: any[])
{
let configs: IConfigOption<AnyObject> = {};
let file = new CADFiler(data);
let version = file.Read();
let count = file.Read();
for (let i = 0; i < count; i++)
{
let name = file.Read();
let config: IConfigOption<KJLImportConfigOption> = {
option: { ...DefaultKJImportOption }
};
deserializeKJLConfigData(file, config.option);
configs[name] = config;
}
return configs;
}
}

@ -57,13 +57,6 @@ export class KJLMaterialMap extends React.Component<{ store: KJLImportConfigStor
</Button>
</div>
</div>
<Button
text="一键删除"
intent={Intent.DANGER}
style={{ position: "absolute", bottom: 11, right: 75 }}
disabled={!store.materialList.some(mtl => mtl.isRender === false) && store.materialList.some(mtl => mtl.isSelect === true) ? false : true}
onClick={() => { this.handleOnekeyDelete(); }}
/>
</div>
</div>
);
@ -81,7 +74,7 @@ export class KJLMaterialMap extends React.Component<{ store: KJLImportConfigStor
}
};
private handleOnekeyDelete = async () =>
handleOnekeyDelete = async () =>
{
let res = await AppConfirm.show({
intent: Intent.DANGER,

@ -0,0 +1,45 @@
import { CADFiler } from "../../../DatabaseServices/CADFiler";
import { KJLImportConfigOption } from "./KJLImportConfigOption";
export function serializeKJLConfigData(file: CADFiler, conf: KJLImportConfigOption)
{
file.Write(conf.version);
file.WriteBool(conf.isImportVirtualModel);
file.Write(conf.kjlUseName);
file.Write2dArray(conf.edgeValueMap);
file.Write2dArray(conf.drillValueMap);
file.Write(conf.materials.length);
for (let material of conf.materials)
{
file.Write(material.kjlName);
file.Write(material.id);
}
}
export function deserializeKJLConfigData(file: CADFiler, option: KJLImportConfigOption)
{
option.version = file.Read();
option.isImportVirtualModel = file.ReadBool();
option.kjlUseName = file.Read();
let count = file.Read();
option.edgeValueMap = file.Read2dArray(count);
count = file.Read();
option.drillValueMap = file.Read2dArray(count);
count = file.Read();
let materials = [];
for (let i = 0; i < count; i++)
{
materials.push({ kjlName: file.Read(), id: file.Read() });
}
option.materials = materials;
if (option.version > 5)
{
//需要的时候这里开始迭代
}
}

@ -79,13 +79,22 @@ export class UploadHoleOption implements Command
}
}
export async function ImportConfig(type: string, store: IConfigStore, newName: string, callback?: () => void)
export async function ImportConfig(type: string, store: IConfigStore, newName: string, filter?: string, callback?: () => void)
{
FileSystem.ChooseFile({
filter: ".json", callback: async (files) =>
filter: filter ?? ".json", callback: async (files) =>
{
let index = 0;
let f = files[0];
if (f.name.substring(f.name.lastIndexOf(".")) !== (filter ?? ".json"))
{
AppToaster.show({
message: "导入文件类型有误,请确认导入文件",
timeout: 3000,
intent: Intent.DANGER
});
return;
}
let json = await FileSystem.ReadFileAsText(f);
if (!json) return;
let fileData = JSON.parse(json);
@ -102,12 +111,16 @@ export async function ImportConfig(type: string, store: IConfigStore, newName: s
let configs = await userConfigStore.GetAllConfigs(type, false) || {};
const importConfigs = fileData.config;
let importConfigs = fileData.config;
if (store.HandleImportConfig)
{
await store.HandleImportConfig(fileData);
}
if (store.GetDeserializeConfig)
{
importConfigs = await store.GetDeserializeConfig(fileData.config);
}
let firstKey: string;
for (let key in importConfigs)

@ -123,6 +123,11 @@ export class CADFiler
this._datas.push(v3.x, v3.y, v3.z);
}
Write2dArray(arr: [any, any][])
{
this._datas.push(arr.length, ...Array.prototype.concat.apply([], arr));
}
Read(): any
{
return this._datas[this.readIndex++];
@ -140,6 +145,15 @@ export class CADFiler
return arr;
}
Read2dArray(count: number): [any, any][]
{
let arr = this._datas.slice(this.readIndex, this.readIndex + count * 2);
this.readIndex += count * 2;
return (function toArrayTwo(arr: any[])
{
return arr.length ? [arr.slice(0, 2)].concat(toArrayTwo(arr.slice(2))) : [];
})(arr);
}
//------------------------ID序列化------------------------
/*
Id:

@ -136,7 +136,7 @@ export class DrillModal extends React.Component<{ store?: DrillStore; }, {}> {
type={BoardModalType.Dr}
configType={Config_ModalType.ConfigListTagModal}
helpUrlName={CommandNames.DrillConfig}
isImpExp
isImpExp={true}
configurationType="排钻配置"
footerChildren={
<>

@ -56,7 +56,7 @@ interface IConfigProps
type: BoardModalType;
store: IConfigStore;
isNotUpdateStore?: boolean;//不需要更新用户配置 例如双击五金属性时
isExpImp?: boolean;
isImpExp?: boolean;
isShowOperButton?: boolean; //是否显示保存和删除配置按钮
otherConfig?: () => AnyObject;
hasconfig?: boolean;
@ -73,7 +73,7 @@ interface IConfigProps
export class UserConfigComponent extends React.Component<IConfigProps, {}>{
static defaultProps = {
isUpdate: true,
isExpImp: false,
isImpExp: false,
hasconfig: true,
};
@observable private exportData: [string, boolean][] = [];
@ -168,21 +168,23 @@ export class UserConfigComponent extends React.Component<IConfigProps, {}>{
{
let store = this.props.store;
return (
<label style={this.props.style} className={this.props.className}>
{
this.props.hasconfig &&
<ConfigList
type={this.props.type}
store={store}
isNotModify={this.props.isShowOperButton}
configType={this.props.configType}
handleSaveConfig={this.handleSaveConfig}
updateBoardOption={this.updateStoreOption}
handleDeleteConfig={this.handleDeleteConfig}
/>
}
<>
<label style={this.props.style} className={this.props.className}>
{
this.props.hasconfig &&
<ConfigList
type={this.props.type}
store={store}
isNotModify={this.props.isShowOperButton}
configType={this.props.configType}
handleSaveConfig={this.handleSaveConfig}
updateBoardOption={this.updateStoreOption}
handleDeleteConfig={this.handleDeleteConfig}
/>
}
</label>
{
this.props.isExpImp &&
this.props.isImpExp &&
<div style={{ display: "flex", width: 105, justifyContent: 'space-between' }}>
<PopoverInput
title="导入"
@ -200,13 +202,13 @@ export class UserConfigComponent extends React.Component<IConfigProps, {}>{
/>
</div>
}
</label>
</>
);
}
private handleImport = async (v: string) =>
{
ImportConfig(this.props.type, this.props.store, v, () =>
ImportConfig(this.props.type, this.props.store, v, this.props.store.ImpExpSuffix, () =>
{
this.updateStoreOption(arrayLast(this.props.store.configsNames));
});
@ -230,10 +232,12 @@ export class UserConfigComponent extends React.Component<IConfigProps, {}>{
type: this.props.type,
config: configs,
};
if (this.props.store.GetSerializeConfig)
data.config = await this.props.store.GetSerializeConfig(configs);
if (this.props.store.GetOtherConfig)
data.other = await this.props.store.GetOtherConfig(configs);
FileSystem.WriteFile(this.props.configurationType + ".json", JSON.stringify(data));
FileSystem.WriteFile(this.props.configurationType + (this.props.store.ImpExpSuffix ?? ".json"), JSON.stringify(data));
};
}

@ -32,15 +32,16 @@ export class PopoverCheckBoxes extends Component<Props> {
<div style={{
maxHeight: 300,
minWidth: 200,
paddingLeft: 10,
marginBottom: 8,
overflow: "auto"
}}>
{
this.props.values.map((d) =>
this.props.values.map((d, i) =>
{
return (
<Checkbox
style={{ margin: 0 }}
key={i}
style={{ margin: 0, marginBottom: 2 }}
label={d[0]}
checked={d[1]}
onChange={() => this.select(d)}

@ -301,7 +301,7 @@ export class ModalFooter extends Component<IModalFooterProps>
{
this.props.isImpExp &&
<UserConfigComponent
isExpImp={true}
isImpExp={true}
store={this.props.store}
type={this.props.type}
configurationType={this.props.configurationType}

@ -30,6 +30,9 @@ export interface IConfigStore
InitConfigs?: () => { [key: string]: IConfigOption; };//如果有多个配置时,重载这个函数
GetOtherConfig?: (conf: any) => AnyObject;
HandleImportConfig?: (conf: any) => void;
ImpExpSuffix?: string; //导入导出文件后缀名
GetSerializeConfig?: (conf: any) => AnyObject; //获取新的序列化配置(导出)
GetDeserializeConfig?: (conf: any) => AnyObject; //获取反序列化配置(导入)
}
export class BoardStore<T = IBaseOption> extends Singleton implements IConfigStore

Loading…
Cancel
Save