Add search box component
This commit is contained in:
parent
ce5e6a34d8
commit
87023251a9
@ -3,4 +3,9 @@
|
|||||||
div.behavior-popup {
|
div.behavior-popup {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.behavior-popup-search-box {
|
||||||
|
padding: 10px 0 0 10px;
|
||||||
|
width: calc(100% - 10px);
|
||||||
}
|
}
|
@ -1,13 +1,18 @@
|
|||||||
import { Component, ReactNode } from "react";
|
import { Component, ReactNode } from "react";
|
||||||
import { Popup } from "@Context/Popups";
|
import { Popup } from "@Context/Popups";
|
||||||
import { Theme } from "@Component/Theme/Theme";
|
|
||||||
import { Localization } from "@Component/Localization/Localization";
|
import { Localization } from "@Component/Localization/Localization";
|
||||||
|
import { SearchBox } from "@Component/SearchBox/SearchBox";
|
||||||
|
import { ConfirmContent } from "@Component/ConfirmPopup/ConfirmPopup";
|
||||||
import "./BehaviorPopup.scss";
|
import "./BehaviorPopup.scss";
|
||||||
|
|
||||||
interface IBehaviorPopupProps {
|
interface IBehaviorPopupProps {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IBehaviorPopupState {
|
||||||
|
searchValue: string;
|
||||||
|
}
|
||||||
|
|
||||||
class BehaviorPopup extends Popup<IBehaviorPopupProps> {
|
class BehaviorPopup extends Popup<IBehaviorPopupProps> {
|
||||||
|
|
||||||
public minWidth: number = 400;
|
public minWidth: number = 400;
|
||||||
@ -24,10 +29,36 @@ class BehaviorPopup extends Popup<IBehaviorPopupProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BehaviorPopupComponent extends Component<IBehaviorPopupProps> {
|
class BehaviorPopupComponent extends Component<IBehaviorPopupProps, IBehaviorPopupState> {
|
||||||
|
|
||||||
|
state: Readonly<IBehaviorPopupState> = {
|
||||||
|
searchValue: ""
|
||||||
|
};
|
||||||
|
|
||||||
|
private renderHeader = () => {
|
||||||
|
return <div className="behavior-popup-search-box">
|
||||||
|
<SearchBox
|
||||||
|
valueChange={(value) => {
|
||||||
|
this.setState({
|
||||||
|
searchValue: value
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
value={this.state.searchValue}
|
||||||
|
/>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
return <Theme className="behavior-popup"></Theme>
|
return <ConfirmContent
|
||||||
|
className="behavior-popup"
|
||||||
|
actions={[{
|
||||||
|
i18nKey: "Popup.Add.Behavior.Action.Add"
|
||||||
|
}]}
|
||||||
|
header={this.renderHeader}
|
||||||
|
headerHeight={36}
|
||||||
|
>
|
||||||
|
|
||||||
|
</ConfirmContent>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,35 @@ div.confirm-root {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
div.header-view {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
div.content-views {
|
div.content-views {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc( 100% - 36px );
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
overflow: scroll;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.content-views::-webkit-scrollbar {
|
||||||
|
width : 8px; /*高宽分别对应横竖滚动条的尺寸*/
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.content-views::-webkit-scrollbar-thumb {
|
||||||
|
/*滚动条里面小方块*/
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.content-views::-webkit-scrollbar-track {
|
||||||
|
/*滚动条里面轨道*/
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: rgba($color: #000000, $alpha: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.content-views.has-padding {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,14 +60,27 @@ div.confirm-root {
|
|||||||
div.action-button.red {
|
div.action-button.red {
|
||||||
color: $lt-red;
|
color: $lt-red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.action-button.blue {
|
||||||
|
color: $lt-blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.action-button.disable {
|
||||||
|
opacity: .75;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div.dark.confirm-root {
|
div.dark.confirm-root {
|
||||||
|
|
||||||
|
div.content-views::-webkit-scrollbar-thumb {
|
||||||
|
background-color: $lt-bg-color-lvl1-dark;
|
||||||
|
}
|
||||||
|
|
||||||
div.action-view {
|
div.action-view {
|
||||||
|
|
||||||
div.action-button {
|
div.action-button, div.action-button.disable:hover {
|
||||||
background-color: $lt-bg-color-lvl3-dark;
|
background-color: $lt-bg-color-lvl3-dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,9 +92,13 @@ div.dark.confirm-root {
|
|||||||
|
|
||||||
div.light.confirm-root {
|
div.light.confirm-root {
|
||||||
|
|
||||||
|
div.content-views::-webkit-scrollbar-thumb {
|
||||||
|
background-color: $lt-bg-color-lvl1-light;
|
||||||
|
}
|
||||||
|
|
||||||
div.action-view {
|
div.action-view {
|
||||||
|
|
||||||
div.action-button {
|
div.action-button, div.action-button.disable:hover {
|
||||||
background-color: $lt-bg-color-lvl3-light;
|
background-color: $lt-bg-color-lvl3-light;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Popup } from "@Context/Popups";
|
import { Popup } from "@Context/Popups";
|
||||||
import { ReactNode } from "react";
|
import { Component, ReactNode } from "react";
|
||||||
import { Message } from "@Component/Message/Message";
|
import { Message } from "@Component/Message/Message";
|
||||||
import { Theme } from "@Component/Theme/Theme";
|
import { Theme } from "@Component/Theme/Theme";
|
||||||
import { AllI18nKeys, Localization } from "@Component/Localization/Localization";
|
import { AllI18nKeys, Localization } from "@Component/Localization/Localization";
|
||||||
@ -7,12 +7,12 @@ import "./ConfirmPopup.scss";
|
|||||||
|
|
||||||
interface IConfirmPopupProps {
|
interface IConfirmPopupProps {
|
||||||
titleI18N?: AllI18nKeys;
|
titleI18N?: AllI18nKeys;
|
||||||
infoI18n: AllI18nKeys;
|
infoI18n?: AllI18nKeys;
|
||||||
yesI18n?: AllI18nKeys;
|
yesI18n?: AllI18nKeys;
|
||||||
noI18n?: AllI18nKeys;
|
noI18n?: AllI18nKeys;
|
||||||
|
red?: "yes" | "no";
|
||||||
yes?: () => any;
|
yes?: () => any;
|
||||||
no?: () => any;
|
no?: () => any;
|
||||||
red?: "yes" | "no";
|
|
||||||
}
|
}
|
||||||
class ConfirmPopup extends Popup<IConfirmPopupProps> {
|
class ConfirmPopup extends Popup<IConfirmPopupProps> {
|
||||||
|
|
||||||
@ -24,37 +24,139 @@ class ConfirmPopup extends Popup<IConfirmPopupProps> {
|
|||||||
return <Localization i18nKey={this.props.titleI18N ?? "Popup.Title.Confirm"}/>
|
return <Localization i18nKey={this.props.titleI18N ?? "Popup.Title.Confirm"}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private genActionClickFunction(fn?: () => any): () => any {
|
||||||
|
return () => {
|
||||||
|
if (fn) fn();
|
||||||
|
this.close();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
|
|
||||||
const yesClassList: string[] = ["action-button", "yes-button"];
|
const actionList: IActionButtonProps[] = [];
|
||||||
const noClassList: string[] = ["action-button", "no-button"];
|
|
||||||
if (this.props.red === "no") {
|
if (this.props.yesI18n || this.props.yes) {
|
||||||
noClassList.push("red");
|
actionList.push({
|
||||||
|
i18nKey: this.props.yesI18n ?? "Popup.Action.Yes",
|
||||||
|
onClick: this.genActionClickFunction(this.props.yes),
|
||||||
|
color: this.props.red === "yes" ? "red" : undefined
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (this.props.red === "yes") {
|
|
||||||
yesClassList.push("red");
|
if (this.props.noI18n || this.props.no) {
|
||||||
|
actionList.push({
|
||||||
|
i18nKey: this.props.noI18n ?? "Popup.Action.Yes",
|
||||||
|
onClick: this.genActionClickFunction(this.props.no),
|
||||||
|
color: this.props.red === "no" ? "red" : undefined
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return <ConfirmContent
|
||||||
|
actions={actionList}
|
||||||
|
>
|
||||||
|
{this.props.infoI18n ? <Message i18nKey={this.props.infoI18n}/> : null}
|
||||||
|
</ConfirmContent>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IConfirmContentProps {
|
||||||
|
hidePadding?: boolean;
|
||||||
|
className?: string;
|
||||||
|
actions: IActionButtonProps[];
|
||||||
|
header?: () => ReactNode;
|
||||||
|
headerHeight?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IActionButtonProps {
|
||||||
|
className?: string;
|
||||||
|
disable?: boolean;
|
||||||
|
color?: "red" | "blue";
|
||||||
|
i18nKey: AllI18nKeys;
|
||||||
|
i18nOption?: Record<string, string>;
|
||||||
|
onClick?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfirmContent extends Component<IConfirmContentProps> {
|
||||||
|
|
||||||
|
public renderActionButton(props: IActionButtonProps, key: number): ReactNode {
|
||||||
|
|
||||||
|
const classList = ["action-button"];
|
||||||
|
if (props.className) {
|
||||||
|
classList.push(props.className);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.color === "red") {
|
||||||
|
classList.push("red");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.color === "blue") {
|
||||||
|
classList.push("blue");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.disable) {
|
||||||
|
classList.push("disable");
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div
|
||||||
|
className={classList.join(" ")}
|
||||||
|
onClick={props.disable ? undefined : props.onClick}
|
||||||
|
key={key}
|
||||||
|
>
|
||||||
|
<Localization i18nKey={props.i18nKey} options={props.i18nOption}/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
private getHeaderHeight(): number {
|
||||||
|
return this.props.headerHeight ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderHeader() {
|
||||||
|
return <div
|
||||||
|
className="header-view"
|
||||||
|
style={{
|
||||||
|
maxHeight: this.getHeaderHeight(),
|
||||||
|
minHeight: this.getHeaderHeight(),
|
||||||
|
height: this.getHeaderHeight()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{this.props.header ? this.props.header() : null}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): ReactNode {
|
||||||
|
|
||||||
|
const contentClassNameList: string[] = ["content-views"];
|
||||||
|
|
||||||
|
if (this.props.className) {
|
||||||
|
contentClassNameList.push(this.props.className);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.props.hidePadding) {
|
||||||
|
contentClassNameList.push("has-padding");
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Theme className="confirm-root">
|
return <Theme className="confirm-root">
|
||||||
<div className="content-views">
|
|
||||||
<Message i18nKey={this.props.infoI18n}/>
|
{this.props.header ? this.renderHeader() : null}
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={contentClassNameList.join(" ")}
|
||||||
|
style={{
|
||||||
|
height: `calc( 100% - ${this.getHeaderHeight() + 36}px )`
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="action-view">
|
<div className="action-view">
|
||||||
<div className={yesClassList.join(" ")} onClick={() => {
|
{
|
||||||
this.props.yes ? this.props.yes() : null;
|
this.props.actions.map((prop, index) => {
|
||||||
this.close();
|
return this.renderActionButton(prop, index);
|
||||||
}}>
|
})
|
||||||
<Localization i18nKey={this.props.yesI18n ?? "Popup.Action.Yes"}/>
|
}
|
||||||
</div>
|
|
||||||
<div className={noClassList.join(" ")} onClick={() => {
|
|
||||||
this.props.no ? this.props.no() : null;
|
|
||||||
this.close();
|
|
||||||
}}>
|
|
||||||
<Localization i18nKey={this.props.noI18n ?? "Popup.Action.No"}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Theme>;
|
</Theme>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { ConfirmPopup }
|
export { ConfirmPopup, ConfirmContent }
|
95
source/Component/SearchBox/SearchBox.scss
Normal file
95
source/Component/SearchBox/SearchBox.scss
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
@import "../Theme/Theme.scss";
|
||||||
|
|
||||||
|
$search-box-height: 26px;
|
||||||
|
|
||||||
|
div.search-box-root {
|
||||||
|
min-height: $search-box-height;
|
||||||
|
max-width: 280px;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 3px;
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
div.search-icon {
|
||||||
|
min-width: $search-box-height;
|
||||||
|
height: $search-box-height;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.input-box {
|
||||||
|
width: calc(100% - 26px);
|
||||||
|
height: $search-box-height;
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
outline: none;
|
||||||
|
background-color: transparent;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.clean-box {
|
||||||
|
height: $search-box-height;
|
||||||
|
width: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
div.clean-box-view {
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
right: 24px;
|
||||||
|
border-radius: 3px;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dark.search-box-root {
|
||||||
|
|
||||||
|
div.clean-box {
|
||||||
|
|
||||||
|
div.clean-box-view:hover {
|
||||||
|
background-color: $lt-bg-color-lvl2-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.clean-box-view {
|
||||||
|
background-color: $lt-bg-color-lvl3-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.input-box input {
|
||||||
|
color: $lt-font-color-normal-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.light.search-box-root {
|
||||||
|
|
||||||
|
div.clean-box {
|
||||||
|
|
||||||
|
div.clean-box-view:hover {
|
||||||
|
background-color: $lt-bg-color-lvl3-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.clean-box-view {
|
||||||
|
background-color: $lt-bg-color-lvl2-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.input-box input {
|
||||||
|
color: $lt-font-color-normal-light;
|
||||||
|
}
|
||||||
|
}
|
60
source/Component/SearchBox/SearchBox.tsx
Normal file
60
source/Component/SearchBox/SearchBox.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { AllI18nKeys, I18N } from "@Component/Localization/Localization";
|
||||||
|
import { BackgroundLevel, FontLevel, Theme } from "@Component/Theme/Theme";
|
||||||
|
import { useSettingWithEvent, IMixinSettingProps } from "@Context/Setting";
|
||||||
|
import { Icon } from "@fluentui/react";
|
||||||
|
import { Component, ReactNode } from "react";
|
||||||
|
import "./SearchBox.scss";
|
||||||
|
|
||||||
|
interface ISearchBoxProps {
|
||||||
|
value?: string;
|
||||||
|
valueChange?: (value: string) => void;
|
||||||
|
placeholderI18N?: AllI18nKeys;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@useSettingWithEvent("language")
|
||||||
|
class SearchBox extends Component<ISearchBoxProps & IMixinSettingProps> {
|
||||||
|
|
||||||
|
private renderCleanBox() {
|
||||||
|
return <div className="clean-box">
|
||||||
|
<div
|
||||||
|
className="clean-box-view"
|
||||||
|
onClick={() => {
|
||||||
|
if (this.props.valueChange) {
|
||||||
|
this.props.valueChange("")
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon iconName="CalculatorMultiply"/>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): ReactNode {
|
||||||
|
return <Theme
|
||||||
|
className={"search-box-root" + (this.props.className ? ` ${this.props.className}` : "")}
|
||||||
|
backgroundLevel={BackgroundLevel.Level3}
|
||||||
|
fontLevel={FontLevel.normal}
|
||||||
|
>
|
||||||
|
<div className="search-icon">
|
||||||
|
<Icon iconName="search"/>
|
||||||
|
</div>
|
||||||
|
<div className="input-box">
|
||||||
|
<input
|
||||||
|
value={this.props.value}
|
||||||
|
placeholder={
|
||||||
|
I18N(this.props, this.props.placeholderI18N ?? "Common.Search.Placeholder")
|
||||||
|
}
|
||||||
|
onInput={(e) => {
|
||||||
|
if (e.target instanceof HTMLInputElement && this.props.valueChange) {
|
||||||
|
this.props.valueChange(e.target.value)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{this.props.value ? this.renderCleanBox() : null}
|
||||||
|
</Theme>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { SearchBox };
|
@ -53,10 +53,12 @@ const EN_US = {
|
|||||||
"Popup.Delete.Objects.Confirm": "Are you sure you want to delete this object(s)? The object is deleted and cannot be recalled.",
|
"Popup.Delete.Objects.Confirm": "Are you sure you want to delete this object(s)? The object is deleted and cannot be recalled.",
|
||||||
"Popup.Setting.Title": "Preferences setting",
|
"Popup.Setting.Title": "Preferences setting",
|
||||||
"Popup.Add.Behavior.Title": "Add behavior",
|
"Popup.Add.Behavior.Title": "Add behavior",
|
||||||
|
"Popup.Add.Behavior.Action.Add": "Add all select behavior",
|
||||||
"Build.In.Label.Name.All.Group": "All group",
|
"Build.In.Label.Name.All.Group": "All group",
|
||||||
"Build.In.Label.Name.All.Range": "All range",
|
"Build.In.Label.Name.All.Range": "All range",
|
||||||
"Behavior.Template.Title": "Behavior",
|
"Behavior.Template.Title": "Behavior",
|
||||||
"Behavior.Template.Intro": "This is a template behavior",
|
"Behavior.Template.Intro": "This is a template behavior",
|
||||||
|
"Common.Search.Placeholder": "Search in here...",
|
||||||
"Common.No.Data": "No Data",
|
"Common.No.Data": "No Data",
|
||||||
"Common.No.Unknown.Error": "Unknown error",
|
"Common.No.Unknown.Error": "Unknown error",
|
||||||
"Common.Attr.Title.Basic": "Basic properties",
|
"Common.Attr.Title.Basic": "Basic properties",
|
||||||
|
@ -53,10 +53,12 @@ const ZH_CN = {
|
|||||||
"Popup.Delete.Objects.Confirm": "你确定要删除这个(些)对象吗?对象被删除将无法撤回。",
|
"Popup.Delete.Objects.Confirm": "你确定要删除这个(些)对象吗?对象被删除将无法撤回。",
|
||||||
"Popup.Setting.Title": "首选项设置",
|
"Popup.Setting.Title": "首选项设置",
|
||||||
"Popup.Add.Behavior.Title": "添加行为",
|
"Popup.Add.Behavior.Title": "添加行为",
|
||||||
|
"Popup.Add.Behavior.Action.Add": "添加全部选中行为",
|
||||||
"Build.In.Label.Name.All.Group": "全部群",
|
"Build.In.Label.Name.All.Group": "全部群",
|
||||||
"Build.In.Label.Name.All.Range": "全部范围",
|
"Build.In.Label.Name.All.Range": "全部范围",
|
||||||
"Behavior.Template.Title": "行为",
|
"Behavior.Template.Title": "行为",
|
||||||
"Behavior.Template.Intro": "这是一个模板行为",
|
"Behavior.Template.Intro": "这是一个模板行为",
|
||||||
|
"Common.Search.Placeholder": "在此处搜索...",
|
||||||
"Common.No.Data": "暂无数据",
|
"Common.No.Data": "暂无数据",
|
||||||
"Common.No.Unknown.Error": "未知错误",
|
"Common.No.Unknown.Error": "未知错误",
|
||||||
"Common.Attr.Title.Basic": "基础属性",
|
"Common.Attr.Title.Basic": "基础属性",
|
||||||
|
Loading…
Reference in New Issue
Block a user