This commit is contained in:
2025-03-01 22:40:33 +08:00
parent e9c1a1ca1e
commit e1f4584be4
21 changed files with 12270 additions and 62 deletions

View File

@ -1,5 +1,6 @@
{
"manifestVersion": 1,
"blockTypeID": "blk_67bf27b12481001387d8f3b9",
"projectName": "任务管理小应用"
"projectName": "任务管理小应用",
"url": "https://hailiang.feishu.cn/base/EciWbKOEXa68HIsnh5Ac7vZgnff"
}

View File

@ -8,4 +8,17 @@
<body>
<div id="root"></div>
</body>
<script>
function increment() {
var amount = document.getElementById("amount");
amount.value = parseInt(amount.value) + 1;
}
function decrement() {
var amount = document.getElementById("amount");
if (amount.value > 0) {
amount.value = parseInt(amount.value) - 1;
}
}
</script>
</html>

View File

@ -1,7 +1,7 @@
import { bitable } from "@lark-opdev/block-bitable-api";
import { FC, useEffect } from "react";
import { useAsync } from "react-async-hook";
import { getCurrentTask, setCompleted } from "./utils";
import { getCurrentTag, setAmount, setChecked} from "./utils";
import {
Typography,
Tag,
@ -9,19 +9,21 @@ import {
Divider,
Space,
Toast,
InputNumber,
} from "@douyinfe/semi-ui";
const { Title, Text } = Typography;
const defaultTask = {
description: "",
tag: "",
userName: "",
completed: false,
amount: 0,
checked: false
};
export const App = () => {
const task = useAsync(getCurrentTask, []);
const { description, userName, completed } = task.result ?? defaultTask;
const task = useAsync(getCurrentTag, []);
const { tag, userName, amount, checked } = task.result ?? defaultTask;
// 切换上下一条记录时,触发 SelectionChange
useEffect(() => {
@ -30,11 +32,24 @@ export const App = () => {
);
}, []);
const toggleCompleted = () => {
setCompleted(!completed)
const amountMinus = () => {
setAmount(amount - 1 > 0 ? amount - 1 : 0)
.then(() => task.execute())
.then(() => Toast.success("更新任务状态成功"))
.catch(() => Toast.error("更新任务状态失败"));
.then(() => Toast.success("amountMinus成功"))
.catch(() => Toast.error("amountMinus失败"));
};
const amountPlus = () => {
setAmount(amount + 1)
.then(() => task.execute())
.then(() => Toast.success("amountPlus成功"))
.catch(() => Toast.error("amountPlus失败"));
};
const togglechecked = () => {
setChecked(true)
.then(() => task.execute())
.then(() => Toast.success("amountPlus成功"))
.catch(() => Toast.error("amountPlus失败"));
};
if (task.loading) return <div>loading</div>;
@ -42,53 +57,80 @@ export const App = () => {
return (
<PureTaskComponment
description={description}
tag={tag}
userName={userName}
completed={completed}
toggleCompleted={toggleCompleted}
amount={amount}
checked={checked}
amountMinus={amountMinus}
amountPlus={amountPlus}
togglechecked={togglechecked}
/>
);
};
interface PureTaskComponmentProps {
description: string;
tag: string;
userName: string;
completed: boolean;
toggleCompleted: () => void;
amount: number;
checked: boolean;
amountMinus: () => void;
amountPlus: () => void;
togglechecked: () => void;
}
const PureTaskComponment: FC<PureTaskComponmentProps> = ({
description,
tag,
userName,
completed,
toggleCompleted,
amount,
checked,
togglechecked,
amountMinus,
amountPlus,
}) => {
return (
<Space vertical align="start">
<div>
<Title heading={2}></Title>
<Title heading={2}>Check</Title>
</div>
<div>
<Text></Text>
<Text>{description}</Text>
<Text>{tag}</Text>
</div>
<div>
<Text>amount:</Text>
<InputNumber
id="amount"
color={checked ? "green" : "yellow"}>
{amount}
</InputNumber>
</div>
<Divider />
<div>
<Button
type="warning"
onClick={amountMinus}
disabled={amount <= 0}
circle={true}
>
</Button>
<Button
type="primary"
onClick={amountPlus}
>
</Button>
</div>
<div>
<Text></Text>
<Text>{userName}</Text>
</div>
<div>
<Text></Text>
<Tag color={completed ? "green" : "blue"}>
{completed ? "已完成" : "未完成"}
</Tag>
</div>
<Divider />
<div>
<Button
type={completed ? "danger" : "primary"}
onClick={toggleCompleted}
type="primary"
onClick={togglechecked}
>
{completed ? "撤销完成任务" : "完成任务"}
{checked ? "取消" : "确认"}
</Button>
</div>
</Space>

View File

@ -1,7 +1,8 @@
import {
IOpenCheckbox,
IOpenSegment,
IOpenNumber,
IOpenTextSegment,
IOpenUser,
IOpenCheckbox,
bitable
} from "@lark-opdev/block-bitable-api";
@ -10,18 +11,18 @@ import {
* 可以保证字段 ID 与模板一致
*/
/** 任务描述字段 ID */
const descriptionFieldId = "fldaxqIJ1m";
/** 任务执行人字段名称 */
const userFieldName = "任务执行人";
/** 是否完成字段 ID */
const completedFieldId = "fld9cvGzic";
/** 游芯 规格 ID */
// const descriptionFieldId = "fldrxqL8uz";
const tagFieldId = "fld2xdCqrs";
/** 游芯 盘库人 ID */
// const userFieldName = "fldDyaB5ev";
const userFieldName = "盘库人";
/** 游芯 外库数量 ID */
// const completedFieldId = "fldsOIpOBk";
const amountFieldId = "fldC9cnnAY";
/** 尝试一下:接入是否延期字段 ID */
// const exceedingFieldId = "todo"
const checkedFieldId = "fldJkHhQgQ";
function getUserName(userValue: IOpenUser[] | null) {
if (!userValue || userValue.length === 0) {
return "任务执行人不存在";
@ -29,33 +30,31 @@ function getUserName(userValue: IOpenUser[] | null) {
return userValue[0].name ?? "用户没有设置姓名";
}
function getDescription(descriptionValue: IOpenSegment[] | null) {
if (!descriptionValue || descriptionValue.length === 0) {
return "任务描述不存在";
}
return descriptionValue.map((segment) => segment.text).join("");
}
export async function getCurrentTask() {
export async function getCurrentTag() {
// 1. 读取选中的表和记录 //
const { tableId, recordId } = await bitable.base.getSelection();
if (!tableId || !recordId) throw new Error("选区状态读取失败");
const table = await bitable.base.getTableById(tableId);
// 2. 读取单元格 //
const completedValue = (await table.getCellValue(
completedFieldId,
const amountValue = (await table.getCellValue(
amountFieldId,
recordId
)) as IOpenCheckbox;
)) as IOpenNumber;
const userField = await table.getFieldByName(userFieldName);
const userValue = (await table.getCellValue(
userField.id,
recordId
)) as IOpenUser[];
const descriptionValue = (await table.getCellValue(
descriptionFieldId,
const tagValue = (await table.getCellValue(
tagFieldId,
recordId
)) as IOpenSegment[];
)) as IOpenTextSegment[];
const checkedValue = (await table.getCellValue(
checkedFieldId,
recordId
)) as IOpenCheckbox;
// 尝试一下:读取是否延期字段
// 单选的值类型为 IOpenSingleSelect
@ -66,20 +65,31 @@ export async function getCurrentTask() {
// 3. 将单元格结构体转换成业务所需数据 //
return {
description: getDescription(descriptionValue),
tag: tagValue[0]?.text ?? "error",
userName: getUserName(userValue),
completed: completedValue,
amount: amountValue,
checked: checkedValue,
// 尝试一下:返回是否延期信息
// exceeding: exceedingText
};
}
export async function setCompleted(completed: boolean) {
export async function setAmount(amount: number) {
// 1. 读取选中的表和记录 //
const { tableId, recordId } = await bitable.base.getSelection();
if (!tableId || !recordId) throw new Error("选区状态读取失败");
const table = await bitable.base.getTableById(tableId);
// 2. 将业务数据转换成单元格结构,然后写入 //
table.setCellValue(completedFieldId, recordId, completed as IOpenCheckbox);
table.setCellValue(amountFieldId, recordId, amount as IOpenNumber);
}
export async function setChecked(checked: boolean) {
// 1. 读取选中的表和记录 //
const { tableId, recordId } = await bitable.base.getSelection();
if (!tableId || !recordId) throw new Error("选区状态读取失败");
const table = await bitable.base.getTableById(tableId);
// 2. 将业务数据转换成单元格结构,然后写入 //
table.setCellValue(checkedFieldId, recordId, checked as IOpenCheckbox);
}