优化一些组件效果

This commit is contained in:
z9130 2024-09-10 22:30:01 +08:00
parent 2c10bb44d5
commit 16e2611a1e
1604 changed files with 90057 additions and 79153 deletions

4
.browserslistrc Normal file
View File

@ -0,0 +1,4 @@
> 1%
last 2 versions
not dead
not ie 11

1
.commitlintrc.mjs Normal file
View File

@ -0,0 +1 @@
export { default } from '@vben/commitlint-config';

5
.dockerignore Normal file
View File

@ -0,0 +1,5 @@
node_modules
.git
.gitignore
*.md
dist

View File

@ -1,11 +1,18 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
charset=utf-8
end_of_line=lf
insert_final_newline=true
indent_style=space
indent_size=2
max_line_length = 100
trim_trailing_whitespace = true
quote_type = single
[*.{yml,yaml,json}]
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

48
.env
View File

@ -1,48 +0,0 @@
VITE_BASE_URL=/
VITE_APP_TITLE=ERP 综合办公系统
VITE_APP_DESC=
# the prefix of the icon name
VITE_ICON_PREFIX=icon
# the prefix of the local svg icon component, must include VITE_ICON_PREFIX
# format {VITE_ICON_PREFIX}-{local icon name}
VITE_ICON_LOCAL_PREFIX=icon-local
# 路由模式: static 静态 dynamic 动态
VITE_AUTH_ROUTE_MODE=dynamic
# static 静态路由首页地址
VITE_ROUTE_HOME=home
# 默认菜单图标
VITE_MENU_ICON=mdi:menu
# 当在开发模式下,是否使用代理
VITE_HTTP_PROXY=Y
# vue-router 路由模式: hash | history | memory
VITE_ROUTER_HISTORY_MODE=history
# success code of backend service, when the code is received, the request is successful
VITE_SERVICE_SUCCESS_CODE=200
# logout codes of backend service, when the code is received, the user will be logged out and redirected to login page
VITE_SERVICE_LOGOUT_CODES=8888,8889
# modal logout codes of backend service, when the code is received, the user will be logged out by displaying a modal
VITE_SERVICE_MODAL_LOGOUT_CODES=7777,7778
# token expired codes of backend service, when the code is received, it will refresh the token and resend the request
VITE_SERVICE_EXPIRED_TOKEN_CODES=9999,9998
# when the route mode is static, the defined super role
VITE_STATIC_SUPER_ROLE=R_SUPER
# sourcemap
VITE_SOURCE_MAP=N
# Used to differentiate storage across different domains
VITE_STORAGE_PREFIX=app_

View File

@ -1,7 +0,0 @@
# backend service base url, prod environment
VITE_SERVICE_BASE_URL=https://mock.apifox.com/m1/3109515-0-default
# other backend service base url, prod environment
VITE_OTHER_SERVICE_BASE_URL= `{
"demo": "http://localhost:9529"
}`

View File

@ -1,7 +0,0 @@
# backend service base url, prod environment
VITE_SERVICE_BASE_URL=http://192.168.147.238:8083
# other backend service base url, prod environment
VITE_OTHER_SERVICE_BASE_URL= `{
"demo": "http://localhost:9529"
}`

View File

@ -1,3 +0,0 @@
module.exports = {
extends: ['antfu'],
};

24
.gitattributes vendored
View File

@ -1,13 +1,11 @@
"*.vue" eol=lf
"*.js" eol=lf
"*.ts" eol=lf
"*.jsx" eol=lf
"*.tsx" eol=lf
"*.mjs" eol=lf
"*.json" eol=lf
"*.html" eol=lf
"*.css" eol=lf
"*.scss" eol=lf
"*.md" eol=lf
"*.yaml" eol=lf
"*.yml" eol=lf
# https://docs.github.com/cn/get-started/getting-started-with-git/configuring-git-to-handle-line-endings
# Automatically normalize line endings (to LF) for all text-based files.
* text=auto eol=lf
# Declare files that will always have CRLF line endings on checkout.
*.{cmd,[cC][mM][dD]} text eol=crlf
*.{bat,[bB][aA][tT]} text eol=crlf
# Denote all files that are truly binary and should not be modified.
*.{ico,png,jpg,jpeg,gif,webp,svg,woff,woff2} binary

2
.gitconfig Normal file
View File

@ -0,0 +1,2 @@
[core]
ignorecase = false

55
.gitignore vendored
View File

@ -1,4 +1,33 @@
# Logs
node_modules
.DS_Store
dist
dist-ssr
dist.zip
dist.tar
dist.war
.nitro
.output
*-dist.zip
*-dist.tar
*-dist.war
coverage
*.local
**/.vitepress/cache
.cache
.turbo
.temp
dev-dist
.stylelintcache
yarn.lock
package-lock.json
.VSCodeCounter
**/backend-mock/data
# local env files
.env.local
.env.*.local
.eslintcache
logs
*.log
npm-debug.log*
@ -6,31 +35,17 @@ yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
vite.config.mts.*
vite.config.mjs.*
vite.config.js.*
vite.config.ts.*
# Editor directories and files
.vscode/*
!.vscode/extensions.json
!.vscode/settings.json
!.vscode/launch.json
.idea
# .vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
package-lock.json
yarn.lock
.history
.VSCodeCounter
vite.config.ts.**

6
.gitpod.yml Normal file
View File

@ -0,0 +1,6 @@
ports:
- port: 5555
onOpen: open-preview
tasks:
- init: corepack enable && pnpm install
command: pnpm run dev

6
.husky/commit-msg Normal file
View File

@ -0,0 +1,6 @@
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.

3
.husky/post-merge Normal file
View File

@ -0,0 +1,3 @@
# 每次 git pull 之后, 安装依赖
pnpm install

7
.husky/pre-commit Normal file
View File

@ -0,0 +1,7 @@
# 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.

20
.lintstagedrc.mjs Normal file
View File

@ -0,0 +1,20 @@
export default {
'{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [
'prettier --cache --write--parser json',
],
'*.{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',
],
'*.md': ['prettier --cache --ignore-unknown --write'],
'*.vue': [
'prettier --write',
'eslint --cache --fix',
'stylelint --fix --allow-empty-input',
],
'package.json': ['prettier --cache --write'],
};

28
.ls-lint.yml Normal file
View File

@ -0,0 +1,28 @@
ls:
.js: kebab-case | pointcase
.vue: kebab-case | pointcase
.ts: kebab-case | pointcase
.tsx: kebab-case | pointcase
.jsx: kebab-case | pointcase
.css: kebab-case | pointcase
.d.ts: kebab-case | pointcase
# shadcn 自动生成文件为 PascalCase 格式
packages/@core/ui-kit/shadcn-ui/src/components/ui:
.vue: PascalCase
ignore:
- "**/*.png"
- "**/*.jpg"
- "**/*.jpeg"
- "**/*.jpeg"
- "**/*.gif"
- "**/_util.ts"
- "**/deps/**"
- "**/dist/**"
- "**/node_modules/**"
- "**/.turbo/**"
- .git
- .vscode
- .idea
- node_modules
- .cache

1
.node-version Normal file
View File

@ -0,0 +1 @@
20.14.0

17
.npmrc
View File

@ -1,4 +1,13 @@
registry=https://registry.npmmirror.com/
shamefully-hoist=true
ignore-workspace-root-check=true
link-workspace-packages=true
registry = "https://registry.npmmirror.com"
public-hoist-pattern[]=husky
public-hoist-pattern[]=eslint
public-hoist-pattern[]=prettier
public-hoist-pattern[]=prettier-plugin-tailwindcss
public-hoist-pattern[]=stylelint
public-hoist-pattern[]=*postcss*
public-hoist-pattern[]=@commitlint/*
public-hoist-pattern[]=czg
strict-peer-dependencies=false
auto-install-peers=true
dedupe-peer-dependents=true

18
.prettierignore Normal file
View File

@ -0,0 +1,18 @@
dist
dev-dist
.local
.output.js
node_modules
.nvmrc
coverage
CODEOWNERS
.nitro
.output
**/*.svg
**/*.sh
public
.npmrc
*-lock.yaml

1
.prettierrc.mjs Normal file
View File

@ -0,0 +1 @@
export { default } from '@vben/prettier-config';

4
.stylelintignore Normal file
View File

@ -0,0 +1,4 @@
dist
public
__tests__
coverage

View File

@ -1,34 +1,28 @@
{
"recommendations": [
// my extensions, ofc :P
"antfu.browse-lite",
"antfu.iconify",
"antfu.slidev",
"antfu.unocss",
"antfu.vite",
"antfu.where-am-i",
"antfu.open-in-github-button",
"lokalise.i18n-ally",
// themes & icons
"antfu.icons-carbon",
"antfu.theme-vitesse",
"file-icons.file-icons",
"sainnhe.gruvbox-material",
// life savers!
"dbaeumer.vscode-eslint",
// Vue 3
"Vue.volar",
"GitHub.copilot",
"usernamehw.errorlens",
// 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",
// up to you
"eamodio.gitlens",
"EditorConfig.EditorConfig",
"github.vscode-github-actions",
"GitHub.vscode-pull-request-github",
"johnsoncodehk.vscode-tsconfig-helper",
"mpontus.tab-cycle",
"naumovs.color-highlight",
"WakaTime.vscode-wakatime",
"znck.grammarly"
// Tailwind CSS VS Code
"bradlc.vscode-tailwindcss",
// iconify
"antfu.iconify",
// i18n
"Lokalise.i18n-ally",
// CSS
"vunguyentuan.vscode-css-variables"
],
"unwantedRecommendations": [
// volar
"octref.vetur"
]
}

37
.vscode/global.code-snippets vendored Normal file
View File

@ -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": "<sc",
"body": [
"<script setup lang=\"ts\">",
"const props = defineProps<{",
" modelValue?: boolean,",
"}>()",
"$1",
"</script>",
"",
"<template>",
" <div>",
" <slot/>",
" </div>",
"</template>",
],
},
"vue-computed": {
"scope": "javascript,typescript,vue",
"prefix": "com",
"body": ["computed(() => { $1 })"],
},
}

42
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,42 @@
{
"$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/src"
},
{
"type": "chrome",
"name": "vben admin antd dev",
"request": "launch",
"url": "http://localhost:5666",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}/apps/web-antd/src"
},
{
"type": "chrome",
"name": "vben admin ele dev",
"request": "launch",
"url": "http://localhost:5777",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}/apps/web-ele/src"
},
{
"type": "chrome",
"name": "vben admin naive dev",
"request": "launch",
"url": "http://localhost:5888",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}/apps/web-naive/src"
}
]
}

468
.vscode/settings.json vendored
View File

@ -1,304 +1,228 @@
{
// ========== Visuals ==========
"editor.cursorSmoothCaretAnimation": "on",
// "editor.fontFamily": "Input Mono, monospace",
"editor.guides.bracketPairs": "active",
"editor.lineNumbers": "interval",
"editor.renderWhitespace": "boundary",
"window.autoDetectColorScheme": true,
"workbench.colorTheme": "Vitesse Dark Soft",
"workbench.editor.tabActionLocation": "left",
"workbench.fontAliasing": "antialiased",
"workbench.iconTheme": "file-icons-colourless",
"tailwindCSS.experimental.configFile": "internal/tailwind-config/src/index.ts",
// workbench
"workbench.list.smoothScrolling": true,
"workbench.preferredDarkColorTheme": "Vitesse Dark",
"workbench.preferredLightColorTheme": "Vitesse Dark Soft",
"workbench.productIconTheme": "icons-carbon",
"workbench.sideBar.location": "right",
"workbench.startupEditor": "newUntitledFile",
"workbench.tree.expandMode": "singleClick",
"workbench.tree.indent": 10,
// ========== Editor ==========
"debug.onTaskErrors": "debugAnyway",
"diffEditor.ignoreTrimWhitespace": true,
"editor.wordSeparators": "`~!@#%^&*()=+[{]}\\|;:'\",.<>/?",
"editor.find.addExtraSpaceOnTop": false,
"editor.inlineSuggest.enabled": true,
"editor.multiCursorModifier": "ctrlCmd",
"editor.suggestSelection": "first",
"editor.tabSize": 2,
"editor.unicodeHighlight.invisibleCharacters": false,
"editor.stickyScroll.enabled": true,
"editor.hover.sticky": true,
"editor.codeActionsOnSave": {
"source.fixAll": "never",
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
"explorer.confirmDelete": false,
"explorer.confirmDragAndDrop": false,
"files.eol": "\n",
"files.insertFinalNewline": true,
"files.simpleDialog.enable": true,
"git.autofetch": true,
"git.confirmSync": false,
"git.enableSmartCommit": true,
"git.untrackedChanges": "separate",
"scm.diffDecorationsGutterWidth": 2,
"terminal.integrated.cursorBlinking": true,
"terminal.integrated.cursorStyle": "line",
"terminal.integrated.fontWeight": "300",
"terminal.integrated.persistentSessionReviveProcess": "never",
"terminal.integrated.tabs.enabled": true,
"workbench.editor.closeOnFileDelete": true,
"workbench.editor.highlightModifiedTabs": true,
"workbench.editor.closeOnFileDelete": true,
"workbench.editor.limit.enabled": true,
"workbench.editor.limit.perEditorGroup": true,
"workbench.editor.limit.value": 5,
"search.exclude": {
"**/*.snap": true,
"**/*.svg": true,
"**/.git": true,
"**/.github": false,
"**/.nuxt": true,
"**/.output": true,
"**/.pnpm": true,
"**/.vscode": true,
"**/.yarn": true,
"**/assets": true,
"**/bower_components": true,
"**/dist/**": true,
"**/logs": true,
"**/node_modules": true,
"**/out/**": true,
"**/package-lock.json": true,
"**/pnpm-lock.yaml": true,
"**/public": true,
"**/temp": true,
"**/yarn.lock": true,
"**/CHANGELOG*": true,
"**/LICENSE*": true,
// editor
"editor.tabSize": 2,
"editor.detectIndentation": false,
"editor.cursorBlinking": "expand",
"editor.largeFileOptimizations": false,
"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"
},
// ========== Global Level Config, needs to put in User Settings ==========
"window.dialogStyle": "custom",
"window.nativeTabs": true, // this is great, macOS only
"window.title": "${rootName}", // this make tabs more readable
"window.titleBarStyle": "custom",
"extensions.autoUpdate": "onlyEnabledExtensions",
// ========== Extension configs ==========
"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": "vscode.typescript-language-features"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "Vue.volar"
},
// 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,
"**/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
},
// 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"
],
// ESLint config: https://github.com/antfu/eslint-config
"eslint.codeAction.showDocumentation": {
"enable": true
},
"eslint.quiet": true,
// Silent the stylistic rules in you IDE, but still auto fix them
"eslint.rules.customizations": [
{
"rule": "style/*",
"severity": "off"
},
{
"rule": "format/*",
"severity": "off"
},
{
"rule": "*-indent",
"severity": "off"
},
{
"rule": "*-spacing",
"severity": "off"
},
{
"rule": "*-spaces",
"severity": "off"
},
{
"rule": "*-order",
"severity": "off"
},
{
"rule": "*-dangle",
"severity": "off"
},
{
"rule": "*-newline",
"severity": "off"
},
{
"rule": "*quotes",
"severity": "off"
},
{
"rule": "*semi",
"severity": "off"
}
],
"errorLens.enabledDiagnosticLevels": ["warning", "error"],
"errorLens.excludeBySource": ["cSpell", "Grammarly", "eslint"],
"stylelint.enable": true,
"stylelint.packageManager": "pnpm",
"stylelint.validate": ["css", "less", "postcss", "scss", "vue"],
"stylelint.snippet": ["css", "less", "postcss", "scss", "vue"],
"typescript.inlayHints.enumMemberValues.enabled": true,
"typescript.preferences.preferTypeOnlyAutoImports": true,
"typescript.preferences.includePackageJsonAutoImports": "on",
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"javascriptreact",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml",
"toml"
"json5"
],
"tailwindCSS.experimental.classRegex": [
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
],
"github.copilot.enable": {
"*": true,
"markdown": true,
"plaintext": false,
"yaml": false
},
"cSpell.allowCompoundWords": true,
"cSpell.language": "en,en-US",
"css.lint.hexColorLength": "ignore",
"githubIssues.workingIssueFormatScm": "#${issueNumberLabel}",
"githubPullRequests.fileListLayout": "tree",
"gitlens.codeLens.authors.enabled": false,
"gitlens.codeLens.enabled": false,
"gitlens.codeLens.recentChange.enabled": false,
"gitlens.menus": {
"editor": {
"blame": false,
"clipboard": true,
"compare": true,
"history": false,
"remote": false
},
"editorGroup": {
"blame": true,
"compare": false
},
"editorTab": {
"clipboard": true,
"compare": true,
"history": true,
"remote": true
},
"explorer": {
"clipboard": true,
"compare": true,
"history": true,
"remote": true
},
"scm": {
"authors": true
},
"scmGroup": {
"compare": true,
"openClose": true,
"stash": true
},
"scmGroupInline": {
"stash": true
},
"scmItem": {
"clipboard": true,
"compare": true,
"history": true,
"remote": false,
"stash": true
}
},
"i18n-ally.autoDetection": false,
"i18n-ally.displayLanguage": "en",
"i18n-ally.ignoredLocales": [],
"iconify.annotations": true,
"iconify.inplace": true,
"svg.preview.mode": "svg",
// I only use Prettier for manually formatting
"prettier.enable": false,
"prettier.printWidth": 200,
"prettier.semi": false,
"prettier.singleQuote": true,
// ========== File Nesting ==========
// this might not be up to date with the repo, please check yourself
// https://github.com/antfu/vscode-file-nesting-config
"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}.json",
"i18n-ally.enabledParsers": ["json", "ts", "js", "yaml"],
"i18n-ally.sourceLanguage": "en",
"i18n-ally.displayLanguage": "zh-CN",
"i18n-ally.enabledFrameworks": ["vue", "react"],
//
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.expand": false,
"explorer.fileNesting.patterns": {
"*.asax": "$(capture).*.cs, $(capture).*.vb",
"*.ascx": "$(capture).*.cs, $(capture).*.vb",
"*.ashx": "$(capture).*.cs, $(capture).*.vb",
"*.aspx": "$(capture).*.cs, $(capture).*.vb",
"*.bloc.dart": "$(capture).event.dart, $(capture).state.dart",
"*.c": "$(capture).h",
"*.cc": "$(capture).hpp, $(capture).h, $(capture).hxx",
"*.cjs": "$(capture).cjs.map, $(capture).*.cjs, $(capture)_*.cjs",
"*.component.ts": "$(capture).component.html, $(capture).component.spec.ts, $(capture).component.css, $(capture).component.scss, $(capture).component.sass, $(capture).component.less",
"*.cpp": "$(capture).hpp, $(capture).h, $(capture).hxx",
"*.cs": "$(capture).*.cs",
"*.cshtml": "$(capture).cshtml.cs",
"*.csproj": "*.config, *proj.user, appsettings.*, bundleconfig.json",
"*.css": "$(capture).css.map, $(capture).*.css",
"*.cxx": "$(capture).hpp, $(capture).h, $(capture).hxx",
"*.dart": "$(capture).freezed.dart, $(capture).g.dart",
"*.ex": "$(capture).html.eex, $(capture).html.heex, $(capture).html.leex",
"*.go": "$(capture)_test.go",
"*.java": "$(capture).class",
"*.js": "$(capture).js.map, $(capture).*.js, $(capture)_*.js",
"*.jsx": "$(capture).js, $(capture).*.jsx, $(capture)_*.js, $(capture)_*.jsx",
"*.master": "$(capture).*.cs, $(capture).*.vb",
"*.mjs": "$(capture).mjs.map, $(capture).*.mjs, $(capture)_*.mjs",
"*.module.ts": "$(capture).resolver.ts, $(capture).controller.ts, $(capture).service.ts",
"*.pubxml": "$(capture).pubxml.user",
"*.resx": "$(capture).*.resx, $(capture).designer.cs, $(capture).designer.vb",
"*.tex": "$(capture).acn, $(capture).acr, $(capture).alg, $(capture).aux, $(capture).bbl, $(capture).blg, $(capture).fdb_latexmk, $(capture).fls, $(capture).glg, $(capture).glo, $(capture).gls, $(capture).idx, $(capture).ind, $(capture).ist, $(capture).lof, $(capture).log, $(capture).lot, $(capture).out, $(capture).pdf, $(capture).synctex.gz, $(capture).toc, $(capture).xdv",
"*.ts": "$(capture).js, $(capture).d.ts.map, $(capture).*.ts, $(capture)_*.js, $(capture)_*.ts",
"*.tsx": "$(capture).ts, $(capture).*.tsx, $(capture)_*.ts, $(capture)_*.tsx",
"*.vbproj": "*.config, *proj.user, appsettings.*, bundleconfig.json",
"*.vue": "$(capture).*.ts, $(capture).*.js, $(capture).story.vue",
"*.xaml": "$(capture).xaml.cs",
"+layout.svelte": "+layout.ts,+layout.ts,+layout.js,+layout.server.ts,+layout.server.js,+layout.gql",
"+page.svelte": "+page.server.ts,+page.server.js,+page.ts,+page.js,+page.gql",
".clang-tidy": ".clang-format, .clangd, compile_commands.json",
".env": "*.env, .env.*, .envrc, env.d.ts",
".gitignore": ".gitattributes, .gitmodules, .gitmessage, .mailmap, .git-blame*",
".project": ".classpath",
"//": "Last update at 4/29/2023, 2:04:58 PM",
"BUILD.bazel": "*.bzl, *.bazel, *.bazelrc, bazel.rc, .bazelignore, .bazelproject, WORKSPACE",
"CMakeLists.txt": "*.cmake, *.cmake.in, .cmake-format.yaml, CMakePresets.json",
"I*.cs": "$(capture).cs",
"artisan": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, server.php, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, webpack.mix.js, windi.config.*",
"astro.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"cargo.toml": ".clippy.toml, .rustfmt.toml, cargo.lock, clippy.toml, cross.toml, rust-toolchain.toml, rustfmt.toml",
"composer.json": ".php*.cache, composer.lock, phpunit.xml*, psalm*.xml",
"default.nix": "shell.nix",
"deno.json*": "*.env, .env.*, .envrc, api-extractor.json, deno.lock, env.d.ts, import-map.json, import_map.json, jsconfig.*, tsconfig.*, tsdoc.*",
"dockerfile": ".dockerignore, docker-compose.*, dockerfile*",
"flake.nix": "flake.lock",
"gatsby-config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, gatsby-browser.*, gatsby-node.*, gatsby-ssr.*, gatsby-transformer.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"gemfile": ".ruby-version, gemfile.lock",
"go.mod": ".air*, go.sum",
"go.work": "go.work.sum",
"mix.exs": ".credo.exs, .dialyzer_ignore.exs, .formatter.exs, .iex.exs, .tool-versions, mix.lock",
"next.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, next-env.d.ts, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"nuxt.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"package.json": ".browserslist*, .circleci*, .commitlint*, .cz-config.js, .czrc, .dlint.json, .dprint.json, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lintstagedrc*, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, bower.json, build.config.*, commitlint*, crowdin*, dangerfile*, dlint.json, dprint.json, eslint*, firebase.json, grunt*, gulp*, jenkins*, lerna*, lint-staged*, nest-cli.*, netlify*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-tasks.sh, release.config.*, renovate*, rollup.config.*, rspack*, simple-git-hooks*, stylelint*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, xo.config.*, yarn*",
"pubspec.yaml": ".metadata, .packages, all_lint_rules.yaml, analysis_options.yaml, build.yaml, pubspec.lock, pubspec_overrides.yaml",
"pyproject.toml": ".pdm.toml, pdm.lock, pyproject.toml",
"quasar.conf.js": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, quasar.extensions.json, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"readme*": "authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying, credits, governance.md, history.md, license*, maintainers, readme*, security.md, sponsors*",
"remix.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, remix.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"rush.json": ".browserslist*, .circleci*, .commitlint*, .cz-config.js, .czrc, .dlint.json, .dprint.json, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lintstagedrc*, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, bower.json, build.config.*, commitlint*, crowdin*, dangerfile*, dlint.json, dprint.json, eslint*, firebase.json, grunt*, gulp*, jenkins*, lerna*, lint-staged*, nest-cli.*, netlify*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-tasks.sh, release.config.*, renovate*, rollup.config.*, rspack*, simple-git-hooks*, stylelint*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, xo.config.*, yarn*",
"shims.d.ts": "*.d.ts",
"svelte.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, houdini.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, mdsvex.config.js, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vite.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"vite.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"vue.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*"
"*.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",
"Dockerfile": "Dockerfile,.docker*,docker-entrypoint.sh,build-local-docker*,nginx.conf",
"eslint.config.mjs": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.*,.prettierrc.*,stylelint.config.*,.lintstagedrc.mjs,.ls-lint*,cspell.json",
"tailwind.config.mjs": "postcss.*"
},
"commentTranslate.hover.enabled": false,
"i18n-ally.keystyle": "nested",
"commentTranslate.multiLineMerge": true,
"vue.server.hybridMode": true,
"typescript.tsdk": "node_modules/typescript/lib",
"vue3snippets.enable-compile-vue-file-on-did-save-code": false,
"[typescriptreact]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
}
}

