From 8e11dbedd2c4fdae7ce84d193f6df17ad393c904 Mon Sep 17 00:00:00 2001 From: wangshaoping Date: Sat, 30 Mar 2024 15:03:06 +0800 Subject: [PATCH] update --- .../core/function/ArithmeticFunction.java | 131 + .../ArithmeticIndicatorProcessor.java | 31 + .../ArithmeticParameterProcessor.java | 31 + io.sc.engine.rule.frontend/.browserslistrc | 5 + io.sc.engine.rule.frontend/.editorconfig | 14 + io.sc.engine.rule.frontend/.eslintrc.cjs | 36 + io.sc.engine.rule.frontend/.gitignore | 31 + io.sc.engine.rule.frontend/.npmignore | 0 io.sc.engine.rule.frontend/.npmrc | 11 + io.sc.engine.rule.frontend/.prettierignore | 3 + io.sc.engine.rule.frontend/.prettierrc.json | 8 + .../2.1.13/assets/iconfont/Anton-Regular.ttf | Bin 0 -> 79396 bytes .../2.1.13/assets/iconfont/demo_index.html | 2700 +++++++++++++++++ .../luckysheet/2.1.13/css/arrow-down.png | Bin 0 -> 85 bytes io.sc.engine.rule.frontend/src/App.vue | 5 + .../src/views/authorization/Authorization.vue | 4 + .../src/views/resources/AttachmentDialog.vue | 83 + .../ArithmeticIndicatorProcessorEntity.java | 58 + .../ArithmeticIndicatorProcessorVo.java | 26 + .../server/migration/support/AllInOne.java | 33 + .../ArithmeticParameterProcessorEntity.java | 57 + .../ArithmeticParameterProcessorVo.java | 26 + .../platform/attachment/api/AttachmentVo.java | 66 + .../controller/AttachmentWebController.java | 60 + .../jpa/entity/AttachmentEntity.java | 118 + .../jpa/repository/AttachmentRepository.java | 18 + .../attachment/service/AttachmentService.java | 52 + .../service/impl/AttachmentServiceImpl.java | 116 + .../sc/platform/orm/entity/AuditorEntity.java | 2 +- 29 files changed, 3724 insertions(+), 1 deletion(-) create mode 100644 io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/function/ArithmeticFunction.java create mode 100644 io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/po/lib/processor/ArithmeticIndicatorProcessor.java create mode 100644 io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/po/model/processor/ArithmeticParameterProcessor.java create mode 100644 io.sc.engine.rule.frontend/.browserslistrc create mode 100644 io.sc.engine.rule.frontend/.editorconfig create mode 100644 io.sc.engine.rule.frontend/.eslintrc.cjs create mode 100644 io.sc.engine.rule.frontend/.gitignore create mode 100644 io.sc.engine.rule.frontend/.npmignore create mode 100644 io.sc.engine.rule.frontend/.npmrc create mode 100644 io.sc.engine.rule.frontend/.prettierignore create mode 100644 io.sc.engine.rule.frontend/.prettierrc.json create mode 100644 io.sc.engine.rule.frontend/public/webjars/luckysheet/2.1.13/assets/iconfont/Anton-Regular.ttf create mode 100644 io.sc.engine.rule.frontend/public/webjars/luckysheet/2.1.13/assets/iconfont/demo_index.html create mode 100644 io.sc.engine.rule.frontend/public/webjars/luckysheet/2.1.13/css/arrow-down.png create mode 100644 io.sc.engine.rule.frontend/src/App.vue create mode 100644 io.sc.engine.rule.frontend/src/views/authorization/Authorization.vue create mode 100644 io.sc.engine.rule.frontend/src/views/resources/AttachmentDialog.vue create mode 100644 io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/lib/entity/processor/ArithmeticIndicatorProcessorEntity.java create mode 100644 io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/lib/vo/processor/ArithmeticIndicatorProcessorVo.java create mode 100644 io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/migration/support/AllInOne.java create mode 100644 io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/model/entity/processor/ArithmeticParameterProcessorEntity.java create mode 100644 io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/model/vo/processor/ArithmeticParameterProcessorVo.java create mode 100644 io.sc.platform.attachment.api/src/main/java/io/sc/platform/attachment/api/AttachmentVo.java create mode 100644 io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/controller/AttachmentWebController.java create mode 100644 io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/jpa/entity/AttachmentEntity.java create mode 100644 io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/jpa/repository/AttachmentRepository.java create mode 100644 io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/service/AttachmentService.java create mode 100644 io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/service/impl/AttachmentServiceImpl.java diff --git a/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/function/ArithmeticFunction.java b/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/function/ArithmeticFunction.java new file mode 100644 index 00000000..d69c45bf --- /dev/null +++ b/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/function/ArithmeticFunction.java @@ -0,0 +1,131 @@ +package io.sc.engine.rule.core.function; + +import java.math.BigDecimal; +import java.util.Random; + +/** + * 算数函数 + * @author wangshaoping + * + */ +public class ArithmeticFunction { + /** + * 获取一个 range 范围内的随机整数 + * @param range 随机数范围 + * @return 随机数 + */ + public static int randomInt(int range) { + Random random =new Random(); + return random.nextInt(range); + } + + /** + * 求最大可比较值 + * @param 参数类型 + * @param numbers 参数列表 + * @return 最大可比较值 + */ + @SafeVarargs + public static > T max(T... numbers) { + T max =null; + if(numbers!=null) { + for(T number : numbers) { + if(number!=null) { + if(max!=null) {if(number.compareTo(max)>0) {max =number;} }else {max =number;} + } + } + } + return max; + } + + /** + * 求最小可比较值 + * @param 参数类型 + * @param numbers 参数列表 + * @return 最小可比较值 + */ + @SafeVarargs + public static > T min(T... numbers) { + T min =null; + if(numbers!=null) { + for(T number : numbers) { + if(number!=null) { + if(min!=null) {if(number.compareTo(min)<0) {min =number;} }else {min =number;} + } + } + } + return min; + } + + /** + * 整数求和 + * @param numbers 其他参数列表 + * @return 和 + */ + public static Integer sum(Integer... numbers) { + Integer sum =null; + if(numbers!=null) { + for(Integer number : numbers) { + if(number!=null) { + if(sum!=null) { sum +=number;}else {sum =number;} + } + } + } + return sum; + } + + /** + * 小数求和 + * @param numbers 其他参数列表 + * @return 和 + */ + public static Long sum(Long... numbers) { + Long sum =null; + if(numbers!=null) { + for(Long number : numbers) { + if(number!=null) { + if(sum!=null) { sum +=number;}else {sum =number;} + } + } + } + return sum; + } + + /** + * 小数求和 + * @param numbers 其他参数列表 + * @return 和 + */ + public static Double sum(Double... numbers) { + Double sum =null; + if(numbers!=null) { + for(Double number : numbers) { + if(number!=null) { + if(sum!=null) { sum +=number;}else {sum =number;} + } + } + } + return sum; + } + + /** + * 小数求和 + * @param numbers 其他参数列表 + * @return 和 + */ + public static BigDecimal sum(BigDecimal... numbers) { + BigDecimal sum =null; + if(numbers!=null) { + for(BigDecimal number : numbers) { + if(number!=null) { + if(sum!=null) { sum=sum.add(number);}else {sum =number;} + } + } + } + return sum; + } + + public static Double transformSequencing(Double value,Double sourceMin,Double sourceMax,Double targetMin,Double targetMax) { + return targetMin + ((value-sourceMin)/(sourceMax-sourceMin))*(targetMax-targetMin); + } +} diff --git a/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/po/lib/processor/ArithmeticIndicatorProcessor.java b/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/po/lib/processor/ArithmeticIndicatorProcessor.java new file mode 100644 index 00000000..ce9f0932 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/po/lib/processor/ArithmeticIndicatorProcessor.java @@ -0,0 +1,31 @@ +package io.sc.engine.rule.core.po.lib.processor; + +import io.sc.engine.rule.core.enums.ProcessorType; +import io.sc.engine.rule.core.po.lib.IndicatorProcessor; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * 指标处理器(算数运算操作) + * @author wangshaoping + * + */ +@JsonTypeName("ARITHMETIC") +@JsonIgnoreProperties(ignoreUnknown=true) +public class ArithmeticIndicatorProcessor extends IndicatorProcessor { + private String arithmetic;//算数表达式 + + @Override + public ProcessorType getType() { + return ProcessorType.ARITHMETIC; + } + + public String getArithmetic() { + return arithmetic; + } + + public void setArithmetic(String arithmetic) { + this.arithmetic = arithmetic; + } +} diff --git a/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/po/model/processor/ArithmeticParameterProcessor.java b/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/po/model/processor/ArithmeticParameterProcessor.java new file mode 100644 index 00000000..e3b0afd6 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/po/model/processor/ArithmeticParameterProcessor.java @@ -0,0 +1,31 @@ +package io.sc.engine.rule.core.po.model.processor; + +import io.sc.engine.rule.core.enums.ProcessorType; +import io.sc.engine.rule.core.po.model.ParameterProcessor; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * 模型参数处理器(算数运算操作) + * @author wangshaoping + * + */ +@JsonTypeName("ARITHMETIC") +@JsonIgnoreProperties(ignoreUnknown=true) +public class ArithmeticParameterProcessor extends ParameterProcessor { + private String arithmetic;//算数表达式 + + @Override + public ProcessorType getType() { + return ProcessorType.ARITHMETIC; + } + + public String getArithmetic() { + return arithmetic; + } + + public void setArithmetic(String arithmetic) { + this.arithmetic = arithmetic; + } +} diff --git a/io.sc.engine.rule.frontend/.browserslistrc b/io.sc.engine.rule.frontend/.browserslistrc new file mode 100644 index 00000000..1fff95c5 --- /dev/null +++ b/io.sc.engine.rule.frontend/.browserslistrc @@ -0,0 +1,5 @@ +chrome >=89 +edge >=88 +firefox >=89 +safari >=15 +ios_saf >=15 \ No newline at end of file diff --git a/io.sc.engine.rule.frontend/.editorconfig b/io.sc.engine.rule.frontend/.editorconfig new file mode 100644 index 00000000..2791f744 --- /dev/null +++ b/io.sc.engine.rule.frontend/.editorconfig @@ -0,0 +1,14 @@ +################################################################# +# 强制对使用该基本代码的所有人实施一致的编码样式 +################################################################# + +# 顶级配置(即不集成父配置) +root = true + +# 针对所有文件 +[*] +charset = utf-8 # 字符集: utf-8 +indent_size = 2 # 缩进大小: 2 +indent_style = space # 缩进风格: 空格 +insert_final_newline = true # 是否在文件的最后插入一个空行 +trim_trailing_whitespace = true # 是否删除行尾的空格 diff --git a/io.sc.engine.rule.frontend/.eslintrc.cjs b/io.sc.engine.rule.frontend/.eslintrc.cjs new file mode 100644 index 00000000..181a97a6 --- /dev/null +++ b/io.sc.engine.rule.frontend/.eslintrc.cjs @@ -0,0 +1,36 @@ +module.exports = { + root: true, + + env: { + browser: true, + es2022: true, + "vue/setup-compiler-macros": true, + }, + + parserOptions:{ + ecmaVersion: 2022, + sourceType:"module", + }, + + extends:[ + "eslint:recommended", + "plugin:vue/vue3-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + ], + + parser: "vue-eslint-parser", + parserOptions: { + ecmaVersion: 2022, + parser: "@typescript-eslint/parser", + sourceType: "module", + }, + + rules:{ + 'semi':[1], + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/no-explicit-any': 'off', + "@typescript-eslint/no-unused-vars": 'off', + 'vue/multi-word-component-names': 'off', /* 禁用 vue 组件名称检查规则 */ + }, +}; diff --git a/io.sc.engine.rule.frontend/.gitignore b/io.sc.engine.rule.frontend/.gitignore new file mode 100644 index 00000000..719bf30c --- /dev/null +++ b/io.sc.engine.rule.frontend/.gitignore @@ -0,0 +1,31 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +test-results/ +playwright-report/ diff --git a/io.sc.engine.rule.frontend/.npmignore b/io.sc.engine.rule.frontend/.npmignore new file mode 100644 index 00000000..e69de29b diff --git a/io.sc.engine.rule.frontend/.npmrc b/io.sc.engine.rule.frontend/.npmrc new file mode 100644 index 00000000..c1c0b295 --- /dev/null +++ b/io.sc.engine.rule.frontend/.npmrc @@ -0,0 +1,11 @@ +# npm 仓库地址, 在 npm install 时使用 +registry=http://nexus.sc.io:8000/repository/npm-public/ + +# 用户邮箱 +email= + +# 注意: 以下 // 不是注释,不能去掉哦 +# 登录 npm 仓库的用户认证信息, 在 npm publish 时使用, publish 的 npm registry 在 package.json 文件中 publishConfig 部分配置 +# _authToken 可通过以下命令获取 +# curl -X PUT -H "Content-Type:application/json" -d '{"_id":"org.couchdb.user:admin","name":"admin","password":"admin"}' http://nexus.sc.io:8000/repository/npm-releases/-/user/org.couchdb.user:admin +//nexus.sc.io:8000/repository/npm-releases/:_authToken=NpmToken.193db44c-7ca5-3cb6-a990-d24b93fb0d10 \ No newline at end of file diff --git a/io.sc.engine.rule.frontend/.prettierignore b/io.sc.engine.rule.frontend/.prettierignore new file mode 100644 index 00000000..b5c08636 --- /dev/null +++ b/io.sc.engine.rule.frontend/.prettierignore @@ -0,0 +1,3 @@ +build +dist +node_modules \ No newline at end of file diff --git a/io.sc.engine.rule.frontend/.prettierrc.json b/io.sc.engine.rule.frontend/.prettierrc.json new file mode 100644 index 00000000..f9e9ce41 --- /dev/null +++ b/io.sc.engine.rule.frontend/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": true, + "tabWidth": 2, + "singleQuote": true, + "printWidth": 160, + "trailingComma": "all" +} \ No newline at end of file diff --git a/io.sc.engine.rule.frontend/public/webjars/luckysheet/2.1.13/assets/iconfont/Anton-Regular.ttf b/io.sc.engine.rule.frontend/public/webjars/luckysheet/2.1.13/assets/iconfont/Anton-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5a582b18064adb3a2b8191e7c26875160172e829 GIT binary patch literal 79396 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 J#-MKe{eLlAN;v=k literal 0 HcmV?d00001 diff --git a/io.sc.engine.rule.frontend/public/webjars/luckysheet/2.1.13/assets/iconfont/demo_index.html b/io.sc.engine.rule.frontend/public/webjars/luckysheet/2.1.13/assets/iconfont/demo_index.html new file mode 100644 index 00000000..b24698ab --- /dev/null +++ b/io.sc.engine.rule.frontend/public/webjars/luckysheet/2.1.13/assets/iconfont/demo_index.html @@ -0,0 +1,2700 @@ + + + + + IconFont Demo + + + + + + + + + + + +
+

+ +
+
+
    + +
  • + +
    链接
    +
    &#xe7f8;
    +
  • + +
  • + +
    打印区域
    +
    &#xe7f5;
    +
  • + +
  • + +
    打印页面配置
    +
    &#xe7f6;
    +
  • + +
  • + +
    打印标题
    +
    &#xe7f7;
    +
  • + +
  • + +
    分页预览
    +
    &#xe7f2;
    +
  • + +
  • + +
    普通
    +
    &#xe7f3;
    +
  • + +
  • + +
    页面布局
    +
    &#xe7f4;
    +
  • + +
  • + +
    表格锁定
    +
    &#xe7ee;
    +
  • + +
  • + +
    转到
    +
    &#xe7f1;
    +
  • + +
  • + +
    右箭头
    +
    &#xe7ed;
    +
  • + +
  • + +
    菜单
    +
    &#xe7ef;
    +
  • + +
  • + +
    替换
    +
    &#xe7f0;
    +
  • + +
  • + +
    冻结
    +
    &#xe7e1;
    +
  • + +
  • + +
    +
    &#xe7e2;
    +
  • + +
  • + +
    +
    &#xe7e3;
    +
  • + +
  • + +
    溢出
    +
    &#xe7e4;
    +
  • + +
  • + +
    升序
    +
    &#xe7e5;
    +
  • + +
  • + +
    内框线
    +
    &#xe7e6;
    +
  • + +
  • + +
    清除筛选
    +
    &#xe7e7;
    +
  • + +
  • + +
    文本向上
    +
    &#xe7e8;
    +
  • + +
  • + +
    降序
    +
    &#xe7e9;
    +
  • + +
  • + +
    内框横线
    +
    &#xe7ea;
    +
  • + +
  • + +
    内框竖线
    +
    &#xe7eb;
    +
  • + +
  • + +
    自定义排序
    +
    &#xe7ec;
    +
  • + +
  • + +
    logo2
    +
    &#xe7df;
    +
  • + +
  • + +
    logo
    +
    &#xe7e0;
    +
  • + +
  • + +
    文本倾斜
    +
    &#xe7de;
    +
  • + +
  • + +
    加粗
    +
    &#xe7d9;
    +
  • + +
  • + +
    搜索
    +
    &#xe78a;
    +
  • + +
  • + +
    关闭
    +
    &#xe78b;
    +
  • + +
  • + +
    下一个
    +
    &#xe78c;
    +
  • + +
  • + +
    下拉
    +
    &#xe78d;
    +
  • + +
  • + +
    文本颜色
    +
    &#xe78e;
    +
  • + +
  • + +
    上一个
    +
    &#xe78f;
    +
  • + +
  • + +
    数据透视
    +
    &#xe790;
    +
  • + +
  • + +
    填充
    +
    &#xe791;
    +
  • + +
  • + +
    增加小数位
    +
    &#xe792;
    +
  • + +
  • + +
    编辑2
    +
    &#xe793;
    +
  • + +
  • + +
    截屏
    +
    &#xe794;
    +
  • + +
  • + +
    减小小数位
    +
    &#xe796;
    +
  • + +
  • + +
    菜单
    +
    &#xe797;
    +
  • + +
  • + +
    数据库
    +
    &#xe798;
    +
  • + +
  • + +
    无边框
    +
    &#xe799;
    +
  • + +
  • + +
    编辑
    +
    &#xe79a;
    +
  • + +
  • + +
    清除样式
    +
    &#xe79b;
    +
  • + +
  • + +
    删除
    +
    &#xe79c;
    +
  • + +
  • + +
    文本居中对齐
    +
    &#xe79d;
    +
  • + +
  • + +
    打印
    +
    &#xe79e;
    +
  • + +
  • + +
    文本分割
    +
    &#xe79f;
    +
  • + +
  • + +
    函数‘
    +
    &#xe7a0;
    +
  • + +
  • + +
    降序
    +
    &#xe7a1;
    +
  • + +
  • + +
    顶部对齐
    +
    &#xe7a2;
    +
  • + +
  • + +
    图片
    +
    &#xe7a3;
    +
  • + +
  • + +
    向下90
    +
    &#xe7a4;
    +
  • + +
  • + +
    竖排文字
    +
    &#xe7a5;
    +
  • + +
  • + +
    全加边框
    +
    &#xe7a6;
    +
  • + +
  • + +
    升序
    +
    &#xe7a7;
    +
  • + +
  • + +
    裁剪
    +
    &#xe7a8;
    +
  • + +
  • + +
    金额
    +
    &#xe7a9;
    +
  • + +
  • + +
    菜单1
    +
    &#xe7aa;
    +
  • + +
  • + +
    取消合并
    +
    &#xe7ab;
    +
  • + +
  • + +
    文本下划线
    +
    &#xe7ac;
    +
  • + +
  • + +
    上边框
    +
    &#xe7ad;
    +
  • + +
  • + +
    定位
    +
    &#xe7ae;
    +
  • + +
  • + +
    四周加边框
    +
    &#xe7af;
    +
  • + +
  • + +
    侧边栏收起
    +
    &#xe7b0;
    +
  • + +
  • + +
    合并
    +
    &#xe7b1;
    +
  • + +
  • + +
    向上倾斜
    +
    &#xe7b2;
    +
  • + +
  • + +
    水平对齐
    +
    &#xe7b3;
    +
  • + +
  • + +
    文本删除线
    +
    &#xe7b4;
    +
  • + +
  • + +
    文本右对齐
    +
    &#xe7b5;
    +
  • + +
  • + +
    前进
    +
    &#xe7b6;
    +
  • + +
  • + +
    图表
    +
    &#xe7b7;
    +
  • + +
  • + +
    右边框
    +
    &#xe7b8;
    +
  • + +
  • + +
    百分号
    +
    &#xe7b9;
    +
  • + +
  • + +
    格式刷
    +
    &#xe7ba;
    +
  • + +
  • + +
    保存
    +
    &#xe7bb;
    +
  • + +
  • + +
    数据验证
    +
    &#xe7bc;
    +
  • + +
  • + +
    截断
    +
    &#xe7bd;
    +
  • + +
  • + +
    格式条件
    +
    &#xe7be;
    +
  • + +
  • + +
    自动换行
    +
    &#xe7bf;
    +
  • + +
  • + +
    侧边栏展开
    +
    &#xe7c0;
    +
  • + +
  • + +
    筛选2
    +
    &#xe7c1;
    +
  • + +
  • + +
    向下倾斜
    +
    &#xe7c2;
    +
  • + +
  • + +
    溢出
    +
    &#xe7c3;
    +
  • + +
  • + +
    垂直合并
    +
    &#xe7c4;
    +
  • + +
  • + +
    文本分散对齐
    +
    &#xe7c5;
    +
  • + +
  • + +
    左边框
    +
    &#xe7c6;
    +
  • + +
  • + +
    分页查看
    +
    &#xe7c7;
    +
  • + +
  • + +
    运行
    +
    &#xe7c8;
    +
  • + +
  • + +
    +
    &#xe7c9;
    +
  • + +
  • + +
    全屏
    +
    &#xe7ca;
    +
  • + +
  • + +
    筛选
    +
    &#xe7cb;
    +
  • + +
  • + +
    更新
    +
    &#xe7cc;
    +
  • + +
  • + +
    清除
    +
    &#xe7cd;
    +
  • + +
  • + +
    +
    &#xe7ce;
    +
  • + +
  • + +
    注释
    +
    &#xe7cf;
    +
  • + +
  • + +
    +
    &#xe7d0;
    +
  • + +
  • + +
    计算
    +
    &#xe7d1;
    +
  • + +
  • + +
    +
    &#xe7d2;
    +
  • + +
  • + +
    底部对齐
    +
    &#xe7d3;
    +
  • + +
  • + +
    向上90
    +
    &#xe7d4;
    +
  • + +
  • + +
    无选装
    +
    &#xe7d5;
    +
  • + +
  • + +
    显示隐藏网格
    +
    &#xe7d6;
    +
  • + +
  • + +
    冻结
    +
    &#xe7d7;
    +
  • + +
  • + +
    文本左对齐
    +
    &#xe7d8;
    +
  • + +
  • + +
    后退
    +
    &#xe7da;
    +
  • + +
  • + +
    水平合并
    +
    &#xe7db;
    +
  • + +
  • + +
    下边框
    +
    &#xe7dc;
    +
  • + +
  • + +
    设置
    +
    &#xe7dd;
    +
  • + +
+
+

Unicode 引用

+
+ +

Unicode 是字体在网页端最原始的应用方式,特点是:

+
    +
  • 兼容性最好,支持 IE6+,及所有现代浏览器。
  • +
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • +
  • 但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。
  • +
+
+

注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式

+
+

Unicode 使用步骤如下:

+

第一步:拷贝项目下面生成的 @font-face

+
@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.eot');
+  src: url('iconfont.eot?#iefix') format('embedded-opentype'),
+      url('iconfont.woff2') format('woff2'),
+      url('iconfont.woff') format('woff'),
+      url('iconfont.ttf') format('truetype'),
+      url('iconfont.svg#iconfont') format('svg');
+}
+
+

