对article upset页面样式优化
This commit is contained in:
parent
0007146658
commit
37d87844f7
|
|
@ -104,7 +104,7 @@ export async function createSession(params, context) {
|
||||||
origin: 'wechat',
|
origin: 'wechat',
|
||||||
type: 'image',
|
type: 'image',
|
||||||
tag1: 'image',
|
tag1: 'image',
|
||||||
objectId: await generateNewIdAsync(),
|
objectId: await generateNewIdAsync(), // 这个域用来标识唯一性
|
||||||
sort: 1000,
|
sort: 1000,
|
||||||
uploadState: 'success',
|
uploadState: 'success',
|
||||||
extra1: data.MediaId,
|
extra1: data.MediaId,
|
||||||
|
|
@ -129,7 +129,7 @@ export async function createSession(params, context) {
|
||||||
origin: 'wechat',
|
origin: 'wechat',
|
||||||
type: 'video',
|
type: 'video',
|
||||||
tag1: 'video',
|
tag1: 'video',
|
||||||
objectId: await generateNewIdAsync(),
|
objectId: await generateNewIdAsync(), // 这个域用来标识唯一性
|
||||||
sort: 1000,
|
sort: 1000,
|
||||||
uploadState: 'success',
|
uploadState: 'success',
|
||||||
extra1: data.MediaId,
|
extra1: data.MediaId,
|
||||||
|
|
@ -151,7 +151,7 @@ export async function createSession(params, context) {
|
||||||
origin: 'wechat',
|
origin: 'wechat',
|
||||||
type: 'audio',
|
type: 'audio',
|
||||||
tag1: 'audio',
|
tag1: 'audio',
|
||||||
objectId: await generateNewIdAsync(),
|
objectId: await generateNewIdAsync(), // 这个域用来标识唯一性
|
||||||
sort: 1000,
|
sort: 1000,
|
||||||
uploadState: 'success',
|
uploadState: 'success',
|
||||||
extra1: data.MediaId,
|
extra1: data.MediaId,
|
||||||
|
|
|
||||||
|
|
@ -2325,8 +2325,8 @@ export async function refreshToken(params, context) {
|
||||||
// 只有server模式去刷新token
|
// 只有server模式去刷新token
|
||||||
// 'development' | 'production' | 'staging'
|
// 'development' | 'production' | 'staging'
|
||||||
const intervals = {
|
const intervals = {
|
||||||
development: 7200 * 1000,
|
development: 7200 * 1000, // 2小时
|
||||||
staging: 600 * 1000,
|
staging: 600 * 1000, // 十分钟
|
||||||
production: 600 * 1000, // 十分钟
|
production: 600 * 1000, // 十分钟
|
||||||
};
|
};
|
||||||
const application = context.getApplication();
|
const application = context.getApplication();
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@ export async function createWechatQrCode(options, context) {
|
||||||
permanent,
|
permanent,
|
||||||
url,
|
url,
|
||||||
expired: false,
|
expired: false,
|
||||||
expiresAt: Date.now() + 2592000 * 1000,
|
expiresAt: Date.now() + 2592000 * 1000, // wecharQrCode里的过期时间都放到最大,由上层关联对象来主动过期(by Xc, 20230131)
|
||||||
props,
|
props,
|
||||||
};
|
};
|
||||||
// 直接创建
|
// 直接创建
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
declare const checkers: (import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "applicationPassport", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>>)[];
|
declare const checkers: (import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "applicationPassport", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>>)[];
|
||||||
export default checkers;
|
export default checkers;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "article", false, {
|
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "article", false, {
|
||||||
tocWidth: number;
|
|
||||||
tocClosed: boolean;
|
tocClosed: boolean;
|
||||||
tocFixed: boolean;
|
tocFixed: boolean;
|
||||||
tocPosition: "left" | "right" | "none";
|
tocPosition: "none" | "left" | "right";
|
||||||
highlightBgColor: string;
|
highlightBgColor: string;
|
||||||
headerTop: number;
|
headerTop: number;
|
||||||
className: string;
|
className: string;
|
||||||
scrollId: string;
|
scrollId: string;
|
||||||
|
tocWidth: number | "auto" | undefined;
|
||||||
|
tocHeight: number | "auto" | undefined;
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,15 @@ export default OakComponent({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
tocWidth: 228,
|
|
||||||
tocClosed: false,
|
tocClosed: false,
|
||||||
tocFixed: true,
|
tocFixed: true,
|
||||||
tocPosition: 'none',
|
tocPosition: 'none',
|
||||||
highlightBgColor: 'none',
|
highlightBgColor: 'none',
|
||||||
headerTop: 0,
|
headerTop: 0, //页面中吸顶部分高度
|
||||||
className: '',
|
className: '',
|
||||||
scrollId: '', // 滚动条所在容器id,不传默认body
|
scrollId: '', // 滚动条所在容器id,不传默认body
|
||||||
|
tocWidth: undefined,
|
||||||
|
tocHeight: undefined,
|
||||||
},
|
},
|
||||||
lifetimes: {},
|
lifetimes: {},
|
||||||
methods: {}
|
methods: {}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { WebComponentProps } from 'oak-frontend-base';
|
import { WebComponentProps } from 'oak-frontend-base';
|
||||||
import { EntityDict } from '../../../oak-app-domain';
|
import { EntityDict } from '../../../oak-app-domain';
|
||||||
export default function Render(props: WebComponentProps<EntityDict, 'article', false, {
|
export default function Render(props: WebComponentProps<EntityDict, 'article', false, {
|
||||||
title?: string;
|
name?: string;
|
||||||
content?: string;
|
content?: string;
|
||||||
tocPosition: 'none' | 'left' | 'right';
|
tocPosition: 'none' | 'left' | 'right';
|
||||||
highlightBgColor: string;
|
highlightBgColor: string;
|
||||||
|
|
@ -10,6 +10,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'article', f
|
||||||
className?: string;
|
className?: string;
|
||||||
tocFixed: boolean;
|
tocFixed: boolean;
|
||||||
tocClosed: boolean;
|
tocClosed: boolean;
|
||||||
tocWidth: 228;
|
|
||||||
scrollId?: string;
|
scrollId?: string;
|
||||||
|
tocWidth?: number | 'auto';
|
||||||
|
tocHeight?: number | 'auto';
|
||||||
}, {}>): React.JSX.Element;
|
}, {}>): React.JSX.Element;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Col, Row } from 'antd';
|
|
||||||
import { Editor } from "@wangeditor/editor-for-react";
|
import { Editor } from "@wangeditor/editor-for-react";
|
||||||
import { SlateNode } from "@wangeditor/editor";
|
import { SlateNode } from "@wangeditor/editor";
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { TocView } from '../toc/tocView';
|
import { TocView } from '../toc/tocView';
|
||||||
import Style from './web.module.less';
|
import Styles from './web.module.less';
|
||||||
export default function Render(props) {
|
export default function Render(props) {
|
||||||
const { className, content, tocPosition = 'none', tocFixed, highlightBgColor = 'none', headerTop = 0, tocClosed = false, tocWidth = 228, scrollId } = props.data;
|
const { className, name, content, tocPosition = 'none', tocFixed, highlightBgColor = 'none', headerTop = 0, tocClosed = false, scrollId, tocWidth, tocHeight } = props.data;
|
||||||
const editorConfig = {
|
const editorConfig = {
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
|
|
@ -34,21 +33,23 @@ export default function Render(props) {
|
||||||
setShowToc(true);
|
setShowToc(true);
|
||||||
}
|
}
|
||||||
}, [tocPosition]);
|
}, [tocPosition]);
|
||||||
return (<div className={classNames(Style.container, className)}>
|
useEffect(() => {
|
||||||
<Row gutter={[16, 0]}>
|
if (name) {
|
||||||
{tocPosition === 'left' ? (<Col flex={`${tocWidth}px`}>
|
window.document.title = name;
|
||||||
<TocView toc={toc} showToc={showToc} tocPosition='left' setShowToc={setShowToc} highlightBgColor={highlightBgColor} headerTop={headerTop} fixed={tocFixed} closed={tocClosed} scrollId={scrollId}/>
|
}
|
||||||
</Col>) : null}
|
}, [name]);
|
||||||
|
return (<div className={classNames(Styles.container, className)}>
|
||||||
|
<div className={Styles.contentContainer}>
|
||||||
|
{tocPosition === "left" ? (<TocView toc={toc} showToc={showToc} tocPosition="left" setShowToc={setShowToc} highlightBgColor={highlightBgColor} headerTop={headerTop} fixed={tocFixed} closed={tocClosed} scrollId={scrollId} tocWidth={tocWidth} tocHeight={tocHeight}/>) : null}
|
||||||
|
|
||||||
<Col flex="auto">
|
<div className={Styles.content}>
|
||||||
<div className={Style.content}>
|
<div className={Styles.editorContainer}>
|
||||||
<div className={Style.editorContainer}>
|
|
||||||
<div style={{ width: "100%" }}>
|
<div style={{ width: "100%" }}>
|
||||||
<Editor defaultConfig={editorConfig} value={html} mode="default" style={{
|
<Editor defaultConfig={editorConfig} value={html} mode="default" style={{
|
||||||
width: '100%'
|
width: '100%'
|
||||||
}} onCreated={setEditor} onChange={(editor) => {
|
}} onCreated={setEditor} onChange={(editor) => {
|
||||||
setHtml(editor.getHtml());
|
setHtml(editor.getHtml());
|
||||||
const headers = editor.getElemsByTypePrefix('header');
|
const headers = editor.getElemsByTypePrefix("header");
|
||||||
const tocItems = headers.map((header) => {
|
const tocItems = headers.map((header) => {
|
||||||
const text = SlateNode.string(header);
|
const text = SlateNode.string(header);
|
||||||
const { id, type } = header;
|
const { id, type } = header;
|
||||||
|
|
@ -63,10 +64,7 @@ export default function Render(props) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
{tocPosition === "right" ? (<TocView toc={toc} showToc={showToc} tocPosition="right" setShowToc={setShowToc} highlightBgColor={highlightBgColor} headerTop={headerTop} fixed={tocFixed} closed={tocClosed} scrollId={scrollId} tocWidth={tocWidth} tocHeight={tocHeight}/>) : null}
|
||||||
{tocPosition === 'right' ? (<Col flex={`${tocWidth}px`}>
|
</div>
|
||||||
<TocView toc={toc} showToc={showToc} tocPosition='right' setShowToc={setShowToc} highlightBgColor={highlightBgColor} headerTop={headerTop} fixed={tocFixed} closed={tocClosed} scrollId={scrollId}/>
|
|
||||||
</Col>) : null}
|
|
||||||
</Row>
|
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,12 @@
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contentContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex: 1;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -14,7 +20,7 @@
|
||||||
max-width: 794px;
|
max-width: 794px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: var(--oak-bg-color-container);
|
background: #fff;
|
||||||
padding: 20px 50px 50px 50px;
|
padding: 20px 50px 50px 50px;
|
||||||
box-shadow: 0 2px 10px rgb(0 0 0 / 12%);
|
box-shadow: 0 2px 10px rgb(0 0 0 / 12%);
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
|
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
|
||||||
tocClosed: boolean;
|
tocClosed: boolean;
|
||||||
tocFixed: boolean;
|
tocFixed: boolean;
|
||||||
tocPosition: "left" | "right" | "none";
|
tocPosition: "none" | "left" | "right";
|
||||||
highlightBgColor: string;
|
highlightBgColor: string;
|
||||||
headerTop: number;
|
headerTop: number;
|
||||||
className: string;
|
className: string;
|
||||||
scrollId: string;
|
scrollId: string;
|
||||||
|
tocWidth: number | "auto" | undefined;
|
||||||
|
tocHeight: number | "auto" | undefined;
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ export default OakComponent({
|
||||||
data: {
|
data: {
|
||||||
content: '',
|
content: '',
|
||||||
title: '',
|
title: '',
|
||||||
author: '',
|
|
||||||
},
|
},
|
||||||
lifetimes: {
|
lifetimes: {
|
||||||
async attached() {
|
async attached() {
|
||||||
|
|
@ -18,7 +17,6 @@ export default OakComponent({
|
||||||
this.setState({
|
this.setState({
|
||||||
content: article?.content,
|
content: article?.content,
|
||||||
title: article?.title,
|
title: article?.title,
|
||||||
author: article?.author,
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
detached() {
|
detached() {
|
||||||
|
|
@ -30,9 +28,11 @@ export default OakComponent({
|
||||||
tocFixed: true,
|
tocFixed: true,
|
||||||
tocPosition: 'none',
|
tocPosition: 'none',
|
||||||
highlightBgColor: 'none',
|
highlightBgColor: 'none',
|
||||||
headerTop: 0,
|
headerTop: 0, //页面中吸顶部分高度
|
||||||
className: '',
|
className: '',
|
||||||
scrollId: '', // 滚动条所在容器id,不传默认body
|
scrollId: '', // 滚动条所在容器id,不传默认body
|
||||||
|
tocWidth: undefined,
|
||||||
|
tocHeight: undefined,
|
||||||
},
|
},
|
||||||
methods: {},
|
methods: {},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,6 @@ export default function Render(props: WebComponentProps<EntityDict, 'article', f
|
||||||
tocFixed: boolean;
|
tocFixed: boolean;
|
||||||
tocClosed: boolean;
|
tocClosed: boolean;
|
||||||
scrollId?: string;
|
scrollId?: string;
|
||||||
|
tocWidth?: number | 'auto';
|
||||||
|
tocHeight?: number | 'auto';
|
||||||
}, {}>): React.JSX.Element;
|
}, {}>): React.JSX.Element;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Editor } from '@wangeditor/editor-for-react';
|
import { Editor } from '@wangeditor/editor-for-react';
|
||||||
import { SlateNode } from '@wangeditor/editor';
|
import { SlateNode } from '@wangeditor/editor';
|
||||||
import { Col, Row } from 'antd';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { TocView } from '../toc/tocView';
|
import { TocView } from '../toc/tocView';
|
||||||
import Styles from './web.module.less';
|
import Styles from './web.module.less';
|
||||||
export default function Render(props) {
|
export default function Render(props) {
|
||||||
const { className, content, tocPosition = 'none', tocFixed, highlightBgColor = 'none', headerTop = 0, tocClosed = false, scrollId } = props.data;
|
const { className, content, tocPosition = 'none', tocFixed, highlightBgColor = 'none', headerTop = 0, tocClosed = false, scrollId, tocWidth, tocHeight } = props.data;
|
||||||
const editorConfig = {
|
const editorConfig = {
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
|
|
@ -35,20 +34,17 @@ export default function Render(props) {
|
||||||
}
|
}
|
||||||
}, [tocPosition]);
|
}, [tocPosition]);
|
||||||
return (<div className={classNames(Styles.container, className)}>
|
return (<div className={classNames(Styles.container, className)}>
|
||||||
<Row gutter={[16, 0]}>
|
<div className={Styles.contentContainer}>
|
||||||
{tocPosition === 'left' && (<Col flex="228px">
|
{tocPosition === "left" && (<TocView toc={toc} showToc={showToc} tocPosition="left" setShowToc={setShowToc} highlightBgColor={highlightBgColor} headerTop={headerTop} fixed={tocFixed} closed={tocClosed} scrollId={scrollId} tocWidth={tocWidth} tocHeight={tocHeight}/>)}
|
||||||
<TocView toc={toc} showToc={showToc} tocPosition='left' setShowToc={setShowToc} highlightBgColor={highlightBgColor} headerTop={headerTop} fixed={tocFixed} closed={tocClosed} scrollId={scrollId}/>
|
|
||||||
</Col>)}
|
|
||||||
|
|
||||||
<Col flex="auto">
|
|
||||||
<div className={Styles.content}>
|
<div className={Styles.content}>
|
||||||
<div className={Styles.editorContainer}>
|
<div className={Styles.editorContainer}>
|
||||||
<div style={{ width: "100%" }}>
|
<div style={{ width: "100%" }}>
|
||||||
<Editor defaultConfig={editorConfig} value={html} mode="default" style={{
|
<Editor defaultConfig={editorConfig} value={html} mode="default" style={{
|
||||||
width: '100%'
|
width: "100%",
|
||||||
}} onCreated={setEditor} onChange={(editor) => {
|
}} onCreated={setEditor} onChange={(editor) => {
|
||||||
setHtml(editor.getHtml());
|
setHtml(editor.getHtml());
|
||||||
const headers = editor.getElemsByTypePrefix('header');
|
const headers = editor.getElemsByTypePrefix("header");
|
||||||
const tocItems = headers.map((header) => {
|
const tocItems = headers.map((header) => {
|
||||||
const text = SlateNode.string(header);
|
const text = SlateNode.string(header);
|
||||||
const { id, type } = header;
|
const { id, type } = header;
|
||||||
|
|
@ -63,10 +59,7 @@ export default function Render(props) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
{tocPosition === "right" && (<TocView toc={toc} showToc={showToc} tocPosition="right" setShowToc={setShowToc} highlightBgColor={highlightBgColor} headerTop={headerTop} fixed={tocFixed} closed={tocClosed} scrollId={scrollId} tocWidth={tocWidth} tocHeight={tocHeight}/>)}
|
||||||
{tocPosition === 'right' && (<Col flex="228px">
|
</div>
|
||||||
<TocView toc={toc} showToc={showToc} tocPosition='right' setShowToc={setShowToc} highlightBgColor={highlightBgColor} headerTop={headerTop} fixed={tocFixed} closed={tocClosed} scrollId={scrollId}/>
|
|
||||||
</Col>)}
|
|
||||||
</Row>
|
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
.container {
|
.container {
|
||||||
// min-height: 100vh;
|
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contentContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex: 1;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,6 @@ export declare function TocView(props: {
|
||||||
fixed?: boolean;
|
fixed?: boolean;
|
||||||
scrollId?: string;
|
scrollId?: string;
|
||||||
closed?: boolean;
|
closed?: boolean;
|
||||||
tocWidth?: number;
|
tocWidth?: number | 'auto';
|
||||||
|
tocHeight?: number | 'auto';
|
||||||
}): import("react").JSX.Element;
|
}): import("react").JSX.Element;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { CaretDownOutlined, CloseOutlined, MenuOutlined } from "@ant-design/icon
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import Style from './tocView.module.less';
|
import Style from './tocView.module.less';
|
||||||
export function TocView(props) {
|
export function TocView(props) {
|
||||||
const { toc, showToc, tocPosition, setShowToc, highlightBgColor, headerTop = 0, scrollId, fixed = false, closed = false, tocWidth = 228 } = props;
|
const { toc, showToc, tocPosition, setShowToc, highlightBgColor, headerTop = 0, scrollId, fixed = false, closed = false, tocWidth, tocHeight } = props;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.documentElement.style.setProperty('--highlight-bg-color', highlightBgColor);
|
document.documentElement.style.setProperty('--highlight-bg-color', highlightBgColor);
|
||||||
}, [highlightBgColor]);
|
}, [highlightBgColor]);
|
||||||
|
|
@ -84,7 +84,7 @@ export function TocView(props) {
|
||||||
};
|
};
|
||||||
return (<div className={classNames(Style.tocContainer, {
|
return (<div className={classNames(Style.tocContainer, {
|
||||||
[Style.fixed]: fixed
|
[Style.fixed]: fixed
|
||||||
})}>
|
})} style={Object.assign({}, tocWidth ? { width: tocWidth } : {}, tocHeight ? { height: tocHeight } : {})}>
|
||||||
{showToc ? (<>
|
{showToc ? (<>
|
||||||
<div className={Style.catalogTitle}>
|
<div className={Style.catalogTitle}>
|
||||||
<div style={{ color: '#A5A5A5' }}>大纲</div>
|
<div style={{ color: '#A5A5A5' }}>大纲</div>
|
||||||
|
|
|
||||||
|
|
@ -88,9 +88,10 @@ export default function Render(props) {
|
||||||
}}/>
|
}}/>
|
||||||
</div> : <>
|
</div> : <>
|
||||||
<Button type="text" icon={<EditOutlined />} size="small" onClick={(e) => {
|
<Button type="text" icon={<EditOutlined />} size="small" onClick={(e) => {
|
||||||
e.stopPropagation();
|
setName(ele.name);
|
||||||
setNameEditing(ele.id);
|
setNameEditing(ele.id);
|
||||||
}} style={{ marginRight: 4 }}/>
|
e.stopPropagation();
|
||||||
|
}}/>
|
||||||
<div className={Styles.name}>
|
<div className={Styles.name}>
|
||||||
<div style={{ marginLeft: 4, overflow: 'hidden', width: '150px', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{ele?.name}</div>
|
<div style={{ marginLeft: 4, overflow: 'hidden', width: '150px', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{ele?.name}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 60px;
|
height: 50px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@ import { EntityDict } from '../../../oak-app-domain';
|
||||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, "article", false, {
|
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, "article", false, {
|
||||||
articleMenuId: string;
|
articleMenuId: string;
|
||||||
changeIsEdit: () => void;
|
changeIsEdit: () => void;
|
||||||
tocPosition: "left" | "right" | "none";
|
tocPosition: "none" | "left" | "right";
|
||||||
highlightBgColor: string;
|
highlightBgColor: string;
|
||||||
onArticlePreview: (content?: string, title?: string) => void;
|
onArticlePreview: (content?: string, title?: string) => void;
|
||||||
origin: string;
|
origin: string;
|
||||||
scrollId: string;
|
scrollId: string;
|
||||||
|
height: number | "auto";
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,12 @@ export default OakComponent({
|
||||||
properties: {
|
properties: {
|
||||||
articleMenuId: '',
|
articleMenuId: '',
|
||||||
changeIsEdit: () => undefined,
|
changeIsEdit: () => undefined,
|
||||||
tocPosition: 'none',
|
tocPosition: 'none', //目录显示位置,none为不显示目录
|
||||||
highlightBgColor: 'none',
|
highlightBgColor: 'none', //点击目录时标题高亮背景色,none为不显示高亮背景色
|
||||||
onArticlePreview: (content, title) => undefined,
|
onArticlePreview: (content, title) => undefined, //预览文章
|
||||||
origin: 'qiniu',
|
origin: 'qiniu', // 默认为七牛云
|
||||||
scrollId: '', // 滚动条所在容器id,不传默认页面编辑器容器id
|
scrollId: '', // 滚动条所在容器id,不传默认页面编辑器容器id
|
||||||
|
height: 600,
|
||||||
},
|
},
|
||||||
listeners: {
|
listeners: {
|
||||||
'editor,content'(prev, next) {
|
'editor,content'(prev, next) {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ export default function Render(props: WebComponentProps<EntityDict, 'article', f
|
||||||
name: string;
|
name: string;
|
||||||
editor: any;
|
editor: any;
|
||||||
content?: string;
|
content?: string;
|
||||||
html?: string;
|
|
||||||
origin?: string;
|
origin?: string;
|
||||||
contentTip: boolean;
|
contentTip: boolean;
|
||||||
articleMenuId: string;
|
articleMenuId: string;
|
||||||
|
|
@ -15,6 +14,9 @@ export default function Render(props: WebComponentProps<EntityDict, 'article', f
|
||||||
tocPosition: 'none' | 'left' | 'right';
|
tocPosition: 'none' | 'left' | 'right';
|
||||||
highlightBgColor: string;
|
highlightBgColor: string;
|
||||||
scrollId?: string;
|
scrollId?: string;
|
||||||
|
tocWidth?: number | 'auto';
|
||||||
|
tocHeight?: number | 'auto';
|
||||||
|
height?: number | 'auto';
|
||||||
}, {
|
}, {
|
||||||
setHtml: (content: string) => void;
|
setHtml: (content: string) => void;
|
||||||
setEditor: (editor: any) => void;
|
setEditor: (editor: any) => void;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Alert, Button, Row, Col, Space, Input, Tooltip, } from "antd";
|
import { Alert, Button, Space, Input, } from "antd";
|
||||||
import "@wangeditor/editor/dist/css/style.css"; // 引入 css
|
import "@wangeditor/editor/dist/css/style.css"; // 引入 css
|
||||||
import { Editor, Toolbar } from "@wangeditor/editor-for-react";
|
import { Editor, Toolbar } from "@wangeditor/editor-for-react";
|
||||||
import { SlateNode } from "@wangeditor/editor";
|
import { SlateNode } from "@wangeditor/editor";
|
||||||
|
|
@ -7,7 +7,8 @@ import { generateNewId } from "oak-domain/lib/utils/uuid";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import Prompt from "../../../components/common/prompt";
|
import Prompt from "../../../components/common/prompt";
|
||||||
import Style from "./web.module.less";
|
import Style from "./web.module.less";
|
||||||
import { CloseOutlined, EyeOutlined, MenuOutlined, CaretDownOutlined } from "@ant-design/icons";
|
import { TocView } from '../toc/tocView';
|
||||||
|
import { EyeOutlined, } from "@ant-design/icons";
|
||||||
// 工具栏配置
|
// 工具栏配置
|
||||||
const toolbarConfig = {
|
const toolbarConfig = {
|
||||||
excludeKeys: ["fullScreen"],
|
excludeKeys: ["fullScreen"],
|
||||||
|
|
@ -27,105 +28,14 @@ function customCheckImageFn(src, alt, url) {
|
||||||
// 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)
|
// 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)
|
||||||
// 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息
|
// 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息
|
||||||
}
|
}
|
||||||
function TocView(props) {
|
|
||||||
const { toc, showToc, tocPosition, setShowToc, highlightBgColor, scrollId } = props;
|
|
||||||
useEffect(() => {
|
|
||||||
document.documentElement.style.setProperty('--highlight-bg-color', highlightBgColor);
|
|
||||||
}, [highlightBgColor]);
|
|
||||||
const generateTocList = (items, currentLevel = 1, parentId = null) => {
|
|
||||||
//递归生成嵌套列表
|
|
||||||
const result = [];
|
|
||||||
let lastId = parentId;
|
|
||||||
while (items.length > 0) {
|
|
||||||
const item = items[0];
|
|
||||||
//有无子级标题,有则显示展开图标
|
|
||||||
const hasChildren = items.length > 1 && items[1].level > item.level;
|
|
||||||
if (item.level > currentLevel) {
|
|
||||||
// 递归生成子列表
|
|
||||||
const sublist = generateTocList(items, item.level, item.id);
|
|
||||||
result.push(<li key={item.id} id={`ul-${lastId}`}>
|
|
||||||
<ul style={{ listStyleType: 'none', paddingInlineStart: '6px' }}>
|
|
||||||
{sublist}
|
|
||||||
</ul>
|
|
||||||
</li>);
|
|
||||||
}
|
|
||||||
else if (item.level < currentLevel) {
|
|
||||||
// 结束当前层级
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// 添加当前层级的 <li>
|
|
||||||
result.push(<li className={Style.listItem} key={item.id} id={`li-${item.id}`} style={{ paddingLeft: `${(item.level - 1) * 6}px`, }}>
|
|
||||||
<CaretDownOutlined id={`icon-${item.id}`} className={Style.icon} style={{ visibility: hasChildren && item.level < 5 ? 'visible' : 'hidden', color: '#A5A5A5' }} onClick={() => {
|
|
||||||
const iconElem = document.getElementById(`icon-${item.id}`);
|
|
||||||
const ulElem = document.getElementById(`ul-${item.id}`);
|
|
||||||
const isFolded = iconElem?.className.includes('iconFold') || ulElem?.className.includes('fold');
|
|
||||||
if (isFolded) {
|
|
||||||
iconElem?.classList.remove(Style.iconFold);
|
|
||||||
ulElem?.classList.remove(Style.fold);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
iconElem?.classList.add(Style.iconFold);
|
|
||||||
ulElem?.classList.add(Style.fold);
|
|
||||||
}
|
|
||||||
}}/>
|
|
||||||
<div style={{ fontSize: '1em', fontWeight: item.level === 1 ? 'bold' : 'normal' }} className={Style.tocItem} onClick={(event) => {
|
|
||||||
// editor.scrollToElem(item.id);
|
|
||||||
//编辑器滚动到对应元素
|
|
||||||
const elem = document.getElementById(item.id);
|
|
||||||
const elemTop = elem?.getBoundingClientRect().top;
|
|
||||||
const scrollContainer = document.getElementById(scrollId || 'article-upsert-editorContainer');
|
|
||||||
const containerTop = scrollContainer?.getBoundingClientRect().top;
|
|
||||||
scrollContainer?.scrollBy({
|
|
||||||
top: elemTop - containerTop,
|
|
||||||
behavior: 'smooth',
|
|
||||||
});
|
|
||||||
//添加背景色
|
|
||||||
elem?.classList.add(Style.highlight);
|
|
||||||
//移除背景色类名
|
|
||||||
setTimeout(function () {
|
|
||||||
elem?.classList.remove(Style.highlight);
|
|
||||||
}, 1000);
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}}>
|
|
||||||
{item.text}
|
|
||||||
</div>
|
|
||||||
</li>);
|
|
||||||
items.shift(); // 移除已处理的项
|
|
||||||
lastId = item.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
return (<div className={classNames(Style.tocContainer, {
|
|
||||||
// [Style.fixed]: fixed
|
|
||||||
})}>
|
|
||||||
{showToc ? (<>
|
|
||||||
<div className={Style.catalogTitle}>
|
|
||||||
<div style={{ color: '#A5A5A5' }}>大纲</div>
|
|
||||||
<CloseOutlined style={{ color: '#A5A5A5' }} onClick={() => setShowToc(false)}/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{(toc && toc.length > 0) ? (<ul style={{ listStyleType: 'none', paddingInlineStart: '0px' }}>{generateTocList([...toc])}</ul>) : (<div style={{ display: 'flex', alignItems: 'center', color: '#B1B1B1', height: '200px' }}>
|
|
||||||
<div>
|
|
||||||
对文档内容应用“标题”样式,即可生成大纲
|
|
||||||
</div>
|
|
||||||
</div>)}
|
|
||||||
</>) : (<div className={classNames(Style.tocButton, { [Style.tocButtonRight]: tocPosition === 'right' })}>
|
|
||||||
<Tooltip title="显示大纲" placement={tocPosition === 'right' ? 'left' : 'right'}>
|
|
||||||
<Button size="small" icon={<MenuOutlined />} onClick={() => setShowToc(true)}/>
|
|
||||||
</Tooltip>
|
|
||||||
</div>)}
|
|
||||||
</div>);
|
|
||||||
}
|
|
||||||
export default function Render(props) {
|
export default function Render(props) {
|
||||||
const { methods, data } = props;
|
const { methods, data } = props;
|
||||||
const { t, setEditor, check, uploadFile, update, setHtml, gotoPreview, clearContentTip, } = methods;
|
const { t, setEditor, check, uploadFile, update, setHtml, gotoPreview, clearContentTip, } = methods;
|
||||||
const { id, content, editor, origin = 'qiniu', oakFullpath, html, tocPosition = 'none', highlightBgColor = 'none', scrollId } = data;
|
const { oakFullpath, id, content, editor, origin = 'qiniu', tocPosition = 'none', highlightBgColor = 'none', scrollId, tocWidth, tocHeight, height = 600 } = data;
|
||||||
const [articleId, setArticleId] = useState('');
|
const [articleId, setArticleId] = useState('');
|
||||||
const [toc, setToc] = useState([]);
|
const [toc, setToc] = useState([]);
|
||||||
const [showToc, setShowToc] = useState(false);
|
const [showToc, setShowToc] = useState(false);
|
||||||
|
const containerId = scrollId || 'article-upsert-editorContainer';
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (id) {
|
if (id) {
|
||||||
setArticleId(id);
|
setArticleId(id);
|
||||||
|
|
@ -137,28 +47,25 @@ export default function Render(props) {
|
||||||
}
|
}
|
||||||
}, [tocPosition]);
|
}, [tocPosition]);
|
||||||
return (<div className={Style.container}>
|
return (<div className={Style.container}>
|
||||||
<Prompt when={!id || data.oakDirty} message={'您确认离开页面吗?'}/>
|
<Prompt when={!id || data.oakDirty} message={"您确认离开页面吗?"}/>
|
||||||
<div style={{ width: 'calc(100% - 16px)', }}>
|
<div style={{ width: "calc(100% - 16px)" }}>
|
||||||
<Toolbar editor={editor} defaultConfig={toolbarConfig} mode="default"/>
|
<Toolbar editor={editor} defaultConfig={toolbarConfig} mode="default"/>
|
||||||
</div>
|
</div>
|
||||||
<Row gutter={[16, 0]}>
|
<div className={Style.contentContainer}>
|
||||||
{tocPosition === 'left' ? (<Col flex="228px">
|
{tocPosition === "left" ? (<TocView toc={toc} showToc={showToc} tocPosition="left" setShowToc={setShowToc} highlightBgColor={highlightBgColor} scrollId={containerId} tocWidth={tocWidth} tocHeight={tocHeight || height}/>) : null}
|
||||||
<TocView toc={toc} showToc={showToc} tocPosition='left' setShowToc={setShowToc} highlightBgColor={highlightBgColor} scrollId={scrollId}/>
|
|
||||||
</Col>) : null}
|
|
||||||
|
|
||||||
<Col flex="auto">
|
<div className={Style.content} style={{ maxWidth: `calc(100% - ${tocWidth || 228}px)` }}>
|
||||||
<div className={Style.content}>
|
<div id={containerId} className={classNames(Style.editorContainer, {
|
||||||
<div id="article-upsert-editorContainer" className={classNames(Style.editorContainer, {
|
[Style.editorExternalContainer]: !!scrollId,
|
||||||
[Style.editorExternalContainer]: !!scrollId
|
|
||||||
})}>
|
})}>
|
||||||
{data.contentTip && (<Alert type="info" message={t('tips.content')} closable onClose={() => clearContentTip()}/>)}
|
{data.contentTip && (<Alert type="info" message={t("tips.content")} closable onClose={() => clearContentTip()}/>)}
|
||||||
<div className={Style.titleContainer}>
|
<div className={Style.titleContainer}>
|
||||||
<Input onChange={(e) => update({ name: e.target.value })} value={data.name} placeholder={'请输入文章标题'} size="large" maxLength={32} suffix={`${[...(data.name || '')].length}/32`} className={Style.titleInput}/>
|
<Input onChange={(e) => update({ name: e.target.value })} value={data.name} placeholder={"请输入文章标题"} size="large" maxLength={32} suffix={`${(data.name || "").length}/32`} className={Style.titleInput}/>
|
||||||
</div>
|
</div>
|
||||||
<div className={Style.editorContent}>
|
<div className={Style.editorContent}>
|
||||||
<Editor defaultConfig={{
|
<Editor defaultConfig={{
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
placeholder: '请输入文章内容...',
|
placeholder: "请输入文章内容...",
|
||||||
MENU_CONF: {
|
MENU_CONF: {
|
||||||
checkImage: customCheckImageFn,
|
checkImage: customCheckImageFn,
|
||||||
uploadImage: {
|
uploadImage: {
|
||||||
|
|
@ -167,21 +74,21 @@ export default function Render(props) {
|
||||||
// TS 语法
|
// TS 语法
|
||||||
// file 即选中的文件
|
// file 即选中的文件
|
||||||
const { name, size, type } = file;
|
const { name, size, type } = file;
|
||||||
const extension = name.substring(name.lastIndexOf('.') + 1);
|
const extension = name.substring(name.lastIndexOf(".") + 1);
|
||||||
const filename = name.substring(0, name.lastIndexOf('.'));
|
const filename = name.substring(0, name.lastIndexOf("."));
|
||||||
const extraFile = {
|
const extraFile = {
|
||||||
entity: 'article',
|
entity: "article",
|
||||||
entityId: articleId,
|
entityId: articleId,
|
||||||
origin: origin,
|
origin: origin,
|
||||||
type: 'image',
|
type: "image",
|
||||||
tag1: 'source',
|
tag1: "source",
|
||||||
objectId: generateNewId(),
|
objectId: generateNewId(),
|
||||||
filename,
|
filename,
|
||||||
size,
|
size,
|
||||||
extension,
|
extension,
|
||||||
bucket: '',
|
bucket: "",
|
||||||
id: generateNewId(),
|
id: generateNewId(),
|
||||||
fileType: type
|
fileType: type,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
// 自己实现上传,并得到图片 url alt href
|
// 自己实现上传,并得到图片 url alt href
|
||||||
|
|
@ -198,27 +105,28 @@ export default function Render(props) {
|
||||||
// TS 语法
|
// TS 语法
|
||||||
// file 即选中的文件
|
// file 即选中的文件
|
||||||
const { name, size, type } = file;
|
const { name, size, type } = file;
|
||||||
const extension = name.substring(name.lastIndexOf('.') + 1);
|
const extension = name.substring(name.lastIndexOf(".") + 1);
|
||||||
const filename = name.substring(0, name.lastIndexOf('.'));
|
const filename = name.substring(0, name.lastIndexOf("."));
|
||||||
const extraFile = {
|
const extraFile = {
|
||||||
entity: 'article',
|
entity: "article",
|
||||||
entityId: articleId,
|
entityId: articleId,
|
||||||
origin: origin,
|
origin: origin,
|
||||||
type: 'video',
|
type: "video",
|
||||||
tag1: 'source',
|
tag1: "source",
|
||||||
objectId: generateNewId(),
|
objectId: generateNewId(),
|
||||||
filename,
|
filename,
|
||||||
size,
|
size,
|
||||||
extension,
|
extension,
|
||||||
bucket: '',
|
bucket: "",
|
||||||
id: generateNewId(),
|
id: generateNewId(),
|
||||||
fileType: type
|
fileType: type,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
// 自己实现上传,并得到图片 url alt href
|
// 自己实现上传,并得到图片 url alt href
|
||||||
const url = await uploadFile(extraFile, file);
|
const url = await uploadFile(extraFile, file);
|
||||||
// 最后插入图片
|
// 最后插入图片
|
||||||
insertFn(url, url + '?vframe/jpg/offset/0');
|
insertFn(url, url +
|
||||||
|
"?vframe/jpg/offset/0");
|
||||||
}
|
}
|
||||||
catch (err) { }
|
catch (err) { }
|
||||||
},
|
},
|
||||||
|
|
@ -226,7 +134,7 @@ export default function Render(props) {
|
||||||
},
|
},
|
||||||
}} onCreated={setEditor} onChange={(editor) => {
|
}} onCreated={setEditor} onChange={(editor) => {
|
||||||
setHtml(editor.getHtml());
|
setHtml(editor.getHtml());
|
||||||
const headers = editor.getElemsByTypePrefix('header');
|
const headers = editor.getElemsByTypePrefix("header");
|
||||||
const tocItems = headers.map((header) => {
|
const tocItems = headers.map((header) => {
|
||||||
const text = SlateNode.string(header);
|
const text = SlateNode.string(header);
|
||||||
const { id, type } = header;
|
const { id, type } = header;
|
||||||
|
|
@ -241,11 +149,8 @@ export default function Render(props) {
|
||||||
minHeight: 440,
|
minHeight: 440,
|
||||||
}} mode="default"/>
|
}} mode="default"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className={Style.footer}>
|
<div className={Style.footer}>
|
||||||
<Row align="middle">
|
|
||||||
<Col flex="none">
|
|
||||||
<Space>
|
<Space>
|
||||||
<Button disabled={!data.oakDirty ||
|
<Button disabled={!data.oakDirty ||
|
||||||
data.oakExecuting} type="primary" onClick={() => {
|
data.oakExecuting} type="primary" onClick={() => {
|
||||||
|
|
@ -255,19 +160,13 @@ export default function Render(props) {
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => {
|
<Button onClick={() => {
|
||||||
gotoPreview(content, data.name);
|
gotoPreview(content, data.name);
|
||||||
}}>
|
}} icon={<EyeOutlined />}>
|
||||||
<EyeOutlined />
|
|
||||||
预览
|
预览
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
{tocPosition === "right" ? (<TocView toc={toc} showToc={showToc} tocPosition="right" setShowToc={setShowToc} highlightBgColor={highlightBgColor} scrollId={containerId} tocWidth={tocWidth} tocHeight={tocHeight}/>) : null}
|
||||||
{tocPosition === 'right' ? (<Col flex="228px">
|
</div>
|
||||||
<TocView toc={toc} showToc={showToc} tocPosition='right' setShowToc={setShowToc} highlightBgColor={highlightBgColor} scrollId={scrollId}/>
|
|
||||||
</Col>) : null}
|
|
||||||
</Row>
|
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,21 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contentContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex: 1;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.editorContainer {
|
.editorContainer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 30px auto 30px auto;
|
margin: 30px auto 30px auto;
|
||||||
|
|
@ -45,10 +56,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
// position: absolute;
|
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
margin-top: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.contentNumber {
|
.contentNumber {
|
||||||
|
|
@ -60,7 +69,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.tocContainer {
|
.tocContainer {
|
||||||
padding-top: 28px;
|
// padding-top: 28px;
|
||||||
position: relative;
|
position: relative;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
@ -101,7 +110,7 @@
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #DDD;
|
||||||
padding: 6px 6px 10px 6px;
|
padding: 34px 6px 10px 6px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ export default function Render(props) {
|
||||||
}
|
}
|
||||||
}, [editArticleId]);
|
}, [editArticleId]);
|
||||||
const [modal, contextHolder] = Modal.useModal();
|
const [modal, contextHolder] = Modal.useModal();
|
||||||
const [name, setName] = useState('');
|
|
||||||
const [nameEditing, setNameEditing] = useState(false);
|
const [nameEditing, setNameEditing] = useState(false);
|
||||||
const [showSub, setShowSub] = useState(false);
|
const [showSub, setShowSub] = useState(false);
|
||||||
const [newBreadcrumbItems, setNewBreadcrumbItems] = useState([]);
|
const [newBreadcrumbItems, setNewBreadcrumbItems] = useState([]);
|
||||||
|
|
@ -51,9 +50,7 @@ export default function Render(props) {
|
||||||
oakPath={`$articleMenu-parent-${row.id}`} onGrandChildEditArticleChange={onChildEditArticleChange} show={show} getBreadcrumbItems={getBreadcrumbItemsByParent} breadcrumbItems={newBreadcrumbItems} drawerOpen={drawerOpen} changeDrawerOpen={changeDrawerOpen} selectedArticleId={selectedArticleId} openArray={openArray ? openArray : undefined} getTopInfo={getTopInfo} articleId={articleId} currentArticle={currentArticle} setCurrentArticle={setCurrentArticle}/>);
|
oakPath={`$articleMenu-parent-${row.id}`} onGrandChildEditArticleChange={onChildEditArticleChange} show={show} getBreadcrumbItems={getBreadcrumbItemsByParent} breadcrumbItems={newBreadcrumbItems} drawerOpen={drawerOpen} changeDrawerOpen={changeDrawerOpen} selectedArticleId={selectedArticleId} openArray={openArray ? openArray : undefined} getTopInfo={getTopInfo} articleId={articleId} currentArticle={currentArticle} setCurrentArticle={setCurrentArticle}/>);
|
||||||
if (!row.parentId && articleMenuId) {
|
if (!row.parentId && articleMenuId) {
|
||||||
return (<>
|
return (<>
|
||||||
<div>
|
|
||||||
{Sub}
|
{Sub}
|
||||||
</div>
|
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
</>);
|
</>);
|
||||||
}
|
}
|
||||||
|
|
@ -145,39 +142,23 @@ export default function Render(props) {
|
||||||
return (<>
|
return (<>
|
||||||
<div className={Styles.container}>
|
<div className={Styles.container}>
|
||||||
<div className={Styles.ne}>
|
<div className={Styles.ne}>
|
||||||
{
|
|
||||||
// nameEditing ? <div className={Styles.name}>
|
|
||||||
// <Input
|
|
||||||
// autoFocus
|
|
||||||
// value={ name || row?.name}
|
|
||||||
// onChange={(evt) => setName(evt.target.value)}
|
|
||||||
// onPressEnter={async () => {
|
|
||||||
// if (name && name !== row?.name) {
|
|
||||||
// await onUpdateName(name);
|
|
||||||
// }
|
|
||||||
// setNameEditing(false);
|
|
||||||
// }}
|
|
||||||
// onBlur={async () => {
|
|
||||||
// if (name && name !== row?.name) {
|
|
||||||
// await onUpdateName(name);
|
|
||||||
// }
|
|
||||||
// setNameEditing(false);
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// </div> :
|
|
||||||
<>
|
|
||||||
<Button type="text" icon={<EditOutlined />} size="small" onClick={() => {
|
<Button type="text" icon={<EditOutlined />} size="small" onClick={() => {
|
||||||
setNameEditing(true);
|
setNameEditing(true);
|
||||||
const modalInstance = modal.confirm({
|
const modalInstance = modal.confirm({
|
||||||
title: '编辑分类',
|
title: "编辑分类",
|
||||||
cancelText: '取消',
|
cancelText: "取消",
|
||||||
okText: '提交',
|
okText: "提交",
|
||||||
content: (<div>
|
content: (<div>
|
||||||
<Form.Item label="分类名称">
|
<Form.Item label="分类名称">
|
||||||
<Input ref={menuNameRef} defaultValue={row.name} onChange={(val) => update({ name: val.target.value })}/>
|
<Input ref={menuNameRef} defaultValue={row.name} onChange={(val) => update({
|
||||||
|
name: val.target
|
||||||
|
.value,
|
||||||
|
})}/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="LOGO" help={<div>
|
<Form.Item label="LOGO" help={<div>
|
||||||
<span>请上传LOGO高清图片,</span>
|
<span>
|
||||||
|
请上传LOGO高清图片,
|
||||||
|
</span>
|
||||||
<span>
|
<span>
|
||||||
108*108像素,仅支持PNG、JPG格式,大小不超过300KB。
|
108*108像素,仅支持PNG、JPG格式,大小不超过300KB。
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -197,11 +178,12 @@ export default function Render(props) {
|
||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
footer: <Space>
|
footer: (<Space>
|
||||||
<ExtraFileCommit entity={oakEntity} oakPath={oakFullpath} afterCommit={() => {
|
<ExtraFileCommit entity={oakEntity} oakPath={oakFullpath} afterCommit={() => {
|
||||||
modalInstance.destroy();
|
modalInstance.destroy();
|
||||||
}} beforeCommit={() => {
|
}} beforeCommit={() => {
|
||||||
if (menuNameRef.current.input.value) {
|
if (menuNameRef.current
|
||||||
|
.input.value) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -211,22 +193,31 @@ export default function Render(props) {
|
||||||
<Button onClick={() => modalInstance.destroy()}>
|
<Button onClick={() => modalInstance.destroy()}>
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>),
|
||||||
});
|
});
|
||||||
}} style={{ marginRight: 4 }}/>
|
}}/>
|
||||||
<div className={Styles.name}>
|
<div className={Styles.name}>
|
||||||
{logo ? (<Image height={26} width={26} src={logo} preview={false}/>) : null}
|
{logo ? (<Image height={26} width={26} src={logo} preview={false}/>) : null}
|
||||||
<div style={{ marginLeft: 4, overflow: 'hidden', width: '100px', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{row?.name}</div>
|
<div style={{
|
||||||
|
marginLeft: 4,
|
||||||
|
overflow: "hidden",
|
||||||
|
width: "100px",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
}}>
|
||||||
|
{row?.name}
|
||||||
</div>
|
</div>
|
||||||
</>}
|
|
||||||
</div>
|
</div>
|
||||||
<Divider type="vertical" style={{ height: '100%', marginTop: 4, marginBottom: 4 }}/>
|
</div>
|
||||||
|
<Divider type="vertical" style={{
|
||||||
|
height: "100%",
|
||||||
|
marginTop: 4,
|
||||||
|
marginBottom: 4,
|
||||||
|
}}/>
|
||||||
<div className={Styles.control}>
|
<div className={Styles.control}>
|
||||||
{!row.parentId && <Button type="text" onClick={() => {
|
{!row.parentId && (<Button type="text" size="small" onClick={() => {
|
||||||
gotoDoc(row?.id);
|
gotoDoc(row?.id);
|
||||||
}} icon={<EyeOutlined />}>
|
}} icon={<EyeOutlined />}></Button>)}
|
||||||
</Button>}
|
|
||||||
|
|
||||||
|
|
||||||
<Dropdown menu={{ items }} placement="bottomRight" arrow>
|
<Dropdown menu={{ items }} placement="bottomRight" arrow>
|
||||||
<Button type="text" icon={<PlusOutlined />} size="small"/>
|
<Button type="text" icon={<PlusOutlined />} size="small"/>
|
||||||
|
|
@ -234,23 +225,21 @@ export default function Render(props) {
|
||||||
<Button type="text" icon={<MinusOutlined />} size="small" onClick={() => {
|
<Button type="text" icon={<MinusOutlined />} size="small" onClick={() => {
|
||||||
if (!allowRemove) {
|
if (!allowRemove) {
|
||||||
modal.error({
|
modal.error({
|
||||||
title: '无法删除',
|
title: "无法删除",
|
||||||
content: hasSubArticles ? '请先删除目录下的文章' : '请先删除目录下的子目录',
|
content: hasSubArticles
|
||||||
okText: '确认'
|
? "请先删除目录下的文章"
|
||||||
|
: "请先删除目录下的子目录",
|
||||||
|
okText: "确认",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
onRemove();
|
onRemove();
|
||||||
}
|
}
|
||||||
}}/>
|
}}/>
|
||||||
{(hasSubArticles || hasSubMenus) ? (showSub ?
|
{hasSubArticles || hasSubMenus ? (showSub ? (<Button type="text" icon={<UpOutlined />} size="small" onClick={() => setShowSub(false)}/>) : (<Button type="text" icon={<DownOutlined />} size="small" onClick={() => setShowSub(true)}/>)) : (<div className={Styles.ph}/>)}
|
||||||
<Button type="text" icon={<UpOutlined />} size="small" onClick={() => setShowSub(false)}/> :
|
|
||||||
<Button type="text" icon={<DownOutlined />} size="small" onClick={() => setShowSub(true)}/>) : <div className={Styles.ph}/>}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{showSub && (<div className={Styles.sub}>
|
{showSub ? Sub : null}
|
||||||
{Sub}
|
|
||||||
</div>)}
|
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
</>);
|
</>);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 60px;
|
height: 50px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
.ne {
|
.ne {
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
margin-left: 20px;
|
margin-left: 10px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
|
|
@ -43,6 +43,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sub {
|
.sub {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
background: rgba(0, 0, 0, 0.02);
|
background: rgba(0, 0, 0, 0.02);
|
||||||
padding-left: 18px;
|
padding-left: 18px;
|
||||||
}
|
}
|
||||||
|
|
@ -78,7 +80,6 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
// padding: 10px;
|
|
||||||
|
|
||||||
.ph {
|
.ph {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
|
||||||
show: "edit" | "doc" | "preview";
|
show: "edit" | "doc" | "preview";
|
||||||
articleMenuId: string;
|
articleMenuId: string;
|
||||||
articleId: string;
|
articleId: string;
|
||||||
tocPosition: "left" | "right" | "none";
|
tocPosition: "none" | "left" | "right";
|
||||||
highlightBgColor: string;
|
highlightBgColor: string;
|
||||||
onMenuView: () => void;
|
onMenuView: () => void;
|
||||||
onMenuViewById: (articleMenuId: string) => void;
|
onMenuViewById: (articleMenuId: string) => void;
|
||||||
onArticleView: (oakId: string) => void;
|
onArticleView: (articleId: string) => void;
|
||||||
onArticlePreview: (content?: string, title?: string) => void;
|
onArticlePreview: (content?: string, title?: string) => void;
|
||||||
onArticleEdit: (oakId: string) => void;
|
onArticleEdit: (articleId: string) => void;
|
||||||
setCopyArticleUrl: (id: string) => string;
|
setCopyArticleUrl: (articleId: string) => string;
|
||||||
origin: string;
|
origin: string;
|
||||||
scrollId: string;
|
scrollId: string;
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
|
|
|
||||||
|
|
@ -14,18 +14,18 @@ export default OakComponent({
|
||||||
properties: {
|
properties: {
|
||||||
entity: '',
|
entity: '',
|
||||||
entityId: '',
|
entityId: '',
|
||||||
show: 'edit',
|
show: 'edit', // edit为编辑,doc为查看,preview为预览
|
||||||
articleMenuId: '',
|
articleMenuId: '', // 菜单id
|
||||||
articleId: '',
|
articleId: '', //文章id
|
||||||
tocPosition: 'none',
|
tocPosition: 'none', //文章目录显示位置,none为不显示目录
|
||||||
highlightBgColor: 'none',
|
highlightBgColor: 'none', //点击文章目录时标题高亮背景色,none为不显示高亮背景色
|
||||||
onMenuView: () => undefined,
|
onMenuView: () => undefined, //查看全部菜单
|
||||||
onMenuViewById: (articleMenuId) => undefined,
|
onMenuViewById: (articleMenuId) => undefined, //查看指定id菜单
|
||||||
onArticleView: (oakId) => undefined,
|
onArticleView: (articleId) => undefined, //查看文章
|
||||||
onArticlePreview: (content, title) => undefined,
|
onArticlePreview: (content, title) => undefined, //预览文章
|
||||||
onArticleEdit: (oakId) => undefined,
|
onArticleEdit: (articleId) => undefined, //编辑文章
|
||||||
setCopyArticleUrl: (id) => '',
|
setCopyArticleUrl: (articleId) => '',
|
||||||
origin: 'qiniu',
|
origin: 'qiniu', // cos origin默认七牛云
|
||||||
scrollId: '', // 滚动条所在容器id,不传默认页面编辑器容器id
|
scrollId: '', // 滚动条所在容器id,不传默认页面编辑器容器id
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
min-width: 320px;
|
width: 320px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|
@ -17,13 +17,14 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 320px;
|
width: 320px;
|
||||||
padding: 8px 10px;
|
padding: 0px 10px;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
top: 0;
|
top: 0;
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
height: 50px;
|
||||||
|
|
||||||
.menuTitle {
|
.menuTitle {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|
@ -129,7 +130,6 @@
|
||||||
padding: 20px 15px;
|
padding: 20px 15px;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
// max-height: 800px;
|
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import { ReactComponentProps } from 'oak-frontend-base';
|
||||||
import { ECode } from '../../../types/ErrorPage';
|
import { ECode } from '../../../types/ErrorPage';
|
||||||
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, false, {
|
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, false, {
|
||||||
code: ECode;
|
code: ECode;
|
||||||
title?: string | undefined;
|
title?: string;
|
||||||
desc?: string | undefined;
|
desc?: string;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
/// <reference types="react" />
|
|
||||||
import { EntityDict } from '../../../oak-app-domain';
|
import { EntityDict } from '../../../oak-app-domain';
|
||||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
|
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
|
||||||
import { ReactComponentProps } from 'oak-frontend-base/lib/types/Page';
|
import { ReactComponentProps } from 'oak-frontend-base/lib/types/Page';
|
||||||
|
|
@ -9,31 +8,14 @@ type AfterCommit = (() => void) | undefined;
|
||||||
type BeforeCommit = (() => boolean | undefined | Promise<boolean | undefined>) | undefined;
|
type BeforeCommit = (() => boolean | undefined | Promise<boolean | undefined>) | undefined;
|
||||||
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
|
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
|
||||||
entity: keyof ED2;
|
entity: keyof ED2;
|
||||||
action?: string | undefined;
|
action?: string;
|
||||||
size?: ButtonProps['size'] | AmButtonProps['size'];
|
size?: ButtonProps['size'] | AmButtonProps['size'];
|
||||||
block?: boolean | undefined;
|
block?: boolean;
|
||||||
type?: ButtonProps['type'] | AmButtonProps['type'];
|
type?: ButtonProps['type'] | AmButtonProps['type'];
|
||||||
executeText?: string | undefined;
|
executeText?: string;
|
||||||
buttonProps?: (ButtonProps & {
|
buttonProps?: ButtonProps & AmButtonProps;
|
||||||
color?: "default" | "success" | "warning" | "primary" | "danger" | undefined;
|
|
||||||
fill?: "none" | "solid" | "outline" | undefined;
|
|
||||||
size?: "small" | "middle" | "large" | "mini" | undefined;
|
|
||||||
block?: boolean | undefined;
|
|
||||||
loading?: boolean | "auto" | undefined;
|
|
||||||
loadingText?: string | undefined;
|
|
||||||
loadingIcon?: import("react").ReactNode;
|
|
||||||
disabled?: boolean | undefined;
|
|
||||||
onClick?: ((event: import("react").MouseEvent<HTMLButtonElement, MouseEvent>) => unknown) | undefined;
|
|
||||||
type?: "button" | "submit" | "reset" | undefined;
|
|
||||||
shape?: "default" | "rounded" | "rectangular" | undefined;
|
|
||||||
children?: import("react").ReactNode;
|
|
||||||
} & Pick<import("react").ClassAttributes<HTMLButtonElement> & import("react").ButtonHTMLAttributes<HTMLButtonElement>, "id" | "onMouseDown" | "onMouseUp" | "onTouchEnd" | "onTouchStart"> & {
|
|
||||||
className?: string | undefined;
|
|
||||||
style?: (import("react").CSSProperties & Partial<Record<"--text-color" | "--background-color" | "--border-radius" | "--border-width" | "--border-style" | "--border-color", string>>) | undefined;
|
|
||||||
tabIndex?: number | undefined;
|
|
||||||
} & import("react").AriaAttributes) | undefined;
|
|
||||||
afterCommit?: AfterCommit;
|
afterCommit?: AfterCommit;
|
||||||
beforeCommit?: BeforeCommit;
|
beforeCommit?: BeforeCommit;
|
||||||
messageProps?: boolean | MessageProps | undefined;
|
messageProps?: MessageProps | boolean;
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,9 @@ export default OakComponent({
|
||||||
data: {
|
data: {
|
||||||
isModalOpen: false,
|
isModalOpen: false,
|
||||||
isModalOpen1: false,
|
isModalOpen1: false,
|
||||||
renderImgs: [],
|
renderImgs: [], // 读取的原文图片,在modal使用
|
||||||
methodsType: '',
|
methodsType: '',
|
||||||
bridgeUrl: '',
|
bridgeUrl: '', // 通过桥接方式获得的url
|
||||||
selectedId: -1,
|
selectedId: -1,
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,6 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
|
||||||
tag2: string;
|
tag2: string;
|
||||||
entity: keyof ED2;
|
entity: keyof ED2;
|
||||||
entityId: string;
|
entityId: string;
|
||||||
style?: string | undefined;
|
style?: string;
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,6 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
|
||||||
entityId: string;
|
entityId: string;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
style?: string | undefined;
|
style?: string;
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ export default OakComponent({
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
disabled: '',
|
disabled: '',
|
||||||
url: '',
|
url: '', // 登录系统之后要返回的页面
|
||||||
callback: undefined,
|
callback: undefined, // 登录成功回调,排除微信登录方式
|
||||||
setLoginMode: (value) => undefined,
|
setLoginMode: (value) => undefined,
|
||||||
digit: 4, //验证码位数
|
digit: 4, //验证码位数
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,15 @@ export default OakComponent({
|
||||||
allowPassword: false,
|
allowPassword: false,
|
||||||
allowWechatMp: false,
|
allowWechatMp: false,
|
||||||
setLoginModeMp(value) { this.setLoginMode(value); },
|
setLoginModeMp(value) { this.setLoginMode(value); },
|
||||||
smsDigit: 4,
|
smsDigit: 4, //短信验证码位数
|
||||||
emailDigit: 4, //邮箱验证码位数
|
emailDigit: 4, //邮箱验证码位数
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
onlyCaptcha: false,
|
onlyCaptcha: false,
|
||||||
onlyPassword: false,
|
onlyPassword: false,
|
||||||
disabled: '',
|
disabled: '',
|
||||||
redirectUri: '',
|
redirectUri: '', // 微信登录后的redirectUri,要指向wechatUser/login去处理
|
||||||
url: '',
|
url: '', // 登录系统之后要返回的页面
|
||||||
callback: undefined, // 登录成功回调,排除微信登录方式
|
callback: undefined, // 登录成功回调,排除微信登录方式
|
||||||
},
|
},
|
||||||
formData({ features, props }) {
|
formData({ features, props }) {
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@ export default OakComponent({
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
disabled: '',
|
disabled: '',
|
||||||
redirectUri: '',
|
redirectUri: '', // 微信登录后的redirectUri,要指向wechatUser/login去处理
|
||||||
url: '',
|
url: '', // 登录系统之后要返回的页面
|
||||||
callback: undefined,
|
callback: undefined, // 登录成功回调,排除微信登录方式
|
||||||
allowSms: false,
|
allowSms: false,
|
||||||
allowEmail: false,
|
allowEmail: false,
|
||||||
allowWechatMp: false,
|
allowWechatMp: false, //小程序切换授权登录
|
||||||
setLoginMode: (value) => undefined,
|
setLoginMode: (value) => undefined,
|
||||||
},
|
},
|
||||||
lifetimes: {},
|
lifetimes: {},
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,10 @@ export default OakComponent({
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
disabled: '',
|
disabled: '',
|
||||||
url: '',
|
url: '', // 登录系统之后要返回的页面
|
||||||
callback: undefined,
|
callback: undefined, // 登录成功回调,排除微信登录方式
|
||||||
allowPassword: false,
|
allowPassword: false, //小程序切换密码登录
|
||||||
allowWechatMp: false,
|
allowWechatMp: false, //小程序切换授权登录
|
||||||
setLoginMode: (value) => undefined,
|
setLoginMode: (value) => undefined,
|
||||||
digit: 4 //验证码位数,
|
digit: 4 //验证码位数,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { EntityDict } from '../../../oak-app-domain';
|
import { EntityDict } from '../../../oak-app-domain';
|
||||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, "userEntityGrant", false, {
|
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, "userEntityGrant", false, {
|
||||||
picker: ((props: {
|
picker: ((props: {
|
||||||
disabled?: boolean | undefined;
|
disabled?: boolean;
|
||||||
entity: keyof EntityDict;
|
entity: keyof EntityDict;
|
||||||
entityFilter: object;
|
entityFilter: object;
|
||||||
relationIds: string[];
|
relationIds: string[];
|
||||||
|
|
@ -9,8 +9,8 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
|
||||||
ruleOnRow: EntityDict['userEntityGrant']['OpSchema']['ruleOnRow'];
|
ruleOnRow: EntityDict['userEntityGrant']['OpSchema']['ruleOnRow'];
|
||||||
onPickRelations: (ids: string[]) => void;
|
onPickRelations: (ids: string[]) => void;
|
||||||
onPickRows: (ids: string[]) => void;
|
onPickRows: (ids: string[]) => void;
|
||||||
pickedRowIds?: string[] | undefined;
|
pickedRowIds?: string[];
|
||||||
pickedRelationIds?: string[] | undefined;
|
pickedRelationIds?: string[];
|
||||||
oakPath: string;
|
oakPath: string;
|
||||||
}) => React.ReactElement) | undefined;
|
}) => React.ReactElement) | undefined;
|
||||||
hideInfo: boolean;
|
hideInfo: boolean;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { ReactComponentProps } from 'oak-frontend-base';
|
||||||
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
|
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
|
||||||
entity: keyof ED2;
|
entity: keyof ED2;
|
||||||
entityId: string;
|
entityId: string;
|
||||||
redirectToAfterConfirm: ED2["userEntityGrant"]["Schema"]["redirectTo"];
|
redirectToAfterConfirm: ED2['userEntityGrant']['Schema']['redirectTo'];
|
||||||
qrCodeType: string;
|
qrCodeType: string;
|
||||||
showTitle: true;
|
showTitle: true;
|
||||||
showBack: false;
|
showBack: false;
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
|
||||||
entity: keyof ED2;
|
entity: keyof ED2;
|
||||||
entityId: string;
|
entityId: string;
|
||||||
relations: EntityDict['relation']['OpSchema'][];
|
relations: EntityDict['relation']['OpSchema'][];
|
||||||
passwordRequire?: boolean | undefined;
|
passwordRequire?: boolean;
|
||||||
allowUpdateName?: boolean | undefined;
|
allowUpdateName?: boolean;
|
||||||
allowUpdateNickname?: boolean | undefined;
|
allowUpdateNickname?: boolean;
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
|
||||||
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
|
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
|
||||||
entity: keyof ED2;
|
entity: keyof ED2;
|
||||||
entityId: string;
|
entityId: string;
|
||||||
allowUpdateName?: boolean | undefined;
|
allowUpdateName?: boolean;
|
||||||
allowUpdateNickname?: boolean | undefined;
|
allowUpdateNickname?: boolean;
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { ReactComponentProps } from 'oak-frontend-base';
|
||||||
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
|
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
|
||||||
entity: keyof ED2;
|
entity: keyof ED2;
|
||||||
entityId: string;
|
entityId: string;
|
||||||
redirectToAfterConfirm: ED2["userEntityGrant"]["Schema"]["redirectTo"];
|
redirectToAfterConfirm: ED2['userEntityGrant']['Schema']['redirectTo'];
|
||||||
qrCodeType: QrCodeType;
|
qrCodeType: QrCodeType;
|
||||||
type: EntityDict['userEntityGrant']['Schema']['type'];
|
type: EntityDict['userEntityGrant']['Schema']['type'];
|
||||||
relations: EntityDict['relation']['OpSchema'][];
|
relations: EntityDict['relation']['OpSchema'][];
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
|
||||||
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
|
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
|
||||||
entity: keyof ED2;
|
entity: keyof ED2;
|
||||||
entityId: string;
|
entityId: string;
|
||||||
redirectToAfterConfirm: ED2["userEntityGrant"]["Schema"]["redirectTo"];
|
redirectToAfterConfirm: ED2['userEntityGrant']['Schema']['redirectTo'];
|
||||||
claimUrl: string;
|
claimUrl: string;
|
||||||
qrCodeType: string;
|
qrCodeType: string;
|
||||||
passwordRequire?: boolean | undefined;
|
passwordRequire?: boolean;
|
||||||
allowUpdateName?: boolean | undefined;
|
allowUpdateName?: boolean;
|
||||||
allowUpdateNickname?: boolean | undefined;
|
allowUpdateNickname?: boolean;
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ export const desc = {
|
||||||
origin: {
|
origin: {
|
||||||
notNull: true,
|
notNull: true,
|
||||||
type: "enum",
|
type: "enum",
|
||||||
enumeration: ["qiniu", "wechat", "ctyun", "aliyun", "tencent", "unknown"]
|
enumeration: ["qiniu", "wechat", "ctyun", "aliyun", "tencent", "local", "unknown"]
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
notNull: true,
|
notNull: true,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ export const style = {
|
||||||
ctyun: '#ff0000',
|
ctyun: '#ff0000',
|
||||||
aliyun: '#1677ff',
|
aliyun: '#1677ff',
|
||||||
tencent: '#0052d9',
|
tencent: '#0052d9',
|
||||||
|
local: '#A9A9A9',
|
||||||
unknown: '#A9A9A9',
|
unknown: '#A9A9A9',
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
|
|
|
||||||
|
|
@ -1 +1,47 @@
|
||||||
{ "name": "文件", "attr": { "origin": "源", "type": "类型", "bucket": "桶", "objectId": "对象编号", "tag1": "标签一", "tag2": "标签二", "filename": "文件名", "md5": "md5", "entity": "关联对象", "entityId": "关联对象id", "extra1": "额外信息", "extra2": "非结构化额外信息", "extension": "后缀名", "size": "文件大小", "sort": "排序", "fileType": "文件类型", "isBridge": "是否桥接访问", "uploadState": "上传状态", "uploadMeta": "上传需要的metadata", "application": "来源应用" }, "v": { "origin": { "qiniu": "七牛云", "ctyun": "天翼云", "wechat": "微信", "aliyun": "阿里云", "tencent": "腾讯云", "unknown": "未知" }, "type": { "image": "图像", "video": "视频", "audio": "音频", "file": "文件" }, "uploadState": { "success": "上传成功", "failed": "上传失败", "uploading": "上传中" } } }
|
{
|
||||||
|
"name": "文件",
|
||||||
|
"attr": {
|
||||||
|
"origin": "源",
|
||||||
|
"type": "类型",
|
||||||
|
"bucket": "桶",
|
||||||
|
"objectId": "对象编号",
|
||||||
|
"tag1": "标签一",
|
||||||
|
"tag2": "标签二",
|
||||||
|
"filename": "文件名",
|
||||||
|
"md5": "md5",
|
||||||
|
"entity": "关联对象",
|
||||||
|
"entityId": "关联对象id",
|
||||||
|
"extra1": "额外信息",
|
||||||
|
"extra2": "非结构化额外信息",
|
||||||
|
"extension": "后缀名",
|
||||||
|
"size": "文件大小",
|
||||||
|
"sort": "排序",
|
||||||
|
"fileType": "文件类型",
|
||||||
|
"isBridge": "是否桥接访问",
|
||||||
|
"uploadState": "上传状态",
|
||||||
|
"uploadMeta": "上传需要的metadata",
|
||||||
|
"application": "来源应用"
|
||||||
|
},
|
||||||
|
"v": {
|
||||||
|
"origin": {
|
||||||
|
"qiniu": "七牛云",
|
||||||
|
"ctyun": "天翼云",
|
||||||
|
"wechat": "微信",
|
||||||
|
"aliyun": "阿里云",
|
||||||
|
"tencent": "腾讯云",
|
||||||
|
"local": "本地",
|
||||||
|
"unknown": "未知"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"image": "图像",
|
||||||
|
"video": "视频",
|
||||||
|
"audio": "音频",
|
||||||
|
"file": "文件"
|
||||||
|
},
|
||||||
|
"uploadState": {
|
||||||
|
"success": "上传成功",
|
||||||
|
"failed": "上传失败",
|
||||||
|
"uploading": "上传中"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
declare const _default: (import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "system", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "passport", import("..").BRC<import("../oak-app-domain").EntityDict>>)[];
|
declare const _default: (import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "system", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "passport", import("..").BRC<import("../oak-app-domain").EntityDict>>)[];
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ async function sendNotification(notification, context) {
|
||||||
await instance.sendSubscribedMessage({
|
await instance.sendSubscribedMessage({
|
||||||
templateId: templateId,
|
templateId: templateId,
|
||||||
data: data,
|
data: data,
|
||||||
openId: data1.openId,
|
openId: data1.openId, // 在notification创建时就赋值了
|
||||||
page,
|
page,
|
||||||
state: StateDict[process.env.NODE_ENV],
|
state: StateDict[process.env.NODE_ENV],
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ async function createSession(params, context) {
|
||||||
origin: 'wechat',
|
origin: 'wechat',
|
||||||
type: 'image',
|
type: 'image',
|
||||||
tag1: 'image',
|
tag1: 'image',
|
||||||
objectId: await (0, uuid_1.generateNewIdAsync)(),
|
objectId: await (0, uuid_1.generateNewIdAsync)(), // 这个域用来标识唯一性
|
||||||
sort: 1000,
|
sort: 1000,
|
||||||
uploadState: 'success',
|
uploadState: 'success',
|
||||||
extra1: data.MediaId,
|
extra1: data.MediaId,
|
||||||
|
|
@ -132,7 +132,7 @@ async function createSession(params, context) {
|
||||||
origin: 'wechat',
|
origin: 'wechat',
|
||||||
type: 'video',
|
type: 'video',
|
||||||
tag1: 'video',
|
tag1: 'video',
|
||||||
objectId: await (0, uuid_1.generateNewIdAsync)(),
|
objectId: await (0, uuid_1.generateNewIdAsync)(), // 这个域用来标识唯一性
|
||||||
sort: 1000,
|
sort: 1000,
|
||||||
uploadState: 'success',
|
uploadState: 'success',
|
||||||
extra1: data.MediaId,
|
extra1: data.MediaId,
|
||||||
|
|
@ -154,7 +154,7 @@ async function createSession(params, context) {
|
||||||
origin: 'wechat',
|
origin: 'wechat',
|
||||||
type: 'audio',
|
type: 'audio',
|
||||||
tag1: 'audio',
|
tag1: 'audio',
|
||||||
objectId: await (0, uuid_1.generateNewIdAsync)(),
|
objectId: await (0, uuid_1.generateNewIdAsync)(), // 这个域用来标识唯一性
|
||||||
sort: 1000,
|
sort: 1000,
|
||||||
uploadState: 'success',
|
uploadState: 'success',
|
||||||
extra1: data.MediaId,
|
extra1: data.MediaId,
|
||||||
|
|
|
||||||
|
|
@ -2346,8 +2346,8 @@ async function refreshToken(params, context) {
|
||||||
// 只有server模式去刷新token
|
// 只有server模式去刷新token
|
||||||
// 'development' | 'production' | 'staging'
|
// 'development' | 'production' | 'staging'
|
||||||
const intervals = {
|
const intervals = {
|
||||||
development: 7200 * 1000,
|
development: 7200 * 1000, // 2小时
|
||||||
staging: 600 * 1000,
|
staging: 600 * 1000, // 十分钟
|
||||||
production: 600 * 1000, // 十分钟
|
production: 600 * 1000, // 十分钟
|
||||||
};
|
};
|
||||||
const application = context.getApplication();
|
const application = context.getApplication();
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ async function createWechatQrCode(options, context) {
|
||||||
permanent,
|
permanent,
|
||||||
url,
|
url,
|
||||||
expired: false,
|
expired: false,
|
||||||
expiresAt: Date.now() + 2592000 * 1000,
|
expiresAt: Date.now() + 2592000 * 1000, // wecharQrCode里的过期时间都放到最大,由上层关联对象来主动过期(by Xc, 20230131)
|
||||||
props,
|
props,
|
||||||
};
|
};
|
||||||
// 直接创建
|
// 直接创建
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ exports.desc = {
|
||||||
origin: {
|
origin: {
|
||||||
notNull: true,
|
notNull: true,
|
||||||
type: "enum",
|
type: "enum",
|
||||||
enumeration: ["qiniu", "wechat", "ctyun", "aliyun", "tencent", "unknown"]
|
enumeration: ["qiniu", "wechat", "ctyun", "aliyun", "tencent", "local", "unknown"]
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
notNull: true,
|
notNull: true,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ exports.style = {
|
||||||
ctyun: '#ff0000',
|
ctyun: '#ff0000',
|
||||||
aliyun: '#1677ff',
|
aliyun: '#1677ff',
|
||||||
tencent: '#0052d9',
|
tencent: '#0052d9',
|
||||||
|
local: '#A9A9A9',
|
||||||
unknown: '#A9A9A9',
|
unknown: '#A9A9A9',
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
|
|
|
||||||
|
|
@ -1 +1,47 @@
|
||||||
{ "name": "文件", "attr": { "origin": "源", "type": "类型", "bucket": "桶", "objectId": "对象编号", "tag1": "标签一", "tag2": "标签二", "filename": "文件名", "md5": "md5", "entity": "关联对象", "entityId": "关联对象id", "extra1": "额外信息", "extra2": "非结构化额外信息", "extension": "后缀名", "size": "文件大小", "sort": "排序", "fileType": "文件类型", "isBridge": "是否桥接访问", "uploadState": "上传状态", "uploadMeta": "上传需要的metadata", "application": "来源应用" }, "v": { "origin": { "qiniu": "七牛云", "ctyun": "天翼云", "wechat": "微信", "aliyun": "阿里云", "tencent": "腾讯云", "unknown": "未知" }, "type": { "image": "图像", "video": "视频", "audio": "音频", "file": "文件" }, "uploadState": { "success": "上传成功", "failed": "上传失败", "uploading": "上传中" } } }
|
{
|
||||||
|
"name": "文件",
|
||||||
|
"attr": {
|
||||||
|
"origin": "源",
|
||||||
|
"type": "类型",
|
||||||
|
"bucket": "桶",
|
||||||
|
"objectId": "对象编号",
|
||||||
|
"tag1": "标签一",
|
||||||
|
"tag2": "标签二",
|
||||||
|
"filename": "文件名",
|
||||||
|
"md5": "md5",
|
||||||
|
"entity": "关联对象",
|
||||||
|
"entityId": "关联对象id",
|
||||||
|
"extra1": "额外信息",
|
||||||
|
"extra2": "非结构化额外信息",
|
||||||
|
"extension": "后缀名",
|
||||||
|
"size": "文件大小",
|
||||||
|
"sort": "排序",
|
||||||
|
"fileType": "文件类型",
|
||||||
|
"isBridge": "是否桥接访问",
|
||||||
|
"uploadState": "上传状态",
|
||||||
|
"uploadMeta": "上传需要的metadata",
|
||||||
|
"application": "来源应用"
|
||||||
|
},
|
||||||
|
"v": {
|
||||||
|
"origin": {
|
||||||
|
"qiniu": "七牛云",
|
||||||
|
"ctyun": "天翼云",
|
||||||
|
"wechat": "微信",
|
||||||
|
"aliyun": "阿里云",
|
||||||
|
"tencent": "腾讯云",
|
||||||
|
"local": "本地",
|
||||||
|
"unknown": "未知"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"image": "图像",
|
||||||
|
"video": "视频",
|
||||||
|
"audio": "音频",
|
||||||
|
"file": "文件"
|
||||||
|
},
|
||||||
|
"uploadState": {
|
||||||
|
"success": "上传成功",
|
||||||
|
"failed": "上传失败",
|
||||||
|
"uploading": "上传中"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
declare const _default: (import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "system", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "passport", import("..").BRC<import("../oak-app-domain").EntityDict>>)[];
|
declare const _default: (import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "system", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "passport", import("..").BRC<import("../oak-app-domain").EntityDict>>)[];
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ async function sendNotification(notification, context) {
|
||||||
await instance.sendSubscribedMessage({
|
await instance.sendSubscribedMessage({
|
||||||
templateId: templateId,
|
templateId: templateId,
|
||||||
data: data,
|
data: data,
|
||||||
openId: data1.openId,
|
openId: data1.openId, // 在notification创建时就赋值了
|
||||||
page,
|
page,
|
||||||
state: StateDict[process.env.NODE_ENV],
|
state: StateDict[process.env.NODE_ENV],
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ export default OakComponent({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
tocWidth: 228,
|
|
||||||
tocClosed: false,
|
tocClosed: false,
|
||||||
tocFixed: true,
|
tocFixed: true,
|
||||||
tocPosition: 'none' as 'none' | 'left' | 'right',
|
tocPosition: 'none' as 'none' | 'left' | 'right',
|
||||||
|
|
@ -28,6 +27,8 @@ export default OakComponent({
|
||||||
headerTop: 0, //页面中吸顶部分高度
|
headerTop: 0, //页面中吸顶部分高度
|
||||||
className: '',
|
className: '',
|
||||||
scrollId: '', // 滚动条所在容器id,不传默认body
|
scrollId: '', // 滚动条所在容器id,不传默认body
|
||||||
|
tocWidth: undefined as number | 'auto' | undefined,
|
||||||
|
tocHeight: undefined as number | 'auto' | undefined,
|
||||||
},
|
},
|
||||||
lifetimes: {
|
lifetimes: {
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,12 @@
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contentContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex: 1;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -14,7 +20,7 @@
|
||||||
max-width: 794px;
|
max-width: 794px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: var(--oak-bg-color-container);
|
background: #fff;
|
||||||
padding: 20px 50px 50px 50px;
|
padding: 20px 50px 50px 50px;
|
||||||
box-shadow: 0 2px 10px rgb(0 0 0 / 12%);
|
box-shadow: 0 2px 10px rgb(0 0 0 / 12%);
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ import { WebComponentProps } from 'oak-frontend-base';
|
||||||
|
|
||||||
import { EntityDict } from '../../../oak-app-domain';
|
import { EntityDict } from '../../../oak-app-domain';
|
||||||
import { TocItem, TocView } from '../toc/tocView';
|
import { TocItem, TocView } from '../toc/tocView';
|
||||||
import Style from './web.module.less';
|
import Styles from './web.module.less';
|
||||||
|
|
||||||
export default function Render(
|
export default function Render(
|
||||||
props: WebComponentProps<
|
props: WebComponentProps<
|
||||||
|
|
@ -16,7 +16,7 @@ export default function Render(
|
||||||
'article',
|
'article',
|
||||||
false,
|
false,
|
||||||
{
|
{
|
||||||
title?: string;
|
name?: string;
|
||||||
content?: string;
|
content?: string;
|
||||||
tocPosition: 'none' | 'left' | 'right';
|
tocPosition: 'none' | 'left' | 'right';
|
||||||
highlightBgColor: string;
|
highlightBgColor: string;
|
||||||
|
|
@ -24,13 +24,14 @@ export default function Render(
|
||||||
className?: string;
|
className?: string;
|
||||||
tocFixed: boolean;
|
tocFixed: boolean;
|
||||||
tocClosed: boolean;
|
tocClosed: boolean;
|
||||||
tocWidth: 228,
|
|
||||||
scrollId?: string;
|
scrollId?: string;
|
||||||
|
tocWidth?: number | 'auto';
|
||||||
|
tocHeight?: number | 'auto';
|
||||||
},
|
},
|
||||||
{}
|
{}
|
||||||
>
|
>
|
||||||
) {
|
) {
|
||||||
const { className, content, tocPosition = 'none', tocFixed, highlightBgColor = 'none', headerTop = 0, tocClosed= false, tocWidth = 228, scrollId } = props.data;
|
const { className, name, content, tocPosition = 'none', tocFixed, highlightBgColor = 'none', headerTop = 0, tocClosed= false, scrollId, tocWidth, tocHeight } = props.data;
|
||||||
const editorConfig: Partial<IEditorConfig> = {
|
const editorConfig: Partial<IEditorConfig> = {
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
|
|
@ -63,28 +64,33 @@ export default function Render(
|
||||||
}
|
}
|
||||||
}, [tocPosition])
|
}, [tocPosition])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (name) {
|
||||||
|
window.document.title = name;
|
||||||
|
}
|
||||||
|
}, [name]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(Style.container, className)}>
|
<div className={classNames(Styles.container, className)}>
|
||||||
<Row gutter={[16, 0]}>
|
<div className={Styles.contentContainer}>
|
||||||
{tocPosition === 'left' ? (
|
{tocPosition === "left" ? (
|
||||||
<Col flex={`${tocWidth}px`}>
|
|
||||||
<TocView
|
<TocView
|
||||||
toc={toc}
|
toc={toc}
|
||||||
showToc={showToc}
|
showToc={showToc}
|
||||||
tocPosition='left'
|
tocPosition="left"
|
||||||
setShowToc={setShowToc}
|
setShowToc={setShowToc}
|
||||||
highlightBgColor={highlightBgColor}
|
highlightBgColor={highlightBgColor}
|
||||||
headerTop={headerTop}
|
headerTop={headerTop}
|
||||||
fixed={tocFixed}
|
fixed={tocFixed}
|
||||||
closed={tocClosed}
|
closed={tocClosed}
|
||||||
scrollId={scrollId}
|
scrollId={scrollId}
|
||||||
|
tocWidth={tocWidth}
|
||||||
|
tocHeight={tocHeight}
|
||||||
/>
|
/>
|
||||||
</Col>
|
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<Col flex="auto">
|
<div className={Styles.content}>
|
||||||
<div className={Style.content}>
|
<div className={Styles.editorContainer}>
|
||||||
<div className={Style.editorContainer}>
|
|
||||||
<div style={{ width: "100%" }}>
|
<div style={{ width: "100%" }}>
|
||||||
<Editor
|
<Editor
|
||||||
defaultConfig={editorConfig}
|
defaultConfig={editorConfig}
|
||||||
|
|
@ -96,39 +102,44 @@ export default function Render(
|
||||||
onCreated={setEditor}
|
onCreated={setEditor}
|
||||||
onChange={(editor) => {
|
onChange={(editor) => {
|
||||||
setHtml(editor.getHtml());
|
setHtml(editor.getHtml());
|
||||||
const headers = editor.getElemsByTypePrefix('header');
|
const headers =
|
||||||
const tocItems = headers.map((header: any) => {
|
editor.getElemsByTypePrefix("header");
|
||||||
const text = SlateNode.string(header)
|
const tocItems = headers.map(
|
||||||
const { id, type } = header
|
(header: any) => {
|
||||||
|
const text =
|
||||||
|
SlateNode.string(header);
|
||||||
|
const { id, type } = header;
|
||||||
return {
|
return {
|
||||||
text,
|
text,
|
||||||
level: parseInt(type.substring(6)),
|
level: parseInt(
|
||||||
|
type.substring(6)
|
||||||
|
),
|
||||||
id,
|
id,
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
setToc([...tocItems]);
|
setToc([...tocItems]);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
{tocPosition === "right" ? (
|
||||||
{tocPosition === 'right' ? (
|
|
||||||
<Col flex={`${tocWidth}px`}>
|
|
||||||
<TocView
|
<TocView
|
||||||
toc={toc}
|
toc={toc}
|
||||||
showToc={showToc}
|
showToc={showToc}
|
||||||
tocPosition='right'
|
tocPosition="right"
|
||||||
setShowToc={setShowToc}
|
setShowToc={setShowToc}
|
||||||
highlightBgColor={highlightBgColor}
|
highlightBgColor={highlightBgColor}
|
||||||
headerTop={headerTop}
|
headerTop={headerTop}
|
||||||
fixed={tocFixed}
|
fixed={tocFixed}
|
||||||
closed={tocClosed}
|
closed={tocClosed}
|
||||||
scrollId={scrollId}
|
scrollId={scrollId}
|
||||||
|
tocWidth={tocWidth}
|
||||||
|
tocHeight={tocHeight}
|
||||||
/>
|
/>
|
||||||
</Col>
|
|
||||||
) : null}
|
) : null}
|
||||||
</Row>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,6 @@ export default OakComponent({
|
||||||
data: {
|
data: {
|
||||||
content: '',
|
content: '',
|
||||||
title: '',
|
title: '',
|
||||||
author: '',
|
|
||||||
},
|
},
|
||||||
lifetimes: {
|
lifetimes: {
|
||||||
async attached() {
|
async attached() {
|
||||||
|
|
@ -20,7 +19,6 @@ export default OakComponent({
|
||||||
this.setState({
|
this.setState({
|
||||||
content: article?.content,
|
content: article?.content,
|
||||||
title: article?.title,
|
title: article?.title,
|
||||||
author: article?.author,
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
detached() {
|
detached() {
|
||||||
|
|
@ -35,6 +33,8 @@ export default OakComponent({
|
||||||
headerTop: 0, //页面中吸顶部分高度
|
headerTop: 0, //页面中吸顶部分高度
|
||||||
className: '',
|
className: '',
|
||||||
scrollId: '', // 滚动条所在容器id,不传默认body
|
scrollId: '', // 滚动条所在容器id,不传默认body
|
||||||
|
tocWidth: undefined as number | 'auto' | undefined,
|
||||||
|
tocHeight: undefined as number | 'auto' | undefined,
|
||||||
},
|
},
|
||||||
methods: {},
|
methods: {},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
.container {
|
.container {
|
||||||
// min-height: 100vh;
|
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contentContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex: 1;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,13 @@ export default function Render(
|
||||||
tocFixed: boolean;
|
tocFixed: boolean;
|
||||||
tocClosed: boolean;
|
tocClosed: boolean;
|
||||||
scrollId?: string;
|
scrollId?: string;
|
||||||
|
tocWidth?: number | 'auto';
|
||||||
|
tocHeight?: number | 'auto';
|
||||||
},
|
},
|
||||||
{}
|
{}
|
||||||
>
|
>
|
||||||
) {
|
) {
|
||||||
const { className, content, tocPosition = 'none', tocFixed, highlightBgColor = 'none', headerTop = 0, tocClosed= false, scrollId } = props.data;
|
const { className, content, tocPosition = 'none', tocFixed, highlightBgColor = 'none', headerTop = 0, tocClosed= false, scrollId, tocWidth, tocHeight } = props.data;
|
||||||
const editorConfig: Partial<IEditorConfig> = {
|
const editorConfig: Partial<IEditorConfig> = {
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
|
|
@ -60,24 +62,23 @@ export default function Render(
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(Styles.container, className)}>
|
<div className={classNames(Styles.container, className)}>
|
||||||
<Row gutter={[16, 0]}>
|
<div className={Styles.contentContainer}>
|
||||||
{tocPosition === 'left' && (
|
{tocPosition === "left" && (
|
||||||
<Col flex="228px">
|
|
||||||
<TocView
|
<TocView
|
||||||
toc={toc}
|
toc={toc}
|
||||||
showToc={showToc}
|
showToc={showToc}
|
||||||
tocPosition='left'
|
tocPosition="left"
|
||||||
setShowToc={setShowToc}
|
setShowToc={setShowToc}
|
||||||
highlightBgColor={highlightBgColor}
|
highlightBgColor={highlightBgColor}
|
||||||
headerTop={headerTop}
|
headerTop={headerTop}
|
||||||
fixed={tocFixed}
|
fixed={tocFixed}
|
||||||
closed={tocClosed}
|
closed={tocClosed}
|
||||||
scrollId={scrollId}
|
scrollId={scrollId}
|
||||||
|
tocWidth={tocWidth}
|
||||||
|
tocHeight={tocHeight}
|
||||||
/>
|
/>
|
||||||
</Col>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Col flex="auto">
|
|
||||||
<div className={Styles.content}>
|
<div className={Styles.content}>
|
||||||
<div className={Styles.editorContainer}>
|
<div className={Styles.editorContainer}>
|
||||||
<div style={{ width: "100%" }}>
|
<div style={{ width: "100%" }}>
|
||||||
|
|
@ -86,44 +87,49 @@ export default function Render(
|
||||||
value={html}
|
value={html}
|
||||||
mode="default"
|
mode="default"
|
||||||
style={{
|
style={{
|
||||||
width: '100%'
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
onCreated={setEditor}
|
onCreated={setEditor}
|
||||||
onChange={(editor) => {
|
onChange={(editor) => {
|
||||||
setHtml(editor.getHtml());
|
setHtml(editor.getHtml());
|
||||||
const headers = editor.getElemsByTypePrefix('header');
|
const headers =
|
||||||
const tocItems = headers.map((header: any) => {
|
editor.getElemsByTypePrefix("header");
|
||||||
const text = SlateNode.string(header)
|
const tocItems = headers.map(
|
||||||
const { id, type } = header
|
(header: any) => {
|
||||||
|
const text =
|
||||||
|
SlateNode.string(header);
|
||||||
|
const { id, type } = header;
|
||||||
return {
|
return {
|
||||||
text,
|
text,
|
||||||
level: parseInt(type.substring(6)),
|
level: parseInt(
|
||||||
|
type.substring(6)
|
||||||
|
),
|
||||||
id,
|
id,
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
setToc([...tocItems]);
|
setToc([...tocItems]);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
{tocPosition === "right" && (
|
||||||
{tocPosition === 'right' && (
|
|
||||||
<Col flex="228px">
|
|
||||||
<TocView
|
<TocView
|
||||||
toc={toc}
|
toc={toc}
|
||||||
showToc={showToc}
|
showToc={showToc}
|
||||||
tocPosition='right'
|
tocPosition="right"
|
||||||
setShowToc={setShowToc}
|
setShowToc={setShowToc}
|
||||||
highlightBgColor={highlightBgColor}
|
highlightBgColor={highlightBgColor}
|
||||||
headerTop={headerTop}
|
headerTop={headerTop}
|
||||||
fixed={tocFixed}
|
fixed={tocFixed}
|
||||||
closed={tocClosed}
|
closed={tocClosed}
|
||||||
scrollId={scrollId}
|
scrollId={scrollId}
|
||||||
|
tocWidth={tocWidth}
|
||||||
|
tocHeight={tocHeight}
|
||||||
/>
|
/>
|
||||||
</Col>
|
|
||||||
)}
|
)}
|
||||||
</Row>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,11 @@ export function TocView(
|
||||||
fixed?: boolean;
|
fixed?: boolean;
|
||||||
scrollId?: string;
|
scrollId?: string;
|
||||||
closed?: boolean,
|
closed?: boolean,
|
||||||
tocWidth?: number,
|
tocWidth?: number | 'auto',
|
||||||
|
tocHeight?: number | 'auto'
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const { toc, showToc, tocPosition, setShowToc, highlightBgColor, headerTop = 0, scrollId, fixed = false, closed = false, tocWidth = 228 } = props;
|
const { toc, showToc, tocPosition, setShowToc, highlightBgColor, headerTop = 0, scrollId, fixed = false, closed = false, tocWidth, tocHeight } = props;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.documentElement.style.setProperty('--highlight-bg-color', highlightBgColor);
|
document.documentElement.style.setProperty('--highlight-bg-color', highlightBgColor);
|
||||||
|
|
@ -118,9 +119,12 @@ export function TocView(
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(Style.tocContainer, {
|
<div
|
||||||
|
className={classNames(Style.tocContainer, {
|
||||||
[Style.fixed]: fixed
|
[Style.fixed]: fixed
|
||||||
})}>
|
})}
|
||||||
|
style={Object.assign({}, tocWidth ? { width: tocWidth } : {}, tocHeight ? { height: tocHeight } : {})}
|
||||||
|
>
|
||||||
{showToc ? (
|
{showToc ? (
|
||||||
<>
|
<>
|
||||||
<div className={Style.catalogTitle}>
|
<div className={Style.catalogTitle}>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 60px;
|
height: 50px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,10 +157,10 @@ export default function Render(props: WebComponentProps<EntityDict, 'articleMenu
|
||||||
icon={<EditOutlined />}
|
icon={<EditOutlined />}
|
||||||
size="small"
|
size="small"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
setName(ele.name);
|
||||||
setNameEditing(ele.id);
|
setNameEditing(ele.id);
|
||||||
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
style={{ marginRight: 4 }}
|
|
||||||
/>
|
/>
|
||||||
<div className={Styles.name}>
|
<div className={Styles.name}>
|
||||||
<div style={{ marginLeft: 4, overflow: 'hidden', width: '150px', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{ele?.name}</div>
|
<div style={{ marginLeft: 4, overflow: 'hidden', width: '150px', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{ele?.name}</div>
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ export default OakComponent({
|
||||||
onArticlePreview: (content?: string, title?: string) => undefined as void, //预览文章
|
onArticlePreview: (content?: string, title?: string) => undefined as void, //预览文章
|
||||||
origin: 'qiniu', // 默认为七牛云
|
origin: 'qiniu', // 默认为七牛云
|
||||||
scrollId: '', // 滚动条所在容器id,不传默认页面编辑器容器id
|
scrollId: '', // 滚动条所在容器id,不传默认页面编辑器容器id
|
||||||
|
height: 600 as number | 'auto',
|
||||||
},
|
},
|
||||||
listeners: {
|
listeners: {
|
||||||
'editor,content'(prev, next) {
|
'editor,content'(prev, next) {
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,21 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contentContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex: 1;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.editorContainer {
|
.editorContainer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 30px auto 30px auto;
|
margin: 30px auto 30px auto;
|
||||||
|
|
@ -45,10 +56,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
// position: absolute;
|
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
margin-top: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.contentNumber {
|
.contentNumber {
|
||||||
|
|
@ -60,7 +69,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.tocContainer {
|
.tocContainer {
|
||||||
padding-top: 28px;
|
// padding-top: 28px;
|
||||||
position: relative;
|
position: relative;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
@ -101,7 +110,7 @@
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #DDD;
|
||||||
padding: 6px 6px 10px 6px;
|
padding: 34px 6px 10px 6px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useState, useRef, useEffect, useMemo } from "react";
|
import React, { useState, useRef, useEffect, useMemo } from "react";
|
||||||
import { Alert, Card, Button, Row, Col, Space, Input, Modal, Tooltip, } from "antd";
|
import { Alert, Button, Row, Col, Space, Input, Modal, Tooltip, } from "antd";
|
||||||
import "@wangeditor/editor/dist/css/style.css"; // 引入 css
|
import "@wangeditor/editor/dist/css/style.css"; // 引入 css
|
||||||
import { Editor, Toolbar } from "@wangeditor/editor-for-react";
|
import { Editor, Toolbar } from "@wangeditor/editor-for-react";
|
||||||
import { IToolbarConfig, SlateNode } from "@wangeditor/editor";
|
import { IToolbarConfig, SlateNode } from "@wangeditor/editor";
|
||||||
|
|
@ -10,11 +10,10 @@ import classNames from "classnames";
|
||||||
import Prompt from "../../../components/common/prompt";
|
import Prompt from "../../../components/common/prompt";
|
||||||
import { EntityDict } from "./../../../oak-app-domain";
|
import { EntityDict } from "./../../../oak-app-domain";
|
||||||
import Style from "./web.module.less";
|
import Style from "./web.module.less";
|
||||||
|
import { TocItem, TocView } from '../toc/tocView';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CloseOutlined,
|
|
||||||
EyeOutlined,
|
EyeOutlined,
|
||||||
MenuOutlined,
|
|
||||||
CaretDownOutlined
|
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
|
|
||||||
type InsertFnType = (url: string, alt?: string, href?: string) => void;
|
type InsertFnType = (url: string, alt?: string, href?: string) => void;
|
||||||
|
|
@ -46,141 +45,6 @@ function customCheckImageFn(
|
||||||
// 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息
|
// 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息
|
||||||
}
|
}
|
||||||
|
|
||||||
type TocItem = {
|
|
||||||
text: string;
|
|
||||||
level: number;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function TocView(
|
|
||||||
props: {
|
|
||||||
toc: TocItem[];
|
|
||||||
showToc: boolean;
|
|
||||||
tocPosition: 'left' | 'right';
|
|
||||||
setShowToc: (showToc: boolean) => void;
|
|
||||||
highlightBgColor: string;
|
|
||||||
scrollId?: string
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
const { toc, showToc, tocPosition, setShowToc, highlightBgColor, scrollId } = props;
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
document.documentElement.style.setProperty('--highlight-bg-color', highlightBgColor);
|
|
||||||
}, [highlightBgColor]);
|
|
||||||
|
|
||||||
const generateTocList = (items: TocItem[], currentLevel: number = 1, parentId: string | null = null): React.ReactNode => {
|
|
||||||
//递归生成嵌套列表
|
|
||||||
const result: React.ReactNode[] = [];
|
|
||||||
let lastId: string | null = parentId;
|
|
||||||
|
|
||||||
while (items.length > 0) {
|
|
||||||
const item = items[0];
|
|
||||||
//有无子级标题,有则显示展开图标
|
|
||||||
const hasChildren = items.length > 1 && items[1].level > item.level;
|
|
||||||
|
|
||||||
if (item.level > currentLevel) {
|
|
||||||
// 递归生成子列表
|
|
||||||
const sublist = generateTocList(items, item.level, item.id);
|
|
||||||
result.push(
|
|
||||||
<li key={item.id} id={`ul-${lastId}`} >
|
|
||||||
<ul style={{ listStyleType: 'none', paddingInlineStart: '6px' }}>
|
|
||||||
{sublist}
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
} else if (item.level < currentLevel) {
|
|
||||||
// 结束当前层级
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// 添加当前层级的 <li>
|
|
||||||
result.push(
|
|
||||||
<li className={Style.listItem} key={item.id} id={`li-${item.id}`} style={{ paddingLeft: `${(item.level - 1) * 6}px`, }}>
|
|
||||||
<CaretDownOutlined id={`icon-${item.id}`} className={Style.icon} style={{ visibility: hasChildren && item.level < 5 ? 'visible' : 'hidden', color: '#A5A5A5' }}
|
|
||||||
onClick={() => {
|
|
||||||
const iconElem = document.getElementById(`icon-${item.id}`);
|
|
||||||
const ulElem = document.getElementById(`ul-${item.id}`);
|
|
||||||
const isFolded = iconElem?.className.includes('iconFold') || ulElem?.className.includes('fold');
|
|
||||||
if (isFolded) {
|
|
||||||
iconElem?.classList.remove(Style.iconFold);
|
|
||||||
ulElem?.classList.remove(Style.fold);
|
|
||||||
} else {
|
|
||||||
iconElem?.classList.add(Style.iconFold);
|
|
||||||
ulElem?.classList.add(Style.fold);
|
|
||||||
}
|
|
||||||
}} />
|
|
||||||
<div
|
|
||||||
style={{ fontSize: '1em', fontWeight: item.level === 1 ? 'bold' : 'normal' }}
|
|
||||||
className={Style.tocItem}
|
|
||||||
onClick={(event: any) => {
|
|
||||||
// editor.scrollToElem(item.id);
|
|
||||||
//编辑器滚动到对应元素
|
|
||||||
const elem = document.getElementById(item.id);
|
|
||||||
const elemTop = elem?.getBoundingClientRect().top;
|
|
||||||
const scrollContainer = document.getElementById(scrollId || 'article-upsert-editorContainer');
|
|
||||||
const containerTop = scrollContainer?.getBoundingClientRect().top;
|
|
||||||
|
|
||||||
scrollContainer?.scrollBy({
|
|
||||||
top: elemTop! - containerTop!,
|
|
||||||
behavior: 'smooth',
|
|
||||||
});
|
|
||||||
//添加背景色
|
|
||||||
elem?.classList.add(Style.highlight);
|
|
||||||
//移除背景色类名
|
|
||||||
setTimeout(function () {
|
|
||||||
elem?.classList.remove(Style.highlight);
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.text}
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
items.shift(); // 移除已处理的项
|
|
||||||
lastId = item.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNames(Style.tocContainer, {
|
|
||||||
// [Style.fixed]: fixed
|
|
||||||
})}>
|
|
||||||
{showToc ? (
|
|
||||||
<>
|
|
||||||
<div className={Style.catalogTitle}>
|
|
||||||
<div style={{ color: '#A5A5A5' }}>大纲</div>
|
|
||||||
<CloseOutlined style={{ color: '#A5A5A5' }} onClick={() => setShowToc(false)} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{(toc && toc.length > 0) ? (
|
|
||||||
<ul style={{ listStyleType: 'none', paddingInlineStart: '0px' }}>{generateTocList([...toc])}</ul>
|
|
||||||
) : (
|
|
||||||
<div style={{ display: 'flex', alignItems: 'center', color: '#B1B1B1', height: '200px' }}>
|
|
||||||
<div>
|
|
||||||
对文档内容应用“标题”样式,即可生成大纲
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className={classNames(Style.tocButton, { [Style.tocButtonRight]: tocPosition === 'right' })}>
|
|
||||||
<Tooltip title="显示大纲" placement={tocPosition === 'right' ? 'left' : 'right'}>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
icon={<MenuOutlined />}
|
|
||||||
onClick={() => setShowToc(true)}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Render(
|
export default function Render(
|
||||||
props: WebComponentProps<
|
props: WebComponentProps<
|
||||||
EntityDict,
|
EntityDict,
|
||||||
|
|
@ -191,14 +55,16 @@ export default function Render(
|
||||||
name: string;
|
name: string;
|
||||||
editor: any;
|
editor: any;
|
||||||
content?: string;
|
content?: string;
|
||||||
html?: string;
|
|
||||||
origin?: string;
|
origin?: string;
|
||||||
contentTip: boolean;
|
contentTip: boolean;
|
||||||
articleMenuId: string;
|
articleMenuId: string;
|
||||||
oakId: string;
|
oakId: string;
|
||||||
tocPosition: 'none' | 'left' | 'right';
|
tocPosition: 'none' | 'left' | 'right';
|
||||||
highlightBgColor: string;
|
highlightBgColor: string;
|
||||||
scrollId?: string
|
scrollId?: string;
|
||||||
|
tocWidth?: number | 'auto';
|
||||||
|
tocHeight?: number | 'auto';
|
||||||
|
height?: number | 'auto';
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
setHtml: (content: string) => void;
|
setHtml: (content: string) => void;
|
||||||
|
|
@ -225,19 +91,22 @@ export default function Render(
|
||||||
clearContentTip,
|
clearContentTip,
|
||||||
} = methods;
|
} = methods;
|
||||||
const {
|
const {
|
||||||
|
oakFullpath,
|
||||||
id,
|
id,
|
||||||
content,
|
content,
|
||||||
editor,
|
editor,
|
||||||
origin = 'qiniu',
|
origin = 'qiniu',
|
||||||
oakFullpath,
|
|
||||||
html,
|
|
||||||
tocPosition = 'none',
|
tocPosition = 'none',
|
||||||
highlightBgColor = 'none',
|
highlightBgColor = 'none',
|
||||||
scrollId
|
scrollId,
|
||||||
|
tocWidth,
|
||||||
|
tocHeight,
|
||||||
|
height = 600
|
||||||
} = data;
|
} = data;
|
||||||
const [articleId, setArticleId] = useState('');
|
const [articleId, setArticleId] = useState('');
|
||||||
const [toc, setToc] = useState<TocItem[]>([]);
|
const [toc, setToc] = useState<TocItem[]>([]);
|
||||||
const [showToc, setShowToc] = useState(false);
|
const [showToc, setShowToc] = useState(false);
|
||||||
|
const containerId = scrollId || 'article-upsert-editorContainer';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (id) {
|
if (id) {
|
||||||
|
|
@ -253,37 +122,42 @@ export default function Render(
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={Style.container}>
|
<div className={Style.container}>
|
||||||
<Prompt when={!id || data.oakDirty} message={'您确认离开页面吗?'} />
|
<Prompt
|
||||||
<div style={{ width: 'calc(100% - 16px)', }}>
|
when={!id || data.oakDirty}
|
||||||
|
message={"您确认离开页面吗?"}
|
||||||
|
/>
|
||||||
|
<div style={{ width: "calc(100% - 16px)" }}>
|
||||||
<Toolbar
|
<Toolbar
|
||||||
editor={editor}
|
editor={editor}
|
||||||
defaultConfig={toolbarConfig}
|
defaultConfig={toolbarConfig}
|
||||||
mode="default"
|
mode="default"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Row gutter={[16, 0]}>
|
<div className={Style.contentContainer}>
|
||||||
{tocPosition === 'left' ? (
|
{tocPosition === "left" ? (
|
||||||
<Col flex="228px">
|
|
||||||
<TocView
|
<TocView
|
||||||
toc={toc}
|
toc={toc}
|
||||||
showToc={showToc}
|
showToc={showToc}
|
||||||
tocPosition='left'
|
tocPosition="left"
|
||||||
setShowToc={setShowToc}
|
setShowToc={setShowToc}
|
||||||
highlightBgColor={highlightBgColor}
|
highlightBgColor={highlightBgColor}
|
||||||
scrollId={scrollId}
|
scrollId={containerId}
|
||||||
|
tocWidth={tocWidth}
|
||||||
|
tocHeight={tocHeight || height}
|
||||||
/>
|
/>
|
||||||
</Col>
|
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<Col flex="auto">
|
<div className={Style.content} style={{ maxWidth: `calc(100% - ${tocWidth || 228}px)` }}>
|
||||||
<div className={Style.content}>
|
<div
|
||||||
<div id="article-upsert-editorContainer" className={classNames(Style.editorContainer, {
|
id={containerId}
|
||||||
[Style.editorExternalContainer]: !!scrollId
|
className={classNames(Style.editorContainer, {
|
||||||
})}>
|
[Style.editorExternalContainer]: !!scrollId,
|
||||||
|
})}
|
||||||
|
>
|
||||||
{data.contentTip && (
|
{data.contentTip && (
|
||||||
<Alert
|
<Alert
|
||||||
type="info"
|
type="info"
|
||||||
message={t('tips.content')}
|
message={t("tips.content")}
|
||||||
closable
|
closable
|
||||||
onClose={() => clearContentTip()}
|
onClose={() => clearContentTip()}
|
||||||
/>
|
/>
|
||||||
|
|
@ -294,10 +168,10 @@ export default function Render(
|
||||||
update({ name: e.target.value })
|
update({ name: e.target.value })
|
||||||
}
|
}
|
||||||
value={data.name}
|
value={data.name}
|
||||||
placeholder={'请输入文章标题'}
|
placeholder={"请输入文章标题"}
|
||||||
size="large"
|
size="large"
|
||||||
maxLength={32}
|
maxLength={32}
|
||||||
suffix={`${[...(data.name || '')].length}/32`}
|
suffix={`${(data.name || "").length}/32`}
|
||||||
className={Style.titleInput}
|
className={Style.titleInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -305,7 +179,7 @@ export default function Render(
|
||||||
<Editor
|
<Editor
|
||||||
defaultConfig={{
|
defaultConfig={{
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
placeholder: '请输入文章内容...',
|
placeholder: "请输入文章内容...",
|
||||||
MENU_CONF: {
|
MENU_CONF: {
|
||||||
checkImage: customCheckImageFn,
|
checkImage: customCheckImageFn,
|
||||||
uploadImage: {
|
uploadImage: {
|
||||||
|
|
@ -316,29 +190,49 @@ export default function Render(
|
||||||
) {
|
) {
|
||||||
// TS 语法
|
// TS 语法
|
||||||
// file 即选中的文件
|
// file 即选中的文件
|
||||||
const { name, size, type } = file;
|
const { name, size, type } =
|
||||||
const extension = name.substring(name.lastIndexOf('.') + 1);
|
file;
|
||||||
const filename = name.substring(0,name.lastIndexOf('.'));
|
const extension =
|
||||||
|
name.substring(
|
||||||
|
name.lastIndexOf(
|
||||||
|
"."
|
||||||
|
) + 1
|
||||||
|
);
|
||||||
|
const filename =
|
||||||
|
name.substring(
|
||||||
|
0,
|
||||||
|
name.lastIndexOf(
|
||||||
|
"."
|
||||||
|
)
|
||||||
|
);
|
||||||
const extraFile = {
|
const extraFile = {
|
||||||
entity: 'article',
|
entity: "article",
|
||||||
entityId: articleId,
|
entityId: articleId,
|
||||||
origin: origin,
|
origin: origin,
|
||||||
type: 'image',
|
type: "image",
|
||||||
tag1: 'source',
|
tag1: "source",
|
||||||
objectId: generateNewId(),
|
objectId:
|
||||||
|
generateNewId(),
|
||||||
filename,
|
filename,
|
||||||
size,
|
size,
|
||||||
extension,
|
extension,
|
||||||
bucket: '',
|
bucket: "",
|
||||||
id: generateNewId(),
|
id: generateNewId(),
|
||||||
fileType: type
|
fileType: type,
|
||||||
} as EntityDict['extraFile']['CreateSingle']['data'];
|
} as EntityDict["extraFile"]["CreateSingle"]["data"];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 自己实现上传,并得到图片 url alt href
|
// 自己实现上传,并得到图片 url alt href
|
||||||
const url = await uploadFile(extraFile, file);
|
const url =
|
||||||
|
await uploadFile(
|
||||||
|
extraFile,
|
||||||
|
file
|
||||||
|
);
|
||||||
// 最后插入图片
|
// 最后插入图片
|
||||||
insertFn( url, extraFile.filename);
|
insertFn(
|
||||||
|
url,
|
||||||
|
extraFile.filename
|
||||||
|
);
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -350,29 +244,50 @@ export default function Render(
|
||||||
) {
|
) {
|
||||||
// TS 语法
|
// TS 语法
|
||||||
// file 即选中的文件
|
// file 即选中的文件
|
||||||
const { name, size, type } = file;
|
const { name, size, type } =
|
||||||
const extension = name.substring(name.lastIndexOf('.') + 1);
|
file;
|
||||||
const filename = name.substring(0,name.lastIndexOf('.'));
|
const extension =
|
||||||
|
name.substring(
|
||||||
|
name.lastIndexOf(
|
||||||
|
"."
|
||||||
|
) + 1
|
||||||
|
);
|
||||||
|
const filename =
|
||||||
|
name.substring(
|
||||||
|
0,
|
||||||
|
name.lastIndexOf(
|
||||||
|
"."
|
||||||
|
)
|
||||||
|
);
|
||||||
const extraFile = {
|
const extraFile = {
|
||||||
entity: 'article',
|
entity: "article",
|
||||||
entityId: articleId,
|
entityId: articleId,
|
||||||
origin: origin,
|
origin: origin,
|
||||||
type: 'video',
|
type: "video",
|
||||||
tag1: 'source',
|
tag1: "source",
|
||||||
objectId: generateNewId(),
|
objectId:
|
||||||
|
generateNewId(),
|
||||||
filename,
|
filename,
|
||||||
size,
|
size,
|
||||||
extension,
|
extension,
|
||||||
bucket: '',
|
bucket: "",
|
||||||
id: generateNewId(),
|
id: generateNewId(),
|
||||||
fileType: type
|
fileType: type,
|
||||||
} as EntityDict['extraFile']['CreateSingle']['data'];
|
} as EntityDict["extraFile"]["CreateSingle"]["data"];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 自己实现上传,并得到图片 url alt href
|
// 自己实现上传,并得到图片 url alt href
|
||||||
const url = await uploadFile(extraFile,file);
|
const url =
|
||||||
|
await uploadFile(
|
||||||
|
extraFile,
|
||||||
|
file
|
||||||
|
);
|
||||||
// 最后插入图片
|
// 最后插入图片
|
||||||
insertFn(url, url + '?vframe/jpg/offset/0');
|
insertFn(
|
||||||
|
url,
|
||||||
|
url +
|
||||||
|
"?vframe/jpg/offset/0"
|
||||||
|
);
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -381,16 +296,20 @@ export default function Render(
|
||||||
onCreated={setEditor}
|
onCreated={setEditor}
|
||||||
onChange={(editor) => {
|
onChange={(editor) => {
|
||||||
setHtml(editor.getHtml());
|
setHtml(editor.getHtml());
|
||||||
const headers = editor.getElemsByTypePrefix('header');
|
const headers = editor.getElemsByTypePrefix("header");
|
||||||
const tocItems = headers.map((header: any) => {
|
const tocItems = headers.map(
|
||||||
const text = SlateNode.string(header)
|
(header: any) => {
|
||||||
const { id, type } = header
|
const text = SlateNode.string(header);
|
||||||
|
const { id, type } = header;
|
||||||
return {
|
return {
|
||||||
text,
|
text,
|
||||||
level: parseInt(type.substring(6)),
|
level: parseInt(
|
||||||
|
type.substring(6)
|
||||||
|
),
|
||||||
id,
|
id,
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
setToc([...tocItems]);
|
setToc([...tocItems]);
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -399,11 +318,8 @@ export default function Render(
|
||||||
mode="default"
|
mode="default"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className={Style.footer}>
|
<div className={Style.footer}>
|
||||||
<Row align="middle">
|
|
||||||
<Col flex="none">
|
|
||||||
<Space>
|
<Space>
|
||||||
<Button
|
<Button
|
||||||
disabled={
|
disabled={
|
||||||
|
|
@ -419,34 +335,28 @@ export default function Render(
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
gotoPreview(
|
gotoPreview(content, data.name);
|
||||||
content,
|
|
||||||
data.name
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
|
icon={<EyeOutlined />}
|
||||||
>
|
>
|
||||||
<EyeOutlined />
|
|
||||||
预览
|
预览
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
{tocPosition === "right" ? (
|
||||||
{tocPosition === 'right' ? (
|
|
||||||
<Col flex="228px">
|
|
||||||
<TocView
|
<TocView
|
||||||
toc={toc}
|
toc={toc}
|
||||||
showToc={showToc}
|
showToc={showToc}
|
||||||
tocPosition='right'
|
tocPosition="right"
|
||||||
setShowToc={setShowToc}
|
setShowToc={setShowToc}
|
||||||
highlightBgColor={highlightBgColor}
|
highlightBgColor={highlightBgColor}
|
||||||
scrollId={scrollId}
|
scrollId={containerId}
|
||||||
|
tocWidth={tocWidth}
|
||||||
|
tocHeight={tocHeight}
|
||||||
/>
|
/>
|
||||||
</Col>
|
|
||||||
) : null}
|
) : null}
|
||||||
</Row>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 60px;
|
height: 50px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
.ne {
|
.ne {
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
margin-left: 20px;
|
margin-left: 10px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
|
|
@ -43,6 +43,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sub {
|
.sub {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
background: rgba(0, 0, 0, 0.02);
|
background: rgba(0, 0, 0, 0.02);
|
||||||
padding-left: 18px;
|
padding-left: 18px;
|
||||||
}
|
}
|
||||||
|
|
@ -78,7 +80,6 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
// padding: 10px;
|
|
||||||
|
|
||||||
.ph {
|
.ph {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,6 @@ export default function Render(props: WebComponentProps<EntityDict, 'articleMenu
|
||||||
}
|
}
|
||||||
}, [editArticleId]);
|
}, [editArticleId]);
|
||||||
const [modal, contextHolder] = Modal.useModal();
|
const [modal, contextHolder] = Modal.useModal();
|
||||||
const [name, setName] = useState('');
|
|
||||||
const [nameEditing, setNameEditing] = useState(false);
|
const [nameEditing, setNameEditing] = useState(false);
|
||||||
const [showSub, setShowSub] = useState(false);
|
const [showSub, setShowSub] = useState(false);
|
||||||
const [newBreadcrumbItems, setNewBreadcrumbItems] = useState([] as string[]);
|
const [newBreadcrumbItems, setNewBreadcrumbItems] = useState([] as string[]);
|
||||||
|
|
@ -145,9 +144,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'articleMenu
|
||||||
if (!row.parentId && articleMenuId) {
|
if (!row.parentId && articleMenuId) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
|
||||||
{Sub}
|
{Sub}
|
||||||
</div>
|
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
@ -294,30 +291,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'articleMenu
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={Styles.container}>
|
<div className={Styles.container}>
|
||||||
<div
|
<div className={Styles.ne}>
|
||||||
className={Styles.ne}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
// nameEditing ? <div className={Styles.name}>
|
|
||||||
// <Input
|
|
||||||
// autoFocus
|
|
||||||
// value={ name || row?.name}
|
|
||||||
// onChange={(evt) => setName(evt.target.value)}
|
|
||||||
// onPressEnter={async () => {
|
|
||||||
// if (name && name !== row?.name) {
|
|
||||||
// await onUpdateName(name);
|
|
||||||
// }
|
|
||||||
// setNameEditing(false);
|
|
||||||
// }}
|
|
||||||
// onBlur={async () => {
|
|
||||||
// if (name && name !== row?.name) {
|
|
||||||
// await onUpdateName(name);
|
|
||||||
// }
|
|
||||||
// setNameEditing(false);
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// </div> :
|
|
||||||
<>
|
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
icon={<EditOutlined />}
|
icon={<EditOutlined />}
|
||||||
|
|
@ -325,25 +299,30 @@ export default function Render(props: WebComponentProps<EntityDict, 'articleMenu
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setNameEditing(true);
|
setNameEditing(true);
|
||||||
const modalInstance = modal.confirm({
|
const modalInstance = modal.confirm({
|
||||||
title: '编辑分类',
|
title: "编辑分类",
|
||||||
cancelText: '取消',
|
cancelText: "取消",
|
||||||
okText: '提交',
|
okText: "提交",
|
||||||
content: (
|
content: (
|
||||||
<div>
|
<div>
|
||||||
<Form.Item
|
<Form.Item label="分类名称">
|
||||||
label="分类名称"
|
|
||||||
>
|
|
||||||
<Input
|
<Input
|
||||||
ref={menuNameRef}
|
ref={menuNameRef}
|
||||||
defaultValue={row.name}
|
defaultValue={row.name}
|
||||||
onChange={(val) => update({ name: val.target.value })}
|
onChange={(val) =>
|
||||||
|
update({
|
||||||
|
name: val.target
|
||||||
|
.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="LOGO"
|
label="LOGO"
|
||||||
help={
|
help={
|
||||||
<div>
|
<div>
|
||||||
<span>请上传LOGO高清图片,</span>
|
<span>
|
||||||
|
请上传LOGO高清图片,
|
||||||
|
</span>
|
||||||
<span>
|
<span>
|
||||||
108*108像素,仅支持PNG、JPG格式,大小不超过300KB。
|
108*108像素,仅支持PNG、JPG格式,大小不超过300KB。
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -374,28 +353,36 @@ export default function Render(props: WebComponentProps<EntityDict, 'articleMenu
|
||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
footer: <Space>
|
footer: (
|
||||||
|
<Space>
|
||||||
<ExtraFileCommit
|
<ExtraFileCommit
|
||||||
entity={oakEntity}
|
entity={oakEntity}
|
||||||
oakPath={oakFullpath}
|
oakPath={oakFullpath}
|
||||||
afterCommit={() => {
|
afterCommit={() => {
|
||||||
modalInstance!.destroy()
|
modalInstance!.destroy();
|
||||||
}}
|
}}
|
||||||
beforeCommit={() => {
|
beforeCommit={() => {
|
||||||
if (menuNameRef.current!.input!.value) {
|
if (
|
||||||
return true
|
menuNameRef.current!
|
||||||
|
.input!.value
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button onClick={() => modalInstance!.destroy()}>
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
modalInstance!.destroy()
|
||||||
|
}
|
||||||
|
>
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
style={{ marginRight: 4 }}
|
|
||||||
/>
|
/>
|
||||||
<div className={Styles.name}>
|
<div className={Styles.name}>
|
||||||
{logo ? (
|
{logo ? (
|
||||||
|
|
@ -406,26 +393,44 @@ export default function Render(props: WebComponentProps<EntityDict, 'articleMenu
|
||||||
preview={false}
|
preview={false}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<div style={{ marginLeft: 4, overflow: 'hidden', width: '100px', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{row?.name}</div>
|
<div
|
||||||
|
style={{
|
||||||
|
marginLeft: 4,
|
||||||
|
overflow: "hidden",
|
||||||
|
width: "100px",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{row?.name}
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
<Divider type="vertical" style={{ height: '100%', marginTop: 4, marginBottom: 4 }} />
|
</div>
|
||||||
|
<Divider
|
||||||
|
type="vertical"
|
||||||
|
style={{
|
||||||
|
height: "100%",
|
||||||
|
marginTop: 4,
|
||||||
|
marginBottom: 4,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<div className={Styles.control}>
|
<div className={Styles.control}>
|
||||||
{
|
{!row.parentId && (
|
||||||
!row.parentId && <Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
|
size="small"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
gotoDoc(row?.id);
|
gotoDoc(row?.id);
|
||||||
}}
|
}}
|
||||||
icon={<EyeOutlined />}
|
icon={<EyeOutlined />}
|
||||||
|
></Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Dropdown
|
||||||
|
menu={{ items }}
|
||||||
|
placement="bottomRight"
|
||||||
|
arrow
|
||||||
>
|
>
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
<Dropdown menu={{ items }} placement="bottomRight" arrow>
|
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
|
|
@ -439,42 +444,39 @@ export default function Render(props: WebComponentProps<EntityDict, 'articleMenu
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!allowRemove) {
|
if (!allowRemove) {
|
||||||
modal.error({
|
modal.error({
|
||||||
title: '无法删除',
|
title: "无法删除",
|
||||||
content: hasSubArticles ? '请先删除目录下的文章' : '请先删除目录下的子目录',
|
content: hasSubArticles
|
||||||
okText: '确认'
|
? "请先删除目录下的文章"
|
||||||
|
: "请先删除目录下的子目录",
|
||||||
|
okText: "确认",
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
onRemove();
|
onRemove();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{
|
{hasSubArticles || hasSubMenus ? (
|
||||||
(hasSubArticles || hasSubMenus) ? (
|
showSub ? (
|
||||||
showSub ?
|
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
icon={<UpOutlined />}
|
icon={<UpOutlined />}
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => setShowSub(false)}
|
onClick={() => setShowSub(false)}
|
||||||
/> :
|
/>
|
||||||
|
) : (
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
icon={<DownOutlined />}
|
icon={<DownOutlined />}
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => setShowSub(true)}
|
onClick={() => setShowSub(true)}
|
||||||
/>
|
/>
|
||||||
) : <div className={Styles.ph} />
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{
|
|
||||||
showSub && (
|
|
||||||
<div className={Styles.sub}>
|
|
||||||
{Sub}
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
) : (
|
||||||
|
<div className={Styles.ph} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{showSub ? Sub : null}
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,10 @@ export default OakComponent({
|
||||||
highlightBgColor: 'none', //点击文章目录时标题高亮背景色,none为不显示高亮背景色
|
highlightBgColor: 'none', //点击文章目录时标题高亮背景色,none为不显示高亮背景色
|
||||||
onMenuView: () => undefined as void, //查看全部菜单
|
onMenuView: () => undefined as void, //查看全部菜单
|
||||||
onMenuViewById: (articleMenuId: string) => undefined as void, //查看指定id菜单
|
onMenuViewById: (articleMenuId: string) => undefined as void, //查看指定id菜单
|
||||||
onArticleView: (oakId: string) => undefined as void, //查看文章
|
onArticleView: (articleId: string) => undefined as void, //查看文章
|
||||||
onArticlePreview: (content?: string, title?: string) => undefined as void, //预览文章
|
onArticlePreview: (content?: string, title?: string) => undefined as void, //预览文章
|
||||||
onArticleEdit: (oakId: string) => undefined as void, //编辑文章
|
onArticleEdit: (articleId: string) => undefined as void, //编辑文章
|
||||||
setCopyArticleUrl: (id: string) => '' as string,
|
setCopyArticleUrl: (articleId: string) => '' as string,
|
||||||
origin: 'qiniu', // cos origin默认七牛云
|
origin: 'qiniu', // cos origin默认七牛云
|
||||||
scrollId: '', // 滚动条所在容器id,不传默认页面编辑器容器id
|
scrollId: '', // 滚动条所在容器id,不传默认页面编辑器容器id
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
min-width: 320px;
|
width: 320px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|
@ -17,13 +17,14 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 320px;
|
width: 320px;
|
||||||
padding: 8px 10px;
|
padding: 0px 10px;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
top: 0;
|
top: 0;
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
height: 50px;
|
||||||
|
|
||||||
.menuTitle {
|
.menuTitle {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|
@ -129,7 +130,6 @@
|
||||||
padding: 20px 15px;
|
padding: 20px 15px;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
// max-height: 800px;
|
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import React, { useEffect, useState, useRef } from 'react';
|
import React, { useEffect, useState, useRef } from 'react';
|
||||||
import { Button, Divider, Tooltip, Space, Drawer, Tag } from 'antd';
|
import { Button, Divider, Tooltip, Space, Drawer } from 'antd';
|
||||||
import type { MenuProps } from 'antd';
|
|
||||||
import { EyeOutlined, CopyOutlined, MenuFoldOutlined, MenuUnfoldOutlined, PlusOutlined, EditOutlined, FileOutlined } from '@ant-design/icons';
|
import { EyeOutlined, CopyOutlined, MenuFoldOutlined, MenuUnfoldOutlined, PlusOutlined, EditOutlined, FileOutlined } from '@ant-design/icons';
|
||||||
import copy from 'copy-to-clipboard';
|
import copy from 'copy-to-clipboard';
|
||||||
import { WebComponentProps } from 'oak-frontend-base';
|
import { WebComponentProps } from 'oak-frontend-base';
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue