diff --git a/magic-api-plugin-component/pom.xml b/magic-api-plugin-component/pom.xml new file mode 100644 index 0000000..e671d42 --- /dev/null +++ b/magic-api-plugin-component/pom.xml @@ -0,0 +1,82 @@ + + + 4.0.0 + + org.ssssssss + magic-api-plugins + 2.0.0 + + + magic-api-plugin-component + jar + magic-api-plugin-component + magic-api-plugin-component + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.6.0 + + + exec-npm-install + generate-resources + + exec + + + npm + + install + + ${basedir}/src/console + + + + exec-npm-run-build + generate-resources + + exec + + + npm + + run + build + + ${basedir}/src/console + + + + + + + + maven-resources-plugin + 3.2.0 + + + copy-resource + generate-resources + + copy-resources + + + ${basedir}/target/classes/magic-editor/plugins + + + ${basedir}/src/console/dist + + + + + + + + + + diff --git a/magic-api-plugin-component/src/console/package.json b/magic-api-plugin-component/src/console/package.json new file mode 100644 index 0000000..cb4ae01 --- /dev/null +++ b/magic-api-plugin-component/src/console/package.json @@ -0,0 +1,18 @@ +{ + "name": "magic-component", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "vite build" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "vue": "^3.2.31", + "@vitejs/plugin-vue": "^2.2.4", + "vite-plugin-svg-icons": "^1.1.0", + "vite": "^2.8.6" + } +} diff --git a/magic-api-plugin-component/src/console/src/components/magic-component-info.vue b/magic-api-plugin-component/src/console/src/components/magic-component-info.vue new file mode 100644 index 0000000..440b9f4 --- /dev/null +++ b/magic-api-plugin-component/src/console/src/components/magic-component-info.vue @@ -0,0 +1,39 @@ + + + diff --git a/magic-api-plugin-component/src/console/src/i18n/en.js b/magic-api-plugin-component/src/console/src/i18n/en.js new file mode 100644 index 0000000..e5c0292 --- /dev/null +++ b/magic-api-plugin-component/src/console/src/i18n/en.js @@ -0,0 +1,14 @@ +export default { + component: { + title: 'Component Info', + name: 'Component', + form: { + componentName: 'Component Name', + description: 'Component Description', + placeholder: { + componentName: 'Please Enter Component Name', + description: 'Please Enter Component Description' + } + } + }, +} diff --git a/magic-api-plugin-component/src/console/src/i18n/zh-cn.js b/magic-api-plugin-component/src/console/src/i18n/zh-cn.js new file mode 100644 index 0000000..f2114f5 --- /dev/null +++ b/magic-api-plugin-component/src/console/src/i18n/zh-cn.js @@ -0,0 +1,14 @@ +export default { + component: { + title: '组件信息', + name: '组件', + form: { + componentName: '组件名称', + description: '组件描述', + placeholder: { + componentName: '请输入组件名称', + description: '请输入组件描述' + } + } + } +} diff --git a/magic-api-plugin-component/src/console/src/icons/component.svg b/magic-api-plugin-component/src/console/src/icons/component.svg new file mode 100644 index 0000000..3753bde --- /dev/null +++ b/magic-api-plugin-component/src/console/src/icons/component.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/magic-api-plugin-component/src/console/src/index.js b/magic-api-plugin-component/src/console/src/index.js new file mode 100644 index 0000000..dff880b --- /dev/null +++ b/magic-api-plugin-component/src/console/src/index.js @@ -0,0 +1,35 @@ +import MagicComponent from './service/magic-component.js' +import localZhCN from './i18n/zh-cn.js' +import localEn from './i18n/en.js' +import MagicComponentInfo from './components/magic-component-info.vue' +import 'vite-plugin-svg-icons/register' +export default (opt) => { + const i18n = opt.i18n + // 添加i18n 国际化信息 + i18n.add('zh-cn', localZhCN) + i18n.add('en', localEn) + return { + // 左侧资源 + resource: [{ + // 资源类型,和后端存储结构一致 + type: 'component', + // 展示图标 + icon: '#magic-component-component', // #开头表示图标在插件中 + // 展示名称 + title: 'component.name', + // 运行服务 + service: MagicComponent(opt.bus, opt.constants, i18n.format, opt.Message, opt.request), + }], + // 底部工具条 + toolbars: [{ + // 当打开的资源类型为 task 时显示 + type: 'component', + // 工具条展示的标题 + title: 'component.title', + // 展示图标 + icon: 'parameter', + // 对应的组件 + component: MagicComponentInfo, + }] + } +} diff --git a/magic-api-plugin-component/src/console/src/service/magic-component.js b/magic-api-plugin-component/src/console/src/service/magic-component.js new file mode 100644 index 0000000..87cc2bc --- /dev/null +++ b/magic-api-plugin-component/src/console/src/service/magic-component.js @@ -0,0 +1,26 @@ +export default function (bus, constants, $i, Message, request) { + return { + // svg text + getIcon: item => ['COMPONENT', '#9012FE'], + // 任务名称 + name: $i('component.name'), + // 脚本语言 + language: 'html', + // 默认脚本 + defaultScript: ` + +`, + // 是否允许执行测试 + runnable: false, + // 是否需要填写路径 + requirePath: false, + // 合并 + merge: item => item + } +} diff --git a/magic-api-plugin-component/src/console/vite.config.js b/magic-api-plugin-component/src/console/vite.config.js new file mode 100644 index 0000000..a4da66b --- /dev/null +++ b/magic-api-plugin-component/src/console/vite.config.js @@ -0,0 +1,37 @@ +import vue from '@vitejs/plugin-vue' +import viteSvgIcons from 'vite-plugin-svg-icons' +import path from 'path' +import pkg from './package.json' + +export default { + base: './', + build: { + minify: false, + cssCodeSplit: true, // 将组件的 style 打包到 js 文件中 + outDir: 'dist', + lib: { + target: 'esnext', + formats: ['iife'], + entry: path.resolve(__dirname, 'src/index.js'), + name: 'MagicComponent', + fileName: (format) => `magic-component.${pkg.version}.${format}.js` + }, + rollupOptions: { + // 确保外部化处理那些你不想打包进库的依赖 + external: ['vue'], + output: { + // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量 + globals: { + vue: 'Vue' + } + } + } + }, + plugins: [ + vue(), + viteSvgIcons({ + iconDirs: [path.resolve(process.cwd(), 'src/icons')], + symbolId: 'magic-component-[name]' + }), + ] +} diff --git a/magic-api-plugin-component/src/main/java/org/ssssssss/magicapi/component/model/ComponentInfo.java b/magic-api-plugin-component/src/main/java/org/ssssssss/magicapi/component/model/ComponentInfo.java new file mode 100644 index 0000000..c9399c5 --- /dev/null +++ b/magic-api-plugin-component/src/main/java/org/ssssssss/magicapi/component/model/ComponentInfo.java @@ -0,0 +1,55 @@ +package org.ssssssss.magicapi.component.model; + +import org.ssssssss.magicapi.core.model.MagicEntity; +import org.ssssssss.magicapi.core.model.PathMagicEntity; + +import java.util.Objects; + +public class ComponentInfo extends PathMagicEntity { + + /** + * 组件描述 + */ + private String description; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public ComponentInfo copy() { + ComponentInfo info = new ComponentInfo(); + super.copyTo(info); + info.setDescription(this.description); + return info; + } + + @Override + public MagicEntity simple() { + ComponentInfo info = new ComponentInfo(); + super.simple(info); + return info; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + ComponentInfo componentInfo = (ComponentInfo) o; + return Objects.equals(id, componentInfo.id) && + Objects.equals(path, componentInfo.path) && + Objects.equals(script, componentInfo.script) && + Objects.equals(name, componentInfo.name) && + Objects.equals(description, componentInfo.description); + } + + @Override + public int hashCode() { + return Objects.hash(id, path, script, name, groupId, description); + } + +} diff --git a/magic-api-plugin-component/src/main/java/org/ssssssss/magicapi/component/service/ComponentInfoMagicResourceStorage.java b/magic-api-plugin-component/src/main/java/org/ssssssss/magicapi/component/service/ComponentInfoMagicResourceStorage.java new file mode 100644 index 0000000..16066eb --- /dev/null +++ b/magic-api-plugin-component/src/main/java/org/ssssssss/magicapi/component/service/ComponentInfoMagicResourceStorage.java @@ -0,0 +1,84 @@ +package org.ssssssss.magicapi.component.service; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.ssssssss.magicapi.component.model.ComponentInfo; +import org.ssssssss.magicapi.core.exception.InvalidArgumentException; +import org.ssssssss.magicapi.core.model.Group; +import org.ssssssss.magicapi.core.model.JsonCode; +import org.ssssssss.magicapi.core.model.MagicEntity; +import org.ssssssss.magicapi.core.model.TreeNode; +import org.ssssssss.magicapi.core.service.AbstractPathMagicResourceStorage; +import org.ssssssss.magicapi.core.service.MagicResourceService; + +import java.util.List; +import java.util.UUID; + +public class ComponentInfoMagicResourceStorage extends AbstractPathMagicResourceStorage { + + @Override + public String folder() { + return "component"; + } + + @Override + public Class magicClass() { + return ComponentInfo.class; + } + + private boolean strIsEnglish(String word) { + boolean sign = true; + for (int i = 0; i < word.length(); i++) { + if (!(word.charAt(i) >= 'A' && word.charAt(i) <= 'Z') + && !(word.charAt(i) >= 'a' && word.charAt(i) <= 'z')) { + return false; + } + } + return true; + } + + public void isNameRepeat(List> groupChildren, String name, String id){ + groupChildren.stream().forEach(it -> { + Group node = it.getNode(); + List> chi = it.getChildren(); + magicResourceService.listFiles(node.getId()).forEach(file -> { + if(null != id){ + if(!file.getId().equals(id) && file.getName().equals(name)){ + throw new InvalidArgumentException(new JsonCode(9004, "组件名称已存在")); + } + }else{ + if(file.getName().equals(name)){ + throw new InvalidArgumentException(new JsonCode(9004, "组件名称已存在")); + } + } + }); + if(chi.size() > 0){ + isNameRepeat(chi, name, id); + } + }); + } + + @Override + public void validate(ComponentInfo entity) { + if(null == entity.getPath() || entity.getPath().equals("")){ + entity.setPath(UUID.randomUUID().toString().replace("-", "")); + } + isNameRepeat(magicResourceService.tree("component").getChildren(), entity.getName(), entity.getId()); + notBlank(entity.getName(), new JsonCode(9001, "组件名称不能为空")); + if(!strIsEnglish(entity.getName())){ + throw new InvalidArgumentException(new JsonCode(9002, "组件名称必须是英文")); + } + notBlank(entity.getDescription(), new JsonCode(9003, "组件描述不能为空")); + } + + @Override + public String buildMappingKey(ComponentInfo info) { + return buildMappingKey(info, magicResourceService.getGroupPath(info.getGroupId())); + } + + @Override + public boolean requirePath() { + return false; + } + +} diff --git a/magic-api-plugin-component/src/main/java/org/ssssssss/magicapi/component/service/ComponentMagicDynamicRegistry.java b/magic-api-plugin-component/src/main/java/org/ssssssss/magicapi/component/service/ComponentMagicDynamicRegistry.java new file mode 100644 index 0000000..3300653 --- /dev/null +++ b/magic-api-plugin-component/src/main/java/org/ssssssss/magicapi/component/service/ComponentMagicDynamicRegistry.java @@ -0,0 +1,28 @@ +package org.ssssssss.magicapi.component.service; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.event.EventListener; +import org.ssssssss.magicapi.component.model.ComponentInfo; +import org.ssssssss.magicapi.core.event.FileEvent; +import org.ssssssss.magicapi.core.event.GroupEvent; +import org.ssssssss.magicapi.core.service.AbstractMagicDynamicRegistry; +import org.ssssssss.magicapi.core.service.MagicResourceStorage; + +public class ComponentMagicDynamicRegistry extends AbstractMagicDynamicRegistry { + + public ComponentMagicDynamicRegistry(MagicResourceStorage magicResourceStorage) { + super(magicResourceStorage); + } + + @EventListener(condition = "#event.type == 'component'") + public void onFileEvent(FileEvent event) { + processEvent(event); + } + + @EventListener(condition = "#event.type == 'component'") + public void onGroupEvent(GroupEvent event) { + processEvent(event); + } + +} diff --git a/magic-api-plugin-component/src/main/java/org/ssssssss/magicapi/component/starter/MagicAPIComponentConfiguration.java b/magic-api-plugin-component/src/main/java/org/ssssssss/magicapi/component/starter/MagicAPIComponentConfiguration.java new file mode 100644 index 0000000..c113f20 --- /dev/null +++ b/magic-api-plugin-component/src/main/java/org/ssssssss/magicapi/component/starter/MagicAPIComponentConfiguration.java @@ -0,0 +1,31 @@ +package org.ssssssss.magicapi.component.starter; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.ssssssss.magicapi.component.service.ComponentInfoMagicResourceStorage; +import org.ssssssss.magicapi.component.service.ComponentMagicDynamicRegistry; +import org.ssssssss.magicapi.core.config.MagicPluginConfiguration; +import org.ssssssss.magicapi.core.model.Plugin; + +@Configuration +public class MagicAPIComponentConfiguration implements MagicPluginConfiguration { + + @Bean + @ConditionalOnMissingBean + public ComponentInfoMagicResourceStorage componentInfoMagicResourceStorage() { + return new ComponentInfoMagicResourceStorage(); + } + + @Bean + @ConditionalOnMissingBean + public ComponentMagicDynamicRegistry componentMagicDynamicRegistry(ComponentInfoMagicResourceStorage componentInfoMagicResourceStorage) { + return new ComponentMagicDynamicRegistry(componentInfoMagicResourceStorage); + } + + @Override + public Plugin plugin() { + return new Plugin("组件", "MagicComponent", "magic-component.1.0.0.iife.js"); + } + +} diff --git a/magic-api-plugin-component/src/main/resources/META-INF/spring.factories b/magic-api-plugin-component/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..def6a68 --- /dev/null +++ b/magic-api-plugin-component/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.ssssssss.magicapi.component.starter.MagicAPIComponentConfiguration diff --git a/magic-boot/pom.xml b/magic-boot/pom.xml index b3d466f..248c48d 100644 --- a/magic-boot/pom.xml +++ b/magic-boot/pom.xml @@ -52,6 +52,16 @@ sa-token-spring-boot-starter ${sa-token.version} + + org.ssssssss + magic-api-plugin-task + ${magic-api.version} + + + org.ssssssss + magic-api-plugin-component + ${magic-api.version} +