Files
kintone-vue-template/README.md
2025-10-23 15:30:57 +08:00

442 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# kintone-vue-ts-template
使用 Vue 、ts 和 Vite 创建 kintone plugin 的初始化模板,先由 [create-plugin](https://cybozu.dev/ja/kintone/sdk/development-environment/create-plugin/) 生成之后再手动引入 Vue。
> プラグイン開発手順https://cybozu.dev/ja/kintone/tips/development/plugins/development-plugin/
包括了以下 kintone 库:
- [kintone-ui-component (v1.22.0)](https://cybozu.dev/ja/kintone/sdk/library/kintone-ui-component-v1/)[文档](https://ui-component.kintone.dev/ja/)
- [@cybozu/eslint-config](https://cybozu.dev/ja/kintone/sdk/development-environment/eslint-config/)
- [@kintone/rest-api-client](https://cybozu.dev/ja/kintone/sdk/rest-api-client/kintone-javascript-client/)[文档](https://github.com/kintone/js-sdk/tree/main/packages/rest-api-client)
- [kintone/plugin-packer](https://cybozu.dev/ja/kintone/sdk/development-environment/plugin-packer/)
- [@kintone/plugin-uploader](https://cybozu.dev/ja/kintone/sdk/development-environment/plugin-uploader/)
- [@kintone/dts-gen](https://cybozu.dev/ja/kintone/sdk/library/dts-gen/)
# 使用步骤
首先进行安装
```bash
npm install # 或 yarn
```
随后需要修改项目信息:
1. `package.json`
```diff
{
+ "name": "项目名",
- "name": "kintone-vue-template",
"private": true,
+ "version": "版本号",
- "version": "0.0.0",
"type": "module",
"scripts": {
"vite:build": "vite build",
"build": "vite build && npm run pkg",
"build-upload": "npm run build && npm run upload",
"pkg": "kintone-plugin-packer --ppk private.ppk --out dist/plugin.zip dist/src",
+ "upload": "修改 kintone 域名、用户名和密码"
- "upload": "kintone-plugin-uploader --base-url https://alicorn.cybozu.com --username maxz --password 7ld7i8vd dist/plugin.zip "
},
...
```
2. `src/manifest.json`
```diff
{
...
+ "icon": "icon 路径",
- "icon": "image/icon.png",
"config": {
...
+ "required_params": [ "/config 页面必填的参数" ]
- "required_params": [ "buttonName" ]
},
+ "name": "项目名",
- "name": {
- "en": "kintone Vue template",
- "ja": "kintone Vue テンプレート"
- },
+ "description": "项目描述",
- "description": {
- "en": "kintone Vue template for creating plugin",
- "ja": "kintoneプラグイン作成用 Vue テンプレート"
- },
+ "description": "项目网站",
- "homepage_url": {
- "en": "https://www.alicorns.co.jp/",
- "ja": "https://www.alicorns.co.jp/"
- },
...
}
```
# 编译流程
- **build**
- `build` 会生成 `dist` 文件夹,以及 `plugin.zip` 文件
> 如果只需要 `dist` 文件夹,可以执行 `vite:build`
```bash
npm run build # 或 yarn build
# 仅生成 `dist` 文件夹
npm run vite:build # 或 yarn vite:build
```
- **build:prod**
- `build:prod` 也是生成 `plugin.zip` 文件,但是会进行压缩和混淆,并且没有 sourceMap在发布的时候使用
```bash
npm run build:prod # 或 yarn build:prod
```
- **upload**
- `upload` 会将 `plugin.zip` 上传到 Kintone plugin
```bash
npm run upload # 或 yarn upload
```
- **build-upload**
- `build-upload` 会顺序执行上面两步
```bash
npm run build-upload # 或 yarn build-upload
```
# 开发说明
当前模板中已经有一个案例,可以参考并且修改。
1. 对于 Config 页面,请修改 `components/Config.vue`
2. 对于 PC 的 App 页面,请修改 `js/desktop.ts`
3. 对于 Mobile 的 App 页面,请修改 `js/mobile.ts`
这三个文件是强制指定的,请不要修改。
## 项目结构
```shell
├── src
│ ├── components # config 页面
│ │ ├── basic
│ │ │ ├── PluginInput.vue
│ │ │ └── PluginLabel.vue
│ │ └── Config.vue # config 页面入口
│ ├── css
│ │ ├── 51-modern-default.css # config 页面额外引用的样式 css
│ │ ├── config.css # config 页面引用的 css
│ │ ├── desktop.css # desktop app 页面引用的 css
│ │ └── mobile.css # mobile app 页面引用的 css
│ ├── i18n # i18n 语言包相关
│ │ ├── lang
│ │ │ ├── en.ts
│ │ │ └── ja.ts
│ │ └── index.ts
│ ├── js
│ │ ├── desktop.ts # desktop app 页面入口
│ │ └── mobile.ts # mobile app 页面入口
│ ├── types
│ │ ├── index.d.ts
│ │ ├── model.d.ts
│ │ └── my-kintone.d.ts # kintone 相关的 ts 类型
│ ├── main.ts
│ └── manifest.json # kintone plugin 需要的配置
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── components.d.ts # vue 中自动 importbuild 的时候生成
├── env.d.ts # vue 类型定义
├── index.html
├── package.json
├── private.ppk # 当前 plugin 密钥,首次 build 自动生成
├── README.md
├── tsconfig.json
└── vite.config.ts # 主要的 vite 配置
└── vite.iife.config.ts # 用于打包 desktop/mobile 文件的配置
```
## 关于 Config 页面开发
只有 **Config 页面** 的开发可以使用 Vue Template其他页面请使用 `js` 文件。
基本上和 Vue 开发没有区别,但是有以下一些限制:
1. CSS 样式只能使用 `css` 文件
2. [`kintone-ui-component` 库有一些限制](#对于-kintone-ui-component-库的限制)
## 关于 desktop/mobile 的 app 页面开发
desktop/mobile 的 js 会被 `vite` 使用 `lib` 模式打包,从而将所有 import 合并到同一个文件里面。
## 关于 CSS 开发
> 暂时不支持在 Vue Template 中创建 css**只能在 `css` 文件夹下新建 css 文件**
`/css` 目录下分别对应了不同环境的 css 样式
- `config.css` - config 页面引用的 css
- `desktop.css` - desktop app 页面引用的 css
- `mobile.css` - mobile app 页面引用的 css
另外,在 `config` 页面引入了 `51-modern-default.css`,里面存放了 kintone 的一些样式
- 如果不需要使用就在 `manifest.json` 中删除
```diff
"config": {
"html": "html/config.html",
"js": [
"js/config.js"
],
"css": [
- "css/51-modern-default.css",
"css/config.css"
],
"required_params": [
"buttonName"
]
},
```
## 关于 KintoneRestAPIClient
在 desktop/mobile直接使用
```ts
import client from '@/plugins/kintoneClient.ts'
client.app...
```
在 vue 中使用 useKintoneClient()
```vue
import { useKintoneClient } from '@/composables/useKintoneClient';
const client = useKintoneClient();// KintoneRestAPIClient
client.app...
```
## 关于 i18n
在 desktop/mobile
```ts
import i18n from '@/i18n';
const { t } = i18n.global;
console.log(t('config.button.label'));
```
在 vue
```vue
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
console.log(t('config.button.label'));
```
# 对于 `kintone-ui-component` 库的限制
## desktop/mobile 页面
在 desktop/mobile 的 app 页面中import 的时候建议使用 lib 下的路径,按需导入
```js
// 建议
import { Button } from 'kintone-ui-component/lib/button';
// 下面的方式不太建议,都会引入所有的组件
import { Button } from 'kintone-ui-component';
import kuc from 'kintone-ui-component';
```
## config 页面
由于 kuc 只提供了 umd 文件,所以对于 vue 页面,有比较多的限制
### 基本使用方式
在 `<template>` 中使用 `<kuc-*>` 组件时:
1. **不需要写 kuc 文档中所说的版本号**
2. 不需要在 `<script>` 中手动 import
这些已经在 `vite.config.ts` 中已经自动处理了。
```ts
<kuc-text :value="modelValue" @change="updateValue" />
```
而对于在 `<script>` 中使用到的 ts type和在 desktop/mobile 一样,请使用 `lib` 下的组件
```ts
import type { TextInputEventDetail } from 'kintone-ui-component/lib/text';
```
### v-model 语法糖无法使用
毕竟不是专门为 vue 开发的,所以默认不能使用 v-model 语法糖
需要自行创建 emit 事件(参考 `/src/components/basic/PluginInput.vue`
```vue
<template>
<kuc-text :value="modelValue" @change="updateValue" />
</template>
<script setup lang="ts">
import type { KucEvent } from '@/types/my-kintone';
import type { TextInputEventDetail } from 'kintone-ui-component/lib/text';
import { defineProps, defineEmits } from 'vue';
// KUC Text 组件不支持 v-model 语法,因此需要进行包装以支持双向绑定
const props = defineProps<{
modelValue: string;
}>();
const emit = defineEmits<{
(e: 'update:modelValue', value: string): void;
}>();
/**
* 处理 v-model 事件
*/
const updateValue = ({ detail }: KucEvent<TextInputEventDetail>) => {
emit('update:modelValue', detail.value || '');
};
</script>
```
### 封装组件的问题
当为了解决 v-model 的问题,可能会需要封装组件。我们会使用 `v-bind` 来避免手动来加 kuc 组件的所有属性。(参考 `/src/components/basic/PluginInput.vue`
```vue
<template>
<kuc-text v-bind="textProps" />
</template>
<script setup lang="ts">
import type { TextProps } from 'kintone-ui-component/lib/text';
import { defineProps, computed } from 'vue';
const props = defineProps<TextProps & {
modelValue: string; // 用于解决 v-model
}>();
/**
* 生成传递给 KUC Text 组件的属性对象
*/
const textProps = computed<TextProps>(() => {
return {
...props,
className: "kuc-text-input " + ${props.className}, // 添加基础样式类
};
</script>
```
但是有的 `boolean` 类型的属性,会被默认设置为 `false`,导致问题
- 比如 `visible: false` 就看不到组件了
所以需要手动将这些 `boolean` 属性设置为 `undefined`
```ts
const props = withDefaults(defineProps<TextProps & {
modelValue: string;
}>(), {
// 布尔值的默认值处理,设置为 undefined 表示未定义,否则默认会是 false
disabled: undefined,
requiredIcon: undefined,
visible: undefined,
});
const textProps = computed<TextProps>(() => {
const baseProps = {
...props,
className: "kuc-text-input " + ${props.className}, // 添加基础样式类
};
// 移除值为 undefined 的属性,确保只传递有效属性
return Object.fromEntries(Object.entries(baseProps).filter(([_, value]) => value !== undefined)) as TextProps;
});
```
### 关于 spinner
使用 spinner 的时候,如果想要限制在某一个组件上(`:container` 属性),直接使用是不行的,它只会加在 `document.body` 上
不知道为啥,当它创建的时候不会用到 `:container` 参数,即使 HTMLNode 是可见的
所以可以使用 `v-show` 先让它隐藏
> 理论上来说spinner 使用 new kucs.spinner() 创建更符合习惯,但是我不太想引入 `kuc.min.js` 文件……
```vue
<template>
<div id="main-area" ref="mainArea">
</div>
<!-- 必须使用 v-show 让 spinner dom 创建的时候不显示 -->
<kuc-spinner :container="mainArea" v-show="loading" ref="spinner"></kuc-spinner>
</template>
<script setup lang="ts">
const loading = ref(false);
const mainArea = shallowRef<HTMLElement | null>(null);
const spinner = shallowRef<Spinner | null>(null);
onMounted(async () => {
// 等待页面完全渲染后再显示加载状态,实现更平滑的用户体验
nextTick(async () => {
loading.value = true;
// ...
// 模拟加载时间,展示 spinner 效果
await new Promise((resolve) => setTimeout(resolve, 1000));
loading.value = false;
});
});
// 监听加载状态变化,控制 spinner 显示/隐藏
watch(loading, (load) => {
load ? spinner.value?.open() : spinner.value?.close();
});
</script>
```
### 关于 tooltip
kuc 没有实现插槽,所以应该当成一个普通组件使用:
```vue
<template>
<button ref="buyButton">购买</button>
<kuc-tooltip title="点击购买" :container="buyButton"></kuc-tooltip>
</template>
<script setup lang="ts">
const buyButton = shallowRef<HTMLButtonElement | null>(null);
</script>
```