├── server ├── .dockerignore ├── .template │ ├── jzero-admin-plugin │ │ └── app │ │ │ ├── go.mod.tpl │ │ │ ├── main.go.tpl │ │ │ ├── .jzero.yaml.tpl │ │ │ ├── internal │ │ │ ├── global │ │ │ │ └── global.go.tpl │ │ │ ├── config │ │ │ │ └── config.go.tpl │ │ │ ├── svc │ │ │ │ ├── middleware.go.tpl │ │ │ │ └── config.go.tpl │ │ │ ├── handler │ │ │ │ ├── route2code.go.tpl │ │ │ │ └── routes.go.tpl │ │ │ ├── model │ │ │ │ └── model.go.tpl │ │ │ ├── custom │ │ │ │ └── custom.go.tpl │ │ │ ├── middleware │ │ │ │ └── middleware.go.tpl │ │ │ └── logic │ │ │ │ └── version │ │ │ │ └── version.go.tpl │ │ │ ├── etc │ │ │ └── etc.yaml.tpl │ │ │ ├── desc │ │ │ └── api │ │ │ │ └── v1 │ │ │ │ └── {{.APP}}_version.api.tpl │ │ │ ├── .gitignore.tpl │ │ │ ├── Dockerfile.tpl │ │ │ ├── README.md.tpl │ │ │ └── cmd │ │ │ ├── root.go.tpl │ │ │ └── version.go.tpl │ └── api │ │ └── serverless_plugins.go.tpl ├── internal │ ├── middleware │ │ ├── authx_middleware.go │ │ └── middleware.go │ ├── model │ │ ├── manage_menu │ │ │ ├── vars.go │ │ │ └── manage_menu_model.go │ │ ├── manage_role │ │ │ ├── vars.go │ │ │ └── manage_role_model.go │ │ ├── manage_user │ │ │ ├── vars.go │ │ │ └── manage_user_model.go │ │ ├── manage_email │ │ │ ├── vars.go │ │ │ └── manage_email_model.go │ │ ├── manage_role_menu │ │ │ ├── vars.go │ │ │ └── manage_role_menu_model.go │ │ ├── manage_user_role │ │ │ ├── vars.go │ │ │ └── manage_user_role_model.go │ │ └── model.go │ ├── config │ │ └── config.go │ ├── constant │ │ └── constant.go │ ├── svc │ │ ├── middleware.go │ │ ├── config.go │ │ └── service_context.go │ ├── types │ │ ├── types.go │ │ ├── swagger │ │ │ └── types.go │ │ ├── common │ │ │ └── types.go │ │ └── version │ │ │ └── types.go │ ├── global │ │ └── global.go │ ├── errcodes │ │ ├── manage │ │ │ └── manage.go │ │ ├── auth │ │ │ └── auth.go │ │ └── errcodes.go │ ├── handler │ │ ├── swagger │ │ │ └── swagger.go │ │ └── version │ │ │ └── version.go │ └── logic │ │ ├── swagger │ │ └── swagger.go │ │ ├── version │ │ └── version.go │ │ └── v1 │ │ ├── route │ │ └── is_route_exist.go │ │ └── manage │ │ ├── role │ │ ├── edit.go │ │ ├── get_all.go │ │ ├── get_menus.go │ │ ├── get_home.go │ │ └── delete.go │ │ └── user │ │ └── delete.go ├── plugins │ ├── helloworld │ │ ├── main.go │ │ ├── .jzero.yaml │ │ ├── internal │ │ │ ├── global │ │ │ │ └── global.go │ │ │ ├── config │ │ │ │ └── config.go │ │ │ ├── types │ │ │ │ ├── types.go │ │ │ │ └── version │ │ │ │ │ └── types.go │ │ │ ├── svc │ │ │ │ ├── middleware.go │ │ │ │ └── config.go │ │ │ ├── handler │ │ │ │ ├── route2code.go │ │ │ │ ├── routes.go │ │ │ │ └── version │ │ │ │ │ └── version.go │ │ │ ├── model │ │ │ │ └── model.go │ │ │ ├── custom │ │ │ │ └── custom.go │ │ │ ├── middleware │ │ │ │ └── middleware.go │ │ │ └── logic │ │ │ │ └── version │ │ │ │ └── version.go │ │ ├── etc │ │ │ └── etc.yaml │ │ ├── desc │ │ │ └── api │ │ │ │ └── v1 │ │ │ │ └── helloworld_version.api │ │ ├── .gitignore │ │ ├── Dockerfile │ │ ├── README.md │ │ └── cmd │ │ │ ├── root.go │ │ │ └── version.go │ └── plugins.go ├── main.go ├── desc │ ├── api │ │ ├── swagger.api │ │ ├── common │ │ │ ├── request.api │ │ │ └── response.api │ │ └── version.api │ ├── sql │ │ ├── manage_user_role.sql │ │ ├── manage_role_menu.sql │ │ ├── manage_role.sql │ │ ├── manage_email.sql │ │ ├── manage_user.sql │ │ └── manage_menu.sql │ └── swagger │ │ ├── swagger.swagger.json │ │ └── v1 │ │ └── swagger.swagger.json ├── .jzero.yaml ├── .gitignore ├── etc │ └── etc.yaml ├── README.md ├── cmd │ ├── root.go │ └── version.go └── Dockerfile ├── web ├── .dockerignore ├── pnpm-workspace.yaml ├── src │ ├── styles │ │ ├── scss │ │ │ ├── global.scss │ │ │ └── scrollbar.scss │ │ └── css │ │ │ └── global.css │ ├── service │ │ ├── api │ │ │ ├── index.ts │ │ │ ├── version.ts │ │ │ └── route.ts │ │ └── request │ │ │ └── type.ts │ ├── views │ │ ├── user-center │ │ │ └── index.vue │ │ ├── _builtin │ │ │ ├── 403 │ │ │ │ └── index.vue │ │ │ ├── 404 │ │ │ │ └── index.vue │ │ │ ├── 500 │ │ │ │ └── index.vue │ │ │ ├── login │ │ │ │ └── modules │ │ │ │ │ └── bind-wechat.vue │ │ │ └── iframe-page │ │ │ │ └── [url].vue │ │ ├── manage │ │ │ └── user-detail │ │ │ │ └── [uuid].vue │ │ └── home │ │ │ ├── modules │ │ │ ├── creativity-banner.vue │ │ │ ├── header-banner.vue │ │ │ └── project-news.vue │ │ │ └── index.vue │ ├── plugins │ │ ├── index.ts │ │ ├── assets.ts │ │ ├── dayjs.ts │ │ ├── nprogress.ts │ │ ├── iconify.ts │ │ └── loading.ts │ ├── enum │ │ └── index.ts │ ├── components │ │ ├── common │ │ │ ├── system-logo.vue │ │ │ ├── dark-mode-container.vue │ │ │ ├── reload-button.vue │ │ │ ├── full-screen.vue │ │ │ ├── pin-toggler.vue │ │ │ ├── app-provider.vue │ │ │ ├── exception-base.vue │ │ │ ├── lang-switch.vue │ │ │ ├── menu-toggler.vue │ │ │ └── theme-schema-switch.vue │ │ ├── custom │ │ │ ├── soybean-avatar.vue │ │ │ ├── github-link.vue │ │ │ ├── web-site-link.vue │ │ │ ├── look-forward.vue │ │ │ ├── button-icon.vue │ │ │ ├── svg-icon.vue │ │ │ └── better-scroll.vue │ │ └── advanced │ │ │ └── table-column-setting.vue │ ├── assets │ │ └── svg-icon │ │ │ ├── activity.svg │ │ │ ├── copy.svg │ │ │ ├── chrome.svg │ │ │ ├── heart.svg │ │ │ ├── at-sign.svg │ │ │ ├── wind.svg │ │ │ ├── cast.svg │ │ │ ├── custom-icon.svg │ │ │ └── logo.svg │ ├── locales │ │ ├── locale.ts │ │ ├── naive.ts │ │ ├── dayjs.ts │ │ └── index.ts │ ├── utils │ │ ├── agent.ts │ │ ├── icon.ts │ │ ├── storage.ts │ │ └── common.ts │ ├── hooks │ │ ├── common │ │ │ └── icon.ts │ │ └── business │ │ │ └── auth.ts │ ├── constants │ │ ├── common.ts │ │ ├── map-sdk.ts │ │ ├── reg.ts │ │ └── business.ts │ ├── layouts │ │ ├── blank-layout │ │ │ └── index.vue │ │ └── modules │ │ │ ├── global-footer │ │ │ └── index.vue │ │ │ ├── global-header │ │ │ └── components │ │ │ │ └── theme-button.vue │ │ │ ├── theme-drawer │ │ │ ├── components │ │ │ │ └── setting-item.vue │ │ │ └── index.vue │ │ │ ├── global-search │ │ │ ├── index.vue │ │ │ └── components │ │ │ │ └── search-footer.vue │ │ │ ├── global-logo │ │ │ └── index.vue │ │ │ ├── global-menu │ │ │ ├── modules │ │ │ │ └── horizontal-menu.vue │ │ │ └── index.vue │ │ │ └── global-sider │ │ │ └── index.vue │ ├── router │ │ ├── guard │ │ │ ├── progress.ts │ │ │ ├── title.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── routes │ │ │ └── builtin.ts │ │ └── elegant │ │ │ └── imports.ts │ ├── store │ │ ├── index.ts │ │ ├── modules │ │ │ └── auth │ │ │ │ └── shared.ts │ │ └── plugins │ │ │ └── index.ts │ ├── typings │ │ ├── package.d.ts │ │ ├── api │ │ │ ├── route │ │ │ │ └── route.d.ts │ │ │ ├── common │ │ │ │ └── common.d.ts │ │ │ └── auth │ │ │ │ └── auth.d.ts │ │ ├── global.d.ts │ │ ├── common.d.ts │ │ └── storage.d.ts │ ├── main.ts │ └── theme │ │ └── vars.ts ├── packages │ ├── alova │ │ ├── src │ │ │ ├── client.ts │ │ │ └── constant.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── scripts │ │ ├── bin.ts │ │ ├── src │ │ │ ├── commands │ │ │ │ ├── cleanup.ts │ │ │ │ ├── index.ts │ │ │ │ ├── update-pkg.ts │ │ │ │ ├── release.ts │ │ │ │ └── changelog.ts │ │ │ ├── shared │ │ │ │ └── index.ts │ │ │ ├── types │ │ │ │ └── index.ts │ │ │ └── config │ │ │ │ └── index.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── color │ │ ├── src │ │ │ ├── shared │ │ │ │ ├── index.ts │ │ │ │ └── name.ts │ │ │ ├── constant │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── utils │ │ ├── src │ │ │ ├── nanoid.ts │ │ │ ├── klona.ts │ │ │ ├── index.ts │ │ │ └── crypto.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── materials │ │ ├── src │ │ │ ├── libs │ │ │ │ ├── page-tab │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── index.module.css.d.ts │ │ │ │ │ ├── svg-close.vue │ │ │ │ │ ├── chrome-tab-bg.vue │ │ │ │ │ ├── shared.ts │ │ │ │ │ ├── button-tab.vue │ │ │ │ │ └── chrome-tab.vue │ │ │ │ ├── simple-scrollbar │ │ │ │ │ ├── index.ts │ │ │ │ │ └── index.vue │ │ │ │ └── admin-layout │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── index.module.css.d.ts │ │ │ │ │ └── index.module.css │ │ │ └── index.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── axios │ │ ├── src │ │ │ ├── constant.ts │ │ │ ├── shared.ts │ │ │ └── options.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── uno-preset │ │ ├── package.json │ │ └── tsconfig.json │ ├── ofetch │ │ ├── src │ │ │ └── index.ts │ │ ├── package.json │ │ └── tsconfig.json │ └── hooks │ │ ├── package.json │ │ ├── src │ │ ├── use-loading.ts │ │ ├── index.ts │ │ ├── use-boolean.ts │ │ ├── use-count-down.ts │ │ └── use-svg-icon-render.ts │ │ └── tsconfig.json ├── build │ ├── config │ │ ├── index.ts │ │ ├── time.ts │ │ └── proxy.ts │ └── plugins │ │ ├── html.ts │ │ ├── index.ts │ │ ├── unocss.ts │ │ └── router.ts ├── .npmrc ├── README.md ├── .env.prod ├── .env.test ├── .editorconfig ├── .gitattributes ├── Dockerfile ├── index.html ├── .gitignore ├── .vscode │ ├── extensions.json │ ├── launch.json │ └── settings.json ├── eslint.config.js ├── tsconfig.json ├── uno.config.ts ├── public │ └── favicon.svg └── vite.config.ts ├── .gitignore ├── core-engine ├── i18n │ ├── embed.go │ ├── locale │ │ ├── zh-CN.json │ │ └── en-US.json │ └── i18n_test.go ├── middleware │ ├── i18n_middleware.go │ └── response_middleware.go ├── helper │ └── auth │ │ └── auth.go ├── svc │ ├── middleware.go │ └── casbin.go └── config │ └── config.go ├── .github ├── dependabot.yml └── workflows │ └── server.yaml ├── deploy └── docker-compose │ ├── nginx │ └── default.conf │ └── mysql │ └── config │ └── my.conf └── jzero-admin.code-workspace /server/.dockerignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /web/pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "packages/*" 3 | -------------------------------------------------------------------------------- /web/src/styles/scss/global.scss: -------------------------------------------------------------------------------- 1 | @import './scrollbar.scss'; 2 | -------------------------------------------------------------------------------- /web/packages/alova/src/client.ts: -------------------------------------------------------------------------------- 1 | export * from 'alova/client'; 2 | -------------------------------------------------------------------------------- /web/build/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './proxy'; 2 | export * from './time'; 3 | -------------------------------------------------------------------------------- /web/packages/scripts/bin.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tsx 2 | 3 | import './src/index.ts'; 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | deploy/docker-compose/mysql/data 3 | deploy/docker-compose/postgres/data -------------------------------------------------------------------------------- /web/packages/color/src/shared/index.ts: -------------------------------------------------------------------------------- 1 | export * from './colord'; 2 | export * from './name'; 3 | -------------------------------------------------------------------------------- /web/packages/utils/src/nanoid.ts: -------------------------------------------------------------------------------- 1 | import { nanoid } from 'nanoid'; 2 | 3 | export { nanoid }; 4 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/go.mod.tpl: -------------------------------------------------------------------------------- 1 | module {{ .Module }} 2 | 3 | go {{ .GoVersion }} -------------------------------------------------------------------------------- /web/packages/color/src/constant/index.ts: -------------------------------------------------------------------------------- 1 | export * from './name'; 2 | export * from './palette'; 3 | -------------------------------------------------------------------------------- /web/packages/utils/src/klona.ts: -------------------------------------------------------------------------------- 1 | import { klona as jsonClone } from 'klona/json'; 2 | 3 | export { jsonClone }; 4 | -------------------------------------------------------------------------------- /web/packages/materials/src/libs/page-tab/index.ts: -------------------------------------------------------------------------------- 1 | import PageTab from './index.vue'; 2 | 3 | export default PageTab; 4 | -------------------------------------------------------------------------------- /core-engine/i18n/embed.go: -------------------------------------------------------------------------------- 1 | package i18n 2 | 3 | import "embed" 4 | 5 | //go:embed locale/*.json 6 | var LocaleFS embed.FS 7 | -------------------------------------------------------------------------------- /server/internal/middleware/authx_middleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | // Notice: Define this middleware in core-engine 4 | -------------------------------------------------------------------------------- /web/packages/alova/src/constant.ts: -------------------------------------------------------------------------------- 1 | /** the backend error code key */ 2 | export const BACKEND_ERROR_CODE = 'BACKEND_ERROR'; 3 | -------------------------------------------------------------------------------- /web/packages/materials/src/libs/simple-scrollbar/index.ts: -------------------------------------------------------------------------------- 1 | import SimpleScrollbar from './index.vue'; 2 | 3 | export default SimpleScrollbar; 4 | -------------------------------------------------------------------------------- /web/src/service/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auth'; 2 | export * from './route'; 3 | export * from './manage'; 4 | export * from './version'; 5 | -------------------------------------------------------------------------------- /web/.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmmirror.com/ 2 | shamefully-hoist=true 3 | ignore-workspace-root-check=true 4 | link-workspace-packages=true 5 | -------------------------------------------------------------------------------- /web/packages/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './crypto'; 2 | export * from './storage'; 3 | export * from './nanoid'; 4 | export * from './klona'; 5 | -------------------------------------------------------------------------------- /core-engine/i18n/locale/zh-CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "manage": { 3 | "menu": { 4 | "existSubMenu": "存在子菜单, 请先删除子菜单" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /server/plugins/helloworld/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "helloworld/cmd" 5 | ) 6 | 7 | func main() { 8 | cmd.Execute() 9 | } 10 | -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | # web 2 | 3 | ```shell 4 | git clone https://github.com/jzero-io/jzero-admin.git 5 | cd web 6 | 7 | pnpm i 8 | pnpm dev 9 | ``` 10 | -------------------------------------------------------------------------------- /core-engine/i18n/locale/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "manage": { 3 | "menu": { 4 | "existSubMenu": "Exist sub menu, please delete first" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/main.go.tpl: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "{{ .Module }}/cmd" 5 | ) 6 | 7 | func main() { 8 | cmd.Execute() 9 | } -------------------------------------------------------------------------------- /server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/jzero-io/jzero-admin/server/cmd" 5 | ) 6 | 7 | func main() { 8 | cmd.Execute() 9 | } 10 | -------------------------------------------------------------------------------- /web/src/views/user-center/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /server/internal/model/manage_menu/vars.go: -------------------------------------------------------------------------------- 1 | package manage_menu 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /server/internal/model/manage_role/vars.go: -------------------------------------------------------------------------------- 1 | package manage_role 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /server/internal/model/manage_user/vars.go: -------------------------------------------------------------------------------- 1 | package manage_user 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /server/plugins/helloworld/.jzero.yaml: -------------------------------------------------------------------------------- 1 | gen: 2 | hooks: 3 | after: 4 | - jzero gen swagger 5 | - jzero format 6 | 7 | style: gozero -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/global/global.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import ( 4 | "helloworld/internal/svc" 5 | ) 6 | 7 | var ServiceContext svc.ServiceContext 8 | -------------------------------------------------------------------------------- /server/internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "github.com/jzero-io/jzero-admin/core-engine/config" 4 | 5 | type Config struct { 6 | config.Config 7 | } 8 | -------------------------------------------------------------------------------- /server/internal/constant/constant.go: -------------------------------------------------------------------------------- 1 | package constant 2 | 3 | type CacheKey string 4 | 5 | const ( 6 | CacheVerificationCodePrefix CacheKey = "verification_code" 7 | ) 8 | -------------------------------------------------------------------------------- /server/internal/model/manage_email/vars.go: -------------------------------------------------------------------------------- 1 | package manage_email 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /web/src/plugins/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | export * from './nprogress'; 3 | export * from './iconify'; 4 | export * from './dayjs'; 5 | export * from './app'; 6 | -------------------------------------------------------------------------------- /web/src/views/_builtin/403/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /web/src/views/_builtin/404/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /web/src/views/_builtin/500/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /server/internal/model/manage_role_menu/vars.go: -------------------------------------------------------------------------------- 1 | package manage_role_menu 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /server/internal/model/manage_user_role/vars.go: -------------------------------------------------------------------------------- 1 | package manage_user_role 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /server/internal/svc/middleware.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | type Middleware struct{} 4 | 5 | func NewMiddleware(svcCtx *ServiceContext) Middleware { 6 | return Middleware{} 7 | } 8 | -------------------------------------------------------------------------------- /server/internal/types/types.go: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package types 3 | 4 | import ( 5 | "time" 6 | ) 7 | 8 | var ( 9 | _ = time.Now() 10 | ) 11 | -------------------------------------------------------------------------------- /web/packages/scripts/src/commands/cleanup.ts: -------------------------------------------------------------------------------- 1 | import { rimraf } from 'rimraf'; 2 | 3 | export async function cleanup(paths: string[]) { 4 | await rimraf(paths, { glob: true }); 5 | } 6 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/.jzero.yaml.tpl: -------------------------------------------------------------------------------- 1 | gen: 2 | hooks: 3 | after: 4 | - jzero gen swagger 5 | - jzero format 6 | 7 | style: {{.Style}} -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/internal/global/global.go.tpl: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import ( 4 | "{{ .Module }}/internal/svc" 5 | ) 6 | 7 | var ServiceContext svc.ServiceContext 8 | -------------------------------------------------------------------------------- /server/internal/types/swagger/types.go: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package swagger 3 | 4 | import ( 5 | "time" 6 | ) 7 | 8 | var ( 9 | _ = time.Now() 10 | ) 11 | -------------------------------------------------------------------------------- /web/src/enum/index.ts: -------------------------------------------------------------------------------- 1 | export enum SetupStoreId { 2 | App = 'app-store', 3 | Theme = 'theme-store', 4 | Auth = 'auth-store', 5 | Route = 'route-store', 6 | Tab = 'tab-store' 7 | } 8 | -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "github.com/jzero-io/jzero-admin/core-engine/config" 4 | 5 | type Config struct { 6 | config.Config 7 | } 8 | -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/types/types.go: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package types 3 | 4 | import ( 5 | "time" 6 | ) 7 | 8 | var ( 9 | _ = time.Now() 10 | ) 11 | -------------------------------------------------------------------------------- /web/src/service/api/version.ts: -------------------------------------------------------------------------------- 1 | import { request } from '../request'; 2 | 3 | export function GetVersion() { 4 | return request({ 5 | url: '/api/version', 6 | method: 'get' 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /server/internal/global/global.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import ( 4 | "github.com/jzero-io/jzero-admin/server/internal/svc" 5 | ) 6 | 7 | var ( 8 | ServiceContext svc.ServiceContext 9 | ) 10 | -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/svc/middleware.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | type Middleware struct { 4 | } 5 | 6 | func NewMiddleware(svcCtx *ServiceContext) Middleware { 7 | return Middleware{} 8 | } 9 | -------------------------------------------------------------------------------- /web/packages/axios/src/constant.ts: -------------------------------------------------------------------------------- 1 | /** request id key */ 2 | export const REQUEST_ID_KEY = 'X-Request-Id'; 3 | 4 | /** the backend error code key */ 5 | export const BACKEND_ERROR_CODE = 'BACKEND_ERROR'; 6 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/internal/config/config.go.tpl: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "github.com/jzero-io/jzero-admin/core-engine/config" 4 | 5 | type Config struct { 6 | config.Config 7 | } -------------------------------------------------------------------------------- /web/packages/color/src/index.ts: -------------------------------------------------------------------------------- 1 | import { colorPalettes } from './constant'; 2 | 3 | export * from './palette'; 4 | export * from './shared'; 5 | export { colorPalettes }; 6 | 7 | export * from './types'; 8 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/internal/svc/middleware.go.tpl: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | type Middleware struct { 4 | } 5 | 6 | func NewMiddleware(svcCtx *ServiceContext) Middleware { 7 | return Middleware{} 8 | } -------------------------------------------------------------------------------- /server/desc/api/swagger.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | go_package: "swagger" 5 | ) 6 | 7 | @server ( 8 | group: swagger 9 | ) 10 | service server { 11 | @handler Swagger 12 | get /swagger 13 | } 14 | 15 | -------------------------------------------------------------------------------- /web/src/plugins/assets.ts: -------------------------------------------------------------------------------- 1 | import 'virtual:svg-icons-register'; 2 | import 'uno.css'; 3 | import '../styles/css/global.css'; 4 | import 'swiper/css'; 5 | import 'swiper/css/navigation'; 6 | import 'swiper/css/pagination'; 7 | -------------------------------------------------------------------------------- /web/.env.prod: -------------------------------------------------------------------------------- 1 | # backend service base url, prod environment 2 | VITE_SERVICE_BASE_URL= 3 | 4 | # other backend service base url, prod environment 5 | VITE_OTHER_SERVICE_BASE_URL= `{ 6 | "demo": "http://localhost:9529" 7 | }` 8 | -------------------------------------------------------------------------------- /web/src/components/common/system-logo.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /web/packages/scripts/src/commands/index.ts: -------------------------------------------------------------------------------- 1 | export * from './git-commit'; 2 | export * from './cleanup'; 3 | export * from './update-pkg'; 4 | export * from './changelog'; 5 | export * from './release'; 6 | export * from './router'; 7 | -------------------------------------------------------------------------------- /web/packages/scripts/src/commands/update-pkg.ts: -------------------------------------------------------------------------------- 1 | import { execCommand } from '../shared'; 2 | 3 | export async function updatePkg(args: string[] = ['--deep', '-u']) { 4 | execCommand('npx', ['ncu', ...args], { stdio: 'inherit' }); 5 | } 6 | -------------------------------------------------------------------------------- /web/src/assets/svg-icon/activity.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/src/styles/css/global.css: -------------------------------------------------------------------------------- 1 | @import './reset.css'; 2 | @import './nprogress.css'; 3 | @import './transition.css'; 4 | 5 | html, 6 | body, 7 | #app { 8 | height: 100%; 9 | } 10 | 11 | html { 12 | overflow-x: hidden; 13 | } 14 | -------------------------------------------------------------------------------- /web/src/views/_builtin/login/modules/bind-wechat.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /web/.env.test: -------------------------------------------------------------------------------- 1 | # backend service base url, test environment 2 | VITE_SERVICE_BASE_URL=http://localhost:8001 3 | 4 | # other backend service base url, test environment 5 | VITE_OTHER_SERVICE_BASE_URL= `{ 6 | "demo": "http://localhost:9528" 7 | }` 8 | -------------------------------------------------------------------------------- /server/desc/api/common/request.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | go_package: "common" 5 | ) 6 | 7 | type PageRequest { 8 | Current int `form:"current,default=1,optional"` 9 | Size int `form:"size,default=10,optional"` 10 | } 11 | 12 | -------------------------------------------------------------------------------- /server/desc/api/common/response.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | go_package: "common" 5 | ) 6 | 7 | type PageResponse { 8 | Current int `json:"current"` 9 | Size int `json:"size"` 10 | Total int64 `json:"total"` 11 | } 12 | 13 | -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/handler/route2code.go: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package handler 4 | 5 | import ( 6 | "net/http" 7 | ) 8 | 9 | func Route2Code(r *http.Request) string { 10 | return "unknown" 11 | } 12 | -------------------------------------------------------------------------------- /web/src/service/request/type.ts: -------------------------------------------------------------------------------- 1 | export interface RequestInstanceState { 2 | /** whether the request is refreshing token */ 3 | refreshTokenFn: Promise | null; 4 | /** the request error message stack */ 5 | errMsgStack: string[]; 6 | } 7 | -------------------------------------------------------------------------------- /server/internal/errcodes/manage/manage.go: -------------------------------------------------------------------------------- 1 | package manage 2 | 3 | import "github.com/jzero-io/jzero/core/status" 4 | 5 | const ( 6 | ExistSubMenuCode = 10311 7 | ) 8 | 9 | func RegisterManage() { 10 | status.Register(ExistSubMenuCode) 11 | } 12 | -------------------------------------------------------------------------------- /web/packages/materials/src/libs/admin-layout/index.ts: -------------------------------------------------------------------------------- 1 | import AdminLayout from './index.vue'; 2 | import { LAYOUT_MAX_Z_INDEX, LAYOUT_SCROLL_EL_ID } from './shared'; 3 | 4 | export default AdminLayout; 5 | export { LAYOUT_SCROLL_EL_ID, LAYOUT_MAX_Z_INDEX }; 6 | -------------------------------------------------------------------------------- /web/packages/uno-preset/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/uno-preset", 3 | "version": "1.3.7", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /web/src/locales/locale.ts: -------------------------------------------------------------------------------- 1 | import zhCN from './langs/zh-cn'; 2 | import enUS from './langs/en-us'; 3 | 4 | const locales: Record = { 5 | 'zh-CN': zhCN, 6 | 'en-US': enUS 7 | }; 8 | 9 | export default locales; 10 | -------------------------------------------------------------------------------- /server/internal/errcodes/auth/auth.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import "github.com/jzero-io/jzero/core/status" 4 | 5 | const ( 6 | RefreshTokenExpiredCode = 40102 7 | ) 8 | 9 | func RegisterAuth() { 10 | status.Register(RefreshTokenExpiredCode) 11 | } 12 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/internal/handler/route2code.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package handler 4 | 5 | import ( 6 | "net/http" 7 | ) 8 | 9 | func Route2Code(r *http.Request) string { 10 | return "unknown" 11 | } -------------------------------------------------------------------------------- /web/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /web/src/views/manage/user-detail/[uuid].vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /web/src/plugins/dayjs.ts: -------------------------------------------------------------------------------- 1 | import { extend } from 'dayjs'; 2 | import localeData from 'dayjs/plugin/localeData'; 3 | import { setDayjsLocale } from '../locales/dayjs'; 4 | 5 | export function setupDayjs() { 6 | extend(localeData); 7 | 8 | setDayjsLocale(); 9 | } 10 | -------------------------------------------------------------------------------- /web/src/utils/agent.ts: -------------------------------------------------------------------------------- 1 | export function isPC() { 2 | const agents = ['Android', 'iPhone', 'webOS', 'BlackBerry', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod']; 3 | const isMobile = agents.some(agent => window.navigator.userAgent.includes(agent)); 4 | return !isMobile; 5 | } 6 | -------------------------------------------------------------------------------- /web/src/plugins/nprogress.ts: -------------------------------------------------------------------------------- 1 | import NProgress from 'nprogress'; 2 | 3 | /** Setup plugin NProgress */ 4 | export function setupNProgress() { 5 | NProgress.configure({ easing: 'ease', speed: 500 }); 6 | 7 | // mount on window 8 | window.NProgress = NProgress; 9 | } 10 | -------------------------------------------------------------------------------- /web/src/hooks/common/icon.ts: -------------------------------------------------------------------------------- 1 | import { useSvgIconRender } from '@sa/hooks'; 2 | import SvgIcon from '@/components/custom/svg-icon.vue'; 3 | 4 | export function useSvgIcon() { 5 | const { SvgIconVNode } = useSvgIconRender(SvgIcon); 6 | 7 | return { 8 | SvgIconVNode 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /web/packages/ofetch/src/index.ts: -------------------------------------------------------------------------------- 1 | import { ofetch } from 'ofetch'; 2 | import type { FetchOptions } from 'ofetch'; 3 | 4 | export function createRequest(options: FetchOptions) { 5 | const request = ofetch.create(options); 6 | 7 | return request; 8 | } 9 | 10 | export default createRequest; 11 | -------------------------------------------------------------------------------- /web/.gitattributes: -------------------------------------------------------------------------------- 1 | "*.vue" eol=lf 2 | "*.js" eol=lf 3 | "*.ts" eol=lf 4 | "*.jsx" eol=lf 5 | "*.tsx" eol=lf 6 | "*.mjs" eol=lf 7 | "*.json" eol=lf 8 | "*.html" eol=lf 9 | "*.css" eol=lf 10 | "*.scss" eol=lf 11 | "*.md" eol=lf 12 | "*.yaml" eol=lf 13 | "*.yml" eol=lf 14 | -------------------------------------------------------------------------------- /web/packages/ofetch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/fetch", 3 | "version": "1.3.7", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | }, 12 | "dependencies": { 13 | "ofetch": "1.4.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /web/src/utils/icon.ts: -------------------------------------------------------------------------------- 1 | export function getLocalIcons() { 2 | const svgIcons = import.meta.glob('/src/assets/svg-icon/*.svg'); 3 | 4 | const keys = Object.keys(svgIcons) 5 | .map(item => item.split('/').at(-1)?.replace('.svg', '') || '') 6 | .filter(Boolean); 7 | 8 | return keys; 9 | } 10 | -------------------------------------------------------------------------------- /server/internal/errcodes/errcodes.go: -------------------------------------------------------------------------------- 1 | package errcodes 2 | 3 | import ( 4 | "github.com/jzero-io/jzero-admin/server/internal/errcodes/auth" 5 | "github.com/jzero-io/jzero-admin/server/internal/errcodes/manage" 6 | ) 7 | 8 | func Register() { 9 | manage.RegisterManage() 10 | auth.RegisterAuth() 11 | } 12 | -------------------------------------------------------------------------------- /server/plugins/plugins.go: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package plugins 3 | 4 | import ( 5 | "github.com/zeromicro/go-zero/rest" 6 | 7 | "github.com/jzero-io/jzero-admin/server/internal/svc" 8 | ) 9 | 10 | func LoadPlugins(server *rest.Server, svcCtx *svc.ServiceContext) { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /web/src/assets/svg-icon/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/src/constants/common.ts: -------------------------------------------------------------------------------- 1 | import { transformRecordToOption } from '@/utils/common'; 2 | 3 | export const yesOrNoRecord: Record = { 4 | Y: 'common.yesOrNo.yes', 5 | N: 'common.yesOrNo.no' 6 | }; 7 | 8 | export const yesOrNoOptions = transformRecordToOption(yesOrNoRecord); 9 | -------------------------------------------------------------------------------- /web/src/assets/svg-icon/chrome.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/packages/scripts/src/shared/index.ts: -------------------------------------------------------------------------------- 1 | import type { Options } from 'execa'; 2 | 3 | export async function execCommand(cmd: string, args: string[], options?: Options) { 4 | const { execa } = await import('execa'); 5 | const res = await execa(cmd, args, options); 6 | return (res?.stdout as string)?.trim() || ''; 7 | } 8 | -------------------------------------------------------------------------------- /web/src/layouts/blank-layout/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /server/internal/types/common/types.go: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package common 3 | 4 | import ( 5 | "time" 6 | ) 7 | 8 | var ( 9 | _ = time.Now() 10 | ) 11 | 12 | type PageResponse struct { 13 | Current int `json:"current"` 14 | Size int `json:"size"` 15 | Total int64 `json:"total"` 16 | } 17 | -------------------------------------------------------------------------------- /web/src/assets/svg-icon/heart.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/src/router/guard/progress.ts: -------------------------------------------------------------------------------- 1 | import type { Router } from 'vue-router'; 2 | 3 | export function createProgressGuard(router: Router) { 4 | router.beforeEach((_to, _from, next) => { 5 | window.NProgress?.start?.(); 6 | next(); 7 | }); 8 | router.afterEach(_to => { 9 | window.NProgress?.done?.(); 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /web/packages/color/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/color", 3 | "version": "1.3.7", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | }, 12 | "dependencies": { 13 | "@sa/utils": "workspace:*", 14 | "colord": "2.9.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /web/src/assets/svg-icon/at-sign.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/src/components/custom/soybean-avatar.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /web/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue'; 2 | import { createPinia } from 'pinia'; 3 | import { resetSetupStore } from './plugins'; 4 | 5 | /** Setup Vue store plugin pinia */ 6 | export function setupStore(app: App) { 7 | const store = createPinia(); 8 | 9 | store.use(resetSetupStore); 10 | 11 | app.use(store); 12 | } 13 | -------------------------------------------------------------------------------- /web/src/store/modules/auth/shared.ts: -------------------------------------------------------------------------------- 1 | import { localStg } from '@/utils/storage'; 2 | 3 | /** Get token */ 4 | export function getToken() { 5 | return localStg.get('token') || ''; 6 | } 7 | 8 | /** Clear auth storage */ 9 | export function clearAuthStorage() { 10 | localStg.remove('token'); 11 | localStg.remove('refreshToken'); 12 | } 13 | -------------------------------------------------------------------------------- /web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20.12.2-bullseye-slim AS builder 2 | 3 | WORKDIR /jzero-admin 4 | 5 | COPY ./ ./ 6 | 7 | RUN --mount=type=cache,target=/node_modules npm install -g pnpm@8.15.6 \ 8 | && pnpm i \ 9 | && pnpm build 10 | 11 | FROM nginx:alpine 12 | 13 | WORKDIR /usr/share/nginx/ 14 | 15 | COPY --from=builder /jzero-admin/dist ./html 16 | -------------------------------------------------------------------------------- /web/packages/hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/hooks", 3 | "version": "1.3.7", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | }, 12 | "dependencies": { 13 | "@sa/axios": "workspace:*", 14 | "@sa/utils": "workspace:*" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /web/packages/materials/src/index.ts: -------------------------------------------------------------------------------- 1 | import AdminLayout, { LAYOUT_MAX_Z_INDEX, LAYOUT_SCROLL_EL_ID } from './libs/admin-layout'; 2 | import PageTab from './libs/page-tab'; 3 | import SimpleScrollbar from './libs/simple-scrollbar'; 4 | 5 | export { AdminLayout, LAYOUT_SCROLL_EL_ID, LAYOUT_MAX_Z_INDEX, PageTab, SimpleScrollbar }; 6 | export * from './types'; 7 | -------------------------------------------------------------------------------- /web/src/assets/svg-icon/wind.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/src/assets/svg-icon/cast.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/build/config/time.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | import utc from 'dayjs/plugin/utc'; 3 | import timezone from 'dayjs/plugin/timezone'; 4 | 5 | export function getBuildTime() { 6 | dayjs.extend(utc); 7 | dayjs.extend(timezone); 8 | 9 | const buildTime = dayjs.tz(Date.now(), 'Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss'); 10 | 11 | return buildTime; 12 | } 13 | -------------------------------------------------------------------------------- /web/src/plugins/iconify.ts: -------------------------------------------------------------------------------- 1 | import { addAPIProvider, disableCache } from '@iconify/vue'; 2 | 3 | /** Setup the iconify offline */ 4 | export function setupIconifyOffline() { 5 | const { VITE_ICONIFY_URL } = import.meta.env; 6 | 7 | if (VITE_ICONIFY_URL) { 8 | addAPIProvider('', { resources: [VITE_ICONIFY_URL] }); 9 | 10 | disableCache('all'); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /web/packages/alova/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/alova", 3 | "version": "0.1.0", 4 | "exports": { 5 | ".": "./src/index.ts", 6 | "./client": "./src/client.ts" 7 | }, 8 | "typesVersions": { 9 | "*": { 10 | "*": ["./src/*"] 11 | } 12 | }, 13 | "dependencies": { 14 | "@sa/utils": "workspace:*", 15 | "alova": "3.0.20" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /web/packages/scripts/src/commands/release.ts: -------------------------------------------------------------------------------- 1 | import { versionBump } from 'bumpp'; 2 | 3 | export async function release(execute = 'pnpm sa changelog', push = true) { 4 | await versionBump({ 5 | files: ['**/package.json', '!**/node_modules'], 6 | execute, 7 | all: true, 8 | tag: true, 9 | commit: 'chore(projects): release v%s', 10 | push 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /web/build/plugins/html.ts: -------------------------------------------------------------------------------- 1 | import type { Plugin } from 'vite'; 2 | 3 | export function setupHtmlPlugin(buildTime: string) { 4 | const plugin: Plugin = { 5 | name: 'html-plugin', 6 | apply: 'build', 7 | transformIndexHtml(html) { 8 | return html.replace('', `\n `); 9 | } 10 | }; 11 | 12 | return plugin; 13 | } 14 | -------------------------------------------------------------------------------- /web/src/locales/naive.ts: -------------------------------------------------------------------------------- 1 | import { dateEnUS, dateZhCN, enUS, zhCN } from 'naive-ui'; 2 | import type { NDateLocale, NLocale } from 'naive-ui'; 3 | 4 | export const naiveLocales: Record = { 5 | 'zh-CN': zhCN, 6 | 'en-US': enUS 7 | }; 8 | 9 | export const naiveDateLocales: Record = { 10 | 'zh-CN': dateZhCN, 11 | 'en-US': dateEnUS 12 | }; 13 | -------------------------------------------------------------------------------- /server/.jzero.yaml: -------------------------------------------------------------------------------- 1 | hooks: 2 | before: 3 | - go install tool 4 | 5 | new: 6 | home: .template/jzero-admin-plugin 7 | 8 | gen: 9 | hooks: 10 | after: 11 | - jzero gen swagger 12 | 13 | style: go_zero 14 | git-change: true 15 | route2Code: true 16 | 17 | model-driver: mysql 18 | model-cache: false 19 | model-ignore-columns: ["create_time", "update_time"] 20 | model-schema: jzero-admin -------------------------------------------------------------------------------- /web/packages/hooks/src/use-loading.ts: -------------------------------------------------------------------------------- 1 | import useBoolean from './use-boolean'; 2 | 3 | /** 4 | * Loading 5 | * 6 | * @param initValue Init value 7 | */ 8 | export default function useLoading(initValue = false) { 9 | const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(initValue); 10 | 11 | return { 12 | loading, 13 | startLoading, 14 | endLoading 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /web/src/components/custom/github-link.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /web/src/router/guard/title.ts: -------------------------------------------------------------------------------- 1 | import { useTitle } from '@vueuse/core'; 2 | import type { Router } from 'vue-router'; 3 | import { $t } from '@/locales'; 4 | 5 | export function createDocumentTitleGuard(router: Router) { 6 | router.afterEach(to => { 7 | const { i18nKey, title } = to.meta; 8 | 9 | const documentTitle = i18nKey ? $t(i18nKey) : title; 10 | 11 | useTitle(documentTitle); 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/model/model.go: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package model 4 | 5 | import ( 6 | "github.com/eddieowens/opts" 7 | "github.com/jzero-io/jzero/core/stores/modelx" 8 | "github.com/zeromicro/go-zero/core/stores/sqlx" 9 | ) 10 | 11 | type Model struct{} 12 | 13 | func NewModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) Model { 14 | return Model{} 15 | } 16 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/internal/handler/routes.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package handler 3 | 4 | import ( 5 | "net/http" 6 | "time" 7 | 8 | "github.com/zeromicro/go-zero/rest" 9 | 10 | "{{.Module}}/internal/svc" 11 | ) 12 | 13 | var ( 14 | _ = http.StatusOK 15 | _ = time.Now() 16 | ) 17 | 18 | func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {} 19 | -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/custom/custom.go: -------------------------------------------------------------------------------- 1 | package custom 2 | 3 | type Custom struct{} 4 | 5 | func New() *Custom { 6 | return &Custom{} 7 | } 8 | 9 | // Init Please add custom logic here. 10 | func (c *Custom) Init() error { 11 | return nil 12 | } 13 | 14 | // Start Please add custom logic here. 15 | func (c *Custom) Start() {} 16 | 17 | // Stop Please add shut down logic here. 18 | func (c *Custom) Stop() {} 19 | -------------------------------------------------------------------------------- /web/packages/materials/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/materials", 3 | "version": "1.3.7", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | }, 12 | "dependencies": { 13 | "@sa/utils": "workspace:*", 14 | "simplebar-vue": "2.3.5" 15 | }, 16 | "devDependencies": { 17 | "typed-css-modules": "0.9.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /web/packages/scripts/src/commands/changelog.ts: -------------------------------------------------------------------------------- 1 | import { generateChangelog, generateTotalChangelog } from '@soybeanjs/changelog'; 2 | import type { ChangelogOption } from '@soybeanjs/changelog'; 3 | 4 | export async function genChangelog(options?: Partial, total = false) { 5 | if (total) { 6 | await generateTotalChangelog(options); 7 | } else { 8 | await generateChangelog(options); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/internal/model/model.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package model 4 | 5 | import ( 6 | "github.com/eddieowens/opts" 7 | "github.com/jzero-io/jzero/core/stores/modelx" 8 | "github.com/zeromicro/go-zero/core/stores/sqlx" 9 | ) 10 | 11 | type Model struct {} 12 | 13 | func NewModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) Model { 14 | return Model{} 15 | } -------------------------------------------------------------------------------- /server/internal/types/version/types.go: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package version 3 | 4 | import ( 5 | "time" 6 | ) 7 | 8 | var ( 9 | _ = time.Now() 10 | ) 11 | 12 | type VersionRequest struct { 13 | } 14 | 15 | type VersionResponse struct { 16 | Version string `json:"version"` 17 | GoVersion string `json:"goVersion"` 18 | Commit string `json:"commit"` 19 | Date string `json:"date"` 20 | } 21 | -------------------------------------------------------------------------------- /web/src/utils/storage.ts: -------------------------------------------------------------------------------- 1 | import { createLocalforage, createStorage } from '@sa/utils'; 2 | 3 | const storagePrefix = import.meta.env.VITE_STORAGE_PREFIX || ''; 4 | 5 | export const localStg = createStorage('local', storagePrefix); 6 | 7 | export const sessionStg = createStorage('session', storagePrefix); 8 | 9 | export const localforage = createLocalforage('local'); 10 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/internal/custom/custom.go.tpl: -------------------------------------------------------------------------------- 1 | package custom 2 | 3 | type Custom struct{} 4 | 5 | func New() *Custom { 6 | return &Custom{} 7 | } 8 | 9 | // Init Please add custom logic here. 10 | func (c *Custom) Init() error { 11 | return nil 12 | } 13 | 14 | // Start Please add custom logic here. 15 | func (c *Custom) Start() {} 16 | 17 | // Stop Please add shut down logic here. 18 | func (c *Custom) Stop() {} 19 | -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/types/version/types.go: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package version 3 | 4 | import ( 5 | "time" 6 | ) 7 | 8 | var ( 9 | _ = time.Now() 10 | ) 11 | 12 | type VersionRequest struct { 13 | } 14 | 15 | type VersionResponse struct { 16 | Version string `json:"version"` 17 | GoVersion string `json:"goVersion"` 18 | Commit string `json:"commit"` 19 | Date string `json:"date"` 20 | } 21 | -------------------------------------------------------------------------------- /web/src/components/common/dark-mode-container.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /web/packages/axios/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/axios", 3 | "version": "1.3.7", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | }, 12 | "dependencies": { 13 | "@sa/utils": "workspace:*", 14 | "axios": "1.12.0", 15 | "axios-retry": "4.5.0", 16 | "qs": "6.13.0" 17 | }, 18 | "devDependencies": { 19 | "@types/qs": "6.9.16" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /web/packages/materials/src/libs/simple-scrollbar/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /server/plugins/helloworld/etc/etc.yaml: -------------------------------------------------------------------------------- 1 | rest: 2 | name: helloworld-api 3 | host: 0.0.0.0 4 | port: 8001 5 | 6 | log: 7 | serviceName: helloworld 8 | encoding: plain 9 | level: info 10 | mode: console 11 | 12 | sqlx: 13 | driverName: "mysql" 14 | dataSource: "root:123456@tcp(127.0.0.1:3306)/jzero-admin?charset=utf8mb4&parseTime=True&loc=Local" 15 | 16 | redis: 17 | host: "127.0.0.1:6379" 18 | type: "node" 19 | pass: "123456" -------------------------------------------------------------------------------- /server/desc/sql/manage_user_role.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `manage_user_role` ( 2 | `id` bigint NOT NULL AUTO_INCREMENT, 3 | `uuid` varchar(36) NOT NULL UNIQUE, 4 | `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 5 | `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 6 | `user_uuid` varchar(36) NOT NULL, 7 | `role_uuid` varchar(36) NOT NULL, 8 | PRIMARY KEY (`id`) 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | %VITE_APP_TITLE% 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /web/src/constants/map-sdk.ts: -------------------------------------------------------------------------------- 1 | /** baidu map sdk url */ 2 | export const BAIDU_MAP_SDK_URL = `https://api.map.baidu.com/getscript?v=3.0&ak=KSezYymXPth1DIGILRX3oYN9PxbOQQmU&services=&t=20210201100830&s=1`; 3 | 4 | /** Amap sdk url */ 5 | export const AMAP_SDK_URL = 'https://webapi.amap.com/maps?v=2.0&key=e7bd02bd504062087e6563daf4d6721d'; 6 | 7 | /** tencent sdk url */ 8 | export const TENCENT_MAP_SDK_URL = 'https://map.qq.com/api/gljs?v=1.exp&key=A6DBZ-KXPLW-JKSRY-ONZF4-CPHY3-K6BL7'; 9 | -------------------------------------------------------------------------------- /web/src/layouts/modules/global-footer/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/etc/etc.yaml.tpl: -------------------------------------------------------------------------------- 1 | rest: 2 | name: {{ .APP }}-api 3 | host: 0.0.0.0 4 | port: 8001 5 | 6 | log: 7 | serviceName: {{ .APP }} 8 | encoding: plain 9 | level: info 10 | mode: console 11 | 12 | sqlx: 13 | driverName: "mysql" 14 | dataSource: "root:123456@tcp(127.0.0.1:3306)/jzero-admin?charset=utf8mb4&parseTime=True&loc=Local" 15 | 16 | redis: 17 | host: "127.0.0.1:6379" 18 | type: "node" 19 | pass: "123456" -------------------------------------------------------------------------------- /web/packages/hooks/src/index.ts: -------------------------------------------------------------------------------- 1 | import useBoolean from './use-boolean'; 2 | import useLoading from './use-loading'; 3 | import useCountDown from './use-count-down'; 4 | import useContext from './use-context'; 5 | import useSvgIconRender from './use-svg-icon-render'; 6 | import useHookTable from './use-table'; 7 | 8 | export { useBoolean, useLoading, useCountDown, useContext, useSvgIconRender, useHookTable }; 9 | 10 | export * from './use-signal'; 11 | export * from './use-table'; 12 | -------------------------------------------------------------------------------- /web/src/typings/package.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | declare namespace BMap { 5 | class Map extends BMapGL.Map {} 6 | class Point extends BMapGL.Point {} 7 | } 8 | 9 | declare const TMap: any; 10 | 11 | interface Window { 12 | /** 13 | * make baidu map request under https protocol 14 | * 15 | * - 0: http 16 | * - 1: https 17 | * - 2: https 18 | */ 19 | HOST_TYPE: '0' | '1' | '2'; 20 | } 21 | -------------------------------------------------------------------------------- /web/src/router/guard/index.ts: -------------------------------------------------------------------------------- 1 | import type { Router } from 'vue-router'; 2 | import { createRouteGuard } from './route'; 3 | import { createProgressGuard } from './progress'; 4 | import { createDocumentTitleGuard } from './title'; 5 | 6 | /** 7 | * Router guard 8 | * 9 | * @param router - Router instance 10 | */ 11 | export function createRouterGuard(router: Router) { 12 | createProgressGuard(router); 13 | createRouteGuard(router); 14 | createDocumentTitleGuard(router); 15 | } 16 | -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/middleware/middleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/rest" 5 | "github.com/zeromicro/go-zero/rest/httpx" 6 | 7 | "helloworld/internal/global" 8 | ) 9 | 10 | func Register(server *rest.Server) { 11 | httpx.SetOkHandler(global.ServiceContext.Ok) 12 | httpx.SetErrorHandlerCtx(global.ServiceContext.Error) 13 | httpx.SetValidator(global.ServiceContext.Validate) 14 | server.Use(global.ServiceContext.I18n) 15 | } 16 | -------------------------------------------------------------------------------- /web/packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/utils", 3 | "version": "1.3.7", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "typesVersions": { 8 | "*": { 9 | "*": ["./src/*"] 10 | } 11 | }, 12 | "dependencies": { 13 | "colord": "2.9.3", 14 | "crypto-js": "4.2.0", 15 | "klona": "2.0.6", 16 | "localforage": "1.10.0", 17 | "nanoid": "5.1.0" 18 | }, 19 | "devDependencies": { 20 | "@types/crypto-js": "4.2.2" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /server/desc/api/version.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | go_package: "version" 5 | ) 6 | 7 | type VersionRequest {} 8 | 9 | type VersionResponse { 10 | Version string `json:"version"` 11 | GoVersion string `json:"goVersion"` 12 | Commit string `json:"commit"` 13 | Date string `json:"date"` 14 | } 15 | 16 | @server ( 17 | prefix: /api 18 | group: version 19 | ) 20 | service server { 21 | @handler Version 22 | get /version (VersionRequest) returns (VersionResponse) 23 | } 24 | 25 | -------------------------------------------------------------------------------- /server/internal/middleware/middleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/rest" 5 | "github.com/zeromicro/go-zero/rest/httpx" 6 | 7 | "github.com/jzero-io/jzero-admin/server/internal/global" 8 | ) 9 | 10 | func Register(server *rest.Server) { 11 | httpx.SetOkHandler(global.ServiceContext.Ok) 12 | httpx.SetErrorHandlerCtx(global.ServiceContext.Error) 13 | httpx.SetValidator(global.ServiceContext.Validate) 14 | server.Use(global.ServiceContext.I18n) 15 | } 16 | -------------------------------------------------------------------------------- /web/src/components/custom/web-site-link.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /web/src/typings/api/route/route.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Api { 2 | /** 3 | * namespace Route 4 | * 5 | * backend api module: "route" 6 | */ 7 | namespace Route { 8 | type ElegantConstRoute = import('@elegant-router/types').ElegantConstRoute; 9 | 10 | interface MenuRoute extends ElegantConstRoute { 11 | id: string; 12 | } 13 | 14 | interface UserRoute { 15 | routes: MenuRoute[]; 16 | home: import('@elegant-router/types').LastLevelRouteKey; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /server/desc/sql/manage_role_menu.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `manage_role_menu` ( 2 | `id` bigint NOT NULL AUTO_INCREMENT, 3 | `uuid` varchar(36) NOT NULL UNIQUE, 4 | `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 5 | `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 6 | `role_uuid` varchar(36) NOT NULL, 7 | `menu_uuid` varchar(36) NOT NULL, 8 | `is_home` tinyint(1) NOT NULL, 9 | PRIMARY KEY (`id`) 10 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci -------------------------------------------------------------------------------- /web/src/views/home/modules/creativity-banner.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /web/src/components/common/reload-button.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /server/desc/sql/manage_role.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `manage_role` ( 2 | `id` bigint NOT NULL AUTO_INCREMENT, 3 | `uuid` varchar(36) NOT NULL UNIQUE, 4 | `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 5 | `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 6 | `name` varchar(50) NOT NULL, 7 | `status` varchar(1) NOT NULL, 8 | `code` varchar(255) NOT NULL, 9 | `desc` longtext NOT NULL, 10 | PRIMARY KEY (`id`) 11 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci -------------------------------------------------------------------------------- /web/src/layouts/modules/global-header/components/theme-button.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /web/src/locales/dayjs.ts: -------------------------------------------------------------------------------- 1 | import { locale } from 'dayjs'; 2 | import 'dayjs/locale/zh-cn'; 3 | import 'dayjs/locale/en'; 4 | import { localStg } from '@/utils/storage'; 5 | 6 | /** 7 | * Set dayjs locale 8 | * 9 | * @param lang 10 | */ 11 | export function setDayjsLocale(lang: App.I18n.LangType = 'zh-CN') { 12 | const localMap = { 13 | 'zh-CN': 'zh-cn', 14 | 'en-US': 'en' 15 | } satisfies Record; 16 | 17 | const l = lang || localStg.get('lang') || 'zh-CN'; 18 | 19 | locale(localMap[l]); 20 | } 21 | -------------------------------------------------------------------------------- /web/src/views/_builtin/iframe-page/[url].vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/internal/middleware/middleware.go.tpl: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/rest" 5 | "github.com/zeromicro/go-zero/rest/httpx" 6 | 7 | "{{ .Module }}/internal/svc" 8 | "{{ .Module }}/internal/global" 9 | ) 10 | 11 | func Register(server *rest.Server) { 12 | httpx.SetOkHandler(global.ServiceContext.Ok) 13 | httpx.SetErrorHandlerCtx(global.ServiceContext.Error) 14 | httpx.SetValidator(global.ServiceContext.Validate) 15 | server.Use(global.ServiceContext.I18n) 16 | } 17 | -------------------------------------------------------------------------------- /web/src/hooks/business/auth.ts: -------------------------------------------------------------------------------- 1 | import { useAuthStore } from '@/store/modules/auth'; 2 | 3 | export function useAuth() { 4 | const authStore = useAuthStore(); 5 | 6 | function hasAuth(codes: string | string[]) { 7 | if (!authStore.isLogin) { 8 | return false; 9 | } 10 | 11 | if (typeof codes === 'string') { 12 | return authStore.userInfo.buttons.includes(codes); 13 | } 14 | 15 | return codes.some(code => authStore.userInfo.buttons.includes(code)); 16 | } 17 | 18 | return { 19 | hasAuth 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | !.vscode/settings.json 24 | !.vscode/launch.json 25 | .idea 26 | *.suo 27 | *.ntvs* 28 | *.njsproj 29 | *.sln 30 | *.sw? 31 | 32 | package-lock.json 33 | yarn.lock 34 | 35 | .VSCodeCounter 36 | -------------------------------------------------------------------------------- /web/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "afzalsayed96.icones", 4 | "antfu.iconify", 5 | "antfu.unocss", 6 | "dbaeumer.vscode-eslint", 7 | "editorconfig.editorconfig", 8 | "esbenp.prettier-vscode", 9 | "lokalise.i18n-ally", 10 | "mhutchie.git-graph", 11 | "mikestead.dotenv", 12 | "naumovs.color-highlight", 13 | "pkief.material-icon-theme", 14 | "sdras.vue-vscode-snippets", 15 | "vue.volar", 16 | "whtouche.vscode-js-console-utils", 17 | "zhuangtongfa.material-theme" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /web/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "chrome", 6 | "request": "launch", 7 | "name": "Vue Debugger", 8 | "url": "http://localhost:9527", 9 | "webRoot": "${workspaceFolder}" 10 | }, 11 | { 12 | "type": "node", 13 | "request": "launch", 14 | "name": "TS Debugger", 15 | "runtimeExecutable": "tsx", 16 | "skipFiles": ["/**", "${workspaceFolder}/node_modules/**"], 17 | "program": "${file}" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /web/src/layouts/modules/theme-drawer/components/setting-item.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /web/src/assets/svg-icon/custom-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/src/components/common/full-screen.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /web/src/layouts/modules/global-search/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /web/src/components/custom/look-forward.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /web/packages/materials/src/libs/page-tab/index.module.css.d.ts: -------------------------------------------------------------------------------- 1 | declare const styles: { 2 | readonly 'button-tab': string; 3 | readonly 'button-tab_dark': string; 4 | readonly 'button-tab_active': string; 5 | readonly 'button-tab_active_dark': string; 6 | readonly 'chrome-tab': string; 7 | readonly 'chrome-tab_active': string; 8 | readonly 'chrome-tab__bg': string; 9 | readonly 'chrome-tab_active_dark': string; 10 | readonly 'chrome-tab_dark': string; 11 | readonly 'chrome-tab-divider': string; 12 | readonly 'svg-close': string; 13 | }; 14 | 15 | export default styles; 16 | -------------------------------------------------------------------------------- /server/plugins/helloworld/desc/api/v1/helloworld_version.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | go_package: "version" 5 | version: "v1" 6 | WrapCodeMsg: true 7 | ) 8 | 9 | type VersionRequest {} 10 | 11 | type VersionResponse { 12 | Version string `json:"version"` 13 | GoVersion string `json:"goVersion"` 14 | Commit string `json:"commit"` 15 | Date string `json:"date"` 16 | } 17 | 18 | @server ( 19 | prefix: /api/v1/helloworld 20 | group: version 21 | ) 22 | service helloworld { 23 | @handler Version 24 | get /version (VersionRequest) returns (VersionResponse) 25 | } 26 | 27 | -------------------------------------------------------------------------------- /web/src/styles/scss/scrollbar.scss: -------------------------------------------------------------------------------- 1 | @mixin scrollbar($size: 7px, $color: rgba(0, 0, 0, 0.5)) { 2 | scrollbar-width: thin; 3 | scrollbar-color: $color transparent; 4 | 5 | &::-webkit-scrollbar-thumb { 6 | background-color: $color; 7 | border-radius: $size; 8 | } 9 | &::-webkit-scrollbar-thumb:hover { 10 | background-color: $color; 11 | border-radius: $size; 12 | } 13 | &::-webkit-scrollbar { 14 | width: $size; 15 | height: $size; 16 | } 17 | &::-webkit-scrollbar-track-piece { 18 | background-color: rgba(0, 0, 0, 0); 19 | border-radius: 0; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /web/packages/alova/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /web/packages/axios/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /web/packages/color/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /web/packages/hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /web/packages/ofetch/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /web/packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /web/packages/materials/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /web/packages/uno-preset/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /core-engine/i18n/i18n_test.go: -------------------------------------------------------------------------------- 1 | package i18n 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestTranslate(t *testing.T) { 11 | c := I18nConf{ 12 | Dir: "", 13 | } 14 | 15 | trans := NewTranslator(c, LocaleFS) 16 | 17 | res := trans.Trans(context.WithValue(context.Background(), "lang", "zh-CN"), "manage.menu.existSubMenu") 18 | assert.Equal(t, "存在子菜单, 请先删除子菜单", res) 19 | 20 | res = trans.Trans(context.WithValue(context.Background(), "lang", "en-US"), "manage.menu.existSubMenu") 21 | assert.Equal(t, "Exist sub menu, please delete first", res) 22 | } 23 | -------------------------------------------------------------------------------- /deploy/docker-compose/nginx/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | location / { 5 | root /usr/share/nginx/html; 6 | try_files $uri $uri/ /index.html; 7 | index index.html index.htm; 8 | } 9 | location /api { 10 | proxy_pass http://server:8001; 11 | proxy_set_header Host $host; 12 | proxy_set_header X-Real-IP $remote_addr; 13 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 14 | } 15 | error_page 500 502 503 504 /50x.html; 16 | location = /50x.html { 17 | root html; 18 | } 19 | } -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/desc/api/v1/{{.APP}}_version.api.tpl: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | go_package: "version" 5 | version: "v1" 6 | WrapCodeMsg: true 7 | ) 8 | 9 | type VersionRequest {} 10 | 11 | type VersionResponse { 12 | Version string `json:"version"` 13 | GoVersion string `json:"goVersion"` 14 | Commit string `json:"commit"` 15 | Date string `json:"date"` 16 | } 17 | 18 | @server( 19 | prefix: /api/v1/{{.APP}} 20 | group: version 21 | ) 22 | service {{ .APP | ToCamel }} { 23 | @handler Version 24 | get /version (VersionRequest) returns (VersionResponse) 25 | } -------------------------------------------------------------------------------- /web/packages/hooks/src/use-boolean.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue'; 2 | 3 | /** 4 | * Boolean 5 | * 6 | * @param initValue Init value 7 | */ 8 | export default function useBoolean(initValue = false) { 9 | const bool = ref(initValue); 10 | 11 | function setBool(value: boolean) { 12 | bool.value = value; 13 | } 14 | function setTrue() { 15 | setBool(true); 16 | } 17 | function setFalse() { 18 | setBool(false); 19 | } 20 | function toggle() { 21 | setBool(!bool.value); 22 | } 23 | 24 | return { 25 | bool, 26 | setBool, 27 | setTrue, 28 | setFalse, 29 | toggle 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /web/packages/scripts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sa/scripts", 3 | "version": "1.3.7", 4 | "bin": { 5 | "sa": "./bin.ts" 6 | }, 7 | "exports": { 8 | ".": "./src/index.ts" 9 | }, 10 | "typesVersions": { 11 | "*": { 12 | "*": ["./src/*"] 13 | } 14 | }, 15 | "devDependencies": { 16 | "@soybeanjs/changelog": "0.3.24", 17 | "bumpp": "9.7.1", 18 | "c12": "2.0.1", 19 | "cac": "6.7.14", 20 | "consola": "3.2.3", 21 | "enquirer": "2.4.1", 22 | "execa": "9.4.0", 23 | "kolorist": "1.8.0", 24 | "npm-check-updates": "17.1.3", 25 | "rimraf": "6.0.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /web/packages/scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "types": ["node"], 11 | "strict": true, 12 | "strictNullChecks": true, 13 | "noUnusedLocals": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "include": ["src/**/*", "typings/**/*"], 19 | "exclude": ["node_modules", "dist"] 20 | } 21 | -------------------------------------------------------------------------------- /server/desc/sql/manage_email.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `manage_email` ( 2 | `id` bigint NOT NULL AUTO_INCREMENT, 3 | `uuid` varchar(36) NOT NULL UNIQUE, 4 | `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 5 | `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 6 | `from` longtext NOT NULL, 7 | `host` longtext NOT NULL, 8 | `port` bigint NOT NULL, 9 | `username` longtext NOT NULL, 10 | `password` longtext NOT NULL, 11 | `enable_ssl` tinyint(1) NOT NULL, 12 | `is_verify` tinyint(1) NOT NULL, 13 | PRIMARY KEY (`id`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci -------------------------------------------------------------------------------- /server/plugins/helloworld/.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # idea 21 | .idea 22 | 23 | # Vs Code 24 | .vscode 25 | 26 | # logs 27 | logs -------------------------------------------------------------------------------- /server/.template/api/serverless_plugins.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package plugins 3 | 4 | import ( 5 | "github.com/zeromicro/go-zero/rest" 6 | 7 | "{{ .Module }}/internal/svc" 8 | {{range $v := .Plugins}}{{ $v.Path | base }} "{{ $v.Module }}/serverless" 9 | {{end}} 10 | ) 11 | 12 | func LoadPlugins(server *rest.Server, svcCtx *svc.ServiceContext) { 13 | {{ range $v := .Plugins }} 14 | { 15 | serverless := {{ $v.Path | base }}.New(svcCtx.ServiceContext) 16 | serverless.HandlerFunc(server, serverless.SvcCtx) 17 | handler.RegisterRoute2Code(serverless.RouteCodesMap) 18 | } 19 | {{end}} 20 | } -------------------------------------------------------------------------------- /web/src/service/api/route.ts: -------------------------------------------------------------------------------- 1 | import { request } from '../request'; 2 | 3 | /** get constant routes */ 4 | export function GetConstantRoutes() { 5 | return request({ url: '/api/v1/route/getConstantRoutes' }); 6 | } 7 | 8 | /** get user routes */ 9 | export function GetUserRoutes() { 10 | return request({ url: '/api/v1/route/getUserRoutes' }); 11 | } 12 | 13 | /** 14 | * whether the route is exist 15 | * 16 | * @param routeName route name 17 | */ 18 | export function IsRouteExist(routeName: string) { 19 | return request({ url: '/api/v1/route/isRouteExist', params: { routeName } }); 20 | } 21 | -------------------------------------------------------------------------------- /web/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@soybeanjs/eslint-config'; 2 | 3 | export default defineConfig( 4 | { vue: true, unocss: true }, 5 | { 6 | rules: { 7 | 'vue/multi-word-component-names': [ 8 | 'warn', 9 | { 10 | ignores: ['index', 'App', 'Register', '[uuid]', '[url]'] 11 | } 12 | ], 13 | 'vue/component-name-in-template-casing': [ 14 | 'warn', 15 | 'PascalCase', 16 | { 17 | registeredComponentsOnly: false, 18 | ignores: ['/^icon-/'] 19 | } 20 | ], 21 | 'unocss/order-attributify': 'off' 22 | } 23 | } 24 | ); 25 | -------------------------------------------------------------------------------- /web/src/locales/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue'; 2 | import { createI18n } from 'vue-i18n'; 3 | import { localStg } from '@/utils/storage'; 4 | import messages from './locale'; 5 | 6 | const i18n = createI18n({ 7 | locale: localStg.get('lang') || 'zh-CN', 8 | fallbackLocale: 'en', 9 | messages, 10 | legacy: false 11 | }); 12 | 13 | /** 14 | * Setup plugin i18n 15 | * 16 | * @param app 17 | */ 18 | export function setupI18n(app: App) { 19 | app.use(i18n); 20 | } 21 | 22 | export const $t = i18n.global.t as App.I18n.$T; 23 | 24 | export function setLocale(locale: App.I18n.LangType) { 25 | i18n.global.locale.value = locale; 26 | } 27 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/.gitignore.tpl: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # idea 21 | .idea 22 | 23 | # Vs Code 24 | .vscode 25 | 26 | # logs 27 | logs -------------------------------------------------------------------------------- /server/plugins/helloworld/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=$BUILDPLATFORM ghcr.io/jzero-io/jzero:latest AS builder 2 | 3 | ARG TARGETARCH 4 | ARG LDFLAGS 5 | 6 | ENV GOPROXY=https://goproxy.cn,direct 7 | 8 | WORKDIR /app 9 | 10 | COPY ./ ./ 11 | 12 | RUN --mount=type=cache,target=/go/pkg CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -a -ldflags="$LDFLAGS" -o /dist/app main.go \ 13 | && jzero gen swagger \ 14 | && cp -r etc /dist/etc \ 15 | && mkdir -p /dist/desc && cp -r desc/swagger /dist/desc 16 | 17 | 18 | FROM alpine:latest 19 | 20 | WORKDIR /dist 21 | 22 | COPY --from=builder /dist . 23 | 24 | EXPOSE 8001 25 | 26 | CMD ["./app", "server"] -------------------------------------------------------------------------------- /web/src/components/common/pin-toggler.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /web/src/typings/global.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | 3 | declare global { 4 | export interface Window { 5 | /** NProgress instance */ 6 | NProgress?: import('nprogress').NProgress; 7 | /** Loading bar instance */ 8 | $loadingBar?: import('naive-ui').LoadingBarProviderInst; 9 | /** Dialog instance */ 10 | $dialog?: import('naive-ui').DialogProviderInst; 11 | /** Message instance */ 12 | $message?: import('naive-ui').MessageProviderInst; 13 | /** Notification instance */ 14 | $notification?: import('naive-ui').NotificationProviderInst; 15 | } 16 | 17 | /** Build time of the project */ 18 | export const BUILD_TIME: string; 19 | } 20 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/Dockerfile.tpl: -------------------------------------------------------------------------------- 1 | FROM --platform=$BUILDPLATFORM ghcr.io/jzero-io/jzero:latest AS builder 2 | 3 | ARG TARGETARCH 4 | ARG LDFLAGS 5 | 6 | ENV GOPROXY=https://goproxy.cn,direct 7 | 8 | WORKDIR /app 9 | 10 | COPY ./ ./ 11 | 12 | RUN --mount=type=cache,target=/go/pkg CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -a -ldflags="$LDFLAGS" -o /dist/app main.go \ 13 | && jzero gen swagger \ 14 | && cp -r etc /dist/etc \ 15 | && mkdir -p /dist/desc && cp -r desc/swagger /dist/desc 16 | 17 | 18 | FROM alpine:latest 19 | 20 | WORKDIR /dist 21 | 22 | COPY --from=builder /dist . 23 | 24 | EXPOSE 8001 25 | 26 | CMD ["./app", "server"] -------------------------------------------------------------------------------- /core-engine/middleware/i18n_middleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | ) 7 | 8 | type I18nMiddleware struct { 9 | } 10 | 11 | func NewI18nMiddleware() *I18nMiddleware { 12 | return &I18nMiddleware{} 13 | } 14 | 15 | func (m *I18nMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { 16 | return func(writer http.ResponseWriter, request *http.Request) { 17 | rctx := request.Context() 18 | if lang := request.Header.Get("Accept-Language"); lang == "" { 19 | rctx = context.WithValue(rctx, "lang", "zh-CN") 20 | } else { 21 | rctx = context.WithValue(rctx, "lang", lang) 22 | } 23 | next(writer, request.WithContext(rctx)) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /server/internal/handler/swagger/swagger.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. Templates Edited by jzero. DO NOT EDIT. 2 | 3 | package swagger 4 | 5 | import ( 6 | "net/http" 7 | 8 | "github.com/zeromicro/go-zero/rest/httpx" 9 | 10 | "github.com/jzero-io/jzero-admin/server/internal/logic/swagger" 11 | "github.com/jzero-io/jzero-admin/server/internal/svc" 12 | ) 13 | 14 | func Swagger(svcCtx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | l := swagger.NewSwagger(r.Context(), svcCtx, r, w) 17 | err := l.Swagger() 18 | if err != nil { 19 | httpx.ErrorCtx(r.Context(), w, err) 20 | } else { 21 | httpx.Ok(w) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /web/src/store/plugins/index.ts: -------------------------------------------------------------------------------- 1 | import type { PiniaPluginContext } from 'pinia'; 2 | import { jsonClone } from '@sa/utils'; 3 | import { SetupStoreId } from '@/enum'; 4 | 5 | /** 6 | * The plugin reset the state of the store which is written by setup syntax 7 | * 8 | * @param context 9 | */ 10 | export function resetSetupStore(context: PiniaPluginContext) { 11 | const setupSyntaxIds = Object.values(SetupStoreId) as string[]; 12 | 13 | if (setupSyntaxIds.includes(context.store.$id)) { 14 | const { $state } = context.store; 15 | 16 | const defaultStore = jsonClone($state); 17 | 18 | context.store.$reset = () => { 19 | context.store.$patch(defaultStore); 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /web/src/typings/common.d.ts: -------------------------------------------------------------------------------- 1 | /** The common type namespace */ 2 | declare namespace CommonType { 3 | /** The strategic pattern */ 4 | interface StrategicPattern { 5 | /** The condition */ 6 | condition: boolean; 7 | /** If the condition is true, then call the action function */ 8 | callback: () => void; 9 | } 10 | 11 | /** 12 | * The option type 13 | * 14 | * @property value: The option value 15 | * @property label: The option label 16 | */ 17 | type Option = { value: K; label: string }; 18 | 19 | type YesOrNo = 'Y' | 'N'; 20 | 21 | /** add null to all properties */ 22 | type RecordNullable = { 23 | [K in keyof T]?: T[K] | null; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # idea 21 | .idea 22 | 23 | # Vs Code 24 | .vscode 25 | 26 | # logs 27 | logs 28 | 29 | # goreleaser output 30 | dist 31 | 32 | *.db 33 | 34 | data 35 | /server 36 | !/server/ -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/handler/routes.go: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package handler 3 | 4 | import ( 5 | "net/http" 6 | "time" 7 | 8 | "github.com/zeromicro/go-zero/rest" 9 | 10 | version "helloworld/internal/handler/version" 11 | "helloworld/internal/svc" 12 | ) 13 | 14 | var ( 15 | _ = http.StatusOK 16 | _ = time.Now() 17 | ) 18 | 19 | func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { 20 | { 21 | server.AddRoutes( 22 | []rest.Route{ 23 | { 24 | Method: http.MethodGet, 25 | Path: "/version", 26 | Handler: version.Version(serverCtx), 27 | }, 28 | }, 29 | rest.WithPrefix("/api/v1/helloworld"), 30 | ) 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /web/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll.eslint": "explicit", 4 | "source.organizeImports": "never" 5 | }, 6 | "eslint.useFlatConfig": true, 7 | "editor.formatOnSave": false, 8 | "eslint.validate": ["html", "css", "scss", "json", "jsonc"], 9 | "i18n-ally.displayLanguage": "zh-cn", 10 | "i18n-ally.enabledParsers": ["ts"], 11 | "i18n-ally.enabledFrameworks": ["vue"], 12 | "i18n-ally.editor.preferEditor": true, 13 | "i18n-ally.keystyle": "nested", 14 | "i18n-ally.localesPaths": ["src/locales/langs"], 15 | "prettier.enable": false, 16 | "typescript.tsdk": "node_modules/typescript/lib", 17 | "unocss.root": ["./"], 18 | "vue.server.hybridMode": true 19 | } 20 | -------------------------------------------------------------------------------- /web/src/layouts/modules/global-logo/index.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /web/packages/materials/src/libs/admin-layout/index.module.css.d.ts: -------------------------------------------------------------------------------- 1 | declare const styles: { 2 | readonly 'layout-header': string; 3 | readonly 'layout-header-placement': string; 4 | readonly 'layout-tab': string; 5 | readonly 'layout-tab-placement': string; 6 | readonly 'layout-sider': string; 7 | readonly 'layout-mobile-sider': string; 8 | readonly 'layout-mobile-sider-mask': string; 9 | readonly 'layout-sider_collapsed': string; 10 | readonly 'layout-footer': string; 11 | readonly 'layout-footer-placement': string; 12 | readonly 'left-gap': string; 13 | readonly 'left-gap_collapsed': string; 14 | readonly 'sider-padding-top': string; 15 | readonly 'sider-padding-bottom': string; 16 | }; 17 | 18 | export default styles; 19 | -------------------------------------------------------------------------------- /core-engine/helper/auth/auth.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type Auth struct { 8 | Uuid string `json:"uuid"` 9 | Username string `json:"username"` 10 | RoleUuids []string `json:"role_uuids"` 11 | } 12 | 13 | func Info(ctx context.Context) (Auth, error) { 14 | var auth Auth 15 | if v, ok := ctx.Value("uuid").(string); ok { 16 | auth.Uuid = v 17 | } 18 | if v, ok := ctx.Value("username").(string); ok { 19 | auth.Username = v 20 | } 21 | if v, ok := ctx.Value("role_uuids").([]any); ok { 22 | roleIds := make([]string, len(v)) 23 | for i, n := range v { 24 | if str, ok := n.(string); ok { 25 | roleIds[i] = str 26 | } 27 | } 28 | auth.RoleUuids = roleIds 29 | } 30 | return auth, nil 31 | } 32 | -------------------------------------------------------------------------------- /server/desc/sql/manage_user.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `manage_user` ( 2 | `id` bigint NOT NULL AUTO_INCREMENT, 3 | `uuid` varchar(36) NOT NULL UNIQUE, 4 | `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 5 | `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 6 | `username` varchar(30) NOT NULL, 7 | `password` varchar(100) NOT NULL, 8 | `nickname` varchar(30) NOT NULL, 9 | `gender` varchar(1) NOT NULL, 10 | `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 11 | `status` varchar(1) NOT NULL, 12 | `email` varchar(100) NOT NULL, 13 | PRIMARY KEY (`id`), 14 | UNIQUE KEY `uni_manage_user_username` (`username`) 15 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci -------------------------------------------------------------------------------- /web/packages/utils/src/crypto.ts: -------------------------------------------------------------------------------- 1 | import CryptoJS from 'crypto-js'; 2 | 3 | export class Crypto { 4 | /** Secret */ 5 | secret: string; 6 | 7 | constructor(secret: string) { 8 | this.secret = secret; 9 | } 10 | 11 | encrypt(data: T): string { 12 | const dataString = JSON.stringify(data); 13 | const encrypted = CryptoJS.AES.encrypt(dataString, this.secret); 14 | return encrypted.toString(); 15 | } 16 | 17 | decrypt(encrypted: string) { 18 | const decrypted = CryptoJS.AES.decrypt(encrypted, this.secret); 19 | const dataString = decrypted.toString(CryptoJS.enc.Utf8); 20 | try { 21 | return JSON.parse(dataString) as T; 22 | } catch { 23 | // avoid parse error 24 | return null; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /server/etc/etc.yaml: -------------------------------------------------------------------------------- 1 | banner: 2 | text: jzero-admin 3 | 4 | rest: 5 | name: jzero-admin-api 6 | host: 0.0.0.0 7 | port: 8001 8 | timeout: 20000 9 | 10 | log: 11 | encoding: plain 12 | level: info 13 | mode: console 14 | 15 | sqlx: 16 | # datasource: "${DATASOURCE:-root:123456@tcp(127.0.0.1:3306)/jzero-admin?charset=utf8mb4&parseTime=True&loc=Local}" 17 | # driverName: "${DRIVER_NAME:-mysql}" 18 | # datasource: "${DATASOURCE:-postgres://root:123456@localhost:5432/jzero-admin}" 19 | # driverName: "${DRIVER_NAME:-pgx}" 20 | datasource: "${DATASOURCE:-jzero-admin.db}" 21 | driverName: "${DRIVER_NAME:-sqlite}" 22 | 23 | redis: 24 | miniRedis: ${REDIS_MINI_REDIS:-true} 25 | # host: "${REDIS_HOST:-127.0.0.1:6379}" 26 | # type: "${REDIS_TYPE:-node}" -------------------------------------------------------------------------------- /server/README.md: -------------------------------------------------------------------------------- 1 | # server 2 | 3 | ## Install Jzero Framework 4 | 5 | ```shell 6 | go install github.com/jzero-io/jzero/cmd/jzero@latest 7 | 8 | jzero check 9 | ``` 10 | 11 | ## Generate code 12 | 13 | ### Generate server code 14 | 15 | ```shell 16 | jzero gen 17 | ``` 18 | 19 | ### Generate swagger code 20 | 21 | ```shell 22 | jzero gen swagger 23 | ``` 24 | 25 | you can see generated swagger json in `desc/swagger` 26 | 27 | ## Build docker image 28 | 29 | ```shell 30 | # add a builder first 31 | docker buildx create --use --name=mybuilder --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master 32 | 33 | # build and load 34 | docker buildx build --platform linux/amd64 --progress=plain -t server:latest . --load 35 | ``` 36 | 37 | ## Documents 38 | 39 | https://docs.jzero.io -------------------------------------------------------------------------------- /web/packages/materials/src/libs/page-tab/svg-close.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /server/cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | // rootCmd represents the base command when called without any subcommands 10 | var rootCmd = &cobra.Command{ 11 | Use: "server", 12 | Short: "server root", 13 | Long: "server root.", 14 | CompletionOptions: cobra.CompletionOptions{ 15 | DisableDefaultCmd: true, 16 | }, 17 | } 18 | 19 | // Execute adds all child commands to the root command and sets flags appropriately. 20 | // This is called by main.main(). It only needs to happen once to the rootCmd. 21 | func Execute() { 22 | err := rootCmd.Execute() 23 | if err != nil { 24 | os.Exit(1) 25 | } 26 | } 27 | 28 | func init() { 29 | rootCmd.PersistentFlags().String("config", "etc/etc.yaml", "config file (default is project root dir etc/etc.yaml") 30 | } 31 | -------------------------------------------------------------------------------- /server/plugins/helloworld/README.md: -------------------------------------------------------------------------------- 1 | # helloworld 2 | 3 | ## Install Jzero Framework 4 | 5 | ```shell 6 | go install github.com/jzero-io/jzero/cmd/jzero@latest 7 | 8 | jzero check 9 | ``` 10 | 11 | ## Generate code 12 | 13 | ### Generate server code 14 | 15 | ```shell 16 | jzero gen 17 | ``` 18 | 19 | ### Generate swagger code 20 | 21 | ```shell 22 | jzero gen swagger 23 | ``` 24 | 25 | you can see generated swagger json in `desc/swagger` 26 | 27 | ## Build docker image 28 | 29 | ```shell 30 | # add a builder first 31 | docker buildx create --use --name=mybuilder --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master 32 | 33 | # build and load 34 | docker buildx build --platform linux/arm64 --progress=plain -t helloworld:latest . --load 35 | ``` 36 | 37 | ## Documents 38 | 39 | https://docs.jzero.io -------------------------------------------------------------------------------- /web/build/plugins/index.ts: -------------------------------------------------------------------------------- 1 | import type { PluginOption } from 'vite'; 2 | import vue from '@vitejs/plugin-vue'; 3 | import vueJsx from '@vitejs/plugin-vue-jsx'; 4 | import VueDevtools from 'vite-plugin-vue-devtools'; 5 | import progress from 'vite-plugin-progress'; 6 | import { setupElegantRouter } from './router'; 7 | import { setupUnocss } from './unocss'; 8 | import { setupUnplugin } from './unplugin'; 9 | import { setupHtmlPlugin } from './html'; 10 | 11 | export function setupVitePlugins(viteEnv: Env.ImportMeta, buildTime: string) { 12 | const plugins: PluginOption = [ 13 | vue(), 14 | vueJsx(), 15 | VueDevtools(), 16 | setupElegantRouter(), 17 | setupUnocss(viteEnv), 18 | ...setupUnplugin(viteEnv), 19 | progress(), 20 | setupHtmlPlugin(buildTime) 21 | ]; 22 | 23 | return plugins; 24 | } 25 | -------------------------------------------------------------------------------- /web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "jsxImportSource": "vue", 6 | "lib": ["DOM", "ESNext"], 7 | "baseUrl": ".", 8 | "module": "ESNext", 9 | "moduleResolution": "node", 10 | "paths": { 11 | "@/*": ["./src/*"], 12 | "~/*": ["./*"] 13 | }, 14 | "resolveJsonModule": true, 15 | "types": ["vite/client", "node", "unplugin-icons/types/vue", "naive-ui/volar"], 16 | "strict": true, 17 | "strictNullChecks": true, 18 | "noUnusedLocals": false, 19 | "allowSyntheticDefaultImports": true, 20 | "esModuleInterop": true, 21 | "forceConsistentCasingInFileNames": true, 22 | "isolatedModules": true 23 | }, 24 | "include": ["./**/*.ts", "./**/*.tsx", "./**/*.vue"], 25 | "exclude": ["node_modules", "dist"] 26 | } 27 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/README.md.tpl: -------------------------------------------------------------------------------- 1 | # {{ .APP }} 2 | 3 | ## Install Jzero Framework 4 | 5 | ```shell 6 | go install github.com/jzero-io/jzero/cmd/jzero@latest 7 | 8 | jzero check 9 | ``` 10 | 11 | ## Generate code 12 | 13 | ### Generate server code 14 | 15 | ```shell 16 | jzero gen 17 | ``` 18 | 19 | ### Generate swagger code 20 | 21 | ```shell 22 | jzero gen swagger 23 | ``` 24 | 25 | you can see generated swagger json in `desc/swagger` 26 | 27 | ## Build docker image 28 | 29 | ```shell 30 | # add a builder first 31 | docker buildx create --use --name=mybuilder --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master 32 | 33 | # build and load 34 | docker buildx build --platform linux/{{ .GoArch }} --progress=plain -t {{ .APP }}:latest . --load 35 | ``` 36 | 37 | ## Documents 38 | 39 | https://docs.jzero.io -------------------------------------------------------------------------------- /server/plugins/helloworld/cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | // rootCmd represents the base command when called without any subcommands 10 | var rootCmd = &cobra.Command{ 11 | Use: "helloworld", 12 | Short: "helloworld root", 13 | Long: "helloworld root.", 14 | CompletionOptions: cobra.CompletionOptions{ 15 | DisableDefaultCmd: true, 16 | }, 17 | } 18 | 19 | // Execute adds all child commands to the root command and sets flags appropriately. 20 | // This is called by main.main(). It only needs to happen once to the rootCmd. 21 | func Execute() { 22 | err := rootCmd.Execute() 23 | if err != nil { 24 | os.Exit(1) 25 | } 26 | } 27 | 28 | func init() { 29 | rootCmd.PersistentFlags().String("config", "etc/etc.yaml", "config file (default is project root dir etc/etc.yaml") 30 | } 31 | -------------------------------------------------------------------------------- /web/src/views/home/index.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /web/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import './plugins/assets'; 3 | import { 4 | setupAppVersionNotification, 5 | setupDayjs, 6 | setupIconifyOffline, 7 | setupLoading, 8 | setupNProgress, 9 | wakeBackend 10 | } from './plugins'; 11 | import { setupStore } from './store'; 12 | import { setupRouter } from './router'; 13 | import { setupI18n } from './locales'; 14 | import App from './App.vue'; 15 | 16 | async function setupApp() { 17 | // serverless 下先唤醒后端 18 | await wakeBackend(); 19 | 20 | setupLoading(); 21 | 22 | setupNProgress(); 23 | 24 | setupIconifyOffline(); 25 | 26 | setupDayjs(); 27 | 28 | const app = createApp(App); 29 | 30 | setupStore(app); 31 | 32 | await setupRouter(app); 33 | 34 | setupI18n(app); 35 | 36 | setupAppVersionNotification(); 37 | 38 | app.mount('#app'); 39 | } 40 | 41 | setupApp(); 42 | -------------------------------------------------------------------------------- /web/packages/axios/src/shared.ts: -------------------------------------------------------------------------------- 1 | import type { AxiosHeaderValue, AxiosResponse, InternalAxiosRequestConfig } from 'axios'; 2 | 3 | export function getContentType(config: InternalAxiosRequestConfig) { 4 | const contentType: AxiosHeaderValue = config.headers?.['Content-Type'] || 'application/json'; 5 | 6 | return contentType; 7 | } 8 | 9 | /** 10 | * check if http status is success 11 | * 12 | * @param status 13 | */ 14 | export function isHttpSuccess(status: number) { 15 | const isSuccessCode = status >= 200 && status < 300; 16 | return isSuccessCode || status === 304; 17 | } 18 | 19 | /** 20 | * is response json 21 | * 22 | * @param response axios response 23 | */ 24 | export function isResponseJson(response: AxiosResponse) { 25 | const { responseType } = response.config; 26 | 27 | return responseType === 'json' || responseType === undefined; 28 | } 29 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/cmd/root.go.tpl: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | // rootCmd represents the base command when called without any subcommands 10 | var rootCmd = &cobra.Command{ 11 | Use: "{{ .APP }}", 12 | Short: "{{ .APP }} root", 13 | Long: "{{ .APP }} root.", 14 | CompletionOptions: cobra.CompletionOptions{ 15 | DisableDefaultCmd: true, 16 | }, 17 | } 18 | 19 | // Execute adds all child commands to the root command and sets flags appropriately. 20 | // This is called by main.main(). It only needs to happen once to the rootCmd. 21 | func Execute() { 22 | err := rootCmd.Execute() 23 | if err != nil { 24 | os.Exit(1) 25 | } 26 | } 27 | 28 | func init() { 29 | rootCmd.PersistentFlags().String("config", "etc/etc.yaml", "config file (default is project root dir etc/etc.yaml") 30 | } -------------------------------------------------------------------------------- /server/internal/model/manage_menu/manage_menu_model.go: -------------------------------------------------------------------------------- 1 | package manage_menu 2 | 3 | import ( 4 | "github.com/eddieowens/opts" 5 | "github.com/jzero-io/jzero/core/stores/modelx" 6 | "github.com/zeromicro/go-zero/core/stores/sqlx" 7 | ) 8 | 9 | var _ ManageMenuModel = (*customManageMenuModel)(nil) 10 | 11 | type ( 12 | // ManageMenuModel is an interface to be customized, add more methods here, 13 | // and implement the added methods in customManageMenuModel. 14 | ManageMenuModel interface { 15 | manageMenuModel 16 | } 17 | 18 | customManageMenuModel struct { 19 | *defaultManageMenuModel 20 | } 21 | ) 22 | 23 | // NewManageMenuModel returns a model for the database table. 24 | func NewManageMenuModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) ManageMenuModel { 25 | return &customManageMenuModel{ 26 | defaultManageMenuModel: newManageMenuModel(conn, op...), 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /server/internal/model/manage_role/manage_role_model.go: -------------------------------------------------------------------------------- 1 | package manage_role 2 | 3 | import ( 4 | "github.com/eddieowens/opts" 5 | "github.com/jzero-io/jzero/core/stores/modelx" 6 | "github.com/zeromicro/go-zero/core/stores/sqlx" 7 | ) 8 | 9 | var _ ManageRoleModel = (*customManageRoleModel)(nil) 10 | 11 | type ( 12 | // ManageRoleModel is an interface to be customized, add more methods here, 13 | // and implement the added methods in customManageRoleModel. 14 | ManageRoleModel interface { 15 | manageRoleModel 16 | } 17 | 18 | customManageRoleModel struct { 19 | *defaultManageRoleModel 20 | } 21 | ) 22 | 23 | // NewManageRoleModel returns a model for the database table. 24 | func NewManageRoleModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) ManageRoleModel { 25 | return &customManageRoleModel{ 26 | defaultManageRoleModel: newManageRoleModel(conn, op...), 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /server/internal/model/manage_user/manage_user_model.go: -------------------------------------------------------------------------------- 1 | package manage_user 2 | 3 | import ( 4 | "github.com/eddieowens/opts" 5 | "github.com/jzero-io/jzero/core/stores/modelx" 6 | "github.com/zeromicro/go-zero/core/stores/sqlx" 7 | ) 8 | 9 | var _ ManageUserModel = (*customManageUserModel)(nil) 10 | 11 | type ( 12 | // ManageUserModel is an interface to be customized, add more methods here, 13 | // and implement the added methods in customManageUserModel. 14 | ManageUserModel interface { 15 | manageUserModel 16 | } 17 | 18 | customManageUserModel struct { 19 | *defaultManageUserModel 20 | } 21 | ) 22 | 23 | // NewManageUserModel returns a model for the database table. 24 | func NewManageUserModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) ManageUserModel { 25 | return &customManageUserModel{ 26 | defaultManageUserModel: newManageUserModel(conn, op...), 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/handler/version/version.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. Templates Edited by jzero. DO NOT EDIT. 2 | 3 | package version 4 | 5 | import ( 6 | "net/http" 7 | 8 | "github.com/zeromicro/go-zero/rest/httpx" 9 | 10 | "helloworld/internal/logic/version" 11 | "helloworld/internal/svc" 12 | types "helloworld/internal/types/version" 13 | ) 14 | 15 | func Version(svcCtx *svc.ServiceContext) http.HandlerFunc { 16 | return func(w http.ResponseWriter, r *http.Request) { 17 | var req types.VersionRequest 18 | if err := httpx.Parse(r, &req); err != nil { 19 | httpx.ErrorCtx(r.Context(), w, err) 20 | return 21 | } 22 | 23 | l := version.NewVersion(r.Context(), svcCtx, r) 24 | resp, err := l.Version(&req) 25 | if err != nil { 26 | httpx.ErrorCtx(r.Context(), w, err) 27 | } else { 28 | httpx.OkJsonCtx(r.Context(), w, resp) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /server/internal/logic/swagger/swagger.go: -------------------------------------------------------------------------------- 1 | package swagger 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/jzero-io/jzero/core/swaggerv2" 8 | "github.com/zeromicro/go-zero/core/logx" 9 | 10 | "github.com/jzero-io/jzero-admin/server/internal/svc" 11 | ) 12 | 13 | type Swagger struct { 14 | logx.Logger 15 | ctx context.Context 16 | svcCtx *svc.ServiceContext 17 | r *http.Request 18 | w http.ResponseWriter 19 | } 20 | 21 | func NewSwagger(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request, w http.ResponseWriter) *Swagger { 22 | return &Swagger{ 23 | Logger: logx.WithContext(ctx), 24 | ctx: ctx, 25 | svcCtx: svcCtx, 26 | r: r, 27 | w: w, 28 | } 29 | } 30 | 31 | func (l *Swagger) Swagger() error { 32 | opts := new(swaggerv2.Swaggerv2Opts).DefaultOptions() 33 | swaggerv2.SwaggerHandler(opts, l.w, l.r) 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /web/src/constants/reg.ts: -------------------------------------------------------------------------------- 1 | export const REG_USER_NAME = /^[\u4E00-\u9FA5a-zA-Z0-9_-]{4,16}$/; 2 | 3 | /** Phone reg */ 4 | export const REG_PHONE = 5 | /^[1](([3][0-9])|([4][01456789])|([5][012356789])|([6][2567])|([7][0-8])|([8][0-9])|([9][012356789]))[0-9]{8}$/; 6 | 7 | /** 8 | * Password reg 9 | * 10 | * 6-18 characters, including letters, numbers, and underscores 11 | */ 12 | export const REG_PWD = /^\w{6,18}$/; 13 | 14 | /** Email reg */ 15 | export const REG_EMAIL = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/; 16 | 17 | /** Six digit code reg */ 18 | export const REG_CODE_SIX = /^\d{6}$/; 19 | 20 | /** Four digit code reg */ 21 | export const REG_CODE_FOUR = /^\d{4}$/; 22 | 23 | /** Url reg */ 24 | export const REG_URL = 25 | /(((^https?:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)$/; 26 | -------------------------------------------------------------------------------- /web/src/layouts/modules/global-menu/modules/horizontal-menu.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /server/internal/model/manage_email/manage_email_model.go: -------------------------------------------------------------------------------- 1 | package manage_email 2 | 3 | import ( 4 | "github.com/eddieowens/opts" 5 | "github.com/jzero-io/jzero/core/stores/modelx" 6 | "github.com/zeromicro/go-zero/core/stores/sqlx" 7 | ) 8 | 9 | var _ ManageEmailModel = (*customManageEmailModel)(nil) 10 | 11 | type ( 12 | // ManageEmailModel is an interface to be customized, add more methods here, 13 | // and implement the added methods in customManageEmailModel. 14 | ManageEmailModel interface { 15 | manageEmailModel 16 | } 17 | 18 | customManageEmailModel struct { 19 | *defaultManageEmailModel 20 | } 21 | ) 22 | 23 | // NewManageEmailModel returns a model for the database table. 24 | func NewManageEmailModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) ManageEmailModel { 25 | return &customManageEmailModel{ 26 | defaultManageEmailModel: newManageEmailModel(conn, op...), 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /web/packages/scripts/src/types/index.ts: -------------------------------------------------------------------------------- 1 | import type { ChangelogOption } from '@soybeanjs/changelog'; 2 | 3 | export interface CliOption { 4 | /** The project root directory */ 5 | cwd: string; 6 | /** 7 | * Cleanup dirs 8 | * 9 | * Glob pattern syntax {@link https://github.com/isaacs/minimatch} 10 | * 11 | * @default 12 | * ```json 13 | * ["** /dist", "** /pnpm-lock.yaml", "** /node_modules", "!node_modules/**"] 14 | * ``` 15 | */ 16 | cleanupDirs: string[]; 17 | /** 18 | * Npm-check-updates command args 19 | * 20 | * @default ['--deep', '-u'] 21 | */ 22 | ncuCommandArgs: string[]; 23 | /** 24 | * Options of generate changelog 25 | * 26 | * @link https://github.com/soybeanjs/changelog 27 | */ 28 | changelogOptions: Partial; 29 | /** The ignore pattern list of git commit verify */ 30 | gitCommitVerifyIgnores: RegExp[]; 31 | } 32 | -------------------------------------------------------------------------------- /core-engine/svc/middleware.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/zeromicro/go-zero/rest" 8 | 9 | "github.com/jzero-io/jzero-admin/core-engine/middleware" 10 | ) 11 | 12 | type Middleware struct { 13 | Authx rest.Middleware 14 | Ok func(ctx context.Context, data any) any 15 | Error func(ctx context.Context, err error) (int, any) 16 | I18n rest.Middleware 17 | Validate *middleware.ValidatorMiddleware 18 | } 19 | 20 | func NewMiddleware(svcCtx *ServiceContext, route2code func(r *http.Request) string) Middleware { 21 | return Middleware{ 22 | Error: middleware.NewErrorMiddleware().Handle, 23 | Ok: middleware.NewOkMiddleware().Handle, 24 | Authx: middleware.NewAuthxMiddleware(svcCtx.CasbinEnforcer, route2code).Handle, 25 | I18n: middleware.NewI18nMiddleware().Handle, 26 | Validate: middleware.NewValidatorMiddleware(), 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /server/internal/handler/version/version.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. Templates Edited by jzero. DO NOT EDIT. 2 | 3 | package version 4 | 5 | import ( 6 | "net/http" 7 | 8 | "github.com/zeromicro/go-zero/rest/httpx" 9 | 10 | "github.com/jzero-io/jzero-admin/server/internal/logic/version" 11 | "github.com/jzero-io/jzero-admin/server/internal/svc" 12 | types "github.com/jzero-io/jzero-admin/server/internal/types/version" 13 | ) 14 | 15 | func Version(svcCtx *svc.ServiceContext) http.HandlerFunc { 16 | return func(w http.ResponseWriter, r *http.Request) { 17 | var req types.VersionRequest 18 | if err := httpx.Parse(r, &req); err != nil { 19 | httpx.ErrorCtx(r.Context(), w, err) 20 | return 21 | } 22 | 23 | l := version.NewVersion(r.Context(), svcCtx, r) 24 | resp, err := l.Version(&req) 25 | if err != nil { 26 | httpx.ErrorCtx(r.Context(), w, err) 27 | } else { 28 | httpx.OkJsonCtx(r.Context(), w, resp) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /server/internal/model/manage_role_menu/manage_role_menu_model.go: -------------------------------------------------------------------------------- 1 | package manage_role_menu 2 | 3 | import ( 4 | "github.com/eddieowens/opts" 5 | "github.com/jzero-io/jzero/core/stores/modelx" 6 | "github.com/zeromicro/go-zero/core/stores/sqlx" 7 | ) 8 | 9 | var _ ManageRoleMenuModel = (*customManageRoleMenuModel)(nil) 10 | 11 | type ( 12 | // ManageRoleMenuModel is an interface to be customized, add more methods here, 13 | // and implement the added methods in customManageRoleMenuModel. 14 | ManageRoleMenuModel interface { 15 | manageRoleMenuModel 16 | } 17 | 18 | customManageRoleMenuModel struct { 19 | *defaultManageRoleMenuModel 20 | } 21 | ) 22 | 23 | // NewManageRoleMenuModel returns a model for the database table. 24 | func NewManageRoleMenuModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) ManageRoleMenuModel { 25 | return &customManageRoleMenuModel{ 26 | defaultManageRoleMenuModel: newManageRoleMenuModel(conn, op...), 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /server/internal/model/manage_user_role/manage_user_role_model.go: -------------------------------------------------------------------------------- 1 | package manage_user_role 2 | 3 | import ( 4 | "github.com/eddieowens/opts" 5 | "github.com/jzero-io/jzero/core/stores/modelx" 6 | "github.com/zeromicro/go-zero/core/stores/sqlx" 7 | ) 8 | 9 | var _ ManageUserRoleModel = (*customManageUserRoleModel)(nil) 10 | 11 | type ( 12 | // ManageUserRoleModel is an interface to be customized, add more methods here, 13 | // and implement the added methods in customManageUserRoleModel. 14 | ManageUserRoleModel interface { 15 | manageUserRoleModel 16 | } 17 | 18 | customManageUserRoleModel struct { 19 | *defaultManageUserRoleModel 20 | } 21 | ) 22 | 23 | // NewManageUserRoleModel returns a model for the database table. 24 | func NewManageUserRoleModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) ManageUserRoleModel { 25 | return &customManageUserRoleModel{ 26 | defaultManageUserRoleModel: newManageUserRoleModel(conn, op...), 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /web/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue'; 2 | import { 3 | type RouterHistory, 4 | createMemoryHistory, 5 | createRouter, 6 | createWebHashHistory, 7 | createWebHistory 8 | } from 'vue-router'; 9 | import { createBuiltinVueRoutes } from './routes/builtin'; 10 | import { createRouterGuard } from './guard'; 11 | 12 | const { VITE_ROUTER_HISTORY_MODE = 'history', VITE_BASE_URL } = import.meta.env; 13 | 14 | const historyCreatorMap: Record RouterHistory> = { 15 | hash: createWebHashHistory, 16 | history: createWebHistory, 17 | memory: createMemoryHistory 18 | }; 19 | 20 | export const router = createRouter({ 21 | history: historyCreatorMap[VITE_ROUTER_HISTORY_MODE](VITE_BASE_URL), 22 | routes: createBuiltinVueRoutes() 23 | }); 24 | 25 | /** Setup Vue Router */ 26 | export async function setupRouter(app: App) { 27 | app.use(router); 28 | createRouterGuard(router); 29 | await router.isReady(); 30 | } 31 | -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/logic/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "os" 7 | "runtime" 8 | 9 | "github.com/zeromicro/go-zero/core/logx" 10 | 11 | "helloworld/internal/svc" 12 | types "helloworld/internal/types/version" 13 | ) 14 | 15 | type Version struct { 16 | logx.Logger 17 | ctx context.Context 18 | svcCtx *svc.ServiceContext 19 | r *http.Request 20 | } 21 | 22 | func NewVersion(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request) *Version { 23 | return &Version{ 24 | Logger: logx.WithContext(ctx), 25 | ctx: ctx, 26 | svcCtx: svcCtx, 27 | r: r, 28 | } 29 | } 30 | 31 | func (l *Version) Version(req *types.VersionRequest) (resp *types.VersionResponse, err error) { 32 | return &types.VersionResponse{ 33 | Version: os.Getenv("VERSION"), 34 | GoVersion: runtime.Version(), 35 | Commit: os.Getenv("COMMIT"), 36 | Date: os.Getenv("DATE"), 37 | }, nil 38 | } 39 | -------------------------------------------------------------------------------- /server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=$BUILDPLATFORM ghcr.io/jzero-io/jzero:latest AS builder 2 | 3 | ARG TARGETARCH 4 | ARG LDFLAGS 5 | 6 | ENV GOPROXY=https://goproxy.cn,direct 7 | 8 | WORKDIR /app 9 | 10 | COPY ./ ./ 11 | 12 | RUN jzero serverless build 13 | 14 | RUN --mount=type=cache,target=/go/pkg CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -a -ldflags="$LDFLAGS" -o /dist/app main.go \ 15 | && cp -r etc /dist \ 16 | && mkdir -p /dist/desc && cp -r desc/swagger /dist/desc && cp -r desc/sql_migration /dist/desc \ 17 | && for plugin in $(ls -d plugins/*/); do \ 18 | mkdir -p /dist/$plugin && cp -r $plugin/etc /dist/$plugin; \ 19 | [ -d $plugin/desc/sql_migration ] && mkdir -p /dist/$plugin/desc && cp -r $plugin/desc/sql_migration /dist/$plugin/desc || true; \ 20 | done 21 | 22 | FROM alpine:latest 23 | 24 | RUN apk add --no-cache tzdata 25 | 26 | WORKDIR /dist 27 | 28 | COPY --from=builder /dist . 29 | 30 | EXPOSE 8001 31 | 32 | CMD ["./app", "server"] -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/internal/logic/version/version.go.tpl: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "os" 7 | "runtime" 8 | 9 | "github.com/zeromicro/go-zero/core/logx" 10 | 11 | "{{.Module}}/internal/svc" 12 | types "{{.Module}}/internal/types/version" 13 | ) 14 | 15 | type Version struct { 16 | logx.Logger 17 | ctx context.Context 18 | svcCtx *svc.ServiceContext 19 | r *http.Request 20 | } 21 | 22 | func NewVersion(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request) *Version { 23 | return &Version{ 24 | Logger: logx.WithContext(ctx), 25 | ctx: ctx, 26 | svcCtx: svcCtx, 27 | r: r, 28 | } 29 | } 30 | 31 | func (l *Version) Version(req *types.VersionRequest) (resp *types.VersionResponse, err error) { 32 | return &types.VersionResponse{ 33 | Version: os.Getenv("VERSION"), 34 | GoVersion: runtime.Version(), 35 | Commit: os.Getenv("COMMIT"), 36 | Date: os.Getenv("DATE"), 37 | }, nil 38 | } -------------------------------------------------------------------------------- /server/internal/logic/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "os" 7 | "runtime" 8 | 9 | "github.com/zeromicro/go-zero/core/logx" 10 | 11 | "github.com/jzero-io/jzero-admin/server/internal/svc" 12 | types "github.com/jzero-io/jzero-admin/server/internal/types/version" 13 | ) 14 | 15 | type Version struct { 16 | logx.Logger 17 | ctx context.Context 18 | svcCtx *svc.ServiceContext 19 | r *http.Request 20 | } 21 | 22 | func NewVersion(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request) *Version { 23 | return &Version{ 24 | Logger: logx.WithContext(ctx), 25 | ctx: ctx, 26 | svcCtx: svcCtx, 27 | r: r, 28 | } 29 | } 30 | 31 | func (l *Version) Version(req *types.VersionRequest) (resp *types.VersionResponse, err error) { 32 | return &types.VersionResponse{ 33 | Version: os.Getenv("VERSION"), 34 | GoVersion: runtime.Version(), 35 | Commit: os.Getenv("COMMIT"), 36 | Date: os.Getenv("DATE"), 37 | }, nil 38 | } 39 | -------------------------------------------------------------------------------- /web/uno.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@unocss/vite'; 2 | import transformerDirectives from '@unocss/transformer-directives'; 3 | import transformerVariantGroup from '@unocss/transformer-variant-group'; 4 | import presetUno from '@unocss/preset-uno'; 5 | import type { Theme } from '@unocss/preset-uno'; 6 | import { presetSoybeanAdmin } from '@sa/uno-preset'; 7 | import { themeVars } from './src/theme/vars'; 8 | 9 | export default defineConfig({ 10 | content: { 11 | pipeline: { 12 | exclude: ['node_modules', 'dist'] 13 | } 14 | }, 15 | theme: { 16 | ...themeVars, 17 | fontSize: { 18 | 'icon-xs': '0.875rem', 19 | 'icon-small': '1rem', 20 | icon: '1.125rem', 21 | 'icon-large': '1.5rem', 22 | 'icon-xl': '2rem' 23 | } 24 | }, 25 | shortcuts: { 26 | 'card-wrapper': 'rd-8px shadow-sm' 27 | }, 28 | transformers: [transformerDirectives(), transformerVariantGroup()], 29 | presets: [presetUno({ dark: 'class' }), presetSoybeanAdmin()] 30 | }); 31 | -------------------------------------------------------------------------------- /web/src/router/routes/builtin.ts: -------------------------------------------------------------------------------- 1 | import type { CustomRoute } from '@elegant-router/types'; 2 | import { layouts, views } from '../elegant/imports'; 3 | import { getRoutePath, transformElegantRoutesToVueRoutes } from '../elegant/transform'; 4 | 5 | export const ROOT_ROUTE: CustomRoute = { 6 | name: 'root', 7 | path: '/', 8 | redirect: getRoutePath(import.meta.env.VITE_ROUTE_HOME) || '/home', 9 | meta: { 10 | title: 'root', 11 | constant: true 12 | } 13 | }; 14 | 15 | const NOT_FOUND_ROUTE: CustomRoute = { 16 | name: 'not-found', 17 | path: '/:pathMatch(.*)*', 18 | component: 'layout.blank$view.404', 19 | meta: { 20 | title: 'not-found', 21 | constant: true 22 | } 23 | }; 24 | 25 | /** builtin routes, it must be constant and setup in vue-router */ 26 | const builtinRoutes: CustomRoute[] = [ROOT_ROUTE, NOT_FOUND_ROUTE]; 27 | 28 | /** create builtin vue routes */ 29 | export function createBuiltinVueRoutes() { 30 | return transformElegantRoutesToVueRoutes(builtinRoutes, layouts, views); 31 | } 32 | -------------------------------------------------------------------------------- /server/plugins/helloworld/internal/svc/config.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/logx" 5 | 6 | "helloworld/internal/config" 7 | ) 8 | 9 | func (sc *ServiceContext) GetConfig() (config.Config, error) { 10 | return sc.ConfigCenter.GetConfig() 11 | } 12 | 13 | func (sc *ServiceContext) MustGetConfig() config.Config { 14 | c, err := sc.GetConfig() 15 | logx.Must(err) 16 | return c 17 | } 18 | 19 | func (sc *ServiceContext) SetConfigListener() { 20 | sc.ConfigCenter.AddListener(func() { 21 | v, err := sc.GetConfig() 22 | if err != nil { 23 | logx.Errorf("reload config error: %v", err) 24 | return 25 | } 26 | 27 | logx.Infof("reload config successfully") 28 | switch v.Log.Level { 29 | case "debug": 30 | logx.SetLevel(logx.DebugLevel) 31 | case "info": 32 | logx.SetLevel(logx.InfoLevel) 33 | case "error": 34 | logx.SetLevel(logx.ErrorLevel) 35 | case "severe": 36 | logx.SetLevel(logx.SevereLevel) 37 | } 38 | 39 | // add custom logic here 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /web/packages/materials/src/libs/page-tab/chrome-tab-bg.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /web/src/layouts/modules/theme-drawer/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /core-engine/svc/casbin.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | sqladapter "github.com/Blank-Xu/sql-adapter" 5 | "github.com/casbin/casbin/v2" 6 | casbinmodel "github.com/casbin/casbin/v2/model" 7 | "github.com/zeromicro/go-zero/core/logx" 8 | ) 9 | 10 | const CasbinModelConf = `[request_definition] 11 | r = sub, obj 12 | 13 | [policy_definition] 14 | p = sub, obj 15 | 16 | [policy_effect] 17 | e = some(where (p.eft == allow)) 18 | 19 | [matchers] 20 | m = r.sub == p.sub && r.obj == p.obj` 21 | 22 | func MustCasbinEnforcer(svcCtx *ServiceContext) *casbin.Enforcer { 23 | db, err := svcCtx.SqlxConn.RawDB() 24 | logx.Must(err) 25 | 26 | adapter, err := sqladapter.NewAdapter(db, svcCtx.Config.Sqlx.DriverName, "casbin_rule") 27 | logx.Must(err) 28 | 29 | casbinModel, err := casbinmodel.NewModelFromString(CasbinModelConf) 30 | logx.Must(err) 31 | 32 | casbinEnforcer, err := casbin.NewEnforcer(casbinModel, adapter) 33 | logx.Must(err) 34 | 35 | err = casbinEnforcer.LoadPolicy() 36 | logx.Must(err) 37 | 38 | return casbinEnforcer 39 | } 40 | -------------------------------------------------------------------------------- /server/internal/svc/config.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "github.com/jzero-io/jzero-admin/server/internal/config" 5 | "github.com/zeromicro/go-zero/core/logx" 6 | ) 7 | 8 | func (sc *ServiceContext) GetConfig() (config.Config, error) { 9 | return sc.ConfigCenter.GetConfig() 10 | } 11 | 12 | func (sc *ServiceContext) MustGetConfig() config.Config { 13 | c, err := sc.ConfigCenter.GetConfig() 14 | logx.Must(err) 15 | return c 16 | } 17 | 18 | func (sc *ServiceContext) SetConfigListener() { 19 | sc.ConfigCenter.AddListener(func() { 20 | v, err := sc.ConfigCenter.GetConfig() 21 | if err != nil { 22 | logx.Errorf("reload config error: %v", err) 23 | return 24 | } 25 | 26 | logx.Infof("reload config successfully") 27 | switch v.Log.Level { 28 | case "debug": 29 | logx.SetLevel(logx.DebugLevel) 30 | case "info": 31 | logx.SetLevel(logx.InfoLevel) 32 | case "error": 33 | logx.SetLevel(logx.ErrorLevel) 34 | case "severe": 35 | logx.SetLevel(logx.SevereLevel) 36 | } 37 | 38 | // add custom logic here 39 | }) 40 | } 41 | -------------------------------------------------------------------------------- /web/src/components/common/app-provider.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /server/internal/svc/service_context.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/jzero-io/jzero-admin/core-engine/svc" 7 | "github.com/jzero-io/jzero/core/configcenter" 8 | "github.com/jzero-io/jzero/core/stores/modelx" 9 | 10 | "github.com/jzero-io/jzero-admin/server/internal/config" 11 | "github.com/jzero-io/jzero-admin/server/internal/model" 12 | ) 13 | 14 | type ServiceContext struct { 15 | *svc.ServiceContext 16 | ConfigCenter configcenter.ConfigCenter[config.Config] 17 | Model model.Model 18 | Middleware 19 | } 20 | 21 | func NewServiceContext(cc configcenter.ConfigCenter[config.Config], route2code func(r *http.Request) string) *ServiceContext { 22 | svcCtx := &ServiceContext{ 23 | ConfigCenter: cc, 24 | } 25 | svcCtx.SetConfigListener() 26 | 27 | svcCtx.ServiceContext = svc.NewServiceContext(svcCtx.ConfigCenter.MustGetConfig().Config, route2code) 28 | svcCtx.Model = model.NewModel(svcCtx.SqlxConn, modelx.WithCachedConn(modelx.NewConnWithCache(svcCtx.SqlxConn, svcCtx.Cache))) 29 | svcCtx.Middleware = NewMiddleware(svcCtx) 30 | return svcCtx 31 | } 32 | -------------------------------------------------------------------------------- /web/packages/hooks/src/use-count-down.ts: -------------------------------------------------------------------------------- 1 | import { computed, onScopeDispose, ref } from 'vue'; 2 | import { useRafFn } from '@vueuse/core'; 3 | 4 | /** 5 | * count down 6 | * 7 | * @param seconds - count down seconds 8 | */ 9 | export default function useCountDown(seconds: number) { 10 | const FPS_PER_SECOND = 60; 11 | 12 | const fps = ref(0); 13 | 14 | const count = computed(() => Math.ceil(fps.value / FPS_PER_SECOND)); 15 | 16 | const isCounting = computed(() => fps.value > 0); 17 | 18 | const { pause, resume } = useRafFn( 19 | () => { 20 | if (fps.value > 0) { 21 | fps.value -= 1; 22 | } else { 23 | pause(); 24 | } 25 | }, 26 | { immediate: false } 27 | ); 28 | 29 | function start(updateSeconds: number = seconds) { 30 | fps.value = FPS_PER_SECOND * updateSeconds; 31 | resume(); 32 | } 33 | 34 | function stop() { 35 | fps.value = 0; 36 | pause(); 37 | } 38 | 39 | onScopeDispose(() => { 40 | pause(); 41 | }); 42 | 43 | return { 44 | count, 45 | isCounting, 46 | start, 47 | stop 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/internal/svc/config.go.tpl: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/logx" 5 | 6 | "{{ .Module }}/internal/config" 7 | ) 8 | 9 | func (sc *ServiceContext) GetConfig() (config.Config, error) { 10 | return sc.ConfigCenter.GetConfig() 11 | } 12 | 13 | func (sc *ServiceContext) MustGetConfig() config.Config { 14 | c, err := sc.GetConfig() 15 | logx.Must(err) 16 | return c 17 | } 18 | 19 | func (sc *ServiceContext) SetConfigListener() { 20 | sc.ConfigCenter.AddListener(func() { 21 | v, err := sc.GetConfig() 22 | if err != nil { 23 | logx.Errorf("reload config error: %v", err) 24 | return 25 | } 26 | 27 | logx.Infof("reload config successfully") 28 | switch v.Log.Level { 29 | case "debug": 30 | logx.SetLevel(logx.DebugLevel) 31 | case "info": 32 | logx.SetLevel(logx.InfoLevel) 33 | case "error": 34 | logx.SetLevel(logx.ErrorLevel) 35 | case "severe": 36 | logx.SetLevel(logx.SevereLevel) 37 | } 38 | 39 | // add custom logic here 40 | }) 41 | } -------------------------------------------------------------------------------- /web/build/config/proxy.ts: -------------------------------------------------------------------------------- 1 | import type { ProxyOptions } from 'vite'; 2 | import { createServiceConfig } from '../../src/utils/service'; 3 | 4 | /** 5 | * Set http proxy 6 | * 7 | * @param env - The current env 8 | * @param enable - If enable http proxy 9 | */ 10 | export function createViteProxy(env: Env.ImportMeta, enable: boolean) { 11 | const isEnableHttpProxy = enable && env.VITE_HTTP_PROXY === 'Y'; 12 | 13 | if (!isEnableHttpProxy) return undefined; 14 | 15 | const { baseURL, proxyPattern, other } = createServiceConfig(env); 16 | 17 | const proxy: Record = createProxyItem({ baseURL, proxyPattern }); 18 | 19 | other.forEach(item => { 20 | Object.assign(proxy, createProxyItem(item)); 21 | }); 22 | 23 | return proxy; 24 | } 25 | 26 | function createProxyItem(item: App.Service.ServiceConfigItem) { 27 | const proxy: Record = {}; 28 | 29 | proxy[item.proxyPattern] = { 30 | target: item.baseURL, 31 | changeOrigin: true, 32 | rewrite: path => path.replace(new RegExp(`^${item.proxyPattern}`), '') 33 | }; 34 | 35 | return proxy; 36 | } 37 | -------------------------------------------------------------------------------- /web/build/plugins/unocss.ts: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import path from 'node:path'; 3 | import unocss from '@unocss/vite'; 4 | import presetIcons from '@unocss/preset-icons'; 5 | import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders'; 6 | 7 | export function setupUnocss(viteEnv: Env.ImportMeta) { 8 | const { VITE_ICON_PREFIX, VITE_ICON_LOCAL_PREFIX } = viteEnv; 9 | 10 | const localIconPath = path.join(process.cwd(), 'src/assets/svg-icon'); 11 | 12 | /** The name of the local icon collection */ 13 | const collectionName = VITE_ICON_LOCAL_PREFIX.replace(`${VITE_ICON_PREFIX}-`, ''); 14 | 15 | return unocss({ 16 | presets: [ 17 | presetIcons({ 18 | prefix: `${VITE_ICON_PREFIX}-`, 19 | scale: 1, 20 | extraProperties: { 21 | display: 'inline-block' 22 | }, 23 | collections: { 24 | [collectionName]: FileSystemIconLoader(localIconPath, svg => 25 | svg.replace(/^ 2 | import { $t } from '@/locales'; 3 | 4 | defineOptions({ name: 'SearchFooter' }); 5 | 6 | 7 | 24 | 25 | 37 | -------------------------------------------------------------------------------- /web/src/typings/storage.d.ts: -------------------------------------------------------------------------------- 1 | /** The storage namespace */ 2 | declare namespace StorageType { 3 | interface Session { 4 | /** The theme color */ 5 | themeColor: string; 6 | // /** 7 | // * the theme settings 8 | // */ 9 | // themeSettings: App.Theme.ThemeSetting; 10 | } 11 | 12 | interface Local { 13 | /** The i18n language */ 14 | lang: App.I18n.LangType; 15 | /** The token */ 16 | token: string; 17 | /** Fixed sider with mix-menu */ 18 | mixSiderFixed: CommonType.YesOrNo; 19 | /** The refresh token */ 20 | refreshToken: string; 21 | /** The theme color */ 22 | themeColor: string; 23 | /** The theme settings */ 24 | themeSettings: App.Theme.ThemeSetting; 25 | /** 26 | * The override theme flags 27 | * 28 | * The value is the build time of the project 29 | */ 30 | overrideThemeFlag: string; 31 | /** The global tabs */ 32 | globalTabs: App.Global.Tab[]; 33 | /** The backup theme setting before is mobile */ 34 | backupThemeSettingBeforeIsMobile: { 35 | layout: UnionKey.ThemeLayoutMode; 36 | siderCollapse: boolean; 37 | }; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jzero-admin.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "server", 5 | "name": "server" 6 | }, 7 | { 8 | "path": "web", 9 | "name": "web" 10 | }, 11 | { 12 | "path": "deploy", 13 | "name": "deploy" 14 | }, 15 | { 16 | "path": ".", 17 | "name": "root" 18 | } 19 | ], 20 | "settings": { 21 | "go.toolsEnvVars": { 22 | "GOPROXY": "https://goproxy.cn,direct", 23 | "GONOPROXY": "none;" 24 | }, 25 | "i18n-ally.displayLanguage": "zh-cn", 26 | "i18n-ally.enabledParsers": ["ts"], 27 | "i18n-ally.enabledFrameworks": ["vue"], 28 | "i18n-ally.editor.preferEditor": true, 29 | "i18n-ally.keystyle": "nested", 30 | "i18n-ally.localesPaths": ["web/src/locales/langs"], 31 | }, 32 | "launch": { 33 | "version": "0.2.0", 34 | "configurations": [ 35 | { 36 | "type": "go", 37 | "request": "launch", 38 | "name": "server", 39 | "cwd": "${workspaceFolder:server}", 40 | "program": "${workspaceFolder:server}/", 41 | "args": ["server", "--env", "etc/.env.yaml"] 42 | }, 43 | 44 | ], 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /server/internal/logic/v1/manage/role/edit.go: -------------------------------------------------------------------------------- 1 | package role 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/samber/lo" 8 | "github.com/zeromicro/go-zero/core/logx" 9 | 10 | "github.com/jzero-io/jzero-admin/server/internal/svc" 11 | types "github.com/jzero-io/jzero-admin/server/internal/types/v1/manage/role" 12 | ) 13 | 14 | type Edit struct { 15 | logx.Logger 16 | ctx context.Context 17 | svcCtx *svc.ServiceContext 18 | r *http.Request 19 | } 20 | 21 | func NewEdit(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request) *Edit { 22 | return &Edit{ 23 | Logger: logx.WithContext(ctx), 24 | ctx: ctx, 25 | svcCtx: svcCtx, r: r, 26 | } 27 | } 28 | 29 | func (l *Edit) Edit(req *types.EditRequest) (resp *types.EditResponse, err error) { 30 | data, err := l.svcCtx.Model.ManageRole.FindOneByUuid(l.ctx, nil, req.Uuid) 31 | if err != nil { 32 | return nil, err 33 | } 34 | 35 | newData := lo.FromPtr(data) 36 | newData.Code = req.RoleCode 37 | newData.Name = req.RoleName 38 | newData.Desc = req.RoleDesc 39 | newData.Status = req.Status 40 | 41 | err = l.svcCtx.Model.ManageRole.Update(l.ctx, nil, lo.ToPtr(newData)) 42 | return 43 | } 44 | -------------------------------------------------------------------------------- /web/packages/color/src/shared/name.ts: -------------------------------------------------------------------------------- 1 | import { colorNames } from '../constant'; 2 | import { getHex, getHsl, getRgb } from './colord'; 3 | 4 | /** 5 | * Get color name 6 | * 7 | * @param color 8 | */ 9 | export function getColorName(color: string) { 10 | const hex = getHex(color); 11 | const rgb = getRgb(color); 12 | const hsl = getHsl(color); 13 | 14 | let ndf = 0; 15 | let ndf1 = 0; 16 | let ndf2 = 0; 17 | let cl = -1; 18 | let df = -1; 19 | 20 | let name = ''; 21 | 22 | colorNames.some((item, index) => { 23 | const [hexValue, colorName] = item; 24 | 25 | const match = hex === hexValue; 26 | 27 | if (match) { 28 | name = colorName; 29 | } else { 30 | const { r, g, b } = getRgb(hexValue); 31 | const { h, s, l } = getHsl(hexValue); 32 | 33 | ndf1 = (rgb.r - r) ** 2 + (rgb.g - g) ** 2 + (rgb.b - b) ** 2; 34 | ndf2 = (hsl.h - h) ** 2 + (hsl.s - s) ** 2 + (hsl.l - l) ** 2; 35 | 36 | ndf = ndf1 + ndf2 * 2; 37 | if (df < 0 || df > ndf) { 38 | df = ndf; 39 | cl = index; 40 | } 41 | } 42 | 43 | return match; 44 | }); 45 | 46 | name = colorNames[cl][1]; 47 | 48 | return name; 49 | } 50 | -------------------------------------------------------------------------------- /server/desc/swagger/swagger.swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "basePath": "/", 3 | "consumes": [ 4 | "application/json" 5 | ], 6 | "info": { 7 | "version": "1.0" 8 | }, 9 | "paths": { 10 | "/swagger": { 11 | "get": { 12 | "description": "接口权限编码:swagger:swagger", 13 | "operationId": "swaggerSwagger", 14 | "produces": [ 15 | "application/json" 16 | ], 17 | "responses": { 18 | "200": { 19 | "description": "", 20 | "schema": {} 21 | } 22 | }, 23 | "schemes": [ 24 | "https" 25 | ], 26 | "security": [ 27 | { 28 | "apiKey": [] 29 | } 30 | ], 31 | "summary": "Swagger", 32 | "tags": [ 33 | "swagger" 34 | ] 35 | } 36 | } 37 | }, 38 | "produces": [ 39 | "application/json" 40 | ], 41 | "schemes": [ 42 | "http", 43 | "https" 44 | ], 45 | "securityDefinitions": { 46 | "apiKey": { 47 | "description": "Enter Authorization", 48 | "in": "header", 49 | "name": "Authorization", 50 | "type": "apiKey" 51 | } 52 | }, 53 | "swagger": "2.0" 54 | } -------------------------------------------------------------------------------- /server/desc/swagger/v1/swagger.swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "basePath": "/", 3 | "consumes": [ 4 | "application/json" 5 | ], 6 | "info": { 7 | "version": "1.0" 8 | }, 9 | "paths": { 10 | "/swagger": { 11 | "get": { 12 | "description": "接口权限编码:swagger:swagger", 13 | "operationId": "swaggerSwagger", 14 | "produces": [ 15 | "application/json" 16 | ], 17 | "responses": { 18 | "200": { 19 | "description": "", 20 | "schema": {} 21 | } 22 | }, 23 | "schemes": [ 24 | "https" 25 | ], 26 | "security": [ 27 | { 28 | "apiKey": [] 29 | } 30 | ], 31 | "summary": "Swagger", 32 | "tags": [ 33 | "swagger" 34 | ] 35 | } 36 | } 37 | }, 38 | "produces": [ 39 | "application/json" 40 | ], 41 | "schemes": [ 42 | "http", 43 | "https" 44 | ], 45 | "securityDefinitions": { 46 | "apiKey": { 47 | "description": "Enter Authorization", 48 | "in": "header", 49 | "name": "Authorization", 50 | "type": "apiKey" 51 | } 52 | }, 53 | "swagger": "2.0" 54 | } -------------------------------------------------------------------------------- /server/internal/logic/v1/manage/role/get_all.go: -------------------------------------------------------------------------------- 1 | package role 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/zeromicro/go-zero/core/logx" 8 | 9 | "github.com/jzero-io/jzero-admin/server/internal/svc" 10 | types "github.com/jzero-io/jzero-admin/server/internal/types/v1/manage/role" 11 | ) 12 | 13 | type GetAll struct { 14 | logx.Logger 15 | ctx context.Context 16 | svcCtx *svc.ServiceContext 17 | r *http.Request 18 | } 19 | 20 | func NewGetAll(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request) *GetAll { 21 | return &GetAll{ 22 | Logger: logx.WithContext(ctx), 23 | ctx: ctx, 24 | svcCtx: svcCtx, r: r, 25 | } 26 | } 27 | 28 | func (l *GetAll) GetAll(req *types.GetAllRequest) (resp []types.GetAllResponse, err error) { 29 | roles, err := l.svcCtx.Model.ManageRole.FindByCondition(l.ctx, nil) 30 | if err != nil { 31 | return nil, err 32 | } 33 | var list []types.GetAllResponse 34 | 35 | for _, role := range roles { 36 | if role.Status == "1" { 37 | list = append(list, types.GetAllResponse{ 38 | Uuid: role.Uuid, 39 | RoleCode: role.Code, 40 | RoleName: role.Name, 41 | }) 42 | } 43 | } 44 | 45 | return list, nil 46 | } 47 | -------------------------------------------------------------------------------- /web/src/components/common/exception-base.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /web/packages/hooks/src/use-svg-icon-render.ts: -------------------------------------------------------------------------------- 1 | import { h } from 'vue'; 2 | import type { Component } from 'vue'; 3 | 4 | /** 5 | * Svg icon render hook 6 | * 7 | * @param SvgIcon Svg icon component 8 | */ 9 | export default function useSvgIconRender(SvgIcon: Component) { 10 | interface IconConfig { 11 | /** Iconify icon name */ 12 | icon?: string; 13 | /** Local icon name */ 14 | localIcon?: string; 15 | /** Icon color */ 16 | color?: string; 17 | /** Icon size */ 18 | fontSize?: number; 19 | } 20 | 21 | type IconStyle = Partial>; 22 | 23 | /** 24 | * Svg icon VNode 25 | * 26 | * @param config 27 | */ 28 | const SvgIconVNode = (config: IconConfig) => { 29 | const { color, fontSize, icon, localIcon } = config; 30 | 31 | const style: IconStyle = {}; 32 | 33 | if (color) { 34 | style.color = color; 35 | } 36 | if (fontSize) { 37 | style.fontSize = `${fontSize}px`; 38 | } 39 | 40 | if (!icon && !localIcon) { 41 | return undefined; 42 | } 43 | 44 | return () => h(SvgIcon, { icon, localIcon, style }); 45 | }; 46 | 47 | return { 48 | SvgIconVNode 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /web/src/constants/business.ts: -------------------------------------------------------------------------------- 1 | import { transformRecordToOption } from '@/utils/common'; 2 | 3 | export const enableStatusRecord: Record = { 4 | '1': 'page.manage.common.status.enable', 5 | '2': 'page.manage.common.status.disable' 6 | }; 7 | 8 | export const enableStatusOptions = transformRecordToOption(enableStatusRecord); 9 | 10 | export const userGenderRecord: Record = { 11 | '1': 'page.manage.user.gender.male', 12 | '2': 'page.manage.user.gender.female' 13 | }; 14 | 15 | export const userGenderOptions = transformRecordToOption(userGenderRecord); 16 | 17 | export const menuTypeRecord: Record = { 18 | '1': 'page.manage.menu.type.directory', 19 | '2': 'page.manage.menu.type.menu', 20 | '3': 'page.manage.menu.type.button' 21 | }; 22 | 23 | export const menuTypeOptions = transformRecordToOption(menuTypeRecord); 24 | 25 | export const menuIconTypeRecord: Record = { 26 | '1': 'page.manage.menu.iconType.iconify', 27 | '2': 'page.manage.menu.iconType.local' 28 | }; 29 | 30 | export const menuIconTypeOptions = transformRecordToOption(menuIconTypeRecord); 31 | -------------------------------------------------------------------------------- /server/desc/sql/manage_menu.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `manage_menu` ( 2 | `id` bigint NOT NULL AUTO_INCREMENT, 3 | `uuid` varchar(36) NOT NULL UNIQUE, 4 | `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 5 | `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 6 | `status` varchar(1) NOT NULL, 7 | `parent_uuid` varchar(36) NOT NULL, 8 | `menu_type` varchar(1) NOT NULL, 9 | `menu_name` varchar(50) NOT NULL, 10 | `hide_in_menu` tinyint(1) NOT NULL, 11 | `active_menu` varchar(50) NOT NULL, 12 | `order` bigint NOT NULL, 13 | `route_name` varchar(255) NOT NULL, 14 | `route_path` varchar(255) NOT NULL, 15 | `component` varchar(255) NOT NULL, 16 | `icon` varchar(255) NOT NULL, 17 | `icon_type` varchar(1) NOT NULL, 18 | `i18n_key` varchar(255) NOT NULL, 19 | `keep_alive` tinyint(1) NOT NULL, 20 | `href` longtext NOT NULL, 21 | `multi_tab` tinyint(1) NOT NULL, 22 | `fixed_index_in_tab` bigint NOT NULL, 23 | `query` longtext NOT NULL, 24 | `permissions` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 25 | `constant` tinyint(1) NOT NULL, 26 | `button_code` longtext NOT NULL, 27 | PRIMARY KEY (`id`) 28 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci -------------------------------------------------------------------------------- /web/packages/scripts/src/config/index.ts: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import { loadConfig } from 'c12'; 3 | import type { CliOption } from '../types'; 4 | 5 | const defaultOptions: CliOption = { 6 | cwd: process.cwd(), 7 | cleanupDirs: [ 8 | '**/dist', 9 | '**/package-lock.json', 10 | '**/yarn.lock', 11 | '**/pnpm-lock.yaml', 12 | '**/node_modules', 13 | '!node_modules/**' 14 | ], 15 | ncuCommandArgs: ['--deep', '-u'], 16 | changelogOptions: {}, 17 | gitCommitVerifyIgnores: [ 18 | /^((Merge pull request)|(Merge (.*?) into (.*?)|(Merge branch (.*?)))(?:\r?\n)*$)/m, 19 | /^(Merge tag (.*?))(?:\r?\n)*$/m, 20 | /^(R|r)evert (.*)/, 21 | /^(amend|fixup|squash)!/, 22 | /^(Merged (.*?)(in|into) (.*)|Merged PR (.*): (.*))/, 23 | /^Merge remote-tracking branch(\s*)(.*)/, 24 | /^Automatic merge(.*)/, 25 | /^Auto-merged (.*?) into (.*)/ 26 | ] 27 | }; 28 | 29 | export async function loadCliOptions(overrides?: Partial, cwd = process.cwd()) { 30 | const { config } = await loadConfig>({ 31 | name: 'soybean', 32 | defaults: defaultOptions, 33 | overrides, 34 | cwd, 35 | packageJson: true 36 | }); 37 | 38 | return config as CliOption; 39 | } 40 | -------------------------------------------------------------------------------- /web/src/components/common/lang-switch.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /web/src/components/advanced/table-column-setting.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /web/src/theme/vars.ts: -------------------------------------------------------------------------------- 1 | /** Create color palette vars */ 2 | function createColorPaletteVars() { 3 | const colors: App.Theme.ThemeColorKey[] = ['primary', 'info', 'success', 'warning', 'error']; 4 | const colorPaletteNumbers: App.Theme.ColorPaletteNumber[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]; 5 | 6 | const colorPaletteVar = {} as App.Theme.ThemePaletteColor; 7 | 8 | colors.forEach(color => { 9 | colorPaletteVar[color] = `rgb(var(--${color}-color))`; 10 | colorPaletteNumbers.forEach(number => { 11 | colorPaletteVar[`${color}-${number}`] = `rgb(var(--${color}-${number}-color))`; 12 | }); 13 | }); 14 | 15 | return colorPaletteVar; 16 | } 17 | 18 | const colorPaletteVars = createColorPaletteVars(); 19 | 20 | /** Theme vars */ 21 | export const themeVars: App.Theme.ThemeTokenCSSVars = { 22 | colors: { 23 | ...colorPaletteVars, 24 | nprogress: 'rgb(var(--nprogress-color))', 25 | container: 'rgb(var(--container-bg-color))', 26 | layout: 'rgb(var(--layout-bg-color))', 27 | inverted: 'rgb(var(--inverted-bg-color))', 28 | 'base-text': 'rgb(var(--base-text-color))' 29 | }, 30 | boxShadow: { 31 | header: 'var(--header-box-shadow)', 32 | sider: 'var(--sider-box-shadow)', 33 | tab: 'var(--tab-box-shadow)' 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /web/src/views/home/modules/header-banner.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /core-engine/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/logx" 5 | "github.com/zeromicro/go-zero/core/stores/redis" 6 | "github.com/zeromicro/go-zero/core/stores/sqlx" 7 | "github.com/zeromicro/go-zero/rest" 8 | 9 | "github.com/jzero-io/jzero-admin/core-engine/i18n" 10 | ) 11 | 12 | type Config struct { 13 | Rest RestConf 14 | Jwt JwtConf 15 | Log LogConf 16 | Banner BannerConf 17 | Sqlx SqlxConf 18 | Redis RedisConf `json:",optional"` 19 | I18n i18n.I18nConf `json:",optional"` 20 | } 21 | 22 | type RestConf struct { 23 | rest.RestConf 24 | } 25 | 26 | type JwtConf struct { 27 | AccessSecret string `json:",default=jzero-admin"` 28 | AccessExpire int `json:",default=7200"` 29 | RefreshExpire int `json:",default=86400"` 30 | } 31 | 32 | type LogConf struct { 33 | logx.LogConf 34 | } 35 | 36 | type BannerConf struct { 37 | Text string `json:",default=JZERO"` 38 | Color string `json:",default=green"` 39 | FontName string `json:",default=starwars,options=big|larry3d|starwars|standard"` 40 | } 41 | 42 | type SqlxConf struct { 43 | sqlx.SqlConf 44 | } 45 | 46 | type RedisConf struct { 47 | // MiniRedis only for testing 48 | MiniRedis bool `json:",default=false"` 49 | 50 | redis.RedisConf `json:",optional"` 51 | } 52 | -------------------------------------------------------------------------------- /web/src/components/custom/button-icon.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /web/packages/materials/src/libs/page-tab/shared.ts: -------------------------------------------------------------------------------- 1 | import { addColorAlpha, transformColorWithOpacity } from '@sa/color'; 2 | import type { PageTabCssVars, PageTabCssVarsProps } from '../../types'; 3 | 4 | /** The active color of the tab */ 5 | export const ACTIVE_COLOR = '#1890ff'; 6 | 7 | function createCssVars(props: PageTabCssVarsProps) { 8 | const cssVars: PageTabCssVars = { 9 | '--soy-primary-color': props.primaryColor, 10 | '--soy-primary-color1': props.primaryColor1, 11 | '--soy-primary-color2': props.primaryColor2, 12 | '--soy-primary-color-opacity1': props.primaryColorOpacity1, 13 | '--soy-primary-color-opacity2': props.primaryColorOpacity2, 14 | '--soy-primary-color-opacity3': props.primaryColorOpacity3 15 | }; 16 | 17 | return cssVars; 18 | } 19 | 20 | export function createTabCssVars(primaryColor: string) { 21 | const cssProps: PageTabCssVarsProps = { 22 | primaryColor, 23 | primaryColor1: transformColorWithOpacity(primaryColor, 0.1, '#ffffff'), 24 | primaryColor2: transformColorWithOpacity(primaryColor, 0.3, '#000000'), 25 | primaryColorOpacity1: addColorAlpha(primaryColor, 0.1), 26 | primaryColorOpacity2: addColorAlpha(primaryColor, 0.15), 27 | primaryColorOpacity3: addColorAlpha(primaryColor, 0.3) 28 | }; 29 | 30 | return createCssVars(cssProps); 31 | } 32 | -------------------------------------------------------------------------------- /web/packages/materials/src/libs/page-tab/button-tab.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /core-engine/middleware/response_middleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/golang-jwt/jwt/v4" 8 | "github.com/jzero-io/jzero/core/status" 9 | "github.com/pkg/errors" 10 | "github.com/zeromicro/go-zero/core/logx" 11 | ) 12 | 13 | type Body struct { 14 | Data any `json:"data"` 15 | Code int `json:"code"` 16 | Msg string `json:"msg"` 17 | } 18 | 19 | type OkMiddleware struct{} 20 | 21 | func NewOkMiddleware() *OkMiddleware { 22 | return &OkMiddleware{} 23 | } 24 | 25 | type ErrorMiddleware struct{} 26 | 27 | func NewErrorMiddleware() *ErrorMiddleware { 28 | return &ErrorMiddleware{} 29 | } 30 | 31 | func (e *ErrorMiddleware) Handle(ctx context.Context, err error) (int, any) { 32 | logx.WithContext(ctx).Errorf("request error: %v", err) 33 | 34 | if errors.Is(err, jwt.ErrTokenExpired) { 35 | return http.StatusOK, Body{ 36 | Data: nil, 37 | Code: 40101, 38 | Msg: "token expired to refresh token", 39 | } 40 | } 41 | 42 | fromError := status.FromError(err) 43 | return http.StatusOK, Body{ 44 | Data: nil, 45 | Code: int(fromError.Code()), 46 | Msg: fromError.Error(), 47 | } 48 | } 49 | 50 | func (o *OkMiddleware) Handle(_ context.Context, data any) any { 51 | return Body{ 52 | Data: data, 53 | Code: http.StatusOK, 54 | Msg: "success", 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /web/src/utils/common.ts: -------------------------------------------------------------------------------- 1 | import { $t } from '@/locales'; 2 | 3 | /** 4 | * Transform record to option 5 | * 6 | * @example 7 | * ```ts 8 | * const record = { 9 | * key1: 'label1', 10 | * key2: 'label2' 11 | * }; 12 | * const options = transformRecordToOption(record); 13 | * // [ 14 | * // { value: 'key1', label: 'label1' }, 15 | * // { value: 'key2', label: 'label2' } 16 | * // ] 17 | * ```; 18 | * 19 | * @param record 20 | */ 21 | export function transformRecordToOption>(record: T) { 22 | return Object.entries(record).map(([value, label]) => ({ 23 | value, 24 | label 25 | })) as CommonType.Option[]; 26 | } 27 | 28 | /** 29 | * Translate options 30 | * 31 | * @param options 32 | */ 33 | export function translateOptions(options: CommonType.Option[]) { 34 | return options.map(option => ({ 35 | ...option, 36 | label: $t(option.label as App.I18n.I18nKey) 37 | })); 38 | } 39 | 40 | /** 41 | * Toggle html class 42 | * 43 | * @param className 44 | */ 45 | export function toggleHtmlClass(className: string) { 46 | function add() { 47 | document.documentElement.classList.add(className); 48 | } 49 | 50 | function remove() { 51 | document.documentElement.classList.remove(className); 52 | } 53 | 54 | return { 55 | add, 56 | remove 57 | }; 58 | } 59 | -------------------------------------------------------------------------------- /server/internal/logic/v1/manage/role/get_menus.go: -------------------------------------------------------------------------------- 1 | package role 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/jzero-io/jzero/core/stores/condition" 8 | "github.com/zeromicro/go-zero/core/logx" 9 | 10 | "github.com/jzero-io/jzero-admin/server/internal/model/manage_role_menu" 11 | "github.com/jzero-io/jzero-admin/server/internal/svc" 12 | types "github.com/jzero-io/jzero-admin/server/internal/types/v1/manage/role" 13 | ) 14 | 15 | type GetMenus struct { 16 | logx.Logger 17 | ctx context.Context 18 | svcCtx *svc.ServiceContext 19 | r *http.Request 20 | } 21 | 22 | func NewGetMenus(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request) *GetMenus { 23 | return &GetMenus{ 24 | Logger: logx.WithContext(ctx), 25 | ctx: ctx, 26 | svcCtx: svcCtx, r: r, 27 | } 28 | } 29 | 30 | func (l *GetMenus) GetMenus(req *types.GetMenusRequest) (resp *types.GetMenusResponse, err error) { 31 | menus, err := l.svcCtx.Model.ManageRoleMenu.FindByCondition(l.ctx, nil, condition.Condition{ 32 | Field: manage_role_menu.RoleUuid, 33 | Operator: condition.Equal, 34 | Value: req.RoleUuid, 35 | }) 36 | if err != nil { 37 | return 38 | } 39 | 40 | var menuUuids []string 41 | for _, menu := range menus { 42 | menuUuids = append(menuUuids, menu.MenuUuid) 43 | } 44 | resp = &types.GetMenusResponse{MenuUuids: menuUuids} 45 | 46 | return 47 | } 48 | -------------------------------------------------------------------------------- /web/src/layouts/modules/global-sider/index.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /server/internal/logic/v1/manage/role/get_home.go: -------------------------------------------------------------------------------- 1 | package role 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/jzero-io/jzero/core/stores/condition" 8 | "github.com/spf13/cast" 9 | "github.com/zeromicro/go-zero/core/logx" 10 | 11 | "github.com/jzero-io/jzero-admin/server/internal/model/manage_role_menu" 12 | "github.com/jzero-io/jzero-admin/server/internal/svc" 13 | types "github.com/jzero-io/jzero-admin/server/internal/types/v1/manage/role" 14 | ) 15 | 16 | type GetHome struct { 17 | logx.Logger 18 | ctx context.Context 19 | svcCtx *svc.ServiceContext 20 | r *http.Request 21 | } 22 | 23 | func NewGetHome(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request) *GetHome { 24 | return &GetHome{ 25 | Logger: logx.WithContext(ctx), 26 | ctx: ctx, 27 | svcCtx: svcCtx, r: r, 28 | } 29 | } 30 | 31 | func (l *GetHome) GetHome(req *types.GetHomeRequest) (resp string, err error) { 32 | roleHomeMenu, err := l.svcCtx.Model.ManageRoleMenu.FindOneByCondition(l.ctx, nil, condition.NewChain(). 33 | Equal(manage_role_menu.RoleUuid, req.RoleUuid). 34 | Equal(manage_role_menu.IsHome, cast.ToInt(true)). 35 | Build()...) 36 | if err != nil { 37 | return "", err 38 | } 39 | one, err := l.svcCtx.Model.ManageMenu.FindOneByUuid(l.ctx, nil, roleHomeMenu.MenuUuid) 40 | if err != nil { 41 | return "", err 42 | } 43 | return one.RouteName, nil 44 | } 45 | -------------------------------------------------------------------------------- /web/src/components/common/menu-toggler.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /web/packages/materials/src/libs/admin-layout/index.module.css: -------------------------------------------------------------------------------- 1 | /* @type */ 2 | 3 | .layout-header, 4 | .layout-header-placement { 5 | height: var(--soy-header-height); 6 | } 7 | 8 | .layout-header { 9 | z-index: var(--soy-header-z-index); 10 | } 11 | 12 | .layout-tab { 13 | top: var(--soy-header-height); 14 | height: var(--soy-tab-height); 15 | z-index: var(--soy-tab-z-index); 16 | } 17 | 18 | .layout-tab-placement { 19 | height: var(--soy-tab-height); 20 | } 21 | 22 | .layout-sider { 23 | width: var(--soy-sider-width); 24 | z-index: var(--soy-sider-z-index); 25 | } 26 | 27 | .layout-mobile-sider { 28 | z-index: var(--soy-sider-z-index); 29 | } 30 | 31 | .layout-mobile-sider-mask { 32 | z-index: var(--soy-mobile-sider-z-index); 33 | } 34 | 35 | .layout-sider_collapsed { 36 | width: var(--soy-sider-collapsed-width); 37 | z-index: var(--soy-sider-z-index); 38 | } 39 | 40 | .layout-footer, 41 | .layout-footer-placement { 42 | height: var(--soy-footer-height); 43 | } 44 | 45 | .layout-footer { 46 | z-index: var(--soy-footer-z-index); 47 | } 48 | 49 | .left-gap { 50 | padding-left: var(--soy-sider-width); 51 | } 52 | 53 | .left-gap_collapsed { 54 | padding-left: var(--soy-sider-collapsed-width); 55 | } 56 | 57 | .sider-padding-top { 58 | padding-top: var(--soy-header-height); 59 | } 60 | 61 | .sider-padding-bottom { 62 | padding-bottom: var(--soy-footer-height); 63 | } 64 | -------------------------------------------------------------------------------- /web/src/layouts/modules/global-menu/index.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /web/src/plugins/loading.ts: -------------------------------------------------------------------------------- 1 | // @unocss-include 2 | import { getRgb } from '@sa/color'; 3 | import { $t } from '@/locales'; 4 | import { localStg } from '@/utils/storage'; 5 | import systemLogo from '@/assets/svg-icon/logo.svg?raw'; 6 | 7 | export function setupLoading() { 8 | const themeColor = localStg.get('themeColor') || '#646cff'; 9 | 10 | const { r, g, b } = getRgb(themeColor); 11 | 12 | const primaryColor = `--primary-color: ${r} ${g} ${b}`; 13 | 14 | const loadingClasses = [ 15 | 'left-0 top-0', 16 | 'left-0 bottom-0 animate-delay-500', 17 | 'right-0 top-0 animate-delay-1000', 18 | 'right-0 bottom-0 animate-delay-1500' 19 | ]; 20 | 21 | const logoWithClass = systemLogo.replace(' { 25 | return `
`; 26 | }) 27 | .join('\n'); 28 | 29 | const loading = ` 30 |
31 | ${logoWithClass} 32 |
33 |
34 | ${dot} 35 |
36 |
37 |

