init vue
This commit is contained in:
2
app.json
2
app.json
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"appId": "cli_a7359bac85b9d01c",
|
"appId": "cli_a7359bac85b9d01c",
|
||||||
"appName": "blk_inventory"
|
"appName": "blk_inventory_vue"
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"manifestVersion": 1,
|
"manifestVersion": 1,
|
||||||
"blockTypeID": "blk_67bf27b12481001387d8f3b9",
|
"blockTypeID": "blk_67bf27b12481001387d8f3b9",
|
||||||
"projectName": "任务管理小应用"
|
"projectName": "任务管理小应用",
|
||||||
|
"url": "https://hailiang.feishu.cn/base/EciWbKOEXa68HIsnh5Ac7vZgnff"
|
||||||
}
|
}
|
@ -8,4 +8,17 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
</body>
|
</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>
|
</html>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { bitable } from "@lark-opdev/block-bitable-api";
|
import { bitable } from "@lark-opdev/block-bitable-api";
|
||||||
import { FC, useEffect } from "react";
|
import { FC, useEffect } from "react";
|
||||||
import { useAsync } from "react-async-hook";
|
import { useAsync } from "react-async-hook";
|
||||||
import { getCurrentTask, setCompleted } from "./utils";
|
import { getCurrentTag, setAmount, setChecked} from "./utils";
|
||||||
import {
|
import {
|
||||||
Typography,
|
Typography,
|
||||||
Tag,
|
Tag,
|
||||||
@ -9,19 +9,21 @@ import {
|
|||||||
Divider,
|
Divider,
|
||||||
Space,
|
Space,
|
||||||
Toast,
|
Toast,
|
||||||
|
InputNumber,
|
||||||
} from "@douyinfe/semi-ui";
|
} from "@douyinfe/semi-ui";
|
||||||
|
|
||||||
const { Title, Text } = Typography;
|
const { Title, Text } = Typography;
|
||||||
|
|
||||||
const defaultTask = {
|
const defaultTask = {
|
||||||
description: "",
|
tag: "",
|
||||||
userName: "",
|
userName: "",
|
||||||
completed: false,
|
amount: 0,
|
||||||
|
checked: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export const App = () => {
|
export const App = () => {
|
||||||
const task = useAsync(getCurrentTask, []);
|
const task = useAsync(getCurrentTag, []);
|
||||||
const { description, userName, completed } = task.result ?? defaultTask;
|
const { tag, userName, amount, checked } = task.result ?? defaultTask;
|
||||||
|
|
||||||
// 切换上下一条记录时,触发 SelectionChange
|
// 切换上下一条记录时,触发 SelectionChange
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -30,11 +32,24 @@ export const App = () => {
|
|||||||
);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const toggleCompleted = () => {
|
const amountMinus = () => {
|
||||||
setCompleted(!completed)
|
setAmount(amount - 1 > 0 ? amount - 1 : 0)
|
||||||
.then(() => task.execute())
|
.then(() => task.execute())
|
||||||
.then(() => Toast.success("更新任务状态成功"))
|
.then(() => Toast.success("amountMinus成功"))
|
||||||
.catch(() => Toast.error("更新任务状态失败"));
|
.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>;
|
if (task.loading) return <div>loading</div>;
|
||||||
@ -42,53 +57,80 @@ export const App = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PureTaskComponment
|
<PureTaskComponment
|
||||||
description={description}
|
tag={tag}
|
||||||
userName={userName}
|
userName={userName}
|
||||||
completed={completed}
|
amount={amount}
|
||||||
toggleCompleted={toggleCompleted}
|
checked={checked}
|
||||||
|
amountMinus={amountMinus}
|
||||||
|
amountPlus={amountPlus}
|
||||||
|
togglechecked={togglechecked}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface PureTaskComponmentProps {
|
interface PureTaskComponmentProps {
|
||||||
description: string;
|
tag: string;
|
||||||
userName: string;
|
userName: string;
|
||||||
completed: boolean;
|
amount: number;
|
||||||
toggleCompleted: () => void;
|
checked: boolean;
|
||||||
|
amountMinus: () => void;
|
||||||
|
amountPlus: () => void;
|
||||||
|
togglechecked: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PureTaskComponment: FC<PureTaskComponmentProps> = ({
|
const PureTaskComponment: FC<PureTaskComponmentProps> = ({
|
||||||
description,
|
tag,
|
||||||
userName,
|
userName,
|
||||||
completed,
|
amount,
|
||||||
toggleCompleted,
|
checked,
|
||||||
|
togglechecked,
|
||||||
|
amountMinus,
|
||||||
|
amountPlus,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Space vertical align="start">
|
<Space vertical align="start">
|
||||||
<div>
|
<div>
|
||||||
<Title heading={2}>任务管理小应用</Title>
|
<Title heading={2}>Check</Title>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Text>描述:</Text>
|
<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>
|
||||||
<div>
|
<div>
|
||||||
<Text>执行人:</Text>
|
<Text>执行人:</Text>
|
||||||
<Text>{userName}</Text>
|
<Text>{userName}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<Text>完成状态:</Text>
|
|
||||||
<Tag color={completed ? "green" : "blue"}>
|
|
||||||
{completed ? "已完成" : "未完成"}
|
|
||||||
</Tag>
|
|
||||||
</div>
|
|
||||||
<Divider />
|
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
type={completed ? "danger" : "primary"}
|
type="primary"
|
||||||
onClick={toggleCompleted}
|
onClick={togglechecked}
|
||||||
>
|
>
|
||||||
{completed ? "撤销完成任务" : "完成任务"}
|
{checked ? "取消" : "确认"}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Space>
|
</Space>
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
IOpenCheckbox,
|
IOpenNumber,
|
||||||
IOpenSegment,
|
IOpenTextSegment,
|
||||||
IOpenUser,
|
IOpenUser,
|
||||||
|
IOpenCheckbox,
|
||||||
bitable
|
bitable
|
||||||
} from "@lark-opdev/block-bitable-api";
|
} from "@lark-opdev/block-bitable-api";
|
||||||
|
|
||||||
@ -10,18 +11,18 @@ import {
|
|||||||
* 可以保证字段 ID 与模板一致
|
* 可以保证字段 ID 与模板一致
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** 任务描述字段 ID */
|
/** 游芯 规格 ID */
|
||||||
const descriptionFieldId = "fldaxqIJ1m";
|
// const descriptionFieldId = "fldrxqL8uz";
|
||||||
|
const tagFieldId = "fld2xdCqrs";
|
||||||
/** 任务执行人字段名称 */
|
/** 游芯 盘库人 ID */
|
||||||
const userFieldName = "任务执行人";
|
// const userFieldName = "fldDyaB5ev";
|
||||||
|
const userFieldName = "盘库人";
|
||||||
/** 是否完成字段 ID */
|
/** 游芯 外库数量 ID */
|
||||||
const completedFieldId = "fld9cvGzic";
|
// const completedFieldId = "fldsOIpOBk";
|
||||||
|
const amountFieldId = "fldC9cnnAY";
|
||||||
/** 尝试一下:接入是否延期字段 ID */
|
/** 尝试一下:接入是否延期字段 ID */
|
||||||
// const exceedingFieldId = "todo"
|
// const exceedingFieldId = "todo"
|
||||||
|
const checkedFieldId = "fldJkHhQgQ";
|
||||||
function getUserName(userValue: IOpenUser[] | null) {
|
function getUserName(userValue: IOpenUser[] | null) {
|
||||||
if (!userValue || userValue.length === 0) {
|
if (!userValue || userValue.length === 0) {
|
||||||
return "任务执行人不存在";
|
return "任务执行人不存在";
|
||||||
@ -29,33 +30,31 @@ function getUserName(userValue: IOpenUser[] | null) {
|
|||||||
return userValue[0].name ?? "用户没有设置姓名";
|
return userValue[0].name ?? "用户没有设置姓名";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDescription(descriptionValue: IOpenSegment[] | null) {
|
export async function getCurrentTag() {
|
||||||
if (!descriptionValue || descriptionValue.length === 0) {
|
|
||||||
return "任务描述不存在";
|
|
||||||
}
|
|
||||||
return descriptionValue.map((segment) => segment.text).join("");
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getCurrentTask() {
|
|
||||||
// 1. 读取选中的表和记录 //
|
// 1. 读取选中的表和记录 //
|
||||||
const { tableId, recordId } = await bitable.base.getSelection();
|
const { tableId, recordId } = await bitable.base.getSelection();
|
||||||
if (!tableId || !recordId) throw new Error("选区状态读取失败");
|
if (!tableId || !recordId) throw new Error("选区状态读取失败");
|
||||||
const table = await bitable.base.getTableById(tableId);
|
const table = await bitable.base.getTableById(tableId);
|
||||||
|
|
||||||
// 2. 读取单元格 //
|
// 2. 读取单元格 //
|
||||||
const completedValue = (await table.getCellValue(
|
const amountValue = (await table.getCellValue(
|
||||||
completedFieldId,
|
amountFieldId,
|
||||||
recordId
|
recordId
|
||||||
)) as IOpenCheckbox;
|
)) as IOpenNumber;
|
||||||
const userField = await table.getFieldByName(userFieldName);
|
const userField = await table.getFieldByName(userFieldName);
|
||||||
const userValue = (await table.getCellValue(
|
const userValue = (await table.getCellValue(
|
||||||
userField.id,
|
userField.id,
|
||||||
recordId
|
recordId
|
||||||
)) as IOpenUser[];
|
)) as IOpenUser[];
|
||||||
const descriptionValue = (await table.getCellValue(
|
const tagValue = (await table.getCellValue(
|
||||||
descriptionFieldId,
|
tagFieldId,
|
||||||
recordId
|
recordId
|
||||||
)) as IOpenSegment[];
|
)) as IOpenTextSegment[];
|
||||||
|
|
||||||
|
const checkedValue = (await table.getCellValue(
|
||||||
|
checkedFieldId,
|
||||||
|
recordId
|
||||||
|
)) as IOpenCheckbox;
|
||||||
|
|
||||||
// 尝试一下:读取是否延期字段
|
// 尝试一下:读取是否延期字段
|
||||||
// 单选的值类型为 IOpenSingleSelect
|
// 单选的值类型为 IOpenSingleSelect
|
||||||
@ -66,20 +65,31 @@ export async function getCurrentTask() {
|
|||||||
|
|
||||||
// 3. 将单元格结构体转换成业务所需数据 //
|
// 3. 将单元格结构体转换成业务所需数据 //
|
||||||
return {
|
return {
|
||||||
description: getDescription(descriptionValue),
|
tag: tagValue[0]?.text ?? "error",
|
||||||
userName: getUserName(userValue),
|
userName: getUserName(userValue),
|
||||||
completed: completedValue,
|
amount: amountValue,
|
||||||
|
checked: checkedValue,
|
||||||
// 尝试一下:返回是否延期信息
|
// 尝试一下:返回是否延期信息
|
||||||
// exceeding: exceedingText
|
// exceeding: exceedingText
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setCompleted(completed: boolean) {
|
export async function setAmount(amount: number) {
|
||||||
// 1. 读取选中的表和记录 //
|
// 1. 读取选中的表和记录 //
|
||||||
const { tableId, recordId } = await bitable.base.getSelection();
|
const { tableId, recordId } = await bitable.base.getSelection();
|
||||||
if (!tableId || !recordId) throw new Error("选区状态读取失败");
|
if (!tableId || !recordId) throw new Error("选区状态读取失败");
|
||||||
const table = await bitable.base.getTableById(tableId);
|
const table = await bitable.base.getTableById(tableId);
|
||||||
|
|
||||||
// 2. 将业务数据转换成单元格结构,然后写入 //
|
// 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);
|
||||||
}
|
}
|
70
blk_inventory_vue/README.md
Normal file
70
blk_inventory_vue/README.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# demo
|
||||||
|
|
||||||
|
## 文件目录说明
|
||||||
|
|
||||||
|
```ts
|
||||||
|
├─README.md
|
||||||
|
├─block.json 小组件元信息,npm run upload上传的时候,代码将上传到block.json中的blockTypeID对应的小组件(插件),更换其中的url可以更换npm run start预览时打开的多维表格
|
||||||
|
├─jsconfig.json
|
||||||
|
├─package.json
|
||||||
|
├─src 组件
|
||||||
|
| ├─App.vue 组件入口
|
||||||
|
| ├─main.js 入口js文件
|
||||||
|
| ├─locales 多语配置
|
||||||
|
| | ├─en.json en语言配置
|
||||||
|
| | ├─i18n.js 多语配置文件,默认启用中文和英文
|
||||||
|
| | └zh.json zh语言配置
|
||||||
|
| ├─components
|
||||||
|
| | └Form.vue 代码示例
|
||||||
|
| ├─assets
|
||||||
|
| | └main.css 默认重制了一些css样式
|
||||||
|
├─public
|
||||||
|
| ├─favicon.ico 图标
|
||||||
|
| └index.html 入口文件
|
||||||
|
├─config
|
||||||
|
| └webpack.config.js webpack配置文件
|
||||||
|
```
|
||||||
|
|
||||||
|
## 国际化
|
||||||
|
|
||||||
|
本模板已内置国际化方案,你只需提供国际化的文案即可
|
||||||
|
|
||||||
|
1.在 src/locales 对应文件增加国际化文案,如在en.json中:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"title": "title"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2.在代码中通过$t函数使用国际化key,如在App.vue中:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<h1>{{$t('title')}}</h1>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 安装依赖
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm / yarn / pnpm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## 启动
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## 打包
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## 发布
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run upload
|
||||||
|
```
|
4
blk_inventory_vue/block.json
Normal file
4
blk_inventory_vue/block.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"blockTypeID": "blk_67bf27b12481001387d8f3b9",
|
||||||
|
"url": "https://hailiang.feishu.cn/base/AhiKbmafxasuodsRyoHc79junPe"
|
||||||
|
}
|
117
blk_inventory_vue/config/webpack.config.js
Normal file
117
blk_inventory_vue/config/webpack.config.js
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
const { VueLoaderPlugin } = require("vue-loader");
|
||||||
|
const path = require("path");
|
||||||
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||||
|
const { ESBuildMinifyPlugin } = require("esbuild-loader");
|
||||||
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
|
const WebpackBar = require("webpackbar");
|
||||||
|
const {
|
||||||
|
BitableAppWebpackPlugin,
|
||||||
|
opdevMiddleware,
|
||||||
|
} = require("@lark-opdev/block-bitable-webpack-utils");
|
||||||
|
|
||||||
|
const AutoImport = require("unplugin-auto-import/webpack");
|
||||||
|
const Components = require("unplugin-vue-components/webpack");
|
||||||
|
const { ElementPlusResolver } = require("unplugin-vue-components/resolvers");
|
||||||
|
|
||||||
|
const isDevelopment = process.env.NODE_ENV === "development";
|
||||||
|
const isProduction = process.env.NODE_ENV === "production";
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
entry: "./src/main.js",
|
||||||
|
devtool: isProduction ? false : "inline-source-map",
|
||||||
|
mode: isDevelopment ? "development" : "production",
|
||||||
|
stats: "errors-only",
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, "../dist"),
|
||||||
|
clean: true,
|
||||||
|
publicPath: isDevelopment ? "/block/" : "./",
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
use: "vue-loader",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
include: [/node_modules\/@lark-open/],
|
||||||
|
use: ["source-map-loader"],
|
||||||
|
enforce: "pre",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: [isDevelopment ? "style-loader" : MiniCssExtractPlugin.loader, "css-loader"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpg|jpeg|gif|ico|svg)$/,
|
||||||
|
type: "asset/resource",
|
||||||
|
generator: {
|
||||||
|
filename: "assets/[name][ext][query]",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
...(isDevelopment ? [new WebpackBar()] : [new MiniCssExtractPlugin()]),
|
||||||
|
|
||||||
|
new BitableAppWebpackPlugin({
|
||||||
|
// open: true, // 控制是否自动打开多维表格
|
||||||
|
}),
|
||||||
|
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: "index.html",
|
||||||
|
template: "./public/index.html",
|
||||||
|
publicPath: isDevelopment ? "/block/" : "./",
|
||||||
|
}),
|
||||||
|
|
||||||
|
new VueLoaderPlugin(),
|
||||||
|
|
||||||
|
AutoImport({
|
||||||
|
resolvers: [ElementPlusResolver()],
|
||||||
|
dts: false,
|
||||||
|
}),
|
||||||
|
Components({
|
||||||
|
resolvers: [ElementPlusResolver()],
|
||||||
|
dts: false,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
optimization: {
|
||||||
|
minimize: isProduction,
|
||||||
|
minimizer: [new ESBuildMinifyPlugin({ target: "es2015", css: true })],
|
||||||
|
moduleIds: "deterministic",
|
||||||
|
runtimeChunk: true,
|
||||||
|
splitChunks: {
|
||||||
|
chunks: "all",
|
||||||
|
cacheGroups: {
|
||||||
|
vendor: {
|
||||||
|
name: "vendor",
|
||||||
|
test: /[\\/]node_modules[\\/]/,
|
||||||
|
chunks: "all",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
devServer: isProduction
|
||||||
|
? undefined
|
||||||
|
: {
|
||||||
|
hot: true,
|
||||||
|
client: {
|
||||||
|
logging: "error",
|
||||||
|
},
|
||||||
|
setupMiddlewares: (middlewares, devServer) => {
|
||||||
|
if (!devServer || !devServer.app) {
|
||||||
|
throw new Error("webpack-dev-server is not defined");
|
||||||
|
}
|
||||||
|
middlewares.push(opdevMiddleware(devServer));
|
||||||
|
return middlewares;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cache: {
|
||||||
|
type: "filesystem",
|
||||||
|
buildDependencies: {
|
||||||
|
config: [__filename],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = config;
|
8
blk_inventory_vue/jsconfig.json
Normal file
8
blk_inventory_vue/jsconfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
11700
blk_inventory_vue/package-lock.json
generated
Normal file
11700
blk_inventory_vue/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
39
blk_inventory_vue/package.json
Normal file
39
blk_inventory_vue/package.json
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"name": "@bitable/board-view-demo",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "cross-env NODE_ENV=development webpack-dev-server --mode development --config ./config/webpack.config.js",
|
||||||
|
"start": "npm run dev",
|
||||||
|
"build": "cross-env NODE_ENV=production webpack --mode production --config ./config/webpack.config.js",
|
||||||
|
"upload": "npm run build && opdev upload ./dist"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@lark-opdev/block-bitable-api": "^0.3.2",
|
||||||
|
"@vue/compiler-sfc": "^3.3.13",
|
||||||
|
"element-plus": "^2.3.6",
|
||||||
|
"@element-plus/icons": "^0.0.11",
|
||||||
|
"normalize-css": "^2.3.1",
|
||||||
|
"style-loader": "^3.3.3",
|
||||||
|
"vue": "^3.3.11",
|
||||||
|
"vue-i18n": "^9.4.1",
|
||||||
|
"vue-template-compiler": "^2.7.15"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@lark-opdev/block-bitable-webpack-utils": "^0.1.5",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"css-loader": "^6.8.1",
|
||||||
|
"esbuild-loader": "^2.20.0",
|
||||||
|
"html-webpack-plugin": "^5.6.0",
|
||||||
|
"mini-css-extract-plugin": "^2.7.6",
|
||||||
|
"simple-progress-webpack-plugin": "^2.0.0",
|
||||||
|
"source-map-loader": "^4.0.1",
|
||||||
|
"vue-hot-reload-api": "^2.3.4",
|
||||||
|
"vue-loader": "^17.4.0",
|
||||||
|
"webpack": "^5.74.0",
|
||||||
|
"unplugin-auto-import": "^0.16.4",
|
||||||
|
"unplugin-vue-components": "^0.25.1",
|
||||||
|
"webpack-cli": "^4.10.0",
|
||||||
|
"webpack-dev-server": "^4.10.0",
|
||||||
|
"webpackbar": "^5.0.2"
|
||||||
|
}
|
||||||
|
}
|
BIN
blk_inventory_vue/public/favicon.ico
Normal file
BIN
blk_inventory_vue/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
13
blk_inventory_vue/public/index.html
Normal file
13
blk_inventory_vue/public/index.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Base Script</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
26
blk_inventory_vue/src/App.vue
Normal file
26
blk_inventory_vue/src/App.vue
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<script setup>
|
||||||
|
import Form from './components/Form.vue'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<main>
|
||||||
|
<h1>{{$t('title')}}</h1>
|
||||||
|
<h4>编辑 <code>src/App.vue</code> 并保存以重新加载</h4>
|
||||||
|
<Form />
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
main {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
font-size: calc(1.275rem + 0.3vw);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
font-size: 0.875em;
|
||||||
|
color: #d63384;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
</style>
|
1
blk_inventory_vue/src/assets/main.css
Normal file
1
blk_inventory_vue/src/assets/main.css
Normal file
@ -0,0 +1 @@
|
|||||||
|
@import "normalize-css";
|
72
blk_inventory_vue/src/components/Form.vue
Normal file
72
blk_inventory_vue/src/components/Form.vue
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<script>
|
||||||
|
import { bitable } from '@lark-opdev/block-bitable-api';
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import {
|
||||||
|
ElButton,
|
||||||
|
ElForm,
|
||||||
|
ElFormItem,
|
||||||
|
ElSelect,
|
||||||
|
ElOption,
|
||||||
|
} from 'element-plus';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
ElButton,
|
||||||
|
ElForm,
|
||||||
|
ElFormItem,
|
||||||
|
ElSelect,
|
||||||
|
ElOption,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const formData = ref({ table: '' });
|
||||||
|
const tableMetaList = ref([]);
|
||||||
|
|
||||||
|
const addRecord = async () => {
|
||||||
|
const tableId = formData.value.table;
|
||||||
|
if (tableId) {
|
||||||
|
const table = await bitable.base.getTableById(tableId);
|
||||||
|
table.addRecord({ fields: {} });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const [tableList, selection] = await Promise.all([bitable.base.getTableMetaList(), bitable.base.getSelection()]);
|
||||||
|
formData.value.table = selection.tableId;
|
||||||
|
tableMetaList.value = tableList;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
formData,
|
||||||
|
tableMetaList,
|
||||||
|
addRecord,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-form ref="form" class="form" :model="formData" label-position="top">
|
||||||
|
<el-form-item label="选择数据表" size="large">
|
||||||
|
<el-select v-model="formData.table" placeholder="请选择数据表" style="width: 100%">
|
||||||
|
<el-option
|
||||||
|
v-for="meta in tableMetaList"
|
||||||
|
:key="meta.id"
|
||||||
|
:label="meta.name"
|
||||||
|
:value="meta.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-button type="primary" plain size="large" @click="addRecord">新增一行记录</el-button>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form :deep(.el-form-item__label) {
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.form :deep(.el-form-item__content) {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
3
blk_inventory_vue/src/locales/en.json
Normal file
3
blk_inventory_vue/src/locales/en.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title":"title"
|
||||||
|
}
|
20
blk_inventory_vue/src/locales/i18n.js
Normal file
20
blk_inventory_vue/src/locales/i18n.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { createI18n } from 'vue-i18n'
|
||||||
|
import en from './en.json';
|
||||||
|
import zh from './zh.json';
|
||||||
|
import { bitable } from '@lark-opdev/block-bitable-api'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const i18n = createI18n({
|
||||||
|
locale: 'en',
|
||||||
|
allowComposition: true, // 占位符支持
|
||||||
|
messages: {
|
||||||
|
en: en,
|
||||||
|
zh: zh
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
bitable.bridge.getLanguage().then((lang) => {
|
||||||
|
i18n.global.locale = lang
|
||||||
|
})
|
||||||
|
|
3
blk_inventory_vue/src/locales/zh.json
Normal file
3
blk_inventory_vue/src/locales/zh.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "标题"
|
||||||
|
}
|
6
blk_inventory_vue/src/main.js
Normal file
6
blk_inventory_vue/src/main.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
import './assets/main.css'
|
||||||
|
import {i18n} from './locales/i18n.js'
|
||||||
|
createApp(App).use(i18n).mount('#app') // 注入国际化函数$t
|
||||||
|
|
60
id.txt
Normal file
60
id.txt
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
https://hailiang.feishu.cn/base/EciWbKOEXa68HIsnh5Ac7vZgnff?table=tbl9NPZQMl5IVHQ2&view=vewrOuK32q&debugPort=8080
|
||||||
|
|
||||||
|
https://open.feishu.cn/open-apis/bitable/v1/apps/EciWbKOEXa68HIsnh5Ac7vZgnff/tables/tbl9NPZQMl5IVHQ2/fields
|
||||||
|
|
||||||
|
游芯
|
||||||
|
"field_id": "fldrxqL8uz",
|
||||||
|
"field_name": "规格",
|
||||||
|
|
||||||
|
"field_id": "fldBwBQKJK",
|
||||||
|
"field_name": "总数量",
|
||||||
|
|
||||||
|
"field_id": "fldsOIpOBk",
|
||||||
|
"field_name": "外库数量",
|
||||||
|
|
||||||
|
"field_id": "fld7SND51Q",
|
||||||
|
"field_name": "内库数量",
|
||||||
|
|
||||||
|
"field_id": "fldSPcu1Wl",
|
||||||
|
"field_name": "已发放数量",
|
||||||
|
|
||||||
|
"field_id": "fldDyaB5ev",
|
||||||
|
"field_name": "盘库人",
|
||||||
|
|
||||||
|
"field_id": "fldq3A2klb",
|
||||||
|
"field_name": "更新时间",
|
||||||
|
|
||||||
|
|
||||||
|
外模
|
||||||
|
"field_id": "fld2xdCqrs",
|
||||||
|
"field_name": "规格",
|
||||||
|
|
||||||
|
"field_id": "fldF1zn6oR",
|
||||||
|
"field_name": "规格分档",
|
||||||
|
|
||||||
|
"field_id": "flddQLT21S",
|
||||||
|
"field_name": "总数量",
|
||||||
|
|
||||||
|
"field_id": "fldC9cnnAY",
|
||||||
|
"field_name": "外库数量",
|
||||||
|
|
||||||
|
"field_id": "fldi4luuNx",
|
||||||
|
"field_name": "内库数量",
|
||||||
|
|
||||||
|
"field_id": "fldZWiGZXA",
|
||||||
|
"field_name": "已发放",
|
||||||
|
|
||||||
|
"field_id": "fldNX4fdT2",
|
||||||
|
"field_name": "盘库人",
|
||||||
|
|
||||||
|
"field_id": "fld42z5rhX",
|
||||||
|
"field_name": "日期",
|
||||||
|
|
||||||
|
"field_id": "fldL9t6eYb",
|
||||||
|
"field_name": "单价",
|
||||||
|
|
||||||
|
"field_id": "fldR7yqETT",
|
||||||
|
"field_name": "总价",
|
||||||
|
|
||||||
|
"field_id": "fldJkHhQgQ",
|
||||||
|
"field_name": "已盘",
|
Reference in New Issue
Block a user