mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-24 07:49:47 +08:00
Compare commits
19 Commits
9c51f75404
...
v2.0
Author | SHA1 | Date | |
---|---|---|---|
3496852be1 | |||
4e27f3b5a5 | |||
e623b560e4 | |||
8aeb73627a | |||
3f148a4e62 | |||
34ab7d5da2 | |||
513dc31eaa | |||
dc2fbbd556 | |||
56fd5434ca | |||
ad207255bb | |||
3146c039f0 | |||
d5bbc37dec | |||
2f794c4b73 | |||
378aa869bf | |||
4a4244b5c4 | |||
ecad1c3e78 | |||
9ef0bd416e | |||
25ee32074a | |||
8412a8db16 |
@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"playwright": {
|
"playwright": {
|
||||||
"command": "npx",
|
"command": "npx",
|
||||||
"args": ["@playwright/mcp@0.0.29"]
|
"args": ["@playwright/mcp@latest"]
|
||||||
},
|
},
|
||||||
"mcp-server-time": {
|
"mcp-server-time": {
|
||||||
"command": "uvx",
|
"command": "uvx",
|
||||||
@ -26,14 +26,21 @@
|
|||||||
"command": "npx",
|
"command": "npx",
|
||||||
"args": ["-y", "mcp-shrimp-task-manager"],
|
"args": ["-y", "mcp-shrimp-task-manager"],
|
||||||
"env": {
|
"env": {
|
||||||
"DATA_DIR": "D:/workspace/mcp-shrimp-task-manager/data",
|
"DATA_DIR": "D:/workspace/tools/mcp-shrimp-task-manager/data",
|
||||||
"TEMPLATES_USE": "en",
|
"TEMPLATES_USE": "en",
|
||||||
"ENABLE_GUI": "false"
|
"ENABLE_GUI": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mcp-deepwiki": {
|
"mcp-deepwiki": {
|
||||||
"command": "npx",
|
"command": "npx",
|
||||||
"args": ["-y", "mcp-deepwiki@latest"]
|
"args": ["-y", "mcp-deepwiki@latest"]
|
||||||
|
},
|
||||||
|
"memory": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "@modelcontextprotocol/server-memory"],
|
||||||
|
"env": {
|
||||||
|
"MEMORY_FILE_PATH": "D:/workspace/tools/server-memory/memory.json"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
---
|
---
|
||||||
description:
|
|
||||||
globs:
|
|
||||||
alwaysApply: false
|
alwaysApply: false
|
||||||
---
|
---
|
||||||
|
|
||||||
**# RIPER-5 + 多维度思维 + 代理执行协议 (v4.9.1 - MCP工具驱动版)**
|
**# RIPER-5 + 多维度思维 + 代理执行协议 (v4.9.1 - MCP工具驱动版)**
|
||||||
|
|
||||||
**元指令:** 此协议旨在最大化你的战略规划与执行效率。你的核心任务是**指挥和利用MCP工具集**来驱动项目进展。严格遵守核心原则,利用 `mcp-shrimp-task-manager` 进行项目规划与追踪,使用 `deepwiki-mcp` 进行深度研究。主动管理 `/project_document` 作为知识库。**每轮主要响应后,调用 `mcp.feedback_enhanced` 进行交互或通知。**
|
**元指令:** 此协议旨在最大化你的战略规划与执行效率。你的核心任务是**指挥和利用MCP工具集**来驱动项目进展。严格遵守核心原则,利用 `mcp-shrimp-task-manager` 进行项目规划与追踪,使用 `deepwiki-mcp` 进行深度研究。主动管理 `/project_document` 作为知识库。**每轮主要响应后,调用 `mcp.feedback_enhanced` 进行交互或通知。**
|
||||||
@ -167,5 +164,4 @@ alwaysApply: false
|
|||||||
|
|
||||||
* **极致效率:** AI应最大限度地减少手动干预,让MCP工具处理所有可以自动化的工作。
|
* **极致效率:** AI应最大限度地减少手动干预,让MCP工具处理所有可以自动化的工作。
|
||||||
* **战略聚焦:** 将AI的“思考”集中在无法被工具替代的领域:战略决策、创新构想、复杂问题诊断 (`mcp.sequential_thinking`) 和最终质量把关。
|
* **战略聚焦:** 将AI的“思考”集中在无法被工具替代的领域:战略决策、创新构想、复杂问题诊断 (`mcp.sequential_thinking`) 和最终质量把关。
|
||||||
|
|
||||||
* **无缝集成:** 期望AI能流畅地在不同MCP工具之间传递信息,形成一个高度整合的自动化工作流。
|
* **无缝集成:** 期望AI能流畅地在不同MCP工具之间传递信息,形成一个高度整合的自动化工作流。
|
||||||
|
2
.env.dev
2
.env.dev
@ -15,6 +15,8 @@ VITE_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
|
|||||||
|
|
||||||
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
|
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
|
||||||
VITE_APP_ENCRYPT=Y
|
VITE_APP_ENCRYPT=Y
|
||||||
|
# AES 加密头标识
|
||||||
|
VITE_HEADER_FLAG=encrypt-key
|
||||||
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
||||||
VITE_APP_RSA_PUBLIC_KEY='MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
|
VITE_APP_RSA_PUBLIC_KEY='MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
|
||||||
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
|
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
|
||||||
|
@ -12,6 +12,8 @@ VITE_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
|
|||||||
|
|
||||||
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
|
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
|
||||||
VITE_APP_ENCRYPT=Y
|
VITE_APP_ENCRYPT=Y
|
||||||
|
# AES 加密头标识
|
||||||
|
VITE_HEADER_FLAG=encrypt-key
|
||||||
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
||||||
VITE_APP_RSA_PUBLIC_KEY='MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
|
VITE_APP_RSA_PUBLIC_KEY='MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
|
||||||
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
|
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
|
||||||
|
@ -12,6 +12,8 @@ VITE_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
|
|||||||
|
|
||||||
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
|
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
|
||||||
VITE_APP_ENCRYPT=Y
|
VITE_APP_ENCRYPT=Y
|
||||||
|
# AES 加密头标识
|
||||||
|
VITE_HEADER_FLAG=encrypt-key
|
||||||
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
||||||
VITE_APP_RSA_PUBLIC_KEY='MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
|
VITE_APP_RSA_PUBLIC_KEY='MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
|
||||||
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
|
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
|
||||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -31,7 +31,8 @@
|
|||||||
"vue.server.hybridMode": true,
|
"vue.server.hybridMode": true,
|
||||||
"files.exclude": { "/docs": true },
|
"files.exclude": { "/docs": true },
|
||||||
"search.exclude": {
|
"search.exclude": {
|
||||||
"/docs": true
|
"/docs": true,
|
||||||
|
"**/dist/**": true
|
||||||
},
|
},
|
||||||
"cSpell.words": ["Axios", "tinymce"]
|
"cSpell.words": ["Axios", "tinymce"]
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import org.apache.velocity.VelocityContext;
|
|||||||
import org.dromara.common.core.utils.DateUtils;
|
import org.dromara.common.core.utils.DateUtils;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.json.utils.JsonUtils;
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
|
import org.dromara.common.mybatis.enums.DataBaseType;
|
||||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
||||||
import org.dromara.generator.constant.GenConstants;
|
import org.dromara.generator.constant.GenConstants;
|
||||||
import org.dromara.generator.domain.GenTable;
|
import org.dromara.generator.domain.GenTable;
|
||||||
@ -58,7 +59,7 @@ public class VelocityUtils {
|
|||||||
velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】");
|
velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】");
|
||||||
velocityContext.put("ClassName", genTable.getClassName());
|
velocityContext.put("ClassName", genTable.getClassName());
|
||||||
velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
|
velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
|
||||||
velocityContext.put("moduleName", genTable.getModuleName());
|
velocityContext.put("moduleName", StrUtil.toSymbolCase(genTable.getModuleName(), '-'));
|
||||||
velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName()));
|
velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName()));
|
||||||
velocityContext.put("businessName", genTable.getBusinessName());
|
velocityContext.put("businessName", genTable.getBusinessName());
|
||||||
velocityContext.put("business_name", StrUtil.toUnderlineCase(genTable.getBusinessName()));
|
velocityContext.put("business_name", StrUtil.toUnderlineCase(genTable.getBusinessName()));
|
||||||
@ -124,11 +125,12 @@ public class VelocityUtils {
|
|||||||
templates.add("vm/java/serviceImpl.java.vm");
|
templates.add("vm/java/serviceImpl.java.vm");
|
||||||
templates.add("vm/java/controller.java.vm");
|
templates.add("vm/java/controller.java.vm");
|
||||||
templates.add("vm/xml/mapper.xml.vm");
|
templates.add("vm/xml/mapper.xml.vm");
|
||||||
if (DataBaseHelper.isOracle()) {
|
DataBaseType dataBaseType = DataBaseHelper.getDataBaseType();
|
||||||
|
if (dataBaseType.isOracle()) {
|
||||||
templates.add("vm/sql/oracle/sql.vm");
|
templates.add("vm/sql/oracle/sql.vm");
|
||||||
} else if (DataBaseHelper.isPostgerSql()) {
|
} else if (dataBaseType.isPostgreSql()) {
|
||||||
templates.add("vm/sql/postgres/sql.vm");
|
templates.add("vm/sql/postgres/sql.vm");
|
||||||
} else if (DataBaseHelper.isSqlServer()) {
|
} else if (dataBaseType.isSqlServer()) {
|
||||||
templates.add("vm/sql/sqlserver/sql.vm");
|
templates.add("vm/sql/sqlserver/sql.vm");
|
||||||
} else {
|
} else {
|
||||||
templates.add("vm/sql/sql.vm");
|
templates.add("vm/sql/sql.vm");
|
||||||
@ -163,7 +165,7 @@ public class VelocityUtils {
|
|||||||
String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
|
String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
|
||||||
String mybatisPath = MYBATIS_PATH + "/" + moduleName;
|
String mybatisPath = MYBATIS_PATH + "/" + moduleName;
|
||||||
String soybeanPath = "soy";
|
String soybeanPath = "soy";
|
||||||
|
String soybeanModuleName = StrUtil.toSymbolCase(moduleName, '-');
|
||||||
if (template.contains("domain.java.vm")) {
|
if (template.contains("domain.java.vm")) {
|
||||||
fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
|
fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
|
||||||
}
|
}
|
||||||
@ -186,17 +188,17 @@ public class VelocityUtils {
|
|||||||
} else if (template.contains("sql.vm")) {
|
} else if (template.contains("sql.vm")) {
|
||||||
fileName = businessName + "Menu.sql";
|
fileName = businessName + "Menu.sql";
|
||||||
} else if (template.contains("index.vue.vm")) {
|
} else if (template.contains("index.vue.vm")) {
|
||||||
fileName = StringUtils.format("{}/views/{}/{}/index.vue", soybeanPath, moduleName, StrUtil.toSymbolCase(businessName, '-'));
|
fileName = StringUtils.format("{}/views/{}/{}/index.vue", soybeanPath, soybeanModuleName, StrUtil.toSymbolCase(businessName, '-'));
|
||||||
} else if (template.contains("index-tree.vue.vm")) {
|
} else if (template.contains("index-tree.vue.vm")) {
|
||||||
fileName = StringUtils.format("{}/views/{}/{}/index.vue", soybeanPath, moduleName, StrUtil.toSymbolCase(businessName, '-'));
|
fileName = StringUtils.format("{}/views/{}/{}/index.vue", soybeanPath, soybeanModuleName, StrUtil.toSymbolCase(businessName, '-'));
|
||||||
} else if (template.contains("api.d.ts.vm")) {
|
} else if (template.contains("api.d.ts.vm")) {
|
||||||
fileName = StringUtils.format("{}/typings/api/{}.{}.api.d.ts", soybeanPath, moduleName, StrUtil.toSymbolCase(businessName, '-'));
|
fileName = StringUtils.format("{}/typings/api/{}.{}.api.d.ts", soybeanPath, soybeanModuleName, StrUtil.toSymbolCase(businessName, '-'));
|
||||||
} else if (template.contains("api.ts.vm")) {
|
} else if (template.contains("api.ts.vm")) {
|
||||||
fileName = StringUtils.format("{}/service/api/{}/{}.ts", soybeanPath, moduleName, StrUtil.toSymbolCase(businessName, '-'));
|
fileName = StringUtils.format("{}/service/api/{}/{}.ts", soybeanPath, soybeanModuleName, StrUtil.toSymbolCase(businessName, '-'));
|
||||||
} else if (template.contains("search.vue.vm")) {
|
} else if (template.contains("search.vue.vm")) {
|
||||||
fileName = StringUtils.format("{}/views/{}/{}/modules/{}-search.vue", soybeanPath, moduleName, StrUtil.toSymbolCase(businessName, '-'), StrUtil.toSymbolCase(businessName, '-'));
|
fileName = StringUtils.format("{}/views/{}/{}/modules/{}-search.vue", soybeanPath, soybeanModuleName, StrUtil.toSymbolCase(businessName, '-'), StrUtil.toSymbolCase(businessName, '-'));
|
||||||
} else if (template.contains("operate-drawer.vue.vm")) {
|
} else if (template.contains("operate-drawer.vue.vm")) {
|
||||||
fileName = StringUtils.format("{}/views/{}/{}/modules/{}-operate-drawer.vue", soybeanPath, moduleName, StrUtil.toSymbolCase(businessName, '-'), StrUtil.toSymbolCase(businessName, '-'));
|
fileName = StringUtils.format("{}/views/{}/{}/modules/{}-operate-drawer.vue", soybeanPath, soybeanModuleName, StrUtil.toSymbolCase(businessName, '-'), StrUtil.toSymbolCase(businessName, '-'));
|
||||||
}
|
}
|
||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
1539
pnpm-lock.yaml
generated
1539
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
|||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import hljs from 'highlight.js/lib/core';
|
import hljs from 'highlight.js/lib/core';
|
||||||
import json from 'highlight.js/lib/languages/json';
|
import json from 'highlight.js/lib/languages/json';
|
||||||
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
hljs.registerLanguage('json', json);
|
hljs.registerLanguage('json', json);
|
||||||
|
|
||||||
@ -10,15 +11,19 @@ defineOptions({
|
|||||||
});
|
});
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
class?: string;
|
||||||
code?: string;
|
code?: string;
|
||||||
showLineNumbers?: boolean;
|
showLineNumbers?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
class: '',
|
||||||
code: '',
|
code: '',
|
||||||
showLineNumbers: false
|
showLineNumbers: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const DEFAULT_CLASS = 'max-h-500px';
|
||||||
|
|
||||||
/** 格式化JSON数据 */
|
/** 格式化JSON数据 */
|
||||||
const jsonData = computed<string>(() => {
|
const jsonData = computed<string>(() => {
|
||||||
if (!props.code) return '';
|
if (!props.code) return '';
|
||||||
@ -33,9 +38,9 @@ const jsonData = computed<string>(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="json-preview">
|
<NScrollbar :class="twMerge(DEFAULT_CLASS, props.class)">
|
||||||
<NCode :code="jsonData" :hljs="hljs" language="json" :show-line-numbers="showLineNumbers" />
|
<NCode :code="jsonData" :hljs="hljs" language="json" :show-line-numbers="showLineNumbers" :word-wrap="true" />
|
||||||
</div>
|
</NScrollbar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -44,18 +49,4 @@ html[class='dark'] {
|
|||||||
background-color: #7c7777;
|
background-color: #7c7777;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.json-preview {
|
|
||||||
width: 100%;
|
|
||||||
max-height: 500px;
|
|
||||||
overflow-y: auto;
|
|
||||||
@include scrollbar();
|
|
||||||
.empty-data {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 100%;
|
|
||||||
color: #999;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -4,5 +4,6 @@ export enum SetupStoreId {
|
|||||||
Auth = 'auth-store',
|
Auth = 'auth-store',
|
||||||
Route = 'route-store',
|
Route = 'route-store',
|
||||||
Tab = 'tab-store',
|
Tab = 'tab-store',
|
||||||
Notice = 'notice-store'
|
Notice = 'notice-store',
|
||||||
|
Dict = 'dict-store'
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ const toGitee = () => {
|
|||||||
</NBadge>
|
</NBadge>
|
||||||
</NButton>
|
</NButton>
|
||||||
</template>
|
</template>
|
||||||
消息
|
{{ $t('page.home.message') }}
|
||||||
</NTooltip>
|
</NTooltip>
|
||||||
</template>
|
</template>
|
||||||
<NCard
|
<NCard
|
||||||
|
@ -8,7 +8,7 @@ import { decrypt, encrypt } from '@/utils/jsencrypt';
|
|||||||
import { getAuthorization, handleExpiredRequest, showErrorMsg } from './shared';
|
import { getAuthorization, handleExpiredRequest, showErrorMsg } from './shared';
|
||||||
import type { RequestInstanceState } from './type';
|
import type { RequestInstanceState } from './type';
|
||||||
|
|
||||||
const encryptHeader = 'encrypt-key';
|
const encryptHeader = import.meta.env.VITE_HEADER_FLAG || 'encrypt-key';
|
||||||
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
|
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
|
||||||
const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
|
const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
|
||||||
|
|
||||||
@ -25,23 +25,6 @@ export const request = createFlatRequest(
|
|||||||
refreshTokenPromise: null
|
refreshTokenPromise: null
|
||||||
} as RequestInstanceState,
|
} as RequestInstanceState,
|
||||||
transform(response: AxiosResponse<App.Service.Response<any>>) {
|
transform(response: AxiosResponse<App.Service.Response<any>>) {
|
||||||
if (import.meta.env.VITE_APP_ENCRYPT === 'Y') {
|
|
||||||
// 加密后的 AES 秘钥
|
|
||||||
const keyStr = response.headers[encryptHeader];
|
|
||||||
// 加密
|
|
||||||
if (keyStr && keyStr !== '') {
|
|
||||||
const data = String(response.data);
|
|
||||||
// 请求体 AES 解密
|
|
||||||
const base64Str = decrypt(keyStr);
|
|
||||||
// base64 解码 得到请求头的 AES 秘钥
|
|
||||||
const aesKey = decryptBase64(base64Str.toString());
|
|
||||||
// aesKey 解码 data
|
|
||||||
const decryptData = decryptWithAes(data, aesKey);
|
|
||||||
// 将结果 (得到的是 JSON 字符串) 转为 JSON
|
|
||||||
response.data = JSON.parse(decryptData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 二进制数据则直接返回
|
// 二进制数据则直接返回
|
||||||
if (response.request.responseType === 'blob' || response.request.responseType === 'arraybuffer') {
|
if (response.request.responseType === 'blob' || response.request.responseType === 'arraybuffer') {
|
||||||
return response.data;
|
return response.data;
|
||||||
@ -81,6 +64,14 @@ export const request = createFlatRequest(
|
|||||||
isBackendSuccess(response) {
|
isBackendSuccess(response) {
|
||||||
// when the backend response code is "0000"(default), it means the request is success
|
// when the backend response code is "0000"(default), it means the request is success
|
||||||
// to change this logic by yourself, you can modify the `VITE_SERVICE_SUCCESS_CODE` in `.env` file
|
// to change this logic by yourself, you can modify the `VITE_SERVICE_SUCCESS_CODE` in `.env` file
|
||||||
|
if (import.meta.env.VITE_APP_ENCRYPT === 'Y' && response.headers[encryptHeader]) {
|
||||||
|
const keyStr = response.headers[encryptHeader];
|
||||||
|
const data = String(response.data);
|
||||||
|
const base64Str = decrypt(keyStr);
|
||||||
|
const aesKey = decryptBase64(base64Str.toString());
|
||||||
|
const decryptData = decryptWithAes(data, aesKey);
|
||||||
|
response.data = JSON.parse(decryptData);
|
||||||
|
}
|
||||||
return String(response.data.code) === import.meta.env.VITE_SERVICE_SUCCESS_CODE;
|
return String(response.data.code) === import.meta.env.VITE_SERVICE_SUCCESS_CODE;
|
||||||
},
|
},
|
||||||
async onBackendFail(response, instance) {
|
async onBackendFail(response, instance) {
|
||||||
|
@ -8,6 +8,7 @@ import { localStg } from '@/utils/storage';
|
|||||||
import { SetupStoreId } from '@/enum';
|
import { SetupStoreId } from '@/enum';
|
||||||
import { useRouteStore } from '../route';
|
import { useRouteStore } from '../route';
|
||||||
import { useTabStore } from '../tab';
|
import { useTabStore } from '../tab';
|
||||||
|
import useNoticeStore from '../notice';
|
||||||
import { clearAuthStorage, getToken } from './shared';
|
import { clearAuthStorage, getToken } from './shared';
|
||||||
|
|
||||||
export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
||||||
@ -15,6 +16,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const routeStore = useRouteStore();
|
const routeStore = useRouteStore();
|
||||||
const tabStore = useTabStore();
|
const tabStore = useTabStore();
|
||||||
|
const noticeStore = useNoticeStore();
|
||||||
const { toLogin, redirectFromLogin } = useRouterPush(false);
|
const { toLogin, redirectFromLogin } = useRouterPush(false);
|
||||||
const { loading: loginLoading, startLoading, endLoading } = useLoading();
|
const { loading: loginLoading, startLoading, endLoading } = useLoading();
|
||||||
|
|
||||||
@ -48,6 +50,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
await toLogin();
|
await toLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noticeStore.clearNotice();
|
||||||
tabStore.cacheTabs();
|
tabStore.cacheTabs();
|
||||||
routeStore.resetStore();
|
routeStore.resetStore();
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
|
import { SetupStoreId } from '@/enum';
|
||||||
|
|
||||||
export const useDictStore = defineStore('dict', () => {
|
export const useDictStore = defineStore(SetupStoreId.Dict, () => {
|
||||||
const dictData = ref<{ [key: string]: Api.System.DictData[] }>({});
|
const dictData = ref<{ [key: string]: Api.System.DictData[] }>({});
|
||||||
|
|
||||||
const getDict = (key: string) => {
|
const getDict = (key: string) => {
|
||||||
|
@ -127,7 +127,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
|
|||||||
}
|
}
|
||||||
// @ts-expect-error no hidden field
|
// @ts-expect-error no hidden field
|
||||||
route.meta.hideInMenu = route.hidden;
|
route.meta.hideInMenu = route.hidden;
|
||||||
if (route.meta.hideInMenu && parent) {
|
if (route.meta.hideInMenu && parent && !route.meta.activeMenu) {
|
||||||
// @ts-expect-error parent.name is activeMenu type
|
// @ts-expect-error parent.name is activeMenu type
|
||||||
route.meta.activeMenu = parent.name;
|
route.meta.activeMenu = parent.name;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ html,
|
|||||||
body,
|
body,
|
||||||
#app {
|
#app {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
|
@ -43,7 +43,7 @@ export const themeSettings: App.Theme.ThemeSetting = {
|
|||||||
fixedHeaderAndTab: true,
|
fixedHeaderAndTab: true,
|
||||||
sider: {
|
sider: {
|
||||||
inverted: false,
|
inverted: false,
|
||||||
width: 220,
|
width: 230,
|
||||||
collapsedWidth: 64,
|
collapsedWidth: 64,
|
||||||
mixWidth: 90,
|
mixWidth: 90,
|
||||||
mixCollapsedWidth: 64,
|
mixCollapsedWidth: 64,
|
||||||
|
1
src/typings/vite-env.d.ts
vendored
1
src/typings/vite-env.d.ts
vendored
@ -114,6 +114,7 @@ declare namespace Env {
|
|||||||
readonly VITE_DEVTOOLS_LAUNCH_EDITOR?: import('vite-plugin-vue-devtools').VitePluginVueDevToolsOptions['launchEditor'];
|
readonly VITE_DEVTOOLS_LAUNCH_EDITOR?: import('vite-plugin-vue-devtools').VitePluginVueDevToolsOptions['launchEditor'];
|
||||||
readonly VITE_APP_CLIENT_ID?: string;
|
readonly VITE_APP_CLIENT_ID?: string;
|
||||||
readonly VITE_APP_ENCRYPT?: CommonType.YesOrNo;
|
readonly VITE_APP_ENCRYPT?: CommonType.YesOrNo;
|
||||||
|
readonly VITE_HEADER_FLAG?: string;
|
||||||
readonly VITE_APP_RSA_PUBLIC_KEY?: string;
|
readonly VITE_APP_RSA_PUBLIC_KEY?: string;
|
||||||
readonly VITE_APP_RSA_PRIVATE_KEY?: string;
|
readonly VITE_APP_RSA_PRIVATE_KEY?: string;
|
||||||
readonly VITE_APP_WEBSOCKET: CommonType.YesOrNo;
|
readonly VITE_APP_WEBSOCKET: CommonType.YesOrNo;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { watch } from 'vue';
|
import { watch } from 'vue';
|
||||||
import { useEventSource } from '@vueuse/core';
|
import { useEventSource } from '@vueuse/core';
|
||||||
import useNoticeStore from '@/store/modules/notice';
|
import useNoticeStore from '@/store/modules/notice';
|
||||||
|
import { $t } from '@/locales';
|
||||||
import { localStg } from './storage';
|
import { localStg } from './storage';
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
@ -34,9 +35,14 @@ export const initSSE = (url: any) => {
|
|||||||
read: false,
|
read: false,
|
||||||
time: new Date().toLocaleString()
|
time: new Date().toLocaleString()
|
||||||
});
|
});
|
||||||
|
let content = data.value;
|
||||||
|
const noticeType = content.match(/\[dict\.(.*?)\]/)?.[1];
|
||||||
|
if (noticeType) {
|
||||||
|
content = content.replace(`dict.${noticeType}`, $t(`dict.${noticeType}` as App.I18n.I18nKey));
|
||||||
|
}
|
||||||
window.$notification?.create({
|
window.$notification?.create({
|
||||||
title: '消息',
|
title: '消息',
|
||||||
content: data.value,
|
content,
|
||||||
type: 'success',
|
type: 'success',
|
||||||
duration: 3000
|
duration: 3000
|
||||||
});
|
});
|
||||||
|
@ -39,8 +39,7 @@ const activeModule = computed(() => moduleMap[props.module || 'pwd-login']);
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- Copyright By https://github.com/Daymychen/art-design-pro/blob/main/src/components/core/views/login/LoginLeftView.vue -->
|
<div class="scroll box-border size-full flex">
|
||||||
<div class="box-border size-full flex">
|
|
||||||
<div class="relative box-border hidden h-full w-65vw overflow-hidden bg-primary-50 xl:block dark:bg-primary-900">
|
<div class="relative box-border hidden h-full w-65vw overflow-hidden bg-primary-50 xl:block dark:bg-primary-900">
|
||||||
<div class="relative z-100 flex items-center pl-30px pt-30px">
|
<div class="relative z-100 flex items-center pl-30px pt-30px">
|
||||||
<SystemLogo class="text-32px text-primary" />
|
<SystemLogo class="text-32px text-primary" />
|
||||||
@ -55,13 +54,13 @@ const activeModule = computed(() => moduleMap[props.module || 'pwd-login']);
|
|||||||
</div>
|
</div>
|
||||||
<WaveBg />
|
<WaveBg />
|
||||||
</div>
|
</div>
|
||||||
<header class="relative h-full flex-1 xl:m-auto sm:!w-full">
|
<div class="relative h-full flex-1 xl:m-auto sm:!w-full">
|
||||||
<div class="relative z-100 block flex items-center pl-30px pt-30px xl:hidden">
|
<header class="flex-y-center justify-between px-30px pt-30px xl:justify-end">
|
||||||
<SystemLogo class="text-32px text-primary" />
|
<div class="relative z-100 block flex items-center xl:hidden">
|
||||||
<h3 class="ml-10px text-20px font-400">{{ $t('system.title') }}</h3>
|
<SystemLogo class="text-32px text-primary" />
|
||||||
</div>
|
<h3 class="ml-10px text-20px font-400">{{ $t('system.title') }}</h3>
|
||||||
<div class="position-fixed right-30px top-24px z-100 flex items-center justify-end">
|
</div>
|
||||||
<div class="ml-15px inline-block flex cursor-pointer select-none p-5px">
|
<div class="flex items-center justify-end">
|
||||||
<ThemeSchemaSwitch
|
<ThemeSchemaSwitch
|
||||||
:theme-schema="themeStore.themeScheme"
|
:theme-schema="themeStore.themeScheme"
|
||||||
:show-tooltip="false"
|
:show-tooltip="false"
|
||||||
@ -77,14 +76,32 @@ const activeModule = computed(() => moduleMap[props.module || 'pwd-login']);
|
|||||||
@change-lang="appStore.changeLocale"
|
@change-lang="appStore.changeLocale"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</header>
|
||||||
<main class="absolute inset-0 m-auto h-630px max-w-450px w-full overflow-hidden rounded-5px bg-cover px-24px">
|
<main
|
||||||
|
class="m-auto mt-10% h-630px max-w-450px w-full rounded-5px bg-cover px-24px xl:absolute xl:inset-0 lg:mt-15% xl:mt-auto"
|
||||||
|
>
|
||||||
<Transition :name="themeStore.page.animateMode" mode="out-in" appear>
|
<Transition :name="themeStore.page.animateMode" mode="out-in" appear>
|
||||||
<component :is="activeModule.component" />
|
<component :is="activeModule.component" />
|
||||||
</Transition>
|
</Transition>
|
||||||
</main>
|
</main>
|
||||||
</header>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped>
|
||||||
|
.scroll {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll {
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
Reference in New Issue
Block a user