diff --git a/src/Add-on/Template/ShowTemplate.ts b/src/Add-on/Template/ShowTemplate.ts index 87c527deb..7abf8b85b 100644 --- a/src/Add-on/Template/ShowTemplate.ts +++ b/src/Add-on/Template/ShowTemplate.ts @@ -2,12 +2,14 @@ import { app } from "../../ApplicationServices/Application"; import { Command } from "../../Editor/CommandMachine"; import { TemplateManage } from "../../UI/Components/Template/TemplateComponent"; import { TempalteEditorStore } from "../../UI/Store/TemplateEditorStore"; +import { ITempTagProps } from "./TemplateTagCommand"; export class ShowTemplate implements Command { + constructor(private tag?: ITempTagProps) { } async exec() { let store = TempalteEditorStore.GetInstance() as TempalteEditorStore; - app.Editor.ModalManage.RenderModeless(TemplateManage, { store }); + app.Editor.ModalManage.RenderModeless(TemplateManage, { store, currentTag: this.tag }); } } diff --git a/src/Add-on/Template/TemplateTagCommand.ts b/src/Add-on/Template/TemplateTagCommand.ts new file mode 100644 index 000000000..4019db51e --- /dev/null +++ b/src/Add-on/Template/TemplateTagCommand.ts @@ -0,0 +1,129 @@ +import { commandMachine } from "../../Editor/CommandMachine"; +import { ShowTemplate } from "./ShowTemplate"; +import { AppToaster } from "../../UI/Components/Toaster"; +import { Intent } from "@blueprintjs/core"; +import { PostJson, RequestStatus } from "../../Common/Request"; +import { ConfigUrls } from "../../Common/HostUrl"; +import { IndexedDbStore, StoreName } from "../../IndexedDb/IndexedDbStore"; +import { GetIndexDBID } from "../../Common/Utils"; +import { CommandList } from "../../UI/Components/CommandPanel/CommandList"; +import { arrayRemoveIf } from "../../Common/ArrayExt"; + + +export interface ITempTagProps +{ + tagName: string; + description: string; + dirId: string; +} + + +export class TemplateTagCommand +{ + //标签-id + private _tagList: ITempTagProps[] = []; + get TagList() + { + return this._tagList; + } + private CheckTagName(tagName: string) + { + let usedCmd = commandMachine.CommandMap.has(tagName) || CommandList.some(cmd => cmd.defaultCustom === tagName || cmd.command === tagName); + + if (usedCmd && this._tagList.findIndex(tag => tag.tagName === tagName) < 0) + { + AppToaster.show({ + message: "该标签已注册为系统命令", + timeout: 3000, + intent: Intent.DANGER, + }); + return false; + } + return true; + } + GetTagById(tid: string) + { + return this._tagList.find(tag => tag.dirId === tid); + } + GetTagByName(tagName: string) + { + return this._tagList.find(d => d.tagName === tagName); + } + AddTag(tagName: string, dirId: string) + { + tagName = tagName.toUpperCase(); + + if (!this.CheckTagName(tagName)) return; + + let tag = this.GetTagByName(tagName); + + if (!tag) + tag = this.GetTagById(dirId); + + if (!tag) + { + tag = { + tagName, + description: "", + dirId: dirId, + }; + this._tagList.push(tag); + } + else + { + commandMachine.RemoveCommand(tag.tagName); + } + tag.tagName = tagName; + tag.dirId = dirId; + + commandMachine.RegisterCommand(tagName, new ShowTemplate(tag)); + AppToaster.show({ + message: `标签:${tagName}添加成功`, + timeout: 3000, + intent: Intent.SUCCESS, + }); + } + RemoveTag(tagName: string) + { + arrayRemoveIf(this._tagList, tag => tag.tagName === tagName); + commandMachine.RemoveCommand(tagName); + AppToaster.show({ + message: `标签:${tagName}移除成功`, + timeout: 3000, + intent: Intent.SUCCESS, + }); + } + async UploadTagList() + { + let data = await PostJson(ConfigUrls.Edit, { key: TemplateTagCommand.name, value: JSON.stringify(this._tagList) }); + if (data.err_code === RequestStatus.Ok) + { + const dbStore = await IndexedDbStore.CADStore(); + dbStore.Put(StoreName.ConfigData, GetIndexDBID(TemplateTagCommand.name), this._tagList.slice()); + dbStore.Put(StoreName.ConfigVersion, GetIndexDBID(TemplateTagCommand.name), data.version); + } + } + ReadTagList(tags: ITempTagProps[]) + { + if (!Array.isArray(tags)) return; + for (let tag of tags) + { + this._tagList.push(tag); + commandMachine.RegisterCommand(tag.tagName, new ShowTemplate(tag)); + } + } + ModifyTagName(tagName: string, newName: string) + { + if (!this.CheckTagName(newName)) return; + + let tag = this.GetTagByName(tagName); + if (tag) + { + commandMachine.RemoveCommand(tagName); + tag.tagName = newName; + commandMachine.RegisterCommand(newName, new ShowTemplate(tag)); + } + } +} + +export const templateTagCommand = new TemplateTagCommand(); diff --git a/src/Common/Utils.ts b/src/Common/Utils.ts index a94e84c1b..fd06f268d 100644 --- a/src/Common/Utils.ts +++ b/src/Common/Utils.ts @@ -2,6 +2,7 @@ import { Object3D } from "three"; import { Entity } from "../DatabaseServices/Entity/Entity"; import { equaln } from "../Geometry/GeUtils"; import { safeEval } from "./eval"; +import { StoreageKeys } from "./StoreageKeys"; //仅数字构成的3位字符串(不以0开头) export const digitStrReg = /^[^0\D]\d{0,2}$/; @@ -242,3 +243,8 @@ export function getFileSize(size: number) size /= 1024; } } + +export function GetIndexDBID(id: string) +{ + return localStorage.getItem(StoreageKeys.Uid) + ":" + id; +} diff --git a/src/Editor/CommandMachine.ts b/src/Editor/CommandMachine.ts index f3a43c199..c7779a3d0 100644 --- a/src/Editor/CommandMachine.ts +++ b/src/Editor/CommandMachine.ts @@ -67,6 +67,12 @@ class CommandMachine this.CommandMap.set(cmdName, cmd); this.m_CommandNameList.add(cmdName); } + RemoveCommand(cmdName: string) + { + cmdName = cmdName.toUpperCase(); + this.CommandMap.delete(cmdName); + this.m_CommandNameList.delete(cmdName); + } RegisterCustomCommand(oldName: string, newName: string) { let oldCmd = this.CommandMap.get(oldName); diff --git a/src/UI/Components/Modal/ModalStyle/BoardModal.less b/src/UI/Components/Modal/ModalStyle/BoardModal.less index fbf36f541..d29641b24 100644 --- a/src/UI/Components/Modal/ModalStyle/BoardModal.less +++ b/src/UI/Components/Modal/ModalStyle/BoardModal.less @@ -232,3 +232,7 @@ width: 300px; } } + +#commonModal .bp3-align-right { + justify-content: flex-end; +} diff --git a/src/UI/Components/SourceManage/CommonPanel.tsx b/src/UI/Components/SourceManage/CommonPanel.tsx index 4330f822d..4f222fb70 100644 --- a/src/UI/Components/SourceManage/CommonPanel.tsx +++ b/src/UI/Components/SourceManage/CommonPanel.tsx @@ -151,10 +151,7 @@ export class CommonPanel extends React.Component (n.isSelected = false)); - if (isSelected) - nodeData.isSelected = isSelected; - else - nodeData.isSelected = originallySelected == null ? true : !originallySelected; + nodeData.isSelected = true; this.setState(this.state); }; //点击目录 @@ -909,7 +906,7 @@ export class CommonPanel extends React.Component } { this.inputEl.value = ""; this.container.removeEventListener('keydown', this.onKeydown); + this.container.parentElement.focus(); } render() { diff --git a/src/UI/Components/Template/Template.less b/src/UI/Components/Template/Template.less index a55a864b0..2940fe40b 100644 --- a/src/UI/Components/Template/Template.less +++ b/src/UI/Components/Template/Template.less @@ -145,9 +145,86 @@ display: flex; } } + + .tag-list { + border-right: 1px solid #ccc; + display: flex; + width: 50%; + flex-wrap: wrap; + align-content: start; + + .pagination { + margin-top: 20px; + } + + &>.tag-img { + width: 25%; + outline: 1px solid #ccc; + height: 0; + text-align: center; + padding-bottom: calc(25% + 20px); + position: relative; + } + + &>.tag-img:hover:after { + content: ""; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-color: #ccc; + opacity: 0.2; + } + } + + .tag-name-list { + list-style: none; + width: 100px; + text-align: left; + padding: 0; + max-height: 100%; + overflow: auto; + border-right: 1px solid #ccc; + padding-right: 5px; + width: 20%; + + li { + border-bottom: 1px solid #ccc; + padding: 5px; + cursor: pointer; + } + + li:hover { + background-color: #ccc; + } + + li.active { + background-color: rgba(19, 124, 189); + color: #fff; + } + } + } #commonModal .template-detail { + &>.add-tag { + display: flex; + align-items: center; + padding-top: 10px; + + input { + width: 100px; + } + + button { + height: 20px; + min-height: 20px; + line-height: 20px; + padding: 0 5px; + } + } + &>div { input { height: 30px; @@ -201,6 +278,14 @@ } } +#commonModal .tag-temp-detail { + flex: 1; + + &>ul { + max-height: 100%; + } +} + #commonModal .template-design { width: 40vw; height: 61vh; @@ -377,3 +462,24 @@ } } } + +.tag-names { + padding: 0; + + ul { + width: 100px; + text-align: center; + padding: 5px; + max-height: 200px; + overflow: auto; + + li { + border-bottom: 1px solid #ccc; + padding: 2px 0; + } + + li:hover { + background-color: #ccc; + } + } +} diff --git a/src/UI/Components/Template/TemplateComponent.tsx b/src/UI/Components/Template/TemplateComponent.tsx index b5fa61b34..efacfa13f 100644 --- a/src/UI/Components/Template/TemplateComponent.tsx +++ b/src/UI/Components/Template/TemplateComponent.tsx @@ -1,4 +1,4 @@ -import { Button, Classes, Intent } from '@blueprintjs/core'; +import { Button, Classes, Intent, Card, Popover } from '@blueprintjs/core'; import { observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -13,7 +13,7 @@ import { Board } from '../../../DatabaseServices/Entity/Board'; import { Entity } from '../../../DatabaseServices/Entity/Entity'; import { EditorOnlineTemplate, GetOnlineTemplate, ReplaceTemplate, SetTemplatePositionAndSetParent, UploadTemplate } from '../../../DatabaseServices/Template/TempateUtils'; import { TemplateRecord } from '../../../DatabaseServices/Template/TemplateRecord'; -import { CommandWrap } from '../../../Editor/CommandMachine'; +import { CommandWrap, commandMachine } from '../../../Editor/CommandMachine'; import { JigUtils } from '../../../Editor/JigUtils'; import { PromptStatus } from '../../../Editor/PromptResult'; import { PointSelectSpaceClamp } from '../../../Geometry/SpaceParse/PointSelectSpaceClamp'; @@ -31,9 +31,12 @@ import { TemplateVisualSpace } from '../../../DatabaseServices/Template/ProgramT import { IDrawerDoorTempInfo, HandleHorPos, HandleVePos } from '../../Store/DoorInterface'; import { BoardOpenDir, IDrawBoardAutoCutOption } from '../../Store/BoardInterface'; import { DoorStore } from '../../Store/DoorDrawerStore/DoorStore'; -import { AutoCutCheckbox } from '../Board/BoardCommon'; +import { TemplateTagCom, ITemplateTagComProps } from './TemplateTagCom'; +import { UploadAutoCutConfig, ReadAutoCutConfig } from '../../../Add-on/TemplateSearch'; import { AutoCutting } from '../../../Add-on/BoardCutting/AutoCuttingReactor'; -import { ReadAutoCutConfig, UploadAutoCutConfig } from '../../../Add-on/TemplateSearch'; +import { AutoCutCheckbox } from '../Board/BoardCommon'; +import { templateTagCommand, ITempTagProps } from '../../../Add-on/Template/TemplateTagCommand'; +import { KeyBoard } from '../../../Common/KeyEnum'; export interface INeedUpdateParams { @@ -44,8 +47,14 @@ export interface INeedUpdateParams isLock?: boolean; } +export interface ITemplateManage +{ + store?: TempalteEditorStore; + currentTag?: ITempTagProps; +} + @observer -export class TemplateManage extends React.Component<{ store: TempalteEditorStore; }, {}> { +export class TemplateManage extends React.Component { @observable private option: IGetRoomInfo = { roomName: "", cabName: "", @@ -67,15 +76,59 @@ export class TemplateManage extends React.Component<{ store: TempalteEditorStore private renderNav = () => { return ( -