${$t('system.title')}

38 |
`; 39 | 40 | const app = document.getElementById('app'); 41 | 42 | if (app) { 43 | app.innerHTML = loading; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /web/src/components/common/theme-schema-switch.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /server/cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "runtime" 8 | "time" 9 | 10 | "github.com/spf13/cast" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var ( 15 | Version string 16 | Commit string 17 | Date string 18 | ) 19 | 20 | // versionCmd represents the version command 21 | var versionCmd = &cobra.Command{ 22 | Use: "version", 23 | Short: "server version", 24 | Long: `server version`, 25 | Run: func(cmd *cobra.Command, args []string) { 26 | printVersion() 27 | }, 28 | } 29 | 30 | func printVersion() { 31 | var versionBuffer bytes.Buffer 32 | 33 | if Version == "" { 34 | Version = "unknown" 35 | } 36 | versionBuffer.WriteString(fmt.Sprintf("jzero-admin-server version %s %s/%s\n", Version, runtime.GOOS, runtime.GOARCH)) 37 | 38 | versionBuffer.WriteString(fmt.Sprintf("Go version %s\n", runtime.Version())) 39 | 40 | if Commit == "" { 41 | Commit = "unknown" 42 | } 43 | versionBuffer.WriteString(fmt.Sprintf("Git commit %s\n", Commit)) 44 | 45 | if Date != "" { 46 | Date = cast.ToString(cast.ToTimeInDefaultLocation(Date, time.Local)) 47 | } else { 48 | Date = "unknown" 49 | } 50 | versionBuffer.WriteString(fmt.Sprintf("Build date: %s\n", Date)) 51 | 52 | fmt.Print(versionBuffer.String()) 53 | } 54 | 55 | func init() { 56 | _ = os.Setenv("VERSION", Version) 57 | _ = os.Setenv("COMMIT", Commit) 58 | _ = os.Setenv("DATE", Date) 59 | 60 | rootCmd.AddCommand(versionCmd) 61 | } 62 | -------------------------------------------------------------------------------- /server/plugins/helloworld/cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "runtime" 8 | "time" 9 | 10 | "github.com/spf13/cast" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var ( 15 | Version string 16 | Commit string 17 | Date string 18 | ) 19 | 20 | // versionCmd represents the version command 21 | var versionCmd = &cobra.Command{ 22 | Use: "version", 23 | Short: "helloworld version", 24 | Long: `helloworld version`, 25 | Run: func(cmd *cobra.Command, args []string) { 26 | printVersion() 27 | }, 28 | } 29 | 30 | func printVersion() { 31 | var versionBuffer bytes.Buffer 32 | 33 | if Version == "" { 34 | Version = "unknown" 35 | } 36 | versionBuffer.WriteString(fmt.Sprintf("helloworld version %s %s/%s\n", Version, runtime.GOOS, runtime.GOARCH)) 37 | 38 | versionBuffer.WriteString(fmt.Sprintf("Go version %s\n", runtime.Version())) 39 | 40 | if Commit == "" { 41 | Commit = "unknown" 42 | } 43 | versionBuffer.WriteString(fmt.Sprintf("Git commit %s\n", Commit)) 44 | 45 | if Date != "" { 46 | Date = cast.ToString(cast.ToTimeInDefaultLocation(Date, time.Local)) 47 | } else { 48 | Date = "unknown" 49 | } 50 | versionBuffer.WriteString(fmt.Sprintf("Build date: %s\n", Date)) 51 | 52 | fmt.Print(versionBuffer.String()) 53 | } 54 | 55 | func init() { 56 | _ = os.Setenv("VERSION", Version) 57 | _ = os.Setenv("COMMIT", Commit) 58 | _ = os.Setenv("DATE", Date) 59 | 60 | rootCmd.AddCommand(versionCmd) 61 | } 62 | -------------------------------------------------------------------------------- /web/src/router/elegant/imports.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /* prettier-ignore */ 3 | // Generated by elegant-router 4 | // Read more: https://github.com/soybeanjs/elegant-router 5 | 6 | import type { RouteComponent } from "vue-router"; 7 | import type { LastLevelRouteKey, RouteLayout } from "@elegant-router/types"; 8 | 9 | import BaseLayout from "@/layouts/base-layout/index.vue"; 10 | import BlankLayout from "@/layouts/blank-layout/index.vue"; 11 | 12 | export const layouts: Record Promise)> = { 13 | base: BaseLayout, 14 | blank: BlankLayout, 15 | }; 16 | 17 | export const views: Record Promise)> = { 18 | 403: () => import("@/views/_builtin/403/index.vue"), 19 | 404: () => import("@/views/_builtin/404/index.vue"), 20 | 500: () => import("@/views/_builtin/500/index.vue"), 21 | "iframe-page": () => import("@/views/_builtin/iframe-page/[url].vue"), 22 | login: () => import("@/views/_builtin/login/index.vue"), 23 | about: () => import("@/views/about/index.vue"), 24 | home: () => import("@/views/home/index.vue"), 25 | manage_menu: () => import("@/views/manage/menu/index.vue"), 26 | manage_role: () => import("@/views/manage/role/index.vue"), 27 | "manage_user-detail": () => import("@/views/manage/user-detail/[uuid].vue"), 28 | manage_user: () => import("@/views/manage/user/index.vue"), 29 | "user-center": () => import("@/views/user-center/index.vue"), 30 | }; 31 | -------------------------------------------------------------------------------- /web/src/typings/api/common/common.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-empty-interface */ 2 | declare namespace Api { 3 | namespace Common { 4 | /** common params of paginating */ 5 | interface PaginatingCommonParams { 6 | /** current page number */ 7 | current: number; 8 | /** page size */ 9 | size: number; 10 | /** total count */ 11 | total: number; 12 | } 13 | 14 | /** common params of paginating query list data */ 15 | interface PaginatingQueryRecord extends PaginatingCommonParams { 16 | records: T[]; 17 | } 18 | 19 | /** common search params of table */ 20 | type CommonSearchParams = Pick; 21 | 22 | /** 23 | * enable status 24 | * 25 | * - "1": enabled 26 | * - "2": disabled 27 | */ 28 | type EnableStatus = '1' | '2'; 29 | 30 | /** common record */ 31 | type CommonRecord = { 32 | /** record uuid */ 33 | uuid: string; 34 | /** record creator */ 35 | createBy: string; 36 | /** record create time */ 37 | createTime: string; 38 | /** record updater */ 39 | updateBy: string; 40 | /** record update time */ 41 | updateTime: string; 42 | /** record status */ 43 | status: EnableStatus | null; 44 | } & T; 45 | 46 | // eslint-disable-next-line @typescript-eslint/no-empty-object-type 47 | interface Empty {} 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /web/src/views/home/modules/project-news.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /web/packages/axios/src/options.ts: -------------------------------------------------------------------------------- 1 | import type { CreateAxiosDefaults } from 'axios'; 2 | import type { IAxiosRetryConfig } from 'axios-retry'; 3 | import { stringify } from 'qs'; 4 | import { isHttpSuccess } from './shared'; 5 | import type { RequestOption } from './type'; 6 | 7 | export function createDefaultOptions(options?: Partial>) { 8 | const opts: RequestOption = { 9 | onRequest: async config => config, 10 | isBackendSuccess: _response => true, 11 | onBackendFail: async () => {}, 12 | transformBackendResponse: async response => response.data, 13 | onError: async () => {} 14 | }; 15 | 16 | Object.assign(opts, options); 17 | 18 | return opts; 19 | } 20 | 21 | export function createRetryOptions(config?: Partial) { 22 | const retryConfig: IAxiosRetryConfig = { 23 | retries: 0 24 | }; 25 | 26 | Object.assign(retryConfig, config); 27 | 28 | return retryConfig; 29 | } 30 | 31 | export function createAxiosConfig(config?: Partial) { 32 | const TEN_SECONDS = 10 * 1000; 33 | 34 | const axiosConfig: CreateAxiosDefaults = { 35 | timeout: TEN_SECONDS, 36 | headers: { 37 | 'Content-Type': 'application/json' 38 | }, 39 | validateStatus: isHttpSuccess, 40 | paramsSerializer: params => { 41 | return stringify(params); 42 | } 43 | }; 44 | 45 | Object.assign(axiosConfig, config); 46 | 47 | return axiosConfig; 48 | } 49 | -------------------------------------------------------------------------------- /web/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /server/.template/jzero-admin-plugin/app/cmd/version.go.tpl: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "runtime" 8 | "time" 9 | 10 | "github.com/spf13/cast" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var ( 15 | Version string 16 | Commit string 17 | Date string 18 | ) 19 | 20 | // versionCmd represents the version command 21 | var versionCmd = &cobra.Command{ 22 | Use: "version", 23 | Short: "{{ .APP }} version", 24 | Long: `{{ .APP }} version`, 25 | Run: func(cmd *cobra.Command, args []string) { 26 | printVersion() 27 | }, 28 | } 29 | 30 | func printVersion() { 31 | var versionBuffer bytes.Buffer 32 | 33 | if Version == "" { 34 | Version = "unknown" 35 | } 36 | versionBuffer.WriteString(fmt.Sprintf("{{ .APP }} version %s %s/%s\n", Version, runtime.GOOS, runtime.GOARCH)) 37 | 38 | versionBuffer.WriteString(fmt.Sprintf("Go version %s\n", runtime.Version())) 39 | 40 | if Commit == "" { 41 | Commit = "unknown" 42 | } 43 | versionBuffer.WriteString(fmt.Sprintf("Git commit %s\n", Commit)) 44 | 45 | if Date != "" { 46 | Date = cast.ToString(cast.ToTimeInDefaultLocation(Date, time.Local)) 47 | } else { 48 | Date = "unknown" 49 | } 50 | versionBuffer.WriteString(fmt.Sprintf("Build date: %s\n", Date)) 51 | 52 | fmt.Print(versionBuffer.String()) 53 | } 54 | 55 | func init() { 56 | _ = os.Setenv("VERSION", Version) 57 | _ = os.Setenv("COMMIT", Commit) 58 | _ = os.Setenv("DATE", Date) 59 | 60 | rootCmd.AddCommand(versionCmd) 61 | } 62 | -------------------------------------------------------------------------------- /web/src/assets/svg-icon/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/src/typings/api/auth/auth.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-empty-interface */ 2 | declare namespace Api { 3 | /** 4 | * namespace Auth 5 | * 6 | * backend api module: "auth" 7 | */ 8 | namespace Auth { 9 | interface LoginResponse { 10 | token: string; 11 | refreshToken: string; 12 | } 13 | 14 | interface GetUserInfoResponse { 15 | userUuid: string; 16 | username: string; 17 | roles: string[]; 18 | buttons: string[]; 19 | } 20 | 21 | interface CodeLoginRequest { 22 | email: string; 23 | verificationCode: string; 24 | verificationUuid: string; 25 | } 26 | 27 | interface RegisterRequest { 28 | email: string; 29 | verificationCode: string; 30 | verificationUuid: string; 31 | username: string; 32 | password: string; 33 | } 34 | 35 | // eslint-disable-next-line @typescript-eslint/no-empty-object-type 36 | interface RegisterResponse {} 37 | 38 | interface SendVerificationCodeRequest { 39 | verificationType: string; 40 | email: string; 41 | } 42 | 43 | interface SendVerificationCodeResponse { 44 | verificationUuid: string; 45 | } 46 | 47 | interface ResetPasswordRequest { 48 | email: string; 49 | verificationUuid: string; 50 | verificationCode: string; 51 | password: string; 52 | } 53 | 54 | // eslint-disable-next-line @typescript-eslint/no-empty-object-type 55 | interface ResetPasswordResponse {} 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /.github/workflows/server.yaml: -------------------------------------------------------------------------------- 1 | name: server 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - 'server/**' 9 | - '.github/workflows/server.yaml' 10 | 11 | permissions: 12 | contents: write 13 | 14 | jobs: 15 | ci: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 22 | 23 | - uses: actions/setup-go@v5 24 | with: 25 | go-version: '1.22.3' 26 | 27 | - name: Download tools 28 | run: |- 29 | go install github.com/jzero-io/gorename@latest 30 | go install github.com/jaronnie/grum@latest 31 | 32 | - name: Upload to jaronnie/jzero-admin-deploy-server 33 | run: | 34 | cd server 35 | gorename github.com/jzero-io/jzero-admin/server/internal github.com/jzero-io/jzero-admin/server/server 36 | cd .. 37 | 38 | GITHUB_TOKEN=${{ secrets.ACCESS_TOKEN }} grum clone https://github.com/jaronnie/jzero-admin-deploy-server 39 | cd jzero-admin-deploy-server 40 | git config user.name "dependabot[bot]" 41 | git config user.email "49699333+dependabot[bot]@users.noreply.github.com" 42 | find . -type f -mindepth 1 ! -path "./api/*" ! -path "./vercel.json" ! -path "./.git/*" ! -path "./s.yaml" -exec rm -rf {} + 43 | cp -r ../server/. . 44 | git add . 45 | git diff-index --quiet HEAD || git commit -m "feat(server): update" 46 | git push -f 47 | -------------------------------------------------------------------------------- /deploy/docker-compose/mysql/config/my.conf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; version 2 of the License. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | 16 | # 17 | # The MySQL Server configuration file. 18 | # 19 | # For explanations see 20 | # http://dev.mysql.com/doc/mysql/en/server-system-variables.html 21 | 22 | [mysqld] 23 | character_set_server=utf8 24 | init_connect='SET NAMES utf8' 25 | 26 | pid-file = /var/run/mysqld/mysqld.pid 27 | socket = /var/run/mysqld/mysqld.sock 28 | datadir = /var/lib/mysql 29 | secure-file-priv= NULL 30 | # Disabling symbolic-links is recommended to prevent assorted security risks 31 | symbolic-links=0 32 | lower_case_table_names=1 33 | 34 | [mysql] 35 | default-character-set = utf8 36 | 37 | [mysql.server] 38 | default-character-set = utf8 39 | 40 | [mysqld_safe] 41 | default-character-set = utf8 42 | 43 | [client] 44 | default-character-set = utf8 -------------------------------------------------------------------------------- /server/internal/model/model.go: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package model 4 | 5 | import ( 6 | "github.com/eddieowens/opts" 7 | "github.com/jzero-io/jzero/core/stores/modelx" 8 | "github.com/zeromicro/go-zero/core/stores/sqlx" 9 | 10 | "github.com/jzero-io/jzero-admin/server/internal/model/manage_email" 11 | "github.com/jzero-io/jzero-admin/server/internal/model/manage_menu" 12 | "github.com/jzero-io/jzero-admin/server/internal/model/manage_role" 13 | "github.com/jzero-io/jzero-admin/server/internal/model/manage_role_menu" 14 | "github.com/jzero-io/jzero-admin/server/internal/model/manage_user" 15 | "github.com/jzero-io/jzero-admin/server/internal/model/manage_user_role" 16 | ) 17 | 18 | type Model struct { 19 | ManageEmail manage_email.ManageEmailModel 20 | ManageMenu manage_menu.ManageMenuModel 21 | ManageRole manage_role.ManageRoleModel 22 | ManageRoleMenu manage_role_menu.ManageRoleMenuModel 23 | ManageUser manage_user.ManageUserModel 24 | ManageUserRole manage_user_role.ManageUserRoleModel 25 | } 26 | 27 | func NewModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) Model { 28 | return Model{ 29 | ManageEmail: manage_email.NewManageEmailModel(conn, op...), 30 | ManageMenu: manage_menu.NewManageMenuModel(conn, op...), 31 | ManageRole: manage_role.NewManageRoleModel(conn, op...), 32 | ManageRoleMenu: manage_role_menu.NewManageRoleMenuModel(conn, op...), 33 | ManageUser: manage_user.NewManageUserModel(conn, op...), 34 | ManageUserRole: manage_user_role.NewManageUserRoleModel(conn, op...), 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /server/internal/logic/v1/manage/user/delete.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/jzero-io/jzero/core/stores/condition" 8 | "github.com/zeromicro/go-zero/core/logx" 9 | "github.com/zeromicro/go-zero/core/stores/sqlx" 10 | 11 | "github.com/jzero-io/jzero-admin/server/internal/model/manage_user" 12 | "github.com/jzero-io/jzero-admin/server/internal/svc" 13 | types "github.com/jzero-io/jzero-admin/server/internal/types/v1/manage/user" 14 | ) 15 | 16 | type Delete struct { 17 | logx.Logger 18 | ctx context.Context 19 | svcCtx *svc.ServiceContext 20 | r *http.Request 21 | } 22 | 23 | func NewDelete(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request) *Delete { 24 | return &Delete{ 25 | Logger: logx.WithContext(ctx), 26 | ctx: ctx, 27 | svcCtx: svcCtx, r: r, 28 | } 29 | } 30 | 31 | func (l *Delete) Delete(req *types.DeleteRequest) (resp *types.DeleteResponse, err error) { 32 | if len(req.Uuids) == 0 { 33 | return nil, nil 34 | } 35 | 36 | err = l.svcCtx.SqlxConn.TransactCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error { 37 | if err = l.svcCtx.Model.ManageUser.DeleteByCondition(l.ctx, session, condition.Condition{ 38 | Field: manage_user.Uuid, 39 | Operator: condition.In, 40 | Value: req.Uuids, 41 | }); err != nil { 42 | return err 43 | } 44 | if err = l.svcCtx.Model.ManageUserRole.DeleteByCondition(l.ctx, session, condition.NewChain().In("user_uuid", req.Uuids).Build()...); err != nil { 45 | return err 46 | } 47 | return nil 48 | }) 49 | 50 | return 51 | } 52 | -------------------------------------------------------------------------------- /web/src/components/custom/svg-icon.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /web/src/components/custom/better-scroll.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /server/internal/logic/v1/manage/role/delete.go: -------------------------------------------------------------------------------- 1 | package role 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/jzero-io/jzero/core/stores/condition" 8 | "github.com/pkg/errors" 9 | "github.com/zeromicro/go-zero/core/logx" 10 | 11 | "github.com/jzero-io/jzero-admin/server/internal/model/manage_role" 12 | "github.com/jzero-io/jzero-admin/server/internal/model/manage_user_role" 13 | "github.com/jzero-io/jzero-admin/server/internal/svc" 14 | types "github.com/jzero-io/jzero-admin/server/internal/types/v1/manage/role" 15 | ) 16 | 17 | type Delete struct { 18 | logx.Logger 19 | ctx context.Context 20 | svcCtx *svc.ServiceContext 21 | r *http.Request 22 | } 23 | 24 | func NewDelete(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request) *Delete { 25 | return &Delete{ 26 | Logger: logx.WithContext(ctx), 27 | ctx: ctx, 28 | svcCtx: svcCtx, r: r, 29 | } 30 | } 31 | 32 | func (l *Delete) Delete(req *types.DeleteRequest) (resp *types.DeleteResponse, err error) { 33 | if len(req.Uuids) == 0 { 34 | return nil, nil 35 | } 36 | 37 | userRoles, err := l.svcCtx.Model.ManageUserRole.FindByCondition(l.ctx, nil, condition.Condition{ 38 | Field: manage_user_role.RoleUuid, 39 | Operator: condition.In, 40 | Value: req.Uuids, 41 | }) 42 | if err != nil { 43 | return nil, err 44 | } 45 | if len(userRoles) > 0 { 46 | return nil, errors.New("角色被绑定, 请解除绑定后再进行删除") 47 | } 48 | 49 | err = l.svcCtx.Model.ManageRole.DeleteByCondition(l.ctx, nil, condition.Condition{ 50 | Field: manage_role.Uuid, 51 | Operator: condition.In, 52 | Value: req.Uuids, 53 | }) 54 | return 55 | } 56 | -------------------------------------------------------------------------------- /web/packages/materials/src/libs/page-tab/chrome-tab.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /web/vite.config.ts: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import { URL, fileURLToPath } from 'node:url'; 3 | import { defineConfig, loadEnv } from 'vite'; 4 | import { setupVitePlugins } from './build/plugins'; 5 | import { createViteProxy, getBuildTime } from './build/config'; 6 | 7 | export default defineConfig(configEnv => { 8 | const viteEnv = loadEnv(configEnv.mode, process.cwd()) as unknown as Env.ImportMeta; 9 | 10 | const buildTime = getBuildTime(); 11 | 12 | const enableProxy = configEnv.command === 'serve' && !configEnv.isPreview; 13 | 14 | return { 15 | base: viteEnv.VITE_BASE_URL, 16 | resolve: { 17 | alias: { 18 | '~': fileURLToPath(new URL('./', import.meta.url)), 19 | '@': fileURLToPath(new URL('./src', import.meta.url)) 20 | } 21 | }, 22 | css: { 23 | preprocessorOptions: { 24 | scss: { 25 | api: 'modern-compiler', 26 | additionalData: `@use "@/styles/scss/global.scss" as *;` 27 | } 28 | } 29 | }, 30 | plugins: setupVitePlugins(viteEnv, buildTime), 31 | define: { 32 | BUILD_TIME: JSON.stringify(buildTime) 33 | }, 34 | server: { 35 | host: '0.0.0.0', 36 | port: 9527, 37 | open: true, 38 | proxy: createViteProxy(viteEnv, enableProxy), 39 | fs: { 40 | cachedChecks: false 41 | } 42 | }, 43 | preview: { 44 | port: 9725 45 | }, 46 | build: { 47 | reportCompressedSize: false, 48 | sourcemap: viteEnv.VITE_SOURCE_MAP === 'Y', 49 | commonjsOptions: { 50 | ignoreTryCatch: false 51 | } 52 | } 53 | }; 54 | }); 55 | -------------------------------------------------------------------------------- /web/build/plugins/router.ts: -------------------------------------------------------------------------------- 1 | import type { RouteMeta } from 'vue-router'; 2 | import ElegantVueRouter from '@elegant-router/vue/vite'; 3 | import type { RouteKey } from '@elegant-router/types'; 4 | 5 | export function setupElegantRouter() { 6 | return ElegantVueRouter({ 7 | layouts: { 8 | base: 'src/layouts/base-layout/index.vue', 9 | blank: 'src/layouts/blank-layout/index.vue' 10 | }, 11 | customRoutes: { 12 | names: [ 13 | 'exception_403', 14 | 'exception_404', 15 | 'exception_500', 16 | 'document_project', 17 | 'document_project-link', 18 | 'document_vue', 19 | 'document_vite', 20 | 'document_unocss', 21 | 'document_naive', 22 | 'document_antd' 23 | ] 24 | }, 25 | routePathTransformer(routeName, routePath) { 26 | const key = routeName as RouteKey; 27 | 28 | if (key === 'login') { 29 | const modules: UnionKey.LoginModule[] = ['pwd-login', 'code-login', 'register', 'reset-pwd', 'bind-wechat']; 30 | 31 | const moduleReg = modules.join('|'); 32 | 33 | return `/login/:module(${moduleReg})?`; 34 | } 35 | 36 | return routePath; 37 | }, 38 | onRouteMetaGen(routeName) { 39 | const key = routeName as RouteKey; 40 | 41 | const constantRoutes: RouteKey[] = ['login', '403', '404', '500']; 42 | 43 | const meta: Partial = { 44 | title: key, 45 | i18nKey: `route.${key}` as App.I18n.I18nKey 46 | }; 47 | 48 | if (constantRoutes.includes(key)) { 49 | meta.constant = true; 50 | } 51 | 52 | return meta; 53 | } 54 | }); 55 | } 56 | --------------------------------------------------------------------------------