第二步:定义使用 iconfont 的样式

+
.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+

第三步:挑选相应图标并获取字体编码,应用于页面

+
+<span class="iconfont">&#x33;</span>
+
+
+

"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    + 链接 +
    +
    .luckysheet-iconfont-lianjie +
    +
  • + +
  • + +
    + 打印区域 +
    +
    .luckysheet-iconfont-dayinquyu +
    +
  • + +
  • + +
    + 打印页面配置 +
    +
    .luckysheet-iconfont-dayinyemianpeizhi +
    +
  • + +
  • + +
    + 打印标题 +
    +
    .luckysheet-iconfont-dayinbiaoti +
    +
  • + +
  • + +
    + 分页预览 +
    +
    .luckysheet-iconfont-fenyeyulan +
    +
  • + +
  • + +
    + 普通 +
    +
    .luckysheet-iconfont-putong +
    +
  • + +
  • + +
    + 页面布局 +
    +
    .luckysheet-iconfont-yemianbuju +
    +
  • + +
  • + +
    + 表格锁定 +
    +
    .luckysheet-iconfont-biaogesuoding +
    +
  • + +
  • + +
    + 转到 +
    +
    .luckysheet-iconfont-zhuandao1 +
    +
  • + +
  • + +
    + 右箭头 +
    +
    .luckysheet-iconfont-youjiantou +
    +
  • + +
  • + +
    + 菜单 +
    +
    .luckysheet-iconfont-caidan2 +
    +
  • + +
  • + +
    + 替换 +
    +
    .luckysheet-iconfont-tihuan +
    +
  • + +
  • + +
    + 冻结 +
    +
    .luckysheet-iconfont-dongjie1 +
    +
  • + +
  • + +
    + 剪 +
    +
    .luckysheet-iconfont-jian1 +
    +
  • + +
  • + +
    + 加 +
    +
    .luckysheet-iconfont-jia1 +
    +
  • + +
  • + +
    + 溢出 +
    +
    .luckysheet-iconfont-yichu1 +
    +
  • + +
  • + +
    + 升序 +
    +
    .luckysheet-iconfont-shengxu1 +
    +
  • + +
  • + +
    + 内框线 +
    +
    .luckysheet-iconfont-neikuangxian +
    +
  • + +
  • + +
    + 清除筛选 +
    +
    .luckysheet-iconfont-qingchushaixuan +
    +
  • + +
  • + +
    + 文本向上 +
    +
    .luckysheet-iconfont-wenbenxiangshang +
    +
  • + +
  • + +
    + 降序 +
    +
    .luckysheet-iconfont-jiangxu1 +
    +
  • + +
  • + +
    + 内框横线 +
    +
    .luckysheet-iconfont-neikuanghengxian +
    +
  • + +
  • + +
    + 内框竖线 +
    +
    .luckysheet-iconfont-neikuangshuxian +
    +
  • + +
  • + +
    + 自定义排序 +
    +
    .luckysheet-iconfont-zidingyipaixu +
    +
  • + +
  • + +
    + logo2 +
    +
    .luckysheet-iconfont-logo2 +
    +
  • + +
  • + +
    + logo +
    +
    .luckysheet-iconfont-logo +
    +
  • + +
  • + +
    + 文本倾斜 +
    +
    .luckysheet-iconfont-wenbenqingxie1 +
    +
  • + +
  • + +
    + 加粗 +
    +
    .luckysheet-iconfont-jiacu +
    +
  • + +
  • + +
    + 搜索 +
    +
    .luckysheet-iconfont-sousuo +
    +
  • + +
  • + +
    + 关闭 +
    +
    .luckysheet-iconfont-guanbi +
    +
  • + +
  • + +
    + 下一个 +
    +
    .luckysheet-iconfont-xiayige +
    +
  • + +
  • + +
    + 下拉 +
    +
    .luckysheet-iconfont-xiala +
    +
  • + +
  • + +
    + 文本颜色 +
    +
    .luckysheet-iconfont-wenbenyanse +
    +
  • + +
  • + +
    + 上一个 +
    +
    .luckysheet-iconfont-shangyige +
    +
  • + +
  • + +
    + 数据透视 +
    +
    .luckysheet-iconfont-shujutoushi +
    +
  • + +
  • + +
    + 填充 +
    +
    .luckysheet-iconfont-tianchong +
    +
  • + +
  • + +
    + 增加小数位 +
    +
    .luckysheet-iconfont-zengjiaxiaoshuwei +
    +
  • + +
  • + +
    + 编辑2 +
    +
    .luckysheet-iconfont-bianji2 +
    +
  • + +
  • + +
    + 截屏 +
    +
    .luckysheet-iconfont-jieping +
    +
  • + +
  • + +
    + 减小小数位 +
    +
    .luckysheet-iconfont-jianxiaoxiaoshuwei +
    +
  • + +
  • + +
    + 菜单 +
    +
    .luckysheet-iconfont-caidan +
    +
  • + +
  • + +
    + 数据库 +
    +
    .luckysheet-iconfont-shujuku +
    +
  • + +
  • + +
    + 无边框 +
    +
    .luckysheet-iconfont-wubiankuang +
    +
  • + +
  • + +
    + 编辑 +
    +
    .luckysheet-iconfont-bianji +
    +
  • + +
  • + +
    + 清除样式 +
    +
    .luckysheet-iconfont-qingchuyangshi +
    +
  • + +
  • + +
    + 删除 +
    +
    .luckysheet-iconfont-shanchu +
    +
  • + +
  • + +
    + 文本居中对齐 +
    +
    .luckysheet-iconfont-wenbenjuzhongduiqi +
    +
  • + +
  • + +
    + 打印 +
    +
    .luckysheet-iconfont-dayin +
    +
  • + +
  • + +
    + 文本分割 +
    +
    .luckysheet-iconfont-wenbenfenge +
    +
  • + +
  • + +
    + 函数‘ +
    +
    .luckysheet-iconfont-hanshu +
    +
  • + +
  • + +
    + 降序 +
    +
    .luckysheet-iconfont-jiangxu +
    +
  • + +
  • + +
    + 顶部对齐 +
    +
    .luckysheet-iconfont-dingbuduiqi +
    +
  • + +
  • + +
    + 图片 +
    +
    .luckysheet-iconfont-tupian +
    +
  • + +
  • + +
    + 向下90 +
    +
    .luckysheet-iconfont-xiangxia90 +
    +
  • + +
  • + +
    + 竖排文字 +
    +
    .luckysheet-iconfont-shupaiwenzi +
    +
  • + +
  • + +
    + 全加边框 +
    +
    .luckysheet-iconfont-quanjiabiankuang +
    +
  • + +
  • + +
    + 升序 +
    +
    .luckysheet-iconfont-shengxu +
    +
  • + +
  • + +
    + 裁剪 +
    +
    .luckysheet-iconfont-caijian +
    +
  • + +
  • + +
    + 金额 +
    +
    .luckysheet-iconfont-jine +
    +
  • + +
  • + +
    + 菜单1 +
    +
    .luckysheet-iconfont-caidan1 +
    +
  • + +
  • + +
    + 取消合并 +
    +
    .luckysheet-iconfont-quxiaohebing +
    +
  • + +
  • + +
    + 文本下划线 +
    +
    .luckysheet-iconfont-wenbenxiahuaxian +
    +
  • + +
  • + +
    + 上边框 +
    +
    .luckysheet-iconfont-shangbiankuang +
    +
  • + +
  • + +
    + 定位 +
    +
    .luckysheet-iconfont-dingwei +
    +
  • + +
  • + +
    + 四周加边框 +
    +
    .luckysheet-iconfont-sizhoujiabiankuang +
    +
  • + +
  • + +
    + 侧边栏收起 +
    +
    .luckysheet-iconfont-cebianlanshouqi +
    +
  • + +
  • + +
    + 合并 +
    +
    .luckysheet-iconfont-hebing +
    +
  • + +
  • + +
    + 向上倾斜 +
    +
    .luckysheet-iconfont-xiangshangqingxie +
    +
  • + +
  • + +
    + 水平对齐 +
    +
    .luckysheet-iconfont-shuipingduiqi +
    +
  • + +
  • + +
    + 文本删除线 +
    +
    .luckysheet-iconfont-wenbenshanchuxian +
    +
  • + +
  • + +
    + 文本右对齐 +
    +
    .luckysheet-iconfont-wenbenyouduiqi +
    +
  • + +
  • + +
    + 前进 +
    +
    .luckysheet-iconfont-qianjin +
    +
  • + +
  • + +
    + 图表 +
    +
    .luckysheet-iconfont-tubiao +
    +
  • + +
  • + +
    + 右边框 +
    +
    .luckysheet-iconfont-youbiankuang +
    +
  • + +
  • + +
    + 百分号 +
    +
    .luckysheet-iconfont-baifenhao +
    +
  • + +
  • + +
    + 格式刷 +
    +
    .luckysheet-iconfont-geshishua +
    +
  • + +
  • + +
    + 保存 +
    +
    .luckysheet-iconfont-baocun +
    +
  • + +
  • + +
    + 数据验证 +
    +
    .luckysheet-iconfont-shujuyanzheng +
    +
  • + +
  • + +
    + 截断 +
    +
    .luckysheet-iconfont-jieduan +
    +
  • + +
  • + +
    + 格式条件 +
    +
    .luckysheet-iconfont-geshitiaojian +
    +
  • + +
  • + +
    + 自动换行 +
    +
    .luckysheet-iconfont-zidonghuanhang +
    +
  • + +
  • + +
    + 侧边栏展开 +
    +
    .luckysheet-iconfont-cebianlanzhankai +
    +
  • + +
  • + +
    + 筛选2 +
    +
    .luckysheet-iconfont-shaixuan2 +
    +
  • + +
  • + +
    + 向下倾斜 +
    +
    .luckysheet-iconfont-xiangxiaqingxie +
    +
  • + +
  • + +
    + 溢出 +
    +
    .luckysheet-iconfont-yichu +
    +
  • + +
  • + +
    + 垂直合并 +
    +
    .luckysheet-iconfont-chuizhihebing +
    +
  • + +
  • + +
    + 文本分散对齐 +
    +
    .luckysheet-iconfont-wenbenfensanduiqi +
    +
  • + +
  • + +
    + 左边框 +
    +
    .luckysheet-iconfont-zuobiankuang +
    +
  • + +
  • + +
    + 分页查看 +
    +
    .luckysheet-iconfont-fenyechakan +
    +
  • + +
  • + +
    + 运行 +
    +
    .luckysheet-iconfont-yunhang +
    +
  • + +
  • + +
    + 列 +
    +
    .luckysheet-iconfont-lie +
    +
  • + +
  • + +
    + 全屏 +
    +
    .luckysheet-iconfont-quanping +
    +
  • + +
  • + +
    + 筛选 +
    +
    .luckysheet-iconfont-shaixuan +
    +
  • + +
  • + +
    + 更新 +
    +
    .luckysheet-iconfont-gengxin +
    +
  • + +
  • + +
    + 清除 +
    +
    .luckysheet-iconfont-qingchu +
    +
  • + +
  • + +
    + 行 +
    +
    .luckysheet-iconfont-hang +
    +
  • + +
  • + +
    + 注释 +
    +
    .luckysheet-iconfont-zhushi +
    +
  • + +
  • + +
    + 剪 +
    +
    .luckysheet-iconfont-jian +
    +
  • + +
  • + +
    + 计算 +
    +
    .luckysheet-iconfont-jisuan +
    +
  • + +
  • + +
    + 加 +
    +
    .luckysheet-iconfont-jia +
    +
  • + +
  • + +
    + 底部对齐 +
    +
    .luckysheet-iconfont-dibuduiqi +
    +
  • + +
  • + +
    + 向上90 +
    +
    .luckysheet-iconfont-xiangshang90 +
    +
  • + +
  • + +
    + 无选装 +
    +
    .luckysheet-iconfont-wuxuanzhuang +
    +
  • + +
  • + +
    + 显示隐藏网格 +
    +
    .luckysheet-iconfont-xianshiyincangwangge +
    +
  • + +
  • + +
    + 冻结 +
    +
    .luckysheet-iconfont-dongjie +
    +
  • + +
  • + +
    + 文本左对齐 +
    +
    .luckysheet-iconfont-wenbenzuoduiqi +
    +
  • + +
  • + +
    + 后退 +
    +
    .luckysheet-iconfont-houtui +
    +
  • + +
  • + +
    + 水平合并 +
    +
    .luckysheet-iconfont-shuipinghebing +
    +
  • + +
  • + +
    + 下边框 +
    +
    .luckysheet-iconfont-xiabiankuang +
    +
  • + +
  • + +
    + 设置 +
    +
    .luckysheet-iconfont-shezhi +
    +
  • + +
