前文已经对飞书项目插件开发中的一些常见后端场景予以了介绍。在本章节中,我们将主要探讨前端开发中存在的一些问题。并且,我们会通过一个实际的功能,引领你走进插件开发的前端世界。
控件介绍
控件实际上是飞书项目中最为普适的一个插件点位,能够覆盖大部分的交互场景。在控件中,可以自定义 UI 以及交互逻辑,以此来达到我们的理想效果。例如,我们今天要实现的功能 ——Excel 导入功能。
前置准备
- 全局安装命令行工具
npm i -g @lark-project/cli
2. 初始化插件工程
lpm init plugin_demo [plugin-id] [plugin-secret]
3. 启动工程
cd plugin_demo && lpm start
4. 打开飞书项目开心调试
开发过程
可以看到,插件的模板里已经为我们提供了一个控件的 demo。那么,现在我们就着手对其进行修改,从无到有地实现 Excel 导入功能吧。
首先我们需要把控件拖入页面中进行调试。
(在实例中的展示)
1. 安装依赖项
“xlsx” 能够轻松读取复杂的 Excel 表格,同时也可以生成新的表格。因此,我们安装 “xlsx” 来处理 Excel 数据。
yarn add xlsx
2.处理数据
在控件中选择 Excle 表格并且处理数据
const handleChange = useCallback(({ fileList, currentFile }) => {
try {
if (!currentFile) {
return;
}
const render = new FileReader();
render.readAsBinaryString(currentFile.fileInstance);
render.onload = e => {
if (e.target && e.target.result) {
// 读取文件生成workbook
const workbook = XLSX.read(e.target.result, { type: 'binary' });
const { SheetNames } = workbook;
const worksheet = workbook.Sheets[SheetNames[0]];
const jsonData: any[] = XLSX.utils.sheet_to_json(worksheet);
console.log('🚀🌈🌈🌈 ~ handleChange ~ jsonData:', jsonData);
}
};
} catch (error) {
console.error(error);
}
}, []);
可以看到数据解析成功
3. 生成工作项
调用接口创建工作项
const newData = convertData(data);
for (const item of newData) {
// 注意: 这里调用后端接口, 后端需要调用 openapi 创建工作项
await axios
.post('https://xxxxx', {
work_item_type_key: 'story', // 工作项类型(根据实际情况传递)
...item,
})
.then(res => {
Toast.success('创建成功');
});
}
接口调用成功后生成对应工作项
完整代码
import React, { useState } from 'react';
import { Button, Toast, Upload } from '@douyinfe/semi-ui';
import { IControlFormItemProps } from '../../../../../constants/type';
import * as XLSX from 'xlsx';
import axios from 'axios';
const DisplayFormItem = (props: IControlFormItemProps) => {
const [data, setData] = useState<Record<string, any>>([]);
const handleChange = ({ fileList, currentFile }) => {
try {
if (!currentFile) {
return;
}
const render = new FileReader();
render.readAsBinaryString(currentFile.fileInstance);
render.onload = e => {
if (e.target && e.target.result) {
// 读取文件生成workbook
const workbook = XLSX.read(e.target.result, { type: 'binary' });
const { SheetNames } = workbook;
const worksheet = workbook.Sheets[SheetNames[0]];
const jsonData: any[] = XLSX.utils.sheet_to_json(worksheet);
setData(jsonData);
}
};
} catch (error) {
console.error(error);
}
};
// 转换为后端可用数据
const convertData = data => {
try {
return data.map(item => ({
name: item.name,
field_value_pairs: [
{
field_key: 'description',
field_value: item.description,
},
],
}));
} catch (error) {
console.error(error);
}
return null;
};
const handleCreateWorkItem = async () => {
const newData = convertData(data);
for (const item of newData) {
// 注意: 这里调用后端接口, 后端需要调用 openapi 创建工作项
await axios
.post('https://xxxxx', {
work_item_type_key: 'story', // 工作项类型(根据实际情况传递)
...item,
})
.then(res => {
Toast.success('创建成功');
});
}
};
if (props.mode === 'configure') {
return '配置页不支持展示';
}
return (
<div>
<Button
disabled={data.length === 0}
onClick={handleCreateWorkItem}
style={{ marginBottom: 8 }}
>
生成工作项
</Button>
<Upload
action=""
limit={1}
draggable={true}
dragMainText={'点击上传文件或拖拽文件到这里'}
dragSubText="支持任意类型文件"
uploadTrigger="custom"
onChange={handleChange}
/>
</div>
);
};
export default DisplayFormItem;