@ -0,0 +1,7 @@ |
|||||||
|
node_modules |
||||||
|
.DS_Store |
||||||
|
dist |
||||||
|
*.local |
||||||
|
index.html |
||||||
|
.remote-assets |
||||||
|
components.d.ts |
@ -0,0 +1,11 @@ |
|||||||
|
# Welcome to [Slidev](https://github.com/slidevjs/slidev)! |
||||||
|
|
||||||
|
To start the slide show: |
||||||
|
|
||||||
|
- `npm install` |
||||||
|
- `npm run dev` |
||||||
|
- visit http://localhost:3030 |
||||||
|
|
||||||
|
Edit the [slides.md](./slides.md) to see the changes. |
||||||
|
|
||||||
|
Learn more about Slidev on [documentations](https://sli.dev/). |
@ -0,0 +1,37 @@ |
|||||||
|
<script setup lang="ts"> |
||||||
|
import { ref } from 'vue' |
||||||
|
|
||||||
|
const props = defineProps({ |
||||||
|
count: { |
||||||
|
default: 0, |
||||||
|
}, |
||||||
|
}) |
||||||
|
|
||||||
|
const counter = ref(props.count) |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<div flex="~" w="min" border="~ main rounded-md"> |
||||||
|
<button |
||||||
|
border="r main" |
||||||
|
p="2" |
||||||
|
font="mono" |
||||||
|
outline="!none" |
||||||
|
hover:bg="gray-400 opacity-20" |
||||||
|
@click="counter -= 1" |
||||||
|
> |
||||||
|
- |
||||||
|
</button> |
||||||
|
<span m="auto" p="2">{{ counter }}</span> |
||||||
|
<button |
||||||
|
border="l main" |
||||||
|
p="2" |
||||||
|
font="mono" |
||||||
|
outline="!none" |
||||||
|
hover:bg="gray-400 opacity-20" |
||||||
|
@click="counter += 1" |
||||||
|
> |
||||||
|
+ |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</template> |
@ -0,0 +1,16 @@ |
|||||||
|
[build] |
||||||
|
publish = "dist" |
||||||
|
command = "npm run build" |
||||||
|
|
||||||
|
[build.environment] |
||||||
|
NODE_VERSION = "20" |
||||||
|
|
||||||
|
[[redirects]] |
||||||
|
from = "/.well-known/*" |
||||||
|
to = "/.well-known/:splat" |
||||||
|
status = 200 |
||||||
|
|
||||||
|
[[redirects]] |
||||||
|
from = "/*" |
||||||
|
to = "/index.html" |
||||||
|
status = 200 |
@ -0,0 +1,16 @@ |
|||||||
|
{ |
||||||
|
"name": "fast-iot-ppt", |
||||||
|
"type": "module", |
||||||
|
"private": true, |
||||||
|
"scripts": { |
||||||
|
"build": "slidev build", |
||||||
|
"dev": "slidev --open", |
||||||
|
"export": "slidev export" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"@slidev/cli": "^0.48.0-beta.6", |
||||||
|
"@slidev/theme-default": "latest", |
||||||
|
"@slidev/theme-seriph": "latest", |
||||||
|
"vue": "^3.4.19" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
# Multiple Entries |
||||||
|
|
||||||
|
You can split your slides.md into multiple files and organize them as you want using the `src` attribute. |
||||||
|
|
||||||
|
#### `slides.md` |
||||||
|
|
||||||
|
```markdown |
||||||
|
# Page 1 |
||||||
|
|
||||||
|
Page 2 from main entry. |
||||||
|
|
||||||
|
--- |
||||||
|
src: ./subpage.md |
||||||
|
--- |
||||||
|
``` |
||||||
|
|
||||||
|
<br> |
||||||
|
|
||||||
|
#### `subpage.md` |
||||||
|
|
||||||
|
```markdown |
||||||
|
# Page 2 |
||||||
|
|
||||||
|
Page 2 from another file. |
||||||
|
``` |
||||||
|
|
||||||
|
[Learn more](https://sli.dev/guide/syntax.html#multiple-entries) |
After Width: | Height: | Size: 151 KiB |
After Width: | Height: | Size: 189 KiB |
After Width: | Height: | Size: 274 KiB |
After Width: | Height: | Size: 115 KiB |
After Width: | Height: | Size: 149 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 522 KiB |
@ -0,0 +1,400 @@ |
|||||||
|
--- |
||||||
|
theme: seriph |
||||||
|
background: https://source.unsplash.com/collection/94734566/1920x1080 |
||||||
|
highlighter: shiki |
||||||
|
lineNumbers: true |
||||||
|
transition: slide-left |
||||||
|
mdc: true |
||||||
|
--- |
||||||
|
|
||||||
|
# Fast Iot Web |
||||||
|
|
||||||
|
工业互联网前端开源平台模版介绍 |
||||||
|
|
||||||
|
--- |
||||||
|
layout: center |
||||||
|
--- |
||||||
|
|
||||||
|
# 1. 模版基础 |
||||||
|
|
||||||
|
--- |
||||||
|
layout: image-right |
||||||
|
image: /vben.png |
||||||
|
backgroundSize: contain |
||||||
|
--- |
||||||
|
|
||||||
|
# 模版介绍 |
||||||
|
|
||||||
|
<a href='https://gitee.com/yudaocode/yudao-ui-admin-vben'>yudao-ui-admin-vben</a> <carbon-direction-straight-right /> <a href='https://github.com/vbenjs/vue-vben-admin'>vue-vben-admin</a> |
||||||
|
|
||||||
|
Vue Vben Admin 是一个免费开源的中后台模版。使用了最新的 vue3、vite4、TypeScript 等主流技术开发,开箱即用的中后台前端解决方案,也可用于学习参考。 |
||||||
|
|
||||||
|
- 最新技术栈: 使用 Vue3/vite2 等前端前沿技术开发 |
||||||
|
- TypeScript: 应用程序级 JavaScript 的语言 |
||||||
|
- 主题: 可配置的主题 |
||||||
|
- 国际化: 内置完善的国际化方案 |
||||||
|
- 权限: 内置完善的动态路由权限生成方案 |
||||||
|
- 组件: 二次封装了多个常用的组件 |
||||||
|
|
||||||
|
<!-- |
||||||
|
1. Vben 在 Vue3 刚推出时就出现了,一直迭代至今,目前最新版本是 v2.10.0, 而 yudao-ui-admin-vben fork 了 Vben, 大约是在 v.2.7.0 版本之前,所以目前的模版是基于 Vben 的,但是有一定的差距,其次 Vben 原维护者已经停止维护,目前由社区人员维护,目前有点过重了 |
||||||
|
--> |
||||||
|
|
||||||
|
--- |
||||||
|
layout: image-right |
||||||
|
image: /fast-iot-web.png |
||||||
|
backgroundSize: contain |
||||||
|
--- |
||||||
|
|
||||||
|
# 模版技术栈 |
||||||
|
|
||||||
|
<div><a href='http://223.99.228.240:33000/liukai/fast-iot-web'><carbon:logo-github /> Fast iot web</a></div> |
||||||
|
|
||||||
|
<br/> |
||||||
|
|
||||||
|
- vue@3.3.8 -> 最新 vue@3.4.19 |
||||||
|
- vite@4.5.1 -> 最新 vite@5.1.4 |
||||||
|
- ant-design-vue@4.0.8 -> 最新 ant-design-vue@4.1.2 |
||||||
|
- typescript@5.3.3 |
||||||
|
- unocss@0.58.3 |
||||||
|
- @antfu/eslint-config@2.6.2 |
||||||
|
- node>=18.12.0 |
||||||
|
- pnpm>=8.10.0 |
||||||
|
|
||||||
|
<!-- |
||||||
|
1. 目前仓库在 gitea,还没有放在 git 或 gitee 上 |
||||||
|
2. vite 为什么不用最新版?后面会提及,这里暂时不介绍,vue、ant-design-vue 不用最新版的原因是 Slot 插槽 TS 类型有问题 |
||||||
|
3. 强制 TS 类型安全,在提交时会执行 type:check |
||||||
|
4. 没有 prettier,只需用 Eslint(因为个人原因,antfu 生态) |
||||||
|
5. 这里主要列举了一些核心包,其他包看下 package.json |
||||||
|
6. 目前仓库 git 提交比较混乱,因为改动较大,最后会整合一下 git 提交记录 |
||||||
|
7. 强制使用 pnpm,基于 npx only-allow pnpm 这个命令 |
||||||
|
--> |
||||||
|
|
||||||
|
--- |
||||||
|
layout: image-right |
||||||
|
image: /command.png |
||||||
|
backgroundSize: contain |
||||||
|
--- |
||||||
|
|
||||||
|
# 项目命令 |
||||||
|
|
||||||
|
<br /> |
||||||
|
|
||||||
|
- dev -> 开发环境 |
||||||
|
- build -> 构建生产环境 |
||||||
|
- type:check -> 执行 TS 检查 |
||||||
|
- lint -> 执行 Eslint 检查 |
||||||
|
- changelog -> 生成版本日志 |
||||||
|
- release -> 版本发布 |
||||||
|
|
||||||
|
<!-- |
||||||
|
1. changelog: 基于约定式提交规范生成版本日志 (git 提交记录要更细) |
||||||
|
2. release: 集成了一个第三方库 bumpp ,自动发布版本,包含:修改版本号、执行 changelog 命令、创建版本提交记录、创建 Tag、推送提交记录和 Tag 到 Git 仓库,一般来说发版时直接执行 release 就可以了 |
||||||
|
3. 后面有文章介绍这两个命令的集成 |
||||||
|
4. 顺便讨论一个 Git 工作流的应用,git rebase + marge(fast forward) 与 git rebase + git merge --squash (/skwɒʃ/) |
||||||
|
--> |
||||||
|
|
||||||
|
--- |
||||||
|
layout: image-right |
||||||
|
image: /dir.png |
||||||
|
backgroundSize: contain |
||||||
|
--- |
||||||
|
|
||||||
|
# 项目目录 |
||||||
|
|
||||||
|
- /build -> 构建项目代码,例如:vite config、plugin |
||||||
|
- /api -> 后端请求交互 |
||||||
|
|
||||||
|
```plain |
||||||
|
|-- user |
||||||
|
-- index.ts |
||||||
|
-- types.ts |
||||||
|
``` |
||||||
|
|
||||||
|
- /views -> 页面 |
||||||
|
|
||||||
|
```plain{1,2,3,4} |
||||||
|
|-- user |
||||||
|
-- index.vue |
||||||
|
-- data.ts |
||||||
|
-- UserFormModal.vue |
||||||
|
-- ?form.vue |
||||||
|
``` |
||||||
|
|
||||||
|
<!-- |
||||||
|
1. 多语言支持,但是没有怎么去使用 |
||||||
|
2. css 使用 unocss |
||||||
|
3. 下面的 types 目录是公共的类型 |
||||||
|
4. data.ts 用法后面介绍 |
||||||
|
5. components 目录下存放的是公共组件(与业务无关),如果是与业务有关的公共组件,可以新建 /views/components |
||||||
|
6. 如果新建、编辑、详情是页面的话,可以增加 form.vue / detail.vue 小写开头的 .vue 文件(或者有更好的命名方式?) |
||||||
|
--> |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
# 菜单路由 |
||||||
|
|
||||||
|
路由使用的 `BACK` (后端路由模式),移除了 `ROLE` (角色权限) 和 `ROUTE_MAPPING` (路由映射) 两种模式。 |
||||||
|
|
||||||
|
新增路由在 系统管理 -> 菜单管理 页面动态增加: |
||||||
|
|
||||||
|
<div flex='~ gap-10px items-center' class='gap-[10px]'> |
||||||
|
<img src='/menu-1.png' class='flex-1 w-0 shadow-lg'/> |
||||||
|
<img src='/menu-2.png' class='flex-1 w-0 shadow-lg'/> |
||||||
|
<img src='/menu-3.png' class='flex-1 w-0 shadow-lg'/> |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- |
||||||
|
1. 路由路径和组件路径一般是相同的 |
||||||
|
2. 当开启 keep-alive 时,组件名称是必须且唯一 |
||||||
|
3. 是否在菜单栏显示,用于添加不再菜单栏展示的页面(如:新增、编辑、详情或其他) |
||||||
|
4. 路由遵从嵌套路由规则 |
||||||
|
5. 所有子路由默认都会转为二级路由,所以不能存在二层以上的内嵌路由 |
||||||
|
--> |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
# 按钮权限 |
||||||
|
|
||||||
|
项目中存在三种权限判断方式,分别为: |
||||||
|
1. 函数 |
||||||
|
2. 组件 |
||||||
|
3. 指令 |
||||||
|
|
||||||
|
```ts{1|3-5|7} |
||||||
|
<button v-if="hasPermission(codes)">Create</button> |
||||||
|
|
||||||
|
<Authority :value="codes"> |
||||||
|
<button>Create</button> |
||||||
|
</Authority> |
||||||
|
|
||||||
|
<button v-auth="codes">Create</button> |
||||||
|
``` |
||||||
|
|
||||||
|
推荐使用函数方式 |
||||||
|
|
||||||
|
--- |
||||||
|
layout: center |
||||||
|
--- |
||||||
|
|
||||||
|
# 2. 常用组件介绍 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
# BasicTable |
||||||
|
|
||||||
|
```ts{2|3|4,7-11|12-14|5,19-23} |
||||||
|
<script setup lang='ts'> |
||||||
|
import { BasicTable, TableAction, useTable } from '@/components/Table' |
||||||
|
import { columns, searchFormSchema } from './data' |
||||||
|
import { getUserList } from '@/api/user' |
||||||
|
import type { SystemUser } from '@/api/user/types' |
||||||
|
|
||||||
|
const [registerTable, { reload }] = useTable({ |
||||||
|
api(params) { |
||||||
|
return getUserList({ ...params, deptId: selectionDept.value }) |
||||||
|
}, |
||||||
|
columns, |
||||||
|
formConfig: { |
||||||
|
schemas: searchFormSchema, |
||||||
|
}, |
||||||
|
}) |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<BasicTable :api="async () => ([] as SystemUser[])" @register="registerTable"> |
||||||
|
<template #bodyCell="{ record }"> |
||||||
|
... |
||||||
|
</template> |
||||||
|
</BasicTable> |
||||||
|
</template> |
||||||
|
``` |
||||||
|
<!-- |
||||||
|
1. 使用 hooks 方式 |
||||||
|
2. useTable 支持泛型,但不用手动传递,会根据 api 的返回值自动推断 |
||||||
|
3. Vue 泛型组件不能传递泛型,只能通过 Props 推断,但是我们使用 useTable 时,使用 register 传递的 props,所以就无法推断出来了 (这样可以获取到 slot 泛型支持) |
||||||
|
4. 更多的使用,参考 Vben 和 ant-design Table 文档 |
||||||
|
--> |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
# BasicForm |
||||||
|
|
||||||
|
```ts{2-3|5-11|15} |
||||||
|
<script setup lang='ts'> |
||||||
|
import { BasicForm, useForm } from '@/components/Form' |
||||||
|
import { formSchema } from './data' |
||||||
|
|
||||||
|
const [registerForm, { setFieldsValue, validate }] = useForm({ |
||||||
|
labelWidth: 120, |
||||||
|
baseColProps: { span: 24 }, |
||||||
|
schemas: formSchema, |
||||||
|
showActionButtonGroup: false, |
||||||
|
actionColOptions: { span: 23 }, |
||||||
|
}) |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<BasicForm @register="registerForm" /> |
||||||
|
</template> |
||||||
|
``` |
||||||
|
|
||||||
|
<!-- |
||||||
|
1. 使用 hooks 方式 |
||||||
|
2. 目前 useForm 不支持泛型 (之前没加,但是加上最好,谁有兴趣的话可以做一下) |
||||||
|
--> |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
# BasicModal |
||||||
|
|
||||||
|
BasicModal 用法使用两个 `Hook` 实现,`useModal` 和 `useModalInner` |
||||||
|
|
||||||
|
useModal |
||||||
|
|
||||||
|
```ts{2,3|5,9|none} |
||||||
|
<script setup lang='ts'> |
||||||
|
import { useModal } from '@/components/Modal' |
||||||
|
import UserFormModal from './UserFormModal.vue' |
||||||
|
|
||||||
|
const [registerModal, { openModal }] = useModal<string>() |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<UserFormModal @register="registerModal" /> |
||||||
|
</template> |
||||||
|
``` |
||||||
|
|
||||||
|
<!-- |
||||||
|
1. useModal 在父组件中使用 (如:user.vue) |
||||||
|
2. useModal 支持泛型,可以约束 openModal 函数调用参数类型 |
||||||
|
--> |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
# BasicModal |
||||||
|
|
||||||
|
useInnerModal |
||||||
|
|
||||||
|
```ts{2|4-6|10} |
||||||
|
<script setup lang='ts'> |
||||||
|
import { BasicModal, useModalInner } from '@/components/Modal' |
||||||
|
|
||||||
|
const [registerModal] = useModalInner(async (id: string) => { |
||||||
|
... |
||||||
|
}) |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<BasicModal v-bind="$attrs" @register="registerModal" /> |
||||||
|
</template> |
||||||
|
``` |
||||||
|
|
||||||
|
<br/> |
||||||
|
|
||||||
|
<v-click> |
||||||
|
|
||||||
|
```ts |
||||||
|
const [ModalComponent, { openModal }] = useModal(Component) |
||||||
|
const { openModal } = useModal(Component) |
||||||
|
|
||||||
|
openModal(state) |
||||||
|
``` |
||||||
|
|
||||||
|
</v-click> |
||||||
|
|
||||||
|
<!-- |
||||||
|
1. $attrs 是必须的,它会将父组件的 register 传递下去 |
||||||
|
2. 这种用法怎么样(探讨 Modal 新形势) |
||||||
|
--> |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
# Icon |
||||||
|
移除了之前的 `<Icon />` 组件,使用 unocss presetIcon 代替, 图标集:<a href='https://icones.js.org/' target='__blank'>Icones</a> |
||||||
|
|
||||||
|
```html |
||||||
|
<span class='i-ant-design:edit-outlined'></span> |
||||||
|
``` |
||||||
|
|
||||||
|
项目集成了 Icones 中所有的图标集,但下面这些会更常用: |
||||||
|
|
||||||
|
- Ant Design Icons |
||||||
|
- IonIcons |
||||||
|
- Material Design Icons |
||||||
|
- Carbon |
||||||
|
|
||||||
|
<br/> |
||||||
|
|
||||||
|
VsCode Plugins: |
||||||
|
|
||||||
|
- UnoCSS |
||||||
|
- Iconify IntelliSense |
||||||
|
|
||||||
|
<!-- |
||||||
|
1. Icon 是按需引入的(除了 Ant Design Icons) |
||||||
|
2. 项目引入了 Ant Design Icons 所有的图标,用于 IconPicker 组件 |
||||||
|
3. 其他的组件查看代码或者 Vben 文档 |
||||||
|
--> |
||||||
|
|
||||||
|
|
||||||
|
--- |
||||||
|
layout: center |
||||||
|
--- |
||||||
|
|
||||||
|
# 3. 其他 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
# 项目提交规范 |
||||||
|
|
||||||
|
项目使用 git hooks 强制约束代码规范与提交规范: |
||||||
|
|
||||||
|
1. 项目用一个简单的正则来校验 Git Message |
||||||
|
|
||||||
|
```ts |
||||||
|
const commitRE |
||||||
|
= /^(revert: )?(feat|fix|docs|style|refactor|perf|test|build|ci|chore|types|wip|release)(\(.+\))?: .{1,50}/ |
||||||
|
``` |
||||||
|
<br> |
||||||
|
|
||||||
|
2. 使用 `type:check` 校验 TS 类型正确性 (执行时间会稍微有点长) |
||||||
|
|
||||||
|
--- |
||||||
|
layout: image-right |
||||||
|
image: https://source.unsplash.com/collection/94734565/1920x1080 |
||||||
|
--- |
||||||
|
|
||||||
|
# 开源分享 |
||||||
|
|
||||||
|
- [ ] GitHub CICD 流程介绍 |
||||||
|
- [ ] Git 提交规范与 changelog 生成 |
||||||
|
- [ ] BasicForm TS 类型优化 |
||||||
|
- [ ] BasicTable 与 UseTable 泛型支持 |
||||||
|
- [ ] 更多 |
||||||
|
|
||||||
|
<br> |
||||||
|
<br> |
||||||
|
<br> |
||||||
|
|
||||||
|
<a href='https://www.yuque.com/g/yuqueyonghurkd3lk/lfm6ik/collaborator/join?token=QlhaZiT6IAREiGWC&source=book_collaborator# 邀请你共同编辑知识库《开源知识点总结》' target='__blank'> |
||||||
|
语雀 - 开源知识点总结 |
||||||
|
</a> |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
# 下一步需要做的 |
||||||
|
|
||||||
|
1. 升级 Vue、Ant-design 版本 (等待 ant-design 更新) |
||||||
|
2. 解决循序引用问题(复杂度较高) |
||||||
|
3. 树形 Table 不支持异步加载 |
||||||
|
4. BasicTree 组件异步加载不生效(BUG) |
||||||
|
5. 重复组件问题(BasicTree / ApiTree) |
||||||
|
6. 完善系统管理、新增产品、设备、监控页面 |
||||||
|
7. 样式调整? |
||||||
|
|
||||||
|
<!-- |
||||||
|
1. 目前 Table 异步加载,依靠 onExpand 事件实现 |
||||||
|
2. PR 提交,与 review |
||||||
|
--> |
@ -0,0 +1,9 @@ |
|||||||
|
/* eslint-disable no-console */ |
||||||
|
|
||||||
|
// #region snippet
|
||||||
|
function hello() { |
||||||
|
console.log('Hello from snippets/external.ts') |
||||||
|
} |
||||||
|
// #endregion snippet
|
||||||
|
|
||||||
|
export default hello |