+
+

font-class 引用

+
+ +

font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

+

与 Unicode 使用方式相比,具有如下特点:

+
    +
  • 兼容性良好,支持 IE8+,及所有现代浏览器。
  • +
  • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
  • +
  • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
  • +
  • 不过因为本质上还是使用的字体,所以多色图标还是不支持的。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 fontclass 代码:

+
<link rel="stylesheet" href="./iconfont.css">
+
+

第二步:挑选相应图标并获取类名,应用于页面:

+
<span class="iconfont luckysheet-iconfont-xxx"></span>
+
+
+

" + iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    链接
    +
    #luckysheet-iconfont-lianjie
    +
  • + +
  • + +
    打印区域
    +
    #luckysheet-iconfont-dayinquyu
    +
  • + +
  • + +
    打印页面配置
    +
    #luckysheet-iconfont-dayinyemianpeizhi
    +
  • + +
  • + +
    打印标题
    +
    #luckysheet-iconfont-dayinbiaoti
    +
  • + +
  • + +
    分页预览
    +
    #luckysheet-iconfont-fenyeyulan
    +
  • + +
  • + +
    普通
    +
    #luckysheet-iconfont-putong
    +
  • + +
  • + +
    页面布局
    +
    #luckysheet-iconfont-yemianbuju
    +
  • + +
  • + +
    表格锁定
    +
    #luckysheet-iconfont-biaogesuoding
    +
  • + +
  • + +
    转到
    +
    #luckysheet-iconfont-zhuandao1
    +
  • + +
  • + +
    右箭头
    +
    #luckysheet-iconfont-youjiantou
    +
  • + +
  • + +
    菜单
    +
    #luckysheet-iconfont-caidan2
    +
  • + +
  • + +
    替换
    +
    #luckysheet-iconfont-tihuan
    +
  • + +
  • + +
    冻结
    +
    #luckysheet-iconfont-dongjie1
    +
  • + +
  • + +
    +
    #luckysheet-iconfont-jian1
    +
  • + +
  • + +
    +
    #luckysheet-iconfont-jia1
    +
  • + +
  • + +
    溢出
    +
    #luckysheet-iconfont-yichu1
    +
  • + +
  • + +
    升序
    +
    #luckysheet-iconfont-shengxu1
    +
  • + +
  • + +
    内框线
    +
    #luckysheet-iconfont-neikuangxian
    +
  • + +
  • + +
    清除筛选
    +
    #luckysheet-iconfont-qingchushaixuan
    +
  • + +
  • + +
    文本向上
    +
    #luckysheet-iconfont-wenbenxiangshang
    +
  • + +
  • + +
    降序
    +
    #luckysheet-iconfont-jiangxu1
    +
  • + +
  • + +
    内框横线
    +
    #luckysheet-iconfont-neikuanghengxian
    +
  • + +
  • + +
    内框竖线
    +
    #luckysheet-iconfont-neikuangshuxian
    +
  • + +
  • + +
    自定义排序
    +
    #luckysheet-iconfont-zidingyipaixu
    +
  • + +
  • + +
    logo2
    +
    #luckysheet-iconfont-logo2
    +
  • + +
  • + +
    logo
    +
    #luckysheet-iconfont-logo
    +
  • + +
  • + +
    文本倾斜
    +
    #luckysheet-iconfont-wenbenqingxie1
    +
  • + +
  • + +
    加粗
    +
    #luckysheet-iconfont-jiacu
    +
  • + +
  • + +
    搜索
    +
    #luckysheet-iconfont-sousuo
    +
  • + +
  • + +
    关闭
    +
    #luckysheet-iconfont-guanbi
    +
  • + +
  • + +
    下一个
    +
    #luckysheet-iconfont-xiayige
    +
  • + +
  • + +
    下拉
    +
    #luckysheet-iconfont-xiala
    +
  • + +
  • + +
    文本颜色
    +
    #luckysheet-iconfont-wenbenyanse
    +
  • + +
  • + +
    上一个
    +
    #luckysheet-iconfont-shangyige
    +
  • + +
  • + +
    数据透视
    +
    #luckysheet-iconfont-shujutoushi
    +
  • + +
  • + +
    填充
    +
    #luckysheet-iconfont-tianchong
    +
  • + +
  • + +
    增加小数位
    +
    #luckysheet-iconfont-zengjiaxiaoshuwei
    +
  • + +
  • + +
    编辑2
    +
    #luckysheet-iconfont-bianji2
    +
  • + +
  • + +
    截屏
    +
    #luckysheet-iconfont-jieping
    +
  • + +
  • + +
    减小小数位
    +
    #luckysheet-iconfont-jianxiaoxiaoshuwei
    +
  • + +
  • + +
    菜单
    +
    #luckysheet-iconfont-caidan
    +
  • + +
  • + +
    数据库
    +
    #luckysheet-iconfont-shujuku
    +
  • + +
  • + +
    无边框
    +
    #luckysheet-iconfont-wubiankuang
    +
  • + +
  • + +
    编辑
    +
    #luckysheet-iconfont-bianji
    +
  • + +
  • + +
    清除样式
    +
    #luckysheet-iconfont-qingchuyangshi
    +
  • + +
  • + +
    删除
    +
    #luckysheet-iconfont-shanchu
    +
  • + +
  • + +
    文本居中对齐
    +
    #luckysheet-iconfont-wenbenjuzhongduiqi
    +
  • + +
  • + +
    打印
    +
    #luckysheet-iconfont-dayin
    +
  • + +
  • + +
    文本分割
    +
    #luckysheet-iconfont-wenbenfenge
    +
  • + +
  • + +
    函数‘
    +
    #luckysheet-iconfont-hanshu
    +
  • + +
  • + +
    降序
    +
    #luckysheet-iconfont-jiangxu
    +
  • + +
  • + +
    顶部对齐
    +
    #luckysheet-iconfont-dingbuduiqi
    +
  • + +
  • + +
    图片
    +
    #luckysheet-iconfont-tupian
    +
  • + +
  • + +
    向下90
    +
    #luckysheet-iconfont-xiangxia90
    +
  • + +
  • + +
    竖排文字
    +
    #luckysheet-iconfont-shupaiwenzi
    +
  • + +
  • + +
    全加边框
    +
    #luckysheet-iconfont-quanjiabiankuang
    +
  • + +
  • + +
    升序
    +
    #luckysheet-iconfont-shengxu
    +
  • + +
  • + +
    裁剪
    +
    #luckysheet-iconfont-caijian
    +
  • + +
  • + +
    金额
    +
    #luckysheet-iconfont-jine
    +
  • + +
  • + +
    菜单1
    +
    #luckysheet-iconfont-caidan1
    +
  • + +
  • + +
    取消合并
    +
    #luckysheet-iconfont-quxiaohebing
    +
  • + +
  • + +
    文本下划线
    +
    #luckysheet-iconfont-wenbenxiahuaxian
    +
  • + +
  • + +
    上边框
    +
    #luckysheet-iconfont-shangbiankuang
    +
  • + +
  • + +
    定位
    +
    #luckysheet-iconfont-dingwei
    +
  • + +
  • + +
    四周加边框
    +
    #luckysheet-iconfont-sizhoujiabiankuang
    +
  • + +
  • + +
    侧边栏收起
    +
    #luckysheet-iconfont-cebianlanshouqi
    +
  • + +
  • + +
    合并
    +
    #luckysheet-iconfont-hebing
    +
  • + +
  • + +
    向上倾斜
    +
    #luckysheet-iconfont-xiangshangqingxie
    +
  • + +
  • + +
    水平对齐
    +
    #luckysheet-iconfont-shuipingduiqi
    +
  • + +
  • + +
    文本删除线
    +
    #luckysheet-iconfont-wenbenshanchuxian
    +
  • + +
  • + +
    文本右对齐
    +
    #luckysheet-iconfont-wenbenyouduiqi
    +
  • + +
  • + +
    前进
    +
    #luckysheet-iconfont-qianjin
    +
  • + +
  • + +
    图表
    +
    #luckysheet-iconfont-tubiao
    +
  • + +
  • + +
    右边框
    +
    #luckysheet-iconfont-youbiankuang
    +
  • + +
  • + +
    百分号
    +
    #luckysheet-iconfont-baifenhao
    +
  • + +
  • + +
    格式刷
    +
    #luckysheet-iconfont-geshishua
    +
  • + +
  • + +
    保存
    +
    #luckysheet-iconfont-baocun
    +
  • + +
  • + +
    数据验证
    +
    #luckysheet-iconfont-shujuyanzheng
    +
  • + +
  • + +
    截断
    +
    #luckysheet-iconfont-jieduan
    +
  • + +
  • + +
    格式条件
    +
    #luckysheet-iconfont-geshitiaojian
    +
  • + +
  • + +
    自动换行
    +
    #luckysheet-iconfont-zidonghuanhang
    +
  • + +
  • + +
    侧边栏展开
    +
    #luckysheet-iconfont-cebianlanzhankai
    +
  • + +
  • + +
    筛选2
    +
    #luckysheet-iconfont-shaixuan2
    +
  • + +
  • + +
    向下倾斜
    +
    #luckysheet-iconfont-xiangxiaqingxie
    +
  • + +
  • + +
    溢出
    +
    #luckysheet-iconfont-yichu
    +
  • + +
  • + +
    垂直合并
    +
    #luckysheet-iconfont-chuizhihebing
    +
  • + +
  • + +
    文本分散对齐
    +
    #luckysheet-iconfont-wenbenfensanduiqi
    +
  • + +
  • + +
    左边框
    +
    #luckysheet-iconfont-zuobiankuang
    +
  • + +
  • + +
    分页查看
    +
    #luckysheet-iconfont-fenyechakan
    +
  • + +
  • + +
    运行
    +
    #luckysheet-iconfont-yunhang
    +
  • + +
  • + +
    +
    #luckysheet-iconfont-lie
    +
  • + +
  • + +
    全屏
    +
    #luckysheet-iconfont-quanping
    +
  • + +
  • + +
    筛选
    +
    #luckysheet-iconfont-shaixuan
    +
  • + +
  • + +
    更新
    +
    #luckysheet-iconfont-gengxin
    +
  • + +
  • + +
    清除
    +
    #luckysheet-iconfont-qingchu
    +
  • + +
  • + +
    +
    #luckysheet-iconfont-hang
    +
  • + +
  • + +
    注释
    +
    #luckysheet-iconfont-zhushi
    +
  • + +
  • + +
    +
    #luckysheet-iconfont-jian
    +
  • + +
  • + +
    计算
    +
    #luckysheet-iconfont-jisuan
    +
  • + +
  • + +
    +
    #luckysheet-iconfont-jia
    +
  • + +
  • + +
    底部对齐
    +
    #luckysheet-iconfont-dibuduiqi
    +
  • + +
  • + +
    向上90
    +
    #luckysheet-iconfont-xiangshang90
    +
  • + +
  • + +
    无选装
    +
    #luckysheet-iconfont-wuxuanzhuang
    +
  • + +
  • + +
    显示隐藏网格
    +
    #luckysheet-iconfont-xianshiyincangwangge
    +
  • + +
  • + +
    冻结
    +
    #luckysheet-iconfont-dongjie
    +
  • + +
  • + +
    文本左对齐
    +
    #luckysheet-iconfont-wenbenzuoduiqi
    +
  • + +
  • + +
    后退
    +
    #luckysheet-iconfont-houtui
    +
  • + +
  • + +
    水平合并
    +
    #luckysheet-iconfont-shuipinghebing
    +
  • + +
  • + +
    下边框
    +
    #luckysheet-iconfont-xiabiankuang
    +
  • + +
  • + +
    设置
    +
    #luckysheet-iconfont-shezhi
    +
  • + +
