feat: initial commit

This commit is contained in:
gin
2026-05-07 18:39:00 +08:00
commit cdee21ee8e
653 changed files with 63946 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
+15
View File
@@ -0,0 +1,15 @@
# Shared frontend env reference. Copy values into each app-specific .env file.
# Web (Vite)
VITE_PORT=8848
VITE_PUBLIC_PATH=./
VITE_ROUTER_HISTORY="hash"
VITE_CDN=false
VITE_COMPRESSION="none"
VITE_HIDE_HOME=false
VITE_APP_BASE_API=/dev-api
# App (Taro)
TARO_APP_ID=
TARO_APP_API_BASE=
+11
View File
@@ -0,0 +1,11 @@
node_modules
dist
build
.taro
.cache
coverage
*.d.ts
public
src/assets
web/public
web/src/assets
+4
View File
@@ -0,0 +1,4 @@
shamefully-hoist=true
strict-peer-dependencies=false
shell-emulator=true
+10
View File
@@ -0,0 +1,10 @@
node_modules
dist
build
.taro
.cache
coverage
pnpm-lock.yaml
web/public
web/src/assets
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
bracketSpacing: true,
singleQuote: false,
arrowParens: "avoid",
trailingComma: "none"
};
+14
View File
@@ -0,0 +1,14 @@
node_modules
dist
build
.taro
.cache
coverage
web/public
web/src/assets
web/src/style/reset.scss
src/style/reset.scss
app/src/app.scss
app/src/pages/index/index.scss
src/app.scss
src/pages/index/index.scss
+4
View File
@@ -0,0 +1,4 @@
# Taro development environment
# TARO_APP_ID="your development app id"
TARO_APP_API_BASE=
+4
View File
@@ -0,0 +1,4 @@
# Taro production environment
# TARO_APP_ID="your production app id"
TARO_APP_API_BASE=
+4
View File
@@ -0,0 +1,4 @@
# Taro test environment
# TARO_APP_ID="your test app id"
TARO_APP_API_BASE=
+21
View File
@@ -0,0 +1,21 @@
// ESLint 检查 .vue 文件需要单独配置编辑器:
// https://eslint.vuejs.org/user-guide/#editor-integrations
{
"extends": ["taro/vue3", "../eslint.base.cjs"],
"parser": "vue-eslint-parser",
"parserOptions": {
"parser": "@typescript-eslint/parser",
"extraFileExtensions": [".vue"],
"ecmaVersion": "latest",
"sourceType": "module"
},
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"parser": "@typescript-eslint/parser"
}
],
"rules": {
"vue/multi-word-component-names": "off"
}
}
+8
View File
@@ -0,0 +1,8 @@
dist/
deploy_versions/
.temp/
.rn_temp/
node_modules/
.DS_Store
.swc
*.local
+11
View File
@@ -0,0 +1,11 @@
// babel-preset-taro 更多选项和默认值:
// https://docs.taro.zone/docs/next/babel-config
module.exports = {
presets: [
['taro', {
framework: 'vue3',
ts: true,
compiler: 'vite',
}]
]
}
+7
View File
@@ -0,0 +1,7 @@
import type { UserConfigExport } from "@tarojs/cli"
export default {
mini: {},
h5: {}
} satisfies UserConfigExport<'vite'>
+90
View File
@@ -0,0 +1,90 @@
import { defineConfig, type UserConfigExport } from '@tarojs/cli'
import devConfig from './dev'
import prodConfig from './prod'
// https://taro-docs.jd.com/docs/next/config#defineconfig-辅助函数
export default defineConfig<'vite'>(async merge => {
const baseConfig: UserConfigExport<'vite'> = {
projectName: 'app',
date: '2026-5-6',
designWidth: 750,
deviceRatio: {
640: 2.34 / 2,
750: 1,
375: 2,
828: 1.81 / 2
},
sourceRoot: 'src',
outputRoot: 'dist',
plugins: [
"@tarojs/plugin-generator"
],
defineConstants: {
},
copy: {
patterns: [
],
options: {
}
},
framework: 'vue3',
compiler: 'vite',
mini: {
postcss: {
pxtransform: {
enable: true,
config: {
}
},
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
config: {
namingPattern: 'module', // 转换模式,取值为 global/module
generateScopedName: '[name]__[local]___[hash:base64:5]'
}
}
},
},
h5: {
publicPath: '/',
staticDirectory: 'static',
miniCssExtractPluginOption: {
ignoreOrder: true,
filename: 'css/[name].[hash].css',
chunkFilename: 'css/[name].[chunkhash].css'
},
postcss: {
autoprefixer: {
enable: true,
config: {}
},
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
config: {
namingPattern: 'module', // 转换模式,取值为 global/module
generateScopedName: '[name]__[local]___[hash:base64:5]'
}
}
},
},
rn: {
appName: 'taroDemo',
postcss: {
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
}
}
}
}
if (process.env.NODE_ENV === 'development') {
// 本地开发构建配置(不混淆压缩)
return merge({}, baseConfig, devConfig)
}
// 生产构建配置(默认开启压缩混淆等)
return merge({}, baseConfig, prodConfig)
})
+33
View File
@@ -0,0 +1,33 @@
import type { UserConfigExport } from "@tarojs/cli"
export default {
mini: {},
h5: {
/**
* WebpackChain 插件配置
* @docs https://github.com/neutrinojs/webpack-chain
*/
// webpackChain (chain) {
// /**
// * 如果 h5 端编译后体积过大,可以使用 webpack-bundle-analyzer 插件对打包体积进行分析。
// * @docs https://github.com/webpack-contrib/webpack-bundle-analyzer
// */
// chain.plugin('analyzer')
// .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [])
// /**
// * 如果 h5 端首屏加载时间过长,可以使用 prerender-spa-plugin 插件预加载首页。
// * @docs https://github.com/chrisvfritz/prerender-spa-plugin
// */
// const path = require('path')
// const Prerender = require('prerender-spa-plugin')
// const staticDir = path.join(__dirname, '..', 'dist')
// chain
// .plugin('prerender')
// .use(new Prerender({
// staticDir,
// routes: [ '/pages/index/index' ],
// postProcess: (context) => ({ ...context, outputPath: path.join(staticDir, 'index.html') })
// }))
// }
}
} satisfies UserConfigExport<'vite'>
+78
View File
@@ -0,0 +1,78 @@
{
"name": "@simple-template/app",
"version": "1.0.0",
"private": true,
"description": "simple app",
"templateInfo": {
"name": "default",
"typescript": true,
"css": "Sass",
"framework": "Vue3"
},
"scripts": {
"prepare": "echo \"Git hooks are managed by ../../.githooks\"",
"new": "taro new",
"build:weapp": "taro build --type weapp",
"build:swan": "taro build --type swan",
"build:alipay": "taro build --type alipay",
"build:tt": "taro build --type tt",
"build:h5": "taro build --type h5",
"build:rn": "taro build --type rn",
"build:qq": "taro build --type qq",
"build:jd": "taro build --type jd",
"build:harmony-hybrid": "taro build --type harmony-hybrid",
"dev:weapp": "pnpm build:weapp -- --watch",
"dev:swan": "pnpm build:swan -- --watch",
"dev:alipay": "pnpm build:alipay -- --watch",
"dev:tt": "pnpm build:tt -- --watch",
"dev:h5": "pnpm build:h5 -- --watch",
"dev:rn": "pnpm build:rn -- --watch",
"dev:qq": "pnpm build:qq -- --watch",
"dev:jd": "pnpm build:jd -- --watch",
"dev:harmony-hybrid": "pnpm build:harmony-hybrid -- --watch",
"lint": "eslint --ignore-path ../.eslintignore \"{src,config}/**/*.{vue,js,ts,tsx}\" && pnpm --dir .. exec stylelint \"app/src/**/*.{vue,css,scss}\" --config ./stylelint.config.cjs --ignore-path ./.stylelintignore",
"typecheck": "tsc --noEmit"
},
"browserslist": [
"defaults and fully supports es6-module",
"maintained node versions"
],
"author": "",
"dependencies": {
"@babel/runtime": "^7.24.4",
"@tarojs/components": "4.2.0",
"@tarojs/helper": "4.2.0",
"@tarojs/plugin-platform-weapp": "4.2.0",
"@tarojs/plugin-platform-alipay": "4.2.0",
"@tarojs/plugin-platform-tt": "4.2.0",
"@tarojs/plugin-platform-swan": "4.2.0",
"@tarojs/plugin-platform-jd": "4.2.0",
"@tarojs/plugin-platform-qq": "4.2.0",
"@tarojs/plugin-platform-h5": "4.2.0",
"@tarojs/plugin-platform-harmony-hybrid": "4.2.0",
"@tarojs/runtime": "4.2.0",
"@tarojs/shared": "4.2.0",
"@tarojs/taro": "4.2.0",
"@tarojs/plugin-framework-vue3": "4.2.0",
"vue": "^3.0.0"
},
"devDependencies": {
"@tarojs/plugin-generator": "4.2.0",
"@babel/core": "^7.24.4",
"@babel/plugin-transform-class-properties": "7.25.9",
"@tarojs/cli": "4.2.0",
"@tarojs/vite-runner": "4.2.0",
"babel-preset-taro": "4.2.0",
"eslint-config-taro": "4.2.0",
"eslint": "^8.57.0",
"terser": "^5.30.4",
"vite": "^4.2.0",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"eslint-plugin-vue": "^9.17.0",
"sass": "^1.75.0",
"typescript": "^5.4.5",
"postcss": "^8.5.6",
"@types/minimatch": "^5"
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"miniprogramRoot": "./dist",
"projectname": "app",
"description": "simple app",
"appid": "touristappid",
"setting": {
"urlCheck": true,
"es6": false,
"enhance": false,
"compileHotReLoad": false,
"postcss": false,
"minified": false
},
"compileType": "miniprogram"
}
+11
View File
@@ -0,0 +1,11 @@
export default defineAppConfig({
pages: [
'pages/index/index'
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#fff',
navigationBarTitleText: 'WeChat',
navigationBarTextStyle: 'black'
}
})
View File
+15
View File
@@ -0,0 +1,15 @@
import { createApp } from 'vue'
import './app.scss'
const App = createApp({
onShow () {
console.log('App onShow.')
},
// 入口组件不需要实现 render 方法,即使实现了也会被 taro 所覆盖
})
export default App
+17
View File
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta content="width=device-width,initial-scale=1,user-scalable=no" name="viewport">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-touch-fullscreen" content="yes">
<meta name="format-detection" content="telephone=no,address=no">
<meta name="apple-mobile-web-app-status-bar-style" content="white">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" >
<title>app</title>
<script><%= htmlWebpackPlugin.options.script %></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
@@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: '首页'
})
+19
View File
@@ -0,0 +1,19 @@
<template>
<view class="index">
<text>{{ msg }}</text>
</view>
</template>
<script>
import { ref } from 'vue'
import './index.scss'
export default {
setup () {
const msg = ref('Hello world')
return {
msg
}
}
}
</script>
+31
View File
@@ -0,0 +1,31 @@
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
"removeComments": false,
"preserveConstEnums": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"noImplicitAny": false,
"allowSyntheticDefaultImports": true,
"outDir": "lib",
"noUnusedLocals": true,
"noUnusedParameters": true,
"strictNullChecks": true,
"sourceMap": true,
"rootDir": ".",
"jsx": "preserve",
"allowJs": true,
"resolveJsonModule": true,
"typeRoots": [
"node_modules/@types"
],
"paths": {
// TS5090 leading './'
"@/*": ["./src/*"]
}
},
"include": ["./src", "./types", "./config"],
"compileOnSave": false
}
+31
View File
@@ -0,0 +1,31 @@
/// <reference types="@tarojs/taro" />
declare module '*.png';
declare module '*.gif';
declare module '*.jpg';
declare module '*.jpeg';
declare module '*.svg';
declare module '*.css';
declare module '*.less';
declare module '*.scss';
declare module '*.sass';
declare module '*.styl';
declare namespace NodeJS {
interface ProcessEnv {
/** NODE 内置环境变量, 会影响到最终构建生成产物 */
NODE_ENV: 'development' | 'production',
/** 当前构建的平台 */
TARO_ENV: 'weapp' | 'swan' | 'alipay' | 'h5' | 'rn' | 'tt' | 'qq' | 'jd' | 'harmony' | 'jdrn'
/**
* 当前构建的小程序 appid
* @description 若不同环境有不同的小程序,可通过在 env 文件中配置环境变量`TARO_APP_ID`来方便快速切换 appid 而不必手动去修改 dist/project.config.json 文件
* @see https://taro-docs.jd.com/docs/next/env-mode-config#特殊环境变量-taro_app_id
*/
TARO_APP_ID: string
}
}
declare module '@tarojs/components' {
export * from '@tarojs/components/types/index.vue3'
}
+10
View File
@@ -0,0 +1,10 @@
export {}
declare module 'vue' {
export interface GlobalComponents extends JSX.IntrinsicElements {
/** Note: Vue 在 runtime 中将 JSX.IntrinsicElements 通过 index signature 重复声明标签
* 这会导致插件无法正常跳转类型,可以手动覆盖声明标签活得更好的体验,参考如下:
* 'scroll-view': JSX.IntrinsicElements['scroll-view']
*/
}
}
+21
View File
@@ -0,0 +1,21 @@
module.exports = {
env: {
browser: true,
es2021: true,
node: true
},
parserOptions: {
ecmaVersion: "latest",
sourceType: "module"
},
rules: {
"no-debugger": "off",
"no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
]
}
};
+53
View File
@@ -0,0 +1,53 @@
{
"name": "frontend",
"version": "1.0.0",
"private": true,
"author": "GIN",
"description": "simple template frontend",
"scripts": {
"dev:web": "pnpm --filter @simple-template/web dev",
"build:web": "pnpm --filter @simple-template/web build",
"preview:web": "pnpm --filter @simple-template/web preview",
"typecheck:web": "pnpm --filter @simple-template/web typecheck",
"dev:app:weapp": "pnpm --filter @simple-template/app dev:weapp",
"build:app:weapp": "pnpm --filter @simple-template/app build:weapp",
"dev:app:h5": "pnpm --filter @simple-template/app dev:h5",
"build:app:h5": "pnpm --filter @simple-template/app build:h5",
"lint:web": "pnpm --filter @simple-template/web lint",
"lint:app": "pnpm --filter @simple-template/app lint",
"lint": "pnpm lint:web && pnpm lint:app",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,vue,css,scss,html,json,md}\"",
"typecheck:app": "pnpm --filter @simple-template/app typecheck",
"typecheck": "pnpm typecheck:web && pnpm typecheck:app"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.60.0",
"@typescript-eslint/parser": "^5.60.0",
"postcss-html": "^1.5.0",
"postcss-scss": "^4.0.6",
"prettier": "^2.8.8",
"stylelint": "^16.4.0",
"stylelint-config-html": "^1.1.0",
"stylelint-config-recess-order": "^4.2.0",
"stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard": "^38.0.0",
"stylelint-config-standard-scss": "^13.1.0",
"stylelint-order": "^6.0.3",
"stylelint-scss": "^6.12.1",
"typescript": "^5.4.5"
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"rollup",
"webpack",
"core-js"
]
},
"allowedDeprecatedVersions": {
"sourcemap-codec": "*",
"w3c-hr-time": "*",
"stable": "*"
}
}
}
+13508
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -0,0 +1,4 @@
packages:
- "web"
- "app"
+86
View File
@@ -0,0 +1,86 @@
module.exports = {
root: true,
extends: [
"stylelint-config-standard",
"stylelint-config-html/vue",
"stylelint-config-recess-order"
],
plugins: ["stylelint-order", "stylelint-scss"],
overrides: [
{
files: ["**/*.{css,html,vue}"],
customSyntax: "postcss-html"
},
{
files: ["**/*.scss"],
customSyntax: "postcss-scss",
extends: [
"stylelint-config-standard-scss",
"stylelint-config-recommended-vue/scss"
]
}
],
rules: {
"selector-class-pattern": null,
"no-empty-source": null,
"no-descending-specificity": null,
"declaration-property-value-no-unknown": null,
"scss/dollar-variable-pattern": null,
"selector-pseudo-class-no-unknown": [
true,
{
ignorePseudoClasses: ["deep", "global"]
}
],
"selector-pseudo-element-no-unknown": [
true,
{
ignorePseudoElements: ["v-deep", "v-global", "v-slotted"]
}
],
"at-rule-no-unknown": [
true,
{
ignoreAtRules: [
"tailwind",
"apply",
"variants",
"responsive",
"screen",
"function",
"if",
"each",
"include",
"mixin",
"use"
]
}
],
"rule-empty-line-before": [
"always",
{
ignore: ["after-comment", "first-nested"]
}
],
"unit-no-unknown": [true, { ignoreUnits: ["rpx"] }],
"order/order": [
[
"dollar-variables",
"custom-properties",
"at-rules",
"declarations",
{
type: "at-rule",
name: "supports"
},
{
type: "at-rule",
name: "media"
},
"rules"
],
{ severity: "warning" }
]
},
ignoreFiles: ["**/*.js", "**/*.ts", "**/*.jsx", "**/*.tsx"]
};
+16
View File
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "esnext",
"moduleResolution": "node",
"strict": false,
"experimentalDecorators": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"sourceMap": true,
"resolveJsonModule": true,
"jsx": "preserve"
}
}
+21
View File
@@ -0,0 +1,21 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
.eslintcache
report.html
yarn.lock
npm-debug.log*
.pnpm-error.log*
.pnpm-debug.log
tests/**/coverage/
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
tsconfig.tsbuildinfo
+4
View File
@@ -0,0 +1,4 @@
# Web default environment
VITE_PORT = 8848
VITE_HIDE_HOME = false
+6
View File
@@ -0,0 +1,6 @@
# Web development environment
VITE_PORT = 80
VITE_PUBLIC_PATH = ./
VITE_ROUTER_HISTORY = "hash"
VITE_APP_BASE_API = '/dev-api'
+7
View File
@@ -0,0 +1,7 @@
# Web production environment
VITE_PUBLIC_PATH = ./
VITE_ROUTER_HISTORY = "hash"
VITE_CDN = false
VITE_COMPRESSION = "none"
VITE_APP_BASE_API = '/prod-api'
+7
View File
@@ -0,0 +1,7 @@
# Web staging environment
VITE_PUBLIC_PATH = ./
VITE_ROUTER_HISTORY = "hash"
VITE_CDN = true
VITE_COMPRESSION = "none"
VITE_APP_BASE_API = '/stage-api'
+121
View File
@@ -0,0 +1,121 @@
module.exports = {
root: true,
env: {
node: true
},
globals: {
// Ref sugar (take 2)
$: "readonly",
$$: "readonly",
$ref: "readonly",
$shallowRef: "readonly",
$computed: "readonly",
// index.d.ts
// global.d.ts
Fn: "readonly",
PromiseFn: "readonly",
RefType: "readonly",
LabelValueOptions: "readonly",
EmitType: "readonly",
TargetContext: "readonly",
ComponentElRef: "readonly",
ComponentRef: "readonly",
ElRef: "readonly",
global: "readonly",
ForDataType: "readonly",
ComponentRoutes: "readonly",
// script setup
defineProps: "readonly",
defineEmits: "readonly",
defineExpose: "readonly",
withDefaults: "readonly"
},
extends: [
"../eslint.base.cjs",
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/typescript/recommended",
"@vue/prettier",
"@vue/eslint-config-typescript"
],
parser: "vue-eslint-parser",
parserOptions: {
parser: "@typescript-eslint/parser",
ecmaVersion: 2020,
sourceType: "module",
jsxPragma: "React",
ecmaFeatures: {
jsx: true
}
},
overrides: [
{
files: ["*.ts", "*.vue"],
rules: {
"no-undef": "off"
}
},
{
files: ["*.vue"],
parser: "vue-eslint-parser",
parserOptions: {
parser: "@typescript-eslint/parser",
extraFileExtensions: [".vue"],
ecmaVersion: "latest",
ecmaFeatures: {
jsx: true
}
},
rules: {
"no-undef": "off"
}
}
],
rules: {
"vue/no-v-html": "off",
"vue/require-default-prop": "off",
"vue/require-explicit-emits": "off",
"vue/multi-word-component-names": "off",
"@typescript-eslint/no-explicit-any": "off", // any
"no-debugger": "off",
"@typescript-eslint/explicit-module-boundary-types": "off", // setup()
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"vue/html-self-closing": [
"error",
{
html: {
void: "always",
normal: "always",
component: "always"
},
svg: "always",
math: "always"
}
],
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
],
"no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
],
"prettier/prettier": [
"error",
{
endOfLine: "auto"
}
]
}
};
+24
View File
@@ -0,0 +1,24 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
.eslintcache
report.html
yarn.lock
npm-debug.log*
.pnpm-error.log*
.pnpm-debug.log
tests/**/coverage/
# 本机调试debug配置文件
.vscode/launch.json
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
tsconfig.tsbuildinfo
+31
View File
@@ -0,0 +1,31 @@
{
"recommendations": [
"akamud.vscode-theme-onedark",
"antfu.iconify",
"bradlc.vscode-tailwindcss",
"christian-kohler.npm-intellisense",
"christian-kohler.path-intellisense",
"Codeium.codeium",
"csstools.postcss",
"DavidAnson.vscode-markdownlint",
"dbaeumer.vscode-eslint",
"donjayamanne.githistory",
"dsznajder.es7-react-js-snippets",
"eamodio.gitlens",
"ecmel.vscode-html-css",
"esbenp.prettier-vscode",
"genieai.chatgpt-vscode",
"hollowtree.vue-snippets",
"lokalise.i18n-ally",
"mhutchie.git-graph",
"mikestead.dotenv",
"pmneo.tsimporter",
"streetsidesoftware.code-spell-checker",
"stylelint.vscode-stylelint",
"syler.sass-indented",
"sysoev.language-stylus",
"vscode-icons-team.vscode-icons",
"Vue.volar",
"xabikos.JavaScriptSnippets"
]
}
+32
View File
@@ -0,0 +1,32 @@
{
"editor.formatOnType": true,
"editor.formatOnSave": true,
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.tabSize": 2,
"editor.formatOnPaste": true,
"editor.guides.bracketPairs": "active",
"files.autoSave": "afterDelay",
"git.confirmSync": false,
"workbench.startupEditor": "newUntitledFile",
"editor.suggestSelection": "first",
"editor.acceptSuggestionOnCommitCharacter": false,
"css.lint.propertyIgnoredDueToDisplay": "ignore",
"editor.quickSuggestions": {
"other": true,
"comments": true,
"strings": true
},
"files.associations": {
"editor.snippetSuggestions": "top"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"iconify.excludes": ["el"],
"cSpell.words": ["iconify", "Qrcode"]
}
+22
View File
@@ -0,0 +1,22 @@
{
"Vue3.0快速生成模板": {
"scope": "vue",
"prefix": "Vue3.0",
"body": [
"<template>",
"\t<div>test</div>",
"</template>\n",
"<script lang='ts'>",
"export default {",
"\tsetup() {",
"\t\treturn {}",
"\t}",
"}",
"</script>\n",
"<style lang='scss' scoped>\n",
"</style>",
"$2"
],
"description": "Vue3.0"
}
}
+17
View File
@@ -0,0 +1,17 @@
{
"Vue3.2+快速生成模板": {
"scope": "vue",
"prefix": "Vue3.2+",
"body": [
"<script setup lang='ts'>",
"</script>\n",
"<template>",
"\t<div>test</div>",
"</template>\n",
"<style lang='scss' scoped>\n",
"</style>",
"$2"
],
"description": "Vue3.2+"
}
}
+20
View File
@@ -0,0 +1,20 @@
{
"Vue3.3+defineOptions快速生成模板": {
"scope": "vue",
"prefix": "Vue3.3+",
"body": [
"<script setup lang='ts'>",
"defineOptions({",
"\tname: ''",
"})",
"</script>\n",
"<template>",
"\t<div>test</div>",
"</template>\n",
"<style lang='scss' scoped>\n",
"</style>",
"$2"
],
"description": "Vue3.3+defineOptions快速生成模板"
}
}
+20
View File
@@ -0,0 +1,20 @@
FROM node:16-alpine as build-stage
WORKDIR /app
RUN corepack enable
RUN corepack prepare pnpm@7.32.1 --activate
RUN npm config set registry https://registry.npmmirror.com
COPY .npmrc package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020-present, pure-admin
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 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.
+36
View File
@@ -0,0 +1,36 @@
<h1>vue-pure-admin Lite Editionno i18n version</h1>
[![license](https://img.shields.io/github/license/pure-admin/vue-pure-admin.svg)](LICENSE)
**English** | [中文](./README.md)
## Introduce
The simplified version is based on the shelf extracted from [vue-pure-admin](https://github.com/pure-admin/vue-pure-admin), which contains main functions and is more suitable for actual project development. The packaged size is introduced globally [element-plus](https://element-plus.org) is still below `2.3MB`, and the full version of the code will be permanently synchronized. After enabling `brotli` compression and `cdn` to replace the local library mode, the package size is less than `350kb`
## Supporting Video
- [Click Watch Tutorial](https://www.bilibili.com/video/BV1kg411v7QT)
- [Click Watch UI Design](https://www.bilibili.com/video/BV17g411T7rq)
## Docs
- [documentation site](https://yiming_chang.gitee.io/pure-admin-doc)
## Preview
- [Click me to view the preview station](https://pure-admin-thin.netlify.app/#/login)
## Maintainer
[xiaoxian521](https://github.com/xiaoxian521)
## ⚠️ Attention
- The Lite version does not accept any issues and prs. If you have any questions, please go to the full version [issues](https://github.com/pure-admin/vue-pure-admin/issues/new/choose) to mention, thank you!
## License
In principle, no fees and copyrights are charged, and it is commercially available, but if you need secondary open source (such as using this platform for secondary development and open source, the front-end code must be open source and free), please contact the author for permission! (Free, just take a record)
[MIT © 2020-present, pure-admin](./LICENSE)
+145
View File
@@ -0,0 +1,145 @@
<p align="center">
<img src="https://img.shields.io/badge/Release-V1.8.0-green.svg" alt="Downloads">
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" alt="Build Status">
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="Build Status">
<img src="https://img.shields.io/badge/Spring%20Boot-2.7.1-blue.svg" alt="Downloads">
<a target="_blank" href="https://bladex.vip">
<img src="https://img.shields.io/badge/Author-valarchie-ff69b4.svg" alt="Downloads">
</a>
<a target="_blank" href="https://bladex.vip">
<img src="https://img.shields.io/badge/Copyright%20-@Agileboot-%23ff3f59.svg" alt="Downloads">
</a>
</p>
<p align="center">
<img alt="logo" height="200" src="https://oscimg.oschina.net/oscnet/up-eda2a402cc061f1f5f40d9ac4c084f4c98c.png">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">AgileBoot v2.0.0</h1>
<h4 align="center">基于SpringBoot+Vue3前后端分离的Java快速开发框架</h4>
<p align="center">
</p>
## ⚡ 平台简介 ⚡
- 本仓库是 Agilboot 快速开发脚手架的配套前端项目。前端是基于优秀的开源项目[Pure-Admin](https://github.com/pure-admin/vue-pure-admin)开发而成。在此感谢 Pure-Admin 作者。
- 本仓库前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) 版本。
- 配套后端代码仓库地址[AgileBoot-Back-End](https://github.com/valarchie/AgileBoot-Back-End) 版本。
- 规范请参照该文档 [前端规范](https://gitee.com/MinJieLiu/web-standard#/MinJieLiu/web-standard)
### 前端配套资料
#### 配套视频
- [点我查看教程](https://www.bilibili.com/video/BV1kg411v7QT)
- [点我查看 UI 设计](https://www.bilibili.com/video/BV17g411T7rq)
#### 配套保姆级文档
- [查看文档](https://yiming_chang.gitee.io/pure-admin-doc)
#### Pure-Admin 框架预览
- [查看预览](https://pure-admin-thin.netlify.app/#/login)
#### Pure-Admin 维护者
- [xiaoxian521](https://github.com/xiaoxian521)
## ✨ 使用 ✨
### 开发环境
Node.js 版本要求:16.0+
pnpm 版本要求:6.0+
优先选择 node=16, pnpm=7.30.5的环境.
如果您还没安装 pnpm,请执行下面命令进行安装(mac 用户遇到安装报错请在命令前加上 sudo) 如果是 windows 用户,使用 power shell 管理员权限执行
```
npm install -g pnpm
```
安装依赖
```
pnpm install
```
启动平台
```
pnpm run dev
```
不管是什么源,我们都可以不用管,直接执行下面命令即可
npm config set registry https://registry.npmmirror.com
上面的命令是将本地的源换成国内源 npmmirror
(opens new window),经过几轮测试,发现它的下载速度快且同步率高,同步频率 10 分钟一次,如果您之前的源是这个 http://registry.npm.taobao.org ,那您必须换成 npmmirror 啦,因为原淘宝 npm 域名即将停止解析
## 🙊 系统内置功能 🙊
🙂 大部分功能,均有通过 **单元测试** **集成测试** 保证质量。
| | 功能 | 描述 |
| --- | ---------- | ------------------------------------------------------------- |
| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 |
| ⭐ | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |
| ⭐ | 岗位管理 | 配置系统用户所属担任职务 |
| | 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等,本地缓存提供性能 |
| ⭐ | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 |
| | 参数管理 | 对系统动态配置常用参数 |
| | 通知公告 | 系统通知公告信息发布维护 |
| 🚀 | 操作日志 | 系统正常操作日志记录和查询;系统异常信息日志记录和查询 |
| | 登录日志 | 系统登录日志记录查询包含登录异常 |
| | 在线用户 | 当前系统中活跃用户状态监控 |
| | 系统接口 | 根据业务代码自动生成相关的 api 接口文档 |
| | 服务监控 | 监视当前系统 CPU、内存、磁盘、堆栈等相关信息 |
| | 缓存监控 | 对系统的缓存信息查询,命令统计等 |
| | 连接池监视 | 监视当前系统数据库连接池状态,可进行分析 SQL 找出系统性能瓶颈 |
## 💥 在线体验 💥
演示地址:
- <www.agileboot.vip>
- <www.agileboot.cc>
> 账号密码:admin/admin123
[项目文档](https://juejin.cn/column/7159946528827080734)
## 🎬 AgileBoot 全栈交流群 🎬
QQ 群: [![加入QQ群](https://img.shields.io/badge/1398880-blue.svg)](https://qm.qq.com/cgi-bin/qm/qr?k=TR5guoXS0HssErVWefmdFRirJvfpEvp1&jump_from=webapi&authKey=VkWMmVhp/pNdWuRD8sqgM+Sv2+Vy2qCJQSeLmeXlLtfER2RJBi6zL56PdcRlCmTs) 点击按钮入群。
如果觉得该项目对您有帮助,可以小额捐赠支持本项目演示网站服务器等费用~
<img alt="logo" height="200" src="https://oscimg.oschina.net/oscnet/up-28b63fdd7b3ce003bd30c25883f2276212b.png">
### 用法
#### 安装依赖
```
pnpm install
```
#### 安装一个包
```
pnpm add 包名
```
#### 卸载一个包
```
pnpm remove 包名
```
### 许可证
原则上不收取任何费用及版权,可商用,不过如需二次开源(比如用此平台二次开发并开源,要求前端代码必须开源免费)请联系作者获取许可!(免费,走个记录而已)
+57
View File
@@ -0,0 +1,57 @@
import { Plugin as importToCDN } from "vite-plugin-cdn-import";
/**
* @description 打包时采用`cdn`模式,仅限外网使用(默认不采用,如果需要采用cdn模式,请在 .env.production 文件,将 VITE_CDN 设置成true
* 平台采用国内cdnhttps://www.bootcdn.cn,当然你也可以选择 https://unpkg.com 或者 https://www.jsdelivr.com
* 提醒:mockjs不能用cdn模式引入,会报错。正确的方式是,生产环境删除mockjs,使用真实的后端请求
* 注意:上面提到的仅限外网使用也不是完全肯定的,如果你们公司内网部署的有相关js、css文件,也可以将下面配置对应改一下,整一套内网版cdn
*/
export const getCdnPlugin = () =>
importToCDN({
//prodUrl解释: name: 对应下面modules的nameversion: 自动读取本地package.json中dependencies依赖中对应包的版本号,path: 对应下面modules的path,当然也可写完整路径,会替换prodUrl)
prodUrl: "https://cdn.bootcdn.net/ajax/libs/{name}/{version}/{path}",
modules: [
{
name: "vue",
var: "Vue",
path: "vue.global.prod.min.js"
},
{
name: "vue-router",
var: "VueRouter",
path: "vue-router.global.min.js"
},
// 项目中没有直接安装vue-demi,但是pinia用到了,所以需要在引入pinia前引入vue-demihttps://github.com/vuejs/pinia/blob/v2/packages/pinia/package.json#L77
{
name: "vue-demi",
var: "VueDemi",
path: "index.iife.min.js"
},
{
name: "pinia",
var: "Pinia",
path: "pinia.iife.min.js"
},
{
name: "element-plus",
var: "ElementPlus",
path: "index.full.min.js",
css: "index.min.css"
},
{
name: "axios",
var: "axios",
path: "axios.min.js"
},
{
name: "dayjs",
var: "dayjs",
path: "dayjs.min.js"
},
{
name: "echarts",
var: "echarts",
path: "echarts.min.js"
}
]
});
+63
View File
@@ -0,0 +1,63 @@
import type { Plugin } from "vite";
import { isArray } from "@pureadmin/utils";
import compressPlugin from "vite-plugin-compression";
export const configCompressPlugin = (
compress: ViteCompression
): Plugin | Plugin[] => {
if (compress === "none") return null;
const gz = {
// 生成的压缩包后缀
ext: ".gz",
// 体积大于threshold才会被压缩
threshold: 0,
// 默认压缩.js|mjs|json|css|html后缀文件,设置成true,压缩全部文件
filter: () => true,
// 压缩后是否删除原始文件
deleteOriginFile: false
};
const br = {
ext: ".br",
algorithm: "brotliCompress",
threshold: 0,
filter: () => true,
deleteOriginFile: false
};
const codeList = [
{ k: "gzip", v: gz },
{ k: "brotli", v: br },
{ k: "both", v: [gz, br] }
];
const plugins: Plugin[] = [];
codeList.forEach(item => {
if (compress.includes(item.k)) {
if (compress.includes("clear")) {
if (isArray(item.v)) {
item.v.forEach(vItem => {
plugins.push(
compressPlugin(Object.assign(vItem, { deleteOriginFile: true }))
);
});
} else {
plugins.push(
compressPlugin(Object.assign(item.v, { deleteOriginFile: true }))
);
}
} else {
if (isArray(item.v)) {
item.v.forEach(vItem => {
plugins.push(compressPlugin(vItem));
});
} else {
plugins.push(compressPlugin(item.v));
}
}
}
});
return plugins;
};
+37
View File
@@ -0,0 +1,37 @@
/** 处理环境变量 */
const wrapperEnv = (envConfigs: Recordable): ViteEnv => {
/** 此处为默认值 */
const defaultEnvConfigs: ViteEnv = {
VITE_PORT: 8848,
VITE_PUBLIC_PATH: "",
VITE_ROUTER_HISTORY: "",
VITE_CDN: false,
VITE_HIDE_HOME: "false",
VITE_COMPRESSION: "none",
VITE_APP_BASE_API: ""
};
for (const configName of Object.keys(envConfigs)) {
let realConfigValue = envConfigs[configName].replace(/\\n/g, "\n");
realConfigValue =
realConfigValue === "true"
? true
: realConfigValue === "false"
? false
: realConfigValue;
if (configName === "VITE_PORT") {
realConfigValue = Number(realConfigValue);
}
defaultEnvConfigs[configName] = realConfigValue;
if (typeof realConfigValue === "string") {
process.env[configName] = realConfigValue;
} else if (typeof realConfigValue === "object") {
process.env[configName] = JSON.stringify(realConfigValue);
}
}
return defaultEnvConfigs;
};
export { wrapperEnv };
+53
View File
@@ -0,0 +1,53 @@
import type { Plugin } from "vite";
import dayjs, { Dayjs } from "dayjs";
import utils from "@pureadmin/utils";
import duration from "dayjs/plugin/duration";
import { green, blue, bold } from "picocolors";
dayjs.extend(duration);
export function viteBuildInfo(): Plugin {
let config: { command: string };
let startTime: Dayjs;
let endTime: Dayjs;
let outDir: string;
return {
name: "vite:buildInfo",
configResolved(resolvedConfig) {
config = resolvedConfig;
outDir = resolvedConfig.build?.outDir ?? "dist";
},
buildStart() {
console.log(
bold(
green(
`👏欢迎使用${blue(
"[Agileboot全栈项目]"
)},如果您感觉不错,记得点击后面链接给个star哦💖 https://github.com/valarchie/agileboot-back-end`
)
)
);
if (config.command === "build") {
startTime = dayjs(new Date());
}
},
closeBundle() {
if (config.command === "build") {
endTime = dayjs(new Date());
utils.getPackageSize({
folder: outDir,
callback: (size: string) => {
console.log(
bold(
green(
`🎉恭喜打包完成(总用时${dayjs
.duration(endTime.diff(startTime))
.format("mm分ss秒")},打包后的大小为${size}`
)
)
);
}
});
}
}
};
}
+32
View File
@@ -0,0 +1,32 @@
/**
* 此文件作用于 `vite.config.ts` 的 `optimizeDeps.include` 依赖预构建配置项
* 依赖预构建,`vite` 启动时会将下面 include 里的模块,编译成 esm 格式并缓存到 node_modules/.vite 文件夹,页面加载到对应模块时如果浏览器有缓存就读取浏览器缓存,如果没有会读取本地缓存并按需加载
* 尤其当您禁用浏览器缓存时(这种情况只应该发生在调试阶段)必须将对应模块加入到 include里,否则会遇到开发环境切换页面卡顿的问题(vite 会认为它是一个新的依赖包会重新加载并强制刷新页面),因为它既无法使用浏览器缓存,又没有在本地 node_modules/.vite 里缓存
* 温馨提示:如果您使用的第三方库是全局引入,也就是引入到 src/main.ts 文件里,就不需要再添加到 include 里了,因为 vite 会自动将它们缓存到 node_modules/.vite
*/
const include = [
"qs",
"mitt",
"xlsx",
"dayjs",
"axios",
"pinia",
"js-cookie",
"sortablejs",
"pinyin-pro",
"@vueuse/core",
"@pureadmin/utils",
"responsive-storage"
];
/**
* 在预构建中强制排除的依赖项
* 温馨提示:所有以 `@iconify-icons/` 开头引入的的本地图标模块,都应该加入到下面的 `exclude` 里,因为平台推荐的使用方式是哪里需要哪里引入而且都是单个的引入,不需要预构建,直接让浏览器加载就好
*/
const exclude = [
"@iconify-icons/ep",
"@iconify-icons/ri",
"@pureadmin/theme/dist/browser-utils"
];
export { include, exclude };
+43
View File
@@ -0,0 +1,43 @@
import { getCdnPlugin } from "./cdn";
import vue from "@vitejs/plugin-vue";
import { viteBuildInfo } from "./info";
import svgLoader from "vite-svg-loader";
import vueJsx from "@vitejs/plugin-vue-jsx";
import { configCompressPlugin } from "./compress";
// import ElementPlus from "unplugin-element-plus/vite";
import { visualizer } from "rollup-plugin-visualizer";
import removeConsole from "vite-plugin-remove-console";
import { themePreprocessorPlugin } from "@pureadmin/theme";
import { genScssMultipleScopeVars } from "../src/layout/theme";
export function getPluginsList(
VITE_CDN: boolean,
VITE_COMPRESSION: ViteCompression
) {
const lifecycle = process.env.npm_lifecycle_event;
return [
vue(),
// jsx、tsx语法支持
vueJsx(),
VITE_CDN ? getCdnPlugin() : null,
configCompressPlugin(VITE_COMPRESSION),
// 线上环境删除console
removeConsole({ external: ["src/assets/iconfont/iconfont.js"] }),
viteBuildInfo(),
// 自定义主题
themePreprocessorPlugin({
scss: {
multipleScopeVars: genScssMultipleScopeVars(),
extract: true
}
}),
// svg组件化支持
svgLoader(),
// ElementPlus({}),
// mock支持
// 打包分析
lifecycle === "report"
? visualizer({ open: true, brotliSize: true, filename: "report.html" })
: null
];
}
+87
View File
@@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
/>
<title>Agileboot管理系统</title>
<link rel="icon" href="/favicon.ico" />
<script>
window.process = {};
</script>
</head>
<body>
<div id="app">
<style>
html,
body,
#app {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
overflow: hidden;
}
.loader,
.loader::before,
.loader::after {
width: 2.5em;
height: 2.5em;
border-radius: 50%;
animation: load-animation 1.8s infinite ease-in-out;
animation-fill-mode: both;
}
.loader {
position: relative;
top: 0;
margin: 80px auto;
font-size: 10px;
color: #406eeb;
text-indent: -9999em;
transform: translateZ(0);
transform: translate(-50%, 0);
animation-delay: -0.16s;
}
.loader::before,
.loader::after {
position: absolute;
top: 0;
content: "";
}
.loader::before {
left: -3.5em;
animation-delay: -0.32s;
}
.loader::after {
left: 3.5em;
}
@keyframes load-animation {
0%,
80%,
100% {
box-shadow: 0 2.5em 0 -1.3em;
}
40% {
box-shadow: 0 2.5em 0 0;
}
}
</style>
<div class="loader"></div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
+100
View File
@@ -0,0 +1,100 @@
{
"name": "@simple-template/web",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "NODE_OPTIONS=--max-old-space-size=4096 vite",
"serve": "pnpm dev",
"build": "rimraf dist && NODE_OPTIONS=--max-old-space-size=8192 vite build",
"build:staging": "rimraf dist && vite build --mode staging",
"report": "rimraf dist && vite build",
"preview": "vite preview",
"preview:build": "pnpm build && vite preview",
"typecheck": "tsc --noEmit && vue-tsc --noEmit --skipLibCheck",
"svgo": "svgo -f src/assets/svg -o src/assets/svg",
"clean:cache": "rimraf node_modules && pnpm install",
"lint:eslint": "eslint --ignore-path ../.eslintignore --cache --cache-location node_modules/.cache/eslint/.eslintcache --max-warnings 0 \"{src,build}/**/*.{vue,js,ts,tsx}\"",
"lint:prettier": "prettier --check \"src/**/*.{js,ts,json,tsx,css,scss,vue,html,md}\"",
"lint:stylelint": "pnpm --dir .. exec stylelint \"web/**/*.{html,vue,css,scss}\" --config ./stylelint.config.cjs --ignore-path ./.stylelintignore --cache --cache-location web/node_modules/.cache/stylelint/",
"lint": "pnpm lint:eslint && pnpm lint:prettier && pnpm lint:stylelint",
"prepare": "echo \"Git hooks are managed by ../../.githooks\"",
"preinstall": "npx only-allow pnpm"
},
"browserslist": [
"> 1%",
"not ie 11",
"not op_mini all"
],
"dependencies": {
"@pureadmin/descriptions": "^1.1.1",
"@pureadmin/table": "^2.3.2",
"@pureadmin/utils": "^1.9.6",
"@vueuse/core": "^10.2.0",
"@vueuse/motion": "^2.0.0",
"animate.css": "^4.1.1",
"axios": "^1.4.0",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.8",
"echarts": "^5.4.2",
"element-plus": "2.3.6",
"js-cookie": "^3.0.5",
"jsencrypt": "^3.3.2",
"mitt": "^3.0.0",
"nprogress": "^0.2.0",
"pinia": "^2.1.4",
"pinyin-pro": "^3.15.2",
"cropperjs": "^1.5.13",
"vue-tippy": "^6.2.0",
"qrcode": "^1.5.3",
"qs": "^6.11.2",
"responsive-storage": "^2.2.0",
"sortablejs": "^1.15.0",
"typeit": "^8.7.1",
"vue": "^3.3.4",
"vue-router": "^4.2.2",
"vue-types": "^5.1.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@iconify-icons/ep": "^1.2.12",
"@iconify-icons/ri": "^1.2.9",
"@iconify/vue": "^4.1.1",
"@pureadmin/theme": "^3.1.0",
"@types/js-cookie": "^3.0.3",
"@types/node": "^20.3.1",
"@types/nprogress": "0.2.0",
"@types/qs": "^6.9.7",
"@types/sortablejs": "^1.15.1",
"@typescript-eslint/eslint-plugin": "^5.60.0",
"@typescript-eslint/parser": "^5.60.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"@vue/eslint-config-prettier": "^7.1.0",
"@vue/eslint-config-typescript": "^11.0.3",
"autoprefixer": "^10.4.14",
"cssnano": "^6.0.1",
"eslint": "^8.43.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.15.1",
"picocolors": "^1.0.0",
"postcss": "^8.4.24",
"postcss-import": "^15.1.0",
"prettier": "^2.8.8",
"rimraf": "^5.0.1",
"rollup-plugin-visualizer": "^5.9.2",
"sass": "^1.63.6",
"svgo": "^3.0.2",
"tailwindcss": "^3.3.2",
"typescript": "5.0.4",
"vite": "^4.3.9",
"vite-plugin-cdn-import": "^0.3.5",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-remove-console": "^2.1.1",
"vite-svg-loader": "^4.0.0",
"vue-eslint-parser": "^9.3.1",
"vue-tsc": "^1.8.1"
},
"repository": "git@github.com:valarchie/agileboot-front-end-pure.git",
"author": "valarchie",
"license": "MIT"
}
+9
View File
@@ -0,0 +1,9 @@
module.exports = {
plugins: {
"postcss-import": {},
"tailwindcss/nesting": {},
tailwindcss: {},
autoprefixer: {},
...(process.env.NODE_ENV === "production" ? { cssnano: {} } : {})
}
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" class="icon" viewBox="0 0 1024 1024"><path fill="#386BF3" d="M410.558.109c0 210.974-300.876 361.752-300.876 633.548 0 174.943 134.704 316.787 300.876 316.787s300.877-141.817 300.877-316.787C711.408 361.752 410.558 210.974 410.558.109z"/><path fill="#C3D2FB" d="M613.469 73.665c0 211.055-300.877 361.914-300.877 633.547C312.592 882.156 447.296 1024 613.47 1024s300.876-141.817 300.876-316.788C914.29 435.58 613.469 284.72 613.469 73.665z"/><path fill="#303F5B" d="M312.592 707.212c0-183.713 137.636-312.171 226.723-441.39 81.702 106.112 172.12 218.74 172.12 367.726A309.755 309.755 0 0 1 420.36 950.064a323.114 323.114 0 0 1-107.769-242.852z"/></svg>

After

Width:  |  Height:  |  Size: 712 B

+22
View File
@@ -0,0 +1,22 @@
{
"Version": "4.4.0",
"Title": "Agileboot",
"FixedHeader": true,
"HiddenSideBar": false,
"MultiTagsCache": false,
"KeepAlive": true,
"Layout": "vertical",
"Theme": "default",
"DarkMode": false,
"Grey": false,
"Weak": false,
"HideTabs": false,
"SidebarStatus": true,
"EpThemeColor": "#409EFF",
"ShowLogo": true,
"ShowModel": "smart",
"MenuArrowIconNoTransition": true,
"CachingAsyncRoutes": false,
"TooltipEffect": "light",
"ResponsiveStorageNameSpace": "responsive-"
}
+25
View File
@@ -0,0 +1,25 @@
<template>
<el-config-provider :locale="currentLocale">
<router-view />
<ReDialog />
</el-config-provider>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { ElConfigProvider } from "element-plus";
import zhCn from "element-plus/lib/locale/lang/zh-cn";
import { ReDialog } from "@/components/ReDialog";
export default defineComponent({
name: "app",
components: {
[ElConfigProvider.name]: ElConfigProvider,
ReDialog
},
computed: {
currentLocale() {
return zhCn;
}
}
});
</script>
+164
View File
@@ -0,0 +1,164 @@
import { http } from "@/utils/http";
import { RouteRecordRaw } from "vue-router";
export type CaptchaDTO = {
/** 验证码的base64图片 */
captchaCodeImg: string;
/** 验证码对应的缓存key */
captchaCodeKey: string;
};
export type ConfigDTO = {
/** 验证码开关 */
isCaptchaOn: boolean;
/** 系统字典配置(下拉选项之类的) */
dictionary: Record<string, Array<DictionaryData>>;
};
export type LoginByPasswordDTO = {
/** 用户名 */
username: string;
/** 密码 */
password: string;
/** 验证码 */
captchaCode: string;
/** 验证码对应的缓存key */
captchaCodeKey: string;
};
/**
* 后端token实现
*/
export type TokenDTO = {
/** token */
token: string;
/** 当前登录的用户 */
currentUser: CurrentLoginUserDTO;
};
export type CurrentLoginUserDTO = {
userInfo: CurrentUserInfoDTO;
roleKey: string;
permissions: Set<string>;
};
/**
* 当前User
*/
export interface CurrentUserInfoDTO {
avatar?: string;
createTime?: Date;
creatorId?: number;
creatorName?: string;
deptId?: number;
deptName?: string;
email?: string;
loginDate?: Date;
loginIp?: string;
nickName?: string;
phoneNumber?: string;
postId?: number;
postName?: string;
remark?: string;
roleId?: number;
roleName?: string;
sex?: number;
status?: number;
updaterId?: number;
updaterName?: string;
updateTime?: Date;
userId?: number;
username?: string;
userType?: number;
}
export type DictionaryData = {
label: string;
value: number;
cssTag: string;
};
/** 获取系统配置接口 */
export const getConfig = () => {
return http.request<ResponseData<ConfigDTO>>("get", "/getConfig");
};
/** 验证码接口 */
export const getCaptchaCode = () => {
return http.request<ResponseData<CaptchaDTO>>("get", "/captchaImage");
};
/** 登录接口 */
export const loginByPassword = (data: LoginByPasswordDTO) => {
return http.request<ResponseData<TokenDTO>>("post", "/login", { data });
};
/** 获取当前登录用户接口 */
export const getLoginUserInfo = () => {
return http.request<ResponseData<TokenDTO>>("get", "/getLoginUserInfo");
};
export interface RouteMeta {
id: string;
title: string;
icon?: string;
showLink?: boolean;
showParent?: boolean;
auths?: string[];
rank?: number;
frameSrc?: string;
isFrameSrcInternal?: boolean;
}
export type RouteItem = RouteRecordRaw & {
name?: string;
path: string;
meta: RouteMeta;
children?: RouteItem[];
};
type AsyncRoutesResponse = {
code: number;
msg: string;
data: RouteItem[];
};
/**
* 为后端返回的路由添加唯一id,后面我们在构建菜单树的层级结构时需要用到
* 这里我们假设 name + path 是唯一的,若日后有 name + path 不唯一的情况,
* 则需要修改此处的逻辑
*/
const addUniqueId = (routes: RouteItem[]): RouteItem[] => {
return routes.map(route => {
const id = `${route.name || ""}${route.path}`;
if (route.children && route.children.length > 0) {
route.children = addUniqueId(route.children);
}
return {
...route,
meta: {
...route.meta,
id
}
};
});
};
function withId(result: AsyncRoutesResponse) {
if (result.data) {
result.data = addUniqueId(result.data);
}
return result;
}
/**
* 获取动态菜单
* TODO:对于开发环境下此处可以对路由数据做一些校验,比如说 name 是否重复,name+path 是否重复等等
*/
export const getAsyncRoutes = async () => {
const result = await http.request<AsyncRoutesResponse>("get", "/getRouters");
return withId(result);
};
+76
View File
@@ -0,0 +1,76 @@
import { http } from "@/utils/http";
export interface ConfigQuery extends BasePageQuery {
/**
* 配置key
*/
configKey?: string;
/**
* 配置名称
*/
configName?: string;
/**
* 是否允许更改配置
*/
isAllowChange?: string;
}
/**
* ConfigDTO, 配置信息
*/
export interface ConfigDTO {
configId?: string;
configKey?: string;
configName?: string;
configOptions?: string[];
configValue?: string;
createTime?: Date;
isAllowChange?: string;
isAllowChangeStr?: string;
remark?: string;
}
/**
* ConfigUpdateCommand
*/
export interface UpdateConfigRequest {
configValue: string;
}
/** 获取配置列表 */
export const getConfigListApi = (params?: ConfigQuery) => {
return http.request<ResponseData<PageDTO<ConfigDTO>>>(
"get",
"/system/configs",
{
params
}
);
};
/** 获取配置信息 */
export const getConfigInfoApi = (configId: string) => {
return http.request<ResponseData<ConfigDTO>>(
"get",
`/system/config/${configId}`
);
};
/** 刷新配置缓存 */
export const updateConfigApi = (
configId: number,
data: UpdateConfigRequest
) => {
return http.request<ResponseData<PageDTO<ConfigDTO>>>(
"put",
`/system/config/${configId}`,
{
data
}
);
};
/** 刷新配置缓存 */
export const refreshConfigCacheApi = () => {
return http.request<ResponseData<void>>("delete", "/system/configs/cache");
};
+83
View File
@@ -0,0 +1,83 @@
import { http } from "@/utils/http";
export interface DeptQuery extends BaseQuery {
// TODO 目前不需要这个参数
deptId?: number;
parentId?: number;
}
/**
* DeptDTO
*/
export interface DeptDTO {
createTime?: Date;
id?: number;
deptName?: string;
email?: string;
leaderName?: string;
orderNum?: number;
parentId?: number;
phone?: string;
status?: number;
statusStr?: string;
}
/**
* AddDeptCommand
*/
export interface DeptRequest {
deptName: string;
email?: string;
leaderName?: string;
orderNum: number;
parentId: number;
phone?: string;
status: number;
}
export interface DeptTreeDTO {
id: number;
parentId: number;
label: string;
children: [DeptTreeDTO];
}
/** 获取部门列表 */
export const getDeptListApi = (params?: DeptQuery) => {
return http.request<ResponseData<Array<DeptDTO>>>("get", "/system/depts", {
params
});
};
/** 新增部门 */
export const addDeptApi = (data: DeptRequest) => {
console.log(data);
return http.request<ResponseData<void>>("post", "/system/dept", {
data
});
};
/** 部门详情 */
export const getDeptInfoApi = (deptId: string) => {
return http.request<ResponseData<DeptDTO>>("get", `/system/dept/${deptId}`);
};
/** 修改部门 */
export const updateDeptApi = (deptId: string, data: DeptRequest) => {
return http.request<ResponseData<void>>("put", `/system/dept/${deptId}`, {
data
});
};
/** 删除部门 */
export const deleteDeptApi = (deptId: string) => {
return http.request<ResponseData<void>>("delete", `/system/dept/${deptId}`);
};
/** 获取部门树级结构 */
export const getDeptTree = () => {
return http.request<ResponseData<DeptTreeDTO>>(
"get",
"/system/depts/dropdown"
);
};
+116
View File
@@ -0,0 +1,116 @@
import { http } from "@/utils/http";
export interface OperationLogsQuery extends BasePageQuery {
businessType?: string;
requestModule?: string;
status?: string;
username?: string;
}
export interface OperationLogDTO {
businessType?: number;
businessTypeStr?: string;
calledMethod?: string;
deptId?: number;
deptName?: string;
errorStack?: string;
operationId?: number;
operationParam?: string;
operationResult?: string;
operationTime?: Date;
operatorIp?: string;
operatorLocation?: string;
operatorType?: number;
operatorTypeStr?: string;
requestMethod?: string;
requestModule?: string;
requestUrl?: string;
status?: number;
statusStr?: string;
userId?: number;
username?: string;
}
/** 获取操作日志列表 */
export const getOperationLogListApi = (params?: OperationLogsQuery) => {
return http.request<ResponseData<PageDTO<OperationLogDTO>>>(
"get",
"/logs/operationLogs",
{
params
}
);
};
export const exportOperationLogExcelApi = (
params: OperationLogsQuery,
fileName: string
) => {
return http.download("/logs/operationLogs/excel", fileName, {
params
});
};
export const deleteOperationLogApi = (data: Array<number>) => {
return http.request<ResponseData<void>>("delete", "/logs/operationLogs", {
params: {
// 需要将数组转换为字符串 否则Axios会将参数变成 noticeIds[0]:1 noticeIds[1]:2 这种格式,后端接收参数不成功
operationIds: data.toString()
}
});
};
/** 登录日志查询类 */
export interface LoginLogQuery extends BasePageQuery {
beginTime?: string;
endTime?: string;
ipAddress?: string;
status?: string;
username?: string;
}
/**
* 登录日志信息
*/
export interface LoginLogsDTO {
browser?: string;
infoId?: string;
ipAddress?: string;
loginLocation?: string;
loginTime?: Date;
msg?: string;
operationSystem?: string;
/** TODO 这个登录状态的设计很奇怪 需要重构掉 */
status?: number;
statusStr?: string;
username?: string;
}
/** 获取操作日志列表 */
export const getLoginLogListApi = (params?: LoginLogQuery) => {
return http.request<ResponseData<PageDTO<LoginLogsDTO>>>(
"get",
"/logs/loginLogs",
{
params
}
);
};
export const exportLoginLogExcelApi = (
params: LoginLogQuery,
fileName: string
) => {
return http.download("/logs/loginLogs/excel", fileName, {
params
});
};
export const deleteLoginLogApi = (data: Array<number>) => {
return http.request<ResponseData<void>>("delete", "/logs/loginLogs", {
params: {
// 需要将数组转换为字符串 否则Axios会将参数变成 noticeIds[0]:1 noticeIds[1]:2 这种格式,后端接收参数不成功
ids: data.toString()
}
});
};
+118
View File
@@ -0,0 +1,118 @@
import { http } from "@/utils/http";
import { Tree } from "@/utils/tree";
export interface MenuQuery {
isButton: boolean;
}
/**
* MenuDTO
*/
export interface MenuDTO extends Tree {
createTime?: Date;
isButton?: number;
id?: number;
menuName?: string;
parentId?: number;
menuType: number;
menuTypeStr: string;
path?: string;
permission?: string;
routerName?: string;
status?: number;
statusStr?: string;
}
/**
* MenuDetailDTO
*/
export interface MenuDetailDTO extends MenuDTO {
meta: MetaDTO;
permission?: string;
}
/**
* AddMenuCommand
*/
export interface MenuRequest {
id: number;
parentId: number;
menuName: string;
routerName?: string;
path?: string;
permission?: string;
status: number;
isButton: boolean;
menuType: number;
meta: MetaDTO;
}
/**
* MetaDTO
*/
export interface MetaDTO {
auths?: string[];
dynamicLevel?: number;
extraIcon?: ExtraIconDTO;
frameLoading?: boolean;
frameSrc?: string;
hiddenTag?: boolean;
icon?: string;
isFrameSrcInternal?: boolean;
keepAlive?: boolean;
rank?: number;
roles?: string[];
showLink?: boolean;
showParent?: boolean;
title?: string;
transition?: TransitionDTO;
}
/**
* ExtraIconDTO
*/
export interface ExtraIconDTO {
name?: string;
svg?: boolean;
}
/**
* TransitionDTO
*/
export interface TransitionDTO {
enterTransition?: string;
leaveTransition?: string;
name?: string;
}
/** 获取菜单列表 */
export const getMenuListApi = (params: MenuQuery) => {
return http.request<ResponseData<Array<MenuDTO>>>("get", "/system/menus", {
params
});
};
/** 添加菜单 */
export const addMenuApi = (data: MenuRequest) => {
return http.request<ResponseData<void>>("post", "/system/menus", { data });
};
/** 修改菜单 */
export const updateMenuApi = (menuId: string, data: MenuRequest) => {
return http.request<ResponseData<void>>("put", `/system/menus/${menuId}`, {
data
});
};
/** 删除菜单 */
export const deleteMenuApi = (menuId: string) => {
return http.request<ResponseData<void>>("delete", `/system/menus/${menuId}`);
};
/** 菜单详情 */
export const getMenuInfoApi = (menuId: string) => {
return http.request<ResponseData<MenuDetailDTO>>(
"get",
`/system/menus/${menuId}`
);
};
+137
View File
@@ -0,0 +1,137 @@
import { http } from "@/utils/http";
export interface OnlineUserQuery {
ipAddress: string;
username: string;
}
export interface OnlineUserInfo {
browser?: string;
deptName?: string;
ipAddress?: string;
loginLocation?: string;
loginTime?: number;
operationSystem?: string;
tokenId?: string;
username?: string;
}
/** 获取操作日志列表 */
export const getOnlineUserListApi = (params?: OnlineUserQuery) => {
return http.request<ResponseData<PageDTO<OnlineUserInfo>>>(
"get",
"/monitor/onlineUsers",
{
params
}
);
};
/** 强制登出用户 */
export const logoutOnlineUserApi = (tokenId: string) => {
return http.request<ResponseData<void>>(
"delete",
`/monitor/onlineUser/${tokenId}`
);
};
/**
* ServerInfo
*/
export interface ServerInfo {
cpuInfo?: CpuInfo;
diskInfos?: DiskInfo[];
jvmInfo?: JvmInfo;
memoryInfo?: MemoryInfo;
systemInfo?: SystemInfo;
}
/**
* CpuInfo
*/
export interface CpuInfo {
cpuNum?: number;
free?: number;
sys?: number;
total?: number;
used?: number;
wait?: number;
}
/**
* DiskInfo
*/
export interface DiskInfo {
dirName?: string;
free?: string;
sysTypeName?: string;
total?: string;
typeName?: string;
usage?: number;
used?: string;
}
/**
* JvmInfo
*/
export interface JvmInfo {
free?: number;
home?: string;
inputArgs?: string;
max?: number;
name?: string;
runTime?: string;
startTime?: string;
total?: number;
usage?: number;
used?: number;
version?: string;
}
/**
* MemoryInfo
*/
export interface MemoryInfo {
free?: number;
total?: number;
usage?: number;
used?: number;
}
/**
* SystemInfo
*/
export interface SystemInfo {
computerIp?: string;
computerName?: string;
osArch?: string;
osName?: string;
userDir?: string;
}
/** 获取服务器信息 */
export const getServerInfoApi = () => {
return http.request<ResponseData<ServerInfo>>("get", "/monitor/serverInfo");
};
/**
* RedisCacheInfoDTO
*/
export interface RedisCacheInfoDTO {
commandStats?: CommandStatusDTO[];
dbSize?: number;
info?: { [key: string]: string };
}
/**
* CommandStatusDTO
*/
export interface CommandStatusDTO {
name?: string;
value?: string;
}
/** 获取Redis信息 */
export const getCacheInfoApi = () => {
return http.request<ResponseData<ServerInfo>>("get", "/monitor/cacheInfo");
};
+64
View File
@@ -0,0 +1,64 @@
import { http } from "@/utils/http";
export interface SystemNoticeQuery extends BasePageQuery {
noticeType: string;
noticeTitle: string;
creatorName: string;
}
type SystemNoticeDTO = {
noticeId: string;
noticeTitle: string;
noticeType: number;
noticeContent: string;
status: number;
createTime: Date;
creatorName: string;
};
export type SystemNoticeRequest = {
noticeId?: number;
noticeTitle: string;
noticeType: number;
noticeContent: string;
status: number;
};
/** 获取系统通知列表 */
export const getSystemNoticeListApi = (params?: SystemNoticeQuery) => {
return http.request<ResponseData<PageDTO<SystemNoticeDTO>>>(
"get",
"/system/notices",
{
params
}
);
};
/** 添加系统通知 */
export const addSystemNoticeApi = (data: SystemNoticeRequest) => {
return http.request<ResponseData<void>>("post", "/system/notices", {
data
});
};
/** 修改系统通知 */
export const updateSystemNoticeApi = (data: SystemNoticeRequest) => {
return http.request<ResponseData<void>>(
"put",
`/system/notices/${data.noticeId}`,
{
data
}
);
};
/** 删除系统通知 */
export const deleteSystemNoticeApi = (data: Array<number>) => {
return http.request<ResponseData<void>>("delete", "/system/notices", {
params: {
// 需要将数组转换为字符串 否则Axios会将参数变成 noticeIds[0]:1 noticeIds[1]:2 这种格式,后端接收参数不成功
noticeIds: data.toString()
}
});
};
+70
View File
@@ -0,0 +1,70 @@
import { http } from "@/utils/http";
export interface PostListCommand extends BasePageQuery {
postCode?: string;
postName?: string;
status?: number;
}
export interface PostPageResponse {
createTime: string;
postCode: string;
postId: number;
postName: string;
postSort: number;
remark: string;
status: number;
statusStr: string;
}
export function getPostListApi(params: PostListCommand) {
return http.request<ResponseData<PageDTO<PostPageResponse>>>(
"get",
"/system/post/list",
{
params
}
);
}
export const exportPostExcelApi = (
params: PostListCommand,
fileName: string
) => {
return http.download("/system/post/excel", fileName, {
params
});
};
export const deletePostApi = (data: Array<number>) => {
return http.request<ResponseData<void>>("delete", "/system/post", {
params: {
// 需要将数组转换为字符串 否则Axios会将参数变成 noticeIds[0]:1 noticeIds[1]:2 这种格式,后端接收参数不成功
ids: data.toString()
}
});
};
export interface AddPostCommand {
postCode: string;
postName: string;
postSort: number;
remark?: string;
status?: string;
}
export const addPostApi = (data: AddPostCommand) => {
return http.request<ResponseData<void>>("post", "/system/post", {
data
});
};
export interface UpdatePostCommand extends AddPostCommand {
postId: number;
}
export const updatePostApi = (data: UpdatePostCommand) => {
return http.request<ResponseData<void>>("put", "/system/post", {
data
});
};
+65
View File
@@ -0,0 +1,65 @@
import { http } from "@/utils/http";
export interface RoleQuery extends BasePageQuery {
roleKey?: string;
roleName?: string;
status?: string;
timeRangeColumn?: string;
}
export interface RoleDTO {
createTime: Date;
dataScope: number;
remark: string;
roleId: number;
roleKey: string;
roleName: string;
roleSort: number;
selectedDeptList: number[];
selectedMenuList: number[];
status: number;
}
export function getRoleListApi(params: RoleQuery) {
return http.request<ResponseData<PageDTO<RoleDTO>>>(
"get",
"/system/role/list",
{
params
}
);
}
export function getRoleInfoApi(roleId: number) {
return http.request<ResponseData<RoleDTO>>("get", "/system/role/" + roleId);
}
export interface AddRoleCommand {
dataScope?: string;
menuIds: number[];
remark?: string;
roleKey: string;
roleName: string;
roleSort: number;
status?: string;
}
export function addRoleApi(data: AddRoleCommand) {
return http.request<void>("post", "/system/role", {
data
});
}
export interface UpdateRoleCommand extends AddRoleCommand {
roleId: number;
}
export function updateRoleApi(data: UpdateRoleCommand) {
return http.request<void>("put", "/system/role", {
data
});
}
export function deleteRoleApi(roleId: number) {
return http.request<void>("delete", "/system/role/" + roleId);
}
+176
View File
@@ -0,0 +1,176 @@
import { http } from "@/utils/http";
export interface UserQuery extends BasePageQuery {
deptId?: number;
phoneNumber?: string;
status?: number;
userId?: number;
username?: string;
}
/**
* UserDTO
*/
export interface UserDTO {
avatar?: string;
createTime?: Date;
creatorId?: number;
creatorName?: string;
deptId?: number;
deptName?: string;
email?: string;
loginDate?: Date;
loginIp?: string;
nickname?: string;
phoneNumber?: string;
postId?: number;
remark?: string;
roleId?: number;
roleName?: string;
sex?: number;
status?: number;
updaterId?: number;
updaterName?: string;
updateTime?: Date;
userId?: number;
username?: string;
userType?: number;
}
/**
* AddUserCommand
*/
export interface UserRequest {
userId: number;
avatar?: string;
deptId?: number;
email?: string;
nickname?: string;
phoneNumber?: string;
password: string;
postId?: number;
remark?: string;
roleId?: number;
sex?: number;
status?: number;
username?: string;
}
/**
* UpdateProfileCommand
*/
export interface UserProfileRequest {
email?: string;
nickName?: string;
phoneNumber?: string;
sex?: number;
userId?: number;
}
/**
* ResetPasswordCommand
*/
export interface ResetPasswordRequest {
newPassword?: string;
oldPassword?: string;
userId?: number;
}
/**
* 修改密码
*/
export interface PasswordRequest {
userId: number;
password: string;
}
/** 获取用户列表 */
export const getUserListApi = (params?: UserQuery) => {
return http.request<ResponseData<PageDTO<UserDTO>>>("get", "/system/users", {
params
});
};
/** 新增用户 */
export const addUserApi = (data?: UserRequest) => {
return http.request<ResponseData<void>>("post", "/system/users", {
data
});
};
/** 编辑用户 */
export const updateUserApi = (userId: number, data?: UserRequest) => {
return http.request<ResponseData<void>>("put", `/system/users/${userId}`, {
data
});
};
/** 更改用户密码 */
export const updateUserPasswordApi = (data?: PasswordRequest) => {
return http.request<ResponseData<void>>(
"put",
`/system/users/${data.userId}/password`,
{
data
}
);
};
/** 删除用户 */
export const deleteUserApi = (userId: number) => {
return http.request<ResponseData<void>>("delete", `/system/users/${userId}`);
};
/** 修改用户状态 */
export const updateUserStatusApi = (userId: number, status: number) => {
return http.request<ResponseData<PageDTO<UserDTO>>>(
"put",
`/system/users/${userId}/status`,
{
data: {
status: status
}
}
);
};
/** 批量导出用户 */
export const exportUserExcelApi = (params: UserQuery, fileName: string) => {
return http.download("/system/users/excel", fileName, {
params
});
};
/** 用户头像上传 */
export const uploadUserAvatarApi = data => {
return http.request<ResponseData<void>>(
"post",
"/system/user/profile/avatar",
{
data
},
{
headers: {
"Content-Type": "multipart/form-data"
}
}
);
};
/** 更改用户资料 */
export const updateUserProfileApi = (data?: UserProfileRequest) => {
return http.request<ResponseData<void>>("put", "/system/user/profile", {
data
});
};
/** 更改当前用户密码 */
export const updateCurrentUserPasswordApi = (data?: ResetPasswordRequest) => {
return http.request<ResponseData<void>>(
"put",
"/system/user/profile/password",
{
data
}
);
};
@@ -0,0 +1,26 @@
@font-face {
font-family: "iconfont"; /* Project id 2208059 */
src: url("iconfont.woff2?t=1671895108120") format("woff2"),
url("iconfont.woff?t=1671895108120") format("woff"),
url("iconfont.ttf?t=1671895108120") format("truetype");
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.pure-iconfont-tabs:before {
content: "\e63e";
}
.pure-iconfont-logo:before {
content: "\e620";
}
.pure-iconfont-new:before {
content: "\e615";
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,30 @@
{
"id": "2208059",
"name": "pure-admin",
"font_family": "iconfont",
"css_prefix_text": "pure-iconfont-",
"description": "pure-admin-iconfont",
"glyphs": [
{
"icon_id": "20594647",
"name": "Tabs",
"font_class": "tabs",
"unicode": "e63e",
"unicode_decimal": 58942
},
{
"icon_id": "22129506",
"name": "PureLogo",
"font_class": "logo",
"unicode": "e620",
"unicode_decimal": 58912
},
{
"icon_id": "7795615",
"name": "New",
"font_class": "new",
"unicode": "e615",
"unicode_decimal": 58901
}
]
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" class="icon" viewBox="0 0 1024 1024"><path fill="#386BF3" d="M410.558.109c0 210.974-300.876 361.752-300.876 633.548 0 174.943 134.704 316.787 300.876 316.787s300.877-141.817 300.877-316.787C711.408 361.752 410.558 210.974 410.558.109z"/><path fill="#C3D2FB" d="M613.469 73.665c0 211.055-300.877 361.914-300.877 633.547C312.592 882.156 447.296 1024 613.47 1024s300.876-141.817 300.876-316.788C914.29 435.58 613.469 284.72 613.469 73.665z"/><path fill="#303F5B" d="M312.592 707.212c0-183.713 137.636-312.171 226.723-441.39 81.702 106.112 172.12 218.74 172.12 367.726A309.755 309.755 0 0 1 420.36 950.064a323.114 323.114 0 0 1-107.769-242.852z"/></svg>

After

Width:  |  Height:  |  Size: 712 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 20 20"><g fill="none"><path d="M3 5a2 2 0 0 1 2-2h2a.5.5 0 0 1 0 1H5a1 1 0 0 0-1 1v2a.5.5 0 0 1-1 0V5zm9.5-1.5A.5.5 0 0 1 13 3h2a2 2 0 0 1 2 2v2a.5.5 0 0 1-1 0V5a1 1 0 0 0-1-1h-2a.5.5 0 0 1-.5-.5zm-9 9a.5.5 0 0 1 .5.5v2a1 1 0 0 0 1 1h2a.5.5 0 0 1 0 1H5a2 2 0 0 1-2-2v-2a.5.5 0 0 1 .5-.5zm13 0a.5.5 0 0 1 .5.5v2a2 2 0 0 1-2 2h-2a.5.5 0 0 1 0-1h2a1 1 0 0 0 1-1v-2a.5.5 0 0 1 .5-.5z" fill="currentColor"/></g></svg>

After

Width:  |  Height:  |  Size: 508 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><g fill="none"><path d="M8.5 3.75a.75.75 0 0 0-1.5 0v2.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 0 0 1.5h2.5A2.25 2.25 0 0 0 8.5 6.25v-2.5zm0 16.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 0-.75-.75h-2.5a.75.75 0 0 1 0-1.5h2.5a2.25 2.25 0 0 1 2.25 2.25v2.5zM16.25 3a.75.75 0 0 0-.75.75v2.5a2.25 2.25 0 0 0 2.25 2.25h2.5a.75.75 0 0 0 0-1.5h-2.5a.75.75 0 0 1-.75-.75v-2.5a.75.75 0 0 0-.75-.75zm-.75 17.25a.75.75 0 0 0 1.5 0v-2.5a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 0 0-1.5h-2.5a2.25 2.25 0 0 0-2.25 2.25v2.5z" fill="currentColor"/></g></svg>

After

Width:  |  Height:  |  Size: 631 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M2.88 18.054a35.897 35.897 0 0 1 8.531-16.32.8.8 0 0 1 1.178 0c.166.18.304.332.413.455a35.897 35.897 0 0 1 8.118 15.865c-2.141.451-4.34.747-6.584.874l-2.089 4.178a.5.5 0 0 1-.894 0l-2.089-4.178a44.019 44.019 0 0 1-6.584-.874zm6.698-1.123 1.157.066L12 19.527l1.265-2.53 1.157-.066a42.137 42.137 0 0 0 4.227-.454A33.913 33.913 0 0 0 12 4.09a33.913 33.913 0 0 0-6.649 12.387c1.395.222 2.805.374 4.227.454zM12 15a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></svg>

After

Width:  |  Height:  |  Size: 588 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.38 2.019a7.5 7.5 0 1 0 10.6 10.6C21.662 17.854 17.316 22 12.001 22 6.477 22 2 17.523 2 12c0-5.315 4.146-9.661 9.38-9.981z"/></svg>

After

Width:  |  Height:  |  Size: 263 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85 1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></svg>

After

Width:  |  Height:  |  Size: 480 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" aria-hidden="true" class="iconify iconify--ant-design" viewBox="0 0 1024 1024"><path fill="currentColor" d="M864 170h-60c-4.4 0-8 3.6-8 8v518H310v-73c0-6.7-7.8-10.5-13-6.3l-141.9 112a8 8 0 0 0 0 12.6l141.9 112c5.3 4.2 13 .4 13-6.3v-75h498c35.3 0 64-28.7 64-64V178c0-4.4-3.6-8-8-8z"/></svg>

After

Width:  |  Height:  |  Size: 352 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" aria-hidden="true" class="re-screen" color="#00000073" viewBox="0 0 16 16"><path fill="currentColor" d="M3.5 4H1V3h2V1h1v2.5l-.5.5zM13 3V1h-1v2.5l.5.5H15V3h-2zm-1 9.5V15h1v-2h2v-1h-2.5l-.5.5zM1 12v1h2v2h1v-2.5l-.5-.5H1zm11-1.5-.5.5h-7l-.5-.5v-5l.5-.5h7l.5.5v5zM10 7H6v2h4V7z"/></svg>

After

Width:  |  Height:  |  Size: 348 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" aria-hidden="true" class="re-screen" color="#00000073" viewBox="0 0 16 16"><path fill="currentColor" d="M3 12h10V4H3v8zm2-6h6v4H5V6zM2 6H1V2.5l.5-.5H5v1H2v3zm13-3.5V6h-1V3h-3V2h3.5l.5.5zM14 10h1v3.5l-.5.5H11v-1h3v-3zM2 13h3v1H1.5l-.5-.5V10h1v3z"/></svg>

After

Width:  |  Height:  |  Size: 318 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" aria-hidden="true" class="iconify iconify--mdi" viewBox="0 0 24 24"><path fill="currentColor" d="M1 7h6v2H3v2h4v2H3v2h4v2H1V7m10 0h4v2h-4v2h2a2 2 0 0 1 2 2v2c0 1.11-.89 2-2 2H9v-2h4v-2h-2a2 2 0 0 1-2-2V9c0-1.1.9-2 2-2m8 0h2a2 2 0 0 1 2 2v1h-2V9h-2v6h2v-1h2v1c0 1.11-.89 2-2 2h-2a2 2 0 0 1-2-2V9c0-1.1.9-2 2-2Z"/></svg>

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

@@ -0,0 +1,5 @@
import auth from "./src/auth";
const Auth = auth;
export { Auth };
@@ -0,0 +1,20 @@
import { defineComponent, Fragment } from "vue";
import { hasAuth } from "@/router/utils";
export default defineComponent({
name: "Auth",
props: {
value: {
type: undefined,
default: []
}
},
setup(props, { slots }) {
return () => {
if (!slots) return null;
return hasAuth(props.value) ? (
<Fragment>{slots.default?.()}</Fragment>
) : null;
};
}
});
@@ -0,0 +1,29 @@
import { ElCol } from "element-plus";
import { h, defineComponent } from "vue";
// 封装element-plus的el-col组件
export default defineComponent({
name: "ReCol",
props: {
value: {
type: Number,
default: 24
}
},
render() {
const attrs = this.$attrs;
const val = this.value;
return h(
ElCol,
{
xs: val,
sm: val,
md: val,
lg: val,
xl: val,
...attrs
},
{ default: () => this.$slots.default() }
);
}
});
@@ -0,0 +1,7 @@
import reCropper from "./src";
import { withInstall } from "@pureadmin/utils";
/** 图片裁剪组件 */
export const ReCropper = withInstall(reCropper);
export default ReCropper;
@@ -0,0 +1,11 @@
@import "cropperjs/dist/cropper.css";
@import "tippy.js/dist/tippy.css";
@import "tippy.js/themes/light.css";
@import "tippy.js/animations/perspective.css";
.re-circled {
.cropper-view-box,
.cropper-face {
border-radius: 50%;
}
}

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