mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 13:39:24 +08:00
feat: support qrcode embed in markdown and scan in mobile (#4638)
* feat: workbench block * feat: mobilePage * fix: update WorkbenchAction * feat: support qrcode embed in markdown and scan in mobile * fix: fix markdown button be covered problem * fix: fix unit test error * fix: fix unit test errors * refactor: use react router in qrcode scanner * feat: markdown add loading * fix: fix blank content in print page * refactor: change plugin dependencies to devDependencies * feat: add some padding in markdown editor * chore: improve some code * feat: improve code * fix: add QRCodeScanner * fix: iconColor * fix: Improve code * feat: Improve code * fix: version * chore: improve some code * chore: improve some code * fix: i18n --------- Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
parent
2aa46171b2
commit
45614c8d72
@ -2,9 +2,7 @@
|
|||||||
"version": "1.2.1-alpha",
|
"version": "1.2.1-alpha",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"useWorkspaces": true,
|
"useWorkspaces": true,
|
||||||
"npmClientArgs": [
|
"npmClientArgs": ["--ignore-engines"],
|
||||||
"--ignore-engines"
|
|
||||||
],
|
|
||||||
"command": {
|
"command": {
|
||||||
"version": {
|
"version": {
|
||||||
"forcePublish": true,
|
"forcePublish": true,
|
||||||
|
@ -9,36 +9,83 @@
|
|||||||
|
|
||||||
import { observer, useField, useFieldSchema } from '@formily/react';
|
import { observer, useField, useFieldSchema } from '@formily/react';
|
||||||
import { Input as AntdInput, Button, Space, Spin, theme } from 'antd';
|
import { Input as AntdInput, Button, Space, Spin, theme } from 'antd';
|
||||||
|
import type { TextAreaRef } from 'antd/es/input/TextArea';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import React, { useState } from 'react';
|
import React, { useCallback, useEffect, useState, useRef, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useGlobalTheme } from '../../../global-theme';
|
import { useGlobalTheme } from '../../../global-theme';
|
||||||
import { useDesignable } from '../../hooks/useDesignable';
|
import { useDesignable } from '../../hooks/useDesignable';
|
||||||
import { MarkdownVoidDesigner } from './Markdown.Void.Designer';
|
import { MarkdownVoidDesigner } from './Markdown.Void.Designer';
|
||||||
import { useStyles } from './style';
|
import { useStyles } from './style';
|
||||||
import { useParseMarkdown } from './util';
|
import { parseMarkdown } from './util';
|
||||||
import { TextAreaProps } from 'antd/es/input';
|
import { TextAreaProps } from 'antd/es/input';
|
||||||
import { useBlockHeight } from '../../hooks/useBlockSize';
|
import { useBlockHeight } from '../../hooks/useBlockSize';
|
||||||
|
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
|
||||||
|
import { useCollectionRecord } from '../../../data-source';
|
||||||
|
import { useVariableOptions } from '../../../schema-settings/VariableInput/hooks/useVariableOptions';
|
||||||
|
import { VariableSelect } from '../variable/VariableSelect';
|
||||||
|
import { replaceVariableValue } from '../../../block-provider/hooks';
|
||||||
|
import { useLocalVariables, useVariables } from '../../../variables';
|
||||||
|
import { registerQrcodeWebComponent } from './qrcode-webcom';
|
||||||
export interface MarkdownEditorProps extends Omit<TextAreaProps, 'onSubmit'> {
|
export interface MarkdownEditorProps extends Omit<TextAreaProps, 'onSubmit'> {
|
||||||
|
scope: any[];
|
||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
onSubmit?: (value: string) => void;
|
onSubmit?: (value: string) => void;
|
||||||
onCancel?: (e: React.MouseEvent) => void;
|
onCancel?: (e: React.MouseEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MarkdownEditor = (props: MarkdownEditorProps) => {
|
const MarkdownEditor = (props: MarkdownEditorProps) => {
|
||||||
|
const { scope } = props;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [value, setValue] = useState(props.defaultValue);
|
const [value, setValue] = useState(props.defaultValue);
|
||||||
|
const inputRef = useRef<TextAreaRef>(null);
|
||||||
|
const [options, setOptions] = useState([]);
|
||||||
|
const [curPos, setCurPos] = useState(null);
|
||||||
|
useEffect(() => {
|
||||||
|
setOptions(scope);
|
||||||
|
}, [scope]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const inputEle = inputRef?.current?.resizableTextArea?.textArea;
|
||||||
|
if (curPos && inputEle) {
|
||||||
|
inputEle.setSelectionRange(curPos, curPos);
|
||||||
|
}
|
||||||
|
}, [curPos]);
|
||||||
|
|
||||||
|
const onInsert = useCallback(
|
||||||
|
function (paths: string[]) {
|
||||||
|
const variable: string[] = paths.filter((key) => Boolean(key.trim()));
|
||||||
|
const { current } = inputRef;
|
||||||
|
const inputEle = current?.resizableTextArea?.textArea;
|
||||||
|
if (!inputEle || !variable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
current.focus();
|
||||||
|
const templateVar = `{{${paths.join('.')}}}`;
|
||||||
|
const startPos = inputEle.selectionStart || 0;
|
||||||
|
const newVal = value.substring(0, startPos) + templateVar + value.substring(startPos, value.length);
|
||||||
|
const newPos = startPos + templateVar.length;
|
||||||
|
setValue(newVal);
|
||||||
|
setCurPos(newPos);
|
||||||
|
},
|
||||||
|
[value],
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<div className={'mb-markdown'} style={{ position: 'relative' }}>
|
<div className={'mb-markdown'} style={{ position: 'relative', paddingTop: '20px' }}>
|
||||||
<AntdInput.TextArea
|
<AntdInput.TextArea
|
||||||
|
ref={inputRef}
|
||||||
autoSize={{ minRows: 3 }}
|
autoSize={{ minRows: 3 }}
|
||||||
{...(props as any)}
|
{...(props as any)}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setValue(e.target.value);
|
setValue(e.target.value);
|
||||||
}}
|
}}
|
||||||
|
style={{ paddingBottom: '40px' }}
|
||||||
/>
|
/>
|
||||||
|
<div style={{ position: 'absolute', top: 21, right: 1 }}>
|
||||||
|
<VariableSelect options={options} setOptions={setOptions} onInsert={onInsert} />
|
||||||
|
</div>
|
||||||
|
|
||||||
<Space style={{ position: 'absolute', bottom: 5, right: 5 }}>
|
<Space style={{ position: 'absolute', bottom: 5, right: 5 }}>
|
||||||
<Button
|
<Button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
@ -69,22 +116,46 @@ const useMarkdownHeight = () => {
|
|||||||
return height - 2 * token.paddingLG;
|
return height - 2 * token.paddingLG;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MarkdownVoid: any = observer(
|
export const MarkdownVoid: any = withDynamicSchemaProps(
|
||||||
(props: any) => {
|
observer((props: any) => {
|
||||||
const { isDarkTheme } = useGlobalTheme();
|
const { isDarkTheme } = useGlobalTheme();
|
||||||
const { componentCls, hashId } = useStyles({ isDarkTheme });
|
const { componentCls, hashId } = useStyles({ isDarkTheme });
|
||||||
const { content, className } = props;
|
const { content, className } = props;
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const { onSave, onCancel } = props;
|
const { onSave, onCancel, form } = props;
|
||||||
const { html, loading } = useParseMarkdown(content);
|
const record = useCollectionRecord();
|
||||||
|
const [html, setHtml] = useState('');
|
||||||
|
const variables = useVariables();
|
||||||
|
const localVariables = useLocalVariables();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(true);
|
||||||
|
const cvtContentToHTML = async () => {
|
||||||
|
const replacedContent = await replaceVariableValue(content, variables, localVariables);
|
||||||
|
const html = await parseMarkdown(replacedContent);
|
||||||
|
setHtml(html);
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
cvtContentToHTML();
|
||||||
|
}, [content, variables, localVariables]);
|
||||||
const height = useMarkdownHeight();
|
const height = useMarkdownHeight();
|
||||||
if (loading) {
|
const scope = useVariableOptions({
|
||||||
return <Spin />;
|
collectionField: { uiSchema: schema },
|
||||||
}
|
form,
|
||||||
|
record,
|
||||||
|
uiSchema: schema,
|
||||||
|
noDisabled: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
registerQrcodeWebComponent();
|
||||||
|
}, []);
|
||||||
|
if (loading) return <Spin />;
|
||||||
return field?.editable ? (
|
return field?.editable ? (
|
||||||
<MarkdownEditor
|
<MarkdownEditor
|
||||||
|
scope={scope}
|
||||||
{...props}
|
{...props}
|
||||||
className
|
className
|
||||||
defaultValue={content}
|
defaultValue={content}
|
||||||
@ -115,7 +186,7 @@ export const MarkdownVoid: any = observer(
|
|||||||
dangerouslySetInnerHTML={{ __html: html }}
|
dangerouslySetInnerHTML={{ __html: html }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
}),
|
||||||
{ displayName: 'MarkdownVoid' },
|
{ displayName: 'MarkdownVoid' },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -11,10 +11,15 @@ import { act, fireEvent, render } from '@nocobase/test/client';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import App1 from '../demos/demo1';
|
import App1 from '../demos/demo1';
|
||||||
import App2 from '../demos/demo2';
|
import App2 from '../demos/demo2';
|
||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
|
||||||
describe('Markdown', () => {
|
describe('Markdown', () => {
|
||||||
it('should display the value of user input', () => {
|
it('should display the value of user input', function () {
|
||||||
const { container } = render(<App1 />);
|
const { container } = render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<App1 />
|
||||||
|
</MemoryRouter>,
|
||||||
|
);
|
||||||
const textarea = container.querySelector('.ant-input') as HTMLTextAreaElement;
|
const textarea = container.querySelector('.ant-input') as HTMLTextAreaElement;
|
||||||
act(() => {
|
act(() => {
|
||||||
fireEvent.change(textarea, { target: { value: '## Hello World' } });
|
fireEvent.change(textarea, { target: { value: '## Hello World' } });
|
||||||
@ -23,9 +28,13 @@ describe('Markdown', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Markdown.Void', () => {
|
describe('Markdown.Void', function () {
|
||||||
it('should display the value of user input', async () => {
|
it('should display the value of user input', async () => {
|
||||||
const { container } = render(<App2 />);
|
const { container } = render(
|
||||||
|
<MemoryRouter>
|
||||||
|
<App2 />
|
||||||
|
</MemoryRouter>,
|
||||||
|
);
|
||||||
const button = container.querySelector('.ant-btn') as HTMLButtonElement;
|
const button = container.querySelector('.ant-btn') as HTMLButtonElement;
|
||||||
|
|
||||||
expect(button).not.toBeNull();
|
expect(button).not.toBeNull();
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { QRCode, type QRCodeProps } from 'antd';
|
||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
// ReactDOM.render(
|
||||||
|
// <QRCodeCanvas value="https://reactjs.org/" />,
|
||||||
|
// document.getElementById('mountNode')
|
||||||
|
// );
|
||||||
|
|
||||||
|
class QRCodeWebComponent extends HTMLElement {
|
||||||
|
root: any;
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.attachShadow({ mode: 'open' });
|
||||||
|
this.root = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getProps(attributes, propTypes = {}) {
|
||||||
|
return [...attributes]
|
||||||
|
.filter((attr) => attr.name !== 'style')
|
||||||
|
.map((attr) => this.convert(propTypes, attr.name, attr.value))
|
||||||
|
.reduce((props, prop) => ({ ...props, [prop.name]: prop.value }), {});
|
||||||
|
}
|
||||||
|
convert(propTypes, attrName, attrValue) {
|
||||||
|
const propName = Object.keys(propTypes).find((key) => key.toLowerCase() == attrName);
|
||||||
|
let value = attrValue;
|
||||||
|
if (attrValue === 'true' || attrValue === 'false') value = attrValue == 'true';
|
||||||
|
else if (!isNaN(attrValue) && attrValue !== '') value = +attrValue;
|
||||||
|
else if (/^{.*}/.exec(attrValue)) value = JSON.parse(attrValue);
|
||||||
|
return {
|
||||||
|
name: propName ? propName : attrName,
|
||||||
|
value: value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
const props = {
|
||||||
|
...this.getProps(this.attributes),
|
||||||
|
} as QRCodeProps;
|
||||||
|
this.root = createRoot(this.shadowRoot as ShadowRoot);
|
||||||
|
this.root.render(<QRCode {...props} />);
|
||||||
|
}
|
||||||
|
disconnectedCallback() {
|
||||||
|
this.root.unmount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerQrcodeWebComponent() {
|
||||||
|
if (!customElements.get('qr-code')) {
|
||||||
|
customElements.define('qr-code', QRCodeWebComponent);
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,7 @@ export const useDetailPrintActionProps = () => {
|
|||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
:not(.ant-formily-item-control-content-component) > div.ant-formily-layout>div:first-child {
|
:not(.ant-formily-item-control-content-component) > div.ant-formily-layout div.nb-action-bar { {
|
||||||
overflow: hidden; height: 0;
|
overflow: hidden; height: 0;
|
||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
|
@ -6,5 +6,9 @@
|
|||||||
"@nocobase/client": "1.x",
|
"@nocobase/client": "1.x",
|
||||||
"@nocobase/server": "1.x",
|
"@nocobase/server": "1.x",
|
||||||
"@nocobase/test": "1.x"
|
"@nocobase/test": "1.x"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"html5-qrcode": "^2.3.8",
|
||||||
|
"react-router-dom": "^6.x"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,14 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ButtonEditor, SchemaSettings, useSchemaInitializer, useSchemaInitializerItem } from '@nocobase/client';
|
import {
|
||||||
|
ButtonEditor,
|
||||||
|
ISchema,
|
||||||
|
SchemaSettings,
|
||||||
|
useActionContext,
|
||||||
|
useSchemaInitializer,
|
||||||
|
useSchemaInitializerItem,
|
||||||
|
} from '@nocobase/client';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ModalActionSchemaInitializerItem } from './ModalActionSchemaInitializerItem';
|
import { ModalActionSchemaInitializerItem } from './ModalActionSchemaInitializerItem';
|
||||||
@ -38,11 +45,20 @@ export function WorkbenchScanActionSchemaInitializerItem(props) {
|
|||||||
// 调用插入功能
|
// 调用插入功能
|
||||||
const { insert } = useSchemaInitializer();
|
const { insert } = useSchemaInitializer();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const useCancelAction = () => {
|
||||||
|
const { setVisible } = useActionContext();
|
||||||
|
return {
|
||||||
|
run() {
|
||||||
|
setVisible(false);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalActionSchemaInitializerItem
|
<ModalActionSchemaInitializerItem
|
||||||
title={itemConfig.title}
|
title={t('Scan QR code', { ns: 'block-workbench' })}
|
||||||
modalSchema={{
|
modalSchema={{
|
||||||
title: 'Add Scan Qr code',
|
title: t('Scan QR code', { ns: 'block-workbench' }),
|
||||||
properties: {
|
properties: {
|
||||||
title: {
|
title: {
|
||||||
title: t('Title'),
|
title: t('Title'),
|
||||||
@ -66,7 +82,6 @@ export function WorkbenchScanActionSchemaInitializerItem(props) {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
onSubmit={(values) => {
|
onSubmit={(values) => {
|
||||||
console.log('values', values);
|
|
||||||
insert({
|
insert({
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: values.title,
|
title: values.title,
|
||||||
@ -76,8 +91,41 @@ export function WorkbenchScanActionSchemaInitializerItem(props) {
|
|||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
icon: values.icon,
|
icon: values.icon,
|
||||||
iconColor: values.iconColor,
|
iconColor: values.iconColor,
|
||||||
|
openMode: 'modal',
|
||||||
},
|
},
|
||||||
});
|
properties: {
|
||||||
|
modal: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Modal',
|
||||||
|
title: t('Scan QR code', { ns: 'block-workbench' }),
|
||||||
|
'x-decorator': 'FormV2',
|
||||||
|
properties: {
|
||||||
|
scanner: {
|
||||||
|
'x-component': 'QRCodeScanner',
|
||||||
|
'x-component-props': {
|
||||||
|
fps: 10,
|
||||||
|
qrbox: 250,
|
||||||
|
disableFlip: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Modal.Footer',
|
||||||
|
properties: {
|
||||||
|
close: {
|
||||||
|
title: 'Close',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'default',
|
||||||
|
useAction: useCancelAction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Html5QrcodeScanner } from 'html5-qrcode';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import React, { useEffect } from 'react';
|
||||||
|
|
||||||
|
const qrcodeRegionId = 'html5qr-code-full-region';
|
||||||
|
|
||||||
|
// Creates the configuration object for Html5QrcodeScanner.
|
||||||
|
const createConfig = (props) => {
|
||||||
|
const config: any = {};
|
||||||
|
if (props.fps) {
|
||||||
|
config.fps = props.fps;
|
||||||
|
}
|
||||||
|
if (props.qrbox) {
|
||||||
|
config.qrbox = props.qrbox;
|
||||||
|
}
|
||||||
|
if (props.aspectRatio) {
|
||||||
|
config.aspectRatio = props.aspectRatio;
|
||||||
|
}
|
||||||
|
if (props.disableFlip !== undefined) {
|
||||||
|
config.disableFlip = props.disableFlip;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const QRCodeScanner = (props) => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
useEffect(() => {
|
||||||
|
// when component mounts
|
||||||
|
const config = createConfig(props);
|
||||||
|
const verbose = props.verbose === true;
|
||||||
|
// Suceess callback is required.
|
||||||
|
const qrCodeSuccessCallback = (decodedText, decodedResult) => {
|
||||||
|
navigate(decodedText);
|
||||||
|
};
|
||||||
|
const html5QrcodeScanner = new Html5QrcodeScanner(qrcodeRegionId, config, verbose);
|
||||||
|
html5QrcodeScanner.render(qrCodeSuccessCallback, props.qrCodeErrorCallback);
|
||||||
|
|
||||||
|
// cleanup function when component will unmount
|
||||||
|
return () => {
|
||||||
|
html5QrcodeScanner.clear().catch((error) => {
|
||||||
|
console.error('Failed to clear html5QrcodeScanner. ', error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, [navigate, props]);
|
||||||
|
|
||||||
|
return <div id={qrcodeRegionId} />;
|
||||||
|
};
|
@ -10,17 +10,18 @@
|
|||||||
import { Plugin } from '@nocobase/client';
|
import { Plugin } from '@nocobase/client';
|
||||||
import { WorkbenchBlock } from './WorkbenchBlock';
|
import { WorkbenchBlock } from './WorkbenchBlock';
|
||||||
import { workbenchActionSettingsLink } from './WorkbenchLinkActionSchemaInitializerItem';
|
import { workbenchActionSettingsLink } from './WorkbenchLinkActionSchemaInitializerItem';
|
||||||
// import {
|
import {
|
||||||
// WorkbenchScanActionSchemaInitializerItem,
|
WorkbenchScanActionSchemaInitializerItem,
|
||||||
// workbenchActionSettingsScanQrCode,
|
workbenchActionSettingsScanQrCode,
|
||||||
// } from './WorkbenchScanActionSchemaInitializerItem';
|
} from './WorkbenchScanActionSchemaInitializerItem';
|
||||||
|
import { QRCodeScanner } from './components/qrcode-scanner';
|
||||||
import { workbenchBlockInitializerItem } from './workbenchBlockInitializerItem';
|
import { workbenchBlockInitializerItem } from './workbenchBlockInitializerItem';
|
||||||
import { workbenchBlockSettings } from './workbenchBlockSettings';
|
import { workbenchBlockSettings } from './workbenchBlockSettings';
|
||||||
import { workbenchConfigureActions } from './workbenchConfigureActions';
|
import { workbenchConfigureActions } from './workbenchConfigureActions';
|
||||||
|
|
||||||
export class PluginBlockWorkbenchClient extends Plugin {
|
export class PluginBlockWorkbenchClient extends Plugin {
|
||||||
async load() {
|
async load() {
|
||||||
this.app.addComponents({ WorkbenchBlock });
|
this.app.addComponents({ WorkbenchBlock, QRCodeScanner });
|
||||||
|
|
||||||
// 新增工作台区块的设置器
|
// 新增工作台区块的设置器
|
||||||
this.app.schemaSettingsManager.add(workbenchBlockSettings);
|
this.app.schemaSettingsManager.add(workbenchBlockSettings);
|
||||||
@ -46,11 +47,10 @@ export class PluginBlockWorkbenchClient extends Plugin {
|
|||||||
this.app.schemaSettingsManager.add(workbenchActionSettingsLink);
|
this.app.schemaSettingsManager.add(workbenchActionSettingsLink);
|
||||||
|
|
||||||
// 扫码操作
|
// 扫码操作
|
||||||
// this.app.schemaSettingsManager.add(workbenchActionSettingsScanQrCode);
|
this.app.schemaSettingsManager.add(workbenchActionSettingsScanQrCode);
|
||||||
// this.app.schemaInitializerManager.addItem('workbench:configureActions', `qrcode`, {
|
this.app.schemaInitializerManager.addItem('workbench:configureActions', `qrcode`, {
|
||||||
// title: 'Scan Qr code',
|
Component: WorkbenchScanActionSchemaInitializerItem,
|
||||||
// Component: WorkbenchScanActionSchemaInitializerItem,
|
});
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
{
|
{
|
||||||
"Workbench": "工作台"
|
"Workbench": "工作台",
|
||||||
|
"Scan QR code": "扫描二维码"
|
||||||
}
|
}
|
@ -19605,6 +19605,11 @@ html2sketch@^1.0.2:
|
|||||||
transformation-matrix "^2.11.1"
|
transformation-matrix "^2.11.1"
|
||||||
uuid "^8.2.0"
|
uuid "^8.2.0"
|
||||||
|
|
||||||
|
html5-qrcode@^2.3.8:
|
||||||
|
version "2.3.8"
|
||||||
|
resolved "https://registry.npmmirror.com/html5-qrcode/-/html5-qrcode-2.3.8.tgz#0b0cdf7a9926cfd4be530e13a51db47592adfa0d"
|
||||||
|
integrity sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ==
|
||||||
|
|
||||||
htmlparser2@^6.1.0:
|
htmlparser2@^6.1.0:
|
||||||
version "6.1.0"
|
version "6.1.0"
|
||||||
resolved "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
|
resolved "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
|
||||||
@ -29059,7 +29064,7 @@ react-refresh@0.14.0, react-refresh@^0.14.0:
|
|||||||
resolved "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
|
resolved "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
|
||||||
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
|
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
|
||||||
|
|
||||||
react-router-dom@6.3.0, react-router-dom@6.x, react-router-dom@^6.11.2:
|
react-router-dom@6.3.0, react-router-dom@6.x, react-router-dom@^6.11.2, react-router-dom@^6.23.1:
|
||||||
version "6.21.0"
|
version "6.21.0"
|
||||||
resolved "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-6.21.0.tgz#aa4c6bc046a8e8723095bc09b3c0ab2254532712"
|
resolved "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-6.21.0.tgz#aa4c6bc046a8e8723095bc09b3c0ab2254532712"
|
||||||
integrity sha512-1dUdVj3cwc1npzJaf23gulB562ESNvxf7E4x8upNJycqyUm5BRRZ6dd3LrlzhtLaMrwOCO8R0zoiYxdaJx4LlQ==
|
integrity sha512-1dUdVj3cwc1npzJaf23gulB562ESNvxf7E4x8upNJycqyUm5BRRZ6dd3LrlzhtLaMrwOCO8R0zoiYxdaJx4LlQ==
|
||||||
|
Loading…
x
Reference in New Issue
Block a user