CMS 2.0
typescript, vue3, vue-router, vue-i18n, element-plus, lodash, vite, axios, electron, echarts
- app 应用-单例
- current
- project 当前工程
- projectList 工程列表
- project 工程
- current
- page 当前页面
- pageList 页面列表
- page 页面
- document.body
- canvasNode 页面元素节点
- document.body
- page 页面
- current
- project 工程
- current
目录结构与逻辑结构一致
组件代表一个类,首字母大写
修改某个 state.ts
文件后最好刷新浏览器
- src
- store 数据
- state.ts 数据中心
- sdk 开发套件
- var.ts 变量操作
- i18n 国际化
- themes 主题
- components 全局组件(仅放全局通用组件)
- MyComponent.vue
- MyComponent
- MyComponent.vue
- views 视图
- Frame 框架
- Projects 项目管理列表
- Projects.vue
- Project 项目详情
- Vars 变量管理
- Pages 页面管理
- Sidebar 侧边栏
- Editor 页面编辑器
- Board 画板
- Canvas 画布
- CanvasNode.vue 表示一个画布对象的节点,可以是控件或者元素,组合是一个 div 元素
- Selector 控件选择器
- Toolbar 工具栏
- Zoom 画布缩放器
- WidgetLib 控件库
- widgets 内置控件库
- WidgetName 一个控件,包含两个视图
- WidgetName.vue 控件的渲染视图
- WidgetName.settings.vue 控件的设置视图。当前选中的控件此部分会嵌于右侧边栏 WidgetSettings 中
- Chart 图表基础,不显示在面板上,其它图表继承于它
- components
- settings 图表的公共设置组件,其它图表引用。其它图表特有的设置应该放于自己目录下
- ChartXXX 所有图表以 Chart 为前缀
- WidgetName 一个控件,包含两个视图
- widgets 内置控件库
- Canvas 画布
- Settings 右侧边栏
- Style 样式设置
- styleConverter.ts 样式转换器
get('width') => 1
,set('width', 1) => '1px'
- styleConverter.ts 样式转换器
- WidgetSettings 控件设置,具体控件的设置视图的容器
- Events 事件设置
- Style 样式设置
- state.ts 编辑器数据结构
- history.ts 编辑器历史
- Board 画板
- Resource 资源
- Data 数据管理
- Sidebar 侧边栏
- DataAggregation 数据聚合
- VariableTag 变量归档
- store 数据
- 组件 ====> CanvasNode
- 页面控制器 ====> PageManager
- 系统控制器 ====> Project
- 补充对应块的事件 xxxBlock 的 eventList
- 在@/models/block.ts 中补充对应块的 methodList 属性(xxxBlock.methodList)
- 在对应 model 添加该方法
// 第一步
// 例如 给CanvasNodeBlock 添加 缩放 动作
methodList = [
new MethodBlock({
method: 'setZoom', // 方法名
name: '缩放', // 名字
type: '布局尺寸类', // 分类
arguments: [
// 参数。每个参数都需实例一个 ArgumentBlock
new ArgumentBlock({
name: '模式', // 参数显示名
key: 'model', // 字段名
unit: '', // 单位. 数值类有效
type: ArgumentBlock.types.radio, // 参数类型
expression: '"百分比"', // 默认值。js代码格式
// list 的两种方式,value 统一用 js代码格式
list: ['"百分比"', '"绝对尺寸"'], // select radio
// list = [{name: '百分比', value: '"百分比"'}]
}),
],
}),
]
// 参数的可选类型参考:ArgumentBlock.types
// 第二步
// @/models/CanvasNode.ts 添加 setZoom
export class CanvasNode extends Base{
setZoom(arg: Record<string, any){
console.log('模式:' + arg.model)
}
}
注意:异步方法需返回 promise
// 例如 系统控制器 的系统提示方法
export class Project extends Base {
// 只有一个参数, arg: Record<string, any>
toast(args: Record<string, any>) {
toast(args.message, args.type)
}
}
- 拓展事件信息。在@/models/Block.ts 的 CanvasNodeBlock.privateConfig 对象中添加对应信息
privateConfig = {
is: {
eventList: [],
methodList: [],
},
}
// 例如:给表格组件添加 “选中单元格” 事件
privateConfig = {
// 表格组件 私有配置
ChartTable: {
eventList: [
new EventBlock({
type: 'ClickCell', // 首字母需大写, 否则无效
name: '选中单元格',
// 事件参数
detail: [
{
类别: '',
参数: 'event.fielName',
说明: '字段名',
},
{
类别: '',
参数: 'event.fieldValue',
说明: '字段值',
},
],
}),
],
methodList: [],
},
}
- 在 ChartTable 组件中 派发事件
emit('ClickCell', {
fielName: '1111',
fielValue: '2222',
})
- 拓展动作信息。在@/models/Block.ts 的 CanvasNodeBlock.privateConfig 对象中添加对应信息
privateConfig = {
is: {
eventList: [],
methodList: [],
},
}
// 例如:给图片组件添加 “设置路径” 动作
privateConfig = {
// 图片组件 私有配置
Img: {
eventList: [],
methodList: [
new MethodBlock({
method: 'setSrc',
name: '更新地址',
arguments: [
new ArgumentBlock({
type: ArgumentBlock.types.string,
key: 'src',
name: '地址',
expression: '""', // js代码,默认空字符串
}),
],
}),
],
},
}
- 在 Img 组件中 添加对应动作
// 私有动作
function setSrc(options: any) {
props.filename = options.src
}
// !!! 需给CanvasNode实例的methods添加对应的动作
node.methods.setSrc = setSrc
feat: 功能 fix: 修复 style: 样式 text: 文案 docs: 文档 test: 测试 chore: 其它 pref: 优化 refactor: 重构
指明模块(可选) feat(Editor): 描述 fix(request): xxx
bug 写上 #bugId 和简要描述 fix(scope): #12345 简要描述
一般情况下不用区分模式,只需按运行版开发即可。
- js
const props: {
mode?: string // 什么模式
editing?: boolean // 是否编辑模式
running?: boolean // 是否运行模式
// ...
}
// 例如:
if (props.running) {
console.log('现在是运行模式', props.mode)
}
- css
/* 编辑模式 */
.my-widget.mode-editing {
}
/* 运行模式 */
.my-widget.mode-running {
}
export const config = {
permission: true,
}
- 已实现双向数据绑定、虚拟列表、且支持拖动
- 插槽中 data 及 node 对象中的值是一样的
- 注意:目前树对象列表结构较为单一,需有 id、name 属性。_config 对象为 Tree 树列表控件添加的属性
- 注意:插槽中的参数对象 !== 原数组对象
{
id: string
name: string
children: VirtualTree[]
_config: {
_parentId: string
_expand: boolean
_level: number
_isLeaf: boolean
_show: boolean
}
[key: string]: any
}
<!-- 示例 -->
<Tree
draggable
default-expand-all
v-model="state.sheets"
:filter-node-method="filterNode"
:allow-drop="allowDrop"
@node-drop="handleDrop"
@node-click="nodeClick"
>
<template #default="{ node, data }"> {{data.name}} </template>
</Tree>
属性
属性名 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
modelValue | 展示数据 | array | - | - |
props | 配置选项 | object | - | {label: 'name', children: 'children'} |
empty-text | 内容为空的时候展示的文本 | string | - | - |
default-expand-all | 是否默认展开所有节点 | boolean | - | false |
default-expanded-keys | 默认展开的节点的 key 的数组 | array | - | - |
indent | 相邻级节点间的水平缩进,单位为像素 | number | - | 18 |
draggable | 是否开启拖拽节点功能 | boolean | - | false |
allow-drop | 拖拽时判定目标节点能否成为拖动目标位置。 如果返回 false ,拖动节点不能被拖放到目标节点。 type 参数有三种情况:'before'、'inner' 和 'after',分别表示放置在目标节点前、插入至目标节点和放置在目标节点后 | Function(draggingNode, dropNode, type) | - | - |
方法
方法 | 描述 | 参数 |
---|---|---|
filter | 过滤所有树节点,过滤后的节点将被隐藏 | (val) name 属性包含的值 |
getLevel | 获取节点所在层级的序号 | (id) 查找的节点的 id |
setCurrentKey | 通过 id 设置某个节点的当前选中状态 | (id) 待被选节点的 id |
getCurrentNode | 返回当前被选中节点的数据 (如果没有则返回 null) | - |
getNode | 根据 data 或者 key 拿到 Tree 组件中的 node | (data) 节点的 data 或 id |
append | 为 Tree 中的一个节点追加一个子节点 | (data, id) 1. 要追加的子节点的 data 2. 父节点的 id |
insertAfter | 在 Tree 中给定节点后插入一个节点 | (data, id) 1. 要增加的节点的 data 2. 参考节点的 id |
事件
事件名 | 说明 | 回调参数 |
---|---|---|
update:modelValue | 数据更新时被触发 | 更新后的数组对象 |
node-click | 当节点被点击的时候触发 | (node) 对应节点的节点对象 |
toggle-expand | 节点被展开折叠时触发的事件 | (node, isExpand) 1. 节点对应的 node 2. 是否展开 |
node-drop | 拖拽成功完成时触发的事件 | ({draggingNode, targetNode, parentId}) { 被拖拽节点对应的 Node、结束拖拽时最后进入的节点、被拖拽节点的父节点 id } |
./src/api/
此目录废弃
不要把请求代码专门抽出来放在 ./src/api/
下!!保持逻辑内聚
import request from './src/utils/request.ts'
type ResType = 'your type'
/**
* config属性说明
* silent: 当前请求是否静默(不显示loading)。
* */
// get
const res: ResType = await request('url', { params: params, silent: true })
const res: ResType = await request.get('url', { params: params, silent: true })
// post
const res: ResType = await request.post('url', data, { silent: true })
// put
const res: ResType = await request.put('url', data, { silent: true })
// delete
const res: ResType = await request.delete('url', { silent: true })
接口地址 request
中会自动以此为前缀
param:
url?baseURL=http://127.0.0.1:18000
proxy:
# .env.development
VITE_API_URL=http://127.0.0.1:18000
一般情况用 request
发送请求即可。但是某些情况可能要使用到
import { request, baseURL } from './src/utils/request.ts'
baseURL === request.defaults.baseURL
const url = `${baseURL}/path/to/xxx`
目前发现使用element-ui的部分组件会导致内存增长, 在使用过程勿必按下面的方式使用
- el-tooltip, 设置
teleported=true
(默认值为true),persistent=true
(默认值为false); 这里推荐使用封装的组件EllipsisTooltipLabel
,TitleToolTip
- el-select 设置
teleported=true
(默认值为true),persistent=true
(默认值为true) - el-dialog 设置
append-to-body=true
(默认值为false) - el-tree-select 设置
teleported=true
(默认值为true),persistent=true
(默认值为true) - el-tree 使用自研
VirtualTree
组件替换