{{ item.name }}
-
+
-
+
-
+
@@ -59,15 +59,16 @@
ElButton,
ElMessage,
ElCascader,
+ ElIcon,
} from 'element-plus';
- import { useVisualData } from '@/visual-editor/hooks/useVisualData';
+ import { cloneDeep } from 'lodash-es';
+ import { Delete, Edit } from '@element-plus/icons-vue';
+ import { useImportSwaggerJsonModal } from './utils';
import type { FetchApiItem, VisualEditorModel } from '@/visual-editor/visual-editor.utils';
+ import { useVisualData } from '@/visual-editor/hooks/useVisualData';
import { useModal } from '@/visual-editor/hooks/useModal';
- import { cloneDeep } from 'lodash-es';
import { generateNanoid } from '@/visual-editor/utils/';
import { RequestEnum, ContentTypeEnum } from '@/enums/httpEnum';
- import { useImportSwaggerJsonModal } from './utils';
- import { Delete, Edit } from '@element-plus/icons-vue';
interface IState {
activeNames: string[];
@@ -246,6 +247,7 @@
.model-actions {
display: flex;
+
i {
padding: 6px;
margin: 0 2px;
diff --git a/src/visual-editor/components/left-aside/components/data-source/data-model.vue b/src/visual-editor/components/left-aside/components/data-source/data-model.vue
index 22a8d4f..e55a1ab 100644
--- a/src/visual-editor/components/left-aside/components/data-source/data-model.vue
+++ b/src/visual-editor/components/left-aside/components/data-source/data-model.vue
@@ -23,7 +23,7 @@
{{ item.name }}
-
+
-
+
@@ -59,14 +59,15 @@
ElCard,
ElButton,
ElMessage,
+ ElIcon,
} from 'element-plus';
- import { useVisualData, fieldTypes } from '@/visual-editor/hooks/useVisualData';
+ import { cloneDeep } from 'lodash-es';
+ import { Delete, Edit } from '@element-plus/icons-vue';
+ import { useImportSwaggerJsonModal } from './utils';
import type { VisualEditorModel } from '@/visual-editor/visual-editor.utils';
+ import { useVisualData, fieldTypes } from '@/visual-editor/hooks/useVisualData';
import { useModal } from '@/visual-editor/hooks/useModal';
- import { cloneDeep } from 'lodash-es';
import { generateNanoid } from '@/visual-editor/utils/';
- import { useImportSwaggerJsonModal } from './utils';
- import { Delete, Edit } from '@element-plus/icons-vue';
interface IState {
activeNames: string[];
@@ -261,6 +262,7 @@
.model-actions {
display: flex;
+
i {
padding: 6px;
margin: 0 2px;
diff --git a/src/visual-editor/components/left-aside/components/data-source/index.vue b/src/visual-editor/components/left-aside/components/data-source/index.vue
index f64488e..9f34272 100644
--- a/src/visual-editor/components/left-aside/components/data-source/index.vue
+++ b/src/visual-editor/components/left-aside/components/data-source/index.vue
@@ -1,10 +1,10 @@
@@ -17,18 +17,16 @@
-
-
diff --git a/src/visual-editor/components/simulator-editor/simulator-editor.vue b/src/visual-editor/components/simulator-editor/simulator-editor.vue
index 3743809..7de038c 100644
--- a/src/visual-editor/components/simulator-editor/simulator-editor.vue
+++ b/src/visual-editor/components/simulator-editor/simulator-editor.vue
@@ -55,13 +55,13 @@
diff --git a/src/visual-editor/hooks/useDotProp.ts b/src/visual-editor/hooks/useDotProp.ts
index 5729457..2ee5ff2 100644
--- a/src/visual-editor/hooks/useDotProp.ts
+++ b/src/visual-editor/hooks/useDotProp.ts
@@ -6,13 +6,13 @@
* @update: 2021/5/2 19:54
*/
export const useDotProp = (originObj, propName) => {
- const props: string[] = propName.split('.')
- const isDotProp = props.length > 1
- const prop = props.pop()!
- const propObj = props.reduce((prev, curr) => (prev[curr] ??= {}), originObj)
+ const props: string[] = propName.split('.');
+ const isDotProp = props.length > 1;
+ const prop = props.pop()!;
+ const propObj = props.reduce((prev, curr) => (prev[curr] ??= {}), originObj);
return {
prop,
propObj,
- isDotProp
- }
-}
+ isDotProp,
+ };
+};
diff --git a/src/visual-editor/hooks/useModal.tsx b/src/visual-editor/hooks/useModal.tsx
index 00dd9a0..e01af87 100644
--- a/src/visual-editor/hooks/useModal.tsx
+++ b/src/visual-editor/hooks/useModal.tsx
@@ -12,58 +12,58 @@ import {
PropType,
getCurrentInstance,
ComponentInternalInstance,
- isVNode
-} from 'vue'
-import { ElButton, ElDialog } from 'element-plus'
-import { isFunction } from '@/visual-editor/utils/is'
+ isVNode,
+} from 'vue';
+import { ElButton, ElDialog } from 'element-plus';
+import { isFunction } from '@/visual-editor/utils/is';
interface ModalOptions {
- title?: string
- footer?: null | (() => JSX.Element)
- content: ComponentInternalInstance | (() => JSX.Element)
- onConfirm?: () => void
- onCancel?: () => void
+ title?: string;
+ footer?: null | (() => JSX.Element);
+ content: ComponentInternalInstance | (() => JSX.Element);
+ onConfirm?: () => void;
+ onCancel?: () => void;
props?: {
- [propName: string]: any
- }
+ [propName: string]: any;
+ };
}
const Modal = defineComponent({
props: {
options: {
type: Object as PropType
,
- default: () => ({})
- }
+ default: () => ({}),
+ },
},
setup(props) {
- const instance = getCurrentInstance()!
+ const instance = getCurrentInstance()!;
const state = reactive({
options: props.options,
- visible: true
- })
+ visible: true,
+ });
const methods = {
service: (options: ModalOptions) => {
- state.options = options
- methods.show()
+ state.options = options;
+ methods.show();
},
show: () => (state.visible = true),
- hide: () => (state.visible = false)
- }
+ hide: () => (state.visible = false),
+ };
const handler = {
onConfirm: async () => {
- await state.options.onConfirm?.()
- methods.hide()
+ await state.options.onConfirm?.();
+ methods.hide();
},
onCancel: () => {
- state.options.onCancel?.()
- methods.hide()
- }
- }
+ state.options.onCancel?.();
+ methods.hide();
+ },
+ };
- Object.assign(instance.proxy, methods)
+ Object.assign(instance.proxy!, methods);
return () => (
- )
+ ),
}}
- )
- }
-})
+ );
+ },
+});
export const useModal = (() => {
- let instance: any
+ let instance: any;
return (options: ModalOptions) => {
if (instance) {
- instance.service(options)
- return instance
+ instance.service(options);
+ return instance;
}
- const div = document.createElement('div')
- document.body.appendChild(div)
- const app = createApp(Modal, { options })
- instance = app.mount(div)
- return instance
- }
-})()
+ const div = document.createElement('div');
+ document.body.appendChild(div);
+ const app = createApp(Modal, { options });
+ instance = app.mount(div);
+ return instance;
+ };
+})();
diff --git a/src/visual-editor/hooks/useModel.tsx b/src/visual-editor/hooks/useModel.tsx
index ea83102..8f94ce7 100644
--- a/src/visual-editor/hooks/useModel.tsx
+++ b/src/visual-editor/hooks/useModel.tsx
@@ -1,42 +1,42 @@
-import { ref, watch, defineComponent } from 'vue'
+import { ref, watch, defineComponent } from 'vue';
export function useModel
(getter: () => T, emitter: (val: T) => void) {
- const state = ref(getter()) as { value: T }
+ const state = ref(getter()) as { value: T };
watch(getter, (val) => {
if (val !== state.value) {
- state.value = val
+ state.value = val;
}
- })
+ });
return {
get value() {
- return state.value
+ return state.value;
},
set value(val: T) {
if (state.value !== val) {
- state.value = val
- emitter(val)
+ state.value = val;
+ emitter(val);
}
- }
- }
+ },
+ };
}
export const TestUseModel = defineComponent({
props: {
- modelValue: { type: String }
+ modelValue: { type: String },
},
emits: ['update:modelValue'],
setup(props, ctx) {
const model = useModel(
() => props.modelValue,
- (val) => ctx.emit('update:modelValue', val)
- )
+ (val) => ctx.emit('update:modelValue', val),
+ );
return () => (
自定义的输入框
- )
- }
-})
+ );
+ },
+});
diff --git a/src/visual-editor/hooks/useVisualData.ts b/src/visual-editor/hooks/useVisualData.ts
index 96f9ef3..f5f3724 100644
--- a/src/visual-editor/hooks/useVisualData.ts
+++ b/src/visual-editor/hooks/useVisualData.ts
@@ -5,30 +5,30 @@
* @description:useVisualData
* @update: 2021/5/6 11:59
*/
-import { reactive, inject, readonly, computed, watch } from 'vue'
-import type { InjectionKey } from 'vue'
-import { useRoute, useRouter } from 'vue-router'
+import { reactive, inject, readonly, computed, watch } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import type { InjectionKey } from 'vue';
import type {
VisualEditorModelValue,
VisualEditorBlockData,
VisualEditorPage,
FetchApiItem,
- VisualEditorModel
-} from '@/visual-editor/visual-editor.utils'
+ VisualEditorModel,
+} from '@/visual-editor/visual-editor.utils';
-import { visualConfig } from '@/visual.config'
-import { CacheEnum } from '@/enums'
+import { visualConfig } from '@/visual.config';
+import { CacheEnum } from '@/enums';
// 保存到本地JSON数据的key
-export const localKey = CacheEnum.PAGE_DATA_KEY
+export const localKey = CacheEnum.PAGE_DATA_KEY;
// 注入jsonData的key
-export const injectKey: InjectionKey> = Symbol()
+export const injectKey: InjectionKey> = Symbol();
interface IState {
- currentBlock: VisualEditorBlockData // 当前正在操作的组件
- currentPage: VisualEditorPage // 当前正在操作的页面
- jsonData: VisualEditorModelValue // 整棵JSON树
+ currentBlock: VisualEditorBlockData; // 当前正在操作的组件
+ currentPage: VisualEditorPage; // 当前正在操作的页面
+ jsonData: VisualEditorModelValue; // 整棵JSON树
}
/**
@@ -40,125 +40,125 @@ export const createNewPage = ({ title = '新页面', path = '/' }) => ({
config: {
bgColor: '',
bgImage: '',
- keepAlive: false
+ keepAlive: false,
},
- blocks: []
-})
+ blocks: [],
+});
const defaultValue: VisualEditorModelValue = {
pages: {
// 页面
- '/': createNewPage({ title: '首页' })
+ '/': createNewPage({ title: '首页' }),
},
models: [], // 模型实体集合
actions: {
// 动作集合
fetch: {
name: '接口请求',
- apis: []
+ apis: [],
},
dialog: {
name: '对话框',
- handlers: []
- }
- }
-}
+ handlers: [],
+ },
+ },
+};
export const initVisualData = () => {
- const localData = JSON.parse(sessionStorage.getItem(localKey) as string)
+ const localData = JSON.parse(sessionStorage.getItem(localKey) as string);
const jsonData: VisualEditorModelValue = Object.keys(localData?.pages || {}).length
? localData
- : defaultValue
+ : defaultValue;
- const route = useRoute()
- const router = useRouter()
+ const route = useRoute();
+ const router = useRouter();
- console.log('jsonData:', jsonData)
+ console.log('jsonData:', jsonData);
// 所有页面的path都必须以 / 开发
- const getPrefixPath = (path: string) => (path.startsWith('/') ? path : `/${path}`)
+ const getPrefixPath = (path: string) => (path.startsWith('/') ? path : `/${path}`);
- const currentPage = jsonData.pages[route.path]
+ const currentPage = jsonData.pages[route.path];
const state: IState = reactive({
jsonData,
currentPage,
- currentBlock: currentPage?.blocks?.find((item) => item.focus) ?? ({} as VisualEditorBlockData)
- })
- const paths = Object.keys(jsonData.pages)
+ currentBlock: currentPage?.blocks?.find((item) => item.focus) ?? ({} as VisualEditorBlockData),
+ });
+ const paths = Object.keys(jsonData.pages);
- const isExistPath = paths.some((path) => route.path == path)
+ const isExistPath = paths.some((path) => route.path == path);
// 当前页面是否存在
if (!isExistPath) {
- router.replace(paths[0] || '/')
- state.currentPage = jsonData.pages[paths[0]] ?? defaultValue.pages['/']
+ router.replace(paths[0] || '/');
+ state.currentPage = jsonData.pages[paths[0]] ?? defaultValue.pages['/'];
}
// 路由变化时更新当前操作的页面
watch(
() => route.path,
- (url) => setCurrentPage(url)
- )
+ (url) => setCurrentPage(url),
+ );
// 更新page
- const updatePage = ({ newPath, oldPath, page }) => {
- console.log(state.jsonData.pages[oldPath], page)
+ const updatePage = ({ newPath = '', oldPath, page }) => {
+ console.log(state.jsonData.pages[oldPath], page);
if (newPath && newPath != oldPath) {
- page.path = newPath
+ page.path = newPath;
// 如果传了新的路径,则认为是修改页面路由
- state.jsonData.pages[getPrefixPath(newPath)] = { ...state.jsonData.pages[oldPath], ...page }
- deletePage(oldPath, getPrefixPath(newPath))
+ state.jsonData.pages[getPrefixPath(newPath)] = { ...state.jsonData.pages[oldPath], ...page };
+ deletePage(oldPath, getPrefixPath(newPath));
} else {
- Object.assign(state.jsonData.pages[oldPath], page)
+ Object.assign(state.jsonData.pages[oldPath], page);
}
- }
+ };
// 添加page
const incrementPage = (path = '', page: VisualEditorPage) => {
- state.jsonData.pages[getPrefixPath(path)] ??= page ?? createNewPage({ path })
- }
+ state.jsonData.pages[getPrefixPath(path)] ??= page ?? createNewPage({ path });
+ };
// 删除page
const deletePage = (path = '', redirectPath = '') => {
- delete state.jsonData.pages[path]
+ delete state.jsonData.pages[path];
if (redirectPath) {
- setCurrentPage(redirectPath)
+ setCurrentPage(redirectPath);
}
- }
+ };
// 设置当前页面
const setCurrentPage = (path = '/') => {
- state.currentPage = jsonData.pages[path]
+ state.currentPage = jsonData.pages[path];
if (!state.currentPage) {
- state.currentPage = jsonData.pages['/']
- router.replace('/')
+ state.currentPage = jsonData.pages['/'];
+ router.replace('/');
}
- const currentFocusBlock = state.currentPage.blocks.find((item) => item.focus)
- setCurrentBlock(currentFocusBlock ?? ({} as VisualEditorBlockData))
- }
+ const currentFocusBlock = state.currentPage.blocks.find((item) => item.focus);
+ setCurrentBlock(currentFocusBlock ?? ({} as VisualEditorBlockData));
+ };
// 设置当前被操作的组件
const setCurrentBlock = (block: VisualEditorBlockData) => {
- state.currentBlock = block
- }
+ state.currentBlock = block;
+ };
// 更新pages下面的blocks
const updatePageBlock = (path = '', blocks: VisualEditorBlockData[] = []) => {
- state.jsonData.pages[path].blocks = blocks
- }
+ state.jsonData.pages[path].blocks = blocks;
+ };
/**
* @description 新建API接口请求
*/
const incrementFetchApi = (api: FetchApiItem) => {
- state.jsonData.actions.fetch.apis.push(api)
- }
+ state.jsonData.actions.fetch.apis.push(api);
+ };
/**
* @description 删除某个API接口
*/
const deleteFetchApi = (key: string) => {
- const index = state.jsonData.actions.fetch.apis.findIndex((item) => item.key == key)
+ const index = state.jsonData.actions.fetch.apis.findIndex((item) => item.key == key);
if (index !== -1) {
- state.jsonData.actions.fetch.apis.splice(index, 1)
+ state.jsonData.actions.fetch.apis.splice(index, 1);
}
- }
+ };
/**
* @description 更新某个接口或者批量更新接口
@@ -166,34 +166,34 @@ export const initVisualData = () => {
* @param {boolean} isCover 是否覆盖全部接口
*/
const updateFetchApi = (api: FetchApiItem | FetchApiItem[], isCover = false) => {
- const fetch = state.jsonData.actions.fetch
- const apis = Array.isArray(api) ? api : [api]
+ const fetch = state.jsonData.actions.fetch;
+ const apis = Array.isArray(api) ? api : [api];
if (isCover) {
- fetch.apis = apis
+ fetch.apis = apis;
} else {
apis.forEach((apiItem) => {
- const target = fetch.apis.find((item) => item.key == apiItem.key)
- Object.assign(target, api)
- })
+ const target = fetch.apis.find((item) => item.key == apiItem.key);
+ target && Object.assign(target, api);
+ });
}
- }
+ };
/**
* @description 新增模型
*/
const incrementModel = (model: VisualEditorModel) => {
- state.jsonData.models.push(model)
- }
+ state.jsonData.models.push(model);
+ };
/**
* @description 删除某个模型
*/
const deleteModel = (key: string) => {
- const index = state.jsonData.models.findIndex((item) => item.key == key)
+ const index = state.jsonData.models.findIndex((item) => item.key == key);
if (index !== -1) {
- state.jsonData.models.splice(index, 1)
+ state.jsonData.models.splice(index, 1);
}
- }
+ };
/**
* @param { VisualEditorModel | VisualEditorModel[]} model 模型项或模型数组
@@ -201,27 +201,27 @@ export const initVisualData = () => {
* @description 更新某个模型
*/
const updateModel = (model: VisualEditorModel | VisualEditorModel[], isCover = false) => {
- const jsonData = state.jsonData
- const models = Array.isArray(model) ? model : [model]
+ const jsonData = state.jsonData;
+ const models = Array.isArray(model) ? model : [model];
if (isCover) {
- jsonData.models = models
+ jsonData.models = models;
} else {
models.forEach((modelItem) => {
- const index = jsonData.models.findIndex((item) => item.key == modelItem.key)
+ const index = jsonData.models.findIndex((item) => item.key == modelItem.key);
if (index !== -1) {
- state.jsonData.models.splice(index, 1, modelItem)
+ state.jsonData.models.splice(index, 1, modelItem);
}
- })
+ });
}
- }
+ };
// 使用自定义JSON覆盖整个项目
const overrideProject = (jsonData) => {
- state.jsonData = typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData
- }
+ state.jsonData = typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData;
+ };
return {
- visualConfig: visualConfig,
+ visualConfig,
jsonData: readonly(state.jsonData), // 保护JSONData避免直接修改
currentPage: computed(() => state.currentPage),
currentBlock: computed(() => state.currentBlock),
@@ -237,11 +237,11 @@ export const initVisualData = () => {
updatePage,
incrementPage,
deletePage,
- updatePageBlock
- }
-}
+ updatePageBlock,
+ };
+};
-export const useVisualData = () => inject>(injectKey)!
+export const useVisualData = () => inject>(injectKey)!;
/**
* 实体的字段数据类型
@@ -249,18 +249,18 @@ export const useVisualData = () => inject>(inj
export const fieldTypes = [
{
label: '字符串',
- value: 'string'
+ value: 'string',
},
{
label: '数字',
- value: 'number'
+ value: 'number',
},
{
label: '数组',
- value: 'array'
+ value: 'array',
},
{
label: '布尔值',
- value: 'boolean'
- }
-]
+ value: 'boolean',
+ },
+];
diff --git a/src/visual-editor/index.vue b/src/visual-editor/index.vue
index 9304c61..a64736e 100644
--- a/src/visual-editor/index.vue
+++ b/src/visual-editor/index.vue
@@ -33,34 +33,34 @@
diff --git a/src/visual-editor/plugins/command.plugin.ts b/src/visual-editor/plugins/command.plugin.ts
index 4ed1d99..cff9edf 100644
--- a/src/visual-editor/plugins/command.plugin.ts
+++ b/src/visual-editor/plugins/command.plugin.ts
@@ -1,18 +1,18 @@
-import { reactive, onUnmounted } from 'vue'
-import { KeyboardCode } from './keyboard-code'
+import { reactive, onUnmounted } from 'vue';
+import { KeyboardCode } from './keyboard-code';
export interface CommandExecute {
- undo?: () => void
- redo: () => void
+ undo?: () => void;
+ redo: () => void;
}
export interface Command {
- name: string // 命令唯一标识
- keyboard?: string | string[] // 命令监听的快捷键
- execute: (...args: any[]) => CommandExecute // 命令被执行的时候,所做的内容
- followQueue?: boolean // 命令执行完之后,是否需要将命令执行得到的undo,redo存入命令队列
- init?: () => (() => void) | undefined // 命令初始化函数
- data?: any // 命令缓存所需要的数据
+ name: string; // 命令唯一标识
+ keyboard?: string | string[]; // 命令监听的快捷键
+ execute: (...args: any[]) => CommandExecute; // 命令被执行的时候,所做的内容
+ followQueue?: boolean; // 命令执行完之后,是否需要将命令执行得到的undo,redo存入命令队列
+ init?: () => (() => void) | undefined; // 命令初始化函数
+ data?: any; // 命令缓存所需要的数据
}
export function useCommander() {
@@ -21,8 +21,8 @@ export function useCommander() {
queue: [] as CommandExecute[], // 命令队列
commandArray: [] as Command[], // 命令对象数组
commands: {} as Record void>, // 命令对象,方便通过命令的名称调用命令的execute函数,并且执行额外的命令队列的逻辑
- destroyList: [] as ((() => void) | undefined)[] // 组件销毁的时候,需要调用的销毁逻辑数组
- })
+ destroyList: [] as ((() => void) | undefined)[], // 组件销毁的时候,需要调用的销毁逻辑数组
+ });
/**
* 注册一个命令
@@ -30,56 +30,56 @@ export function useCommander() {
* @date 2021/4/22 11:33 下午
*/
const registry = (command: Command) => {
- state.commandArray.push(command)
+ state.commandArray.push(command);
state.commands[command.name] = (...args) => {
- const { undo, redo } = command.execute(...args)
- redo()
+ const { undo, redo } = command.execute(...args);
+ redo();
/*如果命令执行之后,不需要进入命令队列,则直接结束*/
if (command.followQueue === false) {
- return
+ return;
}
/*否则,将命令队列中剩余的命令去除,保留current及其之前的命令*/
- const { queue, current } = state
+ const { queue, current } = state;
if (queue.length > 0) {
- state.queue = queue.slice(0, current + 1)
+ state.queue = queue.slice(0, current + 1);
}
/*设置命令队列中最后一个命令为当前执行的命令*/
- queue.push({ undo, redo })
+ queue.push({ undo, redo });
/*索引+1,指向队列中的最后一个命令*/
- state.current = current + 1
- }
- }
+ state.current = current + 1;
+ };
+ };
const keyboardEvent = (() => {
const onKeydown = (e: KeyboardEvent) => {
if (document.activeElement !== document.body) {
- return
+ return;
}
- const { keyCode, shiftKey, altKey, ctrlKey, metaKey } = e
- const keyString: string[] = []
- if (ctrlKey || metaKey) keyString.push('ctrl')
- if (shiftKey) keyString.push('shift')
- if (altKey) keyString.push('alt')
- keyString.push(KeyboardCode[keyCode])
- const keyNames = keyString.join('+')
+ const { keyCode, shiftKey, altKey, ctrlKey, metaKey } = e;
+ const keyString: string[] = [];
+ if (ctrlKey || metaKey) keyString.push('ctrl');
+ if (shiftKey) keyString.push('shift');
+ if (altKey) keyString.push('alt');
+ keyString.push(KeyboardCode[keyCode]);
+ const keyNames = keyString.join('+');
state.commandArray.forEach(({ keyboard, name }) => {
if (!keyboard) {
- return
+ return;
}
- const keys = Array.isArray(keyboard) ? keyboard : [keyboard]
+ const keys = Array.isArray(keyboard) ? keyboard : [keyboard];
if (keys.indexOf(keyNames) > -1) {
- state.commands[name]()
- e.stopPropagation()
- e.preventDefault()
+ state.commands[name]();
+ e.stopPropagation();
+ e.preventDefault();
}
- })
- }
+ });
+ };
const init = () => {
- window.addEventListener('keydown', onKeydown)
- return () => window.removeEventListener('keydown', onKeydown)
- }
- return init
- })()
+ window.addEventListener('keydown', onKeydown);
+ return () => window.removeEventListener('keydown', onKeydown);
+ };
+ return init;
+ })();
/**
* useCommander初始化函数,负责初始化键盘监听事件,调用命令的初始化逻辑
@@ -89,14 +89,14 @@ export function useCommander() {
const init = () => {
const onKeydown = (_: KeyboardEvent) => {
// console.log('监听到键盘时间')
- }
- window.addEventListener('keydown', onKeydown)
+ };
+ window.addEventListener('keydown', onKeydown);
state.commandArray.forEach(
- (command) => !!command.init && state.destroyList.push(command.init())
- )
- state.destroyList.push(keyboardEvent())
- state.destroyList.push(() => window.removeEventListener('keydown', onKeydown))
- }
+ (command) => !!command.init && state.destroyList.push(command.init()),
+ );
+ state.destroyList.push(keyboardEvent());
+ state.destroyList.push(() => window.removeEventListener('keydown', onKeydown));
+ };
/**
* 注册撤回命令(撤回命令执行结果不需要进入命令队列)
@@ -111,18 +111,18 @@ export function useCommander() {
return {
redo: () => {
if (state.current === -1) {
- return
+ return;
}
- const queueItem = state.queue[state.current]
+ const queueItem = state.queue[state.current];
// console.log('queueItem',queueItem)
if (queueItem) {
- !!queueItem.undo && queueItem.undo()
- state.current--
+ !!queueItem.undo && queueItem.undo();
+ state.current--;
}
- }
- }
- }
- })
+ },
+ };
+ },
+ });
/**
* 注册重做命令(重做命令执行结果不需要进入命令队列)
@@ -136,21 +136,21 @@ export function useCommander() {
execute: () => {
return {
redo: () => {
- const queueItem = state.queue[state.current + 1]
+ const queueItem = state.queue[state.current + 1];
if (queueItem) {
- queueItem.redo()
- state.current++
+ queueItem.redo();
+ state.current++;
}
- }
- }
- }
- })
+ },
+ };
+ },
+ });
- onUnmounted(() => state.destroyList.forEach((fn) => !!fn && fn()))
+ onUnmounted(() => state.destroyList.forEach((fn) => !!fn && fn()));
return {
state,
registry,
- init
- }
+ init,
+ };
}
diff --git a/src/visual-editor/plugins/event.ts b/src/visual-editor/plugins/event.ts
index f499d59..90a3e2c 100644
--- a/src/visual-editor/plugins/event.ts
+++ b/src/visual-editor/plugins/event.ts
@@ -1,17 +1,17 @@
-type SimplyListener = () => void
+type SimplyListener = () => void;
export function createEvent() {
- const listeners: SimplyListener[] = []
+ const listeners: SimplyListener[] = [];
return {
on: (cb: SimplyListener) => {
- listeners.push(cb)
+ listeners.push(cb);
},
off: (cb: SimplyListener) => {
- const index = listeners.indexOf(cb)
- if (index > -1) listeners.splice(index, 1)
+ const index = listeners.indexOf(cb);
+ if (index > -1) listeners.splice(index, 1);
},
emit: () => {
- listeners.forEach((item) => item())
- }
- }
+ listeners.forEach((item) => item());
+ },
+ };
}
diff --git a/src/visual-editor/plugins/keyboard-code.ts b/src/visual-editor/plugins/keyboard-code.ts
index 80337c2..e48a1dc 100644
--- a/src/visual-editor/plugins/keyboard-code.ts
+++ b/src/visual-editor/plugins/keyboard-code.ts
@@ -67,5 +67,5 @@ export const KeyboardCode = {
120: 'F9',
121: 'F10',
122: 'F11',
- 123: 'F12'
-} as Record
+ 123: 'F12',
+} as Record;
diff --git a/src/visual-editor/types/index.d.ts b/src/visual-editor/types/index.d.ts
index da5a81a..d98a1f4 100644
--- a/src/visual-editor/types/index.d.ts
+++ b/src/visual-editor/types/index.d.ts
@@ -10,43 +10,43 @@
declare global {
/** label-value一般用做选项 */
type LabelValue = {
- label: string
- value: any
- }
+ label: string;
+ value: any;
+ };
/** label-value 数组 一般用做选项 */
- type LabelValueOptions = OptionItem[]
+ type LabelValueOptions = OptionItem[];
- type RequestIdleCallbackHandle = any
+ type RequestIdleCallbackHandle = any;
type RequestIdleCallbackDeadline = {
- readonly didTimeout: boolean
- timeRemaining: () => number
- }
+ readonly didTimeout: boolean;
+ timeRemaining: () => number;
+ };
type RequestIdleCallbackOptions = {
- timeout: number
- }
+ timeout: number;
+ };
interface Window {
- $$refs: any
+ $$refs: any;
requestIdleCallback: (
callback: (deadline: RequestIdleCallbackDeadline) => void,
- opts?: RequestIdleCallbackOptions
- ) => RequestIdleCallbackHandle
- cancelIdleCallback: (handle: RequestIdleCallbackHandle) => void
+ opts?: RequestIdleCallbackOptions,
+ ) => RequestIdleCallbackHandle;
+ cancelIdleCallback: (handle: RequestIdleCallbackHandle) => void;
}
}
declare module '@vue/runtime-core' {
export interface ComponentCustomProperties {
- $$refs: any
+ $$refs: any;
}
}
declare module '@vue/runtime-dom' {
export interface CSSProperties {
/** 临时padding变量. */
- tempPadding?: string
+ tempPadding?: string;
}
}
-export {}
+export {};
diff --git a/src/visual-editor/utils/defer.ts b/src/visual-editor/utils/defer.ts
index 8577000..282b0fd 100644
--- a/src/visual-editor/utils/defer.ts
+++ b/src/visual-editor/utils/defer.ts
@@ -1,22 +1,22 @@
interface Defer {
(): {
- resolve: () => void
- reject: () => void
- promise: Promise
- }
+ resolve: () => void;
+ reject: () => void;
+ promise: Promise;
+ };
(): {
- resolve: (val: T) => void
- reject: () => void
- promise: Promise
- }
+ resolve: (val: T) => void;
+ reject: () => void;
+ promise: Promise;
+ };
}
export const defer: Defer = () => {
- const dfd = {} as any
+ const dfd = {} as any;
dfd.promise = new Promise((resolve, reject) => {
- dfd.resolve = resolve as any
- dfd.reject = reject
- })
- return dfd
-}
+ dfd.resolve = resolve as any;
+ dfd.reject = reject;
+ });
+ return dfd;
+};
diff --git a/src/visual-editor/utils/dialog-service.tsx b/src/visual-editor/utils/dialog-service.tsx
index 7890d43..b110977 100644
--- a/src/visual-editor/utils/dialog-service.tsx
+++ b/src/visual-editor/utils/dialog-service.tsx
@@ -1,69 +1,70 @@
-import { defer } from './defer'
-import { defineComponent, PropType, reactive, createApp, getCurrentInstance } from 'vue'
-import { ElInput, ElDialog, ElButton } from 'element-plus'
+import { defineComponent, PropType, reactive, createApp, getCurrentInstance } from 'vue';
+import { ElInput, ElDialog, ElButton } from 'element-plus';
+import { defer } from './defer';
enum DialogServiceEditType {
textarea = 'textarea',
- input = 'input'
+ input = 'input',
}
interface DialogServiceOption {
- title?: string
- editType: DialogServiceEditType
- editReadonly?: boolean
- editValue?: string | null
- onConfirm: (val?: string | null) => void
+ title?: string;
+ editType: DialogServiceEditType;
+ editReadonly?: boolean;
+ editValue?: string | null;
+ onConfirm: (val?: string | null) => void;
}
const keyGenerator = (() => {
- let count = 0
- return () => `auto_key_${count++}`
-})()
+ let count = 0;
+ return () => `auto_key_${count++}`;
+})();
const ServiceComponent = defineComponent({
+ name: 'DialogService',
props: {
- option: { type: Object as PropType, required: true }
+ option: { type: Object as PropType, required: true },
},
setup(props) {
- const ctx = getCurrentInstance()!
+ const ctx = getCurrentInstance()!;
const state = reactive({
option: props.option,
editValue: null as undefined | null | string,
showFlag: false,
- key: keyGenerator()
- })
+ key: keyGenerator(),
+ });
const methods = {
service: (option: DialogServiceOption) => {
- state.option = option
- state.editValue = option.editValue
- state.key = keyGenerator()
- methods.show()
+ state.option = option;
+ state.editValue = option.editValue;
+ state.key = keyGenerator();
+ methods.show();
},
show: () => {
- state.showFlag = true
+ state.showFlag = true;
},
hide: () => {
- state.showFlag = false
- }
- }
+ state.showFlag = false;
+ },
+ };
const handler = {
onConfirm: () => {
- state.option.onConfirm(state.editValue)
- methods.hide()
+ state.option.onConfirm(state.editValue);
+ methods.hide();
},
onCancel: () => {
- methods.hide()
- }
- }
+ methods.hide();
+ },
+ };
- Object.assign(ctx.proxy, methods)
+ Object.assign(ctx.proxy!, methods);
return () => (
<>
-
+
{{
default: () => (
@@ -79,58 +80,58 @@ const ServiceComponent = defineComponent({
取消
确定
- )
+ ),
}}
>
- )
- }
-})
+ );
+ },
+});
const DialogService = (() => {
- let ins: any
+ let ins: any;
return (option: DialogServiceOption) => {
if (!ins) {
- const el = document.createElement('div')
- document.body.appendChild(el)
- const app = createApp(ServiceComponent, { option })
- ins = app.mount(el)
+ const el = document.createElement('div');
+ document.body.appendChild(el);
+ const app = createApp(ServiceComponent, { option });
+ ins = app.mount(el);
}
- ins.service(option)
- }
-})()
+ ins.service(option);
+ };
+})();
export const $$dialog = Object.assign(DialogService, {
input: (
initValue?: string,
title?: string,
- option?: Omit
+ option?: Omit,
) => {
- const dfd = defer()
+ const dfd = defer();
const opt: DialogServiceOption = {
...option,
editType: DialogServiceEditType.input,
onConfirm: dfd.resolve,
editValue: initValue,
- title
- }
- DialogService(opt)
- return dfd.promise
+ title,
+ };
+ DialogService(opt);
+ return dfd.promise;
},
textarea: (
initValue?: string,
title?: string,
- option?: Omit
+ option?: Omit,
) => {
- const dfd = defer()
+ const dfd = defer();
const opt: DialogServiceOption = {
...option,
editType: DialogServiceEditType.textarea,
onConfirm: dfd.resolve,
editValue: initValue,
- title
- }
- DialogService(opt)
- return dfd.promise
- }
-})
+ title,
+ };
+ DialogService(opt);
+ return dfd.promise;
+ },
+});
diff --git a/src/visual-editor/utils/dropdown-service.tsx b/src/visual-editor/utils/dropdown-service.tsx
index 3d693ad..a846735 100644
--- a/src/visual-editor/utils/dropdown-service.tsx
+++ b/src/visual-editor/utils/dropdown-service.tsx
@@ -9,29 +9,29 @@ import {
onBeforeUnmount,
ref,
provide,
- inject
-} from 'vue'
-import './dropdown-sservice.scss'
-import { defer } from './defer'
+ inject,
+} from 'vue';
+import './dropdown-sservice.scss';
+import { defer } from './defer';
interface DropdownServiceOption {
- reference: MouseEvent | HTMLElement
- content: () => JSX.Element
+ reference: MouseEvent | HTMLElement;
+ content: () => JSX.Element;
}
const DropdownServiceProvider = (() => {
- const DROPDOWN_SERVICE_PROVIDER = '@@DROPDOWN_SERVICE_PROVIDER'
+ const DROPDOWN_SERVICE_PROVIDER = '@@DROPDOWN_SERVICE_PROVIDER';
return {
provide: (handler: { onClick: () => void }) => provide(DROPDOWN_SERVICE_PROVIDER, handler),
- inject: () => inject(DROPDOWN_SERVICE_PROVIDER) as { onClick: () => void }
- }
-})()
+ inject: () => inject(DROPDOWN_SERVICE_PROVIDER) as { onClick: () => void },
+ };
+})();
const ServiceComponent = defineComponent({
props: { option: { type: Object as PropType, required: true } },
setup(props) {
- const ctx = getCurrentInstance()!
- const el = ref>()
+ const ctx = getCurrentInstance()!;
+ const el = ref>();
const state = reactive({
option: props.option,
@@ -39,105 +39,107 @@ const ServiceComponent = defineComponent({
top: 0,
left: 0,
mounted: (() => {
- const dfd = defer()
- onMounted(() => setTimeout(() => dfd.resolve(), 0))
- return dfd.promise
- })()
- })
+ const dfd = defer();
+ onMounted(() => setTimeout(() => dfd.resolve(), 0));
+ return dfd.promise;
+ })(),
+ });
const service = (option: DropdownServiceOption) => {
- state.option = option
+ state.option = option;
if ('addEventListener' in option.reference) {
- const { top, left, height } = option.reference.getBoundingClientRect()!
- state.top = top + height
- state.left = left
+ const { top, left, height } = option.reference.getBoundingClientRect()!;
+ state.top = top + height;
+ state.left = left;
} else {
- const { clientX, clientY } = option.reference
- state.left = clientX
- state.top = clientY
+ const { clientX, clientY } = option.reference;
+ state.left = clientX;
+ state.top = clientY;
}
- methods.show()
- }
+ methods.show();
+ };
const methods = {
show: async () => {
- await state.mounted
- state.showFlag = true
+ await state.mounted;
+ state.showFlag = true;
},
hide: () => {
- state.showFlag = false
- }
- }
+ state.showFlag = false;
+ },
+ };
const classes = computed(() => [
'dropdown-service',
{
- 'dropdown-service-show': state.showFlag
- }
- ])
+ 'dropdown-service-show': state.showFlag,
+ },
+ ]);
const styles = computed(() => ({
top: `${state.top}px`,
- left: `${state.left}px`
- }))
+ left: `${state.left}px`,
+ }));
- Object.assign(ctx.proxy, { service })
+ Object.assign(ctx.proxy!, { service });
const onMousedownDocument = (e: MouseEvent) => {
if (!el.value?.contains(e.target as HTMLElement)) {
- methods.hide()
+ methods.hide();
}
- }
+ };
- onMounted(() => document.body.addEventListener('mousedown', onMousedownDocument, true))
- onBeforeUnmount(() => document.body.removeEventListener('mousedown', onMousedownDocument, true))
+ onMounted(() => document.body.addEventListener('mousedown', onMousedownDocument, true));
+ onBeforeUnmount(() =>
+ document.body.removeEventListener('mousedown', onMousedownDocument, true),
+ );
- DropdownServiceProvider.provide({ onClick: methods.hide })
+ DropdownServiceProvider.provide({ onClick: methods.hide });
return () => (
{state.option.content()}
- )
- }
-})
+ );
+ },
+});
export const DropdownOption = defineComponent({
props: {
label: { type: String },
- icon: { type: String }
+ icon: { type: String },
},
emits: ['click'],
setup(props, ctx) {
- const { onClick: dropdownClickHandler } = DropdownServiceProvider.inject()
+ const { onClick: dropdownClickHandler } = DropdownServiceProvider.inject();
const handler = {
onClick: (e: MouseEvent) => {
- ctx.emit('click', e)
- dropdownClickHandler()
- }
- }
+ ctx.emit('click', e);
+ dropdownClickHandler();
+ },
+ };
return () => (
{props.label}
- )
- }
-})
+ );
+ },
+});
export const $$dropdown = (() => {
- let ins: any
+ let ins: any;
return (option: DropdownServiceOption) => {
if (!ins) {
- const el = document.createElement('div')
- document.body.appendChild(el)
- const app = createApp(ServiceComponent, { option })
- ins = app.mount(el)
+ const el = document.createElement('div');
+ document.body.appendChild(el);
+ const app = createApp(ServiceComponent, { option });
+ ins = app.mount(el);
}
- ins.service(option)
- }
-})()
+ ins.service(option);
+ };
+})();
diff --git a/src/visual-editor/utils/index.ts b/src/visual-editor/utils/index.ts
index 2ea6cb3..f28e4c5 100644
--- a/src/visual-editor/utils/index.ts
+++ b/src/visual-editor/utils/index.ts
@@ -6,14 +6,14 @@
* @Description: 公用的工具函数
* @FilePath: \vite-vue3-lowcode\src\visual-editor\utils\index.ts
*/
-import { customAlphabet } from 'nanoid'
+import { customAlphabet } from 'nanoid';
/**
* @description 部署应用时的基本URL
*/
-export const BASE_URL = import.meta.env.BASE_URL
+export const BASE_URL = import.meta.env.BASE_URL;
/**
* @description 生成nanoid
*/
-export const generateNanoid = customAlphabet('1234567890abcdef', 10)
+export const generateNanoid = customAlphabet('1234567890abcdef', 10);
diff --git a/src/visual-editor/utils/is.ts b/src/visual-editor/utils/is.ts
index 7512caf..79941f9 100644
--- a/src/visual-editor/utils/is.ts
+++ b/src/visual-editor/utils/is.ts
@@ -1,94 +1,99 @@
-const toString = Object.prototype.toString
+const toString = Object.prototype.toString;
export function is(val: unknown, type: string) {
- return toString.call(val) === `[object ${type}]`
+ return toString.call(val) === `[object ${type}]`;
}
export function isDef(val?: T): val is T {
- return typeof val !== 'undefined'
+ return typeof val !== 'undefined';
}
export function isUnDef(val?: T): val is T {
- return !isDef(val)
+ return !isDef(val);
}
export function isObject(val: any): val is Record {
- return val !== null && is(val, 'Object')
+ return val !== null && is(val, 'Object');
}
export function isEmpty(val: T): val is T {
if (isArray(val) || isString(val)) {
- return val.length === 0
+ return val.length === 0;
}
if (val instanceof Map || val instanceof Set) {
- return val.size === 0
+ return val.size === 0;
}
if (isObject(val)) {
- return Object.keys(val).length === 0
+ return Object.keys(val).length === 0;
}
- return false
+ return false;
}
export function isDate(val: unknown): val is Date {
- return is(val, 'Date')
+ return is(val, 'Date');
}
export function isNull(val: unknown): val is null {
- return val === null
+ return val === null;
}
export function isNullAndUnDef(val: unknown): val is null | undefined {
- return isUnDef(val) && isNull(val)
+ return isUnDef(val) && isNull(val);
}
export function isNullOrUnDef(val: unknown): val is null | undefined {
- return isUnDef(val) || isNull(val)
+ return isUnDef(val) || isNull(val);
}
export function isNumber(val: unknown): val is number {
- return is(val, 'Number')
+ return is(val, 'Number');
}
export function isPromise(val: unknown): val is Promise {
- return is(val, 'Promise') && isObject(val) && isFunction(val.then) && isFunction(val.catch)
+ return is(val, 'Promise') && isObject(val) && isFunction(val.then) && isFunction(val.catch);
}
export function isString(val: unknown): val is string {
- return is(val, 'String')
+ return is(val, 'String');
}
export function isFunction(val: unknown): val is Function {
- return typeof val === 'function'
+ return typeof val === 'function';
}
export function isBoolean(val: unknown): val is boolean {
- return is(val, 'Boolean')
+ return is(val, 'Boolean');
}
export function isRegExp(val: unknown): val is RegExp {
- return is(val, 'RegExp')
+ return is(val, 'RegExp');
}
export function isArray(val: any): val is Array {
- return val && Array.isArray(val)
+ return val && Array.isArray(val);
}
export function isWindow(val: any): val is Window {
- return typeof window !== 'undefined' && is(val, 'Window')
+ return typeof window !== 'undefined' && is(val, 'Window');
}
export function isElement(val: unknown): val is Element {
- return isObject(val) && !!val.tagName
+ return isObject(val) && !!val.tagName;
}
-export const isServer = typeof window === 'undefined'
+export function isMap(val: unknown): val is Map {
+ return is(val, 'Map');
+}
+
+export const isServer = typeof window === 'undefined';
-export const isClient = !isServer
+export const isClient = !isServer;
export function isUrl(path: string): boolean {
- const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/
- return reg.test(path)
+ const reg =
+ /(((^https?:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
+ return reg.test(path);
}
diff --git a/src/visual-editor/visual-editor.props.tsx b/src/visual-editor/visual-editor.props.tsx
index 32a004e..7b40a7c 100644
--- a/src/visual-editor/visual-editor.props.tsx
+++ b/src/visual-editor/visual-editor.props.tsx
@@ -14,101 +14,101 @@ export enum VisualEditorPropsType {
/** 模型绑定选择器 */
modelBind = 'ModelBind',
/** 可拖拽项 */
- crossSortable = 'CrossSortable'
+ crossSortable = 'CrossSortable',
}
export type VisualEditorProps = {
- type: VisualEditorPropsType
+ type: VisualEditorPropsType;
/** 表单项标签名称 */
- label: string
+ label: string;
/** 表单项提示说明 */
- tips?: string
+ tips?: string;
/** 表单域标签的位置 */
- labelPosition?: string
+ labelPosition?: string;
/** 表单项默认值 */
- defaultValue?: any
+ defaultValue?: any;
} & {
/** 可选项 */
- options?: VisualEditorSelectOptions
+ options?: VisualEditorSelectOptions;
/** 是否可以多选 */
- multiple?: boolean
+ multiple?: boolean;
/** 项属性配置 */
- showItemPropsConfig?: boolean
+ showItemPropsConfig?: boolean;
} & {
- max?: number
- min?: number
+ max?: number;
+ min?: number;
} & {
- table?: VisualEditorTableOption
-}
+ table?: VisualEditorTableOption;
+};
/*---------------------------------------modelBind-------------------------------------------*/
interface EditorModelBindProp {
- label: string
- defaultValue?: any
- tips?: string
+ label: string;
+ defaultValue?: any;
+ tips?: string;
}
export function createEditorModelBindProp({
label = '字段绑定',
defaultValue,
- tips
+ tips,
}: EditorModelBindProp): VisualEditorProps {
return {
type: VisualEditorPropsType.modelBind,
label,
tips,
- defaultValue
- }
+ defaultValue,
+ };
}
/*---------------------------------------switch-------------------------------------------*/
interface EditorSwitchProp {
- label: string
- defaultValue?: boolean
- tips?: string
+ label: string;
+ defaultValue?: boolean;
+ tips?: string;
}
export function createEditorSwitchProp({
label,
defaultValue,
- tips
+ tips,
}: EditorSwitchProp): VisualEditorProps {
return {
type: VisualEditorPropsType.switch,
label,
tips,
- defaultValue
- }
+ defaultValue,
+ };
}
/*---------------------------------------input-------------------------------------------*/
interface EditorInputProp {
- label: string
- defaultValue?: any
- tips?: string
+ label: string;
+ defaultValue?: any;
+ tips?: string;
}
export function createEditorInputProp({
label,
defaultValue,
- tips
+ tips,
}: EditorInputProp): VisualEditorProps {
return {
type: VisualEditorPropsType.input,
label,
tips,
- defaultValue
- }
+ defaultValue,
+ };
}
/*---------------------------------------InputNumber -------------------------------------------*/
interface EditorInputNumberProp {
- label: string
- defaultValue?: any
- tips?: string
- max?: number
- min?: number
+ label: string;
+ defaultValue?: any;
+ tips?: string;
+ max?: number;
+ min?: number;
}
export function createEditorInputNumberProp({
@@ -116,7 +116,7 @@ export function createEditorInputNumberProp({
defaultValue,
max,
min,
- tips
+ tips,
}: EditorInputNumberProp): VisualEditorProps {
return {
type: VisualEditorPropsType.inputNumber,
@@ -124,39 +124,39 @@ export function createEditorInputNumberProp({
tips,
max,
min,
- defaultValue
- }
+ defaultValue,
+ };
}
/*---------------------------------------color-------------------------------------------*/
interface EditorColorProp {
- label: string
- defaultValue?: string
+ label: string;
+ defaultValue?: string;
}
export function createEditorColorProp({ label, defaultValue }: EditorColorProp): VisualEditorProps {
return {
type: VisualEditorPropsType.color,
label,
- defaultValue
- }
+ defaultValue,
+ };
}
/*---------------------------------------select-------------------------------------------*/
export type VisualEditorSelectOptions = {
- label: string
- value: string | number | boolean | object
- [prop: string]: any
-}[]
+ label: string;
+ value: string | number | boolean | object;
+ [prop: string]: any;
+}[];
interface EditorSelectProp {
- label: string
- options: VisualEditorSelectOptions
- defaultValue?: any
- multiple?: boolean
- tips?: string
+ label: string;
+ options: VisualEditorSelectOptions;
+ defaultValue?: any;
+ multiple?: boolean;
+ tips?: string;
}
export function createEditorSelectProp({
@@ -164,7 +164,7 @@ export function createEditorSelectProp({
options,
defaultValue,
tips,
- multiple
+ multiple,
}: EditorSelectProp): VisualEditorProps {
return {
type: VisualEditorPropsType.select,
@@ -172,47 +172,47 @@ export function createEditorSelectProp({
defaultValue,
tips,
options,
- multiple
- }
+ multiple,
+ };
}
/*---------------------------------------table-------------------------------------------*/
export type VisualEditorTableOption = {
options: {
- label: string // 列显示文本
- field: string // 列绑定的字段
- }[]
- showKey: string
-}
+ label: string; // 列显示文本
+ field: string; // 列绑定的字段
+ }[];
+ showKey: string;
+};
interface EditorTableProp {
- label: string
- option: VisualEditorTableOption
- defaultValue?: { label: string; value: string }[]
+ label: string;
+ option: VisualEditorTableOption;
+ defaultValue?: { label: string; value: string }[];
}
export function createEditorTableProp({
label,
option,
- defaultValue
+ defaultValue,
}: EditorTableProp): VisualEditorProps {
return {
type: VisualEditorPropsType.table,
label,
table: option,
- defaultValue
- }
+ defaultValue,
+ };
}
/*---------------------------------------CrossSortableOptions-------------------------------------------*/
interface EditorCrossSortableProp {
- label: string
- labelPosition: 'top' | ''
- multiple?: boolean
- showItemPropsConfig?: boolean
- defaultValue?: string[] | VisualEditorSelectOptions
+ label: string;
+ labelPosition: 'top' | '';
+ multiple?: boolean;
+ showItemPropsConfig?: boolean;
+ defaultValue?: string[] | VisualEditorSelectOptions;
}
export function createEditorCrossSortableProp({
@@ -220,7 +220,7 @@ export function createEditorCrossSortableProp({
labelPosition,
multiple,
showItemPropsConfig,
- defaultValue
+ defaultValue,
}: EditorCrossSortableProp): VisualEditorProps {
return {
type: VisualEditorPropsType.crossSortable,
@@ -228,6 +228,6 @@ export function createEditorCrossSortableProp({
multiple,
showItemPropsConfig,
labelPosition,
- defaultValue
- }
+ defaultValue,
+ };
}
diff --git a/src/visual-editor/visual-editor.utils.ts b/src/visual-editor/visual-editor.utils.ts
index cb1812b..02bbdb5 100644
--- a/src/visual-editor/visual-editor.utils.ts
+++ b/src/visual-editor/visual-editor.utils.ts
@@ -1,8 +1,8 @@
-import type { VisualEditorProps } from './visual-editor.props';
import { inject, provide } from 'vue';
+import type { VisualEditorProps } from './visual-editor.props';
import type { CSSProperties } from 'vue';
-import { useDotProp } from '@/visual-editor/hooks/useDotProp';
import type { RequestEnum, ContentTypeEnum } from '@/enums/httpEnum';
+import { useDotProp } from '@/visual-editor/hooks/useDotProp';
import { generateNanoid } from '@/visual-editor/utils';
/**
diff --git a/src/visual.config.tsx b/src/visual.config.tsx
index f787abc..aa3b80c 100644
--- a/src/visual.config.tsx
+++ b/src/visual.config.tsx
@@ -1,20 +1,20 @@
-import { createVisualEditorConfig } from './visual-editor/visual-editor.utils'
-import baseWidgets from '@/packages/base-widgets'
-import containerComponent from '@/packages/container-component'
+import { createVisualEditorConfig } from './visual-editor/visual-editor.utils';
+import baseWidgets from '@/packages/base-widgets';
+import containerComponent from '@/packages/container-component';
-export const visualConfig = createVisualEditorConfig()
+export const visualConfig = createVisualEditorConfig();
// 注册基础控件
Object.keys(baseWidgets).forEach((name: string) =>
- visualConfig.registry('baseWidgets', name, baseWidgets[name])
-)
+ visualConfig.registry('baseWidgets', name, baseWidgets[name]),
+);
// 注册容器组件
Object.keys(containerComponent).forEach((name: string) =>
- visualConfig.registry('containerComponents', name, containerComponent[name])
-)
+ visualConfig.registry('containerComponents', name, containerComponent[name]),
+);
console.log(
- '%c成功加载组件数量:' + Object.keys(visualConfig.componentMap).length,
- 'color:#409EFF;background-color:#ecf5ff;padding:0 10px;line-height:2;margin-bottom:4px;'
-)
+ `%c成功加载组件数量:${Object.keys(visualConfig.componentMap).length}`,
+ 'color:#409EFF;background-color:#ecf5ff;padding:0 10px;line-height:2;margin-bottom:4px;',
+);
-console.log('visualConfig:', visualConfig)
+console.log('visualConfig:', visualConfig);
diff --git a/stylelint.config.js b/stylelint.config.js
index 7f9eadd..eff1f87 100644
--- a/stylelint.config.js
+++ b/stylelint.config.js
@@ -4,6 +4,7 @@ module.exports = {
customSyntax: 'postcss-html',
extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
rules: {
+ 'function-no-unknown': null,
'selector-class-pattern': null,
'selector-pseudo-class-no-unknown': [
true,
@@ -35,6 +36,7 @@ module.exports = {
},
],
'no-empty-source': null,
+ 'string-quotes': null,
'named-grid-areas-no-invalid': null,
'unicode-bom': 'never',
'no-descending-specificity': null,
@@ -89,5 +91,10 @@ module.exports = {
],
},
},
+ {
+ files: ['*.scss', '**/*.scss'],
+ customSyntax: 'postcss-scss',
+ extends: ['stylelint-config-standard', 'stylelint-config-recommended-vue'],
+ },
],
};
diff --git a/tsconfig.json b/tsconfig.json
index 31f1c02..570a0c7 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -24,26 +24,12 @@
"removeComments": false,
"strictFunctionTypes": false,
"baseUrl": ".",
- "types": [
- "vite/client",
- "node",
- "element-plus/global"
- ],
- "typeRoots": [
- "./node_modules/@types/",
- "./types"
- ],
+ "types": ["vite/client", "node", "element-plus/global", "unplugin-vue-define-options"],
+ "typeRoots": ["./node_modules/@types/", "./types"],
"paths": {
- "@/*": [
- "src/*"
- ]
+ "@/*": ["src/*"]
},
- "lib": [
- "esnext",
- "dom",
- "dom.iterable",
- "scripthost"
- ]
+ "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
},
"include": [
"src/**/*.ts",
@@ -59,8 +45,5 @@
"components.d.ts",
"auto-imports.d.ts"
],
- "exclude": [
- "node_modules",
- "dist"
- ]
+ "exclude": ["node_modules", "dist"]
}
diff --git a/types/shims/shims-tsx.d.ts b/types/shims/shims-tsx.d.ts
index 22dc021..ebc7400 100644
--- a/types/shims/shims-tsx.d.ts
+++ b/types/shims/shims-tsx.d.ts
@@ -1,18 +1,18 @@
-import Vue, { VNode } from 'vue'
+import Vue, { VNode } from 'vue';
declare module '*.tsx' {
- import Vue from 'compatible-vue'
- export default Vue
+ import Vue from 'compatible-vue';
+ export default Vue;
}
declare global {
namespace JSX {
// tslint:disable no-empty-interface
- type Element = VNode
+ type Element = VNode;
// tslint:disable no-empty-interface
- type ElementClass = Vue
+ type ElementClass = Vue;
interface IntrinsicElements {
- [elem: string]: any
+ [elem: string]: any;
}
}
}
diff --git a/vite.config.ts b/vite.config.ts
index 45e6c52..43c1064 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,12 +1,14 @@
+import { resolve } from 'path';
import { ConfigEnv, loadEnv, UserConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import legacy from '@vitejs/plugin-legacy';
-import { resolve } from 'path';
import { ElementPlusResolver, VantResolver } from 'unplugin-vue-components/resolvers';
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import WindiCSS from 'vite-plugin-windicss';
+import checker from 'vite-plugin-checker';
+import DefineOptions from 'unplugin-vue-define-options/vite';
const CWD = process.cwd();
@@ -31,7 +33,7 @@ export default ({ mode }: ConfigEnv): UserConfig => {
},
},
// TODO 构建包含@charset问题 https://github.com/vitejs/vite/issues/5833
- charset: false,
+ // charset: false,
postcss: {
plugins: [
{
@@ -51,9 +53,12 @@ export default ({ mode }: ConfigEnv): UserConfig => {
vue(),
vueJsx(),
WindiCSS(),
+ // https://github.com/sxzz/unplugin-vue-define-options
+ DefineOptions(),
legacy({
targets: ['defaults', 'not IE 11'],
}),
+ // https://github.com/antfu/unplugin-auto-import#readme
AutoImport({
include: [
/\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
@@ -68,6 +73,14 @@ export default ({ mode }: ConfigEnv): UserConfig => {
dts: true,
resolvers: [ElementPlusResolver(), VantResolver()],
}),
+ // https://github.com/fi3ework/vite-plugin-checker
+ checker({
+ typescript: true,
+ // vueTsc: true,
+ eslint: {
+ lintCommand: 'eslint "./src/**/*.{.vue,ts,tsx}"', // for example, lint .ts & .tsx
+ },
+ }),
],
resolve: {
alias: [
diff --git a/windi.config.ts b/windi.config.ts
index 4291bf8..aa247ee 100644
--- a/windi.config.ts
+++ b/windi.config.ts
@@ -1,6 +1,6 @@
-import { defineConfig } from 'vite-plugin-windicss'
-import colors from 'windicss/colors'
-import typography from 'windicss/plugin/typography'
+import { defineConfig } from 'vite-plugin-windicss';
+import colors from 'windicss/colors';
+import typography from 'windicss/plugin/typography';
export default defineConfig({
darkMode: 'class',
@@ -19,8 +19,8 @@ export default defineConfig({
textDecoration: 'underline',
'&:hover': {
opacity: 1,
- color: colors.teal[600]
- }
+ color: colors.teal[600],
+ },
},
b: { color: 'inherit' },
strong: { color: 'inherit' },
@@ -29,10 +29,10 @@ export default defineConfig({
h2: { color: 'inherit' },
h3: { color: 'inherit' },
h4: { color: 'inherit' },
- code: { color: 'inherit' }
- }
- }
- }
- }
- }
-})
+ code: { color: 'inherit' },
+ },
+ },
+ },
+ },
+ },
+});