diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ac4fe231d..60742282a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ on: - "**.csproj" env: - DOTNET_VERSION: "9.0.301" + DOTNET_VERSION: "9.0.304" jobs: build: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a5cf75644..9020906b2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,7 +4,7 @@ on: pull_request: branches: [ main ] env: - DOTNET_VERSION: "9.0.301" + DOTNET_VERSION: "9.0.304" jobs: publish: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b998f21e5..b536eb539 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,4 +14,4 @@ jobs: with: repo_token: "${{ secrets.GITHUB_TOKEN }}" prerelease: false - automatic_release_tag: "9.2.1" + automatic_release_tag: "9.3.1" diff --git a/Directory.Packages.props b/Directory.Packages.props index 82b823da1..6503ea59f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,16 +3,16 @@ 8.3.5 2.15.2 3.3.5 - 9.2.1 - 9.2.1 - 9.0.4 - 9.0.4 - 9.0.4 + 9.3.1 + 9.3.1 + 9.0.5 + 9.0.5 + 9.0.5 true - + @@ -63,7 +63,8 @@ - + + @@ -157,7 +158,7 @@ - + @@ -174,8 +175,9 @@ - - + + + @@ -264,7 +266,7 @@ - + @@ -276,7 +278,7 @@ - + @@ -299,8 +301,8 @@ - - + + @@ -309,6 +311,7 @@ + diff --git a/apps/vben5/.husky/commit-msg b/apps/vben5/.husky/commit-msg deleted file mode 100644 index 270ebb8c1..000000000 --- a/apps/vben5/.husky/commit-msg +++ /dev/null @@ -1,6 +0,0 @@ -echo Start running commit-msg hook... - -# Check whether the git commit information is standardized -pnpm exec commitlint --edit "$1" - -echo Run commit-msg hook done. diff --git a/apps/vben5/.husky/post-merge b/apps/vben5/.husky/post-merge deleted file mode 100644 index 83fa775d5..000000000 --- a/apps/vben5/.husky/post-merge +++ /dev/null @@ -1,3 +0,0 @@ -# 每次 git pull 之后, 安装依赖 - -pnpm install diff --git a/apps/vben5/.husky/pre-commit b/apps/vben5/.husky/pre-commit deleted file mode 100644 index 5dccee288..000000000 --- a/apps/vben5/.husky/pre-commit +++ /dev/null @@ -1,7 +0,0 @@ -# update `.vscode/vben-admin.code-workspace` file -pnpm vsh code-workspace --auto-commit - -# Format and submit code according to lintstagedrc.js configuration -pnpm exec lint-staged - -echo Run pre-commit hook done. diff --git a/apps/vben5/.lintstagedrc.mjs b/apps/vben5/.lintstagedrc.mjs deleted file mode 100644 index 94b0192a7..000000000 --- a/apps/vben5/.lintstagedrc.mjs +++ /dev/null @@ -1,20 +0,0 @@ -export default { - '*.md': ['prettier --cache --ignore-unknown --write'], - '*.vue': [ - 'prettier --write', - 'eslint --cache --fix', - 'stylelint --fix --allow-empty-input', - ], - '*.{js,jsx,ts,tsx}': [ - 'prettier --cache --ignore-unknown --write', - 'eslint --cache --fix', - ], - '*.{scss,less,styl,html,vue,css}': [ - 'prettier --cache --ignore-unknown --write', - 'stylelint --fix --allow-empty-input', - ], - 'package.json': ['prettier --cache --write'], - '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [ - 'prettier --cache --write--parser json', - ], -}; diff --git a/apps/vben5/.vscode/extensions.json b/apps/vben5/.vscode/extensions.json new file mode 100644 index 000000000..e8dc9ed9b --- /dev/null +++ b/apps/vben5/.vscode/extensions.json @@ -0,0 +1,30 @@ +{ + "recommendations": [ + // Vue 3 的语言支持 + "Vue.volar", + // 将 ESLint JavaScript 集成到 VS Code 中。 + "dbaeumer.vscode-eslint", + // Visual Studio Code 的官方 Stylelint 扩展 + "stylelint.vscode-stylelint", + // 使用 Prettier 的代码格式化程序 + "esbenp.prettier-vscode", + // 支持 dotenv 文件语法 + "mikestead.dotenv", + // 源代码的拼写检查器 + "streetsidesoftware.code-spell-checker", + // Tailwind CSS 的官方 VS Code 插件 + "bradlc.vscode-tailwindcss", + // iconify 图标插件 + "antfu.iconify", + // i18n 插件 + "Lokalise.i18n-ally", + // CSS 变量提示 + "vunguyentuan.vscode-css-variables", + // 在 package.json 中显示 PNPM catalog 的版本 + "antfu.pnpm-catalog-lens" + ], + "unwantedRecommendations": [ + // 和 volar 冲突 + "octref.vetur" + ] +} diff --git a/apps/vben5/.vscode/global.code-snippets b/apps/vben5/.vscode/global.code-snippets new file mode 100644 index 000000000..7604b0148 --- /dev/null +++ b/apps/vben5/.vscode/global.code-snippets @@ -0,0 +1,37 @@ +{ + "import": { + "scope": "javascript,typescript", + "prefix": "im", + "body": ["import { $2 } from '$1';"], + "description": "Import a module", + }, + "export-all": { + "scope": "javascript,typescript", + "prefix": "ex", + "body": ["export * from '$1';"], + "description": "Export a module", + }, + "vue-script-setup": { + "scope": "vue", + "prefix": "", + "const props = defineProps<{", + " modelValue?: boolean,", + "}>()", + "$1", + "", + "", + "", + " ", + " ", + " ", + "", + ], + }, + "vue-computed": { + "scope": "javascript,typescript,vue", + "prefix": "com", + "body": ["computed(() => { $1 })"], + }, +} diff --git a/apps/vben5/.vscode/launch.json b/apps/vben5/.vscode/launch.json new file mode 100644 index 000000000..d868ef52b --- /dev/null +++ b/apps/vben5/.vscode/launch.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "name": "vben admin playground dev", + "request": "launch", + "url": "http://localhost:5555", + "env": { "NODE_ENV": "development" }, + "sourceMaps": true, + "webRoot": "${workspaceFolder}/playground" + }, + { + "type": "chrome", + "name": "vben abp antd dev", + "request": "launch", + "url": "http://localhost:5666", + "env": { "NODE_ENV": "development" }, + "sourceMaps": true, + "webRoot": "${workspaceFolder}/apps/app-antd" + }, + { + "type": "chrome", + "name": "vben admin antd dev", + "request": "launch", + "url": "http://localhost:5666", + "env": { "NODE_ENV": "development" }, + "sourceMaps": true, + "webRoot": "${workspaceFolder}/apps/web-antd" + }, + { + "type": "chrome", + "name": "vben admin ele dev", + "request": "launch", + "url": "http://localhost:5777", + "env": { "NODE_ENV": "development" }, + "sourceMaps": true, + "webRoot": "${workspaceFolder}/apps/web-ele" + }, + { + "type": "chrome", + "name": "vben admin naive dev", + "request": "launch", + "url": "http://localhost:5888", + "env": { "NODE_ENV": "development" }, + "sourceMaps": true, + "webRoot": "${workspaceFolder}/apps/web-naive" + } + ] +} diff --git a/apps/vben5/.vscode/settings.json b/apps/vben5/.vscode/settings.json new file mode 100644 index 000000000..f38c42781 --- /dev/null +++ b/apps/vben5/.vscode/settings.json @@ -0,0 +1,241 @@ +{ + "tailwindCSS.experimental.configFile": "internal/tailwind-config/src/index.ts", + // workbench + "workbench.list.smoothScrolling": true, + "workbench.startupEditor": "newUntitledFile", + "workbench.tree.indent": 10, + "workbench.editor.highlightModifiedTabs": true, + "workbench.editor.closeOnFileDelete": true, + "workbench.editor.limit.enabled": true, + "workbench.editor.limit.perEditorGroup": true, + "workbench.editor.limit.value": 5, + + // editor + "editor.tabSize": 2, + "editor.detectIndentation": false, + "editor.cursorBlinking": "expand", + "editor.largeFileOptimizations": true, + "editor.accessibilitySupport": "off", + "editor.cursorSmoothCaretAnimation": "on", + "editor.guides.bracketPairs": "active", + "editor.inlineSuggest.enabled": true, + "editor.suggestSelection": "recentlyUsedByPrefix", + "editor.acceptSuggestionOnEnter": "smart", + "editor.suggest.snippetsPreventQuickSuggestions": false, + "editor.stickyScroll.enabled": true, + "editor.hover.sticky": true, + "editor.suggest.insertMode": "replace", + "editor.bracketPairColorization.enabled": true, + "editor.autoClosingBrackets": "beforeWhitespace", + "editor.autoClosingDelete": "always", + "editor.autoClosingOvertype": "always", + "editor.autoClosingQuotes": "beforeWhitespace", + "editor.wordSeparators": "`~!@#%^&*()=+[{]}\\|;:'\",.<>/?", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.fixAll.stylelint": "explicit", + "source.organizeImports": "never" + }, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[html]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[scss]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[markdown]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[jsonc]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[vue]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + // extensions + "extensions.ignoreRecommendations": true, + + // terminal + "terminal.integrated.cursorBlinking": true, + "terminal.integrated.persistentSessionReviveProcess": "never", + "terminal.integrated.tabs.enabled": true, + "terminal.integrated.scrollback": 10000, + "terminal.integrated.stickyScroll.enabled": true, + + // files + "files.eol": "\n", + "files.insertFinalNewline": true, + "files.simpleDialog.enable": true, + "files.associations": { + "*.ejs": "html", + "*.art": "html", + "**/tsconfig.json": "jsonc", + "*.json": "jsonc", + "package.json": "json" + }, + + "files.exclude": { + "**/.eslintcache": true, + "**/bower_components": true, + "**/.turbo": true, + "**/.idea": true, + "**/.vitepress": true, + "**/tmp": true, + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.stylelintcache": true, + "**/.DS_Store": true, + "**/vite.config.mts.*": true, + "**/tea.yaml": true + }, + "files.watcherExclude": { + "**/.git/objects/**": true, + "**/.git/subtree-cache/**": true, + "**/.vscode/**": true, + "**/node_modules/**": true, + "**/tmp/**": true, + "**/bower_components/**": true, + "**/dist/**": true, + "**/yarn.lock": true + }, + + "typescript.tsserver.exclude": ["**/node_modules", "**/dist", "**/.turbo"], + + // search + "search.searchEditor.singleClickBehaviour": "peekDefinition", + "search.followSymlinks": false, + // 在使用搜索功能时,将这些文件夹/文件排除在外 + "search.exclude": { + "**/node_modules": true, + "**/*.log": true, + "**/*.log*": true, + "**/bower_components": true, + "**/dist": true, + "**/elehukouben": true, + "**/.git": true, + "**/.github": true, + "**/.gitignore": true, + "**/.svn": true, + "**/.DS_Store": true, + "**/.vitepress/cache": true, + "**/.idea": true, + "**/.vscode": false, + "**/.yarn": true, + "**/tmp": true, + "*.xml": true, + "out": true, + "dist": true, + "node_modules": true, + "CHANGELOG.md": true, + "**/pnpm-lock.yaml": true, + "**/yarn.lock": true + }, + + "debug.onTaskErrors": "debugAnyway", + "diffEditor.ignoreTrimWhitespace": false, + "npm.packageManager": "pnpm", + + "css.validate": false, + "less.validate": false, + "scss.validate": false, + + // extension + "emmet.showSuggestionsAsSnippets": true, + "emmet.triggerExpansionOnTab": false, + + "errorLens.enabledDiagnosticLevels": ["warning", "error"], + "errorLens.excludeBySource": ["cSpell", "Grammarly", "eslint"], + + "stylelint.enable": true, + "stylelint.packageManager": "pnpm", + "stylelint.validate": ["css", "less", "postcss", "scss", "vue"], + "stylelint.customSyntax": "postcss-html", + "stylelint.snippet": ["css", "less", "postcss", "scss", "vue"], + + "typescript.inlayHints.enumMemberValues.enabled": true, + "typescript.preferences.preferTypeOnlyAutoImports": true, + "typescript.preferences.includePackageJsonAutoImports": "on", + + "eslint.validate": [ + "javascript", + "typescript", + "javascriptreact", + "typescriptreact", + "vue", + "html", + "markdown", + "json", + "jsonc", + "json5" + ], + + "tailwindCSS.experimental.classRegex": [ + ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] + ], + + "github.copilot.enable": { + "*": true, + "markdown": true, + "plaintext": false, + "yaml": false + }, + + "cssVariables.lookupFiles": ["packages/core/base/design/src/**/*.css"], + + "i18n-ally.localesPaths": [ + "packages/locales/src/langs", + "playground/src/locales/langs", + "apps/*/src/locales/langs" + ], + "i18n-ally.pathMatcher": "{locale}/{namespace}.{ext}", + "i18n-ally.enabledParsers": ["json"], + "i18n-ally.sourceLanguage": "en", + "i18n-ally.displayLanguage": "zh-CN", + "i18n-ally.enabledFrameworks": ["vue", "react"], + "i18n-ally.keystyle": "nested", + "i18n-ally.sortKeys": true, + "i18n-ally.namespace": true, + + // 控制相关文件嵌套展示 + "explorer.fileNesting.enabled": true, + "explorer.fileNesting.expand": false, + "explorer.fileNesting.patterns": { + "*.ts": "$(capture).test.ts, $(capture).test.tsx, $(capture).spec.ts, $(capture).spec.tsx, $(capture).d.ts", + "*.tsx": "$(capture).test.ts, $(capture).test.tsx, $(capture).spec.ts, $(capture).spec.tsx,$(capture).d.ts", + "*.env": "$(capture).env.*", + "README.md": "README*,CHANGELOG*,LICENSE,CNAME", + "package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,.gitattributes,.gitignore,.gitpod.yml,.npmrc,.browserslistrc,.node-version,.git*,.tazerc.json", + "eslint.config.mjs": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.*,.prettierrc.*,stylelint.config.*,.lintstagedrc.mjs,cspell.json,lefthook.yml", + "tailwind.config.mjs": "postcss.*" + }, + "commentTranslate.hover.enabled": false, + "commentTranslate.multiLineMerge": true, + "vue.server.hybridMode": true, + "typescript.tsdk": "node_modules/typescript/lib", + "oxc.enable": false, + "cSpell.words": [ + "archiver", + "axios", + "dotenv", + "isequal", + "jspm", + "napi", + "nolebase", + "rollup", + "vitest" + ] +} diff --git a/apps/vben5/apps/app-antd/package.json b/apps/vben5/apps/app-antd/package.json index 03fa292ee..efbe91733 100644 --- a/apps/vben5/apps/app-antd/package.json +++ b/apps/vben5/apps/app-antd/package.json @@ -46,6 +46,7 @@ "@abp/text-templating": "workspace:*", "@abp/ui": "workspace:*", "@abp/webhooks": "workspace:*", + "@abp/wechat": "workspace:*", "@vben-core/shadcn-ui": "workspace:*", "@vben/access": "workspace:*", "@vben/common-ui": "workspace:*", @@ -66,6 +67,7 @@ "dayjs": "catalog:", "pinia": "catalog:", "vue": "catalog:", - "vue-router": "catalog:" + "vue-router": "catalog:", + "vue3-colorpicker": "catalog:" } } diff --git a/apps/vben5/apps/app-antd/src/adapter/component/index.ts b/apps/vben5/apps/app-antd/src/adapter/component/index.ts index 4ab140011..e98ba7f61 100644 --- a/apps/vben5/apps/app-antd/src/adapter/component/index.ts +++ b/apps/vben5/apps/app-antd/src/adapter/component/index.ts @@ -31,6 +31,12 @@ const Button = defineAsyncComponent(() => import('ant-design-vue/es/button')); const Checkbox = defineAsyncComponent( () => import('ant-design-vue/es/checkbox'), ); +const ColorPicker = defineAsyncComponent(() => + import('vue3-colorpicker').then((res) => { + import('vue3-colorpicker/style.css'); + return res.ColorPicker; + }), +); const CheckboxGroup = defineAsyncComponent(() => import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup), ); @@ -117,6 +123,7 @@ export type ComponentType = | 'AutoComplete' | 'Checkbox' | 'CheckboxGroup' + | 'ColorPicker' | 'DatePicker' | 'DefaultButton' | 'Divider' @@ -182,6 +189,7 @@ async function initComponentAdapter() { AutoComplete, Checkbox, CheckboxGroup, + ColorPicker, DatePicker, // 自定义默认按钮 DefaultButton: (props, { attrs, slots }) => { diff --git a/apps/vben5/apps/app-antd/src/adapter/request/index.ts b/apps/vben5/apps/app-antd/src/adapter/request/index.ts index e0c13d6a5..1fe3242a1 100644 --- a/apps/vben5/apps/app-antd/src/adapter/request/index.ts +++ b/apps/vben5/apps/app-antd/src/adapter/request/index.ts @@ -37,7 +37,8 @@ export function initRequestClient() { async function doRefreshToken() { const authStore = useAuthStore(); try { - return await authStore.refreshSession(); + const token = await authStore.refreshSession(); + return token ?? ''; } catch { console.warn('The refresh token has expired or is unavailable.'); } @@ -60,6 +61,9 @@ export function initRequestClient() { if (abpStore.tenantId) { config.headers.__tenant = abpStore.tenantId; } + if (abpStore.xsrfToken) { + config.headers.RequestVerificationToken = abpStore.xsrfToken; + } return config; }, }); diff --git a/apps/vben5/apps/app-antd/src/layouts/basic.vue b/apps/vben5/apps/app-antd/src/layouts/basic.vue index 99d4b38f8..a9059508d 100644 --- a/apps/vben5/apps/app-antd/src/layouts/basic.vue +++ b/apps/vben5/apps/app-antd/src/layouts/basic.vue @@ -5,14 +5,8 @@ import { computed, ref, watch } from 'vue'; import { useRouter } from 'vue-router'; import { AuthenticationLoginExpiredModal } from '@vben/common-ui'; -import { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants'; import { useWatermark } from '@vben/hooks'; -import { - BookOpenText, - CircleHelp, - createIconifyIcon, - MdiGithub, -} from '@vben/icons'; +import { createIconifyIcon } from '@vben/icons'; import { BasicLayout, LockScreen, @@ -21,7 +15,6 @@ import { } from '@vben/layouts'; import { preferences } from '@vben/preferences'; import { useAccessStore, useUserStore } from '@vben/stores'; -import { openWindow } from '@vben/utils'; import { useAbpStore } from '@abp/core'; @@ -32,36 +25,7 @@ import LoginForm from '#/views/_core/authentication/login.vue'; const UserSettingsIcon = createIconifyIcon('tdesign:user-setting'); -const notifications = ref([ - { - avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB', - date: '3小时前', - isRead: true, - message: '描述信息描述信息描述信息', - title: '收到了 14 份新周报', - }, - { - avatar: 'https://avatar.vercel.sh/1', - date: '刚刚', - isRead: false, - message: '描述信息描述信息描述信息', - title: '朱偏右 回复了你', - }, - { - avatar: 'https://avatar.vercel.sh/1', - date: '2024-01-01', - isRead: false, - message: '描述信息描述信息描述信息', - title: '曲丽丽 评论了你', - }, - { - avatar: 'https://avatar.vercel.sh/satori', - date: '1天前', - isRead: false, - message: '描述信息描述信息描述信息', - title: '代办提醒', - }, -]); +const notifications = ref([]); useSessions(); @@ -83,33 +47,6 @@ const menus = computed(() => [ icon: UserSettingsIcon, text: $t('abp.account.settings.title'), }, - { - handler: () => { - openWindow(VBEN_DOC_URL, { - target: '_blank', - }); - }, - icon: BookOpenText, - text: $t('ui.widgets.document'), - }, - { - handler: () => { - openWindow(VBEN_GITHUB_URL, { - target: '_blank', - }); - }, - icon: MdiGithub, - text: 'GitHub', - }, - { - handler: () => { - openWindow(`${VBEN_GITHUB_URL}/issues`, { - target: '_blank', - }); - }, - icon: CircleHelp, - text: $t('ui.widgets.qa'), - }, ]); const userInfo = computed(() => { diff --git a/apps/vben5/apps/app-antd/src/locales/index.ts b/apps/vben5/apps/app-antd/src/locales/index.ts index f221600e7..7fe299ca0 100644 --- a/apps/vben5/apps/app-antd/src/locales/index.ts +++ b/apps/vben5/apps/app-antd/src/locales/index.ts @@ -15,6 +15,7 @@ import { preferences } from '@vben/preferences'; import { useAbpStore } from '@abp/core'; import { useLocalizationsApi } from '@abp/localization'; +import { loadPaltformMessages } from '@abp/platform'; import antdEnLocale from 'ant-design-vue/es/locale/en_US'; import antdDefaultLocale from 'ant-design-vue/es/locale/zh_CN'; import dayjs from 'dayjs'; @@ -34,13 +35,17 @@ const localesMap = loadLocalesMapFromDir( * @param lang */ async function loadMessages(lang: SupportedLanguagesType) { - const [appLocaleMessages, _, abpLocales] = await Promise.all([ - localesMap[lang]?.(), - loadThirdPartyMessage(lang), - loadAbpLocale(lang), - ]); + const [appLocaleMessages, platformLocales, _, abpLocales] = await Promise.all( + [ + localesMap[lang]?.(), + loadPaltformMessages(lang), + loadThirdPartyMessage(lang), + loadAbpLocale(lang), + ], + ); return { ...appLocaleMessages?.default, + ...platformLocales?.default, ...abpLocales, }; } diff --git a/apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json b/apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json index 277f4585d..49dced4c6 100644 --- a/apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json +++ b/apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json @@ -142,5 +142,9 @@ "title": "Object storage", "containers": "Containers", "objects": "Files" + }, + "wechat": { + "title": "WeChat", + "settings": "Settings" } } diff --git a/apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json b/apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json index 0665783bc..16bb7ec01 100644 --- a/apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json +++ b/apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json @@ -142,5 +142,9 @@ "title": "对象存储", "containers": "容器管理", "objects": "文件管理" + }, + "wechat": { + "title": "微信集成", + "settings": "微信设置" } } diff --git a/apps/vben5/apps/app-antd/src/preferences.ts b/apps/vben5/apps/app-antd/src/preferences.ts index 4ee0c5515..94d2a3ca8 100644 --- a/apps/vben5/apps/app-antd/src/preferences.ts +++ b/apps/vben5/apps/app-antd/src/preferences.ts @@ -9,7 +9,15 @@ export const overridesPreferences = defineOverridesPreferences({ // overrides app: { accessMode: 'backend', + defaultHomePath: '/workspace', enableRefreshToken: true, name: import.meta.env.VITE_APP_TITLE, }, + theme: { + mode: 'auto', + radius: '0.25', + }, + widget: { + notification: false, + }, }); diff --git a/apps/vben5/apps/app-antd/src/store/auth.ts b/apps/vben5/apps/app-antd/src/store/auth.ts index 7492529a5..3b3452809 100644 --- a/apps/vben5/apps/app-antd/src/store/auth.ts +++ b/apps/vben5/apps/app-antd/src/store/auth.ts @@ -9,14 +9,7 @@ import { LOGIN_PATH } from '@vben/constants'; import { preferences } from '@vben/preferences'; import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores'; -import { - useOidcClient, - usePhoneLoginApi, - useProfileApi, - useQrCodeLoginApi, - useTokenApi, - useUserInfoApi, -} from '@abp/account'; +import { useOAuthService, useProfileApi } from '@abp/account'; import { Events, useAbpStore, useEventBus } from '@abp/core'; import { notification } from 'ant-design-vue'; import { defineStore } from 'pinia'; @@ -26,48 +19,35 @@ import { $t } from '#/locales'; export const useAuthStore = defineStore('auth', () => { const { publish } = useEventBus(); - const { loginApi, refreshTokenApi } = useTokenApi(); - const { loginApi: qrcodeLoginApi } = useQrCodeLoginApi(); - const { loginApi: phoneLoginApi } = usePhoneLoginApi(); - const { getUserInfoApi } = useUserInfoApi(); const { getConfigApi } = useAbpConfigApi(); const { getPictureApi } = useProfileApi(); const accessStore = useAccessStore(); const userStore = useUserStore(); const abpStore = useAbpStore(); const router = useRouter(); - const oidcClient = useOidcClient(); + const oAuthService = useOAuthService(); const loginLoading = ref(false); async function refreshSession() { - if (await oidcClient.getAccessToken()) { - const user = await oidcClient.refreshToken(); + if (await oAuthService.getAccessToken()) { + const user = await oAuthService.refreshToken(); const newToken = `${user?.token_type} ${user?.access_token}`; accessStore.setAccessToken(newToken); if (user?.refresh_token) { accessStore.setRefreshToken(user.refresh_token); } return newToken; - } else { - const { accessToken, tokenType, refreshToken } = await refreshTokenApi({ - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - refreshToken: accessStore.refreshToken!, - }); - const newToken = `${tokenType} ${accessToken}`; - accessStore.setAccessToken(newToken); - accessStore.setRefreshToken(refreshToken); - return newToken; } } async function oidcLogin() { - await oidcClient.login(); + await oAuthService.login(); } async function oidcCallback() { try { - const user = await oidcClient.handleCallback(); + const user = await oAuthService.handleCallback(); return await _loginSuccess({ accessToken: user.access_token, tokenType: user.token_type, @@ -87,8 +67,17 @@ export const useAuthStore = defineStore('auth', () => { ) { try { loginLoading.value = true; - const result = await qrcodeLoginApi({ key, tenantId }); - return await _loginSuccess(result, onSuccess); + const user = await oAuthService.loginByQrCode({ key, tenantId }); + return await _loginSuccess( + { + accessToken: user.access_token, + tokenType: user.token_type, + refreshToken: user.refresh_token ?? '', + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + expiresIn: user.expires_in!, + }, + onSuccess, + ); } finally { loginLoading.value = false; } @@ -101,8 +90,17 @@ export const useAuthStore = defineStore('auth', () => { ) { try { loginLoading.value = true; - const result = await phoneLoginApi({ phoneNumber, code }); - return await _loginSuccess(result, onSuccess); + const user = await oAuthService.loginBySmsCode({ phoneNumber, code }); + return await _loginSuccess( + { + accessToken: user.access_token, + tokenType: user.token_type, + refreshToken: user.refresh_token ?? '', + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + expiresIn: user.expires_in!, + }, + onSuccess, + ); } finally { loginLoading.value = false; } @@ -119,8 +117,17 @@ export const useAuthStore = defineStore('auth', () => { ) { try { loginLoading.value = true; - const result = await loginApi(params as any); - return await _loginSuccess(result, onSuccess); + const user = await oAuthService.loginByPassword(params as any); + return await _loginSuccess( + { + accessToken: user.access_token, + tokenType: user.token_type, + refreshToken: user.refresh_token ?? '', + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + expiresIn: user.expires_in!, + }, + onSuccess, + ); } finally { loginLoading.value = false; } @@ -128,9 +135,11 @@ export const useAuthStore = defineStore('auth', () => { async function logout(redirect: boolean = true) { try { - if (await oidcClient.getAccessToken()) { + if (await oAuthService.getAccessToken()) { accessStore.setAccessToken(null); - await oidcClient.logout(); + await oAuthService.logout(); + } else { + await oAuthService.revokeTokens(); } } catch { // 不做任何处理 @@ -153,7 +162,11 @@ export const useAuthStore = defineStore('auth', () => { async function fetchUserInfo() { let userInfo: null | (UserInfo & { [key: string]: any }) = null; - const userInfoRes = await getUserInfoApi(); + let userInfoRes: { [key: string]: any } = {}; + const user = await oAuthService.getUser(); + if (user) { + userInfoRes = user.profile; + } const abpConfig = await getConfigApi(); const picture = await getPictureApi(); userInfo = { diff --git a/apps/vben5/apps/app-antd/src/views/_core/fallback/not-found.vue b/apps/vben5/apps/app-antd/src/views/_core/fallback/not-found.vue index 4d178e9cb..9fa96d7f1 100644 --- a/apps/vben5/apps/app-antd/src/views/_core/fallback/not-found.vue +++ b/apps/vben5/apps/app-antd/src/views/_core/fallback/not-found.vue @@ -1,9 +1,51 @@ - + + + + + + {{ $t('common.backToHome') }} + + + + {{ $t('common.logout') }} + + + + diff --git a/apps/vben5/apps/app-antd/src/views/account/my-settings/index.vue b/apps/vben5/apps/app-antd/src/views/account/my-settings/index.vue index 29ccab460..5dda522cc 100644 --- a/apps/vben5/apps/app-antd/src/views/account/my-settings/index.vue +++ b/apps/vben5/apps/app-antd/src/views/account/my-settings/index.vue @@ -1,15 +1,98 @@ - + + diff --git a/apps/vben5/apps/app-antd/src/views/dashboard/workspace/index.vue b/apps/vben5/apps/app-antd/src/views/dashboard/workspace/index.vue index b95d61381..9055b39d8 100644 --- a/apps/vben5/apps/app-antd/src/views/dashboard/workspace/index.vue +++ b/apps/vben5/apps/app-antd/src/views/dashboard/workspace/index.vue @@ -1,266 +1,32 @@ - - - - - 早安, {{ userStore.userInfo?.realName }}, 开始您一天的工作吧! - - 今日晴,20℃ - 32℃! - - - - - - - - - - - - - - - - + + + diff --git a/apps/vben5/packages/@abp/account/src/api/index.ts b/apps/vben5/packages/@abp/account/src/api/index.ts index 54e3e8ead..3810e2eb2 100644 --- a/apps/vben5/packages/@abp/account/src/api/index.ts +++ b/apps/vben5/packages/@abp/account/src/api/index.ts @@ -1,7 +1,5 @@ export { useAccountApi } from './useAccountApi'; +export { useExternalLoginsApi } from './useExternalLoginsApi'; export { useMySessionApi } from './useMySessionApi'; -export { usePhoneLoginApi } from './usePhoneLoginApi'; export { useProfileApi } from './useProfileApi'; -export { useQrCodeLoginApi } from './useQrCodeLoginApi'; -export { useTokenApi } from './useTokenApi'; -export { useUserInfoApi } from './useUserInfoApi'; +export { useScanQrCodeApi } from './useScanQrCodeApi'; diff --git a/apps/vben5/packages/@abp/account/src/api/useExternalLoginsApi.ts b/apps/vben5/packages/@abp/account/src/api/useExternalLoginsApi.ts new file mode 100644 index 000000000..ff2b0122f --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/api/useExternalLoginsApi.ts @@ -0,0 +1,58 @@ +import type { + ExternalLoginResultDto, + RemoveExternalLoginInput, + WorkWeixinLoginBindInput, +} from '../types/external-logins'; + +import { useRequest } from '@abp/request'; + +export function useExternalLoginsApi() { + const { cancel, request } = useRequest(); + + /** + * 绑定企业微信 + * @param input 绑定参数 + * @returns { Promise } + */ + async function bindWorkWeixinApi( + input: WorkWeixinLoginBindInput, + ): Promise { + return await request(`/api/account/oauth/work-weixin/bind`, { + method: 'POST', + data: input, + }); + } + + /** + * 获取外部登录提供者列表 + * @returns 外部登录提供者列表 + */ + async function getExternalLoginsApi(): Promise { + return await request( + `/api/account/external-logins`, + { + method: 'GET', + }, + ); + } + + /** + * 移除外部登录提供者 + * @returns { Promise } + */ + async function removeExternalLoginApi( + input: RemoveExternalLoginInput, + ): Promise { + return await request(`/api/account/external-logins/remove`, { + method: 'DELETE', + params: input, + }); + } + + return { + cancel, + bindWorkWeixinApi, + getExternalLoginsApi, + removeExternalLoginApi, + }; +} diff --git a/apps/vben5/packages/@abp/account/src/api/usePhoneLoginApi.ts b/apps/vben5/packages/@abp/account/src/api/usePhoneLoginApi.ts deleted file mode 100644 index 0d6be68b3..000000000 --- a/apps/vben5/packages/@abp/account/src/api/usePhoneLoginApi.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { OAuthTokenResult, PhoneNumberTokenRequest } from '../types/token'; - -import { useAppConfig } from '@vben/hooks'; - -import { useRequest } from '@abp/request'; - -export function usePhoneLoginApi() { - const { cancel, request } = useRequest(); - - /** - * 手机验证码登录 - * @param input 登录参数 - * @returns 用户token - */ - async function loginApi(input: PhoneNumberTokenRequest) { - const { audience, clientId, clientSecret } = useAppConfig( - import.meta.env, - import.meta.env.PROD, - ); - const result = await request('/connect/token', { - data: { - client_id: clientId, - client_secret: clientSecret, - grant_type: 'phone_verify', - phone_number: input.phoneNumber, - phone_verify_code: input.code, - scope: audience, - }, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - }); - return { - accessToken: result.access_token, - expiresIn: result.expires_in, - refreshToken: result.refresh_token, - tokenType: result.token_type, - }; - } - - return { - cancel, - loginApi, - }; -} diff --git a/apps/vben5/packages/@abp/account/src/api/useQrCodeLoginApi.ts b/apps/vben5/packages/@abp/account/src/api/useQrCodeLoginApi.ts deleted file mode 100644 index 3acf36957..000000000 --- a/apps/vben5/packages/@abp/account/src/api/useQrCodeLoginApi.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { - GenerateQrCodeResult, - QrCodeUserInfoResult, -} from '../types/qrcode'; -import type { OAuthTokenResult, QrCodeTokenRequest } from '../types/token'; - -import { useAppConfig } from '@vben/hooks'; - -import { useRequest } from '@abp/request'; - -export function useQrCodeLoginApi() { - const { cancel, request } = useRequest(); - - /** - * 生成登录二维码 - * @returns 二维码信息 - */ - function generateApi(): Promise { - return request('/api/account/qrcode/generate', { - method: 'POST', - }); - } - - /** - * 检查二维码状态 - * @param key 二维码Key - * @returns 二维码信息 - */ - function checkCodeApi(key: string): Promise { - return request(`/api/account/qrcode/${key}/check`, { - method: 'GET', - }); - } - - /** - * 二维码登录 - * @param input 登录参数 - * @returns 用户token - */ - async function loginApi(input: QrCodeTokenRequest) { - const { audience, clientId, clientSecret } = useAppConfig( - import.meta.env, - import.meta.env.PROD, - ); - const result = await request('/connect/token', { - data: { - client_id: clientId, - client_secret: clientSecret, - grant_type: 'qr_code', - qrcode_key: input.key, - scope: audience, - tenant_id: input.tenantId, - }, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - }); - return { - accessToken: result.access_token, - expiresIn: result.expires_in, - refreshToken: result.refresh_token, - tokenType: result.token_type, - }; - } - - return { - cancel, - checkCodeApi, - generateApi, - loginApi, - }; -} diff --git a/apps/vben5/packages/@abp/account/src/api/useScanQrCodeApi.ts b/apps/vben5/packages/@abp/account/src/api/useScanQrCodeApi.ts new file mode 100644 index 000000000..c28fff84b --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/api/useScanQrCodeApi.ts @@ -0,0 +1,37 @@ +import type { + GenerateQrCodeResult, + QrCodeUserInfoResult, +} from '../types/qrcode'; + +import { useRequest } from '@abp/request'; + +export function useScanQrCodeApi() { + const { cancel, request } = useRequest(); + + /** + * 生成登录二维码 + * @returns 二维码信息 + */ + function generateApi(): Promise { + return request('/api/account/qrcode/generate', { + method: 'POST', + }); + } + + /** + * 检查二维码状态 + * @param key 二维码Key + * @returns 二维码信息 + */ + function checkCodeApi(key: string): Promise { + return request(`/api/account/qrcode/${key}/check`, { + method: 'GET', + }); + } + + return { + cancel, + checkCodeApi, + generateApi, + }; +} diff --git a/apps/vben5/packages/@abp/account/src/api/useTokenApi.ts b/apps/vben5/packages/@abp/account/src/api/useTokenApi.ts deleted file mode 100644 index e41e84c10..000000000 --- a/apps/vben5/packages/@abp/account/src/api/useTokenApi.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { - OAuthTokenRefreshModel, - OAuthTokenResult, - PasswordTokenRequestModel, - TokenResult, -} from '../types'; - -import { useAppConfig } from '@vben/hooks'; - -import { useRequest } from '@abp/request'; - -export function useTokenApi() { - const { cancel, request } = useRequest(); - /** - * 用户登录 - * @param input 参数 - * @returns 用户token - */ - async function loginApi( - input: PasswordTokenRequestModel, - ): Promise { - const { audience, clientId, clientSecret } = useAppConfig( - import.meta.env, - import.meta.env.PROD, - ); - const result = await request('/connect/token', { - data: { - client_id: clientId, - client_secret: clientSecret, - grant_type: 'password', - scope: audience, - ...input, - }, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - }); - return { - accessToken: result.access_token, - expiresIn: result.expires_in, - refreshToken: result.refresh_token, - tokenType: result.token_type, - }; - } - - /** - * 刷新令牌 - * @param input 参数 - * @returns 用户token - */ - async function refreshTokenApi(input: OAuthTokenRefreshModel) { - const { audience, clientId, clientSecret } = useAppConfig( - import.meta.env, - import.meta.env.PROD, - ); - const result = await request('/connect/token', { - data: { - client_id: clientId, - client_secret: clientSecret, - grant_type: 'refresh_token', - refresh_token: input.refreshToken, - scope: audience, - }, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - }); - return { - accessToken: result.access_token, - expiresIn: result.expires_in, - refreshToken: result.refresh_token, - tokenType: result.token_type, - }; - } - - return { - cancel, - loginApi, - refreshTokenApi, - }; -} diff --git a/apps/vben5/packages/@abp/account/src/api/useUserInfoApi.ts b/apps/vben5/packages/@abp/account/src/api/useUserInfoApi.ts deleted file mode 100644 index aa7c5adb3..000000000 --- a/apps/vben5/packages/@abp/account/src/api/useUserInfoApi.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { OAuthUserInfo, UserInfo } from '../types/user'; - -import { useRequest } from '@abp/request'; - -export function useUserInfoApi() { - const { cancel, request } = useRequest(); - - /** - * 获取用户信息 - */ - async function getUserInfoApi(): Promise { - const result = await request('/connect/userinfo', { - method: 'GET', - }); - return { - ...result, - emailVerified: result.email_verified, - givenName: result.given_name, - phoneNumberVerified: result.phone_number_verified, - preferredUsername: result.preferred_username, - uniqueName: result.unique_name, - }; - } - - return { - cancel, - getUserInfoApi, - }; -} diff --git a/apps/vben5/packages/@abp/account/src/components/MySetting.vue b/apps/vben5/packages/@abp/account/src/components/MySetting.vue index ee412c254..848cf6630 100644 --- a/apps/vben5/packages/@abp/account/src/components/MySetting.vue +++ b/apps/vben5/packages/@abp/account/src/components/MySetting.vue @@ -1,8 +1,9 @@ - + + + + + + {{ button.title }} + + + + + diff --git a/apps/vben5/packages/@abp/account/src/components/components/SecuritySettings.vue b/apps/vben5/packages/@abp/account/src/components/components/SecuritySettings.vue index 65ac3940b..ce65c2368 100644 --- a/apps/vben5/packages/@abp/account/src/components/components/SecuritySettings.vue +++ b/apps/vben5/packages/@abp/account/src/components/components/SecuritySettings.vue @@ -86,13 +86,8 @@ onMounted(onGet); - - {{ - $t('abp.account.settings.security.password') - }} - - + :title="$t('abp.account.settings.security.password')" + /> diff --git a/apps/vben5/packages/@abp/account/src/hooks/index.ts b/apps/vben5/packages/@abp/account/src/hooks/index.ts index 25bce3f27..556dbb37b 100644 --- a/apps/vben5/packages/@abp/account/src/hooks/index.ts +++ b/apps/vben5/packages/@abp/account/src/hooks/index.ts @@ -1,2 +1,2 @@ export * from './useOAuthError'; -export * from './useOidcClient'; +export * from './useOAuthService'; diff --git a/apps/vben5/packages/@abp/account/src/hooks/useOAuthError.ts b/apps/vben5/packages/@abp/account/src/hooks/useOAuthError.ts index 972f8274d..a1e821002 100644 --- a/apps/vben5/packages/@abp/account/src/hooks/useOAuthError.ts +++ b/apps/vben5/packages/@abp/account/src/hooks/useOAuthError.ts @@ -23,7 +23,8 @@ export function useOAuthError() { return $t('abp.oauth.errors.requiresTwoFactor'); } // Token已失效 - case 'The token is no longer valid.': { + case 'The token is no longer valid.': + case 'The user is no longer allowed to sign in.': { return $t('abp.oauth.errors.tokenHasExpired'); } // 用户尝试登录次数太多,用户被锁定 diff --git a/apps/vben5/packages/@abp/account/src/hooks/useOidcClient.ts b/apps/vben5/packages/@abp/account/src/hooks/useOAuthService.ts similarity index 53% rename from apps/vben5/packages/@abp/account/src/hooks/useOidcClient.ts rename to apps/vben5/packages/@abp/account/src/hooks/useOAuthService.ts index f4090b44e..92e064aeb 100644 --- a/apps/vben5/packages/@abp/account/src/hooks/useOidcClient.ts +++ b/apps/vben5/packages/@abp/account/src/hooks/useOAuthService.ts @@ -1,14 +1,36 @@ +import type { + PasswordTokenRequestModel, + PhoneNumberTokenRequest, + QrCodeTokenRequest, +} from '../types/token'; + import { userManager } from '../utils/auth'; -export function useOidcClient() { +export function useOAuthService() { async function login() { return userManager.signinRedirect(); } + async function loginByPassword(input: PasswordTokenRequestModel) { + return userManager.signinResourceOwnerCredentials(input); + } + + async function loginBySmsCode(input: PhoneNumberTokenRequest) { + return userManager.signinSmsCode(input); + } + + async function loginByQrCode(input: QrCodeTokenRequest) { + return userManager.signinQrCode(input); + } + async function logout() { return userManager.signoutRedirect(); } + async function revokeTokens() { + return userManager.revokeTokens(['access_token', 'refresh_token']); + } + async function refreshToken() { return userManager.signinSilent(); } @@ -33,8 +55,12 @@ export function useOidcClient() { return { login, + loginByPassword, + loginBySmsCode, + loginByQrCode, logout, refreshToken, + revokeTokens, getAccessToken, isAuthenticated, handleCallback, diff --git a/apps/vben5/packages/@abp/account/src/types/bind.ts b/apps/vben5/packages/@abp/account/src/types/bind.ts new file mode 100644 index 000000000..b85215d3d --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/types/bind.ts @@ -0,0 +1,17 @@ +import type { ButtonType } from 'ant-design-vue/lib/button'; + +interface BindButton { + click: () => Promise | void; + title: string; + type?: ButtonType; +} + +interface BindItem { + buttons?: BindButton[]; + description?: string; + enable?: boolean; + slot?: string; + title: string; +} + +export type { BindItem }; diff --git a/apps/vben5/packages/@abp/account/src/types/external-logins.ts b/apps/vben5/packages/@abp/account/src/types/external-logins.ts new file mode 100644 index 000000000..2d8ce8587 --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/types/external-logins.ts @@ -0,0 +1,32 @@ +interface UserLoginInfoDto { + loginProvider: string; + providerDisplayName: string; + providerKey: string; +} + +interface ExternalLoginInfoDto { + displayName: string; + name: string; +} + +interface WorkWeixinLoginBindInput { + code: string; +} + +interface ExternalLoginResultDto { + externalLogins: ExternalLoginInfoDto[]; + userLogins: UserLoginInfoDto[]; +} + +interface RemoveExternalLoginInput { + loginProvider: string; + providerKey: string; +} + +export type { + ExternalLoginInfoDto, + ExternalLoginResultDto, + RemoveExternalLoginInput, + UserLoginInfoDto, + WorkWeixinLoginBindInput, +}; diff --git a/apps/vben5/packages/@abp/account/src/types/index.ts b/apps/vben5/packages/@abp/account/src/types/index.ts index 1dd5f3324..0f182a66b 100644 --- a/apps/vben5/packages/@abp/account/src/types/index.ts +++ b/apps/vben5/packages/@abp/account/src/types/index.ts @@ -1,4 +1,6 @@ export * from './account'; +export * from './bind'; +export * from './external-logins'; export * from './profile'; export * from './token'; export * from './user'; diff --git a/apps/vben5/packages/@abp/account/src/types/token.ts b/apps/vben5/packages/@abp/account/src/types/token.ts index 78df62c18..653b5cde8 100644 --- a/apps/vben5/packages/@abp/account/src/types/token.ts +++ b/apps/vben5/packages/@abp/account/src/types/token.ts @@ -16,6 +16,7 @@ interface PasswordTokenRequest extends TokenRequest { } /** 手机号授权请求数据模型 */ interface PhoneNumberTokenRequest { + [key: string]: any; /** 验证码 */ code: string; /** 手机号 */ @@ -23,6 +24,7 @@ interface PhoneNumberTokenRequest { } /** 扫码登录授权请求数据模型 */ interface QrCodeTokenRequest { + [key: string]: any; /** 二维码Key */ key: string; /** 租户Id */ @@ -30,11 +32,19 @@ interface QrCodeTokenRequest { } /** 用户密码授权请求数据模型 */ interface PasswordTokenRequestModel { + [key: string]: any; /** 用户密码 */ password: string; /** 用户名 */ username: string; } +/** 令牌撤销请求数据类型 */ +interface RevokeTokenRequest { + /** 令牌 */ + token: string; + /** 令牌类型 */ + tokenType?: 'access_token' | 'refresh_token'; +} /** 令牌返回数据模型 */ interface TokenResult { /** 访问令牌 */ @@ -89,6 +99,7 @@ export type { PasswordTokenRequestModel, PhoneNumberTokenRequest, QrCodeTokenRequest, + RevokeTokenRequest, ShouldChangePasswordError, TokenRequest, TokenResult, diff --git a/apps/vben5/packages/@abp/account/src/utils/auth.ts b/apps/vben5/packages/@abp/account/src/utils/auth.ts index 30a7d616f..39260906b 100644 --- a/apps/vben5/packages/@abp/account/src/utils/auth.ts +++ b/apps/vben5/packages/@abp/account/src/utils/auth.ts @@ -1,8 +1,137 @@ +import type { Logger, UserManagerSettings } from 'oidc-client-ts'; + +import type { + PasswordTokenRequestModel, + PhoneNumberTokenRequest, + QrCodeTokenRequest, +} from '../types/token'; + import { useAppConfig } from '@vben/hooks'; -import { UserManager, WebStorageStateStore } from 'oidc-client-ts'; +import { useRequest } from '@abp/request'; +import { + SigninResponse, + UserManager, + WebStorageStateStore, +} from 'oidc-client-ts'; import SecureLS from 'secure-ls'; +class AbpUserManager extends UserManager { + async _fetchUser(logger: Logger, body: URLSearchParams) { + const { request } = useRequest(); + const url = await this.metadataService.getTokenEndpoint(false); + if (!this.settings.omitScopeWhenRequesting) { + body.set('scope', this.settings.scope); + } + const resp = await request(url, { + data: body, + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }); + logger.debug('got signin response'); + const response = new SigninResponse(new URLSearchParams()); + Object.assign(response, resp); + const user = await this._buildUser(response); + if (user.profile && user.profile.sub) { + logger.info('success, signed in subject', user.profile.sub); + } else { + logger.info('no subject'); + } + return user; + } + + _writeChangePasswordToken( + params: URLSearchParams, + model: Record, + ) { + if (model.ChangePasswordToken) { + params.set('ChangePasswordToken', model.ChangePasswordToken); + } + if (model.NewPassword) { + params.set('NewPassword', model.NewPassword); + } + } + _writeTenantId(params: URLSearchParams, model: Record) { + if (model.tenantId) { + params.set('tenantId', model.tenantId); + } + } + _writeTwoFactorToken(params: URLSearchParams, model: Record) { + if (model.TwoFactorProvider) { + params.set('TwoFactorProvider', model.TwoFactorProvider); + } + if (model.TwoFactorCode) { + params.set('TwoFactorCode', model.TwoFactorCode); + } + } + _writeUserId(params: URLSearchParams, model: Record) { + if (model.userId) { + params.set('userId', model.userId); + } + } + async signinQrCode(params: QrCodeTokenRequest) { + const logger = this._logger.create('signinQrCode'); + const client_secret = this.settings.client_secret; + if (!client_secret) { + logger.error('A client_id is required'); + throw new Error('A client_id is required'); + } + const body = new URLSearchParams({ + key: params.key, + grant_type: 'qr_code', + client_id: this.settings.client_id, + client_secret, + }); + this._writeUserId(body, params); + this._writeTenantId(body, params); + this._writeTwoFactorToken(body, params); + return await this._fetchUser(logger, body); + } + + override async signinResourceOwnerCredentials( + params: PasswordTokenRequestModel, + ) { + const logger = this._logger.create('signinResourceOwnerCredentials'); + const client_secret = this.settings.client_secret; + if (!client_secret) { + logger.error('A client_id is required'); + throw new Error('A client_id is required'); + } + const body = new URLSearchParams({ + username: params.username, + password: params.password, + grant_type: 'password', + client_id: this.settings.client_id, + client_secret, + }); + this._writeUserId(body, params); + this._writeTwoFactorToken(body, params); + this._writeChangePasswordToken(body, params); + return await this._fetchUser(logger, body); + } + + async signinSmsCode(params: PhoneNumberTokenRequest) { + const logger = this._logger.create('signinSmsCode'); + const client_secret = this.settings.client_secret; + if (!client_secret) { + logger.error('A client_id is required'); + throw new Error('A client_id is required'); + } + const body = new URLSearchParams({ + phone_number: params.phoneNumber, + phone_verify_code: params.code, + grant_type: 'phone_verify', + client_id: this.settings.client_id, + client_secret, + }); + this._writeUserId(body, params); + this._writeTwoFactorToken(body, params); + return await this._fetchUser(logger, body); + } +} + const { authority, audience, clientId, clientSecret, disablePKCE } = useAppConfig(import.meta.env, import.meta.env.PROD); @@ -17,7 +146,7 @@ const ls = new SecureLS({ // @ts-ignore secure-ls does not have a type definition for this metaKey: `${namespace}-secure-oidc`, }); -export const userManager = new UserManager({ +const oidcSettings: UserManagerSettings = { authority, client_id: clientId, client_secret: clientSecret, @@ -50,4 +179,7 @@ export const userManager = new UserManager({ }, }), disablePKCE, -}); +}; +const userManager = new AbpUserManager(oidcSettings); + +export { oidcSettings, userManager }; diff --git a/apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingDrawer.vue b/apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingDrawer.vue index 616b5568d..577a59d4e 100644 --- a/apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingDrawer.vue +++ b/apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingDrawer.vue @@ -1,5 +1,7 @@ + + + + + + + + + + + + + + + {{ $t('workbench.header.notifier.title') }} + + {{ + $t('workbench.header.notifier.count', [notifierCount]) + }} + + + + diff --git a/apps/vben5/packages/@abp/platform/src/components/workbench/components/WorkbenchQuickNav.vue b/apps/vben5/packages/@abp/platform/src/components/workbench/components/WorkbenchQuickNav.vue new file mode 100644 index 000000000..8479356db --- /dev/null +++ b/apps/vben5/packages/@abp/platform/src/components/workbench/components/WorkbenchQuickNav.vue @@ -0,0 +1,124 @@ + + + + + + {{ title }} + + + + + + + {{ item.displayName }} + + + onMenuClick(menuKey.toString(), item) + " + > + + {{ $t('workbench.content.favoriteMenu.delete') }} + + + + + + + + + + diff --git a/apps/vben5/packages/@abp/platform/src/components/workbench/components/WorkbenchQuickNavModal.vue b/apps/vben5/packages/@abp/platform/src/components/workbench/components/WorkbenchQuickNavModal.vue new file mode 100644 index 000000000..3bd56cc3e --- /dev/null +++ b/apps/vben5/packages/@abp/platform/src/components/workbench/components/WorkbenchQuickNavModal.vue @@ -0,0 +1,137 @@ + + + + + + + + + ({{ slotProps.value }}) + + + + + + + + {{ item.displayName }} + + + + + + + + + diff --git a/apps/vben5/packages/@abp/platform/src/components/workbench/components/WorkbenchTodo.vue b/apps/vben5/packages/@abp/platform/src/components/workbench/components/WorkbenchTodo.vue new file mode 100644 index 000000000..8751f8b79 --- /dev/null +++ b/apps/vben5/packages/@abp/platform/src/components/workbench/components/WorkbenchTodo.vue @@ -0,0 +1,64 @@ + + + + + + {{ title }} + + + + + + + + + + {{ item.title }} + + + + + + + + {{ item.date }} + + + + + + + diff --git a/apps/vben5/packages/@abp/platform/src/components/workbench/components/WorkbenchTrends.vue b/apps/vben5/packages/@abp/platform/src/components/workbench/components/WorkbenchTrends.vue new file mode 100644 index 000000000..48267cdb4 --- /dev/null +++ b/apps/vben5/packages/@abp/platform/src/components/workbench/components/WorkbenchTrends.vue @@ -0,0 +1,65 @@ + + + + + + {{ title }} + + + + + + + + + + {{ item.title }} + + + + + + + + {{ item.date }} + + + + + + + diff --git a/apps/vben5/packages/@abp/platform/src/components/workbench/index.vue b/apps/vben5/packages/@abp/platform/src/components/workbench/index.vue new file mode 100644 index 000000000..d531d34c2 --- /dev/null +++ b/apps/vben5/packages/@abp/platform/src/components/workbench/index.vue @@ -0,0 +1,218 @@ + + + + + + + {{ getWelcomeTitle }} + + 今日晴,20℃ - 32℃! + + + + + $emit('navTo', menu)" + /> + + + + + + + + + + + + + + + + + + + diff --git a/apps/vben5/packages/@abp/platform/src/components/workbench/types.ts b/apps/vben5/packages/@abp/platform/src/components/workbench/types.ts new file mode 100644 index 000000000..13dea780f --- /dev/null +++ b/apps/vben5/packages/@abp/platform/src/components/workbench/types.ts @@ -0,0 +1,10 @@ +interface FavoriteMenu { + color?: string; + displayName: string; + icon?: string; + id: string; + isDefault: boolean; + path?: string; +} + +export type { FavoriteMenu }; diff --git a/apps/vben5/packages/@abp/platform/src/index.ts b/apps/vben5/packages/@abp/platform/src/index.ts index 14fa9fe25..ca7a7275a 100644 --- a/apps/vben5/packages/@abp/platform/src/index.ts +++ b/apps/vben5/packages/@abp/platform/src/index.ts @@ -1,4 +1,5 @@ export * from './api'; export * from './components'; export * from './hooks'; +export * from './locales'; export * from './types'; diff --git a/apps/vben5/packages/@abp/platform/src/locales/index.ts b/apps/vben5/packages/@abp/platform/src/locales/index.ts new file mode 100644 index 000000000..ccf0b963b --- /dev/null +++ b/apps/vben5/packages/@abp/platform/src/locales/index.ts @@ -0,0 +1,20 @@ +import type { SupportedLanguagesType } from '@vben/locales'; + +import { loadLocalesMapFromDir } from '@vben/locales'; + +const modules = import.meta.glob('./langs/**/*.json'); + +const localesMap = loadLocalesMapFromDir( + /\.\/langs\/([^/]+)\/(.*)\.json$/, + modules, +); + +/** + * 加载平台服务本地化资源 + * @param lang 当前语言 + * @returns 资源集合 + */ +export async function loadPaltformMessages(lang: SupportedLanguagesType) { + const locales = localesMap[lang]?.(); + return locales; +} diff --git a/apps/vben5/packages/@abp/platform/src/locales/langs/en-US/workbench.json b/apps/vben5/packages/@abp/platform/src/locales/langs/en-US/workbench.json new file mode 100644 index 000000000..63034d52b --- /dev/null +++ b/apps/vben5/packages/@abp/platform/src/locales/langs/en-US/workbench.json @@ -0,0 +1,37 @@ +{ + "header": { + "welcome": { + "atoon": "Good afternoon, {0}, pay attention to rest oh~", + "afternoon": "Good afternoon, {0}, relax in time, can improve work efficiency~", + "evening": "Good evening, {0}. Still at work? The off work~", + "morning": "Good morning, {0}. Begin your day~" + }, + "notifier": { + "title": "Notifier", + "count": "({0})" + } + }, + "content": { + "favoriteMenu": { + "title": "Favorite Menus", + "home": "Home", + "dashboard": "Dashboard", + "profile": "Personal Profile", + "settings": "Personal Settings", + "notifiers": "Notifiers", + "manage": "Manage menu", + "create": "New menu", + "delete": "Delete Menu", + "select": "Select Menu", + "color": "Select Color", + "alias": "Alias Name", + "icon": "Icon" + }, + "trends": { + "title": "Latest News" + }, + "todo": { + "title": "Todo List" + } + } +} diff --git a/apps/vben5/packages/@abp/platform/src/locales/langs/zh-CN/workbench.json b/apps/vben5/packages/@abp/platform/src/locales/langs/zh-CN/workbench.json new file mode 100644 index 000000000..c2561e71d --- /dev/null +++ b/apps/vben5/packages/@abp/platform/src/locales/langs/zh-CN/workbench.json @@ -0,0 +1,37 @@ +{ + "header": { + "welcome": { + "atoon": "中午好, {0}, 注意休息哦~", + "afternoon": "下午好, {0}, 适时放松,可以提高工作效率~", + "evening": "晚上好, {0}, 还在工作么?该下班了~", + "morning": "早安, {0}, 开始您一天的工作吧~" + }, + "notifier": { + "title": "通知", + "count": "({0})" + } + }, + "content": { + "favoriteMenu": { + "title": "常用", + "home": "首页", + "dashboard": "仪表盘", + "profile": "个人中心", + "settings": "个人设置", + "notifiers": "通知消息", + "manage": "管理菜单", + "create": "添加菜单", + "delete": "删除菜单", + "select": "选择菜单", + "color": "选择颜色", + "alias": "自定义别名", + "icon": "自定义图标" + }, + "trends": { + "title": "最新消息" + }, + "todo": { + "title": "待办事项" + } + } +} diff --git a/apps/vben5/packages/@abp/platform/src/types/favorites.ts b/apps/vben5/packages/@abp/platform/src/types/favorites.ts new file mode 100644 index 000000000..221f13f48 --- /dev/null +++ b/apps/vben5/packages/@abp/platform/src/types/favorites.ts @@ -0,0 +1,34 @@ +import type { AuditedEntityDto, IHasConcurrencyStamp } from '@abp/core'; + +interface UserFavoriteMenuDto extends AuditedEntityDto { + aliasName?: string; + color?: string; + displayName: string; + framework: string; + icon?: string; + menuId: string; + name: string; + path?: string; + userId: string; +} + +interface UserFavoriteMenuCreateOrUpdateDto { + aliasName?: string; + color?: string; + icon?: string; + menuId: string; +} + +interface UserFavoriteMenuCreateDto extends UserFavoriteMenuCreateOrUpdateDto { + framework: string; +} + +interface UserFavoriteMenuUpdateDto + extends IHasConcurrencyStamp, + UserFavoriteMenuCreateOrUpdateDto {} + +export type { + UserFavoriteMenuCreateDto, + UserFavoriteMenuDto, + UserFavoriteMenuUpdateDto, +}; diff --git a/apps/vben5/packages/@abp/platform/src/types/index.ts b/apps/vben5/packages/@abp/platform/src/types/index.ts index 73954c6db..3277e6293 100644 --- a/apps/vben5/packages/@abp/platform/src/types/index.ts +++ b/apps/vben5/packages/@abp/platform/src/types/index.ts @@ -1,4 +1,5 @@ export * from './dataDictionaries'; +export * from './favorites'; export * from './layouts'; export * from './menus'; export * from './messages'; diff --git a/apps/vben5/packages/@abp/settings/src/components/index.ts b/apps/vben5/packages/@abp/settings/src/components/index.ts index aaa211b75..53dbe96f7 100644 --- a/apps/vben5/packages/@abp/settings/src/components/index.ts +++ b/apps/vben5/packages/@abp/settings/src/components/index.ts @@ -1,3 +1,4 @@ export { default as SettingDefinitionTable } from './definitions/SettingDefinitionTable.vue'; +export { default as SettingForm } from './settings/SettingForm.vue'; export { default as SystemSetting } from './settings/SystemSetting.vue'; export { default as UserSetting } from './settings/UserSetting.vue'; diff --git a/apps/vben5/packages/@abp/settings/src/components/settings/SettingForm.vue b/apps/vben5/packages/@abp/settings/src/components/settings/SettingForm.vue index 4849331c9..2caa47d4f 100644 --- a/apps/vben5/packages/@abp/settings/src/components/settings/SettingForm.vue +++ b/apps/vben5/packages/@abp/settings/src/components/settings/SettingForm.vue @@ -71,7 +71,7 @@ async function onSubmit() { const input = toValue(settingsUpdateInput); await props.submitApi(input); emits('change', input); - message.success($t('AbpSettingManagement.SuccessfullySaved')); + message.success($t('AbpSettingManagement.SavedSuccessfully')); } finally { submiting.value = false; } @@ -142,8 +142,8 @@ onMounted(onGet); v-if="detail.slot" :change=" detail.valueType === ValueType.Boolean - ? onCheckChange(detail) - : onValueChange(detail) + ? onCheckChange + : onValueChange " :detail="detail" :name="detail.slot" diff --git a/apps/vben5/packages/@abp/tasks/src/components/job-infos/JobInfoDrawer.vue b/apps/vben5/packages/@abp/tasks/src/components/job-infos/JobInfoDrawer.vue index c33b9c114..715ffb614 100644 --- a/apps/vben5/packages/@abp/tasks/src/components/job-infos/JobInfoDrawer.vue +++ b/apps/vben5/packages/@abp/tasks/src/components/job-infos/JobInfoDrawer.vue @@ -94,6 +94,7 @@ const [Drawer, drawerApi] = useVbenDrawer({ if (isOpen) { try { formModel.value = { + args: {}, beginTime: formatToDate(new Date()), isEnabled: true, jobType: JobType.Once, diff --git a/apps/vben5/packages/@abp/ui/src/components/vxe-table/use-vxe-grid.ts b/apps/vben5/packages/@abp/ui/src/components/vxe-table/use-vxe-grid.ts index a309f5ac4..b15435ed1 100644 --- a/apps/vben5/packages/@abp/ui/src/components/vxe-table/use-vxe-grid.ts +++ b/apps/vben5/packages/@abp/ui/src/components/vxe-table/use-vxe-grid.ts @@ -24,8 +24,8 @@ export function useVbenVxeGrid(options: VxeGridProps) { return () => h(VxeGrid, { ...props, ...attrs, api: extendedApi }, slots); }, { - inheritAttrs: false, name: 'VbenVxeGrid', + inheritAttrs: false, }, ); // Add reactivity support diff --git a/apps/vben5/packages/@abp/ui/src/components/vxe-table/use-vxe-grid.vue b/apps/vben5/packages/@abp/ui/src/components/vxe-table/use-vxe-grid.vue index 6eaa3fa39..4b27cbf2d 100644 --- a/apps/vben5/packages/@abp/ui/src/components/vxe-table/use-vxe-grid.vue +++ b/apps/vben5/packages/@abp/ui/src/components/vxe-table/use-vxe-grid.vue @@ -249,7 +249,7 @@ async function init() { const enableProxyConfig = options.value.proxyConfig?.enabled; if (enableProxyConfig && autoLoad) { props.api.grid.commitProxy?.( - '_init', + 'initial', formOptions.value ? ((await formApi.getValues()) ?? {}) : {}, ); // props.api.reload(formApi.form?.values ?? {}); diff --git a/apps/vben5/packages/@abp/wechat/package.json b/apps/vben5/packages/@abp/wechat/package.json new file mode 100644 index 000000000..28d20c24a --- /dev/null +++ b/apps/vben5/packages/@abp/wechat/package.json @@ -0,0 +1,40 @@ +{ + "name": "@abp/wechat", + "version": "9.2.0", + "homepage": "https://github.com/colinin/abp-next-admin", + "bugs": "https://github.com/colinin/abp-next-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/colinin/abp-next-admin.git", + "directory": "packages/@abp/wechat" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "dependencies": { + "@abp/core": "workspace:*", + "@abp/features": "workspace:*", + "@abp/request": "workspace:*", + "@abp/settings": "workspace:*", + "@abp/ui": "workspace:*", + "@ant-design/icons-vue": "catalog:", + "@vben/access": "workspace:*", + "@vben/common-ui": "workspace:*", + "@vben/hooks": "workspace:*", + "@vben/icons": "workspace:*", + "@vben/layouts": "workspace:*", + "@vben/locales": "workspace:*", + "@wecom/jssdk": "catalog:", + "ant-design-vue": "catalog:", + "dayjs": "catalog:", + "vue": "catalog:*" + } +} diff --git a/apps/vben5/packages/@abp/wechat/src/api/index.ts b/apps/vben5/packages/@abp/wechat/src/api/index.ts new file mode 100644 index 000000000..745447658 --- /dev/null +++ b/apps/vben5/packages/@abp/wechat/src/api/index.ts @@ -0,0 +1,2 @@ +export { userWorkWeixinJsSdkApi } from './userWorkWeixinJsSdkApi'; +export { useWechatSettingsApi } from './useWechatSettingsApi'; diff --git a/apps/vben5/packages/@abp/wechat/src/api/useWechatSettingsApi.ts b/apps/vben5/packages/@abp/wechat/src/api/useWechatSettingsApi.ts new file mode 100644 index 000000000..9f9aa2a19 --- /dev/null +++ b/apps/vben5/packages/@abp/wechat/src/api/useWechatSettingsApi.ts @@ -0,0 +1,40 @@ +import type { ListResultDto } from '@abp/core'; +import type { SettingGroup } from '@abp/settings'; + +import { useRequest } from '@abp/request'; + +export function useWechatSettingsApi() { + const { cancel, request } = useRequest(); + + /** + * 获取全局设置 + * @returns 设置数据传输对象列表 + */ + function getGlobalSettingsApi(): Promise> { + return request>( + `/api/wechat/setting-management/by-global`, + { + method: 'GET', + }, + ); + } + + /** + * 获取租户设置 + * @returns 设置数据传输对象列表 + */ + function getTenantSettingsApi(): Promise> { + return request>( + `/api/wechat/setting-management/by-current-tenant`, + { + method: 'GET', + }, + ); + } + + return { + cancel, + getGlobalSettingsApi, + getTenantSettingsApi, + }; +} diff --git a/apps/vben5/packages/@abp/wechat/src/api/userWorkWeixinJsSdkApi.ts b/apps/vben5/packages/@abp/wechat/src/api/userWorkWeixinJsSdkApi.ts new file mode 100644 index 000000000..804fa7105 --- /dev/null +++ b/apps/vben5/packages/@abp/wechat/src/api/userWorkWeixinJsSdkApi.ts @@ -0,0 +1,22 @@ +import type { AgentConfigDto } from '../types/js-sdk'; + +import { useRequest } from '@abp/request'; + +export function userWorkWeixinJsSdkApi() { + const { cancel, request } = useRequest(); + + /** + * 获取企业微信应用配置 + * @returns 企业微信应用配置Dto + */ + function getAgentConfigApi(): Promise { + return request(`/api/wechat/work/jssdk/agent-config`, { + method: 'GET', + }); + } + + return { + cancel, + getAgentConfigApi, + }; +} diff --git a/apps/vben5/packages/@abp/wechat/src/components/bind-user/index.vue b/apps/vben5/packages/@abp/wechat/src/components/bind-user/index.vue new file mode 100644 index 000000000..e752a0700 --- /dev/null +++ b/apps/vben5/packages/@abp/wechat/src/components/bind-user/index.vue @@ -0,0 +1,62 @@ + + + + + + + + + diff --git a/apps/vben5/packages/@abp/wechat/src/components/index.ts b/apps/vben5/packages/@abp/wechat/src/components/index.ts new file mode 100644 index 000000000..8e84134b5 --- /dev/null +++ b/apps/vben5/packages/@abp/wechat/src/components/index.ts @@ -0,0 +1,2 @@ +export { default as WechatWorkUserBinder } from './bind-user/index.vue'; +export { default as WechatSettings } from './settings/index.vue'; diff --git a/apps/vben5/packages/@abp/wechat/src/components/settings/index.vue b/apps/vben5/packages/@abp/wechat/src/components/settings/index.vue new file mode 100644 index 000000000..e1f3e30a6 --- /dev/null +++ b/apps/vben5/packages/@abp/wechat/src/components/settings/index.vue @@ -0,0 +1,37 @@ + + + + + + + diff --git a/apps/vben5/packages/@abp/wechat/src/index.ts b/apps/vben5/packages/@abp/wechat/src/index.ts new file mode 100644 index 000000000..0ef464305 --- /dev/null +++ b/apps/vben5/packages/@abp/wechat/src/index.ts @@ -0,0 +1,2 @@ +export * from './api'; +export * from './components'; diff --git a/apps/vben5/packages/@abp/wechat/src/types/js-sdk.ts b/apps/vben5/packages/@abp/wechat/src/types/js-sdk.ts new file mode 100644 index 000000000..44031b6b5 --- /dev/null +++ b/apps/vben5/packages/@abp/wechat/src/types/js-sdk.ts @@ -0,0 +1,6 @@ +interface AgentConfigDto { + agentId: string; + corpId: string; +} + +export type { AgentConfigDto }; diff --git a/apps/vben5/packages/@abp/wechat/tsconfig.json b/apps/vben5/packages/@abp/wechat/tsconfig.json new file mode 100644 index 000000000..ce1a891fb --- /dev/null +++ b/apps/vben5/packages/@abp/wechat/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/apps/vben5/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue b/apps/vben5/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue index f3eb6735a..9844c409d 100644 --- a/apps/vben5/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue +++ b/apps/vben5/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue @@ -300,7 +300,7 @@ async function init() { const enableProxyConfig = options.value.proxyConfig?.enabled; if (enableProxyConfig && autoLoad) { props.api.grid.commitProxy?.( - '_init', + 'initial', formOptions.value ? ((await formApi.getValues()) ?? {}) : {}, ); // props.api.reload(formApi.form?.values ?? {}); diff --git a/apps/vben5/pnpm-workspace.yaml b/apps/vben5/pnpm-workspace.yaml index 4acb3954f..517e67b0e 100644 --- a/apps/vben5/pnpm-workspace.yaml +++ b/apps/vben5/pnpm-workspace.yaml @@ -73,6 +73,7 @@ catalog: '@vueuse/core': ^13.1.0 '@vueuse/integrations': ^13.1.0 '@vueuse/motion': ^3.0.3 + '@wecom/jssdk': ^2.3.1 ant-design-vue: ^4.2.6 archiver: ^7.0.1 autoprefixer: ^10.4.21 @@ -205,8 +206,9 @@ catalog: vue-simple-uploader: ^1.0.3 vue-tippy: ^6.7.0 vue-tsc: 2.2.10 - vxe-pc-ui: ^4.5.35 - vxe-table: ^4.13.16 + vue3-colorpicker: ^2.3.0 + vxe-pc-ui: ^4.7.12 + vxe-table: ^4.14.4 watermark-js-plus: ^1.6.0 zod: ^3.24.3 zod-defaults: ^0.1.3 diff --git a/aspnet-core/cleanup-logs.bat b/aspnet-core/cleanup-logs.bat index ef5471574..5ffd61025 100644 --- a/aspnet-core/cleanup-logs.bat +++ b/aspnet-core/cleanup-logs.bat @@ -4,12 +4,17 @@ chcp 65001 echo. 清理所有服务日志 +del .\services\LY.MicroService.Applications.Single\Logs /Q del .\services\LY.MicroService.BackendAdmin.HttpApi.Host\Logs /Q +del .\services\LY.MicroService.AuthServer\Logs /Q +del .\services\LY.MicroService.AuthServer.HttpApi.Host\Logs /Q del .\services\LY.MicroService.identityServer\Logs /Q del .\services\LY.MicroService.identityServer.HttpApi.Host\Logs /Q del .\services\LY.MicroService.LocalizationManagement.HttpApi.Host\Logs /Q del .\services\LY.MicroService.PlatformManagement.HttpApi.Host\Logs /Q del .\services\LY.MicroService.RealtimeMessage.HttpApi.Host\Logs /Q del .\services\LY.MicroService.TaskManagement.HttpApi.Host\Logs /Q +del .\services\LY.MicroService.WebhooksManagement.HttpApi.Host\Logs /Q +del .\services\LY.MicroService.WechatManagement.HttpApi.Host\Logs /Q del .\services\LY.MicroService.WorkflowManagement.HttpApi.Host\Logs /Q diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/FodyWeavers.xml b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN.Abp.AspNetCore.Auditing.csproj b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN.Abp.AspNetCore.Auditing.csproj new file mode 100644 index 000000000..4589f07e1 --- /dev/null +++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN.Abp.AspNetCore.Auditing.csproj @@ -0,0 +1,20 @@ + + + + + + + net9.0 + LINGYUN.Abp.AspNetCore.Auditing + LINGYUN.Abp.AspNetCore.Auditing + false + false + false + + + + + + + + diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN/Abp/AspNetCore/Auditing/AbpAspNetCoreAuditingHeaderOptions.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN/Abp/AspNetCore/Auditing/AbpAspNetCoreAuditingHeaderOptions.cs new file mode 100644 index 000000000..647ea909a --- /dev/null +++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN/Abp/AspNetCore/Auditing/AbpAspNetCoreAuditingHeaderOptions.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +namespace LINGYUN.Abp.AspNetCore.Auditing; +public class AbpAspNetCoreAuditingHeaderOptions +{ + /// + /// 是否在审计日志中记录Http请求头,默认: true + /// + public bool IsEnabled { get; set; } + /// + /// 要记录的Http请求头 + /// + public IList HttpHeaders { get; } + public AbpAspNetCoreAuditingHeaderOptions() + { + IsEnabled = true; + HttpHeaders = new List(); + } +} diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN/Abp/AspNetCore/Auditing/AbpAspNetCoreAuditingModule.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN/Abp/AspNetCore/Auditing/AbpAspNetCoreAuditingModule.cs new file mode 100644 index 000000000..119d69635 --- /dev/null +++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN/Abp/AspNetCore/Auditing/AbpAspNetCoreAuditingModule.cs @@ -0,0 +1,17 @@ +using Volo.Abp.AspNetCore; +using Volo.Abp.Auditing; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.AspNetCore.Auditing; + +[DependsOn(typeof(AbpAspNetCoreModule))] +public class AbpAspNetCoreAuditingModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.Contributors.Add(new AspNetCoreRecordHeaderAuditLogContributor()); + }); + } +} diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN/Abp/AspNetCore/Auditing/AspNetCoreRecordHeaderAuditLogContributor.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN/Abp/AspNetCore/Auditing/AspNetCoreRecordHeaderAuditLogContributor.cs new file mode 100644 index 000000000..67f4a59d3 --- /dev/null +++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN/Abp/AspNetCore/Auditing/AspNetCoreRecordHeaderAuditLogContributor.cs @@ -0,0 +1,51 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using System.Collections.Generic; +using System.Collections.Immutable; +using Volo.Abp.Auditing; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.AspNetCore.Auditing; +public class AspNetCoreRecordHeaderAuditLogContributor : AuditLogContributor, ITransientDependency +{ + private const string HttpHeaderRecordKey = "HttpHeaders"; + + public AspNetCoreRecordHeaderAuditLogContributor() + { + } + + public override void PreContribute(AuditLogContributionContext context) + { + var options = context.ServiceProvider.GetRequiredService>(); + if (!options.Value.IsEnabled) + { + return; + } + + var httpContext = context.ServiceProvider.GetRequiredService().HttpContext; + if (httpContext == null) + { + return; + } + + if (context.AuditInfo.HasProperty(HttpHeaderRecordKey)) + { + return; + } + + var headerRcords = new Dictionary(); + var httpHeaders = httpContext.Request.Headers.ToImmutableDictionary(); + + foreach (var headerKey in options.Value.HttpHeaders) + { + if (httpHeaders.TryGetValue(headerKey, out var headers)) + { + headerRcords[headerKey] = headers.JoinAsString(";"); + } + } + + context.AuditInfo.SetProperty(HttpHeaderRecordKey, headerRcords); + } +} diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/README.md b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/README.md new file mode 100644 index 000000000..de6175010 --- /dev/null +++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/README.md @@ -0,0 +1,19 @@ +# LINGYUN.Abp.AspNetCore.Auditing + +审计日期扩展模块, 用于在审计日志中加入特定的Http请求头记录 + +## 模块引用 + + +```csharp +[DependsOn(typeof(AbpAspNetCoreAuditingModule))] +public class YouProjectModule : AbpModule +{ + // other +} +``` + +## 配置项 + +* AbpAspNetCoreAuditingHeaderOptions.IsEnabled 是否在审计日志中记录Http请求头,默认: true +* AbpAspNetCoreAuditingHeaderOptions.HttpHeaders 需要在审计日志中记录的Http请求头列表 diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Sms.Tencent/LINGYUN/Abp/Sms/Tencent/TencentCloudSmsSender.cs b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Sms.Tencent/LINGYUN/Abp/Sms/Tencent/TencentCloudSmsSender.cs index 501283863..0ffa5d62d 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Sms.Tencent/LINGYUN/Abp/Sms/Tencent/TencentCloudSmsSender.cs +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Sms.Tencent/LINGYUN/Abp/Sms/Tencent/TencentCloudSmsSender.cs @@ -48,6 +48,9 @@ public class TencentCloudSmsSender : ISmsSender, ITransientDependency Check.NotNullOrWhiteSpace(appId, TencentCloudSettingNames.Sms.AppId); + // 短信模板相关参数 + List templateParams = ["TemplateCode", "SignName"]; + // 统一使用 TemplateCode作为模板参数, 解决不一样的sms提供商参数差异 if (!smsMessage.Properties.TryGetValue("TemplateCode", out var templateId)) { @@ -69,7 +72,8 @@ public class TencentCloudSmsSender : ISmsSender, ITransientDependency if (smsMessage.Properties.Any()) { - request.TemplateParamSet = smsMessage.Properties.Select(x => x.Value.ToString()).ToArray(); + // 去掉短信模板相关参数,只保留要用的变量 + request.TemplateParamSet = smsMessage.Properties.Where(x => !templateParams.Contains(x.Key)).Select(x => x.Value.ToString()).ToArray(); } var smsClient = await TencentCloudClientFactory.CreateAsync(); diff --git a/aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/AbpIP2RegionModule.cs b/aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/AbpIP2RegionModule.cs index ab95964e9..863470a46 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/AbpIP2RegionModule.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/AbpIP2RegionModule.cs @@ -29,7 +29,7 @@ public class AbpIP2RegionModule : AbpModule Configure(options => { - options.IPLocationResolvers.Add(new IP2RegionIPLocationResolveContributorBase()); + options.IPLocationResolvers.Add(new IP2RegionIPLocationResolveContributor()); }); } } diff --git a/aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/IP2RegionIPLocationResolveContributorBase.cs b/aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/IP2RegionIPLocationResolveContributor.cs similarity index 96% rename from aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/IP2RegionIPLocationResolveContributorBase.cs rename to aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/IP2RegionIPLocationResolveContributor.cs index 0cc4c2b44..4abb90200 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/IP2RegionIPLocationResolveContributorBase.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.IP2Region/LINGYUN/Abp/IP2Region/IP2RegionIPLocationResolveContributor.cs @@ -5,7 +5,7 @@ using System; using System.Threading.Tasks; namespace LINGYUN.Abp.IP2Region; -public class IP2RegionIPLocationResolveContributorBase : IPLocationResolveContributorBase +public class IP2RegionIPLocationResolveContributor : IPLocationResolveContributorBase { public const string ContributorName = "IP2Region"; public override string Name => ContributorName; diff --git a/aspnet-core/framework/dynamic-queryable/LINGYUN.Linq.Dynamic.Queryable/System/Linq/Expressions/ObjectQueryableExtensions.cs b/aspnet-core/framework/dynamic-queryable/LINGYUN.Linq.Dynamic.Queryable/System/Linq/Expressions/ObjectQueryableExtensions.cs index a7a2baeb6..b31c2bf9e 100644 --- a/aspnet-core/framework/dynamic-queryable/LINGYUN.Linq.Dynamic.Queryable/System/Linq/Expressions/ObjectQueryableExtensions.cs +++ b/aspnet-core/framework/dynamic-queryable/LINGYUN.Linq.Dynamic.Queryable/System/Linq/Expressions/ObjectQueryableExtensions.cs @@ -41,38 +41,30 @@ public static class ObjectQueryableExtensions // For example(MySql): // ...Other (Field <> Value) exp = Expression.NotEqual( - leftParamter, - Expression.Convert(Expression.Constant(paramter.Value), propertyType)); + leftParamter, + GetValue(paramter, propertyType)); break; case DynamicComparison.LessThan: // For example(MySql): // ...Other (Field < Value) - exp = Expression.LessThan( - leftParamter, - Expression.Convert(Expression.Constant(paramter.Value), propertyType)); + exp = BuildLessThanExpression(paramter, leftParamter, propertyType); break; case DynamicComparison.LessThanOrEqual: // For example(MySql): // ...Other (Field <= Value) - exp = Expression.LessThanOrEqual( - leftParamter, - Expression.Convert(Expression.Constant(paramter.Value), propertyType)); + exp = BuildLessThanOrEqualExpression(paramter, leftParamter, propertyType); break; case DynamicComparison.GreaterThan: // For example(MySql): // ...Other (Field > Value) - exp = Expression.GreaterThan( - leftParamter, - Expression.Convert(Expression.Constant(paramter.Value), propertyType)); + exp = BuildGreaterThanExpression(paramter, leftParamter, propertyType); break; case DynamicComparison.GreaterThanOrEqual: // For example(MySql): // ...Other (Field >= Value) - exp = Expression.GreaterThanOrEqual( - leftParamter, - Expression.Convert(Expression.Constant(paramter.Value), propertyType)); + exp = BuildGreaterThanOrEqualExpression(paramter, leftParamter, propertyType); break; case DynamicComparison.StartsWith: // For example(MySql): @@ -80,7 +72,7 @@ public static class ObjectQueryableExtensions exp = Expression.Call( leftParamter, typeof(string).GetMethod(nameof(String.StartsWith), new[] { typeof(string) }), - Expression.Convert(Expression.Constant(paramter.Value), propertyType)); + GetValue(paramter, propertyType)); // TODO: 单元测试通过 // For example(MySql): @@ -106,7 +98,7 @@ public static class ObjectQueryableExtensions Expression.Call( leftParamter, typeof(string).GetMethod(nameof(String.StartsWith), new[] { typeof(string) }), - Expression.Convert(Expression.Constant(paramter.Value), propertyType))); + GetValue(paramter, propertyType))); // TODO: 单元测试通过 // For example(MySql): @@ -129,7 +121,7 @@ public static class ObjectQueryableExtensions exp = Expression.Call( leftParamter, typeof(string).GetMethod(nameof(String.EndsWith), new[] { typeof(string) }), - Expression.Convert(Expression.Constant(paramter.Value), propertyType)); + GetValue(paramter, propertyType)); // TODO: 单元测试通过 // For example(MySql): @@ -153,7 +145,7 @@ public static class ObjectQueryableExtensions Expression.Call( leftParamter, typeof(string).GetMethod(nameof(String.EndsWith), new[] { typeof(string) }), - Expression.Convert(Expression.Constant(paramter.Value), propertyType))); + GetValue(paramter, propertyType))); // TODO: 单元测试通过 // For example(MySql): @@ -176,7 +168,7 @@ public static class ObjectQueryableExtensions exp = Expression.Call( leftParamter, typeof(string).GetMethod(nameof(String.Contains), new[] { typeof(string) }), - Expression.Convert(Expression.Constant(paramter.Value), propertyType)); + GetValue(paramter, propertyType)); // TODO: 单元测试通过 // For example(MySql): @@ -200,7 +192,7 @@ public static class ObjectQueryableExtensions Expression.Call( leftParamter, typeof(string).GetMethod(nameof(String.Contains), new[] { typeof(string) }), - Expression.Convert(Expression.Constant(paramter.Value), propertyType))); + GetValue(paramter, propertyType))); // TODO: 单元测试通过 // For example(MySql): // ...Other ((Field IS NULL) OR (Field NOT LIKE '%Value%')) @@ -223,16 +215,14 @@ public static class ObjectQueryableExtensions // 非空字段设定为比对默认值 exp = Expression.Equal(leftParamter, - Expression.Convert( - Expression.Constant(GetDefaultValue(propertyType)), propertyType)); + Expression.Constant(GetDefaultValue(propertyType))); break; case DynamicComparison.NotNull: // For example(MySql): // ...Other (Field IS NOT NULL) exp = Expression.NotEqual(leftParamter, - Expression.Convert( - Expression.Constant(GetDefaultValue(propertyType)), propertyType)); + Expression.Constant(GetDefaultValue(propertyType))); break; default: case DynamicComparison.Equal: @@ -240,8 +230,8 @@ public static class ObjectQueryableExtensions // ...Other (Field = Value) exp = Expression.Equal( - leftParamter, - Expression.Convert(Expression.Constant(paramter.Value), propertyType)); + leftParamter, + GetValue(paramter, propertyType)); break; } expressions.Push(exp); @@ -267,6 +257,160 @@ public static class ObjectQueryableExtensions return Expression.Lambda(expressions.Pop(), condition.Parameters.ToArray()); } + private static Expression BuildLessThanExpression(DynamicParamter paramter, MemberExpression member, Type propertyType) + { + if (propertyType == typeof(string)) + { + // 字符串比较: Field < Value + return Expression.LessThan( + Expression.Call( + member, + typeof(string).GetMethod("CompareTo", new[] { typeof(string) }), + Expression.Constant(Convert.ToString(paramter.Value))), + Expression.Constant(0)); + } + if (propertyType.IsNullableType()) + { + // 可空类型比较: Field < Value + var underlyingType = Nullable.GetUnderlyingType(propertyType); + + var hasValue = Expression.Property(member, "HasValue"); + var value = Expression.Property(member, "Value"); + + return Expression.AndAlso( + hasValue, + Expression.LessThan( + value, + GetValue(paramter, underlyingType))); + } + else + { + // 数值比较: Field < Value + return Expression.LessThan( + member, + GetValue(paramter, propertyType)); + } + } + + private static Expression BuildLessThanOrEqualExpression(DynamicParamter paramter, MemberExpression member, Type propertyType) + { + if (propertyType == typeof(string)) + { + // 字符串比较: Field <= Value + return Expression.LessThanOrEqual( + Expression.Call( + member, + typeof(string).GetMethod("CompareTo", new[] { typeof(string) }), + Expression.Constant(Convert.ToString(paramter.Value))), + Expression.Constant(0)); + } + if (propertyType.IsNullableType()) + { + // 可空类型比较: Field <= Value + var underlyingType = Nullable.GetUnderlyingType(propertyType); + + var hasValue = Expression.Property(member, "HasValue"); + var value = Expression.Property(member, "Value"); + + return Expression.AndAlso( + hasValue, + Expression.LessThanOrEqual( + value, + GetValue(paramter, underlyingType))); + } + else + { + // 数值比较: Field <= Value + return Expression.LessThanOrEqual( + member, + GetValue(paramter, propertyType)); + } + } + + private static Expression BuildGreaterThanExpression(DynamicParamter paramter, MemberExpression member, Type propertyType) + { + if (propertyType == typeof(string)) + { + // 字符串比较: Field > Value + return Expression.GreaterThan( + Expression.Call( + member, + typeof(string).GetMethod("CompareTo", new[] { typeof(string) }), + Expression.Constant(Convert.ToString(paramter.Value))), + Expression.Constant(0)); + } + if (propertyType.IsNullableType()) + { + // 可空类型比较: Field > Value + var underlyingType = Nullable.GetUnderlyingType(propertyType); + + var hasValue = Expression.Property(member, "HasValue"); + var value = Expression.Property(member, "Value"); + + return Expression.AndAlso( + hasValue, + Expression.GreaterThan( + value, + GetValue(paramter, underlyingType))); + } + else + { + // 数值比较: Field > Value + return Expression.GreaterThan( + member, + GetValue(paramter, propertyType)); + } + } + + private static Expression BuildGreaterThanOrEqualExpression(DynamicParamter paramter, MemberExpression member, Type propertyType) + { + if (propertyType == typeof(string)) + { + // 字符串比较: Field >= Value + return Expression.GreaterThanOrEqual( + Expression.Call( + member, + typeof(string).GetMethod("CompareTo", new[] { typeof(string) }), + Expression.Constant(Convert.ToString(paramter.Value))), + Expression.Constant(0)); + } + + if (propertyType.IsNullableType()) + { + // 可空类型比较: Field >= Value + var underlyingType = Nullable.GetUnderlyingType(propertyType); + + var hasValue = Expression.Property(member, "HasValue"); + var value = Expression.Property(member, "Value"); + + return Expression.AndAlso( + hasValue, + Expression.GreaterThanOrEqual( + value, + GetValue(paramter, underlyingType))); + } + else + { + // 数值比较: Field >= Value + return Expression.GreaterThanOrEqual( + member, + GetValue(paramter, propertyType)); + } + } + + private static ConstantExpression GetValue(DynamicParamter paramter, Type propertyType) + { + object typedValue; + if (propertyType.IsNullableType()) + { + propertyType = Nullable.GetUnderlyingType(propertyType); + } + + typedValue = Convert.ChangeType(paramter.Value, propertyType); + + return Expression.Constant(typedValue, propertyType); + } + private static object GetDefaultValue(Type type) { // TODO: 非空字段此处返回默认值 diff --git a/aspnet-core/framework/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/AppDescriptor.cs b/aspnet-core/framework/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/AppDescriptor.cs index 74a2d6889..149d3e5c1 100644 --- a/aspnet-core/framework/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/AppDescriptor.cs +++ b/aspnet-core/framework/open-api/LINGYUN.Abp.OpenApi/LINGYUN/Abp/OpenApi/AppDescriptor.cs @@ -17,7 +17,7 @@ public class AppDescriptor /// /// 应用token /// - public string AppToken { get; set; } + public string? AppToken { get; set; } /// /// 签名有效时间 /// 单位: s @@ -29,7 +29,7 @@ public class AppDescriptor string appName, string appKey, string appSecret, - string appToken = null, + string? appToken = null, int? signLifeTime = null) { AppName = appName; diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.csproj b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.csproj index 37733ad57..cafad2948 100644 --- a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.csproj +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.csproj @@ -12,7 +12,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250813012035_Upgrade-Abp-Framework-To-9.3.1.Designer.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250813012035_Upgrade-Abp-Framework-To-9.3.1.Designer.cs new file mode 100644 index 000000000..503871227 --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250813012035_Upgrade-Abp-Framework-To-9.3.1.Designer.cs @@ -0,0 +1,5470 @@ +// +using System; +using LY.MicroService.Applications.Single.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migrations +{ + [DbContext(typeof(SingleMigrationsDbContext))] + [Migration("20250813012035_Upgrade-Abp-Framework-To-9.3.1")] + partial class UpgradeAbpFrameworkTo931 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "9.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityEnumInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("PropertyInfoId") + .HasColumnType("char(36)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("varchar(10)") + .HasColumnName("Value"); + + b.HasKey("Id"); + + b.HasIndex("PropertyInfoId", "Name"); + + b.ToTable("AbpAuthEntityEnums", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("JavaScriptType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("JavaScriptType"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("TypeFullName"); + + b.Property("TypeInfoId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TypeInfoId", "TypeFullName"); + + b.ToTable("AbpAuthEntityProperties", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsAuditEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("TypeFullName"); + + b.HasKey("Id"); + + b.HasIndex("TypeFullName"); + + b.ToTable("AbpAuthEntitites", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AccessedProperties") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("AccessedProperties"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("longtext"); + + b.Property("EntityTypeId") + .HasColumnType("char(36)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("longtext") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("OrgCode") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("OrgCode"); + + b.Property("OrgId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthOrganizationUnitEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AccessedProperties") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("AccessedProperties"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("longtext"); + + b.Property("EntityTypeId") + .HasColumnType("char(36)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("longtext") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("RoleName"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthRoleEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.SubjectStrategy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Strategy") + .HasColumnType("int"); + + b.Property("SubjectId") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("SubjectId"); + + b.Property("SubjectName") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("SubjectName"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpAuthSubjectStrategys", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Authors.Author", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BirthDate") + .HasColumnType("datetime(6)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ShortBio") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Demo_Authors", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.Book", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AuthorId") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("Price") + .HasColumnType("float"); + + b.Property("PublishDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.ToTable("Demo_Books", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.BookAuth", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("EntityId") + .HasMaxLength(64) + .HasColumnType("char(64)") + .HasColumnName("EntityId"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("EntityType"); + + b.Property("OrganizationUnit") + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("OrganizationUnit"); + + b.Property("Role") + .HasMaxLength(32) + .HasColumnType("varchar(32)") + .HasColumnName("Role"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EntityId"); + + b.HasIndex("OrganizationUnit"); + + b.HasIndex("Role"); + + b.ToTable("Demo_BooksAuths", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("Data"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("Provider"); + + b.Property("RequestId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("RequestId"); + + b.ToTable("AbpGdprInfos", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("ReadyTime") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpGdprRequests", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Language", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("CultureName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("CultureName"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("DisplayName"); + + b.Property("Enable") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(true); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("TwoLetterISOLanguageName") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("TwoLetterISOLanguageName"); + + b.Property("UiCultureName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("UiCultureName"); + + b.HasKey("Id"); + + b.HasIndex("CultureName"); + + b.ToTable("AbpLocalizationLanguages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Resource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DefaultCultureName") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("DefaultCultureName"); + + b.Property("Description") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Description"); + + b.Property("DisplayName") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("DisplayName"); + + b.Property("Enable") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(true); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("Name"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AbpLocalizationResources", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Text", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CultureName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("CultureName"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("Key"); + + b.Property("ResourceName") + .HasColumnType("longtext"); + + b.Property("Value") + .HasMaxLength(2048) + .HasColumnType("varchar(2048)") + .HasColumnName("Value"); + + b.HasKey("Id"); + + b.HasIndex("Key"); + + b.ToTable("AbpLocalizationTexts", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatCard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Age") + .HasColumnType("int"); + + b.Property("AvatarUrl") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("Birthday") + .HasColumnType("datetime(6)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("LastOnlineTime") + .HasColumnType("datetime(6)"); + + b.Property("NickName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Sex") + .HasColumnType("int"); + + b.Property("Sign") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("State") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatCards", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatFriend", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Black") + .HasColumnType("tinyint(1)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("DontDisturb") + .HasColumnType("tinyint(1)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FrientId") + .HasColumnType("char(36)"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("RemarkName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("SpecialFocus") + .HasColumnType("tinyint(1)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "FrientId"); + + b.ToTable("AppUserChatFriends", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AllowAddFriend") + .HasColumnType("tinyint(1)"); + + b.Property("AllowAnonymous") + .HasColumnType("tinyint(1)"); + + b.Property("AllowReceiveMessage") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendMessage") + .HasColumnType("tinyint(1)"); + + b.Property("RequireAddFriendValition") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatSettings", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("longtext"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("ReceiveUserId") + .HasColumnType("char(36)"); + + b.Property("SendUserName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Source") + .HasColumnType("int"); + + b.Property("State") + .HasColumnType("tinyint"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ReceiveUserId"); + + b.ToTable("AppUserMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.ChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Address") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("AdminUserId") + .HasColumnType("char(36)"); + + b.Property("AllowAnonymous") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendMessage") + .HasColumnType("tinyint(1)"); + + b.Property("AvatarUrl") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("MaxUserCount") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("Notice") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Tag") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AppChatGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.GroupChatBlack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("ShieldUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupChatBlacks", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.GroupMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("longtext"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("SendUserName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Source") + .HasColumnType("int"); + + b.Property("State") + .HasColumnType("tinyint"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.UserChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId", "UserId"); + + b.ToTable("AppUserChatGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.UserGroupCard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsAdmin") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("NickName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("SilenceEnd") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserGroupCards", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property
+ {{ item.title }} +