31
Dockerfile Normal file
View File

@ -0,0 +1,31 @@
FROM node:20-slim AS builder
# --max-old-space-size
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
ENV NODE_OPTIONS=--max-old-space-size=8192
ENV TZ=Asia/Shanghai
RUN corepack enable
WORKDIR /app
# copy package.json and pnpm-lock.yaml to workspace
COPY . /app
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm run build
RUN echo "Builder Success 🎉"
FROM nginx:stable-alpine as production
RUN echo "types { application/javascript js mjs; }" > /etc/nginx/conf.d/mjs.conf
COPY --from=builder /app/playground/dist /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/nginx.conf
EXPOSE 8080
# start nginx
CMD ["nginx", "-g", "daemon off;"]

20
LICENSE
View File

@ -1,21 +1,9 @@
MIT License
Copyright (c) 2021 Soybean
Copyright (c) 2024-present, Vben
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

149
README.ja-JP.md Normal file
View File

@ -0,0 +1,149 @@
<div align="center"> <a href="https://github.com/anncwb/vue-vben-admin"> <img alt="VbenAdmin Logo" width="215" src="https://unpkg.com/@vbenjs/static-source@0.1.6/source/logo-v1.webp"> </a> <br> <br>
[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE)
<h1>Vue Vben Admin</h1>
</div>
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)
**日本語** | [English](./README.md) | [中文](./README.zh-CN.md)
## 紹介
Vue Vben Adminは、最新の`vue3`、`vite`、`TypeScript`などの主流技術を使用して開発された、無料でオープンソースの中・後端テンプレートです。すぐに使える中・後端のフロントエンドソリューションとして、学習の参考にもなります。
## アップグレード通知
これは最新バージョン5.0であり、以前のバージョンとは互換性がありません。新しいプロジェクトを開始する場合は、最新バージョンを使用することをお勧めします。古いバージョンを表示したい場合は、[v2ブランチ](https://github.com/vbenjs/vue-vben-admin/tree/v2)を使用してください。
## 特徴
- **最新技術スタック**: Vue 3やViteなどの最先端フロントエンド技術で開発
- **TypeScript**: アプリケーション規模のJavaScriptのための言語
- **テーマ**: 複数のテーマカラーが利用可能で、カスタマイズオプションも豊富
- **国際化**: 完全な内蔵国際化サポート
- **権限管理**: 動的ルートベースの権限生成ソリューションを内蔵
## プレビュー
- [Vben Admin](https://vben.pro/) - フルバージョンの中国語サイト
テストアカウント: vben/123456
<p align="center">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview1.png">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview2.png">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview3.png">
</p>
### Gitpodを使用
GitpodGitHub用の無料オンライン開発環境でプロジェクトを開き、すぐにコーディングを開始します。
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin)
## ドキュメント
[ドキュメント](https://doc.vben.pro/)
## インストールと使用
- プロジェクトコードを取得
```bash
git clone https://github.com/vbenjs/vue-vben-admin.git
```
- 依存関係のインストール
```bash
cd vue-vben-admin
corepack enable
pnpm install
```
- 実行
```bash
pnpm dev
```
- ビルド
```bash
pnpm build
```
## 変更ログ
[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)
## 貢献方法
ご参加をお待ちしております![Issueを提出](https://github.com/anncwb/vue-vben-admin/issues/new/choose)するか、Pull Requestを送信してください。
**Pull Request:**
1. コードをフォーク!
2. 自分のブランチを作成: `git checkout -b feat/xxxx`
3. 変更をコミット: `git commit -am 'feat(function): add xxxxx'`
4. ブランチをプッシュ: `git push origin feat/xxxx`
5. `pull request`を送信
## Git貢献提出規則
- 参考 [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 規則 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))
- `feat` 新機能の追加
- `fix` 問題/バグの修正
- `style` コードスタイルに関連し、実行結果に影響しない
- `perf` 最適化/パフォーマンス向上
- `refactor` リファクタリング
- `revert` 変更の取り消し
- `test` テスト関連
- `docs` ドキュメント/注釈
- `chore` 依存関係の更新/スキャフォールディング設定の変更など
- `ci` 継続的インテグレーション
- `types` 型定義ファイルの変更
- `wip` 開発中
## ブラウザサポート
ローカル開発には`Chrome 80+`ブラウザを推奨します
モダンブラウザをサポートし、IEはサポートしません
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| :-: | :-: | :-: | :-: | :-: |
| サポートしない | 最新2バージョン | 最新2バージョン | 最新2バージョン | 最新2バージョン |
## メンテナー
[@Vben](https://github.com/anncwb)
## 寄付
このプロジェクトが役に立つと思われた場合、作者にコーヒーを一杯おごってサポートを示すことができます!
![donate](https://unpkg.com/@vbenjs/static-source@0.1.6/source/sponsor.png)
<a style="display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aed;border-radius: 4px;" href="https://www.paypal.com/paypalme/cvvben">Paypal Me</a>
## 貢献者
<a href="https://github.com/vbenjs/vue-vben-admin/graphs/contributors">
<img alt="Contributors"
src="https://opencollective.com/vbenjs/contributors.svg?button=false" />
</a>
## Discord
- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions)
## ライセンス
[MIT © Vben-2020](./LICENSE)

170
README.md
View File

@ -1,92 +1,148 @@
# 前端
<div align="center"> <a href="https://github.com/anncwb/vue-vben-admin"> <img alt="VbenAdmin Logo" width="215" src="https://unpkg.com/@vbenjs/static-source@0.1.6/source/logo-v1.webp"> </a> <br> <br>
[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE)
<h1>Vue Vben Admin</h1>
</div>
## Getting started
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
**English** | [中文](./README.zh-CN.md) | [日本語](./README.ja-JP.md)
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Introduction
## Add your files
Vue Vben Admin is a free and open source middle and back-end template. Using the latest `vue3`, `vite`, `TypeScript` and other mainstream technology development, the out-of-the-box middle and back-end front-end solutions can also be used for learning reference.
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
## Upgrade Notice
```
cd existing_repo
git remote add origin https://git.openserver.cn:8089/XinJiang/TheProjectOfFour/kelamayireligongsi/plrl/vue.git
git branch -M main
git push -uf origin main
This is the latest version, 5.0, and it is not compatible with previous versions. If you are starting a new project, it is recommended to use the latest version. If you wish to view the old version, please use the [v2 branch](https://github.com/vbenjs/vue-vben-admin/tree/v2).
## Feature
- **Latest Technology Stack**: Developed with cutting-edge front-end technologies like Vue 3 and Vite
- **TypeScript**: A language for application-scale JavaScript
- **Themes**: Multiple theme colors available with customizable options
- **Internationalization**: Comprehensive built-in internationalization support
- **Permissions**: Built-in solution for dynamic route-based permission generation
## Preview
- [Vben Admin](https://vben.pro/) - Full version Chinese site
Test Account: vben/123456
<p align="center">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview1.png">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview2.png">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview3.png">
</p>
### Use Gitpod
Open the project in Gitpod (free online dev environment for GitHub) and start coding immediately.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin)
## Documentation
[Document](https://doc.vben.pro/)
## Install and use
- Get the project code
```bash
git clone https://github.com/vbenjs/vue-vben-admin.git
```
## Integrate with your tools
- Installation dependencies
- [ ] [Set up project integrations](https://git.openserver.cn:8089/XinJiang/TheProjectOfFour/kelamayireligongsi/plrl/vue/-/settings/integrations)
```bash
cd vue-vben-admin
## Collaborate with your team
corepack enable
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
pnpm install
```
## Test and Deploy
- run
Use the built-in continuous integration in GitLab.
```bash
pnpm dev
```
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
- build
***
```bash
pnpm build
```
# Editing this README
## Change Log
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## How to contribute
## Name
Choose a self-explaining name for your project.
You are very welcome to join[Raise an issue](https://github.com/anncwb/vue-vben-admin/issues/new/choose) Or submit a Pull Request。
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
**Pull Request:**
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
1. Fork code!
2. Create your own branch: `git checkout -b feat/xxxx`
3. Submit your changes: `git commit -am 'feat(function): add xxxxx'`
4. Push your branch: `git push origin feat/xxxx`
5. submit`pull request`
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Git Contribution submission specification
## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
- reference [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) specification ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))
## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
- `feat` Add new features
- `fix` Fix the problem/BUG
- `style` The code style is related and does not affect the running result
- `perf` Optimization/performance improvement
- `refactor` Refactor
- `revert` Undo edit
- `test` Test related
- `docs` Documentation/notes
- `chore` Dependency update/scaffolding configuration modification etc.
- `ci` Continuous integration
- `types` Type definition file changes
- `wip` In development
## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Browser support
## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README.
The `Chrome 80+` browser is recommended for local development
## Contributing
State if you are open to contributions and what your requirements are for accepting them.
Support modern browsers, not IE
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| :-: | :-: | :-: | :-: | :-: |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Maintainer
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
[@Vben](https://github.com/anncwb)
## Donate
If you think this project is helpful to you, you can help the author buy a cup of coffee to show your support!
![donate](https://unpkg.com/@vbenjs/static-source@0.1.6/source/sponsor.png)
<a style="display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aed;border-radius: 4px;" href="https://www.paypal.com/paypalme/cvvben">Paypal Me</a>
## Contributor
<a href="https://github.com/vbenjs/vue-vben-admin/graphs/contributors">
<img alt="Contributors"
src="https://opencollective.com/vbenjs/contributors.svg?button=false" />
</a>
## Discord
- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions)
## License
For open source projects, say how it is licensed.
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
[MIT © Vben-2020](./LICENSE)

148
README.zh-CN.md Normal file
View File

@ -0,0 +1,148 @@
<div align="center"> <a href="https://github.com/anncwb/vue-vben-admin"> <img alt="VbenAdmin Logo" width="215" src="https://unpkg.com/@vbenjs/static-source@0.1.6/source/logo-v1.webp"> </a> <br> <br>
[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE)
<h1>Vue Vben Admin</h1>
</div>
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)
**中文** | [English](./README.md) | [日本語](./README.ja-JP.md)
## 简介
Vue Vben Admin 是 Vue Vben Admin 的升级版本。作为一个免费开源的中后台模板,它采用了最新的 Vue 3、Vite、TypeScript 等主流技术开发,开箱即用,可用于中后台前端开发,也适合学习参考。
## 升级提示
该版本为最新版本`5.0`, 与其他版本不兼容,如果你是新项目,建议使用最新版本。如果你想查看旧版本,请使用 [v2 分支](https://github.com/vbenjs/vue-vben-admin/tree/v2)
## 特性
- **最新技术栈**:使用 Vue3/vite 等前端前沿技术开发
- **TypeScript**: 应用程序级 JavaScript 的语言
- **主题**:提供多套主题色彩,可配置自定义主题
- **国际化**:内置完善的国际化方案
- **权限** 内置完善的动态路由权限生成方案
## 预览
- [Vben Admin](https://vben.pro/) - 完整版中文站点
测试账号: vben/123456
<p align="center">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview1.png">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview2.png">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview3.png">
</p>
### 使用 Gitpod
在 Gitpod适用于 GitHub 的免费在线开发环境)中打开项目,并立即开始编码.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin)
## 文档
[文档地址](https://doc.vben.pro/)
## 安装使用
- 获取项目代码
```bash
git clone https://github.com/vbenjs/vue-vben-admin.git
```
- 安装依赖
```bash
cd vue-vben-admin
corepack enable
pnpm install
```
- 运行
```bash
pnpm dev
```
- 打包
```bash
pnpm build
```
## 如何贡献
非常欢迎你的加入![提一个 Issue](https://github.com/anncwb/vue-vben-admin/issues/new/choose) 或者提交一个 Pull Request。
**Pull Request:**
1. Fork 代码!
2. 创建自己的分支: `git checkout -b feature/xxxx`
3. 提交你的修改: `git commit -am 'feat(function): add xxxxx'`
4. 推送您的分支: `git push origin feature/xxxx`
5. 提交`pull request`
## Git 贡献提交规范
- 参考 [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 规范 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))
- `feat` 增加新功能
- `fix` 修复问题/BUG
- `style` 代码风格相关无影响运行结果的
- `perf` 优化/性能提升
- `refactor` 重构
- `revert` 撤销修改
- `test` 测试相关
- `docs` 文档/注释
- `chore` 依赖更新/脚手架配置修改等
- `ci` 持续集成
- `types` 类型定义文件更改
- `wip` 开发中
## 浏览器支持
本地开发推荐使用`Chrome 80+` 浏览器
支持现代浏览器, 不支持 IE
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| :-: | :-: | :-: | :-: | :-: |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 维护者
[@Vben](https://github.com/anncwb)
## 捐赠
如果你觉得这个项目对你有帮助,你可以帮作者买一杯咖啡表示支持!
![donate](https://unpkg.com/@vbenjs/static-source@0.1.6/source/sponsor.png)
<a style="display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aed;border-radius: 4px;" href="https://www.paypal.com/paypalme/cvvben">Paypal Me</a>
## 更新日志
[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)
## Contributor
<a href="https://github.com/vbenjs/vue-vben-admin/graphs/contributors">
<img alt="Contributors"
src="https://opencollective.com/vbenjs/contributors.svg?button=false" />
</a>
## Discord
- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions)
## License
[MIT © Vben-2020](./LICENSE)

View File

@ -1,139 +0,0 @@
/**
* Alova
* swagger生成对应的api调用函数
*/
export default {
// api生成设置数组每项代表一个自动生成的规则包含生成的输入输出目录、规范文件地址等等
generator: [
// 服务器1
{
// input参数1openapi的json文件url地址
input: 'http://127.0.0.1:4523/export/openapi/2?version=3.0',
// input参数2以当前项目为相对目录的本地地址
// input: 'openapi/api.json'
// input参数3没有直接指向openapi文件时是一个文档地址必须配合platform参数指定文档类型
// input: 'http://192.168.5.123:8080'
// 可选platform为支持openapi的平台目前只支持swagger默认为空
// 当指定了此参数后input字段只需要指定文档的地址而不需要指定到openapi文件
platform: 'swagger',
// 接口文件和类型文件的输出路径多个generator不能重复的地址否则生成的代码会相互覆盖
output: 'src/api',
// 可选指定生成的响应数据的mediaType以此数据类型来生成200状态码的响应ts格式默认application/json
responseMediaType: 'application/json',
// 可选指定生成的请求体数据的bodyMediaType以此数据类型来生成请求体的ts格式默认application/json
bodyMediaType: 'application/json',
// 可选指定生成的api版本默认为auto会通过当前项目安装的alova版本判断当前项目的版本如果生成不正确你也可以自定义指定版本
version: 'auto',
/**
* auto/ts/typescript/module/commonjsauto
* ts/typescriptts类型文件
* moduleesModule规范文件
* commonjscommonjs规范文件
*/
type: 'typescript',
/**
* api名称访api`Apis`generator时为必填
*/
global: 'Apis',
/**
* api接口函数apiDescriptor来生成api调用函数apiDescripor对象
*/
handleApi: (apiDescriptor, log) => {
// 返回falsy值表示过滤此api
// if (!apiDescriptor.path.startWith('/user')) {
// return;
// }
// apiDescriptor.parameter = apiDescriptor.parameter.filter(
// param => param.in === 'header' && param.name === 'token'
// );
// delete apiDescriptor.requestBody.id;
// apiDescriptor.url = '/app/rl' + apiDescriptor.url;
/**
*
* @param target -
* @param searchStrings -
* @returns
*/
const anyStringExistsInTarget = (target, searchStrings) => {
// 提前返回,如果搜索数组为空
if (searchStrings.length === 0) return false;
// 预处理目标字符串,确保只有一次字符串操作
const lowerCaseTarget = target.toLowerCase();
for (const searchString of searchStrings) {
if (lowerCaseTarget.includes(searchString.toLowerCase())) {
return true; // 只要有一个字符串匹配,立即返回 true
}
}
return false; // 所有字符串都不匹配,返回 false
}
// 接口包含某些参数的时候,需要生成
if (anyStringExistsInTarget(apiDescriptor.url, [
'/api/core', // 人员相关
])) {
apiDescriptor.url = '/uc' + apiDescriptor.url;
apiDescriptor.tags = ['user']
return apiDescriptor;
}
apiDescriptor.url = '/app/rl' + apiDescriptor.url;
if (anyStringExistsInTarget(apiDescriptor.url, [
'/ccsq', // 出差申请
'/meeting', '/addressor', // 会议
'/zbgl', // 值班
'/dish', '/orderfoods', '/recipe', // 订餐
'/officeSuppliesApply', '/officeSuppliesList', '/warehousing', '/inorout', // 办公
'/supervise', '/feedback' // 督察督办
])) {
apiDescriptor.tags = ['erp']
return apiDescriptor;
}
if (anyStringExistsInTarget(apiDescriptor.url, [
'/contractrefertype', // 合同类别
'/contractBaseInfo', //立项
'/selectMerchantsBasicInfo', // 选商
'/sbCtrBasePt',
'/proproviderinfo',
'/contractModelInfo'
])) {
apiDescriptor.tags = ['ht']
return apiDescriptor;
}
apiDescriptor.tags = ['common']
return apiDescriptor;
}
},
],
// 可选是否自动更新接口默认开启每5分钟检查一次false时关闭
autoUpdate: false
/*
autoUpdate: {
// 编辑器开启时更新默认false
launchEditor: true,
// 自动更新间隔,单位毫秒
interval: 5 * 60 * 1000
}
*/
};

5
apps/web-office/.env Normal file
View File

@ -0,0 +1,5 @@
# 应用标题
VITE_APP_TITLE=ERP协同办公系统
# 应用命名空间用于缓存、store等功能的前缀确保隔离
VITE_APP_NAMESPACE=erp-office

View File

@ -0,0 +1,7 @@
# public path
VITE_BASE=/
# Basic interface address SPA
VITE_GLOB_API_URL=/api
VITE_VISUALIZER=true

View File

@ -0,0 +1,16 @@
# 端口号
VITE_PORT=5666
VITE_BASE=/
# 接口地址
VITE_GLOB_API_URL=/api
# 是否开启 Nitro Mock服务true 为开启false 为关闭
VITE_NITRO_MOCK=true
# 是否打开 devtoolstrue 为打开false 为关闭
VITE_DEVTOOLS=false
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true

View File

@ -0,0 +1,16 @@
VITE_BASE=/
# 接口地址
VITE_GLOB_API_URL=/api
# 是否开启压缩,可以设置为 none, brotli, gzip
VITE_COMPRESS=none
# 是否开启 PWA
VITE_PWA=false
# vue-router 的模式
VITE_ROUTER_HISTORY=history
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true

View File

@ -0,0 +1,34 @@
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta name="description" content="Erp Management System" />
<meta name="keywords" content="erp" />
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
/>
<!-- 由 vite 注入 VITE_APP_TITLE 变量,在 .env 文件内配置 -->
<title><%= VITE_APP_TITLE %></title>
<link rel="icon" href="/favicon.ico" />
<script>
// 生产环境下注入百度统计
if (window._VBEN_ADMIN_PRO_APP_CONF_) {
var _hmt = _hmt || [];
(function () {
var hm = document.createElement('script');
hm.src =
'https://hm.baidu.com/hm.js?b38e689f40558f20a9a686d7f6f33edf';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(hm, s);
})();
}
</script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@ -0,0 +1,77 @@
{
"name": "web-office",
"version": "5.1.2",
"homepage": "https://vben.pro",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
"type": "git",
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
"directory": "apps/web-antd"
},
"license": "MIT",
"author": {
"name": "vben",
"email": "ann.vben@gmail.com",
"url": "https://github.com/anncwb"
},
"type": "module",
"scripts": {
"build": "pnpm vite build --mode production",
"build:analyze": "pnpm vite build --mode analyze",
"dev": "pnpm vite --mode development",
"dev:prod": "pnpm vite --mode production",
"preview": "vite preview",
"typecheck": "vue-tsc --noEmit --skipLibCheck"
},
"imports": {
"#/*": "./src/*"
},
"dependencies": {
"@fast-crud/fast-crud": "^1.21.2",
"@fast-crud/fast-extends": "^1.21.2",
"@fast-crud/ui-antdv4": "^1.21.2",
"@fast-crud/ui-interface": "^1.21.2",
"@vben-core/shadcn-ui": "workspace:*",
"@vben/access": "workspace:*",
"@vben/common-ui": "workspace:*",
"@vben/constants": "workspace:*",
"@vben/hooks": "workspace:*",
"@vben/icons": "workspace:*",
"@vben/layouts": "workspace:*",
"@vben/locales": "workspace:*",
"@vben/plugins": "workspace:*",
"@vben/preferences": "workspace:*",
"@vben/request": "workspace:*",
"@vben/stores": "workspace:*",
"@vben/styles": "workspace:*",
"@vben/types": "workspace:*",
"@vben/utils": "workspace:*",
"@vueuse/core": "^11.0.3",
"alova": "^3.0.14",
"ant-design-vue": "^4.2.3",
"big.js": "^6.2.1",
"dayjs": "^1.11.13",
"exceljs": "^4.4.0",
"lodash-es": "^4.17.21",
"pinia": "2.2.2",
"pinia-plugin-persistedstate": "^3.2.1",
"sortablejs": "^1.15.2",
"tyme4ts": "^1.1.2",
"vue": "^3.4.38",
"vue-router": "^4.4.3",
"vxe-pc-ui": "^4.1.12",
"vxe-table": "^4.7.74",
"vxe-table-plugin-antd": "^4.0.8",
"vxe-table-plugin-export-xlsx": "^4.0.2",
"xe-utils": "^3.5.30"
},
"devDependencies": {
"@types/big.js": "^6.2.2",
"@types/lodash-es": "^4.17.12",
"sass": "^1.77.8",
"typescript": "^5.5.4",
"unplugin-auto-import": "^0.18.2",
"unplugin-vue-components": "^0.27.4",
"vite-plugin-lazy-import": "^1.0.7"
}
}

View File

@ -0,0 +1 @@
export { default } from '@vben/tailwind-config/postcss';

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -0,0 +1,3 @@
pnpm i @fast-crud/fast-crud
pnpm i @fast-crud/fast-extends
pnpm i @fast-crud/ui-interface

View File

@ -0,0 +1,73 @@
import { baseRequestClient, requestClient } from '#/api/request/index';
export namespace AuthApi {
/** 登录接口参数 */
export interface LoginParams {
password: string;
username: string;
}
/** 登录接口返回值 */
export interface LoginResult {
accessToken: string;
desc: string;
realName: string;
userId: string;
username: string;
}
export interface RefreshTokenResult {
data: string;
status: number;
}
}
/**
*
*/
export async function loginApi(data: AuthApi.LoginParams) {
return requestClient.post<AuthApi.LoginResult>(
'/uc/uaa/validateAccount',
data,
{
transformResponse: (res) => {
res = JSON.parse(res);
console.log(res);
const info = res.data;
if (info) {
info.accessToken = info.access_token;
info.realName = info.display_name;
return info
}
return res;
},
},
);
}
/**
* accessToken
*/
export async function refreshTokenApi() {
return baseRequestClient.post<AuthApi.RefreshTokenResult>('/auth/refresh', {
withCredentials: true,
});
}
/**
* 退
*/
export async function logoutApi() {
return baseRequestClient.post('/uc/uaa/logout', {
withCredentials: true,
});
}
/**
*
*/
export async function getAccessCodesApi() {
return requestClient.get<string[]>('/auth/codes');
}

View File

@ -0,0 +1,3 @@
export * from './auth';
export * from './menu';
export * from './user';

View File

@ -0,0 +1,10 @@
import type { RouteRecordStringComponent } from '@vben/types';
import { requestClient } from '#/api/request/index';
/**
*
*/
export async function getAllMenusApi() {
return requestClient.get<RouteRecordStringComponent[]>('/menu/all');
}

View File

@ -0,0 +1,15 @@
import type { UserInfo } from '@vben/types';
import { useAccessStore } from '@vben/stores';
import { requestClient } from '#/api/request/index';
/**
*
*/
export async function getUserInfoApi() {
const accessStore = useAccessStore();
return requestClient.post<UserInfo>('/uc/sys/user/checkToken', {
token: accessStore.accessToken,
});
}

22
apps/web-office/src/api/global.d.ts vendored Normal file
View File

@ -0,0 +1,22 @@
export interface QueryOptions {
params?: AnyObject;
pathParams?: AnyObject;
config?: AnyObject;
}
export interface BodyOptions {
params?: AnyObject;
data?: AnyObject;
pathParams?: AnyObject;
config?: AnyObject;
}
export interface RequestOptions {
url: string;
data?: QueryOptions;
}
export interface MutationOptions {
url: string;
data?: BodyOptions;
}

View File

@ -0,0 +1,509 @@
import { http } from "./request/index"
import type { QueryOptions, BodyOptions } from "./global.d"
export default {
meeting: {
/** 协同办公/会议管理 分页查询 */
get_page: (data?: QueryOptions) => http.get("/app/meeting/page", data),
/** 协同办公/会议管理 删除会议 */
post_deletes: (data?: BodyOptions) => http.post("/app/meeting/deletes", data),
/** 协同办公/会议管理 会议保存 */
post_save: (data?: BodyOptions) => http.post("/app/meeting/save", data),
/** 协同办公/会议管理 查看会议台账 */
get_list: (data?: QueryOptions) => http.get("/app/meeting/list", data),
list: {
/** 协同办公/会议管理 会议台账导出 */
get_export: (data?: QueryOptions) => http.get("/app/meeting/list/export", data),
},
},
tysq: {
zzjg: {
yhjbda: {
YhjbdaController: {
/** 统一授权 未命名接口 */
get_yhjbdaGrid: (data?: QueryOptions) => http.get("/app/tysq/zzjg/yhjbda/YhjbdaController/yhjbdaGrid", data),
},
},
},
},
dictType: {
/** 协同办公/字典表 字典类型查询 */
get_list: (data?: QueryOptions) => http.get("/app/dictType/list", data),
/** 协同办公/字典表 字典类型保存 */
post_save: (data?: BodyOptions) => http.post("/app/dictType/save", data),
/** 协同办公/字典表 字典类型删除 */
post_delete: (data?: BodyOptions) => http.post("/app/dictType/deletes", data),
},
uaa: {
/** 用户中心 用户登陆 Copy */
post_validateAccount: (data?: BodyOptions) => http.post("/uc/uaa/validateAccount", data),
},
api: {
core: {
orgemplbc: {
employee: {
/** 用户中心 获取用户信息(分页) */
post_paging: (data?: BodyOptions) => http.post("/uc/api/core/orgemplbc/employee/paging", data),
},
organization: {
RL: {
/** 用户中心 根据组织机构id获取员工信息 */
get_employee: (data?: QueryOptions) => http.get("/uc/api/core/orgemplbc/organization/RL/employee", data),
},
/** 用户中心 获取组织结构信息 */
post_paging: (data?: BodyOptions) => http.post("/uc/api/core/orgemplbc/organization/paging", data),
},
/** 用户中心 根据组织机构id和用户信息查询 */
post_employee: (data?: BodyOptions) => http.post("/uc/api/core/orgemplbc/employee", data),
},
},
},
sys: {
user: {
/** 用户中心 根据token获取用户信息 */
post_checkToken: (data?: BodyOptions) => http.post("/uc/sys/user/checkToken", data),
functiontree: {
/** 用户中心 获取菜单接口 */
get_XTBGXT: (data?: QueryOptions) => http.get("/uc/sys/user/functiontree/XTBGXT", data),
/** 统一授权 未命名接口 */
get_PLRL: (data?: QueryOptions) => http.get("/uc/sys/user/functiontree/PLRL", data),
},
},
},
zbgl: {
/** 协同办公/值班管理 值班查询 */
get_queryZbInfo: (data?: QueryOptions) => http.get("/app/zbgl/queryZbInfo", data),
/** 协同办公/值班管理 保存值班信息 */
post_save: (data?: BodyOptions) => http.post("/app/zbgl/save", data),
/** 协同办公/值班管理 删除值班信息 */
get_deletes: (data?: QueryOptions) => http.get("/app/zbgl/deletes", data),
/** 协同办公/值班管理 导入值班人员信息 */
post_importZbry: (data?: BodyOptions) => http.post("/app/zbgl/importZbry", data),
/** 协同办公/值班管理 门户值班信息查询 */
get_getDutyInfo: (data?: QueryOptions) => http.get("/app/zbgl/getDutyInfo", data),
/** 协同办公/值班管理 导出 */
post_export: (data?: BodyOptions) => http.post("/app/zbgl/export", data),
},
dictData: {
/** 协同办公/字典表 字典数据保存 */
post_save: (data?: BodyOptions) => http.post("/app/dictData/save", data),
/** 合同系统/项目管理 保存 */
get_save: (data?: QueryOptions) => http.get("/app/dictData/save", data),
/** 合同系统/项目名称管理 查询 */
get_page: (data?: QueryOptions) => http.get("/app/dictData/page", data),
/** 协同办公/字典表 字典数据删除 */
post_deletes: (data?: BodyOptions) => http.post("/app/dictData/deletes", data),
/** 合同系统/项目管理 删除 */
get_deletes: (data?: QueryOptions) => http.get("/app/dictData/deletes", data),
},
user: {
/** 统一授权 获取用户列表 */
get_page: (data?: QueryOptions) => http.get("/app/user/page", data),
},
dish: {
/** 协同办公/订餐管理/菜谱管理 菜谱查询 */
get_page: (data?: QueryOptions) => http.get("/app/dish/page", data),
/** 协同办公/订餐管理/菜谱管理 菜谱保存 */
post_save: (data?: BodyOptions) => http.post("/app/dish/save", data),
/** 协同办公/订餐管理/食谱管理 菜谱删除 */
post_deletes: (data?: BodyOptions) => http.post("/app/dish/deletes", data),
},
recipe: {
/** 协同办公/订餐管理/食谱管理 食谱查询 */
get_page: (data?: QueryOptions) => http.get("/app/recipe/page", data),
/** 协同办公/订餐管理/食谱管理 食谱保存 */
post_save: (data?: BodyOptions) => http.post("/app/recipe/save", data),
/** 协同办公/订餐管理/食谱管理 食谱导出 */
get_export: (data?: QueryOptions) => http.get("/app/recipe/export", data),
/** 协同办公/订餐管理/食谱管理 批量保存 */
post_saveBatch: (data?: BodyOptions) => http.post("/app/recipe/saveBatch", data),
/** 协同办公/订餐管理/食谱管理 食谱编辑 */
post_edit: (data?: BodyOptions) => http.post("/app/recipe/edit", data),
},
ccsq: {
/** 协同办公/出差申请 出差申请查询 */
get_page: (data?: QueryOptions) => http.get("/app/ccsq/page", data),
/** 协同办公/出差申请 申请单保存 */
post_save: (data?: BodyOptions) => http.post("/app/ccsq/save", data),
/** 协同办公/出差申请 申请单删除 */
post_deletes: (data?: BodyOptions) => http.post("/app/ccsq/deletes", data),
/** 协同办公/出差申请 出差送审、审核 */
post_audit: (data?: BodyOptions) => http.post("/app/ccsq/audit", data),
/** 协同办公/出差申请 退回 */
post_turnTask: (data?: BodyOptions) => http.post("/app/ccsq/turnTask", data),
/** 协同办公/出差申请 启动流程 */
post_startWorkFlow: (data?: BodyOptions) => http.post("/app/ccsq/startWorkFlow", data),
/** 协同办公/出差申请 送审 */
post_submit: (data?: BodyOptions) => http.post("/app/ccsq/submit", data),
/** 协同办公/出差申请 待办 */
get_toDoPage: (data?: QueryOptions) => http.get("/app/ccsq/toDoPage", data),
/** 协同办公/出差申请 已办 */
get_donePage: (data?: QueryOptions) => http.get("/app/ccsq/donePage", data),
/** 协同办公/出差申请 获取可退回节点信息 */
get_getBackNode: (data?: QueryOptions) => http.get("/app/ccsq/getBackNode", data),
},
orderfood: {
/** 协同办公/订餐管理/订餐 订餐加载接口 */
get_getOne: (data?: QueryOptions) => http.get("/app/orderfood/getOne", data),
/** 协同办公/订餐管理/订餐 订餐保存 */
post_save: (data?: BodyOptions) => http.post("/app/orderfood/save", data),
/** 协同办公/订餐管理/订餐 取消订餐 */
post_cancel: (data?: BodyOptions) => http.post("/app/orderfood/cancel", data),
/** 协同办公/订餐管理/订餐 协助取消他人订餐 */
post_assistCancel: (data?: BodyOptions) => http.post("/app/orderfood/assistCancel", data),
},
orderfoods: {
/** 协同办公/订餐管理/汇总 部门结算汇总 */
get_departmentSummary: (data?: QueryOptions) => http.get("/app/orderfoods/departmentSummary", data),
/** 协同办公/订餐管理/汇总 订餐汇总 */
get_infoList: (data?: QueryOptions) => http.get("/app/orderfoods/infoList", data),
/** 协同办公/订餐管理/汇总 个人结算汇总 */
get_personalSummary: (data?: QueryOptions) => http.get("/app/orderfoods/personalSummary", data),
infoList: {
/** 协同办公/订餐管理/汇总 订餐汇总导出 */
get_export: (data?: QueryOptions) => http.get("/app/orderfoods/infoList/export", data),
},
personalSummary: {
/** 协同办公/订餐管理/汇总 个人结算汇总导出 */
get_export: (data?: QueryOptions) => http.get("/app/orderfoods/personalSummary/export", data),
},
departmentSummary: {
/** 协同办公/订餐管理/汇总 部门结算汇总导出 */
get_export: (data?: QueryOptions) => http.get("/app/orderfoods/departmentSummary/export", data),
},
/** 协同办公/订餐管理/汇总 结算单 */
get_finalStatement: (data?: QueryOptions) => http.get("/app/orderfoods/finalStatement", data),
finalStatement: {
/** 协同办公/订餐管理/汇总 结算表导出 */
get_export: (data?: QueryOptions) => http.get("/app/orderfoods/finalStatement/export", data),
},
/** 协同办公/订餐管理/汇总 结算操作 */
post_balance: (data?: BodyOptions) => http.post("/app/orderfoods/balance", data),
},
officeSuppliesApply: {
/** 协同办公/办公用品/办公用品申请 申请页面查询 */
get_page: (data?: QueryOptions) => http.get("/app/officeSuppliesApply/page", data),
/** 协同办公/办公用品/办公用品申请 申请保存 */
post_save: (data?: BodyOptions) => http.post("/app/officeSuppliesApply/save", data),
/** 协同办公/办公用品/办公用品申请 批量审核 */
post_audit: (data?: BodyOptions) => http.post("/app/officeSuppliesApply/audit", data),
/** 协同办公/办公用品/办公用品申请 批量申请 */
post_saveBatch: (data?: BodyOptions) => http.post("/app/officeSuppliesApply/saveBatch", data),
/** 协同办公/办公用品/办公用品申请 撤销申请 */
post_deletes: (data?: BodyOptions) => http.post("/app/officeSuppliesApply/deletes", data),
},
warehousing: {
/** 协同办公/办公用品/入库/出库 入库查询 */
get_page: (data?: QueryOptions) => http.get("/app/warehousing/page", data),
},
inOrOut: {
/** 协同办公/办公用品/入库/出库 入库/保存 */
post_saveBatch: (data?: BodyOptions) => http.post("/app/inOrOut/saveBatch", data),
},
supervise: {
/** 协同办公/督查督办/立项发起 立项分页查询 */
get_page: (data?: QueryOptions) => http.get("/app/supervise/page", data),
/** 协同办公/督查督办/立项发起 立项保存 */
post_save: (data?: BodyOptions) => http.post("/app/supervise/save", data),
/** 协同办公/督查督办/立项发起 立项删除 */
post_deletes: (data?: BodyOptions) => http.post("/app/supervise/deletes", data),
/** 协同办公/督查督办/立项发起 立项提交 */
post_audit: (data?: BodyOptions) => http.post("/app/supervise/audit", data),
/** 协同办公/督查督办/执行反馈 执行反馈提交 */
post_auditFankui: (data?: BodyOptions) => http.post("/app/supervise/auditFankui", data),
/** 协同办公/督查督办/报表汇总 统计 */
get_huizong: (data?: QueryOptions) => http.get("/app/supervise/huizong", data),
/** 协同办公/督查督办/立项发起 更新状态 */
post_updateStatus: (data?: BodyOptions) => http.post("/app/supervise/updateStatus", data),
},
feedback: {
/** 协同办公/督查督办/执行反馈 执行反馈待办查询 */
get_page: (data?: QueryOptions) => http.get("/app/feedback/page", data),
/** 协同办公/督查督办/执行反馈 执行反馈保存,实际修改操作,保存反馈时间,反馈内容,进度 */
post_saveUpdate: (data?: BodyOptions) => http.post("/app/feedback/saveUpdate", data),
/** 协同办公/督查督办/执行反馈 查询负责部门列表,返回所有的反馈信息 */
get_getDepartment: (data?: QueryOptions) => http.get("/app/feedback/getDepartment", data),
/** 协同办公/督查督办/执行反馈 分发立项任务 */
post_save: (data?: BodyOptions) => http.post("/app/feedback/save", data),
/** 协同办公/督查督办/执行反馈 执行反馈已办查询 */
get_pageDone: (data?: QueryOptions) => http.get("/app/feedback/pageDone", data),
},
file: {
/** 协同办公/文件上传/下载 多文件上传 */
post_uploads: (data?: BodyOptions) => http.post("/app/file/uploads", data),
},
addressor: {
/** 协同办公/会议管理/发言人 发言人查询 */
get_list: (data?: QueryOptions) => http.get("/app/addressor/list", data),
/** 协同办公/会议管理/发言人 发言人批量保存 */
post_saveBatch: (data?: BodyOptions) => http.post("/app/addressor/saveBatch", data),
/** 协同办公/会议管理/发言人 发言人保存 */
post_save: (data?: BodyOptions) => http.post("/app/addressor/save", data),
post_deletes: (data?: BodyOptions) => http.post("/app/addressor/deletes", data),
},
officeSuppliesList: {
/** 协同办公/办公用品/办公用品清单 分页查询 */
get_page: (data?: QueryOptions) => http.get("/app/officeSuppliesList/page", data),
/** 协同办公/办公用品/办公用品清单 批量保存 */
post_saveBatch: (data?: BodyOptions) => http.post("/app/officeSuppliesList/saveBatch", data),
post_deletes: (data?: BodyOptions) => http.post("/app/officeSuppliesList/deletes", data),
},
officeSuppliesApplySum: {
/** 协同办公/办公用品 采购汇总 */
get_list: (data?: QueryOptions) => http.get("/app/officeSuppliesApplySum/list", data),
},
autoOrderfoodPeoples: {
/** 协同办公/订餐管理/自动订餐人员管理 分页查询 */
get_page: (data?: QueryOptions) => http.get("/app/autoOrderfoodPeoples/page", data),
/** 协同办公/订餐管理/自动订餐人员管理 批量保存 */
post_saveBatch: (data?: BodyOptions) => http.post("/app/autoOrderfoodPeoples/saveBatch", data),
post_deletes: (data?: BodyOptions) => http.post("/app/autoOrderfoodPeoples/deletes", data),
},
usercenter: {
/** 协同办公 获取菜单 */
get_menus: (data?: QueryOptions) => http.get("/app/usercenter/menus", data),
},
workflow: {
/** 协同办公/工作流 待办 */
post_queryMyTodoTask: (data?: BodyOptions) => http.post("/app/workflow/queryMyTodoTask", data),
/** 协同办公/工作流 已办 */
post_getHistoricTaskByUserID: (data?: BodyOptions) => http.post("/app/workflow/getHistoricTaskByUserID", data),
},
personTask: {
/** 合同系统/签订 待办查询 */
get_page: (data?: QueryOptions) => http.get("/app/personTask/page", data),
/** 合同系统/签订 已办查询 */
get_pagePersonTaskOver: (data?: QueryOptions) => http.get("/app/personTask/pagePersonTaskOver", data),
/** 合同系统/履行/履行查询 分页合同履行审批查询 */
get_pagePerformanceAudit: (data?: QueryOptions) => http.get("/app/personTask/pagePerformanceAudit", data),
/** 合同系统/履行/履行提示/申请归档 归档保存 */
post_applicationFiling: (data?: BodyOptions) => http.post("/app/personTask/applicationFiling", data),
},
sbCtrBasePt: {
/** 合同系统/申报 合同申报数据查询 */
get_QuerySbCtrBase: (data?: QueryOptions) => http.get("/app/sbCtrBasePt/QuerySbCtrBase", data),
/** 合同系统/申报 合同申报基本信息加载 */
post_page: (data?: BodyOptions) => http.post("/app/sbCtrBasePt/page", data),
/** 合同系统/申报 合同申报基本信息保存 */
post_save: (data?: BodyOptions) => http.post("/app/sbCtrBasePt/save", data),
/** 合同系统/申报 合同申报基本信息删除 */
get_deletes: (data?: QueryOptions) => http.get("/app/sbCtrBasePt/deletes", data),
/** 合同系统/申报 获取资金渠道 */
get_getFundingSource: (data?: QueryOptions) => http.get("/app/sbCtrBasePt/getFundingSource", data),
},
contractBaseInfo: {
/** 合同系统/立项 合同立项保存 */
post_apply: (data?: BodyOptions) => http.post("/app/contractBaseInfo/apply", data),
/** 合同系统/立项 合同立项查询 */
get_page: (data?: QueryOptions) => http.get("/app/contractBaseInfo/page", data),
/** 合同系统/立项 删除 */
post_deletes: (data?: BodyOptions) => http.post("/app/contractBaseInfo/deletes", data),
/** 合同系统/立项 单条查询 */
get_getOne: (data?: QueryOptions) => http.get("/app/contractBaseInfo/getOne", data),
/** 合同系统/立项 提交 */
post_submit: (data?: BodyOptions) => http.post("/app/contractBaseInfo/submit", data),
/** 合同系统/立项 退回 */
post_rollback: (data?: BodyOptions) => http.post("/app/contractBaseInfo/rollback", data),
},
proProviderInfo: {
/** 合同系统/相对人管理 合同相对人查询 */
get_Query: (data?: QueryOptions) => http.get("/app/proProviderInfo/Query", data),
/** 合同系统/相对人管理 获取币种 */
get_getBz: (data?: QueryOptions) => http.get("/app/proProviderInfo/getBz", data),
/** 合同系统/相对人管理 保存 */
post_save: (data?: BodyOptions) => http.post("/app/proProviderInfo/save", data),
/** 合同系统/相对人管理 删除 */
get_deletes: (data?: QueryOptions) => http.get("/app/proProviderInfo/deletes", data),
/** 合同系统/相对人管理 加载 */
post_page: (data?: BodyOptions) => http.post("/app/proProviderInfo/page", data),
},
contractModelInfo: {
/** 合同系统/模板管理 保存 */
post_save: (data?: BodyOptions) => http.post("/app/contractModelInfo/save", data),
/** 合同系统/模板管理 删除 */
get_deletes: (data?: QueryOptions) => http.get("/app/contractModelInfo/deletes", data),
/** 合同系统/模板管理 加载 */
post_page: (data?: BodyOptions) => http.post("/app/contractModelInfo/page", data),
},
contractReferType: {
/** 合同系统/合同类型参照 查询 */
get_list: (data?: QueryOptions) => http.get("/app/contractReferType/list", data),
/** 合同系统/合同类型参照 保存 */
post_save: (data?: BodyOptions) => http.post("/app/contractReferType/save", data),
/** 合同系统/合同类型参照 删除 */
post_deletes: (data?: BodyOptions) => http.post("/app/contractReferType/deletes", data),
},
attachment: {
/** 文件上传/下载(新) 附件加载 */
get_list: (data?: QueryOptions) => http.get("/app/attachment/list", data),
/** 文件上传/下载(新) 文件下载 */
get_download: (data?: QueryOptions) => http.get("/app/attachment/download/{fileUuid}", data),
/** 文件上传/下载(新) 多文件上传 */
post_uploads: (data?: BodyOptions) => http.post("/app/attachment/uploads", data),
},
contractPayment: {
/** 合同系统/履行/履行提示/合同付款 获取合同付款信息 */
get_queryPaymentInfo: (data?: QueryOptions) => http.get("/app/contractPayment/queryPaymentInfo", data),
/** 合同系统/归档/合同归档 历史记录 */
get_historyPaymentInfo: (data?: QueryOptions) => http.get("/app/contractPayment/historyPaymentInfo", data),
/** 合同系统/履行/履行提示/合同付款 保存付款申请 */
post_save: (data?: BodyOptions) => http.post("/app/contractPayment/save", data),
},
selectMerchantsBasicInfo: {
/** 合同系统/选商 分页查询 */
get_page: (data?: QueryOptions) => http.get("/app/selectMerchantsBasicInfo/page", data),
/** 合同系统/选商 选商信息查询(单条) */
get_getOne: (data?: QueryOptions) => http.get("/app/selectMerchantsBasicInfo/getOne", data),
/** 合同系统/选商 选商信息保存 */
post_save: (data?: BodyOptions) => http.post("/app/selectMerchantsBasicInfo/save", data),
/** 合同系统/选商 合同选商保存操作(多个对象) */
post_saveMultiEntity: (data?: BodyOptions) => http.post("/app/selectMerchantsBasicInfo/saveMultiEntity", data),
/** 合同系统/选商 提交 */
post_submit: (data?: BodyOptions) => http.post("/app/selectMerchantsBasicInfo/submit", data),
/** 合同系统/选商 退回 */
post_rollback: (data?: BodyOptions) => http.post("/app/selectMerchantsBasicInfo/rollback", data),
},
lvxChange: {
/** 合同系统/履行/履行提示/合同变更 保存合同变更申请 */
post_save: (data?: BodyOptions) => http.post("/app/lvxChange/save", data),
/** 合同系统/履行/履行提示/合同变更 获取合同变更信息 */
get_getContractChangeInfo: (data?: QueryOptions) => http.get("/app/lvxChange/getContractChangeInfo", data),
},
contractRelieve: {
/** 合同系统/履行/履行提示/合同终止(解除) 获取合同终止(解除)信息 */
get_getContractRelieveInfo: (data?: QueryOptions) => http.get("/app/contractRelieve/getContractRelieveInfo", data),
/** 合同系统/履行/履行提示/合同终止(解除) 保存合同终止信息 */
post_save: (data?: BodyOptions) => http.post("/app/contractRelieve/save", data),
},
contractBreach: {
/** 合同系统/履行/履行提示/合同违约情况 保存合同违约信息 */
post_save: (data?: BodyOptions) => http.post("/app/contractBreach/save", data),
/** 合同系统/履行/履行提示/合同违约情况 获取合同违约信息 */
get_getContractBreachInfo: (data?: QueryOptions) => http.get("/app/contractBreach/getContractBreachInfo", data),
},
lvxResult: {
/** 合同系统/履行/履行结果 履行结果保存 */
post_save: (data?: BodyOptions) => http.post("/app/lvxResult/save", data),
},
contractFiling: {
/** 合同系统/履行/履行提示/临时归档 保存临时归档信息 */
post_save: (data?: BodyOptions) => http.post("/app/contractFiling/save", data),
},
biddingExpert: {
/** 合同系统/选商/选商招标专家 招标专家查询 */
get_list: (data?: QueryOptions) => http.get("/app/biddingExpert/list", data),
/** 合同系统/选商/选商招标专家 选商招标专家保存 */
post_saveBatch: (data?: BodyOptions) => http.post("/app/biddingExpert/saveBatch", data),
/** 合同系统/选商/选商招标专家 选商招标专家删除 */
post_deletes: (data?: BodyOptions) => http.post("/app/biddingExpert/deletes", data),
},
contractFilingFormal: {
/** 合同系统/归档/合同归档 分页查询归档信息 */
get_queryContractFiling: (data?: QueryOptions) => http.get("/app/contractFilingFormal/queryContractFiling", data),
/** 合同系统/归档/合同归档 获取合同招标选商申请信息 */
get_getContractSupplier: (data?: QueryOptions) => http.get("/app/contractFilingFormal/getContractSupplier", data),
/** 合同系统/归档/合同归档 保存合同归档 */
post_save: (data?: BodyOptions) => http.post("/app/contractFilingFormal/save", data),
/** 合同系统/归档/合同回档 分页查询 */
get_pageArchivedContract: (data?: QueryOptions) => http.get("/app/contractFilingFormal/pageArchivedContract", data),
/** 合同系统/归档/合同回档 回档 */
post_saveFilingBack: (data?: BodyOptions) => http.post("/app/contractFilingFormal/saveFilingBack", data),
},
lvxProduct: {
/** 合同系统/履行/履行提示/产品或服务 获取合同产品信息 */
get_getContractProductInfo: (data?: QueryOptions) => http.get("/app/lvxProduct/getContractProductInfo", data),
/** 合同系统/履行/履行提示/产品或服务 累计收款金额 */
get_getSumFromProduct: (data?: QueryOptions) => http.get("/app/lvxProduct/getSumFromProduct", data),
/** 合同系统/履行/履行提示/产品或服务 历史记录 */
get_getListFromHistoryRecord: (data?: QueryOptions) => http.get("/app/lvxProduct/getListFromHistoryRecord", data),
/** 合同系统/履行/履行提示/产品或服务 保存合同产品服务 */
post_save: (data?: BodyOptions) => http.post("/app/lvxProduct/save", data),
},
qdSign: {
/** 合同系统/签订 签订查询 */
get_page: (data?: QueryOptions) => http.get("/app/qdSign/page", data),
/** 合同系统/签订 获取合同签订信息 */
get_getContractSignInfo: (data?: QueryOptions) => http.get("/app/qdSign/getContractSignInfo", data),
/** 合同系统/签订 打印签订审批表 */
get_createUserListWord: (data?: QueryOptions) => http.get("/app/qdSign/createUserListWord", data),
/** 合同系统/签订 打印文本 */
get_textPrint: (data?: QueryOptions) => http.get("/app/qdSign/textPrint", data),
/** 合同系统/签订 保存送审 */
post_save: (data?: BodyOptions) => http.post("/app/qdSign/save", data),
/** 合同系统/签订 废除 */
post_abolish: (data?: BodyOptions) => http.post("/app/qdSign/abolish", data),
},
flowCenter: {
/** 流程中心 启动流程 */
post_start: (data?: BodyOptions) => http.post("/app/flowCenter/start", data),
/** 流程中心 审核通过 */
post_agree: (data?: BodyOptions) => http.post("/app/flowCenter/agree", data),
/** 流程中心 审核退回 */
post_rollback: (data?: BodyOptions) => http.post("/app/flowCenter/rollback", data),
/** 流程中心 获取待办 */
post_getTodoList: (data?: BodyOptions) => http.post("/app/flowCenter/getTodoList", data),
/** 流程中心 获取已办 */
post_doneList: (data?: BodyOptions) => http.post("/app/flowCenter/doneList", data),
/** 流程中心 审核撤回 */
get_revoke: (data?: QueryOptions) => http.get("/app/flowCenter/revoke", data),
/** 流程中心 审核记录 */
get_history: (data?: QueryOptions) => http.get("/app/flowCenter/history", data),
/** 流程中心 查看流程图 */
get_getFlowImg: (data?: QueryOptions) => http.get("/app/flowCenter/getFlowImg", data),
/** 流程中心 获取可退回节点 */
get_getReturnNode: (data?: QueryOptions) => http.get("/app/flowCenter/getReturnNode", data),
/** 流程中心 获取流程节点人员配置信息 */
get_getNextNodeUserConfig: (data?: QueryOptions) => http.get("/app/flowCenter/getNextNodeUserConfig", data),
/** 流程中心 获取待办数量 */
get_getTodoListSize: (data?: QueryOptions) => http.get("/app/flowCenter/getTodoListSize", data),
/** 流程中心 获取当前审核节点配置信息 */
get_getNodeConfigInfo: (data?: QueryOptions) => http.get("/app/flowCenter/getNodeConfigInfo", data),
/** 流程中心 获取下一节点配置信息 */
get_getNextNodeConfig: (data?: QueryOptions) => http.get("/app/flowCenter/getNextNodeConfig", data),
/** 流程中心 获取流程节点人员配置信息 */
post_getFlowNodeUserConfig: (data?: BodyOptions) => http.post("/app/flowCenter/getFlowNodeUserConfig", data),
},
rl: {
moduleParameter: {
/** 流程中心/流程规划 保存 */
post_save: (data?: BodyOptions) => http.post("/app/rl/moduleParameter/save", data),
/** 流程中心/流程规划 查询 */
post_page: (data?: BodyOptions) => http.post("/app/rl/moduleParameter/page", data),
/** 流程中心/流程规划 删除 */
get_deletes: (data?: QueryOptions) => http.get("/app/rl/moduleParameter/deletes", data),
/** 流程中心/流程规划 获取节点审核人 */
get_getNextNodeUser: (data?: QueryOptions) => http.get("/app/rl/moduleParameter/getNextNodeUser", data),
},
},
dutyCount: {
/** 协同办公/订餐管理/值班天数 分页查询 */
get_page: (data?: QueryOptions) => http.get("/app/dutyCount/page", data),
/** 协同办公/订餐管理/值班天数 批量保存 */
post_saveBatch: (data?: BodyOptions) => http.post("/app/dutyCount/saveBatch", data),
/** 协同办公/订餐管理/值班天数 删除 */
post_deletes: (data?: BodyOptions) => http.post("/app/dutyCount/deletes", data),
},
common: {
/** 公共 获取请求ip */
get_getClientIp: (data?: QueryOptions) => http.get("/app/common/getClientIp", data),
},
address: {
/** 协同办公/订餐管理/订餐地址 查询(分页) */
get_page: (data?: QueryOptions) => http.get("/app/address/page", data),
/** 协同办公/订餐管理/订餐地址 保存 */
post_save: (data?: BodyOptions) => http.post("/app/address/save", data),
/** 协同办公/订餐管理/订餐地址 删除 */
post_deletes: (data?: BodyOptions) => http.post("/app/address/deletes", data),
},
superviseFeedbackRecord: {
/** 协同办公/督查督办/反馈记录 保存反馈记录 */
post_save: (data?: BodyOptions) => http.post("/app/superviseFeedbackRecord/save", data),
/** 协同办公/督查督办/反馈记录 查询反馈记录 */
get_page: (data?: QueryOptions) => http.get("/app/superviseFeedbackRecord/page", data),
/** 协同办公/督查督办/反馈记录 删除反馈记录 */
post_deletes: (data?: BodyOptions) => http.post("/app/superviseFeedbackRecord/deletes", data),
},
}

View File

@ -1,6 +1,6 @@
/** BaseUrl: 基础路径 */
const BASE_URL: string = '/proxy-adm'
const BASE_URL: string = '/api'
/** AccessTokenField: header 里传accessToken的键名,一般为 Authorization */
export const ACCESS_TOKEN_FIELD = 'Token'

View File

@ -4,10 +4,9 @@
* @description:
*/
import { createAlova } from 'alova'
import { useUserStore } from '@/store/modules/user'
import { useAccessStore } from '@vben/stores';
import fetchAdapter from 'alova/fetch';
import vueHook from 'alova/vue';
import { ResultEnum } from '@/enums/httpEnum'
import { getBaseURL, ACCESS_TOKEN_FIELD } from './config';
let lock = false
@ -20,10 +19,12 @@ const alova = createAlova({
requestAdapter: fetchAdapter(),
beforeRequest: (method) => {
// ...原请求前拦截器
const userStore = useUserStore()
console.log('beforeRequest', userStore.accessToken)
const accessStore = useAccessStore();
// const userStore = useUserStore()
// console.log('beforeRequest', userStore.accessToken)
// 添加token到请求头
method.config.headers[ACCESS_TOKEN_FIELD] = `${userStore.accessToken}`
// method.config.headers[ACCESS_TOKEN_FIELD] = `${userStore.accessToken}`
},
responded: async (response, method) => {
let json = await response.json();
@ -37,7 +38,7 @@ export function getAccessToken(rToken: string): Promise<any> {
resolve,
reject
})
const userStore = useUserStore();
// const userStore = useUserStore();
if (!lock) {
lock = true
@ -52,9 +53,9 @@ export function getAccessToken(rToken: string): Promise<any> {
console.log(data)
// 如果 refreshToken 请求成功则将新的token存储到本地
if (data && data.accessToken) {
userStore.setToken(data.accessToken);
userStore.setTokenExpiresTime(data.accessExpire)
userStore.setRefreshToken(data.refreshToken);
// userStore.setToken(data.accessToken);
// userStore.setTokenExpiresTime(data.accessExpire)
// userStore.setRefreshToken(data.refreshToken);
while (promiseResult.length) {
// p1.resolve(res.data)
promiseResult.shift().resolve(data)
@ -62,7 +63,7 @@ export function getAccessToken(rToken: string): Promise<any> {
lock = false
return
}
userStore.resetStore()
// userStore.resetStore()
while (promiseResult.length) {
// p1.reject(err)
promiseResult.shift().reject("身份认证已失效,请重新登录")

View File

@ -0,0 +1,404 @@
/**
*
*/
import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences';
import {
authenticateResponseInterceptor,
errorMessageResponseInterceptor,
RequestClient,
} from '@vben/request';
import { useAccessStore } from '@vben/stores';
import { message } from 'ant-design-vue';
import { useAuthStore } from '#/store';
import { refreshTokenApi } from '../core';
import { transferResponse } from './transferResponse';
import { type QueryOptions, type BodyOptions } from '../global.d';
import { merge } from 'lodash-es';
import { createAlova } from 'alova';
import fetchAdapter from 'alova/fetch';
import vueHook from 'alova/vue';
import { ACCESS_TOKEN_FIELD, getBaseURL } from './config';
import { createServerTokenAuthentication } from 'alova/client';
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
function createRequestClient(baseURL: string) {
const client = new RequestClient({
baseURL,
});
/**
*
*/
async function doReAuthenticate() {
console.warn('Access token or refresh token is invalid or expired. ');
const accessStore = useAccessStore();
const authStore = useAuthStore();
accessStore.setAccessToken(null);
if (
preferences.app.loginExpiredMode === 'modal' &&
accessStore.isAccessChecked
) {
accessStore.setLoginExpired(true);
} else {
await authStore.logout();
}
}
/**
* token逻辑
*/
async function doRefreshToken() {
const accessStore = useAccessStore();
const resp = await refreshTokenApi();
const newToken = resp.data;
accessStore.setAccessToken(newToken);
return newToken;
}
function formatToken(token: null | string) {
return token ? `Bearer ${token}` : null;
}
// 请求头处理
client.addRequestInterceptor({
fulfilled: async (config) => {
const accessStore = useAccessStore();
config.headers.Authorization = formatToken(accessStore.accessToken);
config.headers.Token = accessStore.accessToken;
config.headers['Accept-Language'] = preferences.app.locale;
return config;
},
});
// response数据解构
client.addResponseInterceptor({
fulfilled: (response) => {
let { data: responseData, status } = response;
// 统一处理响应数据
responseData = transferResponse(responseData);
console.log('【转换响应】', JSON.parse(JSON.stringify(responseData)));
const { code, data, msg } = responseData;
if (status >= 200 && status < 400 && code === 0) {
return data;
}
throw new Error(`Error ${status}: ${msg}`);
},
});
// token过期的处理
client.addResponseInterceptor(
authenticateResponseInterceptor({
client,
doReAuthenticate,
doRefreshToken,
enableRefreshToken: preferences.app.enableRefreshToken,
formatToken,
}),
);
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string) => message.error(msg)),
);
return client;
}
export const requestClient = createRequestClient(apiURL);
/** 储存过期的token */
let expireTokenCache = []
/** 服务端 Token 校验 */
const { onAuthRequired, onResponseRefreshToken } = createServerTokenAuthentication({
refreshTokenOnSuccess: {
/**
* Token
* response和methodboolean表示token是否过期
*/
isExpired: async (response, method) => {
// 文件下载操作
if (method.meta?.responseType === 'blob') {
return false
}
const responseClone = response.clone();
let data = await responseClone.json()
// 当服务端返回401时表示token过期
let isExpired = ['401'].includes(data.code);
if (isExpired) {
console.log('AccessToken已过期', data.code)
expireTokenCache.push(method.config.headers[ACCESS_TOKEN_FIELD])
}
return isExpired;
},
/** 当token过期时触发在此函数中触发刷新token */
handler: async (response, method) => {
console.warn('Access token or refresh token is invalid or expired. ');
const accessStore = useAccessStore();
const authStore = useAuthStore();
accessStore.setAccessToken(null);
if (
preferences.app.loginExpiredMode === 'modal' &&
accessStore.isAccessChecked
) {
accessStore.setLoginExpired(true);
} else {
await authStore.logout();
}
throw new Error('登录已过期,请重新登录');
// const userStore = useUserStore();
// try {
// let rToken = userStore.refreshToken;
// // 如果没有refreshToken则跳转登录页
// if (!rToken) {
// throw new Error('登录已过期,请重新登录');
// }
// await getAccessToken(rToken)
// expireTokenCache = []
// } catch (error: any) {
// window.$message?.error(error.message);
// userStore.resetStore()
// throw error;
// }
}
}
});
export const alovaInstance = createAlova({
/** 动态代理配置 */
baseURL: getBaseURL(),
/** 框架请求适配器 */
statesHook: vueHook,
requestAdapter: fetchAdapter(),
/** 设置缓存状态:不开启 */
cacheFor: null,
// cacheFor: {
// // 统一设置POST的缓存模式
// GET: {
// mode: 'restore',
// expire: 60 * 10 * 1000
// },
// POST: {
// mode: 'restore',
// expire: 60 * 10 * 1000
// },
// // 统一设置HEAD请求的缓存模式
// HEAD: 60 * 10 * 1000
// },
/** 请求拦截器 */
beforeRequest: onAuthRequired(method => {
const accessStore = useAccessStore();
if (accessStore.accessToken) {
method.config.headers.Token = accessStore.accessToken;
// 统一授权的这个接口需要以Authorization传参无语 /sys/user/functiontree/XTBGXT
method.config.headers.Authorization = `Bearer ${accessStore.accessToken}`;
}
method.config.headers['Accept-Language'] = preferences.app.locale;
// const userStore = useUserStore()
// // 添加token到请求头
// if (userStore.accessToken) {
// method.config.headers[ACCESS_TOKEN_FIELD] = `Bearer ${userStore.accessToken}`
// method.config.headers["Authorization"] = `Bearer ${userStore.accessToken}`
// }
// method.config.cacheFor = {
// // 设置缓存模式为内存模式
// mode: 'restore',
// // 单位为毫秒
// // 当设置为`Infinity`表示数据永不过期设置为0或负数时表示不缓存
// expire: 60 * 10 * 1000
// }
// method.config.transform = (rawData, headers) => {
// console.log('接口响应', rawData)
// return transferResponse(rawData)
// }
}),
/** 响应拦截器 */
responded: onResponseRefreshToken(async (response, method) => {
if (method.meta?.responseType === 'blob') {
let blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
const contentDisposition = response.headers.get('content-disposition');
let fileName = 'downloaded-file';
if (contentDisposition) {
const matches = /filename="?([^"]+)"?/.exec(contentDisposition);
if (matches != null && matches[1]) {
fileName = decodeURIComponent(matches[1]);
}
}
a.download = fileName;
// 触发下载
document.body.appendChild(a);
a.click();
// 移除链接
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
return {
blob: blob,
url: url,
filename: fileName
}
}
// if (response.status >= 400) {
// throw new Error(response.statusText);
// }
let json = await response.json();
console.log('【接口】', method.url)
console.log('原始响应', JSON.parse(JSON.stringify(json)))
json = transferResponse(json)
console.log('改造响应', JSON.parse(JSON.stringify(json)))
if (json.code != 0) {
if (json.code == '401') {
message.error("用户身份过期,请重新登录");
// const userStore = useUserStore();
// userStore.resetStore();
} else {
message.error(json.msg || '服务器开小差,请稍后再试');
}
// 抛出错误或返回reject状态的Promise实例时此请求将抛出错误
throw new Error((json && json.msg) || '出错了');
}
// 解析的响应数据将传给method实例的transformData钩子函数这些函数将在后续讲解
return json.data;
})
});
class Http {
/**
* swagger路径参数pathParams
* "/api/v1/user/{id}",{ pathParams:{ id :1 },params:{ id:2 } }
* /api/v1/user/1?id=2
*/
private replacePathParams(url: string, pathParams?: any): string {
if (!pathParams) return url;
return url.replace(/{(\w+)}/g, (_, key) => pathParams[key] || `{${key}}`);
}
/**
*
* @param customConfig
* @returns
*/
private getConfig(customConfig?: any): any {
// 递归属性拷贝
return merge({}, {
meta: {
showLoading: false,
showError: false,
},
}, customConfig);
}
private request(method: string, url: string, data?: BodyOptions | QueryOptions) {
let finalUrl = this.replacePathParams(url, data?.pathParams);
const config = this.getConfig(data?.config);
// 当组件使用allowClear属性时会将数据置为null导致数据查询失败
if (data && data.params) {
Object.keys(data.params).forEach(key => {
if (data.params[key] === null || data.params[key] === undefined) {
delete data.params[key]
}
})
}
if (data && data.data) {
Object.keys(data.data).forEach(key => {
if (data.data[key] === null || data.data[key] === undefined) {
delete data.data[key]
}
})
}
let alovaMethod: 'Get' | 'Post' | 'Delete' | 'Put' = 'Get';
if (method === 'get' || method === 'delete') {
if (method === 'get') {
alovaMethod = 'Get'
}
if (method === 'delete') {
alovaMethod = 'Delete'
}
return alovaInstance[alovaMethod](finalUrl, { ...config, params: data?.params });
} else {
// 处理 params 到 url 的逻辑
if (data?.params) {
finalUrl = this.appendParamsToUrl(finalUrl, data.params);
}
if (method === 'post') {
alovaMethod = 'Post'
}
if (method === 'put') {
alovaMethod = 'Put'
}
return alovaInstance[alovaMethod](finalUrl, data?.data, { ...config });
}
}
private appendParamsToUrl(url: string, params: any): string {
let queryString = '';
for (const key in params) {
if (Object.prototype.hasOwnProperty.call(params, key)) {
queryString += `${queryString ? '&' : '?'}${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`;
}
}
return url + queryString;
}
get(url: string, data?: QueryOptions) {
return this.request('get', url, data);
}
post(url: string, data?: BodyOptions) {
return this.request('post', url, data);
}
put(url: string, data?: BodyOptions) {
return this.request('put', url, data);
}
patch(url: string, data?: BodyOptions) {
return this.request('patch', url, data);
}
delete(url: string, data?: QueryOptions) {
return this.request('delete', url, data);
}
}
export const http = new Http();
export const baseRequestClient = new RequestClient({ baseURL: apiURL });

View File

@ -1,3 +1,4 @@
const SUCCESS_CODE = 0;
/**
* BFF层
@ -10,42 +11,45 @@ export function transferResponse(response: any) {
// 如果后端直接返回数组,如[xxx]
if (Array.isArray(response)) {
return {
code: import.meta.env.VITE_SERVICE_SUCCESS_CODE,
msg: 'Ok',
code: SUCCESS_CODE,
data: {
rows: response
}
rows: response,
},
msg: 'Ok',
};
}
// 如果后端直接返回数据内容对象,如{xxx},则先进行统一响应包装
if (response.code == undefined) {
response = {
code: import.meta.env.VITE_SERVICE_SUCCESS_CODE,
code: SUCCESS_CODE,
data: response,
msg: 'Ok',
data: response
}
};
}
let { code, msg, data = {}, ...rest } = response;
let { code, data = {}, msg, ...rest } = response;
if (!data) {
data = {}
data = {};
}
if (typeof data === 'string') {
data = {
value: data
}
value: data,
};
}
// eslint-disable-next-line eqeqeq
if (code == 'success') {
code = import.meta.env.VITE_SERVICE_SUCCESS_CODE;
code = 0;
}
if (code == 'failure' || (msg && msg.includes('token无效'))) {
code = 401;
}
if (Array.isArray(data)) {
data = {
rows: data
rows: data,
};
}
@ -69,15 +73,17 @@ export function transferResponse(response: any) {
}
if (response.code == 200 && response.flag === false) {
code = 500
code = 500;
} else if (response.code == '200') {
code = 0;
}
return {
code,
msg,
data: {
...data,
...rest
}
...rest,
},
msg,
};
}

View File

@ -0,0 +1,84 @@
import { baseRequestClient, requestClient } from '#/api/request/index';
import type { UserInfo } from '@vben/types';
import { useAccessStore } from '@vben/stores';
export namespace AuthApi {
/** 登录接口参数 */
export interface LoginParams {
password: string;
username: string;
}
/** 登录接口返回值 */
export interface LoginResult {
accessToken: string;
desc: string;
realName: string;
userId: string;
username: string;
}
export interface RefreshTokenResult {
data: string;
status: number;
}
}
/**
*
*/
export async function loginApi(data: AuthApi.LoginParams) {
return requestClient.post<AuthApi.LoginResult>(
'/uc/uaa/validateAccount',
data,
{
transformResponse: (res) => {
res = JSON.parse(res);
console.log(res);
const info = res.data;
if (info.access_token) {
info.accessToken = info.access_token;
info.realName = info.display_name;
return info
}
return res;
},
},
);
}
/**
* accessToken
*/
export async function refreshTokenApi() {
return baseRequestClient.post<AuthApi.RefreshTokenResult>('/auth/refresh', {
withCredentials: true,
});
}
/**
* 退
*/
export async function logoutApi() {
return baseRequestClient.post('/uc/uaa/logout', {
withCredentials: true,
});
}
/**
*
*/
export async function getAccessCodesApi() {
return requestClient.get<string[]>('/auth/codes');
}
/**
*
*/
export async function getUserInfoApi() {
const accessStore = useAccessStore();
return requestClient.post<UserInfo>('/uc/sys/user/checkToken', {
token: accessStore.accessToken,
});
}

View File

@ -0,0 +1,10 @@
import type { RouteRecordStringComponent } from '@vben/types';
import { requestClient } from '#/api/request/index';
/**
*
*/
export async function getAllMenusApi() {
return requestClient.get<RouteRecordStringComponent[]>('/menu/all');
}

View File

@ -0,0 +1,66 @@
<script lang="ts" setup>
import { computed } from "vue";
import { useAntdDesignTokens } from "@vben/hooks";
import { preferences, usePreferences } from "@vben/preferences";
import { App, ConfigProvider, theme } from "ant-design-vue";
import { antdLocale } from "#/locales";
import { useDictStore } from "./store/dict";
defineOptions({ name: "App" });
const { isDark } = usePreferences();
const { tokens } = useAntdDesignTokens();
const tokenTheme = computed(() => {
const algorithm = isDark.value ? [theme.darkAlgorithm] : [theme.defaultAlgorithm];
// antd
if (preferences.app.compact) {
algorithm.push(theme.compactAlgorithm);
}
return {
algorithm,
token: tokens,
};
});
const dictStore = useDictStore();
if (dictStore.initDict) {
dictStore.setDictMap();
}
</script>
<template>
<ConfigProvider :locale="antdLocale" :theme="tokenTheme">
<App>
<RouterView />
</App>
</ConfigProvider>
</template>
<style>
.vxebasic-table-container {
flex: auto;
min-height: 300px;
}
.ant-btn {
display: flex;
align-items: center;
}
.ant-modal-confirm-btns {
display: flex;
justify-content: flex-end;
}
.ant-btn__warning {
@apply bg-warning text-warning-foreground shadow hover:bg-warning/90;
}
</style>

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -0,0 +1,42 @@
import { createApp } from 'vue';
import { registerAccessDirective } from '@vben/access';
import { initStores } from '@vben/stores';
import '@vben/styles';
import '@vben/styles/antd';
import { setupI18n } from '#/locales';
import App from './app.vue';
import { registerFastCrud } from './plugins/fastCrud';
import { registerVxeTable } from './plugins/vxeTable';
import { router } from './router';
import { VbenButton } from '@vben-core/shadcn-ui';
async function bootstrap(namespace: string) {
const app = createApp(App);
// 国际化 i18n 配置
await setupI18n(app);
// 配置 pinia-tore
await initStores(app, { namespace });
// 安装权限指令
registerAccessDirective(app);
// 配置路由及路由守卫
app.use(router);
// 引入 fast-crud 相关组件
registerFastCrud(app);
registerVxeTable(app)
app.component('vben-button', VbenButton);
app.mount('#app');
}
export { bootstrap };

View File

@ -0,0 +1,94 @@
import { dict } from "@fast-crud/fast-crud";
import Apis from '#/api'
export const unitComponentProps = {
name: 'fs-dict-tree',
vModel: 'value',
allowClear: true,
class: 'min-w-[180px]',
showCheckedStrategy: "SHOW_CHILD",
dict: dict({
isTree: true,
async getData(dict, context) {
const data = await Apis.api.core.orgemplbc.organization.post_paging({
params: {
page: 1,
size: 1000
},
data: {
subFilter: [
{
symbol: "like",
singleValue: "0001%",
key: "ORG_ID",
logic: "AND",
},
],
}
});
data.rows.forEach((item: any) => {
item.label = item.ORG_NAME
item.value = item.ORG_ID
})
let treeData = transTree(data.rows);
return treeData;
},
}),
}
export async function getUnitData(params = {}) {
const data = await Apis.api.core.orgemplbc.organization.post_paging({
params: {
page: 1,
size: 1000
},
data: {
subFilter: [
{
symbol: "like",
singleValue: "0001%",
key: "ORG_ID",
logic: "AND",
},
],
}
});
data.rows.forEach((item: any) => {
item.label = item.ORG_NAME
item.value = item.ORG_ID
})
let treeData = transTree(data.rows);
return treeData;
}
// 转换树行数据的方法
function transTree(list) {
// 最终生成的树行结构
const _treeData = [];
// 对传入进来的 数据进行遍历,查找对应的子级
list.forEach((item) => {
// 给每一项添加子节点
// item.children = []
item.key = item.ORG_ID;
item.label = item.ORG_NAME;
// 如果 pid 为空,说明是最顶级,直接放到 _treeData 中即可
if (item.ORG_LEVEL == 1) {
item.selectable = false
_treeData.push(item);
}
// 根据前面的分析pid 代表的是父级的 id从而可以进行筛选子级
// filter 方法会把满足条件到的每一项,组成一个数组进行返回
const children = list.filter((data) => data.PARENT_ID === item.ORG_ID);
// 如果没有子节点,直接 return 不做任何处理
if (!children.length) return;
// 将返回的子级进行赋值给父级(item)的 children 属性
item.children = children;
});
// 将最终生成的数据返回出去
return _treeData;
}

View File

@ -0,0 +1,99 @@
<template>
<template v-if="props.selectable">
<div v-for="(dict, index) in dicts" :key="index" @click="handleClick(dict)"
:class="{ 'cursor-pointer': selectable }">
<a-tag :color="getTagColor(dict)" :round="!multiple">
{{ dict[labelField] }}
</a-tag>
</div>
</template>
<div v-else-if="Array.isArray(value)" class="flex flex-row flex-wrap">
<template v-for="(dict, index) in dicts" :key="index">
<div v-if="selectedValues.includes(dict.value)" class="mb-1">
<a-tag>
{{ dict[labelField] }}
</a-tag>
</div>
</template>
</div>
<template v-else>
<!-- <a-tag :color="dictData?.colorType || ''">
{{ (dictData && dictData[labelField]) || value }}
</a-tag> -->
</template>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from "vue";
import { Tag, Space } from "ant-design-vue";
import { getDictOpts } from "#/utils/dict";
import type { DictDataType } from "#/utils/dict";
const props = withDefaults(
defineProps<{
type?: string;
options: DictDataType[];
value?: string | number | boolean | Array<string | number | boolean>;
icon?: string;
multiple?: boolean;
selectable?: boolean;
labelField?: string;
valueField?: string;
}>(),
{
type: "",
options: () => [],
multiple: false,
selectable: false,
labelField: "label",
valueField: "value",
value: "",
icon: "",
}
);
const emit = defineEmits(["update:value", "tag-click"]);
const dictData = ref<DictDataType | null>(null);
const selectedValues = ref<Array<string | number>>(
Array.isArray(props.value) ? props.value : []
);
const dicts = computed(() => {
return props.type ? getDictOpts(props.type) : props.options;
});
const handleClick = (dict: DictDataType) => {
emit("tag-click", dict);
if (props.selectable) {
if (props.multiple) {
const index = selectedValues.value.indexOf(dict.value);
if (index === -1) {
selectedValues.value.push(dict.value);
} else {
selectedValues.value.splice(index, 1);
}
emit("update:value", selectedValues.value);
} else {
emit("update:value", dict.value);
}
}
};
const getTagColor = (dict: DictDataType) => {
return (props.multiple && selectedValues.value.includes(dict.value)) ||
(!props.multiple && props.value == dict.value)
? "blue"
: "";
};
onMounted(() => {
})
</script>
<style scoped>
.cursor-pointer {
cursor: pointer;
}
</style>

View File

@ -0,0 +1 @@
export { default as DictTag } from './dict-tag.vue';

View File

@ -1,51 +1,45 @@
import { h } from 'vue';
import dayjs from 'dayjs';
import { NButton, NTag, NTooltip } from 'naive-ui';
import { isArray, isString } from '@/utils/is';
import { DictTag } from '@/components/DictTag';
import { Button, Tag } from 'ant-design-vue';
import { isArray, isString } from 'lodash-es';
import { DictTag } from '#/components/dict-tag';
// import { Icon } from '@/components/Icon';
// import { JsonPreview } from '@/components/CodeEditor';
import TableImg from '../components/TableImg.vue';
import { getDictOpts } from '@/utils/dict';
import { Tooltip } from 'ant-design-vue'
import { getDictOpts } from '#/utils/dict';
export const useRender = {
/**
*
*
* @param text
* @returns image标签
*/
renderImg: (text: string, props?: AnyObject) => {
if (text) {
if (isArray(text)) return h(TableImg, { imgList: text, ...props });
else if (isString(text)) return h(TableImg, { imgList: [text], ...props });
}
return '';
},
// renderImg: (text: string) => {
// if (text) {
// if (isArray(text)) return h(TableImg, { imgList: text });
// else if (isString(text)) return h(TableImg, { imgList: [text] });
// }
// return '';
// },
/**
*
*
* @param url
* @param text
* @returns link
*/
renderLink: (url: string, text?: string) => {
if (url) return h(NButton, { text: true, type: 'info', href: url, target: '_blank' }, () => text || '');
if (url) return h(Button, { type: 'link', href: url, target: '_blank' }, () => text || '');
return '';
},
/**
* text与val
*
* @param text 1
* @param val 2
* @returns 1 + 2
*/
renderText(text, val) {
if (text != undefined) return h('div', `${text} ${val}`);
return h('div', '');
renderText: (text: string, val: string) => {
if (text) return `${text} ${val}`;
else return '';
},
/**
*
* @param text
@ -59,7 +53,7 @@ export const useRender = {
classArr.push('line-clamp-' + params?.maxLine)
}
return h(
NTooltip,
Tooltip,
{ trigger: 'hover' },
{
trigger: () => h('span', { class: classArr.join(' ') }, text),
@ -71,34 +65,31 @@ export const useRender = {
},
/**
*
*
* @param text
* @param color
* @returns
*/
renderTag: (text: string | number, color?: string) => {
if (color) return h(NTag, { type: color }, () => text);
return h(NTag, {}, () => text);
if (color) return h(Tag, { color }, () => text);
else return h(Tag, {}, () => text);
},
/**
*
*
* @param texts
* @returns
*/
renderTags: (texts: string[]) => {
if (texts) {
return h('div', null, [
texts.map(text => {
return h(NTag, null, () => text);
})
texts.map((text) => {
return h(Tag, null, () => text);
}),
]);
}
return '';
},
/**
*
*
* @param text
* @param format
* @returns
@ -107,11 +98,10 @@ export const useRender = {
if (!text) return '';
if (!format) return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
return dayjs(text).format(format);
else return dayjs(text).format(format);
},
/**
*
*
* @param text
* @param dictType
* @returns
@ -140,14 +130,13 @@ export const useRender = {
// },
/**
* 使JsonPreview组件 便JSON
*
* @param json json字符串/obj
* @returns json返回JsonPreview
*/
// renderJsonPreview: (json: any) => {
// if (!json) return '';
// if (typeof json === 'object') return h(JsonPreview, { data: json });
//
// if (typeof json === 'string') {
// try {
// const data = JSON.parse(json);
@ -156,5 +145,5 @@ export const useRender = {
// return json;
// }
// }
// }
// },
};

View File

@ -1,13 +1,13 @@
import { merge } from "lodash-es";
import { ref, computed } from "vue";
import { VxeGridInstance, VxeGridProps } from "vxe-table";
import { ref } from "vue";
import { type VxeGridInstance, type VxeGridProps } from "vxe-table";
export function useVxeTable(props: {
ref: string,
}) {
const xGridRef = ref<VxeGridInstance<AnyObject>>();
const xGridRef = ref<VxeGridInstance<any>>();
return {
xGridRef,

View File

@ -0,0 +1,164 @@
<script lang="ts" setup>
import type { NotificationItem } from "@vben/layouts";
import { computed, ref } from "vue";
import { storeToRefs, useAccessStore } from "@vben/stores";
// import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
import { AuthenticationLoginExpiredModal } from "@vben/common-ui";
import { BasicLayout, LockScreen, Notification, UserDropdown } from "@vben/layouts";
import { preferences } from "@vben/preferences";
import { useUserStore } from "@vben/stores";
import { BookOpenText, CircleHelp, PhUserCircle } from "@vben/icons";
import { useAuthStore } from "#/store";
import { useRouter } from "vue-router";
const router = useRouter();
const notifications = ref<NotificationItem[]>([
// {
// 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 userStore = useUserStore();
const authStore = useAuthStore();
const accessStore = useAccessStore();
const showDot = computed(() => notifications.value.some((item) => !item.isRead));
const menus = computed(() => [
{
handler: () => {
router.push("/user/center");
},
icon: PhUserCircle,
text: "个人中心",
},
// {
// handler: () => {
// openWindow(VBEN_GITHUB_URL, {
// target: '_blank',
// });
// },
// icon: MdiGithub,
// text: 'GitHub',
// },
// {
// handler: () => {
// openWindow(`${VBEN_GITHUB_URL}/issues`, {
// target: '_blank',
// });
// },
// icon: CircleHelp,
// text: $t('widgets.qa'),
// },
]);
const { loginLoading } = storeToRefs(authStore);
const avatar = computed(() => {
return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
});
async function handleLogout() {
await authStore.logout(false);
}
function handleNoticeClear() {
notifications.value = [];
}
function handleMakeAll() {
notifications.value.forEach((item) => (item.isRead = true));
}
function handleViewAll() {
console.log("viewAll");
router.push("/user/todo");
}
const isDev = import.meta.env.DEV;
const value = ref(localStorage.getItem("@@@proxy_type") || ""); // /zp
function handleMenuClick(e) {
console.log(e);
if (e.key == "pro") {
localStorage.setItem("@@@proxy_type", "");
} else {
localStorage.setItem("@@@proxy_type", "/" + e.key);
}
}
</script>
<template>
<BasicLayout @clear-preferences-and-logout="handleLogout">
<template #user-dropdown>
<UserDropdown
:avatar
:description="userStore.userInfo?.belongOrgName"
:menus
:tag-text="userStore.userInfo?.gwmc"
:text="userStore.userInfo?.displayName"
@logout="handleLogout"
/>
</template>
<template #notification>
<a-dropdown v-if="isDev">
<template #overlay>
<a-menu @click="handleMenuClick" selectable>
<a-menu-item key="pro"> 正式 </a-menu-item>
<a-menu-item key="czg"> czg </a-menu-item>
<a-menu-item key="zp"> zp </a-menu-item>
<a-menu-item key="zzz"> zzz </a-menu-item>
</a-menu>
</template>
<a-button> {{ value ? "代理" + value : "代理切换" }} </a-button>
</a-dropdown>
<Notification
:dot="showDot"
:notifications="notifications"
@clear="handleNoticeClear"
@make-all="handleMakeAll"
@view-all="handleViewAll"
/>
</template>
<template #extra>
<AuthenticationLoginExpiredModal
v-model:open="accessStore.loginExpired"
:avatar
:loading="loginLoading"
password-placeholder=""
username-placeholder=""
@submit="authStore.authLogin"
/>
</template>
<template #lock-screen>
<LockScreen :avatar :text="userStore.userInfo?.displayName" @to-login="handleLogout" />
</template>
</BasicLayout>
</template>

View File

@ -0,0 +1,8 @@
const BasicLayout = () => import('./basic.vue');
const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);
const AuthPageLayout = () =>
import('@vben/layouts').then((m) => m.AuthPageLayout);
export { AuthPageLayout, BasicLayout, IFrameView };

View File

@ -0,0 +1,3 @@
# locale
每个app使用的国际化可能不同这里用于扩展国际化的功能例如扩展 dayjs、antd组件库的多语言切换以及app本身的国际化文件。

View File

@ -0,0 +1,94 @@
import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
import type { Locale } from 'ant-design-vue/es/locale';
import type { App } from 'vue';
import { ref } from 'vue';
import { $t, setupI18n as coreSetup, loadLocalesMap } from '@vben/locales';
import { preferences } from '@vben/preferences';
import antdEnLocale from 'ant-design-vue/es/locale/en_US';
import antdDefaultLocale from 'ant-design-vue/es/locale/zh_CN';
import dayjs from 'dayjs';
const antdLocale = ref<Locale>(antdDefaultLocale);
const modules = import.meta.glob('./langs/*.json');
const localesMap = loadLocalesMap(modules);
/**
*
*
* @param lang
*/
async function loadMessages(lang: SupportedLanguagesType) {
const [appLocaleMessages] = await Promise.all([
localesMap[lang]?.(),
loadThirdPartyMessage(lang),
]);
return appLocaleMessages?.default;
}
/**
*
* @param lang
*/
async function loadThirdPartyMessage(lang: SupportedLanguagesType) {
await Promise.all([loadAntdLocale(lang), loadDayjsLocale(lang)]);
}
/**
* dayjs的语言包
* @param lang
*/
async function loadDayjsLocale(lang: SupportedLanguagesType) {
let locale;
switch (lang) {
case 'zh-CN': {
locale = await import('dayjs/locale/zh-cn');
break;
}
case 'en-US': {
locale = await import('dayjs/locale/en');
break;
}
// 默认使用英语
default: {
locale = await import('dayjs/locale/en');
}
}
if (locale) {
dayjs.locale(locale);
} else {
console.error(`Failed to load dayjs locale for ${lang}`);
}
}
/**
* antd的语言包
* @param lang
*/
async function loadAntdLocale(lang: SupportedLanguagesType) {
switch (lang) {
case 'zh-CN': {
antdLocale.value = antdDefaultLocale;
break;
}
case 'en-US': {
antdLocale.value = antdEnLocale;
break;
}
}
}
async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
await coreSetup(app, {
defaultLocale: preferences.app.locale,
loadMessages,
missingWarn: !import.meta.env.PROD,
...options,
});
}
export { $t, antdLocale, setupI18n };

View File

@ -0,0 +1,8 @@
{
"page": {
"demos": {
"title": "Demos",
"antd": "Ant Design Vue"
}
}
}

View File

@ -0,0 +1,8 @@
{
"page": {
"demos": {
"title": "演示",
"antd": "Ant Design Vue"
}
}
}

View File

@ -0,0 +1,31 @@
import { initPreferences } from '@vben/preferences';
import { unmountGlobalLoading } from '@vben/utils';
import { overridesPreferences } from './preferences';
/**
*
*/
async function initApplication() {
// name用于指定项目唯一标识
// 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据
const env = import.meta.env.PROD ? 'prod' : 'dev';
const appVersion = import.meta.env.VITE_APP_VERSION;
const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;
// app偏好设置初始化
await initPreferences({
namespace,
overrides: overridesPreferences,
});
// 启动应用并挂载
// vue应用主要逻辑及视图
const { bootstrap } = await import('./bootstrap');
await bootstrap(namespace);
// 移除并销毁loading
unmountGlobalLoading();
}
initApplication();

View File

@ -0,0 +1,21 @@
import type { App } from 'vue';
import FastCrud from '@fast-crud/fast-crud';
import ui from '@fast-crud/ui-antdv4';
import Antdv from 'ant-design-vue';
import { requestClient } from '#/api/request/index';
import '@fast-crud/fast-crud/dist/style.css';
import '@fast-crud/ui-antdv4/dist/style.css';
export function registerFastCrud(app: App) {
app.use(Antdv);
app.use(ui);
app.use(FastCrud, {
async dictRequest(dict) {
//通过字段组件中配置的dict.url获取远程字典数据
let res = await requestClient.get('/app/dictData/page');
console.log(res)
return res.rows;
},
});
}

View File

@ -0,0 +1,202 @@
import type { App } from 'vue';
import VXETable from 'vxe-table'
import {
VxeTable,
VxeColumn,
VxeColgroup,
VxeGrid,
VxeToolbar
} from 'vxe-table'
import VxeUI from 'vxe-pc-ui'
import {
VxeAlert,
VxeAnchor,
VxeAnchorLink,
VxeBreadcrumb,
VxeBreadcrumbItem,
VxeButton,
VxeButtonGroup,
VxeCalendar,
VxeCard,
VxeCarousel,
VxeCheckbox,
VxeCheckboxGroup,
VxeCol,
VxeCollapse,
VxeCollapsePane,
VxeDatePicker,
VxeDrawer,
VxeForm,
VxeFormDesign,
VxeFormGather,
VxeFormItem,
VxeFormView,
VxeIcon,
VxeIconPicker,
VxeImage,
VxeImageGroup,
VxeImagePreview,
VxeInput,
VxeLayoutAside,
VxeLayoutBody,
VxeLayoutContainer,
VxeLayoutFooter,
VxeLayoutHeader,
VxeLink,
VxeListDesign,
VxeListView,
VxeList,
VxeLoading,
VxeMenu,
VxeModal,
VxeNumberInput,
VxeOptgroup,
VxeOption,
VxePager,
VxePasswordInput,
VxePrintPageBreak,
VxePrint,
VxePulldown,
VxeRadio,
VxeRadioButton,
VxeRadioGroup,
VxeRow,
VxeSelect,
VxeSwitch,
VxeTabPane,
VxeTabs,
VxeTag,
VxeText,
VxeTextarea,
VxeTip,
VxeTooltip,
VxeTree,
VxeTreeSelect,
VxeUpload
} from 'vxe-pc-ui'
import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx'
import ExcelJS from 'exceljs'
import VXETablePluginAntd from 'vxe-table-plugin-antd'
// 导入主题变量,也可以重写主题变量
import 'vxe-pc-ui/lib/style.css'
import 'vxe-table/lib/style.css'
import 'vxe-table/styles/cssvar.scss'
import 'vxe-pc-ui/styles/cssvar.scss'
// VxeUI.setTheme('dark')
VxeUI.component(VxeAlert)
VxeUI.component(VxeAnchor)
VxeUI.component(VxeAnchorLink)
VxeUI.component(VxeBreadcrumb)
VxeUI.component(VxeBreadcrumbItem)
VxeUI.component(VxeButton)
VxeUI.component(VxeButtonGroup)
VxeUI.component(VxeCalendar)
VxeUI.component(VxeCard)
VxeUI.component(VxeCarousel)
VxeUI.component(VxeCheckbox)
VxeUI.component(VxeCheckboxGroup)
VxeUI.component(VxeCol)
VxeUI.component(VxeCollapse)
VxeUI.component(VxeCollapsePane)
VxeUI.component(VxeDatePicker)
VxeUI.component(VxeDrawer)
VxeUI.component(VxeForm)
VxeUI.component(VxeFormDesign)
VxeUI.component(VxeFormGather)
VxeUI.component(VxeFormItem)
VxeUI.component(VxeFormView)
VxeUI.component(VxeIcon)
VxeUI.component(VxeIconPicker)
VxeUI.component(VxeImage)
VxeUI.component(VxeImageGroup)
VxeUI.component(VxeImagePreview)
VxeUI.component(VxeInput)
VxeUI.component(VxeLayoutAside)
VxeUI.component(VxeLayoutBody)
VxeUI.component(VxeLayoutContainer)
VxeUI.component(VxeLayoutFooter)
VxeUI.component(VxeLayoutHeader)
VxeUI.component(VxeLink)
VxeUI.component(VxeListDesign)
VxeUI.component(VxeListView)
VxeUI.component(VxeList)
VxeUI.component(VxeLoading)
VxeUI.component(VxeMenu)
VxeUI.component(VxeModal)
VxeUI.component(VxeNumberInput)
VxeUI.component(VxeOptgroup)
VxeUI.component(VxeOption)
VxeUI.component(VxePager)
VxeUI.component(VxePasswordInput)
VxeUI.component(VxePrintPageBreak)
VxeUI.component(VxePrint)
VxeUI.component(VxePulldown)
VxeUI.component(VxeRadio)
VxeUI.component(VxeRadioButton)
VxeUI.component(VxeRadioGroup)
VxeUI.component(VxeRow)
VxeUI.component(VxeSelect)
VxeUI.component(VxeSwitch)
VxeUI.component(VxeTabPane)
VxeUI.component(VxeTabs)
VxeUI.component(VxeTag)
VxeUI.component(VxeText)
VxeUI.component(VxeTextarea)
VxeUI.component(VxeTip)
VxeUI.component(VxeTooltip)
VxeUI.component(VxeTree)
VxeUI.component(VxeTreeSelect)
VxeUI.component(VxeUpload)
VxeUI.component(VxeTable)
VxeUI.component(VxeColumn)
VxeUI.component(VxeColgroup)
VxeUI.component(VxeGrid)
VxeUI.component(VxeToolbar)
VXETable.use(VXETablePluginAntd)
VXETable.use(VXETablePluginExportXLSX, {
ExcelJS
})
VXETable.setConfig({
zIndex: 9999,
grid: {
size: 'mini',
proxyConfig: {
props: {
result: 'data.rows',
total: 'data.total',
},
},
toolbarConfig: {
enabled: true,
},
},
pager: {
background: true,
pageSize: 50,
pageSizes: [50, 100, 300, 500, 1000],
layouts: ['PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'Sizes', 'FullJump', 'Total'],
},
})
export function registerVxeTable(app: App) {
app.use(VxeUI)
app.use(VxeTable)
app.use(VxeColumn)
app.use(VxeColgroup)
app.use(VxeGrid)
app.use(VxeToolbar)
}

View File

@ -0,0 +1,12 @@
import { defineOverridesPreferences } from '@vben/preferences';
/**
* @description
* 使
*/
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
name: import.meta.env.VITE_APP_TITLE,
},
});

View File

@ -0,0 +1,42 @@
import type {
ComponentRecordType,
GenerateMenuAndRoutesOptions,
} from '@vben/types';
import { generateAccessible } from '@vben/access';
import { preferences } from '@vben/preferences';
import { message } from 'ant-design-vue';
import { getAllMenusApi } from '#/api/system/menu';
import { BasicLayout, IFrameView } from '#/layouts';
import { $t } from '#/locales';
const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
const layoutMap: ComponentRecordType = {
BasicLayout,
IFrameView,
};
return await generateAccessible(preferences.app.accessMode, {
...options,
fetchMenuListAsync: async () => {
message.loading({
content: `${$t('common.loadingMenu')}...`,
duration: 1.5,
});
return await getAllMenusApi();
},
// 可以指定没有权限跳转403页面
forbiddenComponent,
// 如果 route.meta.menuVisibleWithForbidden = true
layoutMap,
pageMap,
});
}
export { generateAccess };

View File

@ -0,0 +1,240 @@
import type { Router } from 'vue-router';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
import { preferences } from '@vben/preferences';
import { useAccessStore, useUserStore } from '@vben/stores';
import { startProgress, stopProgress } from '@vben/utils';
import { useTitle } from '@vueuse/core';
import { $t } from '#/locales';
import { coreRouteNames, dynamicRoutes } from '#/router/routes';
import { useAuthStore } from '#/store';
import Apis from '#/api';
import { generateAccess } from './access';
/**
*
* @param router
*/
function setupCommonGuard(router: Router) {
// 记录已经加载的页面
const loadedPaths = new Set<string>();
router.beforeEach(async (to) => {
to.meta.loaded = loadedPaths.has(to.path);
// 页面加载进度条
if (!to.meta.loaded && preferences.transition.progress) {
startProgress();
}
return true;
});
router.afterEach((to) => {
// 记录页面是否加载,如果已经加载,后续的页面切换动画等效果不在重复执行
if (preferences.tabbar.enable) {
loadedPaths.add(to.path);
}
// 关闭页面加载进度条
if (preferences.transition.progress) {
stopProgress();
}
// 动态修改标题
if (preferences.app.dynamicTitle) {
const { title } = to.meta;
// useTitle(`${$t(title)} - ${preferences.app.name}`);
useTitle(`${$t(title)} - ${preferences.app.name}`);
}
});
}
/**
*
* permission.path = "/xx/edit" route.path = "/xx/edit/:id?" id可以为任意值meetingId roleId等
*/
function matchPaths(routePath, permissionPath) {
const routeParts = routePath.split('/');
const permissionParts = permissionPath.split('/');
if (permissionParts.length > routeParts.length) {
return false;
}
return routeParts.every((part, index) => {
return part === permissionParts[index] || part.startsWith(':');
});
}
// 过滤路由,只保留第三个数据源配置的路由
function filterRoutesByPermissions(routes, permissions, staticRouteKeys) {
const filteredRoutes = [];
for (let route of routes) {
console.log('[ route ] >', route)
console.log('[ permission.path ] >', permissions)
const permission = permissions.find(permission =>
matchPaths(route.path, permission.path)
);
const isStaticRoute = staticRouteKeys.includes(route.name);
if (permission || isStaticRoute) {
const newRoute = { ...route };
if (permission) {
newRoute.meta = {
...newRoute.meta,
title: permission.name,
};
if (permission.order) {
newRoute.meta.order = permission.order
}
}
if (route.children) {
newRoute.children = filterRoutesByPermissions(route.children, permissions, staticRouteKeys);
}
filteredRoutes.push(newRoute);
console.log(JSON.parse(JSON.stringify(filteredRoutes)));
}
}
return filteredRoutes;
}
/**
* 访
* @param router
*/
function setupAccessGuard(router: Router) {
router.beforeEach(async (to, from) => {
const accessStore = useAccessStore();
const userStore = useUserStore();
const authStore = useAuthStore();
// 基本路由,这些路由不需要进入权限拦截
if (coreRouteNames.includes(to.name as string)) {
if (to.path === LOGIN_PATH && accessStore.accessToken) {
return decodeURIComponent(
(to.query?.redirect as string) || DEFAULT_HOME_PATH,
);
}
return true;
}
// accessToken 检查
if (!accessStore.accessToken) {
// 明确声明忽略权限访问权限,则可以访问
if (to.meta.ignoreAccess) {
return true;
}
// 没有访问权限,跳转登录页面
if (to.fullPath !== LOGIN_PATH) {
return {
path: LOGIN_PATH,
// 如不需要,直接删除 query
query: { redirect: encodeURIComponent(to.fullPath) },
// 携带当前跳转的页面,登录后重新跳转该页面
replace: true,
};
}
return to;
}
// 是否已经生成过动态路由
if (accessStore.isAccessChecked) {
return true;
}
// 生成路由表
// 当前登录用户拥有的角色标识列表
const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
const userRoles = userInfo.roles ?? [];
// debugger
// 二开从统一授权获取菜单key值遍历本地所有菜单进行添加
let staticRouteKeys = ["Dashboard", "home", "User", "UserCenter", "UserTodo","IFrame","MeetingStandingBook","MeetingStart","DutyStandingBook","ContractInfo"];
let r = await Apis.sys.user.functiontree.get_XTBGXT()
let originRouters = r.rows[0].children;
// 提取数据的函数
const extractData = (input: any[]) => {
const result: any[] = [];
function traverse(node: any) {
if (node.id && node.name && node.remark) {
result.push({
path: node.remark,
name: node.name,
order: node.showOrder || 0,
});
}
if (node.children && node.children.length > 0) {
for (const child of node.children) {
traverse(child);
}
}
}
for (const node of input) {
traverse(node);
}
return result;
}
console.log('originRouters', originRouters)
originRouters = extractData(originRouters);
console.log('originRouters', originRouters)
let finalRoutes = filterRoutesByPermissions(dynamicRoutes, originRouters, staticRouteKeys);
console.log(originRouters)
console.log('finalRoutes', finalRoutes)
console.log('dynamicRoutes', dynamicRoutes)
console.log('userInfo', userInfo)
if (userInfo.accountId == 'Admin.itl'|| userInfo._isSkip) {
finalRoutes = dynamicRoutes;
}
console.log(userInfo)
// 生成菜单和路由
const { accessibleMenus, accessibleRoutes } = await generateAccess({
roles: userRoles,
router,
// 则会在菜单中显示但是访问会被重定向到403
routes: finalRoutes,
});
// 保存菜单信息和路由信息
accessStore.setAccessMenus(accessibleMenus);
accessStore.setAccessRoutes(accessibleRoutes);
accessStore.setIsAccessChecked(true);
const redirectPath = (from.query.redirect ?? to.fullPath) as string;
return {
...router.resolve(decodeURIComponent(redirectPath)),
replace: true,
};
});
}
/**
*
* @param router
*/
function createRouterGuard(router: Router) {
/** 通用 */
setupCommonGuard(router);
/** 权限访问 */
setupAccessGuard(router);
}
export { createRouterGuard };

View File

@ -0,0 +1,32 @@
import {
createRouter,
createWebHashHistory,
createWebHistory,
} from 'vue-router';
import { resetStaticRoutes } from '@vben/utils';
import { createRouterGuard } from './guard';
import { routes } from './routes';
/**
* @zh_CN vue-router实例
*/
const router = createRouter({
history:
import.meta.env.VITE_ROUTER_HISTORY === 'hash'
? createWebHashHistory(import.meta.env.VITE_BASE)
: createWebHistory(import.meta.env.VITE_BASE),
// 应该添加到路由的初始路由列表。
routes,
scrollBehavior: () => ({ left: 0, top: 0 }),
// 是否应该禁止尾部斜杠。
// strict: true,
});
const resetRoutes = () => resetStaticRoutes(router, routes);
// 创建路由守卫
createRouterGuard(router);
export { resetRoutes, router };

View File

@ -0,0 +1,144 @@
import type { RouteRecordRaw } from 'vue-router';
import { DEFAULT_HOME_PATH } from '@vben/constants';
import { AuthPageLayout, BasicLayout, IFrameView } from '#/layouts';
import { $t } from '#/locales';
import Login from '#/views/_core/authentication/login.vue';
/** 全局404页面 */
const fallbackNotFoundRoute: RouteRecordRaw = {
component: () => import('#/views/_core/fallback/not-found.vue'),
meta: {
hideInBreadcrumb: true,
hideInMenu: true,
hideInTab: true,
title: '404',
},
name: 'FallbackNotFound',
path: '/:path(.*)*',
};
/** 基本路由,这些路由是必须存在的 */
const coreRoutes: RouteRecordRaw[] = [
{
meta: {
title: 'Root',
},
name: 'Root',
path: '/',
redirect: DEFAULT_HOME_PATH,
},
{
component: AuthPageLayout,
meta: {
title: 'Authentication',
},
name: 'Authentication',
path: '/auth',
children: [
{
name: 'Login',
path: 'login',
component: Login,
meta: {
title: $t('page.core.login'),
},
},
{
name: 'CodeLogin',
path: 'code-login',
component: () => import('#/views/_core/authentication/code-login.vue'),
meta: {
title: $t('page.core.codeLogin'),
},
},
{
name: 'QrCodeLogin',
path: 'qrcode-login',
component: () =>
import('#/views/_core/authentication/qrcode-login.vue'),
meta: {
title: $t('page.core.qrcodeLogin'),
},
},
{
name: 'ForgetPassword',
path: 'forget-password',
component: () =>
import('#/views/_core/authentication/forget-password.vue'),
meta: {
title: $t('page.core.forgetPassword'),
},
},
{
name: 'Register',
path: 'register',
component: () => import('#/views/_core/authentication/register.vue'),
meta: {
title: $t('page.core.register'),
},
},
],
},
{
component: IFrameView,
meta: {
icon: 'lucide:layout-dashboard',
order: 210,
title: 'iframe',
hideInMenu: true,
hideInTab: true,
},
name: 'IFrame',
path: '/iframe',
children: [
{
name: 'MeetingStandingBook',
path: '/iframe/meeting/standing-book',
component: () => import('#/views/meeting/standing-book/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '供热公司网络生产会议系统-会议查询篇',
},
},
{
name: 'MeetingStart',
path: '/iframe/meeting/start/:id?',
component: () => import('#/views/meeting/start/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '会议发起',
},
},
{
name: 'DutyStandingBook',
path: '/iframe/duty/standing-book',
component: () => import('#/views/duty/standing-book/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '值班信息栏',
},
},
{
name: 'ContractInfo',
path: '/iframe/contract/info',
component: () => import('#/views/contract/iframe-info/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '合同明细信息',
},
},
],
},
];
export { coreRoutes, fallbackNotFoundRoute };

View File

@ -0,0 +1,31 @@
import type { RouteRecordRaw } from 'vue-router';
import { mergeRouteModules, traverseTreeValues } from '@vben/utils';
import { coreRoutes, fallbackNotFoundRoute } from './core';
const dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {
eager: true,
});
// 有需要可以自行打开注释,并创建文件夹
// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });
/** 动态路由 */
const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
/** 外部路由列表访问这些页面可以不需要Layout可能用于内嵌在别的系统 */
// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);
const externalRoutes: RouteRecordRaw[] = [];
/** 路由列表,由基本路由+静态路由组成 */
const routes: RouteRecordRaw[] = [
...coreRoutes,
...externalRoutes,
fallbackNotFoundRoute,
];
/** 基本路由列表,这些路由不需要进入权限拦截 */
const coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);
export { coreRouteNames, dynamicRoutes, routes };

View File

@ -0,0 +1,438 @@
import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts';
const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
icon: 'lucide:layout-dashboard',
order: 2000,
title: '合同管理',
},
name: 'Contract',
path: '/contract',
children: [
{
name: 'ContractConfig',
path: '/contract/config',
component: () => import('#/views/contract/config/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '合同配置',
},
},
{
name: 'ContractApproval',
path: '/contract/approval',
meta: {
icon: 'lucide:area-chart',
title: '合同立项',
},
children: [
{
name: 'ContractApprovalEdit',
path: '/contract/approval/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = ''
e.fullPath = '/contract/approval/edit'
}
},
component: () => import('#/views/contract/approval/edit/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '立项申报',
activePath: '/contract/approval/edit/:id?'
},
},
{
name: 'ContractApprovalTodo',
path: '/contract/approval/todo',
component: () => import('#/views/contract/approval/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '立项提示',
},
},
{
name: 'ContractApprovalList',
path: '/contract/approval/list',
component: () => import('#/views/contract/approval/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '立项查询',
},
},
{
name: 'ContractApprovalSigningBasis',
path: '/contract/approval/signing-basis',
component: () => import('#/views/contract/approval/signing-basis/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '签约依据维护',
},
}
],
},
{
name: 'ContractBusiness',
path: '/contract/business',
meta: {
icon: 'lucide:area-chart',
title: '合同选商',
},
children: [
{
name: 'ContractBusiness',
path: '/contract/business/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = ''
e.fullPath = '/contract/business/edit'
}
},
component: () => import('#/views/contract/business/edit/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '选商填报',
activePath: '/contract/business/edit/:id?'
},
},
{
name: 'ContractBusinessTodo',
path: '/contract/business/todo',
component: () => import('#/views/contract/business/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '选商提示',
},
},
{
name: 'ContractBusinessList',
path: '/contract/business/list',
component: () => import('#/views/contract/business/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '选商查询',
},
},
],
},
{
name: 'ContractDeclaration',
path: '/contract/declaration',
meta: {
icon: 'lucide:area-chart',
title: '合同申报',
},
children: [
{
name: 'ContractDeclarationTodo',
path: '/contract/declaration/todo',
component: () => import('#/views/contract/declaration/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '申报提示',
},
},
{
name: 'ContractDeclarationList',
path: '/contract/declaration/list',
component: () => import('#/views/contract/declaration/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '申报查询',
},
},
{
name: 'ContractDeclarationPrint',
path: '/contract/declaration/print',
component: () => import('#/views/contract/declaration/print/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '合同打印',
},
},
],
},
{
name: 'ContractAudit',
path: '/contract/audit',
meta: {
icon: 'lucide:area-chart',
title: '合同审批',
},
children: [
{
name: 'ContractAuditTodo',
path: '/contract/audit/todo',
component: () => import('#/views/contract/audit/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '审批提示',
},
},
{
name: 'ContractAuditList',
path: '/contract/audit/list',
component: () => import('#/views/contract/audit/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '审批查询',
},
},
],
},
{
name: 'ContractSign',
path: '/contract/sign',
meta: {
icon: 'lucide:area-chart',
title: '合同签订',
},
children: [
{
name: 'ContractSignTodo',
path: '/contract/sign/todo',
component: () => import('#/views/contract/sign/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '签订提示',
},
},
{
name: 'ContractSignList',
path: '/contract/sign/list',
component: () => import('#/views/contract/sign/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '签订查询',
},
},
],
},
{
name: 'ContractPerform',
path: '/contract/perform',
meta: {
icon: 'lucide:area-chart',
title: '合同履行',
},
children: [
{
name: 'ContractPerformTodo',
path: '/contract/perform/todo',
component: () => import('#/views/contract/perform/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '履行提示',
},
},
{
name: 'ContractPerformList',
path: '/contract/perform/list',
component: () => import('#/views/contract/perform/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '履行查询',
},
},
{
name: 'ContractPerformResult',
path: '/contract/perform/result',
component: () => import('#/views/contract/perform/result/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '履行结果填报',
},
},
{
name: 'ContractPerformTemporaryArchive',
path: '/contract/perform/temporary-archive',
component: () => import('#/views/contract/perform/temporary-archive/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '临时归档',
},
},
],
},
{
name: 'ContractArchive',
path: '/contract/archive',
meta: {
icon: 'lucide:area-chart',
title: '合同归档',
},
children: [
{
name: 'ContractArchiveTodoArchive',
path: '/contract/archive/todo/archive',
component: () => import('#/views/contract/archive/todo/archive.vue'),
meta: {
icon: 'lucide:area-chart',
title: '合同归档',
},
},
{
name: 'ContractArchiveTodoRetracement',
path: '/contract/archive/todo/retracement',
component: () => import('#/views/contract/archive/todo/retracement.vue'),
meta: {
icon: 'lucide:area-chart',
title: '合同回档',
},
},
{
name: 'ContractArchiveList',
path: '/contract/archive/list',
component: () => import('#/views/contract/archive/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '归档查询',
},
},
],
},
{
name: 'ContractSignAuthorization',
path: '/contract/sign-authorization',
meta: {
icon: 'lucide:area-chart',
title: '签约授权管理',
},
children: [
{
name: 'ContractSignAuthorizationEdit',
path: '/contract/sign-authorization/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = ''
e.fullPath = '/contract/sign-authorization/edit'
}
},
component: () => import('#/views/contract/sign-authorization/edit/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '签约授权申报',
},
},
{
name: 'ContractSignAuthorizationList',
path: '/contract/sign-authorization/list',
component: () => import('#/views/contract/sign-authorization/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '签约授权查询',
},
},
],
},
{
name: 'ContractCompany',
path: '/contract/company',
meta: {
icon: 'lucide:area-chart',
title: '合同相对人',
},
children: [
{
name: 'ContractCompanyEdit',
path: '/contract/company/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = ''
e.fullPath = '/contract/company/edit'
}
},
component: () => import('#/views/contract/company/edit/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '相对人录入维护',
},
},
{
name: 'ContractCompanyList',
path: '/contract/company/list',
component: () => import('#/views/contract/company/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '相对人查询',
},
},
],
},
// {
// name: 'ContractStatistic',
// path: '/contract/statistic',
// meta: {
// icon: 'lucide:area-chart',
// title: '统计分析',
// },
// children: [
// {
// name: 'ContractStatisticAnalysis',
// path: '/contract/statistic/analysis',
// beforeEnter: (e) => {
// if (e.params.id && e.params.id === ':id') {
// e.params.id = ''
// e.fullPath = '/contract/company/edit'
// }
// },
// component: () => import('#/views/contract/company/edit/index.vue'),
// meta: {
// icon: 'lucide:area-chart',
// title: '统计分析',
// },
// },
// {
// name: 'ContractStatisticAbrogateList',
// path: '/contract/statistic/abrogate-list',
// component: () => import('#/views/contract/company/list/index.vue'),
// meta: {
// icon: 'lucide:area-chart',
// title: '废除查询',
// },
// },
// ],
// },
// {
// name: 'ContractPrint',
// path: '/contract/statistic',
// meta: {
// icon: 'lucide:area-chart',
// title: '统计分析',
// },
// children: [
// {
// name: 'ContractPrintBusiness',
// path: '/contract/print/business',
// component: () => import('#/views/contract/company/edit/index.vue'),
// meta: {
// icon: 'lucide:area-chart',
// title: '统计分析',
// },
// },
// {
// name: 'ContractPrintAbrogateList',
// path: '/contract/print/abrogate-list',
// component: () => import('#/views/contract/company/list/index.vue'),
// meta: {
// icon: 'lucide:area-chart',
// title: '废除查询',
// },
// },
// ],
// },
],
},
];
export default routes;

View File

@ -0,0 +1,49 @@
import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts';
const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
icon: 'lucide:layout-dashboard',
order: -1,
title: '首页',
},
name: 'Dashboard',
path: '/home',
children: [
{
name: 'home',
path: '/home',
component: () => import('#/views/dashboard/home/index.vue'),
meta: {
affixTab: true,
hideInMenu: true,
icon: 'lucide:area-chart',
title: '首页',
},
},
// {
// name: 'Analytics',
// path: '/analytics',
// component: () => import('#/views/dashboard/analytics/index.vue'),
// meta: {
// affixTab: true,
// icon: 'lucide:area-chart',
// title: $t('page.dashboard.analytics'),
// },
// },
// {
// name: 'Workspace',
// path: '/workspace',
// component: () => import('#/views/dashboard/workspace/index.vue'),
// meta: {
// title: $t('page.dashboard.workspace'),
// },
// },
],
},
];
export default routes;

View File

@ -0,0 +1,276 @@
import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts';
const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
icon: 'lucide:layout-dashboard',
order: 110,
title: '督查督办',
},
name: 'Supervise',
path: '/supervise',
children: [
{
name: 'SuperviseEdit',
path: '/supervise/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = ''
e.fullPath = '/supervise/edit'
}
},
component: () => import('#/views/supervise/edit/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '立项填报',
},
},
{
name: 'SuperviseList',
path: '/supervise/list',
component: () => import('#/views/supervise/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '立项查询',
},
},
{
name: 'SuperviseFeedback',
path: '/supervise/feedback',
component: () => import('#/views/supervise/feedback/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '执行与反馈',
},
},
{
name: 'SuperviseSummary',
path: '/supervise/summary',
component: () => import('#/views/supervise/summary/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '报表汇总',
},
},
],
},
{
component: BasicLayout,
meta: {
icon: 'lucide:layout-dashboard',
order: 210,
title: '会议管理',
},
name: 'Meeting',
path: '/meeting',
children: [
{
name: 'MeetingEdit',
path: '/meeting/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = ''
e.fullPath = '/meeting/edit'
}
},
component: () => import('#/views/meeting/edit/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '会议填报',
},
},
{
name: 'MeetingList',
path: '/meeting/list',
component: () => import('#/views/meeting/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '会议查询',
},
},
],
},
{
component: BasicLayout,
meta: {
icon: 'lucide:layout-dashboard',
order: 300,
title: '出差管理',
},
name: 'BussinessTrip',
path: '/bussiness-trip',
children: [
{
name: 'BussinessTripEdit',
path: '/bussiness-trip/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = ''
e.fullPath = '/bussiness-trip/edit'
}
},
component: () => import('#/views/bussiness-trip/edit/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '出差填报',
},
},
{
name: 'BussinessTripTodo',
path: '/bussiness-trip/todo',
component: () => import('#/views/bussiness-trip/todo/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '出差提示',
},
},
{
name: 'BussinessTripList',
path: '/bussiness-trip/list',
component: () => import('#/views/bussiness-trip/list/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '出差查询',
},
},
],
},
{
component: BasicLayout,
meta: {
icon: 'lucide:layout-dashboard',
order: 400,
title: '办公用品管理',
},
name: 'OfficeSupplies',
path: '/office-supplies',
children: [
{
name: 'OfficeSuppliesApply',
path: '/office-supplies/apply',
component: () => import('#/views/office-supplies/apply/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '用品申请',
},
},
{
name: 'OfficeSuppliesSettle',
path: '/office-supplies/settle',
component: () => import('#/views/office-supplies/settle/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '结算清单',
},
},
{
name: 'OfficeSuppliesAudit',
path: '/office-supplies/audit',
component: () => import('#/views/office-supplies/audit/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '用品审核',
},
},
{
name: 'OfficeSuppliesInventory',
path: '/office-supplies/inventory',
component: () => import('#/views/office-supplies/inventory/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '用品库存',
},
},
],
},
{
component: BasicLayout,
meta: {
icon: 'lucide:layout-dashboard',
order: 300,
title: '值班管理',
},
name: 'Duty',
path: '/duty/list',
children: [
{
name: 'DutyList',
path: '/duty/list',
component: () => import('#/views/duty/list/index.vue'),
meta: {
hideInMenu: true,
icon: 'lucide:area-chart',
title: '值班管理',
},
},
]
},
{
component: BasicLayout,
meta: {
icon: 'lucide:layout-dashboard',
order: 300,
title: '订餐管理',
},
name: 'canteen',
path: '/canteen',
children: [
{
name: 'canteen_config',
path: '/canteen/config',
component: () => import('#/views/canteen/config/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '订餐配置',
},
},
{
name: 'canteen_orderfood',
path: '/canteen/orderfood',
component: () => import('#/views/canteen/orderfood/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '订餐',
},
},
{
name: 'canteen_recipe',
path: '/canteen/recipe',
component: () => import('#/views/canteen/recipe/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '食谱',
},
},
{
name: 'canteen_collect',
path: '/canteen/collect',
component: () => import('#/views/canteen/collect/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '订餐汇总',
},
},
{
name: 'canteen_statistics',
path: '/canteen/statistics',
component: () => import('#/views/canteen/statistics/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '订餐统计',
},
},
],
},
];
export default routes;

View File

@ -0,0 +1,29 @@
import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts';
const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
icon: 'lucide:layout-dashboard',
order: 10,
title: '系统管理',
},
name: 'System',
path: '/system',
children: [
{
name: 'Dict',
path: '/system/dict',
component: () => import('#/views/system/dict/index.vue'),
meta: {
icon: 'lucide:area-chart',
title: '字典管理',
},
},
],
},
];
export default routes;

View File

@ -0,0 +1,51 @@
import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts';
const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
hideInMenu: true,
icon: 'lucide:layout-dashboard',
order: -1,
title: '用户中心',
},
name: 'User',
path: '/user',
children: [
{
name: 'UserTodo',
path: '/user/todo',
component: () => import('#/views/user-center/todo/index.vue'),
meta: {
hideInMenu: true,
icon: 'lucide:area-chart',
title: '消息通知',
},
},
{
name: 'UserCenter',
path: '/user/center',
component: () => import('#/views/user-center/center/index.vue'),
meta: {
hideInMenu: true,
icon: 'lucide:area-chart',
title: '个人中心',
},
},
{
name: 'About',
path: '/about',
component: () => import('#/views/_core/about/index.vue'),
meta: {
hideInMenu: true,
icon: 'lucide:area-chart',
title: '关于',
},
},
],
},
];
export default routes;

View File

@ -0,0 +1,131 @@
import type { LoginAndRegisterParams } from '@vben/common-ui';
import type { UserInfo } from '@vben/types';
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
import { notification } from 'ant-design-vue';
import { defineStore } from 'pinia';
import { getUserInfoApi, loginApi } from '#/api/system/auth';
import { $t } from '#/locales';
export const useAuthStore = defineStore('auth', () => {
const accessStore = useAccessStore();
const userStore = useUserStore();
const router = useRouter();
const loginLoading = ref(false);
let loginInfo = localStorage.getItem('loginInfo') || '{}';
/**
*
* Asynchronously handle the login process
* @param params
*/
async function authLogin(
params: LoginAndRegisterParams,
onSuccess?: () => Promise<void> | void,
) {
// 异步处理用户登录操作并获取 accessToken
let userInfo: null | UserInfo = null;
try {
loginLoading.value = true;
if(params.username == 'Admin.itl' || params._isSkip){
}else{
params.username = params.username + '.RL'
}
const loginRes = await loginApi({
...params,
appId: 'PLRL',
appName: 'ERP管理系统',
appSecret: 'r1og4wiyrrvr4qvw2aafhgvy',
});
console.log(loginRes);
if (params._isSkip) {
loginRes._isSkip = params._isSkip
}
loginInfo = JSON.stringify(loginRes);
localStorage.setItem('loginInfo', loginInfo);
const { accessToken } = loginRes;
// 如果成功获取到 accessToken
if (accessToken) {
accessStore.setAccessToken(accessToken);
// 获取用户信息并存储到 accessStore 中
const [fetchUserInfoResult] = await Promise.all([fetchUserInfo()]);
userInfo = fetchUserInfoResult;
if (params._isSkip) {
userInfo._isSkip = params._isSkip
}
userStore.setUserInfo(userInfo);
if (accessStore.loginExpired) {
accessStore.setLoginExpired(false);
} else {
onSuccess
? await onSuccess?.()
: await router.push(userInfo.homePath || DEFAULT_HOME_PATH);
}
if (userInfo?.realName) {
notification.success({
description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,
duration: 3,
message: $t('authentication.loginSuccess'),
});
}
}
} finally {
loginLoading.value = false;
}
return {
userInfo,
};
}
async function logout(redirect: boolean = true) {
// await logoutApi();
resetAllStores();
accessStore.setLoginExpired(false);
// 回登陆页带上当前路由地址
await router.replace({
path: LOGIN_PATH,
query: redirect
? {
redirect: encodeURIComponent(router.currentRoute.value.fullPath),
}
: {},
});
}
async function fetchUserInfo() {
let userInfo: null | UserInfo = null;
userInfo = await getUserInfoApi();
userInfo = { ...JSON.parse(loginInfo), ...userInfo }
userStore.setUserInfo(userInfo);
return userInfo;
}
function $reset() {
localStorage.removeItem('loginInfo');
loginLoading.value = false;
}
return {
$reset,
authLogin,
fetchUserInfo,
loginLoading,
logout,
};
});

View File

@ -1,8 +1,8 @@
import { defineStore } from 'pinia';
import { computed, ref } from 'vue';
import { getDictDataList } from '@/api/system/dict';
import { store } from '@/store';
import dataModule from '@/utils/dict/static.data'
// import { getDictDataList } from '@/api/system/dict';
import Apis from '#/api'
import dataModule from '#/utils/dict/static.data'
const DICT_STORAGE_KEY = 'DICT_KEY';
@ -38,7 +38,7 @@ export const useDictStore = defineStore(
*/
const setDictMap = async (): Promise<boolean> => {
try {
const data = await getDictDataList({ pageNum: 1, pageSize: 10000 });
const data = await Apis.dictData.get_page({ params: { pageNum: 1, pageSize: 10000 } });
const dictDataMap: Record<string, DictDataVO[]> = {};
// 处理静态字典数据
@ -159,6 +159,10 @@ export const useDictStore = defineStore(
return info.label;
};
function $reset() {
// loginLoading.value = false;
}
return {
initDict,
dictMap,
@ -170,14 +174,8 @@ export const useDictStore = defineStore(
getDictData,
getDictInfo,
getDictDataInfo,
getDictDataLabel
getDictDataLabel,
$reset
};
},
{
persist: true
}
);
export function useDictStoreWithOut() {
return useDictStore(store);
}

View File

@ -0,0 +1,2 @@
export * from './auth';
export * from './dict'

View File

@ -1,10 +1,10 @@
/** 数据字典工具类 */
import { useDictStoreWithOut } from '@/store/modules/dict';
import { useDictStore } from '#/store/dict';
export * from './shared';
const dictStore = useDictStoreWithOut();
const dictStore = useDictStore();
/**
* dictType
@ -80,7 +80,7 @@ export function getDictObj(dictType: string, value: any): DictDataType | null {
export function getDictDefaultObj(dictType: string): DictDataType | null {
const dictOptions: DictDataType[] = getDictDatas(dictType);
if (dictOptions) {
return dictOptions.find((dict: DictDataType) => dict.isDefault === true) || dictOptions[0];
return dictOptions.find((dict: DictDataType) => dict.isDefault == '1') || dictOptions[0];
} else {
return null;
}

View File

@ -0,0 +1,101 @@
import { message, type UploadProps } from "ant-design-vue";
import Apis from '#/api';
export class FileUploader {
fileList = [] as UploadProps['fileList'];
uploading = false;
constructor(params: any) {
}
select = async (fileUuids: string) => {
return new Promise<void>(async (resolve, reject) => {
Apis.attachment.get_list({
params: { uuid: fileUuids }
}).then((data) => {
let files = [] as UploadProps['fileList'];
for (const element of data.rows) {
files?.push({
uid: element.fileUuid,
name: element.fileName,
status: 'done',
url: element.fileUrl,
})
}
resolve(files)
}).catch(e => {
reject()
})
})
}
remove: UploadProps['onRemove'] = file => {
if (this.fileList) {
const index = this.fileList.indexOf(file);
const newFileList = this.fileList.slice();
newFileList.splice(index, 1);
this.fileList = newFileList;
}
};
upload = async (files?: UploadProps['fileList'], data?: any) => {
return new Promise<void>(async (resolve, reject) => {
if (this.fileList) {
const formData = new FormData();
if (data && Object.keys(data).length) {
Object.keys(data).forEach((key) => {
formData.append(key, data[key]);
});
}
let file = files ? files : this.fileList;
let alreadyUploaded = [] as string[];
file.forEach((file: UploadProps['fileList'][number]) => {
if (file.originFileObj) {
formData.append('files', file.originFileObj as any);
} else {
alreadyUploaded.push(file.uid)
}
});
this.uploading = true;
// You can use any AJAX library you like
try {
this.fileList = [];
this.uploading = false;
let files = []
for (const element of alreadyUploaded) {
files.push({
fileUuid: element,
})
}
const filesCount = formData.getAll('files').length;
if (filesCount > 0) {
let data = await Apis.attachment.post_uploads({
data: formData,
})
files = files.concat(data.rows)
message.success('上传成功.');
}
resolve(files || [])
} catch (error) {
this.uploading = false;
reject()
message.error('上传失败.');
} finally {
this.uploading = false;
}
}
reject()
});
};
}

View File

@ -1,45 +1,7 @@
import { h, unref } from 'vue';
import type { App, Component, Plugin } from 'vue';
import { NIcon, NTag } from 'naive-ui';
import { cloneDeep } from 'lodash-es';
import { deepClone } from '@vue/devtools-shared';
import { PageEnum } from '@/enums/pageEnum';
import { isObject } from './is';
/** render 图标 */
export function renderIcon(icon) {
return () => h(NIcon, null, { default: () => h(icon) });
}
/** font 图标(Font class) */
export function renderFontClassIcon(icon: string, iconName = 'iconfont') {
return () => h('span', { class: [iconName, icon] });
}
/** font 图标(Unicode) */
export function renderUnicodeIcon(icon: string, iconName = 'iconfont') {
return () => h('span', { class: [iconName], innerHTML: icon });
}
/** font svg 图标 */
export function renderfontsvg(icon) {
return () =>
h(NIcon, null, {
default: () => h('svg', { class: `icon`, 'aria-hidden': 'true' }, h('use', { 'xlink:href': `#${icon}` }))
});
}
import { cloneDeep, isObject } from 'lodash-es';
/** render new Tag */
const newTagColors = { color: '#f90', textColor: '#fff', borderColor: '#f90' };
export function renderNew(type = 'warning', text = 'New', color: object = newTagColors) {
return () =>
h(
NTag as any,
{
type,
round: true,
size: 'small',
color
},
{ default: () => text }
);
}
/** 递归组装菜单格式 */
export function generatorMenu(routerMap: Array<any>) {
@ -110,16 +72,6 @@ export function isRootRouter(item) {
return item.meta?.alwaysShow != true && item?.children?.filter(item => !item?.meta?.hidden)?.length === 1;
}
/** 排除Router */
export function filterRouter(routerMap: Array<any>) {
return routerMap.filter(item => {
return (
(item.meta?.hidden || false) != true &&
!['/:path(.*)*', '/', PageEnum.REDIRECT, PageEnum.BASE_LOGIN].includes(item.path)
);
});
}
export const withInstall = <T extends Component>(component: T, alias?: string) => {
const comp = component as any;
comp.install = (app: App) => {
@ -218,7 +170,7 @@ export function isUrl(url: string) {
* @returns {Array} treeData
*/
export function arrayToTree(originalArrayData, treeProps) {
const arrayData = deepClone(originalArrayData);
const arrayData = cloneDeep(originalArrayData);
let { id = '_id', parent_id = 'parent_id', children = 'children', deleteParentId = false, need_field } = treeProps;
const result = [];
const temp = {};

View File

@ -0,0 +1,3 @@
# \_core
此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。

View File

@ -0,0 +1,9 @@
<script lang="ts" setup>
import { About } from '@vben/common-ui';
defineOptions({ name: 'About' });
</script>
<template>
<About />
</template>

View File

@ -0,0 +1,30 @@
<script lang="ts" setup>
import type { LoginCodeParams } from '@vben/common-ui';
import { ref } from 'vue';
import { AuthenticationCodeLogin } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
defineOptions({ name: 'CodeLogin' });
const loading = ref(false);
/**
* 异步处理登录操作
* Asynchronously handle the login process
* @param values 登录表单数据
*/
async function handleLogin(values: LoginCodeParams) {
// eslint-disable-next-line no-console
console.log(values);
}
</script>
<template>
<AuthenticationCodeLogin
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleLogin"
/>
</template>

View File

@ -0,0 +1,23 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { AuthenticationForgetPassword } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
defineOptions({ name: 'ForgetPassword' });
const loading = ref(false);
function handleSubmit(value: string) {
// eslint-disable-next-line no-console
console.log('reset email:', value);
}
</script>
<template>
<AuthenticationForgetPassword
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleSubmit"
/>
</template>

View File

@ -0,0 +1,37 @@
<script lang="ts" setup>
import { AuthenticationLogin } from "@vben/common-ui";
import { useAuthStore } from "#/store";
defineOptions({ name: "Login" });
const authStore = useAuthStore();
const isDev = import.meta.env.DEV;
function mockLogin(username: string, password: string, isSkip: boolean = true) {
authStore.authLogin({
username,
password,
_isSkip: isSkip,
});
}
</script>
<template>
<AuthenticationLogin
:loading="authStore.loginLoading"
password-placeholder=""
username-placeholder=""
@submit="authStore.authLogin"
/>
<div v-if="isDev">
<p class="text-center">快速登录</p>
<a-space>
<a-button @click="mockLogin('Admin.itl', 'ABC123')">超级管理员</a-button>
<a-button @click="mockLogin('zhangxs.itl', 'Rlgs!6243910')">zxs</a-button>
<a-button @click="mockLogin('zengp.itl', 'Rlgs!6243910')">zp</a-button>
<a-button @click="mockLogin('rlqym', 'Rlgs!6243910', false)">rlqym</a-button>
</a-space>
</div>
</template>

View File

@ -0,0 +1,10 @@
<script lang="ts" setup>
import { AuthenticationQrCodeLogin } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
defineOptions({ name: 'QrCodeLogin' });
</script>
<template>
<AuthenticationQrCodeLogin :login-path="LOGIN_PATH" />
</template>

View File

@ -0,0 +1,25 @@
<script lang="ts" setup>
import type { LoginAndRegisterParams } from '@vben/common-ui';
import { ref } from 'vue';
import { AuthenticationRegister } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
defineOptions({ name: 'Register' });
const loading = ref(false);
function handleSubmit(value: LoginAndRegisterParams) {
// eslint-disable-next-line no-console
console.log('register submit:', value);
}
</script>
<template>
<AuthenticationRegister
:loading="loading"
:login-path="LOGIN_PATH"
@submit="handleSubmit"
/>
</template>

View File

@ -0,0 +1,7 @@
<script lang="ts" setup>
import { Fallback } from '@vben/common-ui';
</script>
<template>
<Fallback status="coming-soon" />
</template>

View File

@ -0,0 +1,9 @@
<script lang="ts" setup>
import { Fallback } from '@vben/common-ui';
defineOptions({ name: 'Fallback403Demo' });
</script>
<template>
<Fallback status="403" />
</template>

Some files were not shown because too many files have changed in this diff Show More