diff --git a/app.platform/build.gradle b/app.platform/build.gradle index e7a99eb5..fd6cb77e 100644 --- a/app.platform/build.gradle +++ b/app.platform/build.gradle @@ -16,6 +16,9 @@ dependencies { project(":io.sc.platform.developer"), project(":io.sc.standard"), + // ai + project(":io.sc.platform.ai"), + // 调度 project(":io.sc.platform.scheduler.manager"), project(":io.sc.platform.scheduler.executor"), diff --git a/build-version.gradle b/build-version.gradle index 36742105..b75a321c 100755 --- a/build-version.gradle +++ b/build-version.gradle @@ -16,6 +16,15 @@ ext['PlatformDependencyVersions'] =[ "org.codehaus.groovy:groovy-sql" : "${groovy_version}", "org.codehaus.groovy:groovy-xml" : "${groovy_version}", "mysql:mysql-connector-java" : "${jdbc_mysql_version}", + "com.oracle.database.jdbc:ojdbc8" : "${jdbc_oracle_version}", + "org.mybatis:mybatis" : "${mybatis_version}", + "org.apache.commons:commons-compress" : "${commons_compress_version}", + "com.github.virtuald:curvesapi" : "${curvesapi_version}", + "org.jetbrains.kotlin:kotlin-stdlib" : "${kotlin_stdlib_version}", + "org.apache.poi:poi" : "${poi_version}", + "org.apache.poi:poi-ooxml" : "${poi_version}", + "org.reflections:reflections" : "${reflections_version}", + "com.squareup.okhttp3:okhttp" : "${okhttp_version}" ]; /*********************************************************************** diff --git a/build.gradle b/build.gradle index ec33b579..e01ce4dc 100644 --- a/build.gradle +++ b/build.gradle @@ -59,6 +59,7 @@ subprojects { // exclude group: "org.apache.logging.log4j", module: "log4j-to-slf4j" // exclude group: "org.slf4j", module: "slf4j-jdk14" exclude group: "org.slf4j", module: "slf4j-nop" + exclude group: "org.slf4j", module: "slf4j-reload4j" //exclude group: "com.mysql", module: "mysql-connector-j" if(PlatformDependencyVersions!=null && PlatformDependencyVersions.size()>0) { @@ -751,6 +752,37 @@ subprojects { excludeDirs += file('dist') } } + + task classpath() {} + tasks.classpath.doFirst { + if(isFrontendProject(file('.'))){ + println '开始执行 classpath ......' + } + } + tasks.classpath.doLast { + List jars =new ArrayList<>(); + def doc =new XmlParser().parse(file(project.name + '.iml').absolutePath); + doc.component.each { component -> + if(component.@name=='NewModuleRootManager'){ + component.orderEntry.each { entry -> + if(entry.@type=='module-library'){ + entry.library.CLASSES.root.each { jar -> + String url =jar.@url; + url =url.substring(0,url.length()-2); + url =url.substring(url.lastIndexOf('/')+1); + jars.add(url); + } + } + } + } + } + Collections.sort(jars); + println project.name + ' dependencies jars : {' + jars.each { + println ' ' + it; + } + println '}'; + } } /*********************************************************************** @@ -902,6 +934,16 @@ cleanIdea { dependsOn cleanIdeaWorkspace } +/*----------------------------------------------------------------- + * 清除 IDEA 的所有配置,回复到初始安装状态 + *----------------------------------------------------------------*/ +task cleanIdeaSettings(){} +tasks.cleanIdeaSettings.doFirst { + delete System.getProperty("user.home") + "/Library/Application Support/JetBrains" + delete System.getProperty("user.home") + "/Library/Logs/JetBrains" + delete System.getProperty("user.home") + "/Library/Caches/JetBrains" +} + task github { println '' } diff --git a/erm.frontend/package.json b/erm.frontend/package.json index 5a93f903..e55f39c5 100644 --- a/erm.frontend/package.json +++ b/erm.frontend/package.json @@ -87,6 +87,7 @@ "@codemirror/view": "6.36.2", "@maxgraph/core": "0.14.0", "@quasar/extras": "1.16.15", + "@quasar/quasar-ui-qmarkdown": "2.0.5", "@univerjs/core": "0.5.4", "@univerjs/design": "0.5.4", "@univerjs/docs": "0.5.4", @@ -100,7 +101,7 @@ "@univerjs/thread-comment": "0.5.4", "@univerjs/ui": "0.5.4", "@vueuse/core": "12.4.0", - "axios": "1.7.9", + "axios": "1.8.2", "codemirror": "6.0.1", "dayjs": "1.11.13", "echarts": "5.6.0", @@ -111,7 +112,7 @@ "node-sql-parser": "5.3.6", "pinia": "2.3.0", "pinia-undo": "0.2.4", - "platform-core": "8.2.40", + "platform-core": "8.2.48", "quasar": "2.17.6", "sort-array": "5.0.0", "svg-path-commander": "2.1.7", diff --git a/erm.frontend/src/boostrap.ts b/erm.frontend/src/boostrap.ts index 31a30449..4193c068 100644 --- a/erm.frontend/src/boostrap.ts +++ b/erm.frontend/src/boostrap.ts @@ -15,6 +15,8 @@ import App from './App.vue'; import 'platform-core/dist/css/platform-core.css'; // 导入 tailwind utilities css import 'tailwindcss/utilities.css'; +// 导入 quasar-ui-qmarkdown css +import '@quasar/quasar-ui-qmarkdown/dist/index.css'; // 设置远程组件加载器 // 覆盖 platform-core 包中的 remoteComponentLoader 函数 diff --git a/erm.frontend/webpack.config.common.cjs b/erm.frontend/webpack.config.common.cjs index e8726c5b..b154bfff 100644 --- a/erm.frontend/webpack.config.common.cjs +++ b/erm.frontend/webpack.config.common.cjs @@ -22,7 +22,7 @@ module.exports = { // 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录 path: path.resolve(__dirname, `dist/public/${projectName}`), // 输出文件名 - filename: `javascript/[name].[contenthash:5].js`, + filename: `javascript/[name].[contenthash:6].js`, // 指定发布路径,使用 auto 可具有更多灵活性 publicPath: 'auto', // 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果 @@ -69,7 +69,7 @@ module.exports = { test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/, type: 'asset/resource', generator: { - filename: `fonts/[name].[contenthash:5].[ext]`, + filename: `fonts/[name].[contenthash:6].[ext]`, }, }, @@ -122,8 +122,8 @@ module.exports = { // css 抽取插件 new MiniCssExtractPlugin({ - filename: `css/[name].[contenthash:5].css`, - chunkFilename: `css/[name].[contenthash:5].css`, + filename: `css/[name].[contenthash:6].css`, + chunkFilename: `css/[name].[contenthash:6].css`, }), // 自动生成静态 index.html 文件 diff --git a/erm.frontend/webpack.config.mf.cjs b/erm.frontend/webpack.config.mf.cjs index 45ba1169..b61795a4 100644 --- a/erm.frontend/webpack.config.mf.cjs +++ b/erm.frontend/webpack.config.mf.cjs @@ -1,19 +1,19 @@ /** * webpack module federation 配置 */ -const fs = require('fs'); // 文件读取 -const Json5 =require('json5'); // json5 -const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 -const packageJson = require('./package.json'); // package.json -const projectName =packageJson.name; // 项目名称 -const deps = packageJson.dependencies; // 项目依赖 +const fs = require('fs'); // 文件读取 +const Json5 = require('json5'); // json5 +const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 +const packageJson = require('./package.json'); // package.json +const projectName = packageJson.name; // 项目名称 +const deps = packageJson.dependencies; // 项目依赖 // 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值 const data = fs.readFileSync('./src/routes/routes.json', 'utf8'); -const routes =Json5.parse(data); -const mfExposes ={}; -for(const route of routes){ - mfExposes[route.component]= route.componentPath; +const routes = Json5.parse(data); +const mfExposes = {}; +for (const route of routes) { + mfExposes[route.component] = route.componentPath; } // 导出 webapck 配置的模块联邦部分 @@ -57,24 +57,25 @@ module.exports = { '@univerjs/thread-comment': { requiredVersion: deps['@univerjs/thread-comment'], singleton: true }, '@univerjs/ui': { requiredVersion: deps['@univerjs/ui'], singleton: true }, '@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true }, - 'axios': { requiredVersion: deps['axios'], singleton: true }, - 'codemirror': { requiredVersion: deps['codemirror'], singleton: true }, - 'dayjs': { requiredVersion: deps['dayjs'], singleton: true }, - 'echarts':{ requiredVersion: deps['echarts'], singleton: true }, - 'exceljs':{ requiredVersion: deps['exceljs'], singleton: true }, - 'file-saver':{ requiredVersion: deps['file-saver'], singleton: true }, - 'luckyexcel':{ requiredVersion: deps['luckyexcel'], singleton: true }, - 'mockjs': { requiredVersion: deps['mockjs'], singleton: true }, - 'pinia': { requiredVersion: deps['pinia'], singleton: true }, + axios: { requiredVersion: deps['axios'], singleton: true }, + codemirror: { requiredVersion: deps['codemirror'], singleton: true }, + dayjs: { requiredVersion: deps['dayjs'], singleton: true }, + echarts: { requiredVersion: deps['echarts'], singleton: true }, + exceljs: { requiredVersion: deps['exceljs'], singleton: true }, + 'file-saver': { requiredVersion: deps['file-saver'], singleton: true }, + luckyexcel: { requiredVersion: deps['luckyexcel'], singleton: true }, + mockjs: { requiredVersion: deps['mockjs'], singleton: true }, + pinia: { requiredVersion: deps['pinia'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, - 'quasar': { requiredVersion: deps['quasar'], singleton: true }, + quasar: { requiredVersion: deps['quasar'], singleton: true }, + '@quasar/quasar-ui-qmarkdown': { requiredVersion: deps['@quasar/quasar-ui-qmarkdown'], singleton: true }, 'svg-path-commander': { requiredVersion: deps['svg-path-commander'], singleton: true }, - 'vue': { requiredVersion: deps['vue'], singleton: true }, - 'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, + vue: { requiredVersion: deps['vue'], singleton: true }, + 'vue-dompurify-html': { requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, - 'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true } - } + 'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true }, + }, }), - ] + ], }; diff --git a/erm.frontend/webpack.env.build.cjs b/erm.frontend/webpack.env.build.cjs index fbcf0fbe..446848cf 100644 --- a/erm.frontend/webpack.env.build.cjs +++ b/erm.frontend/webpack.env.build.cjs @@ -1,9 +1,9 @@ /** * 开发环境构建 */ -const { merge } = require('webpack-merge'); // webpack 配置合并函数 -const common = require('./webpack.config.common.cjs'); // webpack 通用配置 -const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置 +const { merge } = require('webpack-merge'); // webpack 配置合并函数 +const common = require('./webpack.config.common.cjs'); // webpack 通用配置 +const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置 module.exports = merge(common, mf, { mode: 'development', @@ -22,76 +22,76 @@ module.exports = merge(common, mf, { splitChunks: { cacheGroups: { - 'shared': { + shared: { name: 'vue', test: /[\\/]node_modules[\\/](axios|dayjs|exceljs|file-saver|luckyexcel|mockjs|xml-formatter)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'vue': { + vue: { name: 'vue', test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router|pinia|@vueuse[\\/]core)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'codemirror':{ + codemirror: { name: 'codemirror', test: /[\\/]node_modules[\\/](codemirror|@codemirror[\\/]autocomplete|@codemirror[\\/]commands|@codemirror[\\/]lang-html|@codemirror[\\/]lang-java|@codemirror[\\/]lang-javascript|@codemirror[\\/]lang-json|@codemirror[\\/]lang-sql|@codemirror[\\/]lang-xml|@codemirror[\\/]language|@codemirror[\\/]search|@codemirror[\\/]state|@codemirror[\\/]view)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'quasar': { + quasar: { name: 'quasar', - test: /[\\/]node_modules[\\/](quasar)[\\/]/, + test: /[\\/]node_modules[\\/](quasar|@quasar[\\/]quasar-ui-qmarkdown)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, 'platform-core': { name: 'platform-core', test: /[\\/]node_modules[\\/]platform-core[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'echarts': { + echarts: { name: 'echarts', test: /[\\/]node_modules[\\/]echarts[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'maxgraph': { + maxgraph: { name: 'maxgraph', test: /[\\/]node_modules[\\/]@maxgraph[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, '@univerjs': { name: '@univerjs', test: /[\\/]node_modules[\\/]@univerjs[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'view': { + view: { name: 'view', test: /[\\/]view[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'vendors': { + vendors: { name: 'vendors', test: /[\\/]node_modules[\\/]/, chunks: 'all', - enforce: true + enforce: true, }, - } - } + }, + }, }, }); diff --git a/gradle.properties b/gradle.properties index e7c8ec43..f4970f70 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,17 +39,20 @@ application_version=1.0.0 platform_group=io.sc platform_version=8.2.10 platform_plugin_version=8.2.10 -platform_core_frontend_version=8.2.40 +platform_core_frontend_version=8.2.48 ########################################################### # dependencies version ########################################################### +ai4j_version=1.2.0 asciidoctor_version=3.3.2 asm_version=9.7.1 checker_version=3.43.0 +commons_compress_version=1.25.0 commons_fileupload_version=1.4 commons_io_version=2.16.1 commons_text_version=1.12.0 +curvesapi_version=1.08 cxf_version=3.2.7 dm_hibernate_version=8.1.2.192 enjoy_version=5.2.2 @@ -64,18 +67,24 @@ jboss_logging_version=3.3.2.Final jcommander_version=1.82 jdbc_dm_version=8.1.2.192 jdbc_mysql_version=5.1.49 +jdbc_oracle_version=19.23.0.0 jib_version=3.3.2 jjwt_version=0.9.1 jxls_jexcel_version=1.0.7 jxls_poi_version=1.0.15 jxls_version=2.4.6 -mybatis_version=2.3.2 +kotlin_stdlib_version=1.9.25 +mybatis_version=3.5.14 +mybatis_spring_boot_starter_version=2.3.2 nimbusds_version=9.22 +ollama4j_version=1.0.78 +okhttp_version=4.12.0 opencsv_version=5.7.1 oshi_version=6.6.1 p6spy_version=3.9.1 pinyin4j_version=2.5.1 poi_version=5.2.5 +reflections_version=0.10.2 schemacrawler_version=16.19.11 shadow_gradle_plugin_version=8.3.1 spring_boot_version=2.7.18 diff --git a/io.sc.engine.mv.frontend/package.json b/io.sc.engine.mv.frontend/package.json index 90ff00a7..cc09c604 100644 --- a/io.sc.engine.mv.frontend/package.json +++ b/io.sc.engine.mv.frontend/package.json @@ -87,6 +87,7 @@ "@codemirror/view": "6.36.2", "@maxgraph/core": "0.14.0", "@quasar/extras": "1.16.15", + "@quasar/quasar-ui-qmarkdown": "2.0.5", "@univerjs/core": "0.5.4", "@univerjs/design": "0.5.4", "@univerjs/docs": "0.5.4", @@ -100,7 +101,7 @@ "@univerjs/thread-comment": "0.5.4", "@univerjs/ui": "0.5.4", "@vueuse/core": "12.4.0", - "axios": "1.7.9", + "axios": "1.8.2", "codemirror": "6.0.1", "dayjs": "1.11.13", "echarts": "5.6.0", @@ -111,7 +112,7 @@ "node-sql-parser": "5.3.6", "pinia": "2.3.0", "pinia-undo": "0.2.4", - "platform-core": "8.2.40", + "platform-core": "8.2.48", "quasar": "2.17.6", "sort-array": "5.0.0", "svg-path-commander": "2.1.7", diff --git a/io.sc.engine.mv.frontend/src/boostrap.ts b/io.sc.engine.mv.frontend/src/boostrap.ts index 31a30449..4193c068 100644 --- a/io.sc.engine.mv.frontend/src/boostrap.ts +++ b/io.sc.engine.mv.frontend/src/boostrap.ts @@ -15,6 +15,8 @@ import App from './App.vue'; import 'platform-core/dist/css/platform-core.css'; // 导入 tailwind utilities css import 'tailwindcss/utilities.css'; +// 导入 quasar-ui-qmarkdown css +import '@quasar/quasar-ui-qmarkdown/dist/index.css'; // 设置远程组件加载器 // 覆盖 platform-core 包中的 remoteComponentLoader 函数 diff --git a/io.sc.engine.mv.frontend/src/views/result/Result.vue b/io.sc.engine.mv.frontend/src/views/result/Result.vue index fdf73dd4..30b3db13 100644 --- a/io.sc.engine.mv.frontend/src/views/result/Result.vue +++ b/io.sc.engine.mv.frontend/src/views/result/Result.vue @@ -13,6 +13,7 @@ :title="$t('menu.engine.mv.result')" :config-button="true" dense-header + db-click-operation="detail" selection="multiple" :checkbox-selection="false" :data-url="Environment.apiContextPath('/api/mv/viewer/result')" diff --git a/io.sc.engine.mv.frontend/src/views/result/ResultDetailDialog.vue b/io.sc.engine.mv.frontend/src/views/result/ResultDetailDialog.vue index 6e5ce949..4daa87f2 100644 --- a/io.sc.engine.mv.frontend/src/views/result/ResultDetailDialog.vue +++ b/io.sc.engine.mv.frontend/src/views/result/ResultDetailDialog.vue @@ -121,20 +121,20 @@ :pageable="false" :toolbar-actions="['refresh', 'separator', 'export']" :columns="[ - { width: 30, name: 'level', label: $t('io.sc.engine.mv.result.binomial.level'), align: 'right' }, - { width: 30, name: 'pd', label: $t('io.sc.engine.mv.result.binomial.pd'), align: 'right' }, - { width: 30, name: 'count', label: $t('io.sc.engine.mv.result.binomial.count'), align: 'right' }, - { width: 50, name: 'defaultCount', label: $t('io.sc.engine.mv.result.binomial.defaultCount'), align: 'right' }, - { width: 50, name: 'ndAvg', label: $t('io.sc.engine.mv.result.binomial.ndAvg'), align: 'right', hidden: true }, - { width: 50, name: 'ndSd', label: $t('io.sc.engine.mv.result.binomial.ndSd'), align: 'right', hidden: true }, - { width: 50, name: 'sl', label: $t('io.sc.engine.mv.result.binomial.sl'), align: 'right', hidden: true }, - { width: 50, name: 'cl', label: $t('io.sc.engine.mv.result.binomial.cl'), align: 'right', hidden: true }, - { width: 50, name: 'zUpper', label: $t('io.sc.engine.mv.result.binomial.zUpper'), align: 'right', hidden: true }, - { width: 50, name: 'zLower', label: $t('io.sc.engine.mv.result.binomial.zLower'), align: 'right', hidden: true }, - { width: 50, name: 'dUpper', label: $t('io.sc.engine.mv.result.binomial.dUpper'), align: 'right', hidden: true }, - { width: 50, name: 'dLower', label: $t('io.sc.engine.mv.result.binomial.dLower'), align: 'right', hidden: true }, - { width: 50, name: 'leUpper', label: $t('io.sc.engine.mv.result.binomial.leUpper'), align: 'center', format: passOrNotFormater }, - { width: 50, name: 'geLower', label: $t('io.sc.engine.mv.result.binomial.geLower'), align: 'center', format: passOrNotFormater }, + { width: 90, name: 'level', label: $t('io.sc.engine.mv.result.binomial.level'), align: 'right' }, + { width: 90, name: 'pd', label: $t('io.sc.engine.mv.result.binomial.pd'), align: 'right' }, + { width: 140, name: 'count', label: $t('io.sc.engine.mv.result.binomial.count'), align: 'right', format: Formater.thousands() }, + { width: 140, name: 'defaultCount', label: $t('io.sc.engine.mv.result.binomial.defaultCount'), align: 'right' }, + { width: 120, name: 'ndAvg', label: $t('io.sc.engine.mv.result.binomial.ndAvg'), align: 'right', hidden: true }, + { width: 120, name: 'ndSd', label: $t('io.sc.engine.mv.result.binomial.ndSd'), align: 'right', hidden: true }, + { width: 90, name: 'sl', label: $t('io.sc.engine.mv.result.binomial.sl'), align: 'right', hidden: true }, + { width: 90, name: 'cl', label: $t('io.sc.engine.mv.result.binomial.cl'), align: 'right', hidden: true }, + { width: 130, name: 'zUpper', label: $t('io.sc.engine.mv.result.binomial.zUpper'), align: 'right', hidden: true }, + { width: 130, name: 'zLower', label: $t('io.sc.engine.mv.result.binomial.zLower'), align: 'right', hidden: true }, + { width: 100, name: 'dUpper', label: $t('io.sc.engine.mv.result.binomial.dUpper'), align: 'right', hidden: true }, + { width: 100, name: 'dLower', label: $t('io.sc.engine.mv.result.binomial.dLower'), align: 'right', hidden: true }, + { width: 220, name: 'leUpper', label: $t('io.sc.engine.mv.result.binomial.leUpper'), align: 'center', format: passOrNotFormater }, + { width: 220, name: 'geLower', label: $t('io.sc.engine.mv.result.binomial.geLower'), align: 'center', format: passOrNotFormater }, ]" > diff --git a/io.sc.engine.mv.frontend/src/views/sample/Sample.vue b/io.sc.engine.mv.frontend/src/views/sample/Sample.vue index 51e145b5..e53690b8 100644 --- a/io.sc.engine.mv.frontend/src/views/sample/Sample.vue +++ b/io.sc.engine.mv.frontend/src/views/sample/Sample.vue @@ -51,10 +51,10 @@ 'export', ]" :columns="[ - { width: 100, name: 'customId', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.customId') }, - { width: 100, name: 'customName', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.customName') }, + { width: 140, name: 'customId', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.customId') }, + { width: 150, name: 'customName', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.customName') }, { width: 120, name: 'modelId', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.modelId') }, - { width: 150, name: 'modelName', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.modelName') }, + { width: 140, name: 'modelName', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.modelName') }, { width: 90, name: 'pd', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.pd'), align: 'right' }, { width: 90, name: 'score', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.score'), align: 'right' }, { width: 90, name: 'scoreQuantitative', label: $t('io.sc.engine.mv.sample.scoreRecord.grid.entity.scoreQuantitative'), align: 'right' }, @@ -95,8 +95,8 @@ :toolbar-configure="{ noIcon: false }" :toolbar-actions="['refresh', 'separator', 'view', 'separator', 'export']" :columns="[ - { width: 100, name: 'customId', label: $t('io.sc.engine.mv.sample.defaultRecord.grid.entity.customId') }, - { width: 100, name: 'defaultConfirmDate', label: $t('io.sc.engine.mv.sample.defaultRecord.grid.entity.defaultConfirmDate') }, + { width: 200, name: 'customId', label: $t('io.sc.engine.mv.sample.defaultRecord.grid.entity.customId') }, + { width: '100%', name: 'defaultConfirmDate', label: $t('io.sc.engine.mv.sample.defaultRecord.grid.entity.defaultConfirmDate') }, ]" :viewer="{ panel: { diff --git a/io.sc.engine.mv.frontend/webpack.config.common.cjs b/io.sc.engine.mv.frontend/webpack.config.common.cjs index e8726c5b..b154bfff 100644 --- a/io.sc.engine.mv.frontend/webpack.config.common.cjs +++ b/io.sc.engine.mv.frontend/webpack.config.common.cjs @@ -22,7 +22,7 @@ module.exports = { // 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录 path: path.resolve(__dirname, `dist/public/${projectName}`), // 输出文件名 - filename: `javascript/[name].[contenthash:5].js`, + filename: `javascript/[name].[contenthash:6].js`, // 指定发布路径,使用 auto 可具有更多灵活性 publicPath: 'auto', // 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果 @@ -69,7 +69,7 @@ module.exports = { test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/, type: 'asset/resource', generator: { - filename: `fonts/[name].[contenthash:5].[ext]`, + filename: `fonts/[name].[contenthash:6].[ext]`, }, }, @@ -122,8 +122,8 @@ module.exports = { // css 抽取插件 new MiniCssExtractPlugin({ - filename: `css/[name].[contenthash:5].css`, - chunkFilename: `css/[name].[contenthash:5].css`, + filename: `css/[name].[contenthash:6].css`, + chunkFilename: `css/[name].[contenthash:6].css`, }), // 自动生成静态 index.html 文件 diff --git a/io.sc.engine.mv.frontend/webpack.config.mf.cjs b/io.sc.engine.mv.frontend/webpack.config.mf.cjs index 45ba1169..b61795a4 100644 --- a/io.sc.engine.mv.frontend/webpack.config.mf.cjs +++ b/io.sc.engine.mv.frontend/webpack.config.mf.cjs @@ -1,19 +1,19 @@ /** * webpack module federation 配置 */ -const fs = require('fs'); // 文件读取 -const Json5 =require('json5'); // json5 -const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 -const packageJson = require('./package.json'); // package.json -const projectName =packageJson.name; // 项目名称 -const deps = packageJson.dependencies; // 项目依赖 +const fs = require('fs'); // 文件读取 +const Json5 = require('json5'); // json5 +const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 +const packageJson = require('./package.json'); // package.json +const projectName = packageJson.name; // 项目名称 +const deps = packageJson.dependencies; // 项目依赖 // 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值 const data = fs.readFileSync('./src/routes/routes.json', 'utf8'); -const routes =Json5.parse(data); -const mfExposes ={}; -for(const route of routes){ - mfExposes[route.component]= route.componentPath; +const routes = Json5.parse(data); +const mfExposes = {}; +for (const route of routes) { + mfExposes[route.component] = route.componentPath; } // 导出 webapck 配置的模块联邦部分 @@ -57,24 +57,25 @@ module.exports = { '@univerjs/thread-comment': { requiredVersion: deps['@univerjs/thread-comment'], singleton: true }, '@univerjs/ui': { requiredVersion: deps['@univerjs/ui'], singleton: true }, '@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true }, - 'axios': { requiredVersion: deps['axios'], singleton: true }, - 'codemirror': { requiredVersion: deps['codemirror'], singleton: true }, - 'dayjs': { requiredVersion: deps['dayjs'], singleton: true }, - 'echarts':{ requiredVersion: deps['echarts'], singleton: true }, - 'exceljs':{ requiredVersion: deps['exceljs'], singleton: true }, - 'file-saver':{ requiredVersion: deps['file-saver'], singleton: true }, - 'luckyexcel':{ requiredVersion: deps['luckyexcel'], singleton: true }, - 'mockjs': { requiredVersion: deps['mockjs'], singleton: true }, - 'pinia': { requiredVersion: deps['pinia'], singleton: true }, + axios: { requiredVersion: deps['axios'], singleton: true }, + codemirror: { requiredVersion: deps['codemirror'], singleton: true }, + dayjs: { requiredVersion: deps['dayjs'], singleton: true }, + echarts: { requiredVersion: deps['echarts'], singleton: true }, + exceljs: { requiredVersion: deps['exceljs'], singleton: true }, + 'file-saver': { requiredVersion: deps['file-saver'], singleton: true }, + luckyexcel: { requiredVersion: deps['luckyexcel'], singleton: true }, + mockjs: { requiredVersion: deps['mockjs'], singleton: true }, + pinia: { requiredVersion: deps['pinia'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, - 'quasar': { requiredVersion: deps['quasar'], singleton: true }, + quasar: { requiredVersion: deps['quasar'], singleton: true }, + '@quasar/quasar-ui-qmarkdown': { requiredVersion: deps['@quasar/quasar-ui-qmarkdown'], singleton: true }, 'svg-path-commander': { requiredVersion: deps['svg-path-commander'], singleton: true }, - 'vue': { requiredVersion: deps['vue'], singleton: true }, - 'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, + vue: { requiredVersion: deps['vue'], singleton: true }, + 'vue-dompurify-html': { requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, - 'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true } - } + 'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true }, + }, }), - ] + ], }; diff --git a/io.sc.engine.mv.frontend/webpack.env.build.cjs b/io.sc.engine.mv.frontend/webpack.env.build.cjs index fbcf0fbe..446848cf 100644 --- a/io.sc.engine.mv.frontend/webpack.env.build.cjs +++ b/io.sc.engine.mv.frontend/webpack.env.build.cjs @@ -1,9 +1,9 @@ /** * 开发环境构建 */ -const { merge } = require('webpack-merge'); // webpack 配置合并函数 -const common = require('./webpack.config.common.cjs'); // webpack 通用配置 -const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置 +const { merge } = require('webpack-merge'); // webpack 配置合并函数 +const common = require('./webpack.config.common.cjs'); // webpack 通用配置 +const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置 module.exports = merge(common, mf, { mode: 'development', @@ -22,76 +22,76 @@ module.exports = merge(common, mf, { splitChunks: { cacheGroups: { - 'shared': { + shared: { name: 'vue', test: /[\\/]node_modules[\\/](axios|dayjs|exceljs|file-saver|luckyexcel|mockjs|xml-formatter)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'vue': { + vue: { name: 'vue', test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router|pinia|@vueuse[\\/]core)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'codemirror':{ + codemirror: { name: 'codemirror', test: /[\\/]node_modules[\\/](codemirror|@codemirror[\\/]autocomplete|@codemirror[\\/]commands|@codemirror[\\/]lang-html|@codemirror[\\/]lang-java|@codemirror[\\/]lang-javascript|@codemirror[\\/]lang-json|@codemirror[\\/]lang-sql|@codemirror[\\/]lang-xml|@codemirror[\\/]language|@codemirror[\\/]search|@codemirror[\\/]state|@codemirror[\\/]view)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'quasar': { + quasar: { name: 'quasar', - test: /[\\/]node_modules[\\/](quasar)[\\/]/, + test: /[\\/]node_modules[\\/](quasar|@quasar[\\/]quasar-ui-qmarkdown)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, 'platform-core': { name: 'platform-core', test: /[\\/]node_modules[\\/]platform-core[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'echarts': { + echarts: { name: 'echarts', test: /[\\/]node_modules[\\/]echarts[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'maxgraph': { + maxgraph: { name: 'maxgraph', test: /[\\/]node_modules[\\/]@maxgraph[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, '@univerjs': { name: '@univerjs', test: /[\\/]node_modules[\\/]@univerjs[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'view': { + view: { name: 'view', test: /[\\/]view[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'vendors': { + vendors: { name: 'vendors', test: /[\\/]node_modules[\\/]/, chunks: 'all', - enforce: true + enforce: true, }, - } - } + }, + }, }, }); diff --git a/io.sc.engine.mv/src/main/java/io/sc/engine/mv/viewer/controller/CoeBinomialHistoryWebController.java b/io.sc.engine.mv/src/main/java/io/sc/engine/mv/viewer/controller/CoeBinomialHistoryWebController.java index cfec3501..0f31bb7d 100644 --- a/io.sc.engine.mv/src/main/java/io/sc/engine/mv/viewer/controller/CoeBinomialHistoryWebController.java +++ b/io.sc.engine.mv/src/main/java/io/sc/engine/mv/viewer/controller/CoeBinomialHistoryWebController.java @@ -6,9 +6,12 @@ import io.sc.engine.mv.viewer.jpa.entity.id.CoeBinomialHistoryId; import io.sc.engine.mv.viewer.jpa.repository.CoeBinomialHistoryRepository; import io.sc.engine.mv.viewer.service.CoeBinomialHistoryService; import io.sc.engine.mv.viewer.vo.CoeBinomialHistoryVo; +import io.sc.engine.mv.viewer.vo.CoeChiSquareHistoryVo; import io.sc.platform.mvc.controller.support.RestCrudController; import io.sc.platform.orm.service.support.CriteriaBuilder; import io.sc.platform.orm.service.support.QueryParameter; +import io.sc.platform.orm.service.support.QueryResult; +import io.sc.platform.util.support.NumberStringComparator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.web.bind.annotation.GetMapping; @@ -18,6 +21,10 @@ import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; @RestController("io.sc.engine.mv.viewer.controller.CoeBinomialHistoryWebController") @RequestMapping("/api/mv/viewer/binomial") @@ -42,6 +49,31 @@ public class CoeBinomialHistoryWebController extends RestCrudController page =super.query(request,response,queryParameter); + String sortPropertyName =queryParameter.getFirstSort().getProperty(); + if("level".equals(sortPropertyName)){ + boolean isAscending =queryParameter.getFirstSort().isAscending(); + return QueryResult.sort(page,new CoeBinomialHistoryVoComparator(isAscending)); + }else{ + return page; + } + } + + private class CoeBinomialHistoryVoComparator implements Comparator { + private NumberStringComparator numberStringComparator =new NumberStringComparator(); + private boolean isAscending =true; + + public CoeBinomialHistoryVoComparator(boolean isAscending){ + this.isAscending =isAscending; + } + + @Override + public int compare(CoeBinomialHistoryVo o1, CoeBinomialHistoryVo o2) { + if(isAscending) { + return numberStringComparator.compare(o1.getLevel(), o2.getLevel()); + }else{ + return numberStringComparator.compare(o2.getLevel(), o1.getLevel()); + } + } } } diff --git a/io.sc.engine.mv/src/main/java/io/sc/engine/mv/viewer/controller/CoeChiSquareHistoryWebController.java b/io.sc.engine.mv/src/main/java/io/sc/engine/mv/viewer/controller/CoeChiSquareHistoryWebController.java index 33ffd66d..b7bcceb6 100644 --- a/io.sc.engine.mv/src/main/java/io/sc/engine/mv/viewer/controller/CoeChiSquareHistoryWebController.java +++ b/io.sc.engine.mv/src/main/java/io/sc/engine/mv/viewer/controller/CoeChiSquareHistoryWebController.java @@ -9,6 +9,8 @@ import io.sc.engine.mv.viewer.vo.CoeChiSquareHistoryVo; import io.sc.platform.mvc.controller.support.RestCrudController; import io.sc.platform.orm.service.support.CriteriaBuilder; import io.sc.platform.orm.service.support.QueryParameter; +import io.sc.platform.orm.service.support.QueryResult; +import io.sc.platform.util.support.NumberStringComparator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.web.bind.annotation.GetMapping; @@ -18,6 +20,10 @@ import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; @RestController("io.sc.engine.mv.viewer.controller.CoeChiSquareHistoryWebController") @RequestMapping("/api/mv/viewer/chiSquare") @@ -42,6 +48,32 @@ public class CoeChiSquareHistoryWebController extends RestCrudController page =super.query(request,response,queryParameter); + String sortPropertyName =queryParameter.getFirstSort().getProperty(); + if("level".equals(sortPropertyName)){ + boolean isAscending =queryParameter.getFirstSort().isAscending(); + return QueryResult.sort(page,new CoeChiSquareHistoryVoComparator(isAscending)); + }else{ + return page; + } + } + + private class CoeChiSquareHistoryVoComparator implements Comparator { + private NumberStringComparator numberStringComparator =new NumberStringComparator(); + private boolean isAscending =true; + + public CoeChiSquareHistoryVoComparator(boolean isAscending){ + this.isAscending =isAscending; + } + + @Override + public int compare(CoeChiSquareHistoryVo o1, CoeChiSquareHistoryVo o2) { + if(isAscending) { + return numberStringComparator.compare(o1.getLevel(), o2.getLevel()); + }else{ + return numberStringComparator.compare(o2.getLevel(), o1.getLevel()); + } + } } } diff --git a/io.sc.engine.rule.frontend/package.json b/io.sc.engine.rule.frontend/package.json index 032edda4..459d13af 100644 --- a/io.sc.engine.rule.frontend/package.json +++ b/io.sc.engine.rule.frontend/package.json @@ -87,6 +87,7 @@ "@codemirror/view": "6.36.2", "@maxgraph/core": "0.14.0", "@quasar/extras": "1.16.15", + "@quasar/quasar-ui-qmarkdown": "2.0.5", "@univerjs/core": "0.5.4", "@univerjs/design": "0.5.4", "@univerjs/docs": "0.5.4", @@ -100,7 +101,7 @@ "@univerjs/thread-comment": "0.5.4", "@univerjs/ui": "0.5.4", "@vueuse/core": "12.4.0", - "axios": "1.7.9", + "axios": "1.8.2", "codemirror": "6.0.1", "dayjs": "1.11.13", "echarts": "5.6.0", @@ -111,7 +112,7 @@ "node-sql-parser": "5.3.6", "pinia": "2.3.0", "pinia-undo": "0.2.4", - "platform-core": "8.2.40", + "platform-core": "8.2.48", "quasar": "2.17.6", "sort-array": "5.0.0", "svg-path-commander": "2.1.7", diff --git a/io.sc.engine.rule.frontend/src/boostrap.ts b/io.sc.engine.rule.frontend/src/boostrap.ts index 31a30449..4193c068 100644 --- a/io.sc.engine.rule.frontend/src/boostrap.ts +++ b/io.sc.engine.rule.frontend/src/boostrap.ts @@ -15,6 +15,8 @@ import App from './App.vue'; import 'platform-core/dist/css/platform-core.css'; // 导入 tailwind utilities css import 'tailwindcss/utilities.css'; +// 导入 quasar-ui-qmarkdown css +import '@quasar/quasar-ui-qmarkdown/dist/index.css'; // 设置远程组件加载器 // 覆盖 platform-core 包中的 remoteComponentLoader 函数 diff --git a/io.sc.engine.rule.frontend/webpack.config.common.cjs b/io.sc.engine.rule.frontend/webpack.config.common.cjs index e8726c5b..b154bfff 100644 --- a/io.sc.engine.rule.frontend/webpack.config.common.cjs +++ b/io.sc.engine.rule.frontend/webpack.config.common.cjs @@ -22,7 +22,7 @@ module.exports = { // 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录 path: path.resolve(__dirname, `dist/public/${projectName}`), // 输出文件名 - filename: `javascript/[name].[contenthash:5].js`, + filename: `javascript/[name].[contenthash:6].js`, // 指定发布路径,使用 auto 可具有更多灵活性 publicPath: 'auto', // 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果 @@ -69,7 +69,7 @@ module.exports = { test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/, type: 'asset/resource', generator: { - filename: `fonts/[name].[contenthash:5].[ext]`, + filename: `fonts/[name].[contenthash:6].[ext]`, }, }, @@ -122,8 +122,8 @@ module.exports = { // css 抽取插件 new MiniCssExtractPlugin({ - filename: `css/[name].[contenthash:5].css`, - chunkFilename: `css/[name].[contenthash:5].css`, + filename: `css/[name].[contenthash:6].css`, + chunkFilename: `css/[name].[contenthash:6].css`, }), // 自动生成静态 index.html 文件 diff --git a/io.sc.engine.rule.frontend/webpack.config.mf.cjs b/io.sc.engine.rule.frontend/webpack.config.mf.cjs index 45ba1169..b61795a4 100644 --- a/io.sc.engine.rule.frontend/webpack.config.mf.cjs +++ b/io.sc.engine.rule.frontend/webpack.config.mf.cjs @@ -1,19 +1,19 @@ /** * webpack module federation 配置 */ -const fs = require('fs'); // 文件读取 -const Json5 =require('json5'); // json5 -const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 -const packageJson = require('./package.json'); // package.json -const projectName =packageJson.name; // 项目名称 -const deps = packageJson.dependencies; // 项目依赖 +const fs = require('fs'); // 文件读取 +const Json5 = require('json5'); // json5 +const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 +const packageJson = require('./package.json'); // package.json +const projectName = packageJson.name; // 项目名称 +const deps = packageJson.dependencies; // 项目依赖 // 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值 const data = fs.readFileSync('./src/routes/routes.json', 'utf8'); -const routes =Json5.parse(data); -const mfExposes ={}; -for(const route of routes){ - mfExposes[route.component]= route.componentPath; +const routes = Json5.parse(data); +const mfExposes = {}; +for (const route of routes) { + mfExposes[route.component] = route.componentPath; } // 导出 webapck 配置的模块联邦部分 @@ -57,24 +57,25 @@ module.exports = { '@univerjs/thread-comment': { requiredVersion: deps['@univerjs/thread-comment'], singleton: true }, '@univerjs/ui': { requiredVersion: deps['@univerjs/ui'], singleton: true }, '@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true }, - 'axios': { requiredVersion: deps['axios'], singleton: true }, - 'codemirror': { requiredVersion: deps['codemirror'], singleton: true }, - 'dayjs': { requiredVersion: deps['dayjs'], singleton: true }, - 'echarts':{ requiredVersion: deps['echarts'], singleton: true }, - 'exceljs':{ requiredVersion: deps['exceljs'], singleton: true }, - 'file-saver':{ requiredVersion: deps['file-saver'], singleton: true }, - 'luckyexcel':{ requiredVersion: deps['luckyexcel'], singleton: true }, - 'mockjs': { requiredVersion: deps['mockjs'], singleton: true }, - 'pinia': { requiredVersion: deps['pinia'], singleton: true }, + axios: { requiredVersion: deps['axios'], singleton: true }, + codemirror: { requiredVersion: deps['codemirror'], singleton: true }, + dayjs: { requiredVersion: deps['dayjs'], singleton: true }, + echarts: { requiredVersion: deps['echarts'], singleton: true }, + exceljs: { requiredVersion: deps['exceljs'], singleton: true }, + 'file-saver': { requiredVersion: deps['file-saver'], singleton: true }, + luckyexcel: { requiredVersion: deps['luckyexcel'], singleton: true }, + mockjs: { requiredVersion: deps['mockjs'], singleton: true }, + pinia: { requiredVersion: deps['pinia'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, - 'quasar': { requiredVersion: deps['quasar'], singleton: true }, + quasar: { requiredVersion: deps['quasar'], singleton: true }, + '@quasar/quasar-ui-qmarkdown': { requiredVersion: deps['@quasar/quasar-ui-qmarkdown'], singleton: true }, 'svg-path-commander': { requiredVersion: deps['svg-path-commander'], singleton: true }, - 'vue': { requiredVersion: deps['vue'], singleton: true }, - 'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, + vue: { requiredVersion: deps['vue'], singleton: true }, + 'vue-dompurify-html': { requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, - 'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true } - } + 'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true }, + }, }), - ] + ], }; diff --git a/io.sc.engine.rule.frontend/webpack.env.build.cjs b/io.sc.engine.rule.frontend/webpack.env.build.cjs index fbcf0fbe..446848cf 100644 --- a/io.sc.engine.rule.frontend/webpack.env.build.cjs +++ b/io.sc.engine.rule.frontend/webpack.env.build.cjs @@ -1,9 +1,9 @@ /** * 开发环境构建 */ -const { merge } = require('webpack-merge'); // webpack 配置合并函数 -const common = require('./webpack.config.common.cjs'); // webpack 通用配置 -const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置 +const { merge } = require('webpack-merge'); // webpack 配置合并函数 +const common = require('./webpack.config.common.cjs'); // webpack 通用配置 +const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置 module.exports = merge(common, mf, { mode: 'development', @@ -22,76 +22,76 @@ module.exports = merge(common, mf, { splitChunks: { cacheGroups: { - 'shared': { + shared: { name: 'vue', test: /[\\/]node_modules[\\/](axios|dayjs|exceljs|file-saver|luckyexcel|mockjs|xml-formatter)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'vue': { + vue: { name: 'vue', test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router|pinia|@vueuse[\\/]core)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'codemirror':{ + codemirror: { name: 'codemirror', test: /[\\/]node_modules[\\/](codemirror|@codemirror[\\/]autocomplete|@codemirror[\\/]commands|@codemirror[\\/]lang-html|@codemirror[\\/]lang-java|@codemirror[\\/]lang-javascript|@codemirror[\\/]lang-json|@codemirror[\\/]lang-sql|@codemirror[\\/]lang-xml|@codemirror[\\/]language|@codemirror[\\/]search|@codemirror[\\/]state|@codemirror[\\/]view)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'quasar': { + quasar: { name: 'quasar', - test: /[\\/]node_modules[\\/](quasar)[\\/]/, + test: /[\\/]node_modules[\\/](quasar|@quasar[\\/]quasar-ui-qmarkdown)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, 'platform-core': { name: 'platform-core', test: /[\\/]node_modules[\\/]platform-core[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'echarts': { + echarts: { name: 'echarts', test: /[\\/]node_modules[\\/]echarts[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'maxgraph': { + maxgraph: { name: 'maxgraph', test: /[\\/]node_modules[\\/]@maxgraph[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, '@univerjs': { name: '@univerjs', test: /[\\/]node_modules[\\/]@univerjs[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'view': { + view: { name: 'view', test: /[\\/]view[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'vendors': { + vendors: { name: 'vendors', test: /[\\/]node_modules[\\/]/, chunks: 'all', - enforce: true + enforce: true, }, - } - } + }, + }, }, }); diff --git a/io.sc.engine.st.frontend/package.json b/io.sc.engine.st.frontend/package.json index 6a2e5cd8..69349722 100644 --- a/io.sc.engine.st.frontend/package.json +++ b/io.sc.engine.st.frontend/package.json @@ -87,6 +87,7 @@ "@codemirror/view": "6.36.2", "@maxgraph/core": "0.14.0", "@quasar/extras": "1.16.15", + "@quasar/quasar-ui-qmarkdown": "2.0.5", "@univerjs/core": "0.5.4", "@univerjs/design": "0.5.4", "@univerjs/docs": "0.5.4", @@ -100,7 +101,7 @@ "@univerjs/thread-comment": "0.5.4", "@univerjs/ui": "0.5.4", "@vueuse/core": "12.4.0", - "axios": "1.7.9", + "axios": "1.8.2", "codemirror": "6.0.1", "dayjs": "1.11.13", "echarts": "5.6.0", @@ -111,7 +112,7 @@ "node-sql-parser": "5.3.6", "pinia": "2.3.0", "pinia-undo": "0.2.4", - "platform-core": "8.2.40", + "platform-core": "8.2.48", "quasar": "2.17.6", "sort-array": "5.0.0", "svg-path-commander": "2.1.7", diff --git a/io.sc.engine.st.frontend/src/boostrap.ts b/io.sc.engine.st.frontend/src/boostrap.ts index 31a30449..4193c068 100644 --- a/io.sc.engine.st.frontend/src/boostrap.ts +++ b/io.sc.engine.st.frontend/src/boostrap.ts @@ -15,6 +15,8 @@ import App from './App.vue'; import 'platform-core/dist/css/platform-core.css'; // 导入 tailwind utilities css import 'tailwindcss/utilities.css'; +// 导入 quasar-ui-qmarkdown css +import '@quasar/quasar-ui-qmarkdown/dist/index.css'; // 设置远程组件加载器 // 覆盖 platform-core 包中的 remoteComponentLoader 函数 diff --git a/io.sc.engine.st.frontend/src/views/DepFactor/DepFactor.vue b/io.sc.engine.st.frontend/src/views/DepFactor/DepFactor.vue index 7380bba3..2141d9ec 100644 --- a/io.sc.engine.st.frontend/src/views/DepFactor/DepFactor.vue +++ b/io.sc.engine.st.frontend/src/views/DepFactor/DepFactor.vue @@ -49,7 +49,7 @@ { width: 60, name: 'year', label: t('year'), align: 'right' }, { width: 60, name: 'quarter', label: t('quarter'), align: 'right' }, { width: 60, name: 'month', label: t('month'), align: 'right' }, - { width: 100, name: 'value', label: t('value') }, + { width: 100, name: 'value', label: t('value'), align: factorDefine.valueType === 'NUMERIC' ? 'right' : 'left' }, ]" :editor="{ dialog: { diff --git a/io.sc.engine.st.frontend/src/views/DepFactor/DepFactorDefine.vue b/io.sc.engine.st.frontend/src/views/DepFactor/DepFactorDefine.vue index 6a48e9aa..154e9fed 100644 --- a/io.sc.engine.st.frontend/src/views/DepFactor/DepFactorDefine.vue +++ b/io.sc.engine.st.frontend/src/views/DepFactor/DepFactorDefine.vue @@ -79,10 +79,10 @@ 'export', ]" :columns="[ - { width: 160, name: 'name', label: $t('name') }, + { width: '100%', name: 'name', label: $t('name') }, { width: 150, name: 'code', label: $t('code') }, { - width: 100, + width: 120, name: 'type', label: $t('type'), format: (value, row) => { @@ -93,7 +93,7 @@ }, }, { width: 60, name: 'period', label: $t('period'), format: Formater.enum(Enums.Period) }, - { width: 70, name: 'valueType', label: $t('valueType'), format: Formater.enum(Enums.ValueType) }, + { width: 80, name: 'valueType', label: $t('valueType'), format: Formater.enum(Enums.ValueType) }, ]" :editor="{ dialog: { diff --git a/io.sc.engine.st.frontend/src/views/IndepFactor/IndepFactor.vue b/io.sc.engine.st.frontend/src/views/IndepFactor/IndepFactor.vue index e8e18c0c..a78dc658 100644 --- a/io.sc.engine.st.frontend/src/views/IndepFactor/IndepFactor.vue +++ b/io.sc.engine.st.frontend/src/views/IndepFactor/IndepFactor.vue @@ -49,7 +49,7 @@ { width: 60, name: 'year', label: t('year'), align: 'right' }, { width: 60, name: 'quarter', label: t('quarter'), align: 'right' }, { width: 60, name: 'month', label: t('month'), align: 'right' }, - { width: 100, name: 'value', label: t('value') }, + { width: 100, name: 'value', label: t('value'), align: factorDefine.valueType === 'NUMERIC' ? 'right' : 'left' }, ]" :editor="{ dialog: { diff --git a/io.sc.engine.st.frontend/src/views/IndepFactor/IndepFactorDefine.vue b/io.sc.engine.st.frontend/src/views/IndepFactor/IndepFactorDefine.vue index b7c06b07..6925d5cc 100644 --- a/io.sc.engine.st.frontend/src/views/IndepFactor/IndepFactorDefine.vue +++ b/io.sc.engine.st.frontend/src/views/IndepFactor/IndepFactorDefine.vue @@ -79,10 +79,10 @@ 'export', ]" :columns="[ - { width: 160, name: 'name', label: $t('name') }, + { width: '100%', name: 'name', label: $t('name') }, { width: 150, name: 'code', label: $t('code') }, { - width: 100, + width: 120, name: 'type', label: $t('type'), format: (value, row) => { @@ -93,7 +93,7 @@ }, }, { width: 60, name: 'period', label: $t('period'), format: Formater.enum(Enums.Period) }, - { width: 70, name: 'valueType', label: $t('valueType'), format: Formater.enum(Enums.ValueType) }, + { width: 80, name: 'valueType', label: $t('valueType'), format: Formater.enum(Enums.ValueType) }, ]" :editor="{ dialog: { diff --git a/io.sc.engine.st.frontend/src/views/Model/ModelAnalysisFactor.vue b/io.sc.engine.st.frontend/src/views/Model/ModelAnalysisFactor.vue index 16295f86..1d9998bf 100644 --- a/io.sc.engine.st.frontend/src/views/Model/ModelAnalysisFactor.vue +++ b/io.sc.engine.st.frontend/src/views/Model/ModelAnalysisFactor.vue @@ -28,9 +28,9 @@ :toolbar-actions="['refresh']" :columns="[ { width: 120, name: 'variable', label: $t('engine.st.model.analysisFactor.grid.entity.variable') }, - { width: 100, name: 'coefficient', label: $t('engine.st.model.analysisFactor.grid.entity.coefficient') }, - { width: 120, name: 'coefficientSe', label: $t('engine.st.model.analysisFactor.grid.entity.coefficientSe') }, - { width: 120, name: 't', label: $t('engine.st.model.analysisFactor.grid.entity.t') }, + { width: 100, name: 'coefficient', label: $t('engine.st.model.analysisFactor.grid.entity.coefficient'), align: 'right' }, + { width: 120, name: 'coefficientSe', label: $t('engine.st.model.analysisFactor.grid.entity.coefficientSe'), align: 'right' }, + { width: 120, name: 't', label: $t('engine.st.model.analysisFactor.grid.entity.t'), align: 'right' }, ]" > diff --git a/io.sc.engine.st.frontend/src/views/Scenario/ScenarioFactor.vue b/io.sc.engine.st.frontend/src/views/Scenario/ScenarioFactor.vue index 5a046d99..d84567a3 100644 --- a/io.sc.engine.st.frontend/src/views/Scenario/ScenarioFactor.vue +++ b/io.sc.engine.st.frontend/src/views/Scenario/ScenarioFactor.vue @@ -86,9 +86,9 @@ { width: 60, name: 'year', label: t('year'), align: 'right' }, { width: 60, name: 'quarter', label: t('quarter'), align: 'right' }, { width: 60, name: 'month', label: t('month'), align: 'right' }, - { width: 80, name: 'valueLow', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueLow') }, - { width: 80, name: 'valueMid', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueMid') }, - { width: 80, name: 'valueHigh', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueHigh') }, + { width: 80, name: 'valueLow', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueLow'), align: 'right' }, + { width: 80, name: 'valueMid', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueMid'), align: 'right' }, + { width: 80, name: 'valueHigh', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueHigh'), align: 'right' }, ]" :editor="{ dialog: { diff --git a/io.sc.engine.st.frontend/src/views/Scenario/ScenarioFactorDefine.vue b/io.sc.engine.st.frontend/src/views/Scenario/ScenarioFactorDefine.vue index 0d435ccf..8b6d9028 100644 --- a/io.sc.engine.st.frontend/src/views/Scenario/ScenarioFactorDefine.vue +++ b/io.sc.engine.st.frontend/src/views/Scenario/ScenarioFactorDefine.vue @@ -42,10 +42,10 @@ 'export', ]" :columns="[ - { width: 160, name: 'name', label: $t('name') }, + { width: '100%', name: 'name', label: $t('name') }, { width: 150, name: 'code', label: $t('code') }, { - width: 100, + width: 120, name: 'type', label: $t('type'), format: (value, row) => { @@ -56,7 +56,7 @@ }, }, { width: 60, name: 'period', label: $t('period'), format: Formater.enum(Enums.Period) }, - { width: 70, name: 'valueType', label: $t('valueType'), format: Formater.enum(Enums.ValueType) }, + { width: 80, name: 'valueType', label: $t('valueType'), format: Formater.enum(Enums.ValueType) }, ]" :editor="{ dialog: { diff --git a/io.sc.engine.st.frontend/src/views/TestCase/TestResult.vue b/io.sc.engine.st.frontend/src/views/TestCase/TestResult.vue index 7aa8d910..68e4598a 100644 --- a/io.sc.engine.st.frontend/src/views/TestCase/TestResult.vue +++ b/io.sc.engine.st.frontend/src/views/TestCase/TestResult.vue @@ -15,9 +15,9 @@ { width: 60, name: 'year', label: t('year'), align: 'right' }, { width: 60, name: 'quarter', label: t('quarter'), align: 'right' }, { width: 60, name: 'month', label: t('month'), align: 'right' }, - { width: 100, name: 'valueLow', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueLow') }, - { width: 100, name: 'valueMid', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueMid') }, - { width: 100, name: 'valueHigh', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueHigh') }, + { width: 100, name: 'valueLow', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueLow'), align: 'right' }, + { width: 100, name: 'valueMid', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueMid'), align: 'right' }, + { width: 100, name: 'valueHigh', label: t('engine.st.scenario.scenarioFactor.grid.entity.valueHigh'), align: 'right' }, ]" :viewer="{ panel: { diff --git a/io.sc.engine.st.frontend/webpack.config.common.cjs b/io.sc.engine.st.frontend/webpack.config.common.cjs index e8726c5b..b154bfff 100644 --- a/io.sc.engine.st.frontend/webpack.config.common.cjs +++ b/io.sc.engine.st.frontend/webpack.config.common.cjs @@ -22,7 +22,7 @@ module.exports = { // 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录 path: path.resolve(__dirname, `dist/public/${projectName}`), // 输出文件名 - filename: `javascript/[name].[contenthash:5].js`, + filename: `javascript/[name].[contenthash:6].js`, // 指定发布路径,使用 auto 可具有更多灵活性 publicPath: 'auto', // 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果 @@ -69,7 +69,7 @@ module.exports = { test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/, type: 'asset/resource', generator: { - filename: `fonts/[name].[contenthash:5].[ext]`, + filename: `fonts/[name].[contenthash:6].[ext]`, }, }, @@ -122,8 +122,8 @@ module.exports = { // css 抽取插件 new MiniCssExtractPlugin({ - filename: `css/[name].[contenthash:5].css`, - chunkFilename: `css/[name].[contenthash:5].css`, + filename: `css/[name].[contenthash:6].css`, + chunkFilename: `css/[name].[contenthash:6].css`, }), // 自动生成静态 index.html 文件 diff --git a/io.sc.engine.st.frontend/webpack.config.mf.cjs b/io.sc.engine.st.frontend/webpack.config.mf.cjs index 45ba1169..b61795a4 100644 --- a/io.sc.engine.st.frontend/webpack.config.mf.cjs +++ b/io.sc.engine.st.frontend/webpack.config.mf.cjs @@ -1,19 +1,19 @@ /** * webpack module federation 配置 */ -const fs = require('fs'); // 文件读取 -const Json5 =require('json5'); // json5 -const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 -const packageJson = require('./package.json'); // package.json -const projectName =packageJson.name; // 项目名称 -const deps = packageJson.dependencies; // 项目依赖 +const fs = require('fs'); // 文件读取 +const Json5 = require('json5'); // json5 +const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 +const packageJson = require('./package.json'); // package.json +const projectName = packageJson.name; // 项目名称 +const deps = packageJson.dependencies; // 项目依赖 // 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值 const data = fs.readFileSync('./src/routes/routes.json', 'utf8'); -const routes =Json5.parse(data); -const mfExposes ={}; -for(const route of routes){ - mfExposes[route.component]= route.componentPath; +const routes = Json5.parse(data); +const mfExposes = {}; +for (const route of routes) { + mfExposes[route.component] = route.componentPath; } // 导出 webapck 配置的模块联邦部分 @@ -57,24 +57,25 @@ module.exports = { '@univerjs/thread-comment': { requiredVersion: deps['@univerjs/thread-comment'], singleton: true }, '@univerjs/ui': { requiredVersion: deps['@univerjs/ui'], singleton: true }, '@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true }, - 'axios': { requiredVersion: deps['axios'], singleton: true }, - 'codemirror': { requiredVersion: deps['codemirror'], singleton: true }, - 'dayjs': { requiredVersion: deps['dayjs'], singleton: true }, - 'echarts':{ requiredVersion: deps['echarts'], singleton: true }, - 'exceljs':{ requiredVersion: deps['exceljs'], singleton: true }, - 'file-saver':{ requiredVersion: deps['file-saver'], singleton: true }, - 'luckyexcel':{ requiredVersion: deps['luckyexcel'], singleton: true }, - 'mockjs': { requiredVersion: deps['mockjs'], singleton: true }, - 'pinia': { requiredVersion: deps['pinia'], singleton: true }, + axios: { requiredVersion: deps['axios'], singleton: true }, + codemirror: { requiredVersion: deps['codemirror'], singleton: true }, + dayjs: { requiredVersion: deps['dayjs'], singleton: true }, + echarts: { requiredVersion: deps['echarts'], singleton: true }, + exceljs: { requiredVersion: deps['exceljs'], singleton: true }, + 'file-saver': { requiredVersion: deps['file-saver'], singleton: true }, + luckyexcel: { requiredVersion: deps['luckyexcel'], singleton: true }, + mockjs: { requiredVersion: deps['mockjs'], singleton: true }, + pinia: { requiredVersion: deps['pinia'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, - 'quasar': { requiredVersion: deps['quasar'], singleton: true }, + quasar: { requiredVersion: deps['quasar'], singleton: true }, + '@quasar/quasar-ui-qmarkdown': { requiredVersion: deps['@quasar/quasar-ui-qmarkdown'], singleton: true }, 'svg-path-commander': { requiredVersion: deps['svg-path-commander'], singleton: true }, - 'vue': { requiredVersion: deps['vue'], singleton: true }, - 'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, + vue: { requiredVersion: deps['vue'], singleton: true }, + 'vue-dompurify-html': { requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, - 'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true } - } + 'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true }, + }, }), - ] + ], }; diff --git a/io.sc.engine.st.frontend/webpack.env.build.cjs b/io.sc.engine.st.frontend/webpack.env.build.cjs index fbcf0fbe..446848cf 100644 --- a/io.sc.engine.st.frontend/webpack.env.build.cjs +++ b/io.sc.engine.st.frontend/webpack.env.build.cjs @@ -1,9 +1,9 @@ /** * 开发环境构建 */ -const { merge } = require('webpack-merge'); // webpack 配置合并函数 -const common = require('./webpack.config.common.cjs'); // webpack 通用配置 -const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置 +const { merge } = require('webpack-merge'); // webpack 配置合并函数 +const common = require('./webpack.config.common.cjs'); // webpack 通用配置 +const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置 module.exports = merge(common, mf, { mode: 'development', @@ -22,76 +22,76 @@ module.exports = merge(common, mf, { splitChunks: { cacheGroups: { - 'shared': { + shared: { name: 'vue', test: /[\\/]node_modules[\\/](axios|dayjs|exceljs|file-saver|luckyexcel|mockjs|xml-formatter)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'vue': { + vue: { name: 'vue', test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router|pinia|@vueuse[\\/]core)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'codemirror':{ + codemirror: { name: 'codemirror', test: /[\\/]node_modules[\\/](codemirror|@codemirror[\\/]autocomplete|@codemirror[\\/]commands|@codemirror[\\/]lang-html|@codemirror[\\/]lang-java|@codemirror[\\/]lang-javascript|@codemirror[\\/]lang-json|@codemirror[\\/]lang-sql|@codemirror[\\/]lang-xml|@codemirror[\\/]language|@codemirror[\\/]search|@codemirror[\\/]state|@codemirror[\\/]view)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'quasar': { + quasar: { name: 'quasar', - test: /[\\/]node_modules[\\/](quasar)[\\/]/, + test: /[\\/]node_modules[\\/](quasar|@quasar[\\/]quasar-ui-qmarkdown)[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, 'platform-core': { name: 'platform-core', test: /[\\/]node_modules[\\/]platform-core[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'echarts': { + echarts: { name: 'echarts', test: /[\\/]node_modules[\\/]echarts[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'maxgraph': { + maxgraph: { name: 'maxgraph', test: /[\\/]node_modules[\\/]@maxgraph[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, '@univerjs': { name: '@univerjs', test: /[\\/]node_modules[\\/]@univerjs[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'view': { + view: { name: 'view', test: /[\\/]view[\\/]/, priority: 20, chunks: 'all', - enforce: true + enforce: true, }, - 'vendors': { + vendors: { name: 'vendors', test: /[\\/]node_modules[\\/]/, chunks: 'all', - enforce: true + enforce: true, }, - } - } + }, + }, }, }); diff --git a/io.sc.platform.ai/build.gradle b/io.sc.platform.ai/build.gradle new file mode 100644 index 00000000..a5494d0c --- /dev/null +++ b/io.sc.platform.ai/build.gradle @@ -0,0 +1,8 @@ +dependencies { + api( + project(":io.sc.platform.system"), + project(":io.sc.platform.ai.frontend"), + //"io.github.lnyo-cly:ai4j-spring-boot-starter:${ai4j_version}", + "com.squareup.okhttp3:okhttp:${okhttp_version}" + ) +} \ No newline at end of file diff --git a/io.sc.platform.ai/gradle.properties b/io.sc.platform.ai/gradle.properties new file mode 100644 index 00000000..e69de29b diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/AnythingllmService.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/AnythingllmService.java new file mode 100644 index 00000000..5a4cd87e --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/AnythingllmService.java @@ -0,0 +1,4 @@ +package io.sc.platform.ai.anythingllm.service; + +public interface AnythingllmService { +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/impl/AnythingllmServiceImpl.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/impl/AnythingllmServiceImpl.java new file mode 100644 index 00000000..6c3bec81 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/impl/AnythingllmServiceImpl.java @@ -0,0 +1,6 @@ +package io.sc.platform.ai.anythingllm.service.impl; + +import io.sc.platform.ai.anythingllm.service.AnythingllmService; + +public class AnythingllmServiceImpl implements AnythingllmService { +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/support/workspaces/StreamChatApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/support/workspaces/StreamChatApi.java new file mode 100644 index 00000000..de60523c --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/support/workspaces/StreamChatApi.java @@ -0,0 +1,86 @@ +package io.sc.platform.ai.anythingllm.service.support.workspaces; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.sc.platform.ai.ollama.MessageWrapper; +import io.sc.platform.ai.ollama.OllamaApi; +import io.sc.platform.ai.ollama.service.support.chat.ChatRequest; +import io.sc.platform.ai.ollama.service.support.chat.Message; +import io.sc.platform.util.CollectionUtil; +import io.sc.platform.util.ObjectMapperUtil; +import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter; + +import java.util.List; + +public class StreamChatApi extends OllamaApi { + private static final Logger log = LoggerFactory.getLogger(StreamChatApi.class); + + public StreamChatApi(String baseUrl){ + super("/api/chat","POST"); + this.baseUrl =baseUrl; + } + + public ResponseBodyEmitter execute(MessageWrapper chatRequest) { + ChatRequest chatCompletion =createChatCompletion(chatRequest); + if(chatCompletion==null) { return null; } + Call call =createRequestCall(chatCompletion); + if(call==null) { return null; } + + ResponseBodyEmitter emitter =new ResponseBodyEmitter(); + call.enqueue(new StreamChatCallback(emitter)); + return emitter; + } + + private ChatRequest createChatCompletion(MessageWrapper chatRequest) { + if(chatRequest==null) { return null; } + + String model =chatRequest.getModel(); + if(!StringUtils.hasText(model)) { return null; } + + List questions =chatRequest.getQuestions(); + if(!CollectionUtil.hasElements(questions)){ return null; } + + ChatRequest chatCompletion =new ChatRequest(); + chatCompletion.setModel(model); + + chatCompletion.addMessage(new Message("user", "使用中文回答")); + for(String question : questions){ + chatCompletion.addMessage(new Message("user",question)); + } + return chatCompletion; + } + + private Call createRequestCall(ChatRequest chatCompletion) { + if(chatCompletion==null) { return null; } + + OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(this.connectTimeout) + .readTimeout(this.readTimeout) + .writeTimeout(this.writeTimeout) + .build(); + + Headers headers = new Headers.Builder() + .set("Content-Type", "application/json") + .set("Accept", "text/event-stream") + .build(); + String json =""; + try { + json = ObjectMapperUtil.json().writeValueAsString(chatCompletion); + } catch (JsonProcessingException e){ + log.error("",e); + return null; + } + RequestBody body = RequestBody.create(json, MediaType.parse("application/json; charset=utf-8")); + okhttp3.Request request = new okhttp3.Request.Builder() + .url(this.baseUrl + this.url) + .headers(headers) + .post(body) + .build(); + + Call call = client.newCall(request); + return call; + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/support/workspaces/StreamChatCallback.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/support/workspaces/StreamChatCallback.java new file mode 100644 index 00000000..0d07453f --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/anythingllm/service/support/workspaces/StreamChatCallback.java @@ -0,0 +1,45 @@ +package io.sc.platform.ai.anythingllm.service.support.workspaces; + +import io.sc.platform.ai.ollama.service.support.chat.ChatResponse; +import io.sc.platform.util.ObjectMapperUtil; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.BufferedSource; +import org.jetbrains.annotations.NotNull; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter; + +import java.io.IOException; + +public class StreamChatCallback implements Callback { + private ResponseBodyEmitter emitter; + + public StreamChatCallback(ResponseBodyEmitter emitter){ + this.emitter =emitter; + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + emitter.completeWithError(e); + } + + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + if(response.isSuccessful()) { + try (ResponseBody body = response.body()) { + BufferedSource bufferedSource = body.source(); + while (!bufferedSource.exhausted()) { + String line = bufferedSource.readUtf8Line(); + ChatResponse responseObject =ObjectMapperUtil.json().readValue(line, ChatResponse.class); + emitter.send(responseObject.getMessage().getContent()); + } + emitter.complete(); + } catch (Exception e) { + emitter.completeWithError(e); + } + } else { + emitter.completeWithError(new RuntimeException(response.message())); + } + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/MessageWrapper.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/MessageWrapper.java new file mode 100644 index 00000000..4ec117bc --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/MessageWrapper.java @@ -0,0 +1,25 @@ +package io.sc.platform.ai.ollama; + +import java.util.ArrayList; +import java.util.List; + +public class MessageWrapper { + private String model; + private List questions =new ArrayList<>(); + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public List getQuestions() { + return questions; + } + + public void setQuestions(List questions) { + this.questions = questions; + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/OllamaApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/OllamaApi.java new file mode 100644 index 00000000..1fa6ca53 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/OllamaApi.java @@ -0,0 +1,66 @@ +package io.sc.platform.ai.ollama; + +import java.time.Duration; + +public class OllamaApi { + protected String baseUrl ="http://localhost:11434"; + protected String url; + protected String method; + protected Duration connectTimeout =Duration.ofMinutes(2); + protected Duration readTimeout =Duration.ofMinutes(2); + protected Duration writeTimeout =Duration.ofMinutes(2); + + public OllamaApi(){} + public OllamaApi(String url,String method){ + this.url =url; + this.method =method; + } + + public String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public Duration getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(Duration connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public Duration getReadTimeout() { + return readTimeout; + } + + public void setReadTimeout(Duration readTimeout) { + this.readTimeout = readTimeout; + } + + public Duration getWriteTimeout() { + return writeTimeout; + } + + public void setWriteTimeout(Duration writeTimeout) { + this.writeTimeout = writeTimeout; + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/controller/OllamaWebController.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/controller/OllamaWebController.java new file mode 100644 index 00000000..37d22ceb --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/controller/OllamaWebController.java @@ -0,0 +1,31 @@ +package io.sc.platform.ai.ollama.controller; + +import io.sc.platform.ai.ollama.MessageWrapper; +import io.sc.platform.ai.ollama.service.OllamaService; +import io.sc.platform.ai.ollama.service.support.tags.TagsResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter; + +import java.util.List; + +@RestController("io.sc.platform.ai.ollama.controller.OllamaWebController") +@RequestMapping("/api/ai/ollama") +public class OllamaWebController { + @Autowired private OllamaService ollamaService; + + @PostMapping("/chat") + public ResponseBodyEmitter chat(@RequestBody MessageWrapper wrapper){ + return ollamaService.chat(wrapper); + } + + @GetMapping("/tags") + public TagsResponse tags(){ + return ollamaService.tags(); + } + + @GetMapping("/modelNames") + public List modelNames(){ + return ollamaService.modelNames(); + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/OllamaService.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/OllamaService.java new file mode 100644 index 00000000..31661581 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/OllamaService.java @@ -0,0 +1,13 @@ +package io.sc.platform.ai.ollama.service; + +import io.sc.platform.ai.ollama.MessageWrapper; +import io.sc.platform.ai.ollama.service.support.tags.TagsResponse; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter; + +import java.util.List; + +public interface OllamaService { + public ResponseBodyEmitter chat(MessageWrapper wrapper); + public TagsResponse tags(); + public List modelNames(); +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/impl/OllamaServiceImpl.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/impl/OllamaServiceImpl.java new file mode 100644 index 00000000..abcac5b5 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/impl/OllamaServiceImpl.java @@ -0,0 +1,69 @@ +package io.sc.platform.ai.ollama.service.impl; + +import io.sc.platform.ai.ollama.MessageWrapper; +import io.sc.platform.ai.ollama.service.OllamaService; +import io.sc.platform.ai.ollama.service.support.chat.ChatApi; +import io.sc.platform.ai.ollama.service.support.tags.Model; +import io.sc.platform.ai.ollama.service.support.tags.TagsApi; +import io.sc.platform.ai.ollama.service.support.tags.TagsResponse; +import io.sc.platform.mvc.service.SystemParameterService; +import io.sc.platform.util.CollectionUtil; +import io.sc.platform.util.StringUtil; +import io.sc.platform.util.support.NumberStringComparator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@Service("io.sc.platform.ai.service.impl.OllamaServiceImpl") +public class OllamaServiceImpl implements OllamaService { + private static final String KEY_API_URL ="parameter.ai.provider.ollama.apiUrl"; + private static final String KEY_DEFAULT_MODEL_NAME ="parameter.ai.provider.ollama.defaultModelName"; + + @Autowired private SystemParameterService systemParameterService; + + @Override + public ResponseBodyEmitter chat(MessageWrapper wrapper) { + Map parameters =getParameters(); + if(!StringUtil.hasText(wrapper.getModel())){ + wrapper.setModel(parameters.get(KEY_DEFAULT_MODEL_NAME)); + } + ChatApi api =new ChatApi(parameters.get(KEY_API_URL)); + return api.execute(wrapper); + } + + @Override + public TagsResponse tags() { + Map parameters =getParameters(); + TagsApi api =new TagsApi(parameters.get(KEY_API_URL)); + return api.execute(); + } + + @Override + public List modelNames() { + Map parameters =getParameters(); + TagsApi api =new TagsApi(parameters.get(KEY_API_URL)); + TagsResponse response =api.execute(); + if(response==null){ + return Collections.emptyList(); + } + List models =response.getModels(); + if(!CollectionUtil.hasElements(models)){ + return Collections.emptyList(); + } + List result =new ArrayList<>(); + for(Model model : models){ + result.add(model.getModel()); + } + Collections.sort(result, new NumberStringComparator()); + return result; + } + + private Map getParameters(){ + return systemParameterService.getParameters(new String[]{KEY_API_URL,KEY_DEFAULT_MODEL_NAME}); + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/blobs/BlobsApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/blobs/BlobsApi.java new file mode 100644 index 00000000..4f32b3f5 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/blobs/BlobsApi.java @@ -0,0 +1,11 @@ +package io.sc.platform.ai.ollama.service.support.blobs; + +import io.sc.platform.ai.ollama.OllamaApi; + +public class BlobsApi extends OllamaApi { + public BlobsApi(){ + super("/api/blobs/","HEAD"); + } + + +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatApi.java new file mode 100644 index 00000000..ff6c7fbc --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatApi.java @@ -0,0 +1,84 @@ +package io.sc.platform.ai.ollama.service.support.chat; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.sc.platform.ai.ollama.MessageWrapper; +import io.sc.platform.ai.ollama.OllamaApi; +import io.sc.platform.util.CollectionUtil; +import io.sc.platform.util.ObjectMapperUtil; +import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter; + +import java.util.List; + +public class ChatApi extends OllamaApi { + private static final Logger log = LoggerFactory.getLogger(ChatApi.class); + + public ChatApi(String baseUrl){ + super("/api/chat","POST"); + this.baseUrl =baseUrl; + } + + public ResponseBodyEmitter execute(MessageWrapper wrapper) { + ChatRequest chatRequest =createChatRequest(wrapper); + if(chatRequest==null) { return null; } + Call call =createRequestCall(chatRequest); + if(call==null) { return null; } + + ResponseBodyEmitter emitter =new ResponseBodyEmitter(); + call.enqueue(new ChatCallback(emitter)); + return emitter; + } + + private ChatRequest createChatRequest(MessageWrapper wrapper) { + if(wrapper==null) { return null; } + + String model =wrapper.getModel(); + if(!StringUtils.hasText(model)) { return null; } + + List questions =wrapper.getQuestions(); + if(!CollectionUtil.hasElements(questions)){ return null; } + + ChatRequest request =new ChatRequest(); + request.setModel(model); + + request.addMessage(new Message("user", "使用中文回答")); + for(String question : questions){ + request.addMessage(new Message("user",question)); + } + return request; + } + + private Call createRequestCall(ChatRequest chatRequest) { + if(chatRequest==null) { return null; } + + OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(this.connectTimeout) + .readTimeout(this.readTimeout) + .writeTimeout(this.writeTimeout) + .build(); + + Headers headers = new Headers.Builder() + .set("Content-Type", "application/json") + .set("Accept", "text/event-stream") + .build(); + String json =""; + try { + json = ObjectMapperUtil.json().writeValueAsString(chatRequest); + } catch (JsonProcessingException e){ + log.error("",e); + return null; + } + RequestBody body = RequestBody.create(json, MediaType.parse("application/json; charset=utf-8")); + okhttp3.Request request = new okhttp3.Request.Builder() + .url(this.baseUrl + this.url) + .headers(headers) + .post(body) + .build(); + + Call call = client.newCall(request); + return call; + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatCallback.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatCallback.java new file mode 100644 index 00000000..407029da --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatCallback.java @@ -0,0 +1,44 @@ +package io.sc.platform.ai.ollama.service.support.chat; + +import io.sc.platform.util.ObjectMapperUtil; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.BufferedSource; +import org.jetbrains.annotations.NotNull; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter; + +import java.io.IOException; + +public class ChatCallback implements Callback { + private ResponseBodyEmitter emitter; + + public ChatCallback(ResponseBodyEmitter emitter){ + this.emitter =emitter; + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + emitter.completeWithError(e); + } + + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + if(response.isSuccessful()) { + try (ResponseBody body = response.body()) { + BufferedSource bufferedSource = body.source(); + while (!bufferedSource.exhausted()) { + String line = bufferedSource.readUtf8Line(); + ChatResponse chatResponse =ObjectMapperUtil.json().readValue(line, ChatResponse.class); + emitter.send(chatResponse.getMessage().getContent()); + } + emitter.complete(); + } catch (Exception e) { + emitter.completeWithError(e); + } + } else { + emitter.completeWithError(new RuntimeException(response.message())); + } + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatRequest.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatRequest.java new file mode 100644 index 00000000..cc66b358 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatRequest.java @@ -0,0 +1,80 @@ +package io.sc.platform.ai.ollama.service.support.chat; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@JsonIgnoreProperties(ignoreUnknown=true) +public class ChatRequest { + private String model; + private List messages =new ArrayList<>(); + private List tools =new ArrayList<>(); + + private String format; + private Map options =new HashMap<>(); + private boolean stream =true; + private long keepAlive =1000*60*5; + + public void addMessage(Message message){ + messages.add(message); + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public List getMessages() { + return messages; + } + + public void setMessages(List messages) { + this.messages = messages; + } + + public List getTools() { + return tools; + } + + public void setTools(List tools) { + this.tools = tools; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public Map getOptions() { + return options; + } + + public void setOptions(Map options) { + this.options = options; + } + + public boolean getStream() { + return stream; + } + + public void setStream(boolean stream) { + this.stream = stream; + } + + public long getKeepAlive() { + return keepAlive; + } + + public void setKeepAlive(long keepAlive) { + this.keepAlive = keepAlive; + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatResponse.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatResponse.java new file mode 100644 index 00000000..a0040e35 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/ChatResponse.java @@ -0,0 +1,117 @@ +package io.sc.platform.ai.ollama.service.support.chat; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown=true) +public class ChatResponse { + @JsonProperty("model") + private String model; + + @JsonProperty("created_at") + private String createdAt; + + @JsonProperty("message") + private Message message; + + @JsonProperty("done") + private boolean done; + + @JsonProperty("total_duration") + private long totalDuration; + + @JsonProperty("load_duration") + private long loadDuration; + + @JsonProperty("prompt_eval_count") + private long promptEvalCount; + + @JsonProperty("prompt_eval_duration") + private long promptEvalDuration; + + @JsonProperty("eval_count") + private long evalCount; + + @JsonProperty("eval_duration") + private long evalDuration; + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + public Message getMessage() { + return message; + } + + public void setMessage(Message message) { + this.message = message; + } + + public boolean isDone() { + return done; + } + + public void setDone(boolean done) { + this.done = done; + } + + public long getTotalDuration() { + return totalDuration; + } + + public void setTotalDuration(long totalDuration) { + this.totalDuration = totalDuration; + } + + public long getLoadDuration() { + return loadDuration; + } + + public void setLoadDuration(long loadDuration) { + this.loadDuration = loadDuration; + } + + public long getPromptEvalCount() { + return promptEvalCount; + } + + public void setPromptEvalCount(long promptEvalCount) { + this.promptEvalCount = promptEvalCount; + } + + public long getPromptEvalDuration() { + return promptEvalDuration; + } + + public void setPromptEvalDuration(long promptEvalDuration) { + this.promptEvalDuration = promptEvalDuration; + } + + public long getEvalCount() { + return evalCount; + } + + public void setEvalCount(long evalCount) { + this.evalCount = evalCount; + } + + public long getEvalDuration() { + return evalDuration; + } + + public void setEvalDuration(long evalDuration) { + this.evalDuration = evalDuration; + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/Message.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/Message.java new file mode 100644 index 00000000..097d5ded --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/Message.java @@ -0,0 +1,54 @@ +package io.sc.platform.ai.ollama.service.support.chat; + +import java.util.ArrayList; +import java.util.List; + +public class Message { + public static final String SYSTEM ="system"; + public static final String USER ="user"; + public static final String ASSISTANT ="assistant"; + public static final String TOOL ="tool"; + + private String role; + private String content; + private List images =new ArrayList<>(); + private List toolCalls =new ArrayList<>(); + + public Message(){} + public Message(String role,String content){ + this.role =role; + this.content =content; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public List getImages() { + return images; + } + + public void setImages(List images) { + this.images = images; + } + + public List getToolCalls() { + return toolCalls; + } + + public void setToolCalls(List toolCalls) { + this.toolCalls = toolCalls; + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/Tool.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/Tool.java new file mode 100644 index 00000000..6a869bdb --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/chat/Tool.java @@ -0,0 +1,4 @@ +package io.sc.platform.ai.ollama.service.support.chat; + +public class Tool { +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/copy/OllamaCopyApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/copy/OllamaCopyApi.java new file mode 100644 index 00000000..dd829b77 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/copy/OllamaCopyApi.java @@ -0,0 +1,11 @@ +package io.sc.platform.ai.ollama.service.support.copy; + +import io.sc.platform.ai.ollama.OllamaApi; + +public class OllamaCopyApi extends OllamaApi { + public OllamaCopyApi(){ + super("/api/copy","POST"); + } + + +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/create/OllamaCreateApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/create/OllamaCreateApi.java new file mode 100644 index 00000000..4219aae7 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/create/OllamaCreateApi.java @@ -0,0 +1,11 @@ +package io.sc.platform.ai.ollama.service.support.create; + +import io.sc.platform.ai.ollama.OllamaApi; + +public class OllamaCreateApi extends OllamaApi { + public OllamaCreateApi(){ + super("/api/create","POST"); + } + + +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/delete/OllamaDeleteApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/delete/OllamaDeleteApi.java new file mode 100644 index 00000000..a1a3ad17 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/delete/OllamaDeleteApi.java @@ -0,0 +1,11 @@ +package io.sc.platform.ai.ollama.service.support.delete; + +import io.sc.platform.ai.ollama.OllamaApi; + +public class OllamaDeleteApi extends OllamaApi { + public OllamaDeleteApi(){ + super("/api/delete","DELETE"); + } + + +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/embed/OllamaEmbedApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/embed/OllamaEmbedApi.java new file mode 100644 index 00000000..440255fc --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/embed/OllamaEmbedApi.java @@ -0,0 +1,11 @@ +package io.sc.platform.ai.ollama.service.support.embed; + +import io.sc.platform.ai.ollama.OllamaApi; + +public class OllamaEmbedApi extends OllamaApi { + public OllamaEmbedApi(){ + super("/api/embed","POST"); + } + + +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/embeddings/OllamaEmbeddingsApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/embeddings/OllamaEmbeddingsApi.java new file mode 100644 index 00000000..0d2d2cb6 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/embeddings/OllamaEmbeddingsApi.java @@ -0,0 +1,11 @@ +package io.sc.platform.ai.ollama.service.support.embeddings; + +import io.sc.platform.ai.ollama.OllamaApi; + +public class OllamaEmbeddingsApi extends OllamaApi { + public OllamaEmbeddingsApi(){ + super("/api/embeddings","POST"); + } + + +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/generate/OllamaGenerateApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/generate/OllamaGenerateApi.java new file mode 100644 index 00000000..a8bba44d --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/generate/OllamaGenerateApi.java @@ -0,0 +1,11 @@ +package io.sc.platform.ai.ollama.service.support.generate; + +import io.sc.platform.ai.ollama.OllamaApi; + +public class OllamaGenerateApi extends OllamaApi { + public OllamaGenerateApi(){ + super("/api/generate","POST"); + } + + +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/ps/OllamaPsApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/ps/OllamaPsApi.java new file mode 100644 index 00000000..b2f7fd2c --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/ps/OllamaPsApi.java @@ -0,0 +1,11 @@ +package io.sc.platform.ai.ollama.service.support.ps; + +import io.sc.platform.ai.ollama.OllamaApi; + +public class OllamaPsApi extends OllamaApi { + public OllamaPsApi(){ + super("/api/ps","GET"); + } + + +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/pull/OllamaPullApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/pull/OllamaPullApi.java new file mode 100644 index 00000000..88afbc86 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/pull/OllamaPullApi.java @@ -0,0 +1,11 @@ +package io.sc.platform.ai.ollama.service.support.pull; + +import io.sc.platform.ai.ollama.OllamaApi; + +public class OllamaPullApi extends OllamaApi { + public OllamaPullApi(){ + super("/api/pull","POST"); + } + + +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/push/OllamaPushApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/push/OllamaPushApi.java new file mode 100644 index 00000000..05b0398f --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/push/OllamaPushApi.java @@ -0,0 +1,11 @@ +package io.sc.platform.ai.ollama.service.support.push; + +import io.sc.platform.ai.ollama.OllamaApi; + +public class OllamaPushApi extends OllamaApi { + public OllamaPushApi(){ + super("/api/push","POST"); + } + + +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/show/OllamaShowApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/show/OllamaShowApi.java new file mode 100644 index 00000000..738c7d92 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/show/OllamaShowApi.java @@ -0,0 +1,11 @@ +package io.sc.platform.ai.ollama.service.support.show; + +import io.sc.platform.ai.ollama.OllamaApi; + +public class OllamaShowApi extends OllamaApi { + public OllamaShowApi(){ + super("/api/show","POST"); + } + + +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/Details.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/Details.java new file mode 100644 index 00000000..e7f3b9f0 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/Details.java @@ -0,0 +1,71 @@ +package io.sc.platform.ai.ollama.service.support.tags; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown=true) +public class Details { + @JsonProperty("parent_model") + private String parentModel; + + private String format; + private String family; + private List families; + + @JsonProperty("parameter_size") + private String parameterSize; + + @JsonProperty("quantization_level") + private String quantizationLevel; + + public String getParentModel() { + return parentModel; + } + + public void setParentModel(String parentModel) { + this.parentModel = parentModel; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public String getFamily() { + return family; + } + + public void setFamily(String family) { + this.family = family; + } + + public List getFamilies() { + return families; + } + + public void setFamilies(List families) { + this.families = families; + } + + public String getParameterSize() { + return parameterSize; + } + + public void setParameterSize(String parameterSize) { + this.parameterSize = parameterSize; + } + + public String getQuantizationLevel() { + return quantizationLevel; + } + + public void setQuantizationLevel(String quantizationLevel) { + this.quantizationLevel = quantizationLevel; + } +} + diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/Model.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/Model.java new file mode 100644 index 00000000..c4efcf96 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/Model.java @@ -0,0 +1,65 @@ +package io.sc.platform.ai.ollama.service.support.tags; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown=true) +public class Model { + private String name; + private String model; + + @JsonProperty("modified_at") + private String modifiedAt; + + private long size; + private String digest; + private Details details; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getModifiedAt() { + return modifiedAt; + } + + public void setModifiedAt(String modifiedAt) { + this.modifiedAt = modifiedAt; + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public String getDigest() { + return digest; + } + + public void setDigest(String digest) { + this.digest = digest; + } + + public Details getDetails() { + return details; + } + + public void setDetails(Details details) { + this.details = details; + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/TagsApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/TagsApi.java new file mode 100644 index 00000000..e2e5ac66 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/TagsApi.java @@ -0,0 +1,42 @@ +package io.sc.platform.ai.ollama.service.support.tags; + +import io.sc.platform.ai.ollama.OllamaApi; +import io.sc.platform.util.ObjectMapperUtil; +import okhttp3.*; + +import java.io.IOException; + +public class TagsApi extends OllamaApi { + public TagsApi(String baseUrl){ + super("/api/tags","GET"); + this.baseUrl =baseUrl; + } + + public TagsResponse execute() { + Call call =createRequestCall(); + if(call==null) { return null; } + try { + Response response = call.execute(); + ResponseBody body =response.body(); + TagsResponse tagsResponse = ObjectMapperUtil.json().readValue(body.source().readUtf8(), TagsResponse.class); + return tagsResponse; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private Call createRequestCall() { + OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(this.connectTimeout) + .readTimeout(this.readTimeout) + .writeTimeout(this.writeTimeout) + .build(); + Request request = new Request.Builder() + .url(this.baseUrl + this.url) + .get() + .build(); + + Call call = client.newCall(request); + return call; + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/TagsResponse.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/TagsResponse.java new file mode 100644 index 00000000..9d335f8b --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/tags/TagsResponse.java @@ -0,0 +1,19 @@ +package io.sc.platform.ai.ollama.service.support.tags; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.ArrayList; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown=true) +public class TagsResponse { + private List models =new ArrayList<>(); + + public List getModels() { + return models; + } + + public void setModels(List models) { + this.models = models; + } +} diff --git a/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/version/OllamaVersionApi.java b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/version/OllamaVersionApi.java new file mode 100644 index 00000000..7a453f91 --- /dev/null +++ b/io.sc.platform.ai/src/main/java/io/sc/platform/ai/ollama/service/support/version/OllamaVersionApi.java @@ -0,0 +1,11 @@ +package io.sc.platform.ai.ollama.service.support.version; + +import io.sc.platform.ai.ollama.OllamaApi; + +public class OllamaVersionApi extends OllamaApi { + public OllamaVersionApi(){ + super("/api/version","GET"); + } + + +} diff --git a/io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/components.json b/io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/components.json new file mode 100644 index 00000000..fbfe8232 --- /dev/null +++ b/io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/components.json @@ -0,0 +1,16 @@ +/* + * 自动组件扫描插件配置 + * 功能: 该插件配置为框架提供自动扫描组件的包名,配置的包名将会自动被 spring 进行扫描 + * 使用说明: + * includes: 包含自动扫描的包名列表 + * excludes: 排除自动扫描的包名列表 + * 注意: 当一个包名同时存在于 includes 和 excludes 中, excludes 优先, 即该包不会被自动扫描 + */ + +{ + "includes":[ + "io.sc.platform.ai.ollama.controller", + "io.sc.platform.ai.ollama.service.impl" + ], + "excludes":[] +} diff --git a/io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/messages.json b/io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/messages.json new file mode 100644 index 00000000..34cfbae5 --- /dev/null +++ b/io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/messages.json @@ -0,0 +1,5 @@ +{ + "includes":[ + "io/sc/platform/ai/i18n/parameters" + ] +} \ No newline at end of file diff --git a/io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/parameters.json b/io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/parameters.json new file mode 100644 index 00000000..a0f17490 --- /dev/null +++ b/io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/parameters.json @@ -0,0 +1,67 @@ +/* + * 系统参数贡献项配置示例 + * 功能说明: 为系统提供参数配置 + * 使用说明: + * id: 参数唯一标识 + * parentId: 父唯一标识,用于进行参数分类 + * code: 参数代码,应用可通过该代码获取参数值 + * defaultValue: 默认值 + * order: 排序 + */ + +[ + //AI 服务器 + {"id":"parameter.ai","order":2000}, + //AI 服务器/是否开启智能对话 + { + "id" :"parameter.ai.chat.enable", + "parentId" :"parameter.ai", + "code" :"parameter.ai.chat.enable", + "defaultValue" :"true", + "order" : 100, + "options" : { + "true" : "parameter.ai.chat.enable.options.enable", + "false" : "parameter.ai.chat.enable.options.disable" + } + }, + //AI 服务器/默认服务提供者 + { + "id" :"parameter.ai.provider.default", + "parentId" :"parameter.ai", + "code" :"parameter.ai.provider.default", + "defaultValue" :"ollama", + "order" : 200, + "options" : { + "ollama" : "parameter.ai.provider.default.options.ollama" + } + }, + //AI 服务器/服务提供者 + {"id":"parameter.ai.provider", "parentId":"parameter.ai", "order":300}, + //AI 服务器/服务提供者/Ollama + {"id":"parameter.ai.provider.ollama", "parentId":"parameter.ai.provider", "order":100}, + //AI 服务器/服务提供者/Ollama/api url + { + "id" :"parameter.ai.provider.ollama.apiUrl", + "parentId" :"parameter.ai.provider.ollama", + "code" :"parameter.ai.provider.ollama.apiUrl", + "defaultValue" :"http://localhost:11434", + "order" : 100 + }, + //AI 服务器/服务提供者/Ollama/默认模型名称 + { + "id" :"parameter.ai.provider.ollama.defaultModelName", + "parentId" :"parameter.ai.provider.ollama", + "code" :"parameter.ai.provider.ollama.defaultModelName", + "defaultValue" :"deepseek-r1:14b", + "order" : 200, + "options" : { + "deepseek-r1:1.5b" : "deepseek-r1:1.5b", + "deepseek-r1:7b" : "deepseek-r1:7b", + "deepseek-r1:8b" : "deepseek-r1:8b", + "deepseek-r1:14b" : "deepseek-r1:14b", + "deepseek-r1:32b" : "deepseek-r1:32b", + "deepseek-r1:70b" : "deepseek-r1:70b", + "deepseek-r1:671b" : "deepseek-r1:671b" + } + } +] diff --git a/io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/security.json b/io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/security.json new file mode 100644 index 00000000..78c65b2a --- /dev/null +++ b/io.sc.platform.ai/src/main/resources/META-INF/platform/plugins/security.json @@ -0,0 +1,4 @@ +{ + "permitPatterns":[ + ] +} \ No newline at end of file diff --git a/io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters.properties b/io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters.properties new file mode 100644 index 00000000..11b92d1d --- /dev/null +++ b/io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters.properties @@ -0,0 +1,12 @@ +parameter.ai=AI +parameter.ai.chat.enable=AI Chat Enable +parameter.ai.chat.enable.options.enable=Enable +parameter.ai.chat.enable.options.disable=Disable + +parameter.ai.provider.default=Model Provider (default) +parameter.ai.provider.default.options.ollama=Ollama + +parameter.ai.provider=Model Providers +parameter.ai.provider.ollama=Ollama +parameter.ai.provider.ollama.apiUrl=Api URL +parameter.ai.provider.ollama.defaultModelName=Default Model Name \ No newline at end of file diff --git a/io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters_tw_CN.properties b/io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters_tw_CN.properties new file mode 100644 index 00000000..755c59ec --- /dev/null +++ b/io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters_tw_CN.properties @@ -0,0 +1,12 @@ +parameter.ai=\u4EBA\u5DE5\u667A\u80FD +parameter.ai.chat.enable=\u662F\u5426\u958B\u555F\u667A\u80FD\u5C0D\u8A71 +parameter.ai.chat.enable.options.enable=\u958B\u555F +parameter.ai.chat.enable.options.disable=\u95DC\u9589 + +parameter.ai.provider.default=\u9ED8\u8A8D\u6A21\u578B\u63D0\u4F9B\u5546 +parameter.ai.provider.default.options.ollama=Ollama + +parameter.ai.provider=\u6A21\u578B\u63D0\u4F9B\u5546 +parameter.ai.provider.ollama=Ollama +parameter.ai.provider.ollama.apiUrl=Api URL +parameter.ai.provider.ollama.defaultModelName=\u9ED8\u8A8D\u6A21\u578B\u540D\u7A31 \ No newline at end of file diff --git a/io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters_zh_CN.properties b/io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters_zh_CN.properties new file mode 100644 index 00000000..4cbc5b93 --- /dev/null +++ b/io.sc.platform.ai/src/main/resources/io/sc/platform/ai/i18n/parameters_zh_CN.properties @@ -0,0 +1,13 @@ +parameter.ai=\u4EBA\u5DE5\u667A\u80FD + +parameter.ai.chat.enable=\u662F\u5426\u5F00\u542F\u667A\u80FD\u5BF9\u8BDD +parameter.ai.chat.enable.options.enable=\u5F00\u542F +parameter.ai.chat.enable.options.disable=\u5173\u95ED + +parameter.ai.provider.default=\u9ED8\u8BA4\u6A21\u578B\u63D0\u4F9B\u5546 +parameter.ai.provider.default.options.ollama=Ollama + +parameter.ai.provider=\u6A21\u578B\u63D0\u4F9B\u5546 +parameter.ai.provider.ollama=Ollama +parameter.ai.provider.ollama.apiUrl=Api URL +parameter.ai.provider.ollama.defaultModelName=\u9ED8\u8BA4\u6A21\u578B\u540D\u79F0 \ No newline at end of file diff --git a/io.sc.platform.app-nacos/build.gradle b/io.sc.platform.app-nacos/build.gradle index 6bc9f816..a12bbfdb 100644 --- a/io.sc.platform.app-nacos/build.gradle +++ b/io.sc.platform.app-nacos/build.gradle @@ -1,6 +1,5 @@ dependencies { api( - project(":io.sc.platform.app"), project(":io.sc.platform.springcloud.nacos"), project(":io.sc.platform.springcloud.sentinel"), ) diff --git a/io.sc.platform.core.frontend/package.json b/io.sc.platform.core.frontend/package.json index 521a0814..c3a67a2c 100644 --- a/io.sc.platform.core.frontend/package.json +++ b/io.sc.platform.core.frontend/package.json @@ -1,6 +1,6 @@ { "name": "platform-core", - "version": "8.2.40", + "version": "8.2.48", "description": "前端核心包,用于快速构建前端的脚手架", "//main": "库的主文件", "main": "dist/platform-core.js", @@ -115,6 +115,7 @@ "@codemirror/view": "6.36.2", "@maxgraph/core": "0.14.0", "@quasar/extras": "1.16.15", + "@quasar/quasar-ui-qmarkdown": "2.0.5", "@univerjs/core": "0.5.4", "@univerjs/design": "0.5.4", "@univerjs/docs": "0.5.4", @@ -128,7 +129,7 @@ "@univerjs/thread-comment": "0.5.4", "@univerjs/ui": "0.5.4", "@vueuse/core": "12.4.0", - "axios": "1.7.9", + "axios": "1.8.2", "codemirror": "6.0.1", "dayjs": "1.11.13", "echarts": "5.6.0", diff --git a/io.sc.platform.core.frontend/src/boostrap.ts b/io.sc.platform.core.frontend/src/boostrap.ts index 85d1067a..265e7c2d 100644 --- a/io.sc.platform.core.frontend/src/boostrap.ts +++ b/io.sc.platform.core.frontend/src/boostrap.ts @@ -15,6 +15,8 @@ import App from './App.vue'; // import 'platform-core/dist/css/platform-core.css'; // // 导入 tailwind utilities css // import 'tailwindcss/utilities.css'; +// // 导入 quasar-ui-qmarkdown css +// import '@quasar/quasar-ui-qmarkdown/dist/index.css'; // 设置远程组件加载器 // 覆盖 platform-core 包中的 remoteComponentLoader 函数 diff --git a/io.sc.platform.core.frontend/src/components/index.ts b/io.sc.platform.core.frontend/src/components/index.ts index 06378e8d..5e95116b 100644 --- a/io.sc.platform.core.frontend/src/components/index.ts +++ b/io.sc.platform.core.frontend/src/components/index.ts @@ -11,6 +11,7 @@ import component_testcase_loading from '@/views/testcase/loading/loading.vue'; import component_testcase_excel from '@/views/testcase/excel/Excel.vue'; import component_testcase_word from '@/views/testcase/word/Word.vue'; import component_testcase_maxgraph from '@/views/testcase/maxgraph/Maxgraph.vue'; +import component_testcase_ai from '@/views/testcase/ai/Ai.vue'; import component_testcase_likmDialog from '@/views/likm/Dialog.vue'; import component_testcase_likmDrawer from '@/views/likm/Drawer.vue'; import component_testcase_likmForm from '@/views/likm/Form.vue'; @@ -31,6 +32,7 @@ const localComponents = { 'component.testcase.excel': component_testcase_excel, 'component.testcase.word': component_testcase_word, 'component.testcase.maxgraph': component_testcase_maxgraph, + 'component.testcase.ai': component_testcase_ai, 'component.testcase.likmDialog': component_testcase_likmDialog, 'component.testcase.likmDrawer': component_testcase_likmDrawer, 'component.testcase.likmForm': component_testcase_likmForm, diff --git a/io.sc.platform.core.frontend/src/i18n/messages.json b/io.sc.platform.core.frontend/src/i18n/messages.json index fa46698e..fe95bf80 100644 --- a/io.sc.platform.core.frontend/src/i18n/messages.json +++ b/io.sc.platform.core.frontend/src/i18n/messages.json @@ -10,6 +10,7 @@ "menu.testcase.excel": "Excel", "menu.testcase.word": "Word", "menu.testcase.maxgraph": "Graph Editor", + "menu.testcase.ai": "AI", "route.testcase.noMenuRoute": "No Menu Route" } diff --git a/io.sc.platform.core.frontend/src/i18n/messages_tw_CN.json b/io.sc.platform.core.frontend/src/i18n/messages_tw_CN.json index 85003056..69d958b0 100644 --- a/io.sc.platform.core.frontend/src/i18n/messages_tw_CN.json +++ b/io.sc.platform.core.frontend/src/i18n/messages_tw_CN.json @@ -10,6 +10,7 @@ "menu.testcase.excel": "Excel", "menu.testcase.word": "Word", "menu.testcase.maxgraph": "图形编辑器", + "menu.testcase.ai": "AI", "route.testcase.noMenuRoute": "無關聯菜單路由" } diff --git a/io.sc.platform.core.frontend/src/i18n/messages_zh_CN.json b/io.sc.platform.core.frontend/src/i18n/messages_zh_CN.json index 2fca94e2..15de1e60 100644 --- a/io.sc.platform.core.frontend/src/i18n/messages_zh_CN.json +++ b/io.sc.platform.core.frontend/src/i18n/messages_zh_CN.json @@ -10,6 +10,7 @@ "menu.testcase.excel": "Excel", "menu.testcase.word": "Word", "menu.testcase.maxgraph": "图形编辑器", + "menu.testcase.ai": "AI", "route.testcase.noMenuRoute": "无关联菜单路由" } diff --git a/io.sc.platform.core.frontend/src/menus/menus.json b/io.sc.platform.core.frontend/src/menus/menus.json index 21141c4a..a4713657 100644 --- a/io.sc.platform.core.frontend/src/menus/menus.json +++ b/io.sc.platform.core.frontend/src/menus/menus.json @@ -109,6 +109,15 @@ "icon": "bi-palette", "routeName": "route.testcase.maxgraph" }, + { + "type": "ROUTE", + "order": 700, + "parentId": "menu.testcase", + "id": "menu.testcase.ai", + "titleI18nKey": "menu.testcase.ai", + "icon": "bi-palette", + "routeName": "route.testcase.ai" + }, { "type": "GROUP", "order": 30000, "id": "menu.testcase.likm", "titleI18nKey": "测试用例-likm", "icon": "home" }, { diff --git a/io.sc.platform.core.frontend/src/platform/components/layout/WVExpandDiv.vue b/io.sc.platform.core.frontend/src/platform/components/layout/WVExpandDiv.vue index 42bc047a..c6768866 100644 --- a/io.sc.platform.core.frontend/src/platform/components/layout/WVExpandDiv.vue +++ b/io.sc.platform.core.frontend/src/platform/components/layout/WVExpandDiv.vue @@ -14,6 +14,10 @@ const props = defineProps({ fixed: { type: Boolean, default: false }, }); +const emit = defineEmits<{ + (e: 'sizeChanged', height: object): void; +}>(); + const gc = Environment.getConfigure(); const q = useQuasar(); const containerRef = ref(); @@ -64,6 +68,7 @@ const changeDivHeight = () => { } containerHeightRef.value = height > 0 ? height : 0; } + emit('sizeChanged', { width: containerRef.value.getBoundingClientRect().width, height: containerHeightRef.value }); } else if (props.expand === 'parent') { const parentElement = containerRef.value.parentElement; const availableHeight = Math.floor(parentElement.getBoundingClientRect().y) + Math.floor(parentElement.clientHeight); @@ -74,6 +79,7 @@ const changeDivHeight = () => { let height = availableHeight - y; containerHeightRef.value = height > 0 ? height : 0; } + emit('sizeChanged', { width: containerRef.value.getBoundingClientRect().width, height: containerHeightRef.value }); } } }; diff --git a/io.sc.platform.core.frontend/src/platform/index.ts b/io.sc.platform.core.frontend/src/platform/index.ts index 0910df26..412c7385 100644 --- a/io.sc.platform.core.frontend/src/platform/index.ts +++ b/io.sc.platform.core.frontend/src/platform/index.ts @@ -78,7 +78,7 @@ export { PConst } from './PConst'; /** * 导出插件 */ -export { axios, blobAxios, noErrorAxios } from './plugin'; +export { axios, blobAxios, noErrorAxios, Fetch } from './plugin'; export { eventBus } from './plugin'; export { i18n, t, $t } from './plugin'; export { usePlatformStore } from './plugin'; diff --git a/io.sc.platform.core.frontend/src/platform/layout/sub-layout/Topper.vue b/io.sc.platform.core.frontend/src/platform/layout/sub-layout/Topper.vue index f43187e8..f01869d6 100644 --- a/io.sc.platform.core.frontend/src/platform/layout/sub-layout/Topper.vue +++ b/io.sc.platform.core.frontend/src/platform/layout/sub-layout/Topper.vue @@ -27,9 +27,9 @@ - - - + + + - + 120 diff --git a/io.sc.platform.core.frontend/src/platform/plugin/axios.ts b/io.sc.platform.core.frontend/src/platform/plugin/axios.ts index ae126ddf..2aa1f611 100644 --- a/io.sc.platform.core.frontend/src/platform/plugin/axios.ts +++ b/io.sc.platform.core.frontend/src/platform/plugin/axios.ts @@ -4,7 +4,8 @@ import Axios from 'axios'; import { i18n } from './i18n'; import { Environment } from '@/platform/plugin/environment'; import { AuthenticationManager, SessionManager, ServerExceptionHandler } from './manager'; -import { QuasarTools } from '@/platform/utils'; +import { QuasarTools, Tools } from '@/platform/utils'; +import { getHashes } from 'node:crypto'; const ignoredUrls: string[] = [PConst.API_I18N_MESSAGES_URL, PConst.API_APP_CONFIGURE_URL]; const gc = Environment.getConfigure(); @@ -102,6 +103,36 @@ blobAxios.interceptors.response.use((response: any) => { return response; }, getResponseErrorInterceptor(true)); +class Fetch { + public static buildHeaders() { + const gc = Environment.getConfigure(); + // 监测会话是否过期 + if (SessionManager.isTimeout()) { + AuthenticationManager.removeLocalAccessToken(); + } + + // 请求头 + const headers = { + locale: gc.setting.i18n.locale, + 'Content-Type': 'application/json; charset=UTF-8', + }; + if (AuthenticationManager.getLocalAccessToken()) { + headers['Authorization'] = 'Bearer ' + AuthenticationManager.getLocalAccessToken() + ''; + } + return headers; + } + + public static isAuthorization(url: string) { + // 忽略无需认证的请求 URL + for (const ignoredUrl of ignoredUrls) { + if (ignoredUrl.includes(url)) { + return false; + } + } + return true; + } +} + export default { install: (app: App) => { app.config.globalProperties.$axios = axios; @@ -109,4 +140,4 @@ export default { }, }; -export { axios, blobAxios, noErrorAxios }; +export { axios, blobAxios, noErrorAxios, Fetch }; diff --git a/io.sc.platform.core.frontend/src/platform/plugin/index.ts b/io.sc.platform.core.frontend/src/platform/plugin/index.ts index cb68f098..2f9a6c5f 100644 --- a/io.sc.platform.core.frontend/src/platform/plugin/index.ts +++ b/io.sc.platform.core.frontend/src/platform/plugin/index.ts @@ -15,7 +15,7 @@ export default { }, }; -export { axios, blobAxios, noErrorAxios } from './axios'; +export { axios, blobAxios, noErrorAxios, Fetch } from './axios'; export { eventBus } from './quasar'; export { i18n, t, $t } from './i18n'; export { usePlatformStore } from './pinia'; diff --git a/io.sc.platform.core.frontend/src/platform/plugin/quasar-components.ts b/io.sc.platform.core.frontend/src/platform/plugin/quasar-components.ts index 264715f9..706dec55 100644 --- a/io.sc.platform.core.frontend/src/platform/plugin/quasar-components.ts +++ b/io.sc.platform.core.frontend/src/platform/plugin/quasar-components.ts @@ -123,3 +123,5 @@ export { QVideo, QVirtualScroll, } from 'quasar'; + +export { QMarkdown } from '@quasar/quasar-ui-qmarkdown'; diff --git a/io.sc.platform.core.frontend/src/platform/plugin/quasar.ts b/io.sc.platform.core.frontend/src/platform/plugin/quasar.ts index 7a4d8e57..db187213 100644 --- a/io.sc.platform.core.frontend/src/platform/plugin/quasar.ts +++ b/io.sc.platform.core.frontend/src/platform/plugin/quasar.ts @@ -9,6 +9,7 @@ const gc = Environment.getConfigure(); const eventBus: any = new EventBus(); import { Quasar } from 'quasar'; +import qmarkdown from '@quasar/quasar-ui-qmarkdown'; import * as quasarComponents from './quasar-components'; import * as quasarDirectives from './quasar-directives'; diff --git a/io.sc.platform.core.frontend/src/routes/routes.json b/io.sc.platform.core.frontend/src/routes/routes.json index 29deba26..dda10bc7 100644 --- a/io.sc.platform.core.frontend/src/routes/routes.json +++ b/io.sc.platform.core.frontend/src/routes/routes.json @@ -14,7 +14,7 @@ { "force": true, "name": "route.testcase.noMenuRoute", - "icon":'bi-1-circle', + "icon": "bi-1-circle", "path": "testcase/noMenuRoute/:id", "parent": "/", "priority": 0, @@ -116,6 +116,19 @@ } }, + { + "name": "route.testcase.ai", + "path": "testcase/ai", + "parent": "/", + "priority": 0, + "component": "component.testcase.ai", + "componentPath": "@/views/testcase/ai/Ai.vue", + "redirect": null, + "meta": { + "permissions": ["/testcase/ai/**/*"] + } + }, + { "name": "route.testcase.likm.dialog", "path": "testcase/likm/dialog", diff --git a/io.sc.platform.core.frontend/src/views/testcase/code-mirror/code-mirror.vue b/io.sc.platform.core.frontend/src/views/testcase/code-mirror/code-mirror.vue index 077d5c9a..0de0dddd 100644 --- a/io.sc.platform.core.frontend/src/views/testcase/code-mirror/code-mirror.vue +++ b/io.sc.platform.core.frontend/src/views/testcase/code-mirror/code-mirror.vue @@ -1,18 +1,32 @@