{"id":19174878,"url":"https://github.com/un-pany/v3-admin","last_synced_at":"2025-04-06T00:09:23.564Z","repository":{"id":37877577,"uuid":"357889486","full_name":"un-pany/v3-admin","owner":"un-pany","description":"☀️ A vue3 admin template, based on 'vue-cli'","archived":false,"fork":false,"pushed_at":"2023-08-11T02:34:45.000Z","size":47658,"stargazers_count":353,"open_issues_count":0,"forks_count":55,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-29T23:08:55.682Z","etag":null,"topics":["admin","axios","element-plus","pinia","sass","typescript","vue-admin","vue-cli","vue-router","vue3","vue3-admin","vue3-template"],"latest_commit_sha":null,"homepage":"https://un-pany.github.io/v3-admin","language":"Vue","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/un-pany.png","metadata":{"files":{"readme":"README.en.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-14T12:00:29.000Z","updated_at":"2025-03-24T00:00:28.000Z","dependencies_parsed_at":"2024-12-16T14:51:18.640Z","dependency_job_id":"d3c0703d-7f9c-487e-92b6-95f90c484b66","html_url":"https://github.com/un-pany/v3-admin","commit_stats":null,"previous_names":[],"tags_count":39,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/un-pany%2Fv3-admin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/un-pany%2Fv3-admin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/un-pany%2Fv3-admin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/un-pany%2Fv3-admin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/un-pany","download_url":"https://codeload.github.com/un-pany/v3-admin/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247415967,"owners_count":20935387,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["admin","axios","element-plus","pinia","sass","typescript","vue-admin","vue-cli","vue-router","vue3","vue3-admin","vue3-template"],"created_at":"2024-11-09T10:19:33.153Z","updated_at":"2025-04-06T00:09:23.541Z","avatar_url":"https://github.com/un-pany.png","language":"Vue","funding_links":[],"categories":[],"sub_categories":[],"readme":"## ❗ Note\n\nThe project has been refactored with Vite since 3.1.3 and is open sourced here: [V3 Admin Vite](https://github.com/un-pany/v3-admin-vite), if Vue CLI is not required for you, then I recommend you use a new version based on Vite because it is faster, stronger, and more speciative!\n\n# ⚡️ Introduction\n\nA free and open source mid-back management system basic solution based on Vue3, TypeScript, Element Plus, Pinia and Vue CLI 5.x\n\n- Electron: [v3-electron](https://github.com/un-pany/v3-electron)\n\n## Documentation\n\n[简体中文](https://juejin.cn/post/6963876125428678693) | English Docs\n\n## preview\n\n| position     | account         | link                                       |\n| ------------ | --------------- | ------------------------------------------ |\n| github-pages | admin or editor | [link](https://un-pany.github.io/v3-admin) |\n\n## Features\n\n```text\n- User management\n  - login\n  - logout\n\n- Permission Authentication\n  - page permissions\n  - directive permissions\n\n- Multi-environment build\n  - development\n  - test\n  - production\n\n- Global Features\n  - svg\n  - Multiple themes switching（Contains dark themes）\n  - Dynamic sidebar (supports multi-level routing)\n  - Dynamic breadcrumb\n  - Tags-view (Tab page Support right-click operation)\n  - Screenfull\n  - Responsive Sidebar\n  - monitor（based on mitojs）\n\n- Error Page\n  - 401\n  - 404\n\n- Dashboard\n  - admin\n  - editor\n\n- Auto deployment\n```\n\n## Directory\n\n```\n# v3-admin\n├─ .env.development   # development environment\n├─ .env.production    # production environment\n├─ .env.test          # test environment\n├─ .eslintrc.js       # eslint\n├─ deploy             # auto deployment\n├─ public\n│  ├─ favicon.ico\n│  ├─ index.html\n├─ src\n│  ├─ @types          # ts declaration\n│  ├─ api             # api interface\n│  ├─ assets          # static resources\n│  ├─ components      # global components\n│  ├─ config          # global config\n│  ├─ constant        # constant\n│  ├─ directives      # global directives\n│  ├─ icons           # svg icon\n│  ├─ layout          # layout\n│  ├─ model           # global model\n│  ├─ plugins         # plugins\n│  ├─ router          # router\n│  ├─ store           # pinia store\n│  ├─ styles          # global styles\n│  ├─ utils           # utils\n│  └─ views           # pages\n│  ├─ App.vue         # entry page\n│  ├─ main.ts         # entry file\n│  └─ shims.d.ts      # module injection\n├─ tsconfig.json      # ts Compile config\n└─ vue.config.js      # vue-cli config\n```\n\n## Getting started\n\n```bash\n# config\n1. Install the 'eslint' plugin\n2. Install the 'volar' plugin\n3. node 16+\n4. pnpm 6+\n\n# clone the project\ngit clone https://github.com/un-pany/v3-admin.git\n\n# enter the project directory\ncd v3-admin\n\n# install dependency\npnpm\n\n# develop\npnpm dev\n```\n\n## Multi-environment build\n\n```bash\n# build test environment\npnpm build:test\n\n# build production environment\npnpm build:prod\n```\n\n## Code format check\n\n```bash\npnpm lint\n```\n\n## Auto deployment\n\n```bash\npnpm deploy\n```\n\n# 📚 Essentials\n\n## Router\n\n### Config items\n\n```\n// this route cannot be clicked in breadcrumb navigation when noRedirect is set\nredirect: 'noRedirect'\n\n// 'asyncRoutes': Be sure to fill in the name of the set route, otherwise there may be problems in resetting the route\n// If you want to show to 'tags-view', is required\nname: 'router-name'\n\nmeta: {\n  // Set the name of the route displayed in the sidebar and breadcrumbs\n  title: 'title'\n  // Icon to set this route, Remember to import svg into @/icons/svg\n  icon: 'svg-name'\n  // if set to true, lt will not appear in sidebar nav\n  hidden: true\n  // required roles to navigate to this route, Support multiple permissions stacking\n  roles: ['admin', 'editor']\n  // The default is true. If it is set to false, it will not be displayed in breadcrumbs\n  breadcrumb: false\n  // The default is false. If set to true, it will be fixed in tags-view\n  affix: true\n\n  // When the children under a route declare more than one route, it will automatically become a nested mode\n  // When there is only one, the sub route will be displayed in the sidebar as the root route\n  // If you want to display your root route regardless of the number of children declarations below\n  // You can set alwayShow: true, which will ignore the previously defined rules and always display the root route\n  alwaysShow: true\n\n  // When this property is set, the sidebar corresponding to the activemenu property will be highlighted when entering the route\n  activeMenu: '/dashboard'\n}\n```\n\n### Dynamic routes\n\n`constantRoutes` places routes that do not require judgment permission in the resident route\n\n`asyncRoutes` places routes that require dynamic permission judgment and are dynamically added through `addRoute`\n\n**Note: Dynamic routing must be configured with the name attribute, otherwise the routing will not be reset when the routing is reset, which may cause business bugs**\n\n## Sidebar and breadcrumb\n\n### Sidebar\n\n![](https://ss.im5i.com/2021/10/20/yFV2O.png)\n\nSidebar `@/layout/components/sidebar` is dynamically generated by reading routing and combining permission judgment (in other words, the constant route + has permission route)\n\n### Sidebar external links\n\nYou can set an outer chain in the sidebar, as long as you fill in the useful URL path in Path, you will help you open this page when you click on the sidebar.\n\n```typescript\n{\n  path: 'link',\n  component: Layout,\n  children: [\n    {\n      path: 'https://github.com/un-pany/v3-admin',\n      meta: { title: 'link', icon: 'link' },\n      name: 'Link'\n    }\n  ]\n}\n```\n\n### Breadcrumb\n\n![](https://ss.im5i.com/2021/10/20/yFdaR.png)\n\nBreadcrumb ` @/layout/components/bread-crumb` is also generated dynamically according to the route. The route setting `breadcrumb: false` will not appear in the breadcrumb. The route setting `redirect: 'noredirect'`cannot be clicked in the breadcrumb\n\n## Permission\n\nWhen logging in, compare the routing table by obtaining the permissions (roles) of the current user, generate an accessible routing table according to the permissions of the current user, and then dynamically mount it to the router through `addRoute`.\n\n### Role permission control\n\nThe control codes are all in `@/router/permission.ts`, which can be modified according to specific business:\n\n```typescript\nimport NProgress from \"nprogress\"\nimport \"nprogress/nprogress.css\"\nimport router from \"@/router\"\nimport { RouteLocationNormalized } from \"vue-router\"\nimport { useUserStoreHook } from \"@/store/modules/user\"\nimport { usePermissionStoreHook } from \"@/store/modules/permission\"\nimport { ElMessage } from \"element-plus\"\nimport { whiteList } from \"@/config/white-list\"\nimport rolesSettings from \"@/config/roles\"\nimport { getToken } from \"@/utils/cookies\"\n\nconst userStore = useUserStoreHook()\nconst permissionStore = usePermissionStoreHook()\nNProgress.configure({ showSpinner: false })\n\nrouter.beforeEach(async (to: RouteLocationNormalized, _: RouteLocationNormalized, next: any) =\u003e {\n  NProgress.start()\n  // Determine if the user is logged in\n  if (getToken()) {\n    if (to.path === \"/login\") {\n      // Redirect to the homepage if you log in and ready to enter the Login page.\n      next({ path: \"/\" })\n      NProgress.done()\n    } else {\n      // Check if the user has obtained its permissions role\n      if (userStore.roles.length === 0) {\n        try {\n          if (rolesSettings.openRoles) {\n            // Note: The role must be an array! E.g: ['admin'] 或 ['developer', 'editor']\n            await userStore.getInfo()\n            // Fetch the Roles returned by the interface\n            const roles = userStore.roles\n            // Generate accessible Routes based on roles\n            permissionStore.setRoutes(roles)\n          } else {\n            // Enable the default role without turning on the role function\n            userStore.setRoles(rolesSettings.defaultRoles)\n            permissionStore.setRoutes(rolesSettings.defaultRoles)\n          }\n          // Dynamically add accessible Routes\n          permissionStore.dynamicRoutes.forEach((route) =\u003e {\n            router.addRoute(route)\n          })\n          // Ensure that the added route has been completed\n          // Set replace: true, so navigation will not leave a history\n          next({ ...to, replace: true })\n        } catch (err: any) {\n          // Delete token and redirect to the login page\n          userStore.resetToken()\n          ElMessage.error(err || \"Has Error\")\n          next(\"/login\")\n          NProgress.done()\n        }\n      } else {\n        next()\n      }\n    }\n  } else {\n    // If there is no TOKEN\n    if (whiteList.indexOf(to.path) !== -1) {\n      // If you are in a whitelist that you don't need to log in, you will enter directly.\n      next()\n    } else {\n      // Other pages without access rights will be redirected to the login page\n      next(\"/login\")\n      NProgress.done()\n    }\n  }\n})\n\nrouter.afterEach(() =\u003e {\n  NProgress.done()\n})\n```\n\n### Cancel the role feature\n\nIf you don't need the function of role, you can turn it off in `@/config/roles`. After turning it off, the system will enable the default role (usually the admin role with the highest permission), that is, each logged in user can see all routes\n\n```typescript\ninterface RolesSettings {\n  // Whether to enable the role function (After opening, the server needs to cooperate and return the role of the current user in the query user details interface)\n  openRoles: boolean\n  // After closing the role, the default role of the currently logged in user will take effect (admin by default, with all permissions)\n  defaultRoles: Array\u003cstring\u003e\n}\n\nconst rolesSettings: RolesSettings = {\n  openRoles: true,\n  defaultRoles: [\"admin\"],\n}\n\nexport default rolesSettings\n```\n\n### Directive permissions\n\nConcisely implement button level permission judgment (registered to the global and can be used directly):\n\n```html\n\u003cel-tag v-permission=\"['admin']\"\u003eadmin is visible\u003c/el-tag\u003e\n\u003cel-tag v-permission=\"['editor']\"\u003eeditor is visible\u003c/el-tag\u003e\n\u003cel-tag v-permission=\"['admin','editor']\"\u003eadmin and editor are visible\u003c/el-tag\u003e\n```\n\nHowever, in some cases, `v-permission` is not suitable. For example: `el-tab` or `el-table-column` of ` element-plus` and other scenes that dynamically render `DOM`. You can only do this by manually setting `v-if`.\n\nAt this time, you can use **permission judgment function**.\n\n```typescript\nimport { checkPermission } from \"@/utils/permission\"\n```\n\n```html\n\u003cel-tab-pane v-if=\"checkPermission(['admin'])\" label=\"Admin\"\u003eadmin is visible\u003c/el-tab-pane\u003e\n\u003cel-tab-pane v-if=\"checkPermission(['editor'])\" label=\"Editor\"\u003eeditor id visible\u003c/el-tab-pane\u003e\n\u003cel-tab-pane v-if=\"checkPermission(['admin','editor'])\" label=\"AdminEditor\"\u003eadmin and editor are visible\u003c/el-tab-pane\u003e\n```\n\n## Send HTTP request\n\nThe general process is as follows：\n\n![](https://ss.im5i.com/2021/10/20/yFlGd.png)\n\n### Common management API\n\n`@/api/login.ts`\n\n```typescript\nimport { request } from \"@/utils/service\"\n\ninterface UserRequestData {\n  username: string\n  password: string\n}\n\nexport function accountLogin(data: UserRequestData) {\n  return request({\n    url: \"user/login\",\n    method: \"post\",\n    data,\n  })\n}\n```\n\n### Encapsulated service.ts\n\n`@/utils/service.ts ` is based on axios, which encapsulates request interceptor, response interceptor, unified error handling, unified timeout handling, baseURL setting, CancelToken, etc.\n\n## Multi-environment\n\n### Build\n\nWhen the project is developed and need build, there are two built-in environments:\n\n```sh\n# build test environment\npnpm build:test\n\n# build production environment\npnpm build:prod\n```\n\n### Variables\n\nIn the `.env.xxx` and other files, the variables corresponding to the environment are configured:\n\n```sh\n# Interface corresponding to current environment baseURL\nVUE_APP_BASE_API = 'https://www.xxx.com'\n```\n\naccess：\n\n```js\nconsole.log(process.env.VUE_APP_BASE_API)\n```\n\n# ✈️ Advanced\n\n## ESLint\n\nCode specifications are important!\n\n- Config item：Set in the `.eslintrc.js` file\n- Cancel auto lint：Set `lintOnSave` to `false` in `vue.config.js`\n- The ESlint plug-in of VSCode is recommended here. When coding, it can mark the code that does not comply with the specification in red, and when you save the code, it will automatically help you repair some simple problematic code (VScode configuration ESlint tutorial can be found through Google)\n- Perform lint manually：`pnpm lint`（Execute this command before submitting the code, especially if your `lintOnSave` is `false`）\n\n## Git Hooks\n\ngitHooks is configured in `package. json`, and the code will be detected every time you commit\n\n```json\n\"gitHooks\": {\n    \"pre-commit\": \"lint-staged\"\n  },\n  \"lint-staged\": {\n    \"*.{js,jsx,vue,ts,tsx}\": [\n      \"vue-cli-service lint\",\n      \"git add\"\n    ]\n  }\n```\n\n## Cross origin\n\nUse `proxy` in `vue.config` for reverse proxy.\n\nFor the corresponding production environment, `nginx` can be used as the reverse proxy.\n\n### Reverse proxy\n\n```typescript\nproxy: {\n  '/api/': {\n    target: 'http://xxxxxx/api/',\n    ws: true,\n    pathRewrite: {\n      '^/api/': ''\n    },\n    changeOrigin: true,\n    secure: false\n  }\n}\n```\n\n### CORS\n\nThis scheme has nothing special to do for the front end. It is no different from ordinary sending requests in writing. Most of the workload is on the server.\nAfter completing [CORS](http://www.ruanyifeng.com/blog/2016/04/cors.html), you can easily call the interface in either the development environment or the production environment.\n\n## SVG\n\nThere are global `@/components/svg-icon` components, and the icons can be stored in `@/icons/svg`.\n\n### Usage\n\nThere is no need to import components into the page, which can be used directly.\n\n```html\n\u003c!-- name is the svg file name --\u003e\n\u003c!-- class can modify the default style --\u003e\n\u003csvg-icon name=\"user\" font-size=\"20px\" class=\"icon\" /\u003e\n```\n\n### Get more icons\n\nRecommended use [iconfont](https://www.iconfont.cn/)\n\n## Auto deployment\n\nFill in the **server IP, port, username, password** and other information in the `deploy/index. JS` file, and then execute the `pnpm deploy` command to automatically publish dist file to the corresponding server.\n\n\u003e Note: the username, password and other information in this file are sensitive information and shouldn't be uploaded to the remote repositories, which is very important!\n\n## Add new theme（Take dark theme as an example）\n\n- New theme\n  - `src/style/theme/dark/index.scss`\n  - `src/style/theme/dark/setting.scss`\n- Register the new theme\n  - `src/style/theme/register.scss`\n  - `src/config/theme.ts`\n\n# ❓ Common problem\n\n## All errors\n\nGoogle can solve 99% of error reports.\n\n## Dependency error\n\n- Recommended use pnpm\n- Attempt to delete `node_modules` `.lock` and install again\n- Google search it\n\n## When the routing mode is switched to browserhistory, a blank page appears after refreshing\n\nChange the value of `publicPath` in the ` @/config/vue.custom.config.ts` file from `./` to`/`\n\n# ☕ Other\n\n## Standing on the shoulders of giants\n\n- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)\n- [vue3-composition-admin](https://github.com/rcyj-FED/vue3-composition-admin)\n- [vue-vben-admin](https://github.com/anncwb/vue-vben-admin)\n- [d2-admin](https://github.com/d2-projects/d2-admin)\n- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)\n- [vue3-antd-admin](https://github.com/buqiyuan/vue3-antd-admin)\n\n# 📄 License\n\n[MIT](https://github.com/un-pany/v3-admin/blob/master/LICENSE)\n\nCopyright (c) 2021 UNPany\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fun-pany%2Fv3-admin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fun-pany%2Fv3-admin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fun-pany%2Fv3-admin/lists"}