+
+

Symbol 引用

+
+ +

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 + 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

+
    +
  • 支持多色图标了,不再受单色限制。
  • +
  • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
  • +
  • 兼容性较差,支持 IE9+,及现代浏览器。
  • +
  • 浏览器渲染 SVG 的性能一般,还不如 png。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 symbol 代码:

+
<script src="./iconfont.js"></script>
+
+

第二步:加入通用 CSS 代码(引入一次就行):

+
<style>
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>
+
+

第三步:挑选相应图标并获取类名,应用于页面:

+
<svg class="icon" aria-hidden="true">
+  <use xlink:href="#icon-xxx"></use>
+</svg>
+
+
+
+ +
+
+ + + diff --git a/io.sc.engine.rule.frontend/public/webjars/luckysheet/2.1.13/css/arrow-down.png b/io.sc.engine.rule.frontend/public/webjars/luckysheet/2.1.13/css/arrow-down.png new file mode 100644 index 0000000000000000000000000000000000000000..89a612f6e6aeac91bf76c8272865fd75837fce95 GIT binary patch literal 85 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1n!3HFw&5r&6QZk+{jv*Y;$*WeZ_|e}t^VaR# jl9Ce`I?l5sD_myy6DO1uzwOX1pgIOmS3j3^P6 + + + + diff --git a/io.sc.engine.rule.frontend/src/views/authorization/Authorization.vue b/io.sc.engine.rule.frontend/src/views/authorization/Authorization.vue new file mode 100644 index 00000000..bc1844a1 --- /dev/null +++ b/io.sc.engine.rule.frontend/src/views/authorization/Authorization.vue @@ -0,0 +1,4 @@ + + diff --git a/io.sc.engine.rule.frontend/src/views/resources/AttachmentDialog.vue b/io.sc.engine.rule.frontend/src/views/resources/AttachmentDialog.vue new file mode 100644 index 00000000..7c32ebd3 --- /dev/null +++ b/io.sc.engine.rule.frontend/src/views/resources/AttachmentDialog.vue @@ -0,0 +1,83 @@ + + diff --git a/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/lib/entity/processor/ArithmeticIndicatorProcessorEntity.java b/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/lib/entity/processor/ArithmeticIndicatorProcessorEntity.java new file mode 100644 index 00000000..f686101a --- /dev/null +++ b/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/lib/entity/processor/ArithmeticIndicatorProcessorEntity.java @@ -0,0 +1,58 @@ +package io.sc.engine.rule.server.lib.entity.processor; + +import com.fasterxml.jackson.annotation.JsonTypeName; +import io.sc.engine.rule.core.enums.ProcessorType; +import io.sc.engine.rule.core.util.ExpressionReplacer; +import io.sc.engine.rule.server.lib.entity.IndicatorProcessorEntity; +import io.sc.engine.rule.server.lib.vo.processor.ArithmeticIndicatorProcessorVo; + +import javax.persistence.Column; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import java.util.Map; + +/** + * 指标处理器(算数运算操作)实体类 + */ +@Entity +@DiscriminatorValue("ARITHMETIC") +@JsonTypeName("ARITHMETIC") +public class ArithmeticIndicatorProcessorEntity extends IndicatorProcessorEntity { + //算数表达式 + @Column(name="ARITHMETIC_") + private String arithmetic; + + @Override + public ArithmeticIndicatorProcessorVo toVo() { + ArithmeticIndicatorProcessorVo vo =new ArithmeticIndicatorProcessorVo(); + super.toVo(vo); + vo.setType(this.getType()); + vo.setArithmetic(this.getArithmetic()); + return vo; + } + + @Override + public ProcessorType getType() { + return ProcessorType.ARITHMETIC; + } + + public String getArithmetic() { + return arithmetic; + } + + public void setArithmetic(String arithmetic) { + this.arithmetic = arithmetic; + } + + @Override + public boolean replace(Map mapping) { + String replaced =ExpressionReplacer.replace(this.arithmetic, mapping); + replaced =(replaced==null?"":replaced); + boolean result =false; + if(!replaced.equals(this.arithmetic)) { + result =true; + } + this.arithmetic =replaced; + return result; + } +} diff --git a/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/lib/vo/processor/ArithmeticIndicatorProcessorVo.java b/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/lib/vo/processor/ArithmeticIndicatorProcessorVo.java new file mode 100644 index 00000000..169cc2ba --- /dev/null +++ b/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/lib/vo/processor/ArithmeticIndicatorProcessorVo.java @@ -0,0 +1,26 @@ +package io.sc.engine.rule.server.lib.vo.processor; + +import io.sc.engine.rule.core.enums.ProcessorType; +import io.sc.engine.rule.server.lib.vo.IndicatorProcessorVo; + +/** + * 指标处理器(算数运算操作)Vo 类 + */ +public class ArithmeticIndicatorProcessorVo extends IndicatorProcessorVo { + //算数表达式 + private String arithmetic; + + @Override + public ProcessorType getType() { + return ProcessorType.ARITHMETIC; + } + + public String getArithmetic() { + return arithmetic; + } + + public void setArithmetic(String arithmetic) { + this.arithmetic = arithmetic; + } + +} diff --git a/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/migration/support/AllInOne.java b/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/migration/support/AllInOne.java new file mode 100644 index 00000000..795c305c --- /dev/null +++ b/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/migration/support/AllInOne.java @@ -0,0 +1,33 @@ +package io.sc.engine.rule.server.migration.support; + +import java.util.ArrayList; +import java.util.List; + +import io.sc.engine.rule.core.po.dictionary.Dictionary; +import io.sc.engine.rule.core.po.lib.Lib; +import io.sc.engine.rule.core.po.resource.Resource; + +public class AllInOne { + private List resources =new ArrayList(); + private List libs =new ArrayList(); + private List dictionaries =new ArrayList(); + + public List getResources() { + return resources; + } + public void setResources(List resources) { + this.resources = resources; + } + public List getLibs() { + return libs; + } + public void setLibs(List libs) { + this.libs = libs; + } + public List getDictionaries() { + return dictionaries; + } + public void setDictionaries(List dictionaries) { + this.dictionaries = dictionaries; + } +} diff --git a/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/model/entity/processor/ArithmeticParameterProcessorEntity.java b/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/model/entity/processor/ArithmeticParameterProcessorEntity.java new file mode 100644 index 00000000..1685d34b --- /dev/null +++ b/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/model/entity/processor/ArithmeticParameterProcessorEntity.java @@ -0,0 +1,57 @@ +package io.sc.engine.rule.server.model.entity.processor; + +import com.fasterxml.jackson.annotation.JsonTypeName; +import io.sc.engine.rule.core.enums.ProcessorType; +import io.sc.engine.rule.core.util.ExpressionReplacer; +import io.sc.engine.rule.server.model.entity.ParameterProcessorEntity; +import io.sc.engine.rule.server.model.vo.processor.ArithmeticParameterProcessorVo; + +import javax.persistence.Column; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import java.util.Map; + +/** + * 模型参数处理器(算数运算操作)实体类 + */ +@Entity +@DiscriminatorValue("ARITHMETIC") +@JsonTypeName("ARITHMETIC") +public class ArithmeticParameterProcessorEntity extends ParameterProcessorEntity { + //算数表达式 + @Column(name="ARITHMETIC_") + private String arithmetic; + + @Override + public ArithmeticParameterProcessorVo toVo() { + ArithmeticParameterProcessorVo vo =new ArithmeticParameterProcessorVo(); + super.toVo(vo); + vo.setArithmetic(this.getArithmetic()); + return vo; + } + + @Override + public ProcessorType getType() { + return ProcessorType.ARITHMETIC; + } + + public String getArithmetic() { + return arithmetic; + } + + public void setArithmetic(String arithmetic) { + this.arithmetic = arithmetic; + } + + @Override + public boolean replace(Map mapping) { + String replaced =ExpressionReplacer.replace(this.arithmetic, mapping); + replaced =(replaced==null?"":replaced); + boolean result =false; + if(!replaced.equals(this.arithmetic)) { + result =true; + } + this.arithmetic =replaced; + return result; + } +} diff --git a/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/model/vo/processor/ArithmeticParameterProcessorVo.java b/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/model/vo/processor/ArithmeticParameterProcessorVo.java new file mode 100644 index 00000000..fa5caeeb --- /dev/null +++ b/io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/model/vo/processor/ArithmeticParameterProcessorVo.java @@ -0,0 +1,26 @@ +package io.sc.engine.rule.server.model.vo.processor; + +import io.sc.engine.rule.core.enums.ProcessorType; +import io.sc.engine.rule.server.model.vo.ParameterProcessorVo; + +/** + * 模型参数处理器(算数运算操作)Vo 类 + */ +public class ArithmeticParameterProcessorVo extends ParameterProcessorVo { + + //算数表达式 + private String arithmetic; + + @Override + public ProcessorType getType() { + return ProcessorType.ARITHMETIC; + } + + public String getArithmetic() { + return arithmetic; + } + + public void setArithmetic(String arithmetic) { + this.arithmetic = arithmetic; + } +} diff --git a/io.sc.platform.attachment.api/src/main/java/io/sc/platform/attachment/api/AttachmentVo.java b/io.sc.platform.attachment.api/src/main/java/io/sc/platform/attachment/api/AttachmentVo.java new file mode 100644 index 00000000..3b24b09a --- /dev/null +++ b/io.sc.platform.attachment.api/src/main/java/io/sc/platform/attachment/api/AttachmentVo.java @@ -0,0 +1,66 @@ +package io.sc.platform.attachment.api; + +import io.sc.platform.attachment.api.enums.PersistenceType; +import io.sc.platform.orm.api.vo.AuditorVo; + +public abstract class AttachmentVo extends AuditorVo { + protected String id; + //业务Key + protected String bussinessKey; + //附件持久化类型 + protected PersistenceType type; + //名称 + protected String name; + //扩展名 + protected String extName; + //描述 + protected String description; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getBussinessKey() { + return bussinessKey; + } + + public void setBussinessKey(String bussinessKey) { + this.bussinessKey = bussinessKey; + } + + public PersistenceType getType() { + return type; + } + + public void setType(PersistenceType type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getExtName() { + return extName; + } + + public void setExtName(String extName) { + this.extName = extName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/controller/AttachmentWebController.java b/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/controller/AttachmentWebController.java new file mode 100644 index 00000000..eb6d55fc --- /dev/null +++ b/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/controller/AttachmentWebController.java @@ -0,0 +1,60 @@ +package io.sc.platform.attachment.controller; + +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.List; +import java.util.Locale; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import io.sc.platform.attachment.api.AttachmentVo; +import io.sc.platform.attachment.api.enums.PersistenceType; +import io.sc.platform.attachment.jpa.entity.AttachmentEntity; +import io.sc.platform.attachment.jpa.entity.DatabaseAttachmentEntity; +import io.sc.platform.attachment.jpa.entity.DiskAttachmentEntity; +import io.sc.platform.attachment.jpa.repository.AttachmentRepository; +import io.sc.platform.attachment.service.AttachmentService; +import io.sc.platform.mvc.controller.support.RestCrudController; +import io.sc.platform.mvc.support.FileDownloader; +import org.springframework.stereotype.Controller; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +@Controller +@RequestMapping("/api/system/attachment") +public class AttachmentWebController extends RestCrudController { + + @GetMapping("findByBussinessKey") + @ResponseBody + public List findByBussinessKey(@RequestParam("bussinessKey")String bussinessKey) throws Exception{ + return service.findByBussinessKey(bussinessKey); + } + + @RequestMapping(value="upload/{bussinessKey}",method = RequestMethod.POST) + @ResponseBody + public void add(HttpServletRequest request,@PathVariable("bussinessKey")String bussinessKey,@RequestParam("file") MultipartFile multipartFile,Locale locale) throws Exception{ + service.upload(bussinessKey, request.getParameter("name"), request.getParameter("description"), multipartFile, locale); + } + + @RequestMapping(value="download/{id}",method=RequestMethod.GET) + public void download(HttpServletRequest request,HttpServletResponse response, @PathVariable("id")String id) throws Exception { + AttachmentEntity entity =service.findById(id); + if(entity!=null) { + if(PersistenceType.DISK.equals(entity.getType())) { + DiskAttachmentEntity _entity =(DiskAttachmentEntity)entity; + String file =service.getDiskAttachmentFilePath(_entity); + if(StringUtils.hasText(file)) { + InputStream in =new FileInputStream(file); + FileDownloader.download(request, response, _entity.getName(), in); + } + }else { + DatabaseAttachmentEntity _entity =(DatabaseAttachmentEntity)entity; + InputStream in =new ByteArrayInputStream(_entity.getBytes()); + FileDownloader.download(request, response, _entity.getName(), in); + } + } + } +} \ No newline at end of file diff --git a/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/jpa/entity/AttachmentEntity.java b/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/jpa/entity/AttachmentEntity.java new file mode 100644 index 00000000..5ced5c49 --- /dev/null +++ b/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/jpa/entity/AttachmentEntity.java @@ -0,0 +1,118 @@ +package io.sc.platform.attachment.jpa.entity; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.sc.platform.attachment.api.AttachmentVo; +import io.sc.platform.attachment.api.enums.PersistenceType; +import io.sc.platform.orm.entity.AuditorEntity; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.*; +import javax.validation.constraints.Size; + +/** + * 附件实体类 + */ +@Entity +@Table(name="SYS_ATTACHMENT") +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorColumn(name="PERSISTENCE_TYPE_",discriminatorType=DiscriminatorType.STRING,length=10) +@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type",defaultImpl= DatabaseAttachmentEntity.class) +@JsonSubTypes({ + @JsonSubTypes.Type(value= DiskAttachmentEntity.class), //磁盘文件 + @JsonSubTypes.Type(value= DatabaseAttachmentEntity.class) //数据库 +}) +public abstract class AttachmentEntity extends AuditorEntity { + //ID,主键 + @Id + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "uuid2") + @Column(name="ID_", length=36) + @Size(max=36) + protected String id; + + //业务Key + @Column(name="BUSSINESS_KEY_", length=256) + @Size(max=256) + protected String bussinessKey; + + //附件持久化类型 + @Column(name="PERSISTENCE_TYPE_", insertable=false,updatable=false) + @Enumerated(EnumType.STRING) + protected PersistenceType type; + + //名称 + @Column(name="NAME_", length=256) + @Size(max=256) + protected String name; + + //扩展名 + @Column(name="EXT_NAME_", length=10) + @Size(max=10) + protected String extName; + + //描述 + @Column(name="DESCRIPTION_", length=1024) + @Size(max=1024) + protected String description; + + public void toVo(AttachmentVo vo){ + if(vo!=null){ + super.toVo(vo); + vo.setId(this.getId()); + vo.setBussinessKey(this.getBussinessKey()); + vo.setType(this.getType()); + vo.setName(this.getName()); + vo.setExtName(this.getExtName()); + vo.setDescription(this.getDescription()); + } + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getBussinessKey() { + return bussinessKey; + } + + public void setBussinessKey(String bussinessKey) { + this.bussinessKey = bussinessKey; + } + + public PersistenceType getType() { + return type; + } + + public void setType(PersistenceType type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getExtName() { + return extName; + } + + public void setExtName(String extName) { + this.extName = extName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/jpa/repository/AttachmentRepository.java b/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/jpa/repository/AttachmentRepository.java new file mode 100644 index 00000000..7e8c54d5 --- /dev/null +++ b/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/jpa/repository/AttachmentRepository.java @@ -0,0 +1,18 @@ +package io.sc.platform.attachment.jpa.repository; + +import io.sc.platform.attachment.jpa.entity.AttachmentEntity; +import io.sc.platform.orm.repository.DaoRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Set; + +public interface AttachmentRepository extends DaoRepository { + + public List findByBussinessKeyOrderByName(String bussinessKey); + + + @Query("select e from AttachmentEntity e where e.bussinessKey in (:bussinessKeys)") + public List findByBussinessKeys(@Param("bussinessKeys")Set bussinessKeys); +} diff --git a/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/service/AttachmentService.java b/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/service/AttachmentService.java new file mode 100644 index 00000000..c4d543da --- /dev/null +++ b/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/service/AttachmentService.java @@ -0,0 +1,52 @@ +package io.sc.platform.attachment.service; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import io.sc.platform.attachment.api.AttachmentVo; +import io.sc.platform.attachment.api.DiskAttachmentVo; +import io.sc.platform.attachment.jpa.entity.AttachmentEntity; +import io.sc.platform.attachment.jpa.entity.DiskAttachmentEntity; +import io.sc.platform.attachment.jpa.repository.AttachmentRepository; +import io.sc.platform.orm.service.DaoService; +import org.springframework.web.multipart.MultipartFile; + + +/** + * 附件服务接口 + */ +public interface AttachmentService extends DaoService { + /** + * 通过业务Key查找附件列表 + * @param bussinessKey 业务Key + * @return 附件列表 + */ + public List findByBussinessKey(String bussinessKey); + + /** + * 通过业务Key集合查找附件列表 + * @param bussinessKeys 业务Key集合 + * @return 附件列表Map(Key:bussinessKey,value:附件列表) + */ + public Map> findByBussinessKeys(Set bussinessKeys); + + /** + * 获取磁盘附件的文件路径 + * @param entity 附件对象 + * @return 磁盘附件的文件路径 + */ + public String getDiskAttachmentFilePath(DiskAttachmentEntity entity); + + /** + * + * 上传附件 + * @param bussinessKey 业务 Key + * @param name 附件名称 + * @param description 附件描述 + * @param multipartFile 附件 + * @param locale 区域 + */ + public void upload(String bussinessKey,String name,String description,MultipartFile multipartFile,Locale locale) throws Exception; +} diff --git a/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/service/impl/AttachmentServiceImpl.java b/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/service/impl/AttachmentServiceImpl.java new file mode 100644 index 00000000..1452020f --- /dev/null +++ b/io.sc.platform.attachment/src/main/java/io/sc/platform/attachment/service/impl/AttachmentServiceImpl.java @@ -0,0 +1,116 @@ +package io.sc.platform.attachment.service.impl; + +import io.sc.platform.attachment.api.AttachmentVo; +import io.sc.platform.attachment.api.enums.PersistenceType; +import io.sc.platform.attachment.jpa.entity.AttachmentEntity; +import io.sc.platform.attachment.jpa.entity.DatabaseAttachmentEntity; +import io.sc.platform.attachment.jpa.entity.DiskAttachmentEntity; +import io.sc.platform.attachment.jpa.repository.AttachmentRepository; +import io.sc.platform.attachment.service.AttachmentService; +import io.sc.platform.core.DirectoryManager; +import io.sc.platform.core.util.FileUtil; +import io.sc.platform.mvc.service.SystemParameterService; +import io.sc.platform.orm.service.impl.DaoServiceImpl; +import io.sc.platform.orm.util.EntityVoUtil; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.util.*; + +@Service("frAttachmentService") +public class AttachmentServiceImpl extends DaoServiceImpl implements AttachmentService { + @Autowired private SystemParameterService systemParameterService; + + @Override + public List findByBussinessKey(String bussinessKey) { + return EntityVoUtil.toVo(repository.findByBussinessKeyOrderByName(bussinessKey)); + } + + + @Override + public Map> findByBussinessKeys(Set bussinessKeys) { + if(bussinessKeys!=null && bussinessKeys.size()>0) { + List entities =repository.findByBussinessKeys(bussinessKeys); + if(entities!=null && entities.size()>0) { + Map> result =new HashMap<>(); + for(AttachmentEntity entity : entities) { + List list =result.get(entity.getBussinessKey()); + if(list==null) { + list =new ArrayList(); + list.add(entity.toVo()); + result.put(entity.getBussinessKey(), list); + }else { + list.add(entity.toVo()); + } + } + return result; + } + } + return null; + } + + + + @Override + public String getDiskAttachmentFilePath(DiskAttachmentEntity entity) { + if(entity!=null) { + String path = DirectoryManager.getInstance().getByName("dir.work.web.upload"); + String attachmentPath =entity.getPath(); + if(StringUtils.hasText(attachmentPath)) { + if(attachmentPath.startsWith("/") || attachmentPath.startsWith("\\")) { + path =path + attachmentPath; + }else { + path =path + File.separator + attachmentPath; + } + } + if(path.endsWith("/") || path.endsWith("\\")) { + path =path + entity.getId() + entity.getExtName(); + }else { + path =path + File.separator + entity.getId() + entity.getExtName(); + } + return path; + } + return null; + } + + @Override + public void upload(String bussinessKey, String name, String description, MultipartFile multipartFile,Locale locale) throws Exception{ + if(multipartFile!=null) { + InputStream ins = multipartFile.getInputStream(); + byte[] bytes = new byte[ins.available()]; + ins.read(bytes); + ins.close(); + + String attachmentPersistenceType = systemParameterService.getParameter("attachmentPersistenceType"); + if (PersistenceType.DISK.equals(PersistenceType.valueOf(attachmentPersistenceType))) { + DiskAttachmentEntity _entity = new DiskAttachmentEntity(); + _entity.setPath("/"); + _entity.setBussinessKey(bussinessKey); + _entity.setName(name); + _entity.setExtName(FileUtil.getFileExtName(multipartFile.getOriginalFilename())); + _entity.setDescription(description); + AttachmentEntity entity = add(_entity); + persistence2Disk((DiskAttachmentEntity) entity, bytes); + } else { + DatabaseAttachmentEntity _entity = new DatabaseAttachmentEntity(); + _entity.setBussinessKey(bussinessKey); + _entity.setName(name); + _entity.setExtName(FileUtil.getFileExtName(multipartFile.getName())); + _entity.setDescription(description); + _entity.setBytes(bytes); + add(_entity); + } + } + } + + private void persistence2Disk(DiskAttachmentEntity entity,byte[] bytes) throws FileNotFoundException, IOException { + String file =getDiskAttachmentFilePath(entity); + if(StringUtils.hasText(file)) { + IOUtils.copy(new ByteArrayInputStream(bytes), new FileOutputStream(file)); + } + } +} diff --git a/io.sc.platform.orm/src/main/java/io/sc/platform/orm/entity/AuditorEntity.java b/io.sc.platform.orm/src/main/java/io/sc/platform/orm/entity/AuditorEntity.java index 09773243..bf001d4a 100644 --- a/io.sc.platform.orm/src/main/java/io/sc/platform/orm/entity/AuditorEntity.java +++ b/io.sc.platform.orm/src/main/java/io/sc/platform/orm/entity/AuditorEntity.java @@ -55,7 +55,7 @@ public abstract class AuditorEntity extends VersionEntity