diff --git a/README.md b/README.md
index 3e705de..dd84e43 100644
--- a/README.md
+++ b/README.md
@@ -471,6 +471,31 @@ render();
```
+- MarkdownPreview
+- Markdown文件预览
+- _ReactFile(@kne/current-lib_react-file)[import * as _ReactFile from "@kne/react-file"],(@kne/current-lib_react-file/dist/index.css),remoteLoader(@kne/remote-loader)
+
+```jsx
+const { MarkdownPreview } = _ReactFile;
+const { createWithRemoteLoader, getPublicPath } = remoteLoader;
+
+const BaseExample = createWithRemoteLoader({
+ modules: ['components-core:InfoPage']
+})(({ remoteModules }) => {
+ const [InfoPage] = remoteModules;
+ return (
+
+
+
+
+
+ );
+});
+
+render();
+
+```
+
### API
@@ -489,6 +514,18 @@ render();
| maxSize | number | - | 单个文件最大尺寸(字节) |
| children | ReactNode | - | 自定义上传按钮内容 |
+### MarkdownPreview
+
+Markdown文件预览组件,支持渲染Markdown格式的文档。
+
+#### 属性
+
+| 属性 | 类型 | 默认值 | 描述 |
+|------|------|-------|------|
+| url | string | - | Markdown文件的URL地址 |
+| className | string | - | 自定义容器类名 |
+| maxWidth | string/number | - | 容器最大宽度 |
+
### FilePreview
文件预览组件,支持多种文件格式的预览。
diff --git a/doc/api.md b/doc/api.md
index a0ccf72..8e8d9d9 100644
--- a/doc/api.md
+++ b/doc/api.md
@@ -13,6 +13,18 @@
| maxSize | number | - | 单个文件最大尺寸(字节) |
| children | ReactNode | - | 自定义上传按钮内容 |
+### MarkdownPreview
+
+Markdown文件预览组件,支持渲染Markdown格式的文档。
+
+#### 属性
+
+| 属性 | 类型 | 默认值 | 描述 |
+|------|------|-------|------|
+| url | string | - | Markdown文件的URL地址 |
+| className | string | - | 自定义容器类名 |
+| maxWidth | string/number | - | 容器最大宽度 |
+
### FilePreview
文件预览组件,支持多种文件格式的预览。
diff --git a/doc/example.json b/doc/example.json
index 51de018..6d7351e 100644
--- a/doc/example.json
+++ b/doc/example.json
@@ -157,6 +157,25 @@
"packageName": "@kne/remote-loader"
}
]
+ },
+ {
+ "title": "MarkdownPreview",
+ "description": "Markdown文件预览",
+ "code": "./markdown-preview.js",
+ "scope": [
+ {
+ "name": "_ReactFile",
+ "packageName": "@kne/current-lib_react-file",
+ "importStatement": "import * as _ReactFile from \"@kne/react-file\""
+ },
+ {
+ "packageName": "@kne/current-lib_react-file/dist/index.css"
+ },
+ {
+ "name": "remoteLoader",
+ "packageName": "@kne/remote-loader"
+ }
+ ]
}
]
}
diff --git a/doc/markdown-preview.js b/doc/markdown-preview.js
new file mode 100644
index 0000000..a20dd96
--- /dev/null
+++ b/doc/markdown-preview.js
@@ -0,0 +1,17 @@
+const { MarkdownPreview } = _ReactFile;
+const { createWithRemoteLoader, getPublicPath } = remoteLoader;
+
+const BaseExample = createWithRemoteLoader({
+ modules: ['components-core:InfoPage']
+})(({ remoteModules }) => {
+ const [InfoPage] = remoteModules;
+ return (
+
+
+
+
+
+ );
+});
+
+render();
diff --git a/package.json b/package.json
index 589542c..add5dc0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@kne/react-file",
- "version": "0.1.30",
+ "version": "0.1.31",
"description": "提供了文件上传,文件预览,文件批量管理等功能",
"syntax": {
"esmodules": true
@@ -90,11 +90,12 @@
"@ant-design/icons": "^5.5.1",
"@kne/button-group": "^0.1.3",
"@kne/create-deferred": "^0.1.0",
- "@kne/global-context": "^1.1.2",
+ "@kne/global-context": "^1.3.2",
"@kne/iframe-resizer": "^0.1.3",
+ "@kne/markdown-components-render": "^0.1.8",
"@kne/react-fetch": "^1.5.5",
"@kne/react-file-type": "^1.0.7",
- "@kne/react-intl": "^0.1.6",
+ "@kne/react-intl": "^0.1.12",
"@kne/use-control-value": "^0.1.8",
"@kne/use-ref-callback": "^0.1.2",
"@kne/use-resize": "^0.1.1",
diff --git "a/prompts/\345\221\275\345\220\215\347\244\272\344\276\213\347\274\226\345\206\231\347\244\272\344\276\213\346\217\217\350\277\260.md" "b/prompts/\345\221\275\345\220\215\347\244\272\344\276\213\347\274\226\345\206\231\347\244\272\344\276\213\346\217\217\350\277\260.md"
new file mode 100644
index 0000000..96ca14b
--- /dev/null
+++ "b/prompts/\345\221\275\345\220\215\347\244\272\344\276\213\347\274\226\345\206\231\347\244\272\344\276\213\346\217\217\350\277\260.md"
@@ -0,0 +1 @@
+根据doc/example.json中code引用的代码实现内容完善doc/example.json中的title和description字段
\ No newline at end of file
diff --git "a/prompts/\347\224\237\346\210\220\346\226\207\346\241\243.md" "b/prompts/\347\224\237\346\210\220\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..99d1a29
--- /dev/null
+++ "b/prompts/\347\224\237\346\210\220\346\226\207\346\241\243.md"
@@ -0,0 +1 @@
+根据代码帮我完成项目概述输出到doc/summary.md,api文档输出到doc/api.md markdown不要使用h1,h2对应的标签,doc/summary.md不需要项目概述标题,不需要依赖项说明,可以适当描述一下项目的特点吸引用户使用,doc/api.md不需要API文档标题,使用h3及之后,api文档优先使用table格式,api部分不需要示例代码,请严格遵守格式要求
\ No newline at end of file
diff --git "a/prompts/\347\224\237\346\210\220\350\257\255\350\250\200\345\214\205.md" "b/prompts/\347\224\237\346\210\220\350\257\255\350\250\200\345\214\205.md"
new file mode 100644
index 0000000..1aafab8
--- /dev/null
+++ "b/prompts/\347\224\237\346\210\220\350\257\255\350\250\200\345\214\205.md"
@@ -0,0 +1 @@
+将代码中的中文文案抽取到src/locale/zh-CN.js中,输入一个locale对象,locale对象中为key和文案的键值对,然后再翻译到en-US.js中,不要修改原始文件的任何内容
\ No newline at end of file
diff --git "a/prompts/\347\273\204\344\273\266\347\244\272\344\276\213\347\274\226\345\206\231.md" "b/prompts/\347\273\204\344\273\266\347\244\272\344\276\213\347\274\226\345\206\231.md"
new file mode 100644
index 0000000..f6f8c3f
--- /dev/null
+++ "b/prompts/\347\273\204\344\273\266\347\244\272\344\276\213\347\274\226\345\206\231.md"
@@ -0,0 +1,282 @@
+# 组件示例编写提示词
+
+本提示词用于编写遵循特定目录结构规范的 React 项目组件示例。
+
+## 1. 目录结构规范
+
+### 项目目录布局
+
+```
+{PROJECT_ROOT}/
+├── src/ # 源代码目录
+│ └── components/ # 组件源代码
+│ ├── ComponentA/ # 单个组件目录
+│ ├── ComponentB/ # 带子组件的目录
+│ │ ├── Sub1/
+│ │ ├── Sub2/
+│ │ └── index.js
+│ └── ...
+├── doc/ # 文档及示例目录(所有组件共用)
+│ ├── example.json # 示例配置文件(核心)
+│ ├── api.md # 组件API文档
+│ ├── summary.md # 组件简要描述
+│ ├── base.js # 基础示例代码
+│ ├── component-a.js # ComponentA示例
+│ ├── component-b.js # ComponentB主组件示例
+│ ├── component-b-sub1.js # ComponentB子组件Sub1示例
+│ ├── component-b-sub2.js # ComponentB子组件Sub2示例
+│ └── style.scss # 示例样式(可选)
+└── package.json # 项目配置文件
+```
+
+### 示例文件规则
+
+**重要**:所有组件的示例文件都统一放在项目根目录的 `doc/` 中,而不是在每个组件目录下创建单独的 `doc/` 目录。
+
+- 单个组件:使用组件名的小写短横线形式命名示例文件,如 `component-a.js`
+- 带子组件的组件:主组件示例使用组件名,子组件示例使用组件名加子组件名,如 `component-b.js`、`component-b-sub1.js`
+
+### 项目配置变量
+
+在编写示例时需要替换以下变量:
+
+| 变量名 | 说明 | 示例值 |
+|--------|------|--------|
+| `{PACKAGE_NAME}` | 从 package.json 的 name 字段获取 | `@kne/react-file` |
+| `{PROJECT_NAME}` | 项目名称,用于 getPublicPath | `react-file` |
+| `{LIB_NAME}` | 组件库名称,通常是驼峰形式 | `ReactFile` |
+
+## 2. example.json 配置结构
+
+所有组件的示例配置统一在 `doc/example.json` 中管理:
+
+```json
+{
+ "isFull": true,
+ "list": [
+ {
+ "title": "ComponentA",
+ "description": "组件A的描述",
+ "code": "./component-a.js",
+ "scope": [
+ {
+ "name": "_{LIB_NAME}",
+ "packageName": "{PACKAGE_NAME}",
+ "importStatement": "import * as _{LIB_NAME} from \"{PACKAGE_NAME}\""
+ },
+ {
+ "packageName": "{PACKAGE_NAME}/dist/index.css"
+ },
+ {
+ "name": "antd",
+ "packageName": "antd"
+ },
+ {
+ "name": "remoteLoader",
+ "packageName": "@kne/remote-loader"
+ }
+ ]
+ },
+ {
+ "title": "ComponentB",
+ "description": "组件B主组件",
+ "code": "./component-b.js",
+ "scope": []
+ },
+ {
+ "title": "ComponentB-Sub1",
+ "description": "组件B子组件Sub1",
+ "code": "./component-b-sub1.js",
+ "scope": []
+ }
+ ]
+}
+```
+
+## 3. 示例代码规范
+
+### 导入方式
+
+- 使用 `scope` 中声明的变量名:`const { FilePreview } = _{LIB_NAME};`
+- 工具包引用:`const { createWithRemoteLoader, getPublicPath } = remoteLoader;`
+
+### 标准示例模板(需要 PureGlobal 模拟数据)
+
+```javascript
+const { YourComponent } = _{LIB_NAME};
+const { createWithRemoteLoader, getPublicPath } = remoteLoader;
+
+const BaseExample = createWithRemoteLoader({
+ modules: ['components-core:Global@PureGlobal', 'components-core:InfoPage']
+})(({ remoteModules }) => {
+ const [PureGlobal, InfoPage] = remoteModules;
+ return (
+ {
+ return { data: { code: 0, data: api.loader() } };
+ },
+ apis: {
+ file: {
+ staticUrl: getPublicPath('{PROJECT_NAME}') || window.PUBLIC_URL,
+ getUrl: {
+ loader: async ({ params }) => {
+ // 模拟数据
+ return 'mock-url';
+ }
+ }
+ }
+ }
+ }}>
+
+
+
+
+
+
+ );
+});
+
+render();
+```
+
+### 简化示例模板(无需远程加载)
+
+```javascript
+const { YourComponent } = _{LIB_NAME};
+const { Flex, Switch } = antd;
+const { useState } = React;
+
+const BaseExample = () => {
+ const [state, setState] = useState(false);
+ return (
+
+
+
+ );
+};
+
+render();
+```
+
+## 4. scope 依赖声明规则
+
+| 场景 | name | packageName | importStatement(可选) |
+|------|------|-------------|------------------------|
+| 项目组件 | `_{LIB_NAME}` | `{PACKAGE_NAME}` | `import * as _{LIB_NAME} from "{PACKAGE_NAME}"` |
+| 样式文件 | - | `{PACKAGE_NAME}/dist/index.css` | - |
+| 远程加载器 | `remoteLoader` | `@kne/remote-loader` | - |
+| Antd组件 | `antd` | `antd` | - |
+| React原生 | `React` | - | -(无需声明) |
+
+## 5. API文档编写
+
+`doc/api.md` 中包含所有组件的API文档,使用表格格式:
+
+```markdown
+### 组件名称
+
+组件描述
+
+#### 属性
+
+| 属性 | 类型 | 默认值 | 描述 |
+|------|------|-------|------|
+| propName | string | - | 属性描述 |
+```
+
+## 6. 数据模拟
+
+在示例中使用 PureGlobal 的 preset 模拟数据:
+
+```javascript
+apis: {
+ file: {
+ staticUrl: getPublicPath('{PROJECT_NAME}') || window.PUBLIC_URL,
+ getUrl: {
+ loader: async ({ params }) => {
+ // 根据 params 返回对应的 mock 数据
+ const urlMap = {
+ 1: '/mock/example.png',
+ 2: '/mock/example.pdf'
+ };
+ return new Promise(resolve => {
+ setTimeout(() => {
+ resolve(urlMap[params.id]);
+ }, 500);
+ });
+ }
+ }
+ }
+}
+```
+
+## 7. 组件导出规范
+
+在组件的主入口 `index.js` 中,需要导出所有子组件:
+
+```javascript
+export { default } from './MainComponent';
+export { default as SubComponent1 } from './SubComponent1';
+export { default as SubComponent2 } from './SubComponent2';
+```
+
+在示例中通过解构引用:
+
+```javascript
+const { MainComponent, SubComponent1, SubComponent2 } = _{LIB_NAME};
+```
+
+## 8. 使用说明
+
+### 创建新组件示例步骤
+
+1. 在 `src/components/` 下创建或编辑组件
+2. 在 `doc/example.json` 中添加示例配置
+3. 在 `doc/` 目录下创建对应的 `.js` 示例文件
+4. 在 `doc/api.md` 中添加组件API文档(如果是新组件)
+5. 在组件的 `index.js` 中确保正确导出
+
+### 变量替换示例
+
+假设项目 `package.json` 中配置为:
+
+```json
+{
+ "name": "@your-org/your-project"
+}
+```
+
+则变量值为:
+
+- `{PACKAGE_NAME}` → `@your-org/your-project`
+- `{PROJECT_NAME}` → `your-project`
+- `{LIB_NAME}` → `YourProject`
+
+实际使用时需要替换为:
+
+```json
+{
+ "name": "_YourProject",
+ "packageName": "@your-org/your-project",
+ "importStatement": "import * as _YourProject from \"@your-org/your-project\""
+}
+```
+
+```javascript
+const { YourComponent } = _YourProject;
+const { createWithRemoteLoader, getPublicPath } = remoteLoader;
+
+// ...
+staticUrl: getPublicPath('your-project') || window.PUBLIC_URL,
+```
+
+## 9. 项目参考
+
+本项目的示例文件位于 `doc/` 目录:
+
+- `doc/example.json` - 所有组件的示例配置
+- `doc/api.md` - 所有组件的API文档
+- `doc/preview.js` - FilePreview 组件示例(包含多种预览类型)
+- `doc/file-list.js` - FileList 组件示例
+- `doc/download.js` - Download 组件示例
+- `doc/markdown-preview.js` - MarkdownPreview 组件示例
diff --git a/src/components/FilePreview/MarkdownPreview.js b/src/components/FilePreview/MarkdownPreview.js
new file mode 100644
index 0000000..c604f16
--- /dev/null
+++ b/src/components/FilePreview/MarkdownPreview.js
@@ -0,0 +1,58 @@
+import React, { useState, useEffect } from 'react';
+import { getAjax } from '@kne/react-fetch';
+import style from './style.module.scss';
+import { Spin } from 'antd';
+import classnames from 'classnames';
+import { createWithIntlProvider, useIntl } from '@kne/react-intl';
+import MarkdownRender from '@kne/markdown-components-render';
+import zhCn from '../../locale/zh-CN';
+
+const MarkdownPreview = createWithIntlProvider(
+ 'zh-CN',
+ zhCn,
+ 'react-file'
+)(({ url, className, maxWidth, ...props }) => {
+ const { formatMessage } = useIntl();
+ const [text, setText] = useState('');
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(false);
+ useEffect(() => {
+ const ajax = getAjax();
+ ajax({ url, method: 'GET' }).then(
+ ({ data }) => {
+ setText(data);
+ setLoading(false);
+ },
+ () => {
+ setLoading(false);
+ setError(true);
+ }
+ );
+ }, [url]);
+
+ return (
+
+ {loading ? (
+
+
+
+ ) : null}
+
+ {error ? (
+
{formatMessage({ id: 'fileLoadedError' })}
+ ) : (
+
+ {text}
+
+ )}
+
+
+ );
+});
+
+export default MarkdownPreview;
diff --git a/src/components/FilePreview/index.js b/src/components/FilePreview/index.js
index ec54f87..d2e64f1 100644
--- a/src/components/FilePreview/index.js
+++ b/src/components/FilePreview/index.js
@@ -8,4 +8,5 @@ export { default as OfficePreview } from './OfficePreview';
export { default as OSSFilePreview } from './OSSFilePreview';
export { default as AudioPreview } from './AudioPreview';
export { default as VideoPreview } from './VideoPreview';
+export { default as MarkdownPreview } from './MarkdownPreview';
export { default as typeFormat, typeComponentMapping } from './typeFormat';
diff --git a/src/components/FilePreview/style.module.scss b/src/components/FilePreview/style.module.scss
index b1c3833..e55043b 100644
--- a/src/components/FilePreview/style.module.scss
+++ b/src/components/FilePreview/style.module.scss
@@ -109,6 +109,61 @@
text-align: left;
}
+.md-inner {
+ background: #ffffff;
+ padding: 20px;
+
+ table {
+ width: 100%;
+ margin: 8px 0 16px;
+ empty-cells: show;
+ border: 1px solid #ebedf0;
+ border-collapse: collapse;
+ border-spacing: 0;
+
+ th {
+ color: #5c6b77;
+ font-weight: 500;
+ white-space: nowrap;
+ background: rgba(0, 0, 0, 0.02);
+ }
+
+ th,
+ td {
+ padding: 16px 24px;
+ text-align: left;
+ border: 1px solid #ebedf0;
+ }
+
+ td:first-child {
+ color: #595959;
+ font-weight: 600;
+ }
+
+ td:nth-child(3) {
+ color: #c41d7f;
+ }
+ }
+
+ pre {
+ background: #f2f4f5;
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ padding: 0.2em 0.4em;
+ font-size: 0.9em;
+ border: 1px solid #eee;
+ border-radius: 3px;
+ }
+
+ code {
+ background: #f2f4f5;
+ }
+
+ p {
+ margin: 0;
+ }
+}
+
.image-inner {
background: #ffffff;
display: block;
diff --git a/src/components/FilePreview/typeFormat.js b/src/components/FilePreview/typeFormat.js
index 6e84a6c..a1f4c33 100644
--- a/src/components/FilePreview/typeFormat.js
+++ b/src/components/FilePreview/typeFormat.js
@@ -6,6 +6,7 @@ import UnknownPreview from './UnknownPreview';
import ImagePreview from './ImagePreview';
import AudioPreview from './AudioPreview';
import VideoPreview from './VideoPreview';
+import MarkdownPreview from './MarkdownPreview';
const typeFormat = url => {
const path = (url || '').split('?')[0];
@@ -13,6 +14,9 @@ const typeFormat = url => {
if (/.txt$/.test(_path)) {
return 'txt';
}
+ if (/.md$/.test(_path)) {
+ return 'markdown';
+ }
if (/.pdf$/.test(_path)) {
return 'pdf';
}
@@ -38,6 +42,7 @@ export default typeFormat;
export const typeComponentMapping = {
txt: TextPreview,
+ markdown: MarkdownPreview,
pdf: PdfPreview,
image: ImagePreview,
html: HtmlPreview,
diff --git a/src/index.js b/src/index.js
index d5afbe8..d71e1c7 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,6 @@
export { default } from './components/File';
export { default as Download, useDownload, download, downloadBlobFile } from './components/Download';
-export { default as FilePreview, HtmlPreview, PdfPreview, TextPreview, ImagePreview, UnknownPreview, OfficePreview, OSSFilePreview, AudioPreview, VideoPreview } from './components/FilePreview';
+export { default as FilePreview, HtmlPreview, PdfPreview, TextPreview, MarkdownPreview, ImagePreview, UnknownPreview, OfficePreview, OSSFilePreview, AudioPreview, VideoPreview } from './components/FilePreview';
export { default as FileButton, useFileModalProps, useFileModal, FileModal } from './components/FileButton';
export { default as Image } from './components/Image';
export { default as PrintButton } from './components/PrintButton';
diff --git a/template-libs-example/public/mock/example.md b/template-libs-example/public/mock/example.md
new file mode 100644
index 0000000..c4c4b6f
--- /dev/null
+++ b/template-libs-example/public/mock/example.md
@@ -0,0 +1,124 @@
+# 候选人X
+
+女 | 29岁 
+15221260000  xxx@sina.com
+
+5年工作经验 | 前端开发工程师 | 期望薪资: 19-22K | 期望城市: 上海
+
+## 个人优势
+
+熟练使用 Vue 框架,拥有独立开发 PC 项目的能力
+
+熟练微信公众号h5项目开发,如直播h5/抽奖h5
+
+熟练使用 uniapp 开发微信小程序,如云课表,熟悉开发过钉钉小程序
+
+熟练使用 DataV+Echarts 开发可视化大屏项目
+
+熟练 Es6, `Vux, Less, Sass` 在项目中的使用
+
+掌握 Element, ant-design, Vant, uView 框架的使用
+
+掌握 HTML 5和 CSS 3新特性及动画
+
+熟悉了解webpack 等前端自动化构建工具
+
+掌握vue-cli 脚手架搭建项目及其后期配置
+
+熟悉Vue3 搭建并开发项目
+
+熟悉百度/高德地图 api 运用定位/画线/标记
+
+掌握 html2canvas 绘制海报/截图以及腾讯云视频的接入
+
+掌握微信 (JsApi) 支付/支付宝支付
+
+熟悉摄像头/胸卡/床卡/手表等硬件接入
+
+熟悉jeecboot及可视化大屏等低代码平台
+
+## 工作经历
+
+上海学威教育科技有限公司 前端开发工程师
+
+2022.08-2023.02
+
+### 内容:
+
+参与项目的原型讨论与前期规划,完成前端框架的搭建/难点分析与技术研发工作
+
+还原 UI 设计稿的交互实现以及与后端人员进行接口的对接
+
+封装通用组件/公共方法,持续优化前端交互体验加快页面响应速度
+
+负责的项目板块:
+
+负责云课表小程序项目清单管理/推广/直播相关页/邀请海报页/我的等功能板块的开发及后期的版本迭代功能的开发及维护
+
+负责h5项目会员卡/专栏/体验课/研修班从商品页到购买到学习/试听等一系列流程的开发;此外还包括活动推广/清单管理/海报邀请等板块的开发及版本迭代
+
+后管项目的维护及日常更新
+
+### 内容:
+
+参与需求评审,与项目经理,产品经理,后端等开发人员等进行项目细节的讨论
+
+负责 PC 系统/小程序/大屏项目的开发及需求更新维护
+
+通用组件封装,提升开发效率和质量
+
+根据项目业务需求,优化底层框架整体架构,完善项目方案
+
+前端代码的发版留存,日常维护更新
+
+配合市场部实时解决一些临时性问题
+
+参与制定代码规范、前端开发流程等规范性文件
+
+## 专业技能
+
+熟练使用 Vue框架,拥有独立开发项目的能力
+
+熟练微信小程序的开发,熟悉开发过钉钉小程序
+
+熟练使用DataV+Echarts开发可视化大屏项目
+
+掌握 Element, ant-design,Vant,uView 框架的使用
+
+熟练微信公众号授权h5项目开发,如直播h5/抽奖h5
+
+熟练 Es6,Vux,Less,Sass 在项目中的使用
+
+掌握百度/高德地图api运用定位/画线
+
+熟悉Vue3搭建并开发项目
+
+掌握 HTML5和 CSS3新特性
+
+熟悉了解webpack等前端自动化构建工具
+
+掌握 html2canvas 绘制海报以及腾讯云视频的接入
+
+掌握 Navicat,Git,SVN,FTP工具使用
+
+掌握PS等图像处理软件进行快速切图,修改
+
+掌握微信(JsApi)支付/支付宝支付
+
+熟悉摄像头/胸卡/床卡/手表等硬件接入
+
+熟悉jecboot及可视化大屏等低代码平台
+
+## 资格证书
+
+大学英语四级 计算机二级 h3c网络工程师
+
+
+
+#### 属性
+
+| 属性 | 类型 | 默认值 | 描述 |
+|---------------|-----------|-----|----------|
+| onBeforePrint | function | - | 打印前的回调函数 |
+| onAfterPrint | function | - | 打印后的回调函数 |
+| children | ReactNode | - | 按钮内容 |
\ No newline at end of file