├── server
├── bin
│ └── .gitkeep
├── uploadFile
│ └── .gitkeep
├── repositories
│ └── modules
│ │ ├── auth
│ │ └── auth.go
│ │ ├── commits
│ │ └── commits.go
│ │ ├── rolesAndInterfaces
│ │ └── rolesAndInterfaces.go
│ │ ├── repositories.go
│ │ ├── logs
│ │ └── logs.go
│ │ └── rolesAndPages
│ │ └── roleAndPages.go
├── utils
│ ├── modules
│ │ ├── contain
│ │ │ └── contain.go
│ │ ├── unique
│ │ │ └── unique.go
│ │ ├── bcrypt
│ │ │ └── bcrypt.go
│ │ ├── logs
│ │ │ └── logs.go
│ │ ├── snowflake
│ │ │ └── snowflake.go
│ │ ├── file
│ │ │ └── file.go
│ │ ├── translator
│ │ │ └── translator.go
│ │ ├── exportExcel
│ │ │ └── exportExcel.go
│ │ ├── jwt
│ │ │ └── jwt.go
│ │ ├── timeTask
│ │ │ └── timeTask.go
│ │ └── captcha
│ │ │ └── captcha.go
│ └── utils.go
├── dto
│ └── modules
│ │ ├── common
│ │ └── common.go
│ │ ├── commits
│ │ └── commits.go
│ │ ├── logs
│ │ └── logs.go
│ │ ├── auth
│ │ └── auth.go
│ │ ├── upload
│ │ └── upload.go
│ │ ├── timeTask
│ │ └── timeTask.go
│ │ ├── department
│ │ └── department.go
│ │ ├── roles
│ │ └── roles.go
│ │ ├── interface
│ │ └── interface.go
│ │ ├── pages
│ │ └── pages.go
│ │ └── template
│ │ └── template.go
├── routers
│ └── modules
│ │ ├── logs
│ │ └── logs.go
│ │ ├── system
│ │ └── system.go
│ │ ├── commits
│ │ └── commits.go
│ │ ├── template
│ │ └── template.go
│ │ ├── auth
│ │ └── auth.go
│ │ ├── department
│ │ └── department.go
│ │ ├── swagger
│ │ └── swagger.go
│ │ ├── timeTask
│ │ └── timeTask.go
│ │ ├── pages
│ │ └── pages.go
│ │ ├── roles
│ │ └── roles.go
│ │ ├── interface
│ │ └── interface.go
│ │ ├── users
│ │ └── users.go
│ │ └── upload
│ │ └── upload.go
├── main.go
├── services
│ ├── modules
│ │ ├── logs
│ │ │ └── logs.go
│ │ ├── rolesAndInterfaces
│ │ │ └── rolesAndInterfaces.go
│ │ ├── usersAndRoles
│ │ │ └── usersAndRoles.go
│ │ ├── department
│ │ │ └── department.go
│ │ └── interface
│ │ │ └── interface.go
│ └── service.go
├── template
│ └── server
│ │ ├── route
│ │ ├── route.go
│ │ └── route.tmpl
│ │ ├── dto
│ │ ├── dto.go
│ │ └── dto.tmpl
│ │ └── service
│ │ ├── service.go
│ │ └── service.tmpl
├── middlewares
│ ├── modules
│ │ ├── session
│ │ │ └── session.go
│ │ ├── request
│ │ │ └── log.go
│ │ ├── cors
│ │ │ └── cors.go
│ │ └── logs
│ │ │ └── logs.go
│ └── middlewares.go
├── bootStrap
│ └── bootStrap.go
├── db
│ └── db.go
├── config
│ └── config.go
└── controllers
│ ├── modules
│ ├── logs
│ │ └── logs.go
│ ├── commits
│ │ └── commits.go
│ └── system
│ │ └── system.go
│ └── controllers.go
├── micro
├── .dockerignore
├── sql
│ ├── data_master
│ │ └── .gitkeep
│ ├── data_slave
│ │ └── .gitkeep
│ ├── master.cnf
│ ├── slave.cnf
│ ├── init-master.sh
│ └── init-slave.sh
├── README.md
├── config
│ └── config.go
├── rpc
│ ├── role
│ │ ├── etc
│ │ │ └── role.yaml
│ │ ├── internal
│ │ │ ├── config
│ │ │ │ └── config.go
│ │ │ ├── svc
│ │ │ │ └── servicecontext.go
│ │ │ └── logic
│ │ │ │ ├── createrolelogic.go
│ │ │ │ ├── roleidshasbeenexistlogic.go
│ │ │ │ ├── rolenamehasbeenexistlogic.go
│ │ │ │ ├── deleterolelogic.go
│ │ │ │ ├── updaterolelogic.go
│ │ │ │ ├── getrolelogic.go
│ │ │ │ └── getrolelistlogic.go
│ │ ├── Dockerfile
│ │ ├── role.go
│ │ └── desc
│ │ │ └── role.proto
│ ├── user
│ │ ├── etc
│ │ │ └── user.yaml
│ │ ├── internal
│ │ │ ├── config
│ │ │ │ └── config.go
│ │ │ ├── svc
│ │ │ │ └── servicecontext.go
│ │ │ └── logic
│ │ │ │ ├── useridhasbeenexistlogic.go
│ │ │ │ ├── useraccounthasbeenexistlogic.go
│ │ │ │ ├── getuserlogic.go
│ │ │ │ ├── getuserbyaccountlogic.go
│ │ │ │ ├── deleteuserlogic.go
│ │ │ │ ├── updateuserlogic.go
│ │ │ │ ├── createuserlogic.go
│ │ │ │ └── getuserlistlogic.go
│ │ ├── Dockerfile
│ │ └── user.go
│ ├── captcha
│ │ ├── etc
│ │ │ └── captcha.yaml
│ │ ├── internal
│ │ │ ├── config
│ │ │ │ └── config.go
│ │ │ ├── svc
│ │ │ │ └── servicecontext.go
│ │ │ ├── server
│ │ │ │ └── captchaserviceserver.go
│ │ │ └── logic
│ │ │ │ ├── verifycaptchalogic.go
│ │ │ │ └── generatecaptchalogic.go
│ │ ├── Dockerfile
│ │ ├── desc
│ │ │ └── captcha.proto
│ │ ├── captcha.go
│ │ └── captchaservice
│ │ │ └── captchaservice.go
│ └── auth
│ │ └── desc
│ │ └── auth.proto
├── api
│ ├── test
│ │ ├── etc
│ │ │ └── user-api.yaml
│ │ ├── internal
│ │ │ ├── config
│ │ │ │ └── config.go
│ │ │ ├── svc
│ │ │ │ └── servicecontext.go
│ │ │ ├── types
│ │ │ │ └── types.go
│ │ │ ├── handler
│ │ │ │ ├── routes.go
│ │ │ │ ├── loginhandler.go
│ │ │ │ └── userinfohandler.go
│ │ │ └── logic
│ │ │ │ ├── userinfologic.go
│ │ │ │ └── loginlogic.go
│ │ ├── desc
│ │ │ └── test.api
│ │ └── user.go
│ ├── user
│ │ ├── etc
│ │ │ └── userservice.yaml
│ │ ├── internal
│ │ │ ├── config
│ │ │ │ └── config.go
│ │ │ ├── svc
│ │ │ │ └── servicecontext.go
│ │ │ ├── handler
│ │ │ │ ├── createuserhandler.go
│ │ │ │ ├── deleteuserhandler.go
│ │ │ │ ├── updateuserhandler.go
│ │ │ │ ├── getuserlisthandler.go
│ │ │ │ └── routes.go
│ │ │ └── logic
│ │ │ │ ├── deleteuserlogic.go
│ │ │ │ ├── updateuserlogic.go
│ │ │ │ ├── createuserlogic.go
│ │ │ │ └── getuserlistlogic.go
│ │ ├── Dockerfile
│ │ └── userservice.go
│ └── auth
│ │ ├── etc
│ │ └── auth.yaml
│ │ ├── internal
│ │ ├── config
│ │ │ └── config.go
│ │ ├── types
│ │ │ └── types.go
│ │ ├── handler
│ │ │ ├── routes.go
│ │ │ ├── loginhandler.go
│ │ │ └── captchahandler.go
│ │ ├── svc
│ │ │ └── servicecontext.go
│ │ └── logic
│ │ │ └── captchalogic.go
│ │ ├── Dockerfile
│ │ ├── auth.go
│ │ └── desc
│ │ └── auth.api
├── model
│ ├── role
│ │ └── role.go
│ └── user
│ │ └── user.go
├── shared
│ ├── redis
│ │ └── redis.go
│ ├── snowflake
│ │ └── snowflake.go
│ ├── token
│ │ └── token.go
│ └── gorm
│ │ └── gorm.go
└── nginx.conf
├── web
├── .env.dev
├── .env.pro
├── src
│ ├── types
│ │ ├── index.ts
│ │ └── menus
│ │ │ └── index.ts
│ ├── styles
│ │ ├── index.css
│ │ ├── global
│ │ │ └── index.css
│ │ └── common
│ │ │ └── index.css
│ ├── assets
│ │ ├── image
│ │ │ ├── 404.png
│ │ │ ├── logo.png
│ │ │ └── loading.gif
│ │ └── svg
│ │ │ ├── moon.svg
│ │ │ ├── start.svg
│ │ │ ├── stop.svg
│ │ │ ├── en-zh.svg
│ │ │ └── zh-en.svg
│ ├── utils
│ │ ├── sleep
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ ├── cache
│ │ │ └── index.ts
│ │ ├── echarts
│ │ │ └── index.ts
│ │ ├── format
│ │ │ └── index.ts
│ │ ├── event
│ │ │ └── index.ts
│ │ └── message
│ │ │ └── index.tsx
│ ├── pages
│ │ ├── Login
│ │ │ └── type.ts
│ │ └── NotFond
│ │ │ └── index.tsx
│ ├── components
│ │ ├── Icon
│ │ │ ├── dark.tsx
│ │ │ ├── light.tsx
│ │ │ ├── translateDark.tsx
│ │ │ ├── translateLight.tsx
│ │ │ └── icon.tsx
│ │ ├── Iframe
│ │ │ └── index.tsx
│ │ ├── Theme
│ │ │ └── index.tsx
│ │ ├── Card
│ │ │ └── index.tsx
│ │ ├── Footer
│ │ │ └── index.tsx
│ │ ├── Auth
│ │ │ └── index.tsx
│ │ ├── AppBreadcrumb
│ │ │ └── index.tsx
│ │ ├── IconSelect
│ │ │ └── index.tsx
│ │ ├── index.ts
│ │ ├── Translate
│ │ │ └── translate.tsx
│ │ └── AppHeaderTab
│ │ │ └── index.tsx
│ ├── service
│ │ ├── index.ts
│ │ ├── api
│ │ │ ├── logs
│ │ │ │ └── index.ts
│ │ │ ├── login
│ │ │ │ └── index.ts
│ │ │ ├── timeTask
│ │ │ │ └── index.ts
│ │ │ ├── pages
│ │ │ │ └── index.ts
│ │ │ ├── department
│ │ │ │ └── index.ts
│ │ │ ├── interface
│ │ │ │ └── index.ts
│ │ │ ├── template
│ │ │ │ └── index.ts
│ │ │ ├── file
│ │ │ │ └── index.ts
│ │ │ └── system
│ │ │ │ └── index.ts
│ │ └── request
│ │ │ ├── lib
│ │ │ └── type.ts
│ │ │ └── index.ts
│ ├── hooks
│ │ ├── useTheme.ts
│ │ └── useAppRoutes.tsx
│ ├── vite-env.d.ts
│ ├── router
│ │ └── index.tsx
│ ├── local
│ │ └── index.ts
│ ├── store
│ │ ├── UploadStore
│ │ │ └── index.ts
│ │ ├── UserStore
│ │ │ └── index.ts
│ │ └── index.ts
│ ├── main.tsx
│ ├── App.tsx
│ └── constant
│ │ └── index.ts
├── postcss.config.js
├── .prettierrc
├── tailwind.config.ts
├── tsconfig.node.json
├── index.html
├── .gitignore
├── tsconfig.json
└── vite.config.ts
├── .gitignore
├── static
├── login.png
├── system.png
└── dashboard.png
├── Dockerfile
├── .github
└── workflows
│ └── go.yml
└── README.md
/server/bin/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/uploadFile/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/micro/.dockerignore:
--------------------------------------------------------------------------------
1 | sql/
2 | .git/
--------------------------------------------------------------------------------
/micro/sql/data_master/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/micro/sql/data_slave/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/.env.dev:
--------------------------------------------------------------------------------
1 | VITE_APP_BASE_URL = "/cms"
--------------------------------------------------------------------------------
/web/.env.pro:
--------------------------------------------------------------------------------
1 | VITE_APP_BASE_URL = "/cms"
--------------------------------------------------------------------------------
/micro/README.md:
--------------------------------------------------------------------------------
1 | # 微服务版本
2 | > 开发中 Coding...
--------------------------------------------------------------------------------
/web/src/types/index.ts:
--------------------------------------------------------------------------------
1 | export type * from './menus/index';
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /micro/sql/data_master/
2 | /micro/sql/data_slave/
3 |
4 |
5 |
--------------------------------------------------------------------------------
/micro/config/config.go:
--------------------------------------------------------------------------------
1 | package appConfig
2 |
3 | var RedisHost = "redis:6379"
4 |
--------------------------------------------------------------------------------
/static/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xi-Yuer/GO-CMS/HEAD/static/login.png
--------------------------------------------------------------------------------
/micro/sql/master.cnf:
--------------------------------------------------------------------------------
1 | server-id=1
2 | log-bin=mysql-bin
3 | binlog-do-db=micro_cms
4 |
--------------------------------------------------------------------------------
/static/system.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xi-Yuer/GO-CMS/HEAD/static/system.png
--------------------------------------------------------------------------------
/static/dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xi-Yuer/GO-CMS/HEAD/static/dashboard.png
--------------------------------------------------------------------------------
/web/src/styles/index.css:
--------------------------------------------------------------------------------
1 | @import './common/index.css';
2 | @import './global/index.css';
3 |
--------------------------------------------------------------------------------
/web/src/assets/image/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xi-Yuer/GO-CMS/HEAD/web/src/assets/image/404.png
--------------------------------------------------------------------------------
/web/src/assets/image/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xi-Yuer/GO-CMS/HEAD/web/src/assets/image/logo.png
--------------------------------------------------------------------------------
/web/src/assets/image/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xi-Yuer/GO-CMS/HEAD/web/src/assets/image/loading.gif
--------------------------------------------------------------------------------
/micro/sql/slave.cnf:
--------------------------------------------------------------------------------
1 | server-id=2
2 | relay-log=relay-log
3 | log-bin=mysql-bin
4 | read-only=1
5 | binlog-do-db=micro_cms
--------------------------------------------------------------------------------
/web/src/utils/sleep/index.ts:
--------------------------------------------------------------------------------
1 | export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
2 |
--------------------------------------------------------------------------------
/web/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/micro/rpc/role/etc/role.yaml:
--------------------------------------------------------------------------------
1 | Name: role.rpc
2 | ListenOn: 0.0.0.0:8082
3 | Etcd:
4 | Hosts:
5 | - etcd:2379
6 | Key: role.rpc
7 |
--------------------------------------------------------------------------------
/micro/rpc/user/etc/user.yaml:
--------------------------------------------------------------------------------
1 | Name: user.rpc
2 | ListenOn: 0.0.0.0:8083
3 | Etcd:
4 | Hosts:
5 | - etcd:2379
6 | Key: user.rpc
7 |
--------------------------------------------------------------------------------
/web/src/pages/Login/type.ts:
--------------------------------------------------------------------------------
1 | export type FieldType = {
2 | account?: string;
3 | password?: string;
4 | captcha?: string;
5 | };
6 |
--------------------------------------------------------------------------------
/web/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from './cache';
2 | export * from './sleep';
3 | export * from './builder';
4 | export * from './message';
5 |
--------------------------------------------------------------------------------
/micro/rpc/captcha/etc/captcha.yaml:
--------------------------------------------------------------------------------
1 | Name: captcha.rpc
2 | ListenOn: 0.0.0.0:8081
3 | Etcd:
4 | Hosts:
5 | - etcd:2379
6 | Key: captcha.rpc
7 |
--------------------------------------------------------------------------------
/micro/api/test/etc/user-api.yaml:
--------------------------------------------------------------------------------
1 | Name: user-api
2 | Host: 0.0.0.0
3 | Port: 8888
4 | Auth:
5 | AccessSecret: "12345699999"
6 | AccessExpire: 86400
--------------------------------------------------------------------------------
/micro/rpc/auth/desc/auth.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package authRPC;
4 |
5 | option go_package = "./auth";
6 |
7 | service AuthService {
8 |
9 | }
--------------------------------------------------------------------------------
/server/repositories/modules/auth/auth.go:
--------------------------------------------------------------------------------
1 | package authRepositorysModules
2 |
3 | var AuthRepository = &authRepository{}
4 |
5 | type authRepository struct {
6 | }
7 |
--------------------------------------------------------------------------------
/micro/rpc/role/internal/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import "github.com/zeromicro/go-zero/zrpc"
4 |
5 | type Config struct {
6 | zrpc.RpcServerConf
7 | }
8 |
--------------------------------------------------------------------------------
/micro/rpc/user/internal/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import "github.com/zeromicro/go-zero/zrpc"
4 |
5 | type Config struct {
6 | zrpc.RpcServerConf
7 | }
8 |
--------------------------------------------------------------------------------
/micro/rpc/captcha/internal/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import "github.com/zeromicro/go-zero/zrpc"
4 |
5 | type Config struct {
6 | zrpc.RpcServerConf
7 | }
8 |
--------------------------------------------------------------------------------
/web/src/components/Icon/dark.tsx:
--------------------------------------------------------------------------------
1 | import moon from '@/assets/svg/moon.svg';
2 | import { Image } from 'antd';
3 |
4 | export const DarkSvg = () => {
5 | return ;
6 | };
7 |
--------------------------------------------------------------------------------
/web/src/components/Icon/light.tsx:
--------------------------------------------------------------------------------
1 | import sun from '@/assets/svg/sun.svg';
2 | import { Image } from 'antd';
3 |
4 | export const LightSvg = () => {
5 | return ;
6 | };
7 |
--------------------------------------------------------------------------------
/server/utils/modules/contain/contain.go:
--------------------------------------------------------------------------------
1 | package contain
2 |
3 | func StringInSlice(str string, slice []string) bool {
4 | for _, s := range slice {
5 | if s == str {
6 | return true
7 | }
8 | }
9 | return false
10 | }
11 |
--------------------------------------------------------------------------------
/micro/api/user/etc/userservice.yaml:
--------------------------------------------------------------------------------
1 | Name: user
2 | Host: 0.0.0.0
3 | Port: 8889
4 | UserService:
5 | Etcd:
6 | Hosts:
7 | - etcd:2379
8 | Key: user.rpc
9 | Auth:
10 | AccessSecret: "12345699999"
11 | AccessExpire: 86400
--------------------------------------------------------------------------------
/web/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": true,
3 | "singleQuote": true,
4 | "tabWidth": 2,
5 | "printWidth": 160,
6 | "bracketSameLine": true,
7 | "arrowParens": "always",
8 | "jsxSingleQuote": true,
9 | "bracketSpacing": true
10 | }
11 |
--------------------------------------------------------------------------------
/micro/api/test/internal/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import "github.com/zeromicro/go-zero/rest"
4 |
5 | type Config struct {
6 | rest.RestConf
7 | Auth struct {
8 | AccessSecret string
9 | AccessExpire int64
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/web/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | darkMode: "selector",
4 | content: ["./index.html", "src/**/*.{js,ts,jsx,tsx}"],
5 | theme: {
6 | extend: {},
7 | },
8 | plugins: [],
9 | };
10 |
--------------------------------------------------------------------------------
/web/src/service/index.ts:
--------------------------------------------------------------------------------
1 | export * from './api/login/index';
2 | export * from './api/pages/index';
3 | export * from './api/system/index';
4 | export * from './api/users/index';
5 | export * from './api/roles/index';
6 | export * from './api/department/index';
7 |
--------------------------------------------------------------------------------
/micro/api/auth/etc/auth.yaml:
--------------------------------------------------------------------------------
1 | Name: auth
2 | Host: 0.0.0.0
3 | Port: 8888
4 | CaptchaService:
5 | Etcd:
6 | Hosts:
7 | - etcd:2379
8 | Key: captcha.rpc
9 | UserService:
10 | Etcd:
11 | Hosts:
12 | - etcd:2379
13 | Key: user.rpc
14 |
--------------------------------------------------------------------------------
/server/dto/modules/common/common.go:
--------------------------------------------------------------------------------
1 | package commonResponsiesModules
2 |
3 | type ExportExcelResponse struct {
4 | IDs []string `json:"ids" form:"ids" binding:"required"`
5 | }
6 |
7 | type HasTotalResponseData struct {
8 | Total int `json:"total"`
9 | List any `json:"list"`
10 | }
11 |
--------------------------------------------------------------------------------
/micro/api/auth/internal/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "github.com/zeromicro/go-zero/rest"
5 | "github.com/zeromicro/go-zero/zrpc"
6 | )
7 |
8 | type Config struct {
9 | rest.RestConf
10 | CaptchaService zrpc.RpcClientConf
11 | UserService zrpc.RpcClientConf
12 | }
13 |
--------------------------------------------------------------------------------
/server/dto/modules/commits/commits.go:
--------------------------------------------------------------------------------
1 | package commitsResponsiesModules
2 |
3 | type CommitResponse struct {
4 | CommitID string `json:"commitID"`
5 | Email string `json:"email"`
6 | Author string `json:"author"`
7 | Message string `json:"message"`
8 | Date string `json:"date"`
9 | }
10 |
--------------------------------------------------------------------------------
/web/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true,
8 | "strict": true
9 | },
10 | "include": ["vite.config.ts"]
11 | }
12 |
--------------------------------------------------------------------------------
/micro/api/test/internal/svc/servicecontext.go:
--------------------------------------------------------------------------------
1 | package svc
2 |
3 | import (
4 | "micro/api/test/internal/config"
5 | )
6 |
7 | type ServiceContext struct {
8 | Config config.Config
9 | }
10 |
11 | func NewServiceContext(c config.Config) *ServiceContext {
12 | return &ServiceContext{
13 | Config: c,
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Go-React-Admin
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/web/src/components/Icon/translateDark.tsx:
--------------------------------------------------------------------------------
1 | import { Image } from 'antd';
2 | import EnZh from '@/assets/svg/en-zh.svg';
3 | import { memo } from 'react';
4 |
5 | const TranslateDark = () => {
6 | return ;
7 | };
8 |
9 | export default memo(TranslateDark);
10 |
--------------------------------------------------------------------------------
/web/src/components/Icon/translateLight.tsx:
--------------------------------------------------------------------------------
1 | import { Image } from 'antd';
2 | import ZhEn from '@/assets/svg/zh-en.svg';
3 | import { memo } from 'react';
4 |
5 | const TranslateLight = () => {
6 | return ;
7 | };
8 |
9 | export default memo(TranslateLight);
10 |
--------------------------------------------------------------------------------
/server/routers/modules/logs/logs.go:
--------------------------------------------------------------------------------
1 | package logsRouterModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/controllers"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func UseLogRoutes(r *gin.RouterGroup) {
9 | group := r.Group("/log")
10 | {
11 | group.GET("/system", controllers.LogsController.GetLogRecords)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/micro/api/user/internal/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "github.com/zeromicro/go-zero/rest"
5 | "github.com/zeromicro/go-zero/zrpc"
6 | )
7 |
8 | type Config struct {
9 | rest.RestConf
10 | Auth struct {
11 | AccessSecret string
12 | AccessExpire int64
13 | }
14 | UserService zrpc.RpcClientConf
15 | }
16 |
--------------------------------------------------------------------------------
/server/routers/modules/system/system.go:
--------------------------------------------------------------------------------
1 | package systemRouterModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/controllers"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func UseSystemRoutes(r *gin.RouterGroup) {
9 | group := r.Group("/system")
10 | {
11 | group.GET("", controllers.SystemController.GetSystemInfo)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/web/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | .idea
5 | npm-debug.log*
6 | yarn-debug.log*
7 | yarn-error.log*
8 | pnpm-debug.log*
9 | lerna-debug.log*
10 |
11 | node_modules
12 | dist
13 | dist-ssr
14 | *.local
15 |
16 | # Editor directories and files
17 | .vscode/*
18 | !.vscode/extensions.json
19 | .idea
20 | .DS_Store
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
--------------------------------------------------------------------------------
/web/src/types/menus/index.ts:
--------------------------------------------------------------------------------
1 | export interface menuType {
2 | pageID: string;
3 | pageName: string;
4 | pagePath: string;
5 | pageIcon: string;
6 | pageComponent: string;
7 | parentPage: string;
8 | children: menuType[];
9 | pageOrder: number;
10 | canEdit: 1 | 0;
11 | isOutSite: boolean;
12 | outSiteLink: string;
13 | createdAt: string;
14 | updateTime: string;
15 | }
16 |
--------------------------------------------------------------------------------
/micro/model/role/role.go:
--------------------------------------------------------------------------------
1 | package roleModlel
2 |
3 | import (
4 | "gorm.io/gorm"
5 | "time"
6 | )
7 |
8 | type Role struct {
9 | ID string `gorm:"<-:create;primaryKey"`
10 | RoleName string `gorm:"not null"`
11 | Description string
12 | CanEdit bool `gorm:"default:true"`
13 | CreatedAt time.Time
14 | UpdatedAt time.Time
15 | DeletedAt gorm.DeletedAt `gorm:"index"`
16 | }
17 |
--------------------------------------------------------------------------------
/micro/sql/init-master.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | # Create replication user
5 | mysql -u root -p${MYSQL_ROOT_PASSWORD} < = ({ name, props }) => {
6 | const Comp = AllIcons[name] as any;
7 | return Comp ? : name;
8 | };
9 |
10 | export default Icon;
11 |
--------------------------------------------------------------------------------
/micro/rpc/role/internal/svc/servicecontext.go:
--------------------------------------------------------------------------------
1 | package svc
2 |
3 | import (
4 | "gorm.io/gorm"
5 | "micro/rpc/role/internal/config"
6 | gormDB "micro/shared/gorm"
7 | )
8 |
9 | type ServiceContext struct {
10 | Config config.Config
11 | GormDB *gorm.DB
12 | }
13 |
14 | func NewServiceContext(c config.Config) *ServiceContext {
15 | return &ServiceContext{
16 | Config: c,
17 | GormDB: gormDB.NewGorm(),
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/micro/rpc/user/internal/svc/servicecontext.go:
--------------------------------------------------------------------------------
1 | package svc
2 |
3 | import (
4 | "gorm.io/gorm"
5 | "micro/rpc/user/internal/config"
6 | gormDB "micro/shared/gorm"
7 | )
8 |
9 | type ServiceContext struct {
10 | Config config.Config
11 | GormDB *gorm.DB
12 | }
13 |
14 | func NewServiceContext(c config.Config) *ServiceContext {
15 | return &ServiceContext{
16 | Config: c,
17 | GormDB: gormDB.NewGorm(),
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/server/routers/modules/commits/commits.go:
--------------------------------------------------------------------------------
1 | package commitsRouterModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/controllers"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func UseCommitsRoutes(r *gin.RouterGroup) {
9 | group := r.Group("/log")
10 | {
11 | group.GET("/commits", controllers.CommitsController.GetCommits)
12 | group.GET("/commits/count", controllers.CommitsController.GetCommitsCount)
13 |
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/server/routers/modules/template/template.go:
--------------------------------------------------------------------------------
1 | package templateRouterModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/controllers"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func UseTTemplateRoutes(r *gin.RouterGroup) {
9 | group := r.Group("/template")
10 | {
11 | group.POST("", controllers.TemplateController.CreateTemplate)
12 | group.POST("/download", controllers.TemplateController.DownloadTemplateZip)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/server/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "github.com/Xi-Yuer/cms/bootStrap"
6 | "os"
7 | "os/signal"
8 | "syscall"
9 | "time"
10 | )
11 |
12 | func main() {
13 | bootStrap.Start()
14 | quit := make(chan os.Signal, 1)
15 | signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
16 | <-quit
17 | _, cancel := context.WithTimeout(context.Background(), 5*time.Second)
18 | defer cancel()
19 | }
20 |
--------------------------------------------------------------------------------
/server/services/modules/logs/logs.go:
--------------------------------------------------------------------------------
1 | package logsServiceModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/dto"
5 | repositories "github.com/Xi-Yuer/cms/repositories/modules"
6 | )
7 |
8 | var LogsService = &logsService{}
9 |
10 | type logsService struct{}
11 |
12 | func (receiver *logsService) GetLogRecords(params *dto.Page) (*dto.HasTotalResponseData, error) {
13 | return repositories.LogsRepository.GetLogRecords(params)
14 | }
15 |
--------------------------------------------------------------------------------
/server/routers/modules/auth/auth.go:
--------------------------------------------------------------------------------
1 | package authRouterModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/controllers"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func UseAuthRoutes(r *gin.RouterGroup) {
9 | group := r.Group("/auth")
10 | {
11 | group.POST("/login", controllers.AuthController.Login)
12 | group.GET("/captcha", controllers.AuthController.Captcha)
13 | group.GET("/cookie", controllers.AuthController.Cookie)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/server/utils/modules/unique/unique.go:
--------------------------------------------------------------------------------
1 | package unique
2 |
3 | // RemoveDuplicatesAndEmpty 移除数组中重复元素
4 | func RemoveDuplicatesAndEmpty(a []string) (ret []string) {
5 | ret = make([]string, 0)
6 | for i := 0; i < len(a); i++ {
7 | repeat := false
8 | for j := i + 1; j < len(a); j++ {
9 | if a[i] == a[j] {
10 | repeat = true
11 | break
12 | }
13 | }
14 | if !repeat {
15 | ret = append(ret, a[i])
16 | }
17 | }
18 | return
19 | }
20 |
--------------------------------------------------------------------------------
/micro/api/test/internal/types/types.go:
--------------------------------------------------------------------------------
1 | // Code generated by goctl. DO NOT EDIT.
2 | package types
3 |
4 | type LoginReq struct {
5 | Username string `json:"username"`
6 | Password string `json:"password"`
7 | }
8 |
9 | type LoginResp struct {
10 | ID string `json:"id"`
11 | Name string `json:"name"`
12 | }
13 |
14 | type UserInfoReq struct {
15 | ID string `json:"id"`
16 | }
17 |
18 | type UserInfoResp struct {
19 | Name string `json:"name"`
20 | }
21 |
--------------------------------------------------------------------------------
/web/src/hooks/useTheme.ts:
--------------------------------------------------------------------------------
1 | import { useAppDispatch, useAppSelector } from '@/store';
2 | import { changeThemeMode } from '@/store/UIStore';
3 |
4 | export const useTheme = () => {
5 | const themeMode = useAppSelector((state) => state.UIStore.themeMode);
6 | const dispatch = useAppDispatch();
7 | const toggleTheme = () => {
8 | dispatch(changeThemeMode(themeMode === 'dark' ? 'light' : 'dark'));
9 | };
10 |
11 | return {
12 | themeMode,
13 | toggleTheme,
14 | };
15 | };
16 |
--------------------------------------------------------------------------------
/micro/api/auth/internal/types/types.go:
--------------------------------------------------------------------------------
1 | // Code generated by goctl. DO NOT EDIT.
2 | package types
3 |
4 | type LoginRequest struct {
5 | Account string `form:"account"`
6 | Password string `form:"password"`
7 | Captcha string `form:"captcha"`
8 | SessionID string `form:"sessionId"`
9 | }
10 |
11 | type CommonResponse struct {
12 | Code int64 `json:"code"`
13 | Data interface{} `json:"data"`
14 | Msg string `json:"msg"`
15 | }
16 |
17 | type EmptyRequest struct {
18 | }
19 |
--------------------------------------------------------------------------------
/web/src/components/Iframe/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC, memo } from 'react';
2 |
3 | export interface IProps {
4 | src: string;
5 | }
6 |
7 | const Iframe: FC = ({ src }) => {
8 | return (
9 |
15 | );
16 | };
17 |
18 | export default memo(Iframe);
19 |
--------------------------------------------------------------------------------
/micro/rpc/captcha/internal/svc/servicecontext.go:
--------------------------------------------------------------------------------
1 | package svc
2 |
3 | import (
4 | "github.com/redis/go-redis/v9"
5 | appConfig "micro/config"
6 | "micro/rpc/captcha/internal/config"
7 | redisDB "micro/shared/redis"
8 | )
9 |
10 | type ServiceContext struct {
11 | Config config.Config
12 | Redis *redis.Client
13 | }
14 |
15 | func NewServiceContext(c config.Config) *ServiceContext {
16 |
17 | return &ServiceContext{
18 | Config: c,
19 | Redis: redisDB.InitRedis(appConfig.RedisHost),
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/micro/api/auth/Dockerfile:
--------------------------------------------------------------------------------
1 | # 使用官方的 Go 语言镜像作为基础镜像
2 | FROM golang:1.21.1-alpine
3 |
4 | # 设置 Go 模块代理
5 | ENV GOPROXY=https://goproxy.cn,direct
6 |
7 | # 设置工作目录
8 | WORKDIR /app
9 |
10 | COPY . .
11 |
12 | # 创建一个目录用于存放编译后的二进制文件和配置文件
13 | RUN mkdir -p ./bin
14 |
15 | # 安装依赖
16 | RUN go mod download
17 |
18 | # 编译 Go 程序
19 | RUN go build -o ./bin/cmd ./api/auth/auth.go
20 |
21 | COPY ./api/auth/etc ./bin/etc
22 |
23 | # 暴露服务的端口
24 | EXPOSE 8888
25 |
26 | # 定义容器启动时运行的命令
27 | CMD ["./bin/cmd", "-f", "./bin/etc/auth.yaml"]
28 |
--------------------------------------------------------------------------------
/micro/rpc/role/Dockerfile:
--------------------------------------------------------------------------------
1 | # 使用官方的 Go 语言镜像作为基础镜像
2 | FROM golang:1.21.1-alpine
3 |
4 | # 设置 Go 模块代理
5 | ENV GOPROXY=https://goproxy.cn,direct
6 |
7 | # 设置工作目录
8 | WORKDIR /app
9 |
10 | COPY . .
11 |
12 | # 创建一个目录用于存放编译后的二进制文件和配置文件
13 | RUN mkdir -p ./bin
14 |
15 | # 安装依赖
16 | RUN go mod download
17 |
18 | # 编译 Go 程序
19 | RUN go build -o ./bin/cmd ./rpc/role/role.go
20 |
21 | COPY ./rpc/role/etc ./bin/etc
22 |
23 | # 暴露服务的端口
24 | EXPOSE 8888
25 |
26 | # 定义容器启动时运行的命令
27 | CMD ["./bin/cmd", "-f", "./bin/etc/role.yaml"]
28 |
--------------------------------------------------------------------------------
/micro/rpc/user/Dockerfile:
--------------------------------------------------------------------------------
1 | # 使用官方的 Go 语言镜像作为基础镜像
2 | FROM golang:1.21.1-alpine
3 |
4 | # 设置 Go 模块代理
5 | ENV GOPROXY=https://goproxy.cn,direct
6 |
7 | # 设置工作目录
8 | WORKDIR /app
9 |
10 | COPY . .
11 |
12 | # 创建一个目录用于存放编译后的二进制文件和配置文件
13 | RUN mkdir -p ./bin
14 |
15 | # 安装依赖
16 | RUN go mod download
17 |
18 | # 编译 Go 程序
19 | RUN go build -o ./bin/cmd ./rpc/user/user.go
20 |
21 | COPY ./rpc/user/etc ./bin/etc
22 |
23 | # 暴露服务的端口
24 | EXPOSE 8888
25 |
26 | # 定义容器启动时运行的命令
27 | CMD ["./bin/cmd", "-f", "./bin/etc/user.yaml"]
28 |
--------------------------------------------------------------------------------
/micro/api/user/internal/svc/servicecontext.go:
--------------------------------------------------------------------------------
1 | package svc
2 |
3 | import (
4 | "github.com/zeromicro/go-zero/zrpc"
5 | "micro/api/user/internal/config"
6 | "micro/rpc/user/userservice"
7 | )
8 |
9 | type ServiceContext struct {
10 | Config config.Config
11 | UserService userservice.UserService
12 | }
13 |
14 | func NewServiceContext(c config.Config) *ServiceContext {
15 | return &ServiceContext{
16 | Config: c,
17 | UserService: userservice.NewUserService(zrpc.MustNewClient(c.UserService)),
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/web/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | interface ImportMetaEnv {
3 | readonly VITE_APP_BASE_URL: string;
4 | }
5 |
6 | interface ImportMeta {
7 | readonly env: ImportMetaEnv;
8 | }
9 |
10 | import 'i18next';
11 | import ns1 from 'locales/en/ns1.json';
12 | import ns2 from 'locales/en/ns2.json';
13 |
14 | declare module 'i18next' {
15 | interface CustomTypeOptions {
16 | defaultNS: 'ns1';
17 | resources: {
18 | ns1: typeof ns1;
19 | ns2: typeof ns2;
20 | };
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/web/src/utils/cache/index.ts:
--------------------------------------------------------------------------------
1 | class Cache {
2 | set(key: string, value: any) {
3 | window.localStorage.setItem(key, JSON.stringify(value));
4 | }
5 |
6 | get(key: string) {
7 | const result = window.localStorage.getItem(key);
8 | if (result) {
9 | return JSON.parse(result);
10 | }
11 | }
12 |
13 | remove(key: string) {
14 | return window.localStorage.removeItem(key);
15 | }
16 |
17 | clear() {
18 | window.localStorage.clear();
19 | }
20 | }
21 |
22 | export const cache = new Cache();
23 |
--------------------------------------------------------------------------------
/micro/api/user/Dockerfile:
--------------------------------------------------------------------------------
1 | # 使用官方的 Go 语言镜像作为基础镜像
2 | FROM golang:1.21.1-alpine
3 |
4 | # 设置 Go 模块代理
5 | ENV GOPROXY=https://goproxy.cn,direct
6 |
7 | # 设置工作目录
8 | WORKDIR /app
9 |
10 | COPY . .
11 |
12 | # 创建一个目录用于存放编译后的二进制文件和配置文件
13 | RUN mkdir -p ./bin
14 |
15 | # 安装依赖
16 | RUN go mod download
17 |
18 | # 编译 Go 程序
19 | RUN go build -o ./bin/cmd ./api/user/userservice.go
20 |
21 | COPY ./api/user/etc ./bin/etc
22 |
23 | # 暴露服务的端口
24 | EXPOSE 8888
25 |
26 | # 定义容器启动时运行的命令
27 | CMD ["./bin/cmd", "-f", "./bin/etc/userservice.yaml"]
28 |
--------------------------------------------------------------------------------
/micro/rpc/captcha/Dockerfile:
--------------------------------------------------------------------------------
1 | # 使用官方的 Go 语言镜像作为基础镜像
2 | FROM golang:1.21.1-alpine
3 |
4 | # 设置 Go 模块代理
5 | ENV GOPROXY=https://goproxy.cn,direct
6 |
7 | # 设置工作目录
8 | WORKDIR /app
9 |
10 | COPY . .
11 |
12 | # 创建一个目录用于存放编译后的二进制文件和配置文件
13 | RUN mkdir -p ./bin
14 |
15 | # 安装依赖
16 | RUN go mod download
17 |
18 | # 编译 Go 程序
19 | RUN go build -o ./bin/cmd ./rpc/captcha/captcha.go
20 |
21 | COPY ./rpc/captcha/etc ./bin/etc
22 |
23 | # 暴露服务的端口
24 | EXPOSE 8888
25 |
26 | # 定义容器启动时运行的命令
27 | CMD ["./bin/cmd", "-f", "./bin/etc/captcha.yaml"]
28 |
--------------------------------------------------------------------------------
/server/template/server/route/route.go:
--------------------------------------------------------------------------------
1 | package TableNameRoute
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/template/server/controller"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func UseTableNameRoutes(r *gin.RouterGroup) {
9 | group := r.Group("/TableName")
10 | c := TableNameController.NewTableNameController()
11 | {
12 | group.GET("", c.GetTableNameListRepo)
13 | group.POST("", c.CreateTableNameRecordRepo)
14 | group.PUT("/:id", c.UpdateTableNameRecordRepo)
15 | group.DELETE("/:id", c.DeleteTableNameRecordRepo)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/server/template/server/dto/dto.go:
--------------------------------------------------------------------------------
1 | package TableNameDto
2 |
3 | type TableNameCreateRequestDTO struct {
4 | Name string `json:"name" binding:"required"`
5 | Age int8 `json:"age" binding:"required"`
6 | }
7 |
8 | type TableNameUpdateRequestDTO struct {
9 | Name string `json:"name" binding:"required"`
10 | Age int8 `json:"age" binding:"required"`
11 | }
12 |
13 | type TableNameFindRequestDTO struct {
14 | Name string `json:"name"`
15 | Age int8 `json:"age"`
16 | Limit int64 `json:"limit"`
17 | Offset int64 `json:"offset"`
18 | }
19 |
--------------------------------------------------------------------------------
/micro/model/user/user.go:
--------------------------------------------------------------------------------
1 | package userModel
2 |
3 | import (
4 | "gorm.io/gorm"
5 | "time"
6 | )
7 |
8 | type User struct {
9 | ID string `gorm:"<-:create;primaryKey"`
10 | Account string `gorm:"<-:create;unique"`
11 | Password string `gorm:"not null"`
12 | NickName string
13 | Avatar string
14 | Status bool `gorm:"default:true"`
15 | DepartmentID string
16 | IsAdmin bool `gorm:"default:false"`
17 | CreatedAt time.Time
18 | UpdatedAt time.Time
19 | DeletedAt gorm.DeletedAt `gorm:"index"`
20 | }
21 |
--------------------------------------------------------------------------------
/server/routers/modules/department/department.go:
--------------------------------------------------------------------------------
1 | package departmentRouterModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/controllers"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func UseDepartmentRoutes(r *gin.RouterGroup) {
9 | group := r.Group("/department")
10 | group.POST("", controllers.DepartmentController.CreateDepartment)
11 | group.DELETE("/:id", controllers.DepartmentController.DeleteDepartment)
12 | group.GET("", controllers.DepartmentController.GetDepartments)
13 | group.PATCH("/:id", controllers.DepartmentController.UpdateDepartment)
14 | }
15 |
--------------------------------------------------------------------------------
/server/routers/modules/swagger/swagger.go:
--------------------------------------------------------------------------------
1 | package swaggerRouterModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/config"
5 | "github.com/Xi-Yuer/cms/docs"
6 | "github.com/gin-gonic/gin"
7 | swaggerfiles "github.com/swaggo/files"
8 | ginSwagger "github.com/swaggo/gin-swagger"
9 | )
10 |
11 | func UseSwaggerRoutes(r *gin.Engine) {
12 | docs.SwaggerInfo.Title = "后台管理系统API接口"
13 | docs.SwaggerInfo.Description = "后台管理系统API接口"
14 | docs.SwaggerInfo.BasePath = config.Config.BASEURL
15 | r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
16 | }
17 |
--------------------------------------------------------------------------------
/server/utils/modules/bcrypt/bcrypt.go:
--------------------------------------------------------------------------------
1 | package bcrypt
2 |
3 | import "golang.org/x/crypto/bcrypt"
4 |
5 | type Bcrypt struct {
6 | }
7 |
8 | func (b *Bcrypt) HashPassword(password string) (string, error) {
9 | generateFromPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
10 | if err != nil {
11 | return "", err
12 | }
13 | return string(generateFromPassword), nil
14 | }
15 |
16 | func (b *Bcrypt) VerifyPassword(password string, hash string) error {
17 | return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
18 | }
19 |
--------------------------------------------------------------------------------
/server/routers/modules/timeTask/timeTask.go:
--------------------------------------------------------------------------------
1 | package timeTaskRouterModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/controllers"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func UseTimeTaskRoutes(r *gin.RouterGroup) {
9 | group := r.Group("/timeTask")
10 |
11 | {
12 | group.POST("/start/:id", controllers.TimeTaskController.StartTimeTask)
13 | group.POST("/stop/:id", controllers.TimeTaskController.StopTimeTask)
14 | group.PATCH("/update/:id", controllers.TimeTaskController.UpdateTimeTask)
15 | group.GET("", controllers.TimeTaskController.GetTimeTask)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/server/template/server/dto/dto.tmpl:
--------------------------------------------------------------------------------
1 | package {{.TableName}}Dto
2 |
3 | type {{.TableName}}CreateRequestDTO struct {
4 | {{range .Fields}} {{.Name}} {{.Type}} `json:"{{.Name}}" binding:"required"`
5 | {{end}}
6 | }
7 |
8 | type {{.TableName}}UpdateRequestDTO struct {
9 | {{range .Fields}} {{.Name}} {{.Type}} `json:"{{.Name}}" binding:"required"`
10 | {{end}}
11 | }
12 |
13 | type {{.TableName}}FindRequestDTO struct {
14 | {{range .Fields}} {{.Name}} {{.Type}} `json:"{{.Name}}" binding:"required"`
15 | {{end}} Limit int64 `json:"limit"`
16 | Offset int64 `json:"offset"`
17 | }
18 |
--------------------------------------------------------------------------------
/web/src/components/Theme/index.tsx:
--------------------------------------------------------------------------------
1 | import { LightSvg } from '@/components/Icon/light.tsx';
2 | import { DarkSvg } from '@/components/Icon/dark.tsx';
3 | import { Switch } from 'antd';
4 | import { useTheme } from '@/hooks/useTheme.ts';
5 | import { memo } from 'react';
6 |
7 | const ThemeBar = () => {
8 | const { toggleTheme, themeMode } = useTheme();
9 | return (
10 | <>
11 | } unCheckedChildren={} onChange={toggleTheme} checked={themeMode === 'dark'} />
12 | >
13 | );
14 | };
15 |
16 | export default memo(ThemeBar);
17 |
--------------------------------------------------------------------------------
/web/src/router/index.tsx:
--------------------------------------------------------------------------------
1 | import { RouteObject } from 'react-router-dom';
2 | import { constants } from '@/constant';
3 |
4 | import Login from '@/pages/Login';
5 | import Main from '@/LayOut';
6 | import NotFond from '@/pages/NotFond';
7 |
8 | export const routes: RouteObject[] = [
9 | {
10 | path: constants.routePath.login,
11 | element: ,
12 | },
13 | {
14 | path: constants.routePath.main,
15 | element: ,
16 | children: [],
17 | },
18 | {
19 | path: '*',
20 | element: ,
21 | },
22 | ];
23 |
24 | export default routes;
25 |
--------------------------------------------------------------------------------
/web/src/pages/NotFond/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC, memo } from 'react';
2 | import { Image } from 'antd';
3 | import NotFondImage from '@/assets/image/404.png';
4 |
5 | const NotFond: FC = () => {
6 | return (
7 |
8 |
9 |
10 | OOPS!
11 | Page Not Font!
12 |
13 |
14 | );
15 | };
16 |
17 | export default memo(NotFond);
18 |
--------------------------------------------------------------------------------
/server/template/server/route/route.tmpl:
--------------------------------------------------------------------------------
1 | package {{ .TableName }}Route
2 |
3 | import (
4 | {{ .TableName }}Controller "{{ .Package }}/template/controller"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func Use{{ .TableName }}Routes(r *gin.RouterGroup) {
9 | group := r.Group("/{{ .TableName }}")
10 | c := {{ .TableName }}Controller.New{{ .TableName }}Controller()
11 | {
12 | group.GET("", c.Get{{ .TableName }}ListRepo)
13 | group.POST("", c.Create{{ .TableName }}RecordRepo)
14 | group.PUT("/:id", c.Update{{ .TableName }}RecordRepo)
15 | group.DELETE("/:id", c.Delete{{ .TableName }}RecordRepo)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/web/src/components/Card/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC, memo, ReactNode } from 'react';
2 | import classNames from 'classnames';
3 | import { useAppSelector } from '@/store';
4 |
5 | const Card: FC<{ children: ReactNode }> = ({ children }) => {
6 | const { themeMode } = useAppSelector((state) => state.UIStore);
7 | return (
8 |
12 | {children}
13 |
14 | );
15 | };
16 |
17 | export default memo(Card);
18 |
--------------------------------------------------------------------------------
/micro/api/test/desc/test.api:
--------------------------------------------------------------------------------
1 | syntax = "v1"
2 |
3 | type LoginReq {
4 | Username string `json:"username"`
5 | Password string `json:"password"`
6 | }
7 |
8 | type LoginResp {
9 | ID string `json:"id"`
10 | Name string `json:"name"`
11 | }
12 |
13 | type UserInfoReq {
14 | ID string `json:"id"`
15 | }
16 |
17 | type UserInfoResp {
18 | Name string `json:"name"`
19 | }
20 |
21 | service user-api {
22 | @handler login
23 | post /user/login (LoginReq) returns (LoginResp)
24 | }
25 |
26 | @server (
27 | jwt: Auth // 开启 jwt 认证
28 | )
29 | service user-api {
30 | @handler userInfo
31 | post /user/info (UserInfoReq) returns (UserInfoResp)
32 | }
--------------------------------------------------------------------------------
/web/src/components/Footer/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC, memo } from 'react';
2 |
3 | const Footer: FC = () => {
4 | return (
5 | <>
6 |
14 | >
15 | );
16 | };
17 |
18 | export default memo(Footer);
19 |
--------------------------------------------------------------------------------
/server/routers/modules/pages/pages.go:
--------------------------------------------------------------------------------
1 | package pagesRouterModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/controllers"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func UsePagesRoutes(r *gin.RouterGroup) {
9 | group := r.Group("/pages")
10 | {
11 | group.POST("", controllers.PagesController.CreatePage)
12 | group.DELETE("/:id", controllers.PagesController.DeletePage)
13 | group.GET("", controllers.PagesController.GetPages)
14 | group.GET("/user", controllers.PagesController.GetUserMenus)
15 | group.GET("/role/:id", controllers.PagesController.GetPagesByRoleID)
16 | group.PATCH("/:id", controllers.PagesController.UpdatePage)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/web/src/service/api/logs/index.ts:
--------------------------------------------------------------------------------
1 | import request from '@/service/request';
2 | import { IHasTotalResponse, Page } from '@/service';
3 | import { AxiosResponse } from 'axios';
4 |
5 | export interface ISysTemLogsResponse {
6 | id: string;
7 | requestDuration: string;
8 | requestMethod: string;
9 | requestPath: string;
10 | requestStatus: string;
11 | userID: string;
12 | userIP: string;
13 | userName: string;
14 | createTime: string;
15 | }
16 |
17 | export const getSysTemLogsRequest = (params: Page) => {
18 | return request.get>>({
19 | url: '/log/system',
20 | params,
21 | });
22 | };
23 |
--------------------------------------------------------------------------------
/micro/api/auth/internal/handler/routes.go:
--------------------------------------------------------------------------------
1 | // Code generated by goctl. DO NOT EDIT.
2 | package handler
3 |
4 | import (
5 | "net/http"
6 |
7 | "micro/api/auth/internal/svc"
8 |
9 | "github.com/zeromicro/go-zero/rest"
10 | )
11 |
12 | func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
13 | server.AddRoutes(
14 | []rest.Route{
15 | {
16 | Method: http.MethodPost,
17 | Path: "/auth/login",
18 | Handler: LoginHandler(serverCtx),
19 | },
20 | {
21 | Method: http.MethodGet,
22 | Path: "/auth/captcha",
23 | Handler: CaptchaHandler(serverCtx),
24 | },
25 | },
26 | rest.WithPrefix("/v1"),
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/web/src/components/Auth/index.tsx:
--------------------------------------------------------------------------------
1 | import { PropsWithChildren, ReactNode } from 'react';
2 | import { useAppSelector } from '@/store';
3 |
4 | interface Props {
5 | permission: string | string[];
6 | }
7 |
8 | const Auth: (props: PropsWithChildren) => ReactNode = ({ children, permission }) => {
9 | const allInterfaceDic = useAppSelector((state) => state.UserStore.userInterfaceDic);
10 | if (Array.isArray(permission)) {
11 | return permission.some((item) => allInterfaceDic.includes(item)) ? children : null;
12 | }
13 | if (allInterfaceDic.includes(permission)) {
14 | return children;
15 | }
16 | return null;
17 | };
18 |
19 | export default Auth;
20 |
--------------------------------------------------------------------------------
/web/src/assets/svg/moon.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/micro/shared/redis/redis.go:
--------------------------------------------------------------------------------
1 | package redisDB
2 |
3 | import (
4 | "context"
5 | "github.com/redis/go-redis/v9"
6 | "log"
7 | "sync"
8 | )
9 |
10 | var (
11 | redisClient *redis.Client
12 | once sync.Once
13 | )
14 |
15 | // InitRedis 初始化 Redis 客户端
16 | func InitRedis(redisAddr string) *redis.Client {
17 | once.Do(func() {
18 | // 创建 Redis 客户端
19 | redisClient = redis.NewClient(&redis.Options{
20 | Addr: redisAddr,
21 | // 设置连接池大小
22 | PoolSize: 10,
23 | })
24 |
25 | // 确保连接到 Redis
26 | _, err := redisClient.Ping(context.Background()).Result()
27 | if err != nil {
28 | log.Fatalf("无法连接到 Redis: %v", err)
29 | }
30 | })
31 |
32 | return redisClient
33 | }
34 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # 基于 Node.js 镜像创建一个 Docker 镜像
2 | FROM node:18
3 |
4 | # 进入前端目录
5 | RUN cd /web
6 |
7 | # 将当前工作目录设置为/app
8 | WORKDIR /app
9 |
10 | # 将 package.json 和 package-lock.json 复制到 /app 目录下
11 | COPY package*.json ./
12 |
13 | # 运行 npm install 安装依赖
14 | RUN npm install
15 |
16 | # 将源代码复制到 /app 目录下
17 | COPY . .
18 |
19 | # 打包构建
20 | RUN npm run build
21 |
22 | # 将构建后的代码复制到 nginx 镜像中
23 | FROM nginx:latest
24 | COPY --from=0 /app/dist /usr/share/nginx/html
25 |
26 | # 暴露容器的 8080 端口,此处其实只是一个声明作用,不写的话也可以,后面运行容器的
27 | # docker run --name container_name -p :命令中container_port可以覆盖此处的声明,不写就默认80端口
28 | EXPOSE 8080
29 |
30 | # 启动 nginx 服务
31 | CMD ["nginx", "-g", "daemon off;"]
32 |
--------------------------------------------------------------------------------
/web/src/local/index.ts:
--------------------------------------------------------------------------------
1 | import i18n from 'i18next';
2 | import { initReactI18next } from 'react-i18next';
3 | import LanguageDetector from 'i18next-browser-languagedetector';
4 | import { constants } from '@/constant';
5 | import { cache } from '@/utils';
6 | import en from './en';
7 | import zh from './zh';
8 |
9 | const i18next = i18n
10 | .use(LanguageDetector)
11 | .use(initReactI18next)
12 | .init({
13 | debug: false,
14 | fallbackLng: cache.get(constants.localStorage.lang) === 'enUS' ? 'en' : 'zh' || 'zh',
15 | interpolation: {
16 | escapeValue: false,
17 | },
18 | resources: {
19 | en,
20 | zh,
21 | },
22 | });
23 |
24 | export default i18next;
25 |
--------------------------------------------------------------------------------
/server/utils/modules/logs/logs.go:
--------------------------------------------------------------------------------
1 | package logsModules
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "time"
7 | )
8 |
9 | var Log = &log{}
10 |
11 | type log struct {
12 | }
13 |
14 | func baseInfo() string {
15 | t := time.Now().Format("2006-01-02 15:04:05")
16 | return fmt.Sprintf("[%s]", t)
17 | }
18 |
19 | func (l *log) Info(v ...interface{}) {
20 | fmt.Printf("【信息】%s %s\n", baseInfo(), v)
21 | }
22 |
23 | func (l *log) Warn(v ...interface{}) {
24 | fmt.Printf("【警告】%s %s\n", baseInfo(), v)
25 | }
26 | func (l *log) Error(v ...interface{}) {
27 | fmt.Printf("【错误】%s %s\n", baseInfo(), v)
28 | }
29 | func (l *log) Panic(v ...interface{}) {
30 | fmt.Printf("【系统错误】%s %s\n", baseInfo(), v)
31 | os.Exit(0)
32 | }
33 |
--------------------------------------------------------------------------------
/web/src/assets/svg/start.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/assets/svg/stop.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/micro/api/auth/internal/svc/servicecontext.go:
--------------------------------------------------------------------------------
1 | package svc
2 |
3 | import (
4 | "github.com/zeromicro/go-zero/zrpc"
5 | "micro/api/auth/internal/config"
6 | "micro/rpc/captcha/captchaservice"
7 | "micro/rpc/user/userservice"
8 | )
9 |
10 | type ServiceContext struct {
11 | Config config.Config
12 | CaptchaService captchaservice.CaptchaService
13 | UserService userservice.UserService
14 | }
15 |
16 | func NewServiceContext(c config.Config) *ServiceContext {
17 | return &ServiceContext{
18 | Config: c,
19 | CaptchaService: captchaservice.NewCaptchaService(zrpc.MustNewClient(c.CaptchaService)),
20 | UserService: userservice.NewUserService(zrpc.MustNewClient(c.UserService)),
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/web/src/utils/echarts/index.ts:
--------------------------------------------------------------------------------
1 | // import the core library.
2 | // Import the echarts core module, which provides the necessary interfaces for using echarts.
3 | import * as echarts from 'echarts/core';
4 | // Import charts, all with Chart suffix
5 | import { BarChart } from 'echarts/charts';
6 | // import components, all suffixed with Component
7 | import { GridComponent, TitleComponent, TooltipComponent } from 'echarts/components';
8 | // Import renderer, note that introducing the CanvasRenderer or SVGRenderer is a required step
9 | import { CanvasRenderer } from 'echarts/renderers';
10 |
11 | // Register the required components
12 | echarts.use([TitleComponent, TooltipComponent, GridComponent, BarChart, CanvasRenderer]);
13 |
--------------------------------------------------------------------------------
/micro/rpc/captcha/desc/captcha.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package captchaRPC;
4 |
5 | option go_package = "./captcha";
6 |
7 | service CaptchaService {
8 | rpc GenerateCaptcha(GenerateCaptchaRequest) returns (GenerateCaptchaResponse);
9 | rpc VerifyCaptcha(VerifyCaptchaRequest) returns (VerifyCaptchaResponse);
10 | }
11 |
12 | message GenerateCaptchaRequest {
13 | string session_id = 1;
14 | }
15 |
16 | message GenerateCaptchaResponse {
17 | string captcha_code = 1;
18 | int64 expires_at = 2;
19 | string captcha = 3;
20 | }
21 |
22 | message VerifyCaptchaRequest {
23 | string session_id = 1;
24 | string captcha_code = 2;
25 | }
26 |
27 | message VerifyCaptchaResponse {
28 | bool valid = 1;
29 | }
30 |
--------------------------------------------------------------------------------
/server/middlewares/modules/session/session.go:
--------------------------------------------------------------------------------
1 | package sessionMiddleWareModule
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/config"
5 | "github.com/gin-contrib/sessions"
6 | "github.com/gin-contrib/sessions/cookie"
7 | "github.com/gin-gonic/gin"
8 | )
9 |
10 | func Session(keyPairs string) gin.HandlerFunc {
11 | store := sessionConfig()
12 | return sessions.Sessions(keyPairs, store)
13 | }
14 | func sessionConfig() sessions.Store {
15 | sessionMaxAge := 3600
16 | sessionSecret := config.Config.APP.SESSIONSECRET
17 | var store sessions.Store
18 | store = cookie.NewStore([]byte(sessionSecret))
19 | store.Options(sessions.Options{
20 | MaxAge: sessionMaxAge, //seconds
21 | Path: "/",
22 | })
23 | return store
24 | }
25 |
--------------------------------------------------------------------------------
/web/src/utils/format/index.ts:
--------------------------------------------------------------------------------
1 | export function formatFileSize(bytes: number) {
2 | if (bytes === 0) return '0 Bytes';
3 |
4 | const k = 1024;
5 | const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
6 | const i = Math.floor(Math.log(bytes) / Math.log(k));
7 |
8 | return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
9 | }
10 |
11 | export function formatTimer(seconds: number) {
12 | // 格式化计时器
13 | const hours = Math.floor(seconds / 3600);
14 | const minutes = Math.floor((seconds % 3600) / 60);
15 | const remainingSeconds = (seconds % 60).toFixed(0);
16 |
17 | return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
18 | }
19 |
--------------------------------------------------------------------------------
/server/routers/modules/roles/roles.go:
--------------------------------------------------------------------------------
1 | package rolesRouterModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/controllers"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func UseRolesRoutes(r *gin.RouterGroup) {
9 | group := r.Group("/roles")
10 | {
11 | group.POST("/query", controllers.RoleController.GetRoles)
12 | group.POST("", controllers.RoleController.CreateRole)
13 | group.DELETE("/:id", controllers.RoleController.DeleteRole)
14 | group.PATCH("/:id", controllers.RoleController.UpdateRole)
15 | group.POST("/bindUser", controllers.RoleController.CreateOneRecord)
16 | group.POST("/deBindUser", controllers.RoleController.DeleteOneRecord)
17 | group.POST("/export", controllers.RoleController.ExportExcel)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/micro/api/auth/auth.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 |
7 | "micro/api/auth/internal/config"
8 | "micro/api/auth/internal/handler"
9 | "micro/api/auth/internal/svc"
10 |
11 | "github.com/zeromicro/go-zero/core/conf"
12 | "github.com/zeromicro/go-zero/rest"
13 | )
14 |
15 | var configFile = flag.String("f", "etc/auth.yaml", "the config file")
16 |
17 | func main() {
18 | flag.Parse()
19 |
20 | var c config.Config
21 | conf.MustLoad(*configFile, &c)
22 |
23 | server := rest.MustNewServer(c.RestConf)
24 | defer server.Stop()
25 |
26 | ctx := svc.NewServiceContext(c)
27 | handler.RegisterHandlers(server, ctx)
28 |
29 | fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
30 | server.Start()
31 | }
32 |
--------------------------------------------------------------------------------
/server/routers/modules/interface/interface.go:
--------------------------------------------------------------------------------
1 | package interfaceRpoterModuels
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/controllers"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func UseInterfaceRouter(r *gin.RouterGroup) {
9 | group := r.Group("/interface")
10 | {
11 |
12 | group.POST("", controllers.InterfaceController.CreateInterface)
13 | group.GET("", controllers.InterfaceController.GetAllInterface)
14 | group.DELETE("/:id", controllers.InterfaceController.DeleteInterface)
15 | group.PATCH("/:id", controllers.InterfaceController.UpdateInterface)
16 | group.GET("/page/:id", controllers.InterfaceController.GetInterfaceByPageID)
17 | group.GET("/role/:id", controllers.InterfaceController.GetInterfacesByRoleID)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/micro/api/user/userservice.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 |
7 | "micro/api/user/internal/config"
8 | "micro/api/user/internal/handler"
9 | "micro/api/user/internal/svc"
10 |
11 | "github.com/zeromicro/go-zero/core/conf"
12 | "github.com/zeromicro/go-zero/rest"
13 | )
14 |
15 | var configFile = flag.String("f", "etc/userservice.yaml", "the config file")
16 |
17 | func main() {
18 | flag.Parse()
19 |
20 | var c config.Config
21 | conf.MustLoad(*configFile, &c)
22 |
23 | server := rest.MustNewServer(c.RestConf)
24 | defer server.Stop()
25 |
26 | ctx := svc.NewServiceContext(c)
27 | handler.RegisterHandlers(server, ctx)
28 |
29 | fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
30 | server.Start()
31 | }
32 |
--------------------------------------------------------------------------------
/micro/api/test/internal/handler/routes.go:
--------------------------------------------------------------------------------
1 | // Code generated by goctl. DO NOT EDIT.
2 | package handler
3 |
4 | import (
5 | "net/http"
6 |
7 | "micro/api/test/internal/svc"
8 |
9 | "github.com/zeromicro/go-zero/rest"
10 | )
11 |
12 | func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
13 | server.AddRoutes(
14 | []rest.Route{
15 | {
16 | Method: http.MethodPost,
17 | Path: "/user/login",
18 | Handler: loginHandler(serverCtx),
19 | },
20 | },
21 | )
22 |
23 | server.AddRoutes(
24 | []rest.Route{
25 | {
26 | Method: http.MethodPost,
27 | Path: "/user/info",
28 | Handler: userInfoHandler(serverCtx),
29 | },
30 | },
31 | rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/server/bootStrap/bootStrap.go:
--------------------------------------------------------------------------------
1 | package bootStrap
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/config"
5 | "github.com/Xi-Yuer/cms/db"
6 | "github.com/Xi-Yuer/cms/routers"
7 | "github.com/Xi-Yuer/cms/utils"
8 | )
9 |
10 | func Start() {
11 | if err := db.InitDB(); err != nil {
12 | utils.Log.Panic(err)
13 | return
14 | }
15 |
16 | if err := utils.File.CheckOrCreateFolder(config.Config.APP.FILEPATH); err != nil {
17 | utils.Log.Panic(err)
18 | return
19 | }
20 | r := routers.SetUpRouters()
21 | go func() {
22 | err := r.Run(config.Config.APP.PORT)
23 | if err != nil {
24 | utils.Log.Panic(err)
25 | }
26 | }()
27 |
28 | utils.Log.Info("服务器启动成功,运行端口", config.Config.APP.PORT)
29 | utils.Log.Info("接口文档地址", config.Config.APP.SWAGPATH)
30 | }
31 |
--------------------------------------------------------------------------------
/server/middlewares/modules/request/log.go:
--------------------------------------------------------------------------------
1 | package requestMiddlewareModule
2 |
3 | import (
4 | "fmt"
5 | "github.com/Xi-Yuer/cms/utils"
6 | "github.com/gin-gonic/gin"
7 | "time"
8 | )
9 |
10 | var RequestMiddlewareModule = &requestMiddlewareModule{}
11 |
12 | type requestMiddlewareModule struct{}
13 |
14 | // RequestLoggerMiddleware 请求日志中间件
15 | func (r *requestMiddlewareModule) RequestLoggerMiddleware(context *gin.Context) {
16 | path := context.Request.URL.Path
17 | methods := context.Request.Method
18 | params := context.Request.URL.RawQuery
19 | status := context.Writer.Status()
20 | start := time.Now()
21 | context.Next()
22 | duration := time.Since(start)
23 | utils.Log.Info(fmt.Sprintf("%v %s %s %s %s", status, methods, duration, path, params))
24 | }
25 |
--------------------------------------------------------------------------------
/micro/api/test/internal/handler/loginhandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/zeromicro/go-zero/rest/httpx"
7 | "micro/api/test/internal/logic"
8 | "micro/api/test/internal/svc"
9 | "micro/api/test/internal/types"
10 | )
11 |
12 | func loginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
13 | return func(w http.ResponseWriter, r *http.Request) {
14 | var req types.LoginReq
15 | if err := httpx.Parse(r, &req); err != nil {
16 | httpx.ErrorCtx(r.Context(), w, err)
17 | return
18 | }
19 |
20 | l := logic.NewLoginLogic(r.Context(), svcCtx)
21 | resp, err := l.Login(&req)
22 | if err != nil {
23 | httpx.ErrorCtx(r.Context(), w, err)
24 | } else {
25 | httpx.OkJsonCtx(r.Context(), w, resp)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/micro/api/auth/internal/handler/loginhandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/zeromicro/go-zero/rest/httpx"
7 | "micro/api/auth/internal/logic"
8 | "micro/api/auth/internal/svc"
9 | "micro/api/auth/internal/types"
10 | )
11 |
12 | func LoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
13 | return func(w http.ResponseWriter, r *http.Request) {
14 | var req types.LoginRequest
15 | if err := httpx.Parse(r, &req); err != nil {
16 | httpx.ErrorCtx(r.Context(), w, err)
17 | return
18 | }
19 |
20 | l := logic.NewLoginLogic(r.Context(), svcCtx)
21 | resp, err := l.Login(&req)
22 | if err != nil {
23 | httpx.ErrorCtx(r.Context(), w, err)
24 | } else {
25 | httpx.OkJsonCtx(r.Context(), w, resp)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/micro/api/auth/internal/handler/captchahandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/zeromicro/go-zero/rest/httpx"
7 | "micro/api/auth/internal/logic"
8 | "micro/api/auth/internal/svc"
9 | "micro/api/auth/internal/types"
10 | )
11 |
12 | func CaptchaHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
13 | return func(w http.ResponseWriter, r *http.Request) {
14 | var req types.EmptyRequest
15 | if err := httpx.Parse(r, &req); err != nil {
16 | httpx.ErrorCtx(r.Context(), w, err)
17 | return
18 | }
19 |
20 | l := logic.NewCaptchaLogic(r.Context(), svcCtx)
21 | resp, err := l.Captcha(&req)
22 | if err != nil {
23 | httpx.ErrorCtx(r.Context(), w, err)
24 | } else {
25 | httpx.OkJsonCtx(r.Context(), w, resp)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/micro/api/auth/desc/auth.api:
--------------------------------------------------------------------------------
1 | syntax = "v1"
2 |
3 | info(
4 | title: "登录鉴权"
5 | desc: "登录鉴权接口"
6 | author: "Xi-Yuer"
7 | email: "2214380963@qq.com"
8 | version: "v1"
9 | )
10 |
11 | type (
12 | LoginRequest {
13 | Account string `form:"account"`
14 | Password string `form:"password"`
15 | Captcha string `form:"captcha"`
16 | SessionID string `form:"sessionId"`
17 | }
18 | CommonResponse {
19 | Code int64 `json:"code"`
20 | Data interface{} `json:"data"`
21 | Msg string `json:"msg"`
22 | }
23 | EmptyRequest {
24 | }
25 | )
26 |
27 | @server(
28 | prefix: /v1/auth
29 | )
30 |
31 | service auth {
32 | @handler Login
33 | post /login (LoginRequest) returns (CommonResponse)
34 |
35 | @handler Captcha
36 | get /captcha (EmptyRequest) returns (CommonResponse)
37 | }
--------------------------------------------------------------------------------
/micro/api/test/internal/handler/userinfohandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/zeromicro/go-zero/rest/httpx"
7 | "micro/api/test/internal/logic"
8 | "micro/api/test/internal/svc"
9 | "micro/api/test/internal/types"
10 | )
11 |
12 | func userInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
13 | return func(w http.ResponseWriter, r *http.Request) {
14 | var req types.UserInfoReq
15 | if err := httpx.Parse(r, &req); err != nil {
16 | httpx.ErrorCtx(r.Context(), w, err)
17 | return
18 | }
19 |
20 | l := logic.NewUserInfoLogic(r.Context(), svcCtx)
21 | resp, err := l.UserInfo(&req)
22 | if err != nil {
23 | httpx.ErrorCtx(r.Context(), w, err)
24 | } else {
25 | httpx.OkJsonCtx(r.Context(), w, resp)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/micro/shared/snowflake/snowflake.go:
--------------------------------------------------------------------------------
1 | package snowflake
2 |
3 | import (
4 | "fmt"
5 | "github.com/bwmarrin/snowflake"
6 | "time"
7 | )
8 |
9 | var Node *snowflake.Node
10 |
11 | func Init(startTime string, machineID int64) (err error) {
12 | var st time.Time
13 | // 格式化 1月2号下午3时4分5秒 2006年
14 | st, err = time.Parse("2006-01-02", startTime)
15 | if err != nil {
16 | return
17 | }
18 |
19 | snowflake.Epoch = st.UnixNano() / 1e6
20 | Node, err = snowflake.NewNode(machineID)
21 | if err != nil {
22 | return
23 | }
24 |
25 | return
26 | }
27 |
28 | func init() {
29 | if err := Init("2024-01-01", 1); err != nil {
30 | fmt.Println("Init() failed, err = ", err)
31 | return
32 | }
33 | }
34 |
35 | // GenID 生成 64 位的 雪花 ID
36 | func GenID() int64 {
37 | return Node.Generate().Int64()
38 | }
39 |
--------------------------------------------------------------------------------
/server/db/db.go:
--------------------------------------------------------------------------------
1 | package db
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "github.com/Xi-Yuer/cms/config"
7 | "github.com/Xi-Yuer/cms/utils"
8 | _ "github.com/go-sql-driver/mysql"
9 | "time"
10 | )
11 |
12 | var DB *sql.DB
13 |
14 | func InitDB() error {
15 | // 初始化数据库连接
16 | db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%s)/cms?charset=utf8&parseTime=True", config.Config.DB.NAME, config.Config.DB.PASSWORD, config.Config.DB.HOST, config.Config.DB.PORT))
17 | if err != nil {
18 | utils.Log.Panic(err)
19 | }
20 |
21 | DB = db
22 |
23 | DB.SetMaxOpenConns(20)
24 | DB.SetMaxIdleConns(10)
25 | DB.SetConnMaxLifetime(time.Minute * 60)
26 | err = DB.Ping()
27 | if err != nil {
28 | utils.Log.Panic(err)
29 | return err
30 | }
31 | utils.Log.Info("数据库连接成功")
32 | return nil
33 | }
34 |
--------------------------------------------------------------------------------
/micro/api/user/internal/handler/createuserhandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/zeromicro/go-zero/rest/httpx"
7 | "micro/api/user/internal/logic"
8 | "micro/api/user/internal/svc"
9 | "micro/api/user/internal/types"
10 | )
11 |
12 | func CreateUserHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
13 | return func(w http.ResponseWriter, r *http.Request) {
14 | var req types.CreateUserRequest
15 | if err := httpx.Parse(r, &req); err != nil {
16 | httpx.ErrorCtx(r.Context(), w, err)
17 | return
18 | }
19 |
20 | l := logic.NewCreateUserLogic(r.Context(), svcCtx)
21 | resp, err := l.CreateUser(&req)
22 | if err != nil {
23 | httpx.ErrorCtx(r.Context(), w, err)
24 | } else {
25 | httpx.OkJsonCtx(r.Context(), w, resp)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/micro/api/user/internal/handler/deleteuserhandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/zeromicro/go-zero/rest/httpx"
7 | "micro/api/user/internal/logic"
8 | "micro/api/user/internal/svc"
9 | "micro/api/user/internal/types"
10 | )
11 |
12 | func DeleteUserHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
13 | return func(w http.ResponseWriter, r *http.Request) {
14 | var req types.DeleteUserRequest
15 | if err := httpx.Parse(r, &req); err != nil {
16 | httpx.ErrorCtx(r.Context(), w, err)
17 | return
18 | }
19 |
20 | l := logic.NewDeleteUserLogic(r.Context(), svcCtx)
21 | resp, err := l.DeleteUser(&req)
22 | if err != nil {
23 | httpx.ErrorCtx(r.Context(), w, err)
24 | } else {
25 | httpx.OkJsonCtx(r.Context(), w, resp)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/micro/api/user/internal/handler/updateuserhandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/zeromicro/go-zero/rest/httpx"
7 | "micro/api/user/internal/logic"
8 | "micro/api/user/internal/svc"
9 | "micro/api/user/internal/types"
10 | )
11 |
12 | func UpdateUserHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
13 | return func(w http.ResponseWriter, r *http.Request) {
14 | var req types.UpdateUserRequest
15 | if err := httpx.Parse(r, &req); err != nil {
16 | httpx.ErrorCtx(r.Context(), w, err)
17 | return
18 | }
19 |
20 | l := logic.NewUpdateUserLogic(r.Context(), svcCtx)
21 | resp, err := l.UpdateUser(&req)
22 | if err != nil {
23 | httpx.ErrorCtx(r.Context(), w, err)
24 | } else {
25 | httpx.OkJsonCtx(r.Context(), w, resp)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/micro/api/test/internal/logic/userinfologic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | "micro/api/test/internal/svc"
8 | "micro/api/test/internal/types"
9 |
10 | "github.com/zeromicro/go-zero/core/logx"
11 | )
12 |
13 | type UserInfoLogic struct {
14 | logx.Logger
15 | ctx context.Context
16 | svcCtx *svc.ServiceContext
17 | }
18 |
19 | func NewUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserInfoLogic {
20 | return &UserInfoLogic{
21 | Logger: logx.WithContext(ctx),
22 | ctx: ctx,
23 | svcCtx: svcCtx,
24 | }
25 | }
26 |
27 | func (l *UserInfoLogic) UserInfo(req *types.UserInfoReq) (resp *types.UserInfoResp, err error) {
28 | value := l.ctx.Value("user_id")
29 | fmt.Println(value)
30 | return &types.UserInfoResp{
31 | Name: "哈哈",
32 | }, nil
33 | }
34 |
--------------------------------------------------------------------------------
/micro/api/user/internal/handler/getuserlisthandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/zeromicro/go-zero/rest/httpx"
7 | "micro/api/user/internal/logic"
8 | "micro/api/user/internal/svc"
9 | "micro/api/user/internal/types"
10 | )
11 |
12 | func GetUserListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
13 | return func(w http.ResponseWriter, r *http.Request) {
14 | var req types.GetUserListRequest
15 | if err := httpx.Parse(r, &req); err != nil {
16 | httpx.ErrorCtx(r.Context(), w, err)
17 | return
18 | }
19 |
20 | l := logic.NewGetUserListLogic(r.Context(), svcCtx)
21 | resp, err := l.GetUserList(&req)
22 | if err != nil {
23 | httpx.ErrorCtx(r.Context(), w, err)
24 | } else {
25 | httpx.OkJsonCtx(r.Context(), w, resp)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/server/routers/modules/users/users.go:
--------------------------------------------------------------------------------
1 | package usersRouterModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/controllers"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func UseUserRoutes(r *gin.RouterGroup) {
9 |
10 | group := r.Group("/users")
11 |
12 | {
13 | group.POST("", controllers.UserController.CreateUser)
14 | group.GET("/:id", controllers.UserController.GetUser)
15 | group.POST("/query", controllers.UserController.GetUsers)
16 | group.POST("/query/role/:id", controllers.UserController.FindUserByParamsAndOutRoleID)
17 | group.GET("/role/:id", controllers.UserController.GetUserByRoleID)
18 | group.PATCH("/:id", controllers.UserController.UpdateUser)
19 | group.DELETE("/:id", controllers.UserController.DeleteUser)
20 | group.POST("/export", controllers.UserController.ExportExcel)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/server/middlewares/middlewares.go:
--------------------------------------------------------------------------------
1 | package middlewares
2 |
3 | import (
4 | authMiddleWareModule "github.com/Xi-Yuer/cms/middlewares/modules/auth"
5 | corsMiddlewareModule "github.com/Xi-Yuer/cms/middlewares/modules/cors"
6 | systemLogsMiddlewareModule "github.com/Xi-Yuer/cms/middlewares/modules/logs"
7 | )
8 | import sessionMiddleWareModule "github.com/Xi-Yuer/cms/middlewares/modules/session"
9 |
10 | var SessionMiddleWareModule = sessionMiddleWareModule.Session
11 |
12 | var AuthMiddleWareModule = authMiddleWareModule.AuthTokenMiddleWare
13 |
14 | var LogsMiddlewareModule = systemLogsMiddlewareModule.SystemLogMiddlewareModule
15 |
16 | var AuthMethodMiddleWare = authMiddleWareModule.AuthMethodMiddleWare
17 |
18 | var AuthVerifyCookie = authMiddleWareModule.AuthVerifyCookie
19 |
20 | var Cors = corsMiddlewareModule.Cors
21 |
--------------------------------------------------------------------------------
/web/src/store/UploadStore/index.ts:
--------------------------------------------------------------------------------
1 | import { createSlice } from '@reduxjs/toolkit';
2 |
3 | export interface IUploadFile {
4 | fileName: string;
5 | fileSize: number;
6 | identifier: string;
7 | progress: number;
8 | }
9 |
10 | interface IUploadStore {
11 | uploadList: IUploadFile[];
12 | }
13 |
14 | const useUploadStore = createSlice({
15 | name: 'uploadStore',
16 | initialState: {
17 | uploadList: [],
18 | } as IUploadStore,
19 | reducers: {
20 | addUploadFile: (state, action) => {
21 | state.uploadList.push(action.payload);
22 | },
23 | updateUploadFileList: (state, action) => {
24 | state.uploadList = action.payload;
25 | },
26 | },
27 | });
28 |
29 | export default useUploadStore.reducer;
30 | export const { addUploadFile, updateUploadFileList } = useUploadStore.actions;
31 |
--------------------------------------------------------------------------------
/server/dto/modules/logs/logs.go:
--------------------------------------------------------------------------------
1 | package logsResponsiesModules
2 |
3 | type CreateLogRecordRequest struct {
4 | ID int64
5 | UserID string
6 | UserName string
7 | UserIP string
8 | RequestPath string
9 | RequestMethod string
10 | RequestStatus int
11 | RequestDuration string
12 | CreateTime int64
13 | }
14 |
15 | type GetLogRecordResponse struct {
16 | ID string `json:"id"`
17 | UserID string `json:"userID"`
18 | UserName string `json:"userName"`
19 | UserIP string `json:"userIP"`
20 | RequestPath string `json:"requestPath"`
21 | RequestMethod string `json:"requestMethod"`
22 | RequestStatus string `json:"requestStatus"`
23 | RequestDuration string `json:"requestDuration"`
24 | CreateTime string `json:"createTime"`
25 | }
26 |
--------------------------------------------------------------------------------
/web/src/components/AppBreadcrumb/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC, memo, useEffect, useState } from 'react';
2 | import { useAppSelector } from '@/store';
3 | import { menuType } from '@/types/menus';
4 | import { getTheCurrentRoutePathAllMenuEntity } from '@/utils';
5 | import { useLocation } from 'react-router-dom';
6 | import { Breadcrumb } from 'antd';
7 |
8 | const AppBreadcrumb: FC = () => {
9 | const { menus } = useAppSelector((state) => state.UserStore);
10 | const { pathname } = useLocation();
11 | const [breadCrumb, setBreadCrumb] = useState([]);
12 |
13 | useEffect(() => {
14 | setBreadCrumb(getTheCurrentRoutePathAllMenuEntity(pathname, menus));
15 | }, [menus, pathname]);
16 | return ({ title: item.pageName }))} className='font-bold select-none' />;
17 | };
18 |
19 | export default memo(AppBreadcrumb);
20 |
--------------------------------------------------------------------------------
/micro/api/test/internal/logic/loginlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "micro/shared/token"
6 |
7 | "micro/api/test/internal/svc"
8 | "micro/api/test/internal/types"
9 |
10 | "github.com/zeromicro/go-zero/core/logx"
11 | )
12 |
13 | type LoginLogic struct {
14 | logx.Logger
15 | ctx context.Context
16 | svcCtx *svc.ServiceContext
17 | }
18 |
19 | func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic {
20 | return &LoginLogic{
21 | Logger: logx.WithContext(ctx),
22 | ctx: ctx,
23 | svcCtx: svcCtx,
24 | }
25 | }
26 |
27 | func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.LoginResp, err error) {
28 | createToken, err := token.CreateToken(100, "xiyuer")
29 | if err != nil {
30 | return nil, err
31 | }
32 | return &types.LoginResp{
33 | ID: "1",
34 | Name: createToken,
35 | }, nil
36 | }
37 |
--------------------------------------------------------------------------------
/server/middlewares/modules/cors/cors.go:
--------------------------------------------------------------------------------
1 | package corsMiddlewareModule
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "net/http"
6 | )
7 |
8 | func Cors(context *gin.Context) {
9 | method := context.Request.Method
10 | context.Header("Access-Control-Allow-Origin", "*")
11 | context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
12 | context.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
13 | context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
14 | context.Header("Access-Control-Allow-Credentials", "true")
15 | // 放行所有OPTIONS方法
16 | if method == "OPTIONS" {
17 | context.AbortWithStatus(http.StatusNoContent)
18 | return
19 | }
20 | context.Next()
21 | }
22 |
--------------------------------------------------------------------------------
/micro/sql/init-slave.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | # Wait for the master to be fully up and running
5 | until mysql -h mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "select 1"; do
6 | >&2 echo "MySQL master is unavailable - sleeping"
7 | sleep 10
8 | done
9 |
10 | # Get master status
11 | MASTER_STATUS=$(mysql -h mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "SHOW MASTER STATUS\G")
12 | CURRENT_LOG=$(echo "$MASTER_STATUS" | grep "File:" | awk '{print $2}')
13 | CURRENT_POS=$(echo "$MASTER_STATUS" | grep "Position:" | awk '{print $2}')
14 |
15 | # Configure replication
16 | mysql -u root -p${MYSQL_ROOT_PASSWORD} < {
8 | const { t } = useTranslation();
9 | const options = Object.keys(AllIcons)
10 | .slice(0, 300)
11 | .map((key: any) => {
12 | return {
13 | value: key,
14 | label: (
15 | <>
16 |
17 | {key}
18 | >
19 | ),
20 | };
21 | });
22 | return (
23 |
24 |
25 |
26 | );
27 | };
28 |
29 | export default memo(IconSelect);
30 |
--------------------------------------------------------------------------------
/web/src/components/index.ts:
--------------------------------------------------------------------------------
1 | import { DarkSvg } from '@/components/Icon/dark.tsx';
2 | import { LightSvg } from '@/components/Icon/light.tsx';
3 | import Icon from '@/components/Icon/icon.tsx';
4 | import IconSelect from '@/components/IconSelect';
5 | import TranslateDark from '@/components/Icon/translateDark.tsx';
6 | import TranslateLight from '@/components/Icon/translateLight.tsx';
7 | import ThemeBar from '@/components/Theme';
8 | import Translate from '@/components/Translate/translate.tsx';
9 | import AppBreadcrumb from '@/components/AppBreadcrumb';
10 | import AppHeaderTab from '@/components/AppHeaderTab';
11 | import Card from '@/components/Card';
12 | import AppUploads from '@/components/AppUploads';
13 | import Footer from '@/components/Footer';
14 |
15 | export { DarkSvg, LightSvg, Icon, IconSelect, TranslateLight, TranslateDark, ThemeBar, Translate, AppBreadcrumb, AppHeaderTab, Card, AppUploads, Footer };
16 |
--------------------------------------------------------------------------------
/web/src/service/request/lib/type.ts:
--------------------------------------------------------------------------------
1 | import type { AxiosInterceptorOptions, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'; // 扩展拦截器
2 |
3 | export interface RequestConfig extends AxiosRequestConfig {
4 | requestInterceptor?: {
5 | onFulfilled?: (value: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise;
6 | onRejected?: ((error: any) => any) | null;
7 | options?: AxiosInterceptorOptions;
8 | };
9 |
10 | responseInterceptor?: {
11 | onFulfilled?: (value: AxiosResponse) => AxiosResponse;
12 | onRejected?: ((error: any) => any) | null;
13 | options?: AxiosInterceptorOptions;
14 | };
15 | }
16 |
17 | export type InterceptorType = Partial>;
18 |
19 | export interface IResponse {
20 | data: T;
21 | message: string;
22 | code: number;
23 | }
24 |
--------------------------------------------------------------------------------
/server/services/modules/rolesAndInterfaces/rolesAndInterfaces.go:
--------------------------------------------------------------------------------
1 | package rolesAndInterfacesServiceModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/dto"
5 | repositories "github.com/Xi-Yuer/cms/repositories/modules"
6 | )
7 |
8 | var RolesAndInterfacesService = &rolesAndInterfacesService{}
9 |
10 | type rolesAndInterfacesService struct{}
11 |
12 | // GetInterfacesByRoleID 根据角色ID获取接口
13 | func (r *rolesAndInterfacesService) GetInterfacesByRoleID(roleId string) ([]*dto.GetInterfaceResponse, error) {
14 | interIDs, err := repositories.RolesAndInterfacesRepository.GetRecordByRoleID(roleId)
15 | if err != nil {
16 | return nil, err
17 | }
18 | var interfaceDic []*dto.GetInterfaceResponse
19 | for _, id := range interIDs {
20 | inter, e := repositories.InterfaceRepository.GetInterfaceByID(id)
21 | if !e {
22 | continue
23 | }
24 | interfaceDic = append(interfaceDic, inter)
25 | }
26 | return interfaceDic, nil
27 | }
28 |
--------------------------------------------------------------------------------
/web/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": [
6 | "ES2020",
7 | "DOM",
8 | "DOM.Iterable",
9 | "ESNext"
10 | ],
11 | "module": "ESNext",
12 | "skipLibCheck": true,
13 | /* Bundler mode */
14 | "moduleResolution": "bundler",
15 | "allowImportingTsExtensions": true,
16 | "resolveJsonModule": true,
17 | "isolatedModules": true,
18 | "noEmit": true,
19 | "jsx": "react-jsx",
20 | /* Linting */
21 | "strict": true,
22 | "noUnusedLocals": true,
23 | "noUnusedParameters": true,
24 | "noFallthroughCasesInSwitch": true,
25 | "baseUrl": ".",
26 | "paths": {
27 | "@/*": [
28 | "src/*"
29 | ]
30 | }
31 | },
32 | "include": [
33 | "src"
34 | ],
35 | "references": [
36 | {
37 | "path": "./tsconfig.node.json"
38 | }
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/server/utils/modules/snowflake/snowflake.go:
--------------------------------------------------------------------------------
1 | package snowflake
2 |
3 | import (
4 | "fmt"
5 | logsModules "github.com/Xi-Yuer/cms/utils/modules/logs"
6 | "github.com/bwmarrin/snowflake"
7 | "time"
8 | )
9 |
10 | var Node *snowflake.Node
11 |
12 | func Init(startTime string, machineID int64) (err error) {
13 | var st time.Time
14 | // 格式化 1月2号下午3时4分5秒 2006年
15 | st, err = time.Parse("2006-01-02", startTime)
16 | if err != nil {
17 | logsModules.Log.Error(err)
18 | return
19 | }
20 |
21 | snowflake.Epoch = st.UnixNano() / 1e6
22 | Node, err = snowflake.NewNode(machineID)
23 | if err != nil {
24 | logsModules.Log.Error(err)
25 | return
26 | }
27 |
28 | return
29 | }
30 |
31 | func init() {
32 | if err := Init("2024-01-01", 1); err != nil {
33 | fmt.Println("Init() failed, err = ", err)
34 | return
35 | }
36 | }
37 |
38 | // GenID 生成 64 位的 雪花 ID
39 | func GenID() int64 {
40 | return Node.Generate().Int64()
41 | }
42 |
--------------------------------------------------------------------------------
/server/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | var Config = config{
4 | APP: APP{
5 | PORT: ":8081",
6 | SESSIONSECRET: "FUCNdjYGFg4G",
7 | JWT: "P8BkI2OpBkY",
8 | SWAGPATH: "http://localhost:8081/swagger/docs/index.html#/example",
9 | BASEURL: "/cms",
10 | FILEPATH: "./uploadFile/",
11 | DOMAIN: "localhost",
12 | },
13 | DB: DB{
14 | NAME: "root",
15 | PASSWORD: "2214380963Wx!!",
16 | HOST: "localhost",
17 | DB: "cms",
18 | PORT: "3306",
19 | },
20 | }
21 |
22 | type config struct {
23 | APP
24 | DB
25 | }
26 |
27 | type APP struct {
28 | PORT string
29 | SESSIONSECRET string
30 | JWT string
31 | SWAGPATH string
32 | BASEURL string
33 | FILEPATH string
34 | DOMAIN string
35 | }
36 | type DB struct {
37 | NAME string
38 | PASSWORD string
39 | HOST string
40 | DB string
41 | PORT string
42 | }
43 |
--------------------------------------------------------------------------------
/server/utils/modules/file/file.go:
--------------------------------------------------------------------------------
1 | package file
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | )
7 |
8 | var File = &file{}
9 |
10 | type file struct{}
11 |
12 | // PathExists 检查文件是否存在
13 | func (f *file) PathExists(path string) bool {
14 | _, err := os.Stat(path)
15 | if err == nil {
16 | return true
17 | }
18 | if os.IsNotExist(err) {
19 | return false
20 | }
21 | return false
22 | }
23 |
24 | // CheckOrCreateFolder 检查文件夹是否存在
25 | func (f *file) CheckOrCreateFolder(folderPath string) error {
26 | // 检查文件夹是否存在
27 | _, err := os.Stat(folderPath)
28 | if os.IsNotExist(err) {
29 | // 文件夹不存在,创建文件夹
30 | err := os.MkdirAll(folderPath, 0755)
31 | if err != nil {
32 | return fmt.Errorf("创建文件夹失败: %v", err)
33 | }
34 | //fmt.Println("文件夹不存在,已创建:", folderPath)
35 | } else if err != nil {
36 | // 其他错误,返回错误信息
37 | return fmt.Errorf("检查文件夹失败: %v", err)
38 | } else {
39 | //fmt.Println("文件夹已存在:", folderPath)
40 | }
41 | return nil
42 | }
43 |
--------------------------------------------------------------------------------
/server/controllers/modules/logs/logs.go:
--------------------------------------------------------------------------------
1 | package logsControllerModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/dto"
5 | "github.com/Xi-Yuer/cms/services"
6 | "github.com/Xi-Yuer/cms/utils"
7 | "github.com/gin-gonic/gin"
8 | )
9 |
10 | var LogsController = &logsControllerModules{}
11 |
12 | type logsControllerModules struct{}
13 |
14 | // GetLogRecords 获取系统日志
15 | // @Summary 获取系统日志
16 | // @Description 获取系统日志
17 | // @Tags 日志管理
18 | // @Accept json
19 | // @Produce json
20 | // @Router /log/system [get]
21 | func (l *logsControllerModules) GetLogRecords(context *gin.Context) {
22 | var params dto.Page
23 | if err := context.ShouldBind(¶ms); err != nil {
24 | utils.Response.ParameterMissing(context, err.Error())
25 | return
26 | }
27 | logRecords, err := services.LogsService.GetLogRecords(¶ms)
28 | if err != nil {
29 | utils.Response.ServerError(context, err.Error())
30 | return
31 | }
32 | utils.Response.Success(context, logRecords)
33 | }
34 |
--------------------------------------------------------------------------------
/micro/api/user/internal/handler/routes.go:
--------------------------------------------------------------------------------
1 | // Code generated by goctl. DO NOT EDIT.
2 | package handler
3 |
4 | import (
5 | "net/http"
6 |
7 | "micro/api/user/internal/svc"
8 |
9 | "github.com/zeromicro/go-zero/rest"
10 | )
11 |
12 | func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
13 | server.AddRoutes(
14 | []rest.Route{
15 | {
16 | Method: http.MethodGet,
17 | Path: "/",
18 | Handler: GetUserListHandler(serverCtx),
19 | },
20 | {
21 | Method: http.MethodDelete,
22 | Path: "/:id",
23 | Handler: DeleteUserHandler(serverCtx),
24 | },
25 | {
26 | Method: http.MethodPut,
27 | Path: "/:id",
28 | Handler: UpdateUserHandler(serverCtx),
29 | },
30 | {
31 | Method: http.MethodPost,
32 | Path: "/",
33 | Handler: CreateUserHandler(serverCtx),
34 | },
35 | },
36 | rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
37 | rest.WithPrefix("/v1/user"),
38 | )
39 | }
40 |
--------------------------------------------------------------------------------
/micro/api/test/user.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "net/http"
7 |
8 | "micro/api/test/internal/config"
9 | "micro/api/test/internal/handler"
10 | "micro/api/test/internal/svc"
11 |
12 | "github.com/zeromicro/go-zero/core/conf"
13 | "github.com/zeromicro/go-zero/rest"
14 | )
15 |
16 | var configFile = flag.String("f", "etc/user-api.yaml", "the config file")
17 |
18 | func main() {
19 | flag.Parse()
20 |
21 | var c config.Config
22 | conf.MustLoad(*configFile, &c)
23 |
24 | server := rest.MustNewServer(c.RestConf, rest.WithUnauthorizedCallback(func(w http.ResponseWriter, r *http.Request, err error) {
25 | // 自定义处理返回
26 | w.WriteHeader(http.StatusUnauthorized)
27 | http.Error(w, "Unauthorized", http.StatusUnauthorized)
28 | }))
29 | defer server.Stop()
30 |
31 | ctx := svc.NewServiceContext(c)
32 | handler.RegisterHandlers(server, ctx)
33 |
34 | fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
35 | server.Start()
36 | }
37 |
--------------------------------------------------------------------------------
/server/dto/modules/upload/upload.go:
--------------------------------------------------------------------------------
1 | package uploadResponsiesModules
2 |
3 | import "mime/multipart"
4 |
5 | type UploadBigFileRequest struct {
6 | Identifier string `form:"identifier" binding:"required"`
7 | UpFile *multipart.FileHeader `form:"file" binding:"required"`
8 | }
9 |
10 | type CheckChunkResponse struct {
11 | HasReadySize int64 `json:"hasReadySize"`
12 | }
13 |
14 | type CheckChunkRequest struct {
15 | Identifier string `form:"identifier" binding:"required"`
16 | }
17 |
18 | type UploadFinishRequest struct {
19 | Identifier string `form:"identifier" binding:"required"`
20 | FileName string `form:"fileName" binding:"required"`
21 | FileSize int64 `form:"fileSize" binding:"required"`
22 | }
23 | type UploadRecordResponse struct {
24 | FileID string `json:"fileID"`
25 | FileName string `json:"fileName"`
26 | FileSize int64 `json:"fileSize"`
27 | UploadUser string `json:"uploadUser"`
28 | UploadTime string `json:"uploadTime"`
29 | }
30 |
--------------------------------------------------------------------------------
/web/src/service/api/login/index.ts:
--------------------------------------------------------------------------------
1 | import request from '@/service/request';
2 | import { Md5 } from 'ts-md5';
3 | import { AxiosResponse } from 'axios';
4 |
5 | export type LoginParamsType = {
6 | account: string;
7 | password: string;
8 | captcha: string;
9 | };
10 |
11 | export interface LoginUserResponseType {
12 | id: string;
13 | account: string;
14 | nickname: string;
15 | isAdmin: number;
16 | avatar: null;
17 | rolesID: string[];
18 | interfaceDic: string[];
19 | departmentID: string;
20 | createTime: Date;
21 | updateTime: Date;
22 | status: string;
23 | }
24 |
25 | export const loginRequest = (data: LoginParamsType) => {
26 | return request.post>({
27 | url: '/auth/login',
28 | data: {
29 | ...data,
30 | password: Md5.hashStr(data.password),
31 | },
32 | });
33 | };
34 |
35 | export const getCaptchaRequest = () => {
36 | return request.get({
37 | url: '/auth/captcha',
38 | responseType: 'blob',
39 | });
40 | };
41 |
--------------------------------------------------------------------------------
/server/dto/modules/timeTask/timeTask.go:
--------------------------------------------------------------------------------
1 | package timeTaskResponsiesModules
2 |
3 | type StartTimeTack struct {
4 | TimeTaskID string `form:"timeTaskID" binding:"required"`
5 | }
6 |
7 | type StopTimeTack struct {
8 | TimeTaskID string `form:"timeTaskID" binding:"required"`
9 | }
10 |
11 | type DeleteTimeTack struct {
12 | TimeTaskID string `form:"timeTaskID" binding:"required"`
13 | }
14 |
15 | type CreateTimeTack struct {
16 | TaskName string `form:"taskName" binding:"required"`
17 | Cron string `form:"cron" binding:"required"`
18 | }
19 |
20 | type UpdateTimeTask struct {
21 | TaskName string `form:"taskName" binding:"required"`
22 | Cron string `form:"cron" binding:"required"`
23 | Status *bool `form:"status" binding:"required"`
24 | }
25 |
26 | type TimeTaskResponse struct {
27 | TimeTaskID string `json:"timeTaskID"`
28 | TaskName string `json:"taskName"`
29 | Cron string `json:"cron"`
30 | Status bool `json:"status"`
31 | LastRunTime string `json:"lastRunTime"`
32 | RunTimes float64 `json:"runTimes"`
33 | }
34 |
--------------------------------------------------------------------------------
/web/src/utils/event/index.ts:
--------------------------------------------------------------------------------
1 | import { EventEmitter } from 'events';
2 | import { RcFile } from 'antd/es/upload';
3 |
4 | const eventEmitter = new EventEmitter();
5 |
6 | // 组件间通讯的事件
7 | export const EVENT_UPLOAD_FILE = 'uploadFile';
8 | export const GET_FILE_LIST = 'getFileList';
9 |
10 | // 注册事件监听
11 | export function addListenerUploadFile(handler: (file: RcFile) => void) {
12 | eventEmitter.on(EVENT_UPLOAD_FILE, handler);
13 | }
14 |
15 | export function addListenerGetFileList(handler: () => void) {
16 | eventEmitter.on(GET_FILE_LIST, handler);
17 | }
18 |
19 | export function removeListenerGetFileList(handler: () => void) {
20 | eventEmitter.removeListener(GET_FILE_LIST, handler);
21 | }
22 |
23 | export function removeListenerUploadFile(handler: (file: RcFile) => void) {
24 | eventEmitter.removeListener(EVENT_UPLOAD_FILE, handler);
25 | }
26 |
27 | // 触发事件
28 | export function emitUploadFile(file: RcFile) {
29 | eventEmitter.emit(EVENT_UPLOAD_FILE, file);
30 | }
31 |
32 | export function emitGetFileList() {
33 | eventEmitter.emit(GET_FILE_LIST);
34 | }
35 |
--------------------------------------------------------------------------------
/micro/rpc/role/role.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 |
7 | "micro/rpc/role/internal/config"
8 | "micro/rpc/role/internal/server"
9 | "micro/rpc/role/internal/svc"
10 | "micro/rpc/role/roleRPC"
11 |
12 | "github.com/zeromicro/go-zero/core/conf"
13 | "github.com/zeromicro/go-zero/core/service"
14 | "github.com/zeromicro/go-zero/zrpc"
15 | "google.golang.org/grpc"
16 | "google.golang.org/grpc/reflection"
17 | )
18 |
19 | var configFile = flag.String("f", "etc/role.yaml", "the config file")
20 |
21 | func main() {
22 | flag.Parse()
23 |
24 | var c config.Config
25 | conf.MustLoad(*configFile, &c)
26 | ctx := svc.NewServiceContext(c)
27 |
28 | s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
29 | roleRPC.RegisterRoleServiceServer(grpcServer, server.NewRoleServiceServer(ctx))
30 |
31 | if c.Mode == service.DevMode || c.Mode == service.TestMode {
32 | reflection.Register(grpcServer)
33 | }
34 | })
35 | defer s.Stop()
36 |
37 | fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
38 | s.Start()
39 | }
40 |
--------------------------------------------------------------------------------
/micro/rpc/user/user.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 |
7 | "micro/rpc/user/internal/config"
8 | "micro/rpc/user/internal/server"
9 | "micro/rpc/user/internal/svc"
10 | "micro/rpc/user/userRPC"
11 |
12 | "github.com/zeromicro/go-zero/core/conf"
13 | "github.com/zeromicro/go-zero/core/service"
14 | "github.com/zeromicro/go-zero/zrpc"
15 | "google.golang.org/grpc"
16 | "google.golang.org/grpc/reflection"
17 | )
18 |
19 | var configFile = flag.String("f", "etc/user.yaml", "the config file")
20 |
21 | func main() {
22 | flag.Parse()
23 |
24 | var c config.Config
25 | conf.MustLoad(*configFile, &c)
26 | ctx := svc.NewServiceContext(c)
27 |
28 | s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
29 | userRPC.RegisterUserServiceServer(grpcServer, server.NewUserServiceServer(ctx))
30 |
31 | if c.Mode == service.DevMode || c.Mode == service.TestMode {
32 | reflection.Register(grpcServer)
33 | }
34 | })
35 | defer s.Stop()
36 |
37 | fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
38 | s.Start()
39 | }
40 |
--------------------------------------------------------------------------------
/micro/rpc/captcha/internal/server/captchaserviceserver.go:
--------------------------------------------------------------------------------
1 | // Code generated by goctl. DO NOT EDIT.
2 | // Source: captcha.proto
3 |
4 | package server
5 |
6 | import (
7 | "context"
8 |
9 | "micro/rpc/captcha/captcha"
10 | "micro/rpc/captcha/internal/logic"
11 | "micro/rpc/captcha/internal/svc"
12 | )
13 |
14 | type CaptchaServiceServer struct {
15 | svcCtx *svc.ServiceContext
16 | captcha.UnimplementedCaptchaServiceServer
17 | }
18 |
19 | func NewCaptchaServiceServer(svcCtx *svc.ServiceContext) *CaptchaServiceServer {
20 | return &CaptchaServiceServer{
21 | svcCtx: svcCtx,
22 | }
23 | }
24 |
25 | func (s *CaptchaServiceServer) GenerateCaptcha(ctx context.Context, in *captcha.GenerateCaptchaRequest) (*captcha.GenerateCaptchaResponse, error) {
26 | l := logic.NewGenerateCaptchaLogic(ctx, s.svcCtx)
27 | return l.GenerateCaptcha(in)
28 | }
29 |
30 | func (s *CaptchaServiceServer) VerifyCaptcha(ctx context.Context, in *captcha.VerifyCaptchaRequest) (*captcha.VerifyCaptchaResponse, error) {
31 | l := logic.NewVerifyCaptchaLogic(ctx, s.svcCtx)
32 | return l.VerifyCaptcha(in)
33 | }
34 |
--------------------------------------------------------------------------------
/micro/rpc/user/internal/logic/useridhasbeenexistlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | userModel "micro/model/user"
6 |
7 | "micro/rpc/user/internal/svc"
8 | "micro/rpc/user/userRPC"
9 |
10 | "github.com/zeromicro/go-zero/core/logx"
11 | )
12 |
13 | type UserIDHasBeenExistLogic struct {
14 | ctx context.Context
15 | svcCtx *svc.ServiceContext
16 | logx.Logger
17 | }
18 |
19 | func NewUserIDHasBeenExistLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserIDHasBeenExistLogic {
20 | return &UserIDHasBeenExistLogic{
21 | ctx: ctx,
22 | svcCtx: svcCtx,
23 | Logger: logx.WithContext(ctx),
24 | }
25 | }
26 |
27 | func (l *UserIDHasBeenExistLogic) UserIDHasBeenExist(in *userRPC.DeleteUserRequest) (*userRPC.CommonResponse, error) {
28 | find := l.svcCtx.GormDB.Model(&userModel.User{}).Find(&userModel.User{}, "id = ?", in.Id)
29 | if find.RowsAffected > 0 {
30 | return &userRPC.CommonResponse{
31 | Ok: true,
32 | Msg: "",
33 | }, nil
34 | }
35 |
36 | return &userRPC.CommonResponse{
37 | Ok: false,
38 | Msg: "用户不存在",
39 | }, nil
40 | }
41 |
--------------------------------------------------------------------------------
/server/services/modules/usersAndRoles/usersAndRoles.go:
--------------------------------------------------------------------------------
1 | package usersAndRolesServiceModules
2 |
3 | import (
4 | "errors"
5 | "github.com/Xi-Yuer/cms/dto"
6 | repositories "github.com/Xi-Yuer/cms/repositories/modules"
7 | )
8 |
9 | var UserAndRolesService = &userAndRolesService{}
10 |
11 | type userAndRolesService struct {
12 | }
13 |
14 | func (u *userAndRolesService) FindRoleById(id string) error {
15 | singleRoleResponse := repositories.RoleRepositorysModules.FindRoleById(id)
16 | if singleRoleResponse == nil {
17 | return errors.New("资源不存在")
18 | }
19 | return nil
20 | }
21 |
22 | func (u *userAndRolesService) GetRoles(params *dto.QueryRolesParams) (*dto.HasTotalResponseData, error) {
23 | return repositories.RoleRepositorysModules.GetRoles(params)
24 | }
25 |
26 | func (u *userAndRolesService) UpdateRole(role *dto.UpdateRoleParams, id string) error {
27 | singleRoleResponse := repositories.RoleRepositorysModules.FindRoleById(id)
28 | if singleRoleResponse == nil {
29 | return errors.New("资源不存在")
30 | }
31 | return repositories.RoleRepositorysModules.UpdateRole(role, id)
32 | }
33 |
--------------------------------------------------------------------------------
/micro/rpc/captcha/captcha.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 |
7 | "micro/rpc/captcha/captcha"
8 | "micro/rpc/captcha/internal/config"
9 | "micro/rpc/captcha/internal/server"
10 | "micro/rpc/captcha/internal/svc"
11 |
12 | "github.com/zeromicro/go-zero/core/conf"
13 | "github.com/zeromicro/go-zero/core/service"
14 | "github.com/zeromicro/go-zero/zrpc"
15 | "google.golang.org/grpc"
16 | "google.golang.org/grpc/reflection"
17 | )
18 |
19 | var configFile = flag.String("f", "etc/captcha.yaml", "the config file")
20 |
21 | func main() {
22 | flag.Parse()
23 |
24 | var c config.Config
25 | conf.MustLoad(*configFile, &c)
26 | ctx := svc.NewServiceContext(c)
27 |
28 | s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
29 | captcha.RegisterCaptchaServiceServer(grpcServer, server.NewCaptchaServiceServer(ctx))
30 |
31 | if c.Mode == service.DevMode || c.Mode == service.TestMode {
32 | reflection.Register(grpcServer)
33 | }
34 | })
35 | defer s.Stop()
36 |
37 | fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
38 | s.Start()
39 | }
40 |
--------------------------------------------------------------------------------
/web/src/service/api/timeTask/index.ts:
--------------------------------------------------------------------------------
1 | import request from '@/service/request';
2 | import { AxiosResponse } from 'axios';
3 |
4 | export interface ITimeTaskResponse {
5 | cron: string;
6 | lastRunTime: string;
7 | runTimes: number;
8 | status: boolean;
9 | taskName: string;
10 | timeTaskID: string;
11 | }
12 |
13 | export const getTimeTaskListRequest = () => {
14 | return request.get>({
15 | url: '/timeTask',
16 | });
17 | };
18 |
19 | export const startTimeTaskRequest = (id: string) => {
20 | return request.post({
21 | url: `/timeTask/start/${id}`,
22 | });
23 | };
24 |
25 | export const stopTimeTaskRequest = (id: string) => {
26 | return request.post({
27 | url: `/timeTask/stop/${id}`,
28 | });
29 | };
30 |
31 | export interface IUpdateTimeTaskRequest {
32 | timeTaskName: string;
33 | cron: string;
34 | status: boolean;
35 | }
36 |
37 | export const updateTimeTaskRequest = (id: string, data: IUpdateTimeTaskRequest) => {
38 | return request.patch({
39 | url: `/timeTask/update/${id}`,
40 | data,
41 | });
42 | };
43 |
--------------------------------------------------------------------------------
/web/src/service/api/pages/index.ts:
--------------------------------------------------------------------------------
1 | import request from '@/service/request';
2 | import { menuType } from '@/types/menus';
3 | import { AxiosResponse } from 'axios';
4 |
5 | export const getUserMenusRequest = () => {
6 | return request.get>({
7 | url: '/pages/user',
8 | });
9 | };
10 |
11 | export const getRoleMenusRequest = (id: string) => {
12 | return request.get>({
13 | url: `/pages/role/${id}`,
14 | });
15 | };
16 |
17 | export const getAllMenusRequest = () => {
18 | return request.get>({
19 | url: '/pages',
20 | });
21 | };
22 |
23 | export const deleteMenuRequest = (id: string) => {
24 | return request.delete({
25 | url: `/pages/${id}`,
26 | });
27 | };
28 |
29 | export const updateMenuRequest = (id: string, data: menuType) => {
30 | return request.patch({
31 | url: `/pages/${id}`,
32 | data,
33 | });
34 | };
35 |
36 | export const createMenuRequest = (data: menuType) => {
37 | return request.post({
38 | url: '/pages',
39 | data,
40 | });
41 | };
42 |
--------------------------------------------------------------------------------
/micro/rpc/role/internal/logic/createrolelogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | roleModlel "micro/model/role"
6 | "micro/rpc/role/internal/svc"
7 | "micro/rpc/role/roleRPC"
8 |
9 | "github.com/zeromicro/go-zero/core/logx"
10 | )
11 |
12 | type CreateRoleLogic struct {
13 | ctx context.Context
14 | svcCtx *svc.ServiceContext
15 | logx.Logger
16 | }
17 |
18 | func NewCreateRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateRoleLogic {
19 | return &CreateRoleLogic{
20 | ctx: ctx,
21 | svcCtx: svcCtx,
22 | Logger: logx.WithContext(ctx),
23 | }
24 | }
25 |
26 | func (l *CreateRoleLogic) CreateRole(in *roleRPC.CreateRoleRequest) (*roleRPC.CommonResponse, error) {
27 | role := &roleModlel.Role{
28 | ID: in.Id,
29 | RoleName: in.RoleName,
30 | Description: in.Description,
31 | CanEdit: in.CanEdit,
32 | }
33 | if err := l.svcCtx.GormDB.Create(role).Error; err != nil {
34 | return &roleRPC.CommonResponse{
35 | Ok: false,
36 | Msg: err.Error(),
37 | }, nil
38 | }
39 |
40 | return &roleRPC.CommonResponse{
41 | Ok: true,
42 | Msg: "创建成功",
43 | }, nil
44 | }
45 |
--------------------------------------------------------------------------------
/micro/rpc/role/internal/logic/roleidshasbeenexistlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "errors"
6 | roleModlel "micro/model/role"
7 | "micro/rpc/role/internal/svc"
8 | "micro/rpc/role/roleRPC"
9 |
10 | "github.com/zeromicro/go-zero/core/logx"
11 | )
12 |
13 | type RoleIDsHasBeenExistLogic struct {
14 | ctx context.Context
15 | svcCtx *svc.ServiceContext
16 | logx.Logger
17 | }
18 |
19 | func NewRoleIDsHasBeenExistLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RoleIDsHasBeenExistLogic {
20 | return &RoleIDsHasBeenExistLogic{
21 | ctx: ctx,
22 | svcCtx: svcCtx,
23 | Logger: logx.WithContext(ctx),
24 | }
25 | }
26 |
27 | func (l *RoleIDsHasBeenExistLogic) RoleIDsHasBeenExist(in *roleRPC.RoleIDsHasBeenExistRequest) (*roleRPC.CommonResponse, error) {
28 | var roles []roleModlel.Role
29 | if err := l.svcCtx.GormDB.Where("id in (?)", in.Ids).Find(&roles).Error; err != nil {
30 | return nil, err
31 | }
32 |
33 | if len(roles) != len(in.Ids) {
34 | return nil, errors.New("角色ID不存在")
35 | }
36 |
37 | return &roleRPC.CommonResponse{
38 | Ok: true,
39 | Msg: "",
40 | }, nil
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/micro/rpc/user/internal/logic/useraccounthasbeenexistlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | userModel "micro/model/user"
6 |
7 | "micro/rpc/user/internal/svc"
8 | "micro/rpc/user/userRPC"
9 |
10 | "github.com/zeromicro/go-zero/core/logx"
11 | )
12 |
13 | type UserAccountHasBeenExistLogic struct {
14 | ctx context.Context
15 | svcCtx *svc.ServiceContext
16 | logx.Logger
17 | }
18 |
19 | func NewUserAccountHasBeenExistLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserAccountHasBeenExistLogic {
20 | return &UserAccountHasBeenExistLogic{
21 | ctx: ctx,
22 | svcCtx: svcCtx,
23 | Logger: logx.WithContext(ctx),
24 | }
25 | }
26 |
27 | func (l *UserAccountHasBeenExistLogic) UserAccountHasBeenExist(in *userRPC.UserAccountHasBeenExistRequest) (*userRPC.CommonResponse, error) {
28 | find := l.svcCtx.GormDB.Model(&userModel.User{}).Find(&userModel.User{}, "account = ?", in.Account)
29 | if find.RowsAffected > 0 {
30 | return &userRPC.CommonResponse{
31 | Ok: true,
32 | Msg: "账号已存在",
33 | }, nil
34 | }
35 |
36 | return &userRPC.CommonResponse{
37 | Ok: false,
38 | Msg: "账号不存在",
39 | }, nil
40 | }
41 |
--------------------------------------------------------------------------------
/web/src/main.tsx:
--------------------------------------------------------------------------------
1 | import ReactDOM from 'react-dom/client';
2 | import '@/utils/echarts';
3 | import 'animate.css';
4 | import '@/styles/index.css';
5 | import '@/local/index';
6 | import store from '@/store';
7 | import { Provider } from 'react-redux';
8 | import { PersistGate } from 'redux-persist/integration/react';
9 | import { persistStore } from 'redux-persist';
10 | import { HashRouter } from 'react-router-dom';
11 | import { App as AntdApp, Image, Spin } from 'antd';
12 | import App from '@/App.tsx';
13 | import ErrorBoundary from 'antd/es/alert/ErrorBoundary';
14 | import LoadingGIF from '@/assets/image/loading.gif';
15 |
16 | ReactDOM.createRoot(document.getElementById('root')!).render(
17 |
18 |
19 | } style={{ width: '100px', height: '100px' }}>}
21 | persistor={persistStore(store)}>
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | ,
30 | );
31 |
--------------------------------------------------------------------------------
/micro/api/user/internal/logic/deleteuserlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "micro/api/user/internal/svc"
6 | "micro/api/user/internal/types"
7 | "micro/rpc/user/userRPC"
8 |
9 | "github.com/zeromicro/go-zero/core/logx"
10 | )
11 |
12 | type DeleteUserLogic struct {
13 | logx.Logger
14 | ctx context.Context
15 | svcCtx *svc.ServiceContext
16 | }
17 |
18 | func NewDeleteUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteUserLogic {
19 | return &DeleteUserLogic{
20 | Logger: logx.WithContext(ctx),
21 | ctx: ctx,
22 | svcCtx: svcCtx,
23 | }
24 | }
25 |
26 | func (l *DeleteUserLogic) DeleteUser(req *types.DeleteUserRequest) (resp *types.DeleteUserResponse, err error) {
27 | response, err := l.svcCtx.UserService.DeleteUser(l.ctx, &userRPC.DeleteUserRequest{Id: req.ID})
28 | if err != nil {
29 | return &types.DeleteUserResponse{
30 | Code: 500,
31 | Msg: err.Error(),
32 | }, nil
33 | }
34 | if !response.Ok {
35 | return &types.DeleteUserResponse{
36 | Code: 500,
37 | Msg: response.Msg,
38 | }, nil
39 | }
40 | return &types.DeleteUserResponse{
41 | Code: 200,
42 | Msg: response.Msg,
43 | }, nil
44 | }
45 |
--------------------------------------------------------------------------------
/micro/nginx.conf:
--------------------------------------------------------------------------------
1 | worker_processes auto;
2 | events {
3 | worker_connections 4096;
4 | }
5 |
6 | http {
7 | include mime.types;
8 | default_type application/octet-stream;
9 |
10 | sendfile on;
11 | keepalive_timeout 65;
12 |
13 | upstream auth_api {
14 | server auth-service:8888;
15 | }
16 |
17 | upstream user_api {
18 | server user-service:8889;
19 | }
20 |
21 | server {
22 | listen 80;
23 | server_name localhost;
24 |
25 | location /auth/ {
26 | proxy_pass http://auth_api/;
27 | proxy_set_header Host $host;
28 | proxy_set_header X-Real-IP $remote_addr;
29 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
30 | proxy_set_header X-Forwarded-Proto $scheme;
31 | }
32 |
33 | location /user/ {
34 | proxy_pass http://user_api/;
35 | proxy_set_header Host $host;
36 | proxy_set_header X-Real-IP $remote_addr;
37 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
38 | proxy_set_header X-Forwarded-Proto $scheme;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/web/src/assets/svg/en-zh.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/web/src/assets/svg/zh-en.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/micro/rpc/user/internal/logic/getuserlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | userModel "micro/model/user"
6 |
7 | "micro/rpc/user/internal/svc"
8 | "micro/rpc/user/userRPC"
9 |
10 | "github.com/zeromicro/go-zero/core/logx"
11 | )
12 |
13 | type GetUserLogic struct {
14 | ctx context.Context
15 | svcCtx *svc.ServiceContext
16 | logx.Logger
17 | }
18 |
19 | func NewGetUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserLogic {
20 | return &GetUserLogic{
21 | ctx: ctx,
22 | svcCtx: svcCtx,
23 | Logger: logx.WithContext(ctx),
24 | }
25 | }
26 |
27 | func (l *GetUserLogic) GetUser(in *userRPC.GetUserRequest) (*userRPC.GetUserResponse, error) {
28 | var user userModel.User
29 | if err := l.svcCtx.GormDB.Model(&userModel.User{}).First(&user, in.Id).Error; err != nil {
30 | return nil, err
31 | }
32 | return &userRPC.GetUserResponse{
33 | Id: user.ID,
34 | Account: user.Account,
35 | Nickname: user.NickName,
36 | Avatar: user.Avatar,
37 | Department: user.DepartmentID,
38 | Status: user.Status,
39 | IsAdmin: user.IsAdmin,
40 | CreateTime: user.CreatedAt.String(),
41 | UpdateTime: user.UpdatedAt.String(),
42 | }, nil
43 | }
44 |
--------------------------------------------------------------------------------
/web/src/styles/global/index.css:
--------------------------------------------------------------------------------
1 | .loginBg {
2 | background: url('@/assets/svg/bg.svg');
3 | background-size: contain;
4 | }
5 |
6 | body {
7 | width: 100vw;
8 | height: 100vh;
9 | overflow: hidden;
10 | }
11 |
12 | @-webkit-keyframes fadeInRight {
13 | 0% {
14 | opacity: 0;
15 | -webkit-transform: translate3d(100%, 0, 0);
16 | transform: translate3d(50%, 0, 0);
17 | }
18 | to {
19 | opacity: 1;
20 | -webkit-transform: translateZ(0);
21 | transform: translateZ(0);
22 | }
23 | }
24 |
25 | @keyframes fadeInRight {
26 | 0% {
27 | opacity: 0;
28 | -webkit-transform: translate3d(100%, 0, 0);
29 | transform: translate3d(50%, 0, 0);
30 | }
31 | to {
32 | opacity: 1;
33 | -webkit-transform: translateZ(0);
34 | transform: translateZ(0);
35 | }
36 | }
37 |
38 | /* animations.css */
39 | .enter {
40 | transform: translateY(200%);
41 | }
42 |
43 | .enter-active {
44 | transform: translateY(0%);
45 | transition: all 1s ease;
46 | }
47 |
48 | .exit {
49 | transform: translateY(0%);
50 | }
51 |
52 | .exit-active {
53 | transform: translateY(200%);
54 | transition: all 1s ease;
55 | }
56 |
--------------------------------------------------------------------------------
/server/repositories/modules/commits/commits.go:
--------------------------------------------------------------------------------
1 | package commitsRepositoryModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/db"
5 | "github.com/Xi-Yuer/cms/dto"
6 | )
7 |
8 | var CommitsRepositoryModules = &commitsRepositoryModules{}
9 |
10 | type commitsRepositoryModules struct{}
11 |
12 | func (c *commitsRepositoryModules) GetCommits() []*dto.CommitResponse {
13 | rows, err := db.DB.Query("SELECT commit_id, author, email, commit_date, message FROM cms.commits")
14 | if err != nil {
15 | return nil
16 | }
17 | var commitLogs []*dto.CommitResponse
18 |
19 | for rows.Next() {
20 | var commit dto.CommitResponse
21 | err := rows.Scan(&commit.CommitID, &commit.Author, &commit.Email, &commit.Date, &commit.Message)
22 | if err != nil {
23 | continue
24 | } else {
25 | commitLogs = append(commitLogs, &commit)
26 | }
27 |
28 | }
29 | return commitLogs
30 | }
31 |
32 | func (c *commitsRepositoryModules) GetCommitsCount() (int, error) {
33 | query := "SELECT COUNT(*) FROM cms.commits"
34 | rows, err := db.DB.Query(query)
35 | if err != nil {
36 | return 0, err
37 | }
38 | var count int
39 | for rows.Next() {
40 | err := rows.Scan(&count)
41 | if err != nil {
42 | return 0, err
43 | }
44 | }
45 | return count, nil
46 | }
47 |
--------------------------------------------------------------------------------
/micro/rpc/role/internal/logic/rolenamehasbeenexistlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | roleModlel "micro/model/role"
6 |
7 | "micro/rpc/role/internal/svc"
8 | "micro/rpc/role/roleRPC"
9 |
10 | "github.com/zeromicro/go-zero/core/logx"
11 | )
12 |
13 | type RoleNameHasBeenExistLogic struct {
14 | ctx context.Context
15 | svcCtx *svc.ServiceContext
16 | logx.Logger
17 | }
18 |
19 | func NewRoleNameHasBeenExistLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RoleNameHasBeenExistLogic {
20 | return &RoleNameHasBeenExistLogic{
21 | ctx: ctx,
22 | svcCtx: svcCtx,
23 | Logger: logx.WithContext(ctx),
24 | }
25 | }
26 |
27 | func (l *RoleNameHasBeenExistLogic) RoleNameHasBeenExist(in *roleRPC.RoleNamesHasBeenExistRequest) (*roleRPC.CommonResponse, error) {
28 | count := int64(0)
29 | if err := l.svcCtx.GormDB.Where("role_name = ?", in.Names).First(&roleModlel.Role{}).Count(&count).Error; err != nil {
30 | return &roleRPC.CommonResponse{
31 | Ok: false,
32 | Msg: err.Error(),
33 | }, nil
34 | }
35 | if count > 0 {
36 | return &roleRPC.CommonResponse{
37 | Ok: true,
38 | Msg: "角色名已存在",
39 | }, nil
40 | }
41 | return &roleRPC.CommonResponse{
42 | Ok: false,
43 | Msg: "",
44 | }, nil
45 | }
46 |
--------------------------------------------------------------------------------
/micro/api/user/internal/logic/updateuserlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "micro/api/user/internal/svc"
6 | "micro/api/user/internal/types"
7 | "micro/rpc/user/userRPC"
8 |
9 | "github.com/zeromicro/go-zero/core/logx"
10 | )
11 |
12 | type UpdateUserLogic struct {
13 | logx.Logger
14 | ctx context.Context
15 | svcCtx *svc.ServiceContext
16 | }
17 |
18 | func NewUpdateUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateUserLogic {
19 | return &UpdateUserLogic{
20 | Logger: logx.WithContext(ctx),
21 | ctx: ctx,
22 | svcCtx: svcCtx,
23 | }
24 | }
25 |
26 | func (l *UpdateUserLogic) UpdateUser(req *types.UpdateUserRequest) (resp *types.UpdateUserResponse, err error) {
27 | response, _ := l.svcCtx.UserService.UpdateUser(l.ctx, &userRPC.UpdateUserRequest{
28 | Id: req.ID,
29 | Password: req.Password,
30 | Nickname: req.Nickname,
31 | Avatar: req.Avatar,
32 | Status: req.Status,
33 | Department: req.DepartmentID,
34 | IsAdmin: req.IsAdmin,
35 | })
36 | if response.Ok {
37 | return &types.UpdateUserResponse{
38 | Code: 200,
39 | Msg: response.Msg,
40 | }, nil
41 | }
42 | return &types.UpdateUserResponse{
43 | Code: 500,
44 | Msg: response.Msg,
45 | }, nil
46 | }
47 |
--------------------------------------------------------------------------------
/micro/rpc/captcha/internal/logic/verifycaptchalogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "fmt"
7 |
8 | "micro/rpc/captcha/captcha"
9 | "micro/rpc/captcha/internal/svc"
10 |
11 | "github.com/zeromicro/go-zero/core/logx"
12 | )
13 |
14 | type VerifyCaptchaLogic struct {
15 | ctx context.Context
16 | svcCtx *svc.ServiceContext
17 | logx.Logger
18 | }
19 |
20 | func NewVerifyCaptchaLogic(ctx context.Context, svcCtx *svc.ServiceContext) *VerifyCaptchaLogic {
21 | return &VerifyCaptchaLogic{
22 | ctx: ctx,
23 | svcCtx: svcCtx,
24 | Logger: logx.WithContext(ctx),
25 | }
26 | }
27 |
28 | func (l *VerifyCaptchaLogic) VerifyCaptcha(in *captcha.VerifyCaptchaRequest) (*captcha.VerifyCaptchaResponse, error) {
29 | sessionID := in.GetSessionId()
30 | userInputCode := in.GetCaptchaCode()
31 |
32 | // 从 Redis 中获取存储的验证码
33 | storedCode, err := l.svcCtx.Redis.Get(l.ctx, fmt.Sprintf("captcha:%s", sessionID)).Result()
34 | if err != nil {
35 | return nil, errors.New("验证码已过期,请重新获取")
36 | }
37 |
38 | // 检查存储的验证码是否与用户输入的验证码匹配
39 | valid := storedCode == userInputCode
40 |
41 | // 删除 Redis 中存储的验证码
42 | l.svcCtx.Redis.Del(l.ctx, fmt.Sprintf("captcha:%s", sessionID))
43 |
44 | return &captcha.VerifyCaptchaResponse{
45 | Valid: valid,
46 | }, nil
47 | }
48 |
--------------------------------------------------------------------------------
/server/dto/modules/department/department.go:
--------------------------------------------------------------------------------
1 | package departmentResponsiesModules
2 |
3 | type CreateDepartmentRequest struct {
4 | DepartmentName string `form:"departmentName" binding:"required"`
5 | ParentDepartment *string `form:"parentDepartment"`
6 | DepartmentDescription string `form:"departmentDescription"`
7 | DepartmentOrder int `form:"departmentOrder"`
8 | }
9 |
10 | type DepartmentResponse struct {
11 | ID string `json:"id"`
12 | DepartmentName string `json:"departmentName"`
13 | ParentDepartment *string `json:"parentDepartment"`
14 | DepartmentOrder int `json:"departmentOrder"`
15 | DepartmentDescription *string `json:"departmentDescription"`
16 | Children []*DepartmentResponse `json:"children"`
17 | CreateTime string `json:"createTime"`
18 | UpdateTime string `json:"updateTime"`
19 | }
20 |
21 | type UpdateDepartmentRequest struct {
22 | DepartmentName string `form:"departmentName"`
23 | ParentDepartment string `form:"parentDepartment"`
24 | DepartmentDescription string `json:"departmentDescription"`
25 | DepartmentOrder int `form:"departmentOrder"`
26 | }
27 |
--------------------------------------------------------------------------------
/micro/rpc/role/internal/logic/deleterolelogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "errors"
6 | roleModlel "micro/model/role"
7 |
8 | "micro/rpc/role/internal/svc"
9 | "micro/rpc/role/roleRPC"
10 |
11 | "github.com/zeromicro/go-zero/core/logx"
12 | )
13 |
14 | type DeleteRoleLogic struct {
15 | ctx context.Context
16 | svcCtx *svc.ServiceContext
17 | logx.Logger
18 | }
19 |
20 | func NewDeleteRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteRoleLogic {
21 | return &DeleteRoleLogic{
22 | ctx: ctx,
23 | svcCtx: svcCtx,
24 | Logger: logx.WithContext(ctx),
25 | }
26 | }
27 |
28 | func (l *DeleteRoleLogic) DeleteRole(in *roleRPC.DeleteRoleRequest) (*roleRPC.CommonResponse, error) {
29 | existLogic := NewRoleIDsHasBeenExistLogic(l.ctx, l.svcCtx)
30 | exist, err := existLogic.RoleIDsHasBeenExist(&roleRPC.RoleIDsHasBeenExistRequest{Ids: []string{in.Id}})
31 |
32 | if err != nil {
33 | return nil, err
34 | }
35 |
36 | if !exist.Ok {
37 | return nil, errors.New("角色ID不存在")
38 | }
39 |
40 | if err := l.svcCtx.GormDB.Delete(&roleModlel.Role{}, "id = ?", in.Id).Error; err != nil {
41 | return &roleRPC.CommonResponse{
42 | Ok: false,
43 | Msg: err.Error(),
44 | }, nil
45 | }
46 | return &roleRPC.CommonResponse{
47 | Ok: true,
48 | Msg: "删除成功",
49 | }, nil
50 | }
51 |
--------------------------------------------------------------------------------
/web/src/components/Translate/translate.tsx:
--------------------------------------------------------------------------------
1 | import { FC, memo } from 'react';
2 | import TranslateDark from '@/components/Icon/translateDark.tsx';
3 | import { useTheme } from '@/hooks/useTheme.ts';
4 | import TranslateLight from '@/components/Icon/translateLight.tsx';
5 | import { Dropdown, MenuProps } from 'antd';
6 | import { useTranslation } from 'react-i18next';
7 | import { changeLang } from '@/store/UIStore';
8 | import { useDispatch } from 'react-redux';
9 |
10 | const Translate: FC = () => {
11 | const { themeMode } = useTheme();
12 | const { i18n } = useTranslation();
13 | const dispatch = useDispatch();
14 | const items: MenuProps['items'] = [
15 | {
16 | key: 'zhCN',
17 | label: '简体中文',
18 | },
19 | {
20 | key: 'enUS',
21 | label: 'English',
22 | },
23 | ];
24 | const onClick: MenuProps['onClick'] = async ({ key }) => {
25 | dispatch(changeLang(key as 'zhCN' | 'enUS'));
26 | await i18n.changeLanguage(key === 'zhCN' ? 'zh' : 'en');
27 | };
28 |
29 | return (
30 |
31 |
32 | {themeMode === 'light' ? : }
33 |
34 |
35 | );
36 | };
37 |
38 | export default memo(Translate);
39 |
--------------------------------------------------------------------------------
/web/src/store/UserStore/index.ts:
--------------------------------------------------------------------------------
1 | import { createSlice } from '@reduxjs/toolkit';
2 | import { cache } from '@/utils';
3 | import { constants } from '@/constant';
4 | import { menuType } from '@/types/menus';
5 | import { LoginUserResponseType } from '@/service';
6 |
7 | interface IUserStore {
8 | token: string | null;
9 | userInfo: LoginUserResponseType | undefined;
10 | menus: menuType[];
11 | userInterfaceDic: string[];
12 | }
13 |
14 | const UserStoreSlice = createSlice({
15 | name: 'UserStore',
16 | initialState: {
17 | token: null,
18 | userInfo: undefined,
19 | menus: [],
20 | userInterfaceDic: [],
21 | } as IUserStore,
22 | reducers: {
23 | changeToken(state, action) {
24 | cache.set(constants.localStorage.token, action.payload);
25 | state.token = action.payload;
26 | },
27 | changeUserInfo(state, action) {
28 | state.userInfo = action.payload;
29 | },
30 | changeMenus(state, action) {
31 | state.menus = action.payload;
32 | },
33 | changeAllInterfaceDic(state, action: { payload: string[]; type: string }) {
34 | state.userInterfaceDic = action.payload;
35 | },
36 | },
37 | });
38 |
39 | export default UserStoreSlice.reducer;
40 | export const { changeToken, changeUserInfo, changeMenus, changeAllInterfaceDic } = UserStoreSlice.actions;
41 |
--------------------------------------------------------------------------------
/web/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite';
2 | import react from '@vitejs/plugin-react';
3 | import viteCompression from 'vite-plugin-compression';
4 |
5 | const prefix = `monaco-editor/esm/vs`;
6 |
7 | export default defineConfig({
8 | plugins: [react()],
9 | resolve: {
10 | alias: {
11 | '@': '/src',
12 | },
13 | },
14 | build: {
15 | rollupOptions: {
16 | output: {
17 | manualChunks: {
18 | tsWorker: [`${prefix}/language/typescript/ts.worker`],
19 | editorWorker: [`${prefix}/editor/editor.worker`],
20 | },
21 | chunkFileNames: 'js/[name]-[hash].js', // 引入文件名的名称
22 | entryFileNames: 'js/[name]-[hash].js', // 包的入口文件名称
23 | assetFileNames: '[ext]/[name]-[hash].[ext]', // 资源文件像 字体,图片等
24 | },
25 | plugins: [viteCompression()],
26 | },
27 | target: ['esnext'],
28 | terserOptions: {
29 | enclose: false,
30 | compress: true,
31 | sourceMap: false,
32 | },
33 | },
34 | server: {
35 | proxy: {
36 | '/cms': {
37 | target: 'http://localhost:8081',
38 | changeOrigin: true,
39 | },
40 | },
41 | },
42 | preview: {
43 | proxy: {
44 | '/cms': {
45 | target: 'http://127.124.28.77:8081',
46 | changeOrigin: true,
47 | },
48 | },
49 | },
50 | });
51 |
--------------------------------------------------------------------------------
/micro/rpc/user/internal/logic/getuserbyaccountlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | userModel "micro/model/user"
7 |
8 | "micro/rpc/user/internal/svc"
9 | "micro/rpc/user/userRPC"
10 |
11 | "github.com/zeromicro/go-zero/core/logx"
12 | )
13 |
14 | type GetUserByAccountLogic struct {
15 | ctx context.Context
16 | svcCtx *svc.ServiceContext
17 | logx.Logger
18 | }
19 |
20 | func NewGetUserByAccountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserByAccountLogic {
21 | return &GetUserByAccountLogic{
22 | ctx: ctx,
23 | svcCtx: svcCtx,
24 | Logger: logx.WithContext(ctx),
25 | }
26 | }
27 |
28 | func (l *GetUserByAccountLogic) GetUserByAccount(in *userRPC.GetUserByAccountRequest) (*userRPC.GetUserResponse, error) {
29 | var user *userModel.User
30 | if err := l.svcCtx.GormDB.Model(&userModel.User{}).First(&user, "account = ?", in.Account).Error; err != nil {
31 | fmt.Println(err)
32 | return nil, err
33 | }
34 | return &userRPC.GetUserResponse{
35 | Id: user.ID,
36 | Account: user.Account,
37 | Password: "",
38 | Nickname: user.NickName,
39 | Avatar: user.Avatar,
40 | Status: user.Status,
41 | Department: user.DepartmentID,
42 | IsAdmin: user.IsAdmin,
43 | CreateTime: user.CreatedAt.String(),
44 | UpdateTime: user.UpdatedAt.String(),
45 | }, nil
46 | }
47 |
--------------------------------------------------------------------------------
/web/src/service/api/department/index.ts:
--------------------------------------------------------------------------------
1 | import request from '@/service/request';
2 | import { AxiosResponse } from 'axios';
3 |
4 | export interface IDepartmentResponse {
5 | id: string;
6 | departmentName: string;
7 | parentDepartment: string;
8 | departmentOrder: number;
9 | departmentDescription: string;
10 | children: IDepartmentResponse[];
11 | createTime: string;
12 | updateTime: string;
13 | }
14 |
15 | export interface IAddDepartmentRequest {
16 | departmentName: string;
17 | parentDepartment: string;
18 | departmentOrder: number;
19 | departmentDescription: string;
20 | }
21 |
22 | export const getDepartmentRequest = () => {
23 | return request.get>({
24 | url: '/department',
25 | });
26 | };
27 |
28 | export const addDepartmentRequest = (data: IAddDepartmentRequest) => {
29 | return request.post>({
30 | url: '/department',
31 | data,
32 | });
33 | };
34 |
35 | export const deleteDepartmentRequest = (id: string) => {
36 | return request.delete>({
37 | url: `/department/${id}`,
38 | });
39 | };
40 |
41 | export const updateDepartmentRequest = (id: string, data: IAddDepartmentRequest) => {
42 | return request.patch>({
43 | url: `/department/${id}`,
44 | data,
45 | });
46 | };
47 |
--------------------------------------------------------------------------------
/micro/api/user/internal/logic/createuserlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "micro/rpc/user/userRPC"
6 | "micro/shared/snowflake"
7 | "strconv"
8 |
9 | "micro/api/user/internal/svc"
10 | "micro/api/user/internal/types"
11 |
12 | "github.com/zeromicro/go-zero/core/logx"
13 | )
14 |
15 | type CreateUserLogic struct {
16 | logx.Logger
17 | ctx context.Context
18 | svcCtx *svc.ServiceContext
19 | }
20 |
21 | func NewCreateUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateUserLogic {
22 | return &CreateUserLogic{
23 | Logger: logx.WithContext(ctx),
24 | ctx: ctx,
25 | svcCtx: svcCtx,
26 | }
27 | }
28 |
29 | func (l *CreateUserLogic) CreateUser(req *types.CreateUserRequest) (resp *types.UpdateUserResponse, err error) {
30 | response, _ := l.svcCtx.UserService.CreateUser(l.ctx, &userRPC.CreateUserRequest{
31 | Id: strconv.FormatInt(snowflake.GenID(), 10),
32 | Account: req.Account,
33 | Password: req.Password,
34 | Nickname: req.Nickname,
35 | Avatar: req.Avatar,
36 | Status: req.Status,
37 | Department: req.DepartmentID,
38 | IsAdmin: req.IsAdmin,
39 | })
40 | if response.Ok {
41 | return &types.UpdateUserResponse{
42 | Code: 200,
43 | Msg: response.Msg,
44 | }, nil
45 | }
46 | return &types.UpdateUserResponse{
47 | Code: 500,
48 | Msg: response.Msg,
49 | }, nil
50 | }
51 |
--------------------------------------------------------------------------------
/micro/rpc/role/internal/logic/updaterolelogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/zeromicro/go-zero/core/logx"
7 | roleModlel "micro/model/role"
8 | "micro/rpc/role/internal/svc"
9 | "micro/rpc/role/roleRPC"
10 | )
11 |
12 | type UpdateRoleLogic struct {
13 | ctx context.Context
14 | svcCtx *svc.ServiceContext
15 | logx.Logger
16 | }
17 |
18 | func NewUpdateRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateRoleLogic {
19 | return &UpdateRoleLogic{
20 | ctx: ctx,
21 | svcCtx: svcCtx,
22 | Logger: logx.WithContext(ctx),
23 | }
24 | }
25 |
26 | func (l *UpdateRoleLogic) UpdateRole(in *roleRPC.UpdateRoleRequest) (*roleRPC.CommonResponse, error) {
27 | existLogic := NewRoleIDsHasBeenExistLogic(l.ctx, l.svcCtx)
28 | exist, err := existLogic.RoleIDsHasBeenExist(&roleRPC.RoleIDsHasBeenExistRequest{Ids: []string{in.Id}})
29 |
30 | if err != nil {
31 | return nil, err
32 | }
33 |
34 | if !exist.Ok {
35 | return nil, errors.New("角色ID不存在")
36 | }
37 |
38 | if err = l.svcCtx.GormDB.Model(&roleModlel.Role{}).Where("id = ?", in.Id).Updates(&roleModlel.Role{
39 | RoleName: in.RoleName,
40 | Description: in.Description,
41 | CanEdit: in.CanEdit,
42 | }).Error; err != nil {
43 | return nil, err
44 | }
45 |
46 | return &roleRPC.CommonResponse{
47 | Ok: true,
48 | Msg: "更新成功",
49 | }, nil
50 | }
51 |
--------------------------------------------------------------------------------
/server/utils/modules/translator/translator.go:
--------------------------------------------------------------------------------
1 | package translator
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin/binding"
6 | "github.com/go-playground/locales/en"
7 | "github.com/go-playground/locales/zh"
8 | ut "github.com/go-playground/universal-translator"
9 | "github.com/go-playground/validator/v10"
10 | enTranslations "github.com/go-playground/validator/v10/translations/en"
11 | zhTranslations "github.com/go-playground/validator/v10/translations/zh"
12 | )
13 |
14 | var Trans ut.Translator // 全局验证器
15 |
16 | func ValidatorTrans(locale string) (err error) {
17 | // 修改gin框架中的Validator引擎属性,实现自定制
18 | if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
19 |
20 | zhT := zh.New() // 中文翻译器
21 | enT := en.New() // 英文翻译器
22 | uni := ut.New(enT, zhT, enT)
23 |
24 | // locale 通常取决于 http 请求头的 'Accept-Language'
25 | var ok bool
26 | // 也可以使用 uni.FindTranslator(...) 传入多个locale进行查找
27 | Trans, ok = uni.GetTranslator(locale)
28 | if !ok {
29 | return fmt.Errorf("uni.GetTranslator(%s) failed", locale)
30 | }
31 |
32 | // 注册翻译器
33 | switch locale {
34 | case "en":
35 | err = enTranslations.RegisterDefaultTranslations(v, Trans)
36 | case "zh":
37 | err = zhTranslations.RegisterDefaultTranslations(v, Trans)
38 | default:
39 | err = enTranslations.RegisterDefaultTranslations(v, Trans)
40 | }
41 | return nil
42 | }
43 | return nil
44 | }
45 |
--------------------------------------------------------------------------------
/web/src/styles/common/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | .physicLight {
6 | border-radius: 20px;
7 | background: #ededed;
8 | box-shadow: 9px 9px 18px #c9c9c9,
9 | -9px -9px 18px #ffffff;
10 | }
11 |
12 | .physicLightCard {
13 | border-radius: 10px;
14 | background: #fff;
15 | box-shadow: 9px 9px 18px #c9c9c9,
16 | -9px -9px 18px #ececec;
17 | }
18 |
19 | .physicDark {
20 | border-radius: 20px;
21 | background: #142433;
22 | box-shadow: 9px 9px 18px #272727,
23 | -9px -9px 18px #353535;
24 | }
25 |
26 | .physicDarkDashBoard {
27 | border-radius: 20px;
28 | background: #2e2e2e;
29 | box-shadow: 9px 9px 18px #000000;
30 | }
31 |
32 | .physicDarkCard {
33 | border-radius: 10px;
34 | background: #001624;
35 | box-shadow: 9px 9px 18px #272727,
36 | -9px -9px 18px #2d2d2d;
37 | }
38 |
39 | @layer utilities {
40 | .tran {
41 | transition: all 0.2s ease;
42 | }
43 |
44 | * {
45 | /* Hide scrollbar for Chrome, Safari and Opera */
46 |
47 | .no-scrollbar::-webkit-scrollbar {
48 | display: none;
49 | }
50 |
51 | /* Hide scrollbar for IE, Edge and Firefox */
52 |
53 | .no-scrollbar {
54 | -ms-overflow-style: none; /* IE and Edge */
55 | scrollbar-width: none; /* Firefox */
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/micro/rpc/user/internal/logic/deleteuserlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | userModel "micro/model/user"
6 | "micro/rpc/user/internal/svc"
7 | "micro/rpc/user/userRPC"
8 |
9 | "github.com/zeromicro/go-zero/core/logx"
10 | )
11 |
12 | type DeleteUserLogic struct {
13 | ctx context.Context
14 | svcCtx *svc.ServiceContext
15 | logx.Logger
16 | }
17 |
18 | func NewDeleteUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteUserLogic {
19 | return &DeleteUserLogic{
20 | ctx: ctx,
21 | svcCtx: svcCtx,
22 | Logger: logx.WithContext(ctx),
23 | }
24 | }
25 |
26 | func (l *DeleteUserLogic) DeleteUser(in *userRPC.DeleteUserRequest) (*userRPC.CommonResponse, error) {
27 | existLogic := NewUserIDHasBeenExistLogic(l.ctx, l.svcCtx)
28 | exist, err := existLogic.UserIDHasBeenExist(&userRPC.DeleteUserRequest{Id: in.Id})
29 | if err != nil {
30 | return &userRPC.CommonResponse{
31 | Ok: false,
32 | Msg: err.Error(),
33 | }, err
34 | }
35 | if !exist.Ok {
36 | return &userRPC.CommonResponse{
37 | Ok: false,
38 | Msg: "用户不存在",
39 | }, nil
40 | }
41 | if err := l.svcCtx.GormDB.Where("id = ?", in.Id).Unscoped().Delete(&userModel.User{}).Error; err != nil {
42 | return &userRPC.CommonResponse{
43 | Ok: false,
44 | Msg: err.Error(),
45 | }, nil
46 | }
47 | return &userRPC.CommonResponse{
48 | Ok: true,
49 | Msg: "删除成功",
50 | }, nil
51 | }
52 |
--------------------------------------------------------------------------------
/micro/api/auth/internal/logic/captchalogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "micro/rpc/captcha/captcha"
6 | "micro/shared/snowflake"
7 | "strconv"
8 |
9 | "micro/api/auth/internal/svc"
10 | "micro/api/auth/internal/types"
11 |
12 | "github.com/zeromicro/go-zero/core/logx"
13 | )
14 |
15 | type CaptchaLogic struct {
16 | logx.Logger
17 | ctx context.Context
18 | svcCtx *svc.ServiceContext
19 | }
20 |
21 | func NewCaptchaLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CaptchaLogic {
22 | return &CaptchaLogic{
23 | Logger: logx.WithContext(ctx),
24 | ctx: ctx,
25 | svcCtx: svcCtx,
26 | }
27 | }
28 |
29 | func (l *CaptchaLogic) Captcha(req *types.EmptyRequest) (resp *types.CommonResponse, err error) {
30 | sessionID := strconv.FormatInt(snowflake.GenID(), 10)
31 | generateCaptcha, err := l.svcCtx.CaptchaService.GenerateCaptcha(l.ctx, &captcha.GenerateCaptchaRequest{
32 | SessionId: sessionID,
33 | })
34 |
35 | if err != nil {
36 | return nil, err
37 | }
38 |
39 | return &types.CommonResponse{
40 | Code: 0,
41 | Data: &struct {
42 | Captcha string `json:"captchaCode"`
43 | SessionID string `json:"sessionID"`
44 | CaptchaCode string `json:"captchaBase64Code"`
45 | }{
46 | CaptchaCode: generateCaptcha.CaptchaCode,
47 | Captcha: generateCaptcha.Captcha,
48 | SessionID: sessionID,
49 | },
50 | Msg: "success",
51 | }, nil
52 | }
53 |
--------------------------------------------------------------------------------
/web/src/store/index.ts:
--------------------------------------------------------------------------------
1 | import { combineReducers, configureStore } from '@reduxjs/toolkit';
2 | import { FLUSH, PAUSE, PERSIST, persistReducer, PURGE, REGISTER, REHYDRATE } from 'redux-persist';
3 | import UseUIStoreSlice from '@/store/UIStore';
4 | import UserStoreSlice from '@/store/UserStore';
5 | import useUploadStore from '@/store/UploadStore';
6 | import storage from 'redux-persist/es/storage';
7 | import { useDispatch, useSelector } from 'react-redux';
8 |
9 | const reducers = combineReducers({
10 | UIStore: UseUIStoreSlice,
11 | UserStore: UserStoreSlice,
12 | UploadStore: useUploadStore,
13 | });
14 |
15 | const persistedReducer = persistReducer(
16 | {
17 | key: 'cms',
18 | version: 1,
19 | storage,
20 | whitelist: ['UIStore', 'UserStore'],
21 | blacklist: ['UploadStore'],
22 | },
23 | reducers,
24 | );
25 |
26 | const store = configureStore({
27 | reducer: persistedReducer,
28 | devTools: import.meta.env.NODE_ENV !== 'production',
29 | middleware: (getDefaultMiddleware) =>
30 | getDefaultMiddleware({
31 | serializableCheck: {
32 | ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
33 | },
34 | }),
35 | });
36 |
37 | export type RootState = ReturnType;
38 | export const useAppSelector = (selector: (state: RootState) => T) => useSelector(selector);
39 | export const useAppDispatch = useDispatch;
40 | export default store;
41 |
--------------------------------------------------------------------------------
/web/src/service/request/index.ts:
--------------------------------------------------------------------------------
1 | import Request from '@/service/request/lib';
2 | import { IResponse } from '@/service/request/lib/type.ts';
3 | import { cache, message } from '@/utils';
4 | import { constants } from '@/constant';
5 |
6 | const request = new Request(import.meta.env.VITE_APP_BASE_URL, 1000 * 60, {
7 | requestInterceptor: {
8 | onFulfilled(config) {
9 | const token = cache.get(constants.localStorage.token);
10 | if (token) {
11 | config.headers.Authorization = token;
12 | }
13 | return config;
14 | },
15 | onRejected(error) {
16 | return error;
17 | },
18 | },
19 | responseInterceptor: {
20 | onFulfilled: (value) => {
21 | if (value.data.code > 201) {
22 | message.error(value.data.msg);
23 | }
24 | if (value.data.code == 401) {
25 | cache.clear();
26 | window.location.replace(constants.routePath.login);
27 | message.error('登录过期,请重新登录');
28 | return;
29 | }
30 | return value.data;
31 | },
32 | onRejected(error) {
33 | const { msg } = error.response.data;
34 | message.error(msg);
35 | if (error.response.data.code == 401) {
36 | cache.clear();
37 | window.location.replace(constants.routePath.login);
38 | message.error('登录过期,请重新登录');
39 | return;
40 | }
41 | return error;
42 | },
43 | },
44 | });
45 |
46 | export default request;
47 |
--------------------------------------------------------------------------------
/micro/rpc/role/internal/logic/getrolelogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "errors"
6 | roleModlel "micro/model/role"
7 |
8 | "micro/rpc/role/internal/svc"
9 | "micro/rpc/role/roleRPC"
10 |
11 | "github.com/zeromicro/go-zero/core/logx"
12 | )
13 |
14 | type GetRoleLogic struct {
15 | ctx context.Context
16 | svcCtx *svc.ServiceContext
17 | logx.Logger
18 | }
19 |
20 | func NewGetRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetRoleLogic {
21 | return &GetRoleLogic{
22 | ctx: ctx,
23 | svcCtx: svcCtx,
24 | Logger: logx.WithContext(ctx),
25 | }
26 | }
27 |
28 | func (l *GetRoleLogic) GetRole(in *roleRPC.GetRoleRequest) (*roleRPC.GetRoleResponse, error) {
29 | existLogic := NewRoleIDsHasBeenExistLogic(l.ctx, l.svcCtx)
30 | exist, err := existLogic.RoleIDsHasBeenExist(&roleRPC.RoleIDsHasBeenExistRequest{Ids: []string{in.Id}})
31 |
32 | if err != nil {
33 | return nil, err
34 | }
35 |
36 | if !exist.Ok {
37 | return nil, errors.New("角色ID不存在")
38 | }
39 |
40 | role := roleModlel.Role{}
41 | err = l.svcCtx.GormDB.Model(&roleModlel.Role{}).First(&role, in.Id).Error
42 | if err != nil {
43 | return nil, err
44 | }
45 | return &roleRPC.GetRoleResponse{
46 | Id: role.ID,
47 | RoleName: role.RoleName,
48 | Description: role.Description,
49 | CanEdit: role.CanEdit,
50 | CreateTime: role.CreatedAt.String(),
51 | UpdateTime: role.UpdatedAt.String(),
52 | }, nil
53 | }
54 |
--------------------------------------------------------------------------------
/server/services/modules/department/department.go:
--------------------------------------------------------------------------------
1 | package departmentServiceModules
2 |
3 | import (
4 | "errors"
5 | "github.com/Xi-Yuer/cms/dto"
6 | repositories "github.com/Xi-Yuer/cms/repositories/modules"
7 | "github.com/Xi-Yuer/cms/utils"
8 | )
9 |
10 | var DepartmentService = &departmentService{}
11 |
12 | type departmentService struct{}
13 |
14 | func (d *departmentService) CreateDepartment(params *dto.CreateDepartmentRequest) error {
15 | return repositories.DepartmentRepository.CreateDepartment(params)
16 | }
17 |
18 | func (d *departmentService) DeleteDepartment(id string) error {
19 | if department := repositories.DepartmentRepository.GetDepartmentByID(id); department.ID == "" {
20 | return errors.New("资源不存在")
21 | }
22 | return repositories.DepartmentRepository.DeleteDepartment(id)
23 | }
24 |
25 | func (d *departmentService) GetDepartments() ([]*dto.DepartmentResponse, error) {
26 | department, err := repositories.DepartmentRepository.GetDepartments()
27 | if err != nil {
28 | return nil, err
29 | }
30 | buildDepartment := utils.BuildDepartment(department)
31 | return buildDepartment, nil
32 | }
33 |
34 | func (d *departmentService) UpdateDepartment(id string, params *dto.UpdateDepartmentRequest) error {
35 | if department := repositories.DepartmentRepository.GetDepartmentByID(id); department.ID == "" {
36 | return errors.New("资源不存在")
37 | }
38 | return repositories.DepartmentRepository.UpdateDepartment(id, params)
39 | }
40 |
--------------------------------------------------------------------------------
/micro/rpc/captcha/internal/logic/generatecaptchalogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "math/rand"
7 | "micro/shared/image"
8 | "time"
9 |
10 | "micro/rpc/captcha/captcha"
11 | "micro/rpc/captcha/internal/svc"
12 |
13 | "github.com/zeromicro/go-zero/core/logx"
14 | )
15 |
16 | type GenerateCaptchaLogic struct {
17 | ctx context.Context
18 | svcCtx *svc.ServiceContext
19 | logx.Logger
20 | }
21 |
22 | func NewGenerateCaptchaLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GenerateCaptchaLogic {
23 | return &GenerateCaptchaLogic{
24 | ctx: ctx,
25 | svcCtx: svcCtx,
26 | Logger: logx.WithContext(ctx),
27 | }
28 | }
29 |
30 | func (l *GenerateCaptchaLogic) GenerateCaptcha(in *captcha.GenerateCaptchaRequest) (*captcha.GenerateCaptchaResponse, error) {
31 | sessionID := in.GetSessionId()
32 |
33 | // 生成一个随机的 6 位验证码
34 | code := fmt.Sprintf("%06d", rand.Intn(1000000))
35 |
36 | // 设置验证码的过期时间为 5 分钟后
37 | expiresAt := time.Now().Add(5 * time.Minute).Unix()
38 |
39 | // 将验证码存储到 Redis 中,以 sessionID 为键
40 | if err := l.svcCtx.Redis.Set(l.ctx, fmt.Sprintf("captcha:%s", sessionID), code, 5*time.Minute).Err(); err != nil {
41 | return nil, err
42 | }
43 |
44 | // 生成验证码图片
45 | captchaImage, err := image.GenerateCaptchaImage(code)
46 | if err != nil {
47 | return nil, err
48 | }
49 | return &captcha.GenerateCaptchaResponse{
50 | CaptchaCode: captchaImage,
51 | Captcha: code,
52 | ExpiresAt: expiresAt,
53 | }, nil
54 | }
55 |
--------------------------------------------------------------------------------
/server/controllers/modules/commits/commits.go:
--------------------------------------------------------------------------------
1 | package commitsControllerModules
2 |
3 | import (
4 | repositories "github.com/Xi-Yuer/cms/repositories/modules"
5 | "github.com/Xi-Yuer/cms/utils"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | var CommitsController = &commitsController{}
10 |
11 | type commitsController struct{}
12 |
13 | // GetCommits 获取Git提交记录
14 | // @Summary 获取Git提交记录
15 | // @Description 获取Git提交记录
16 | // @Tags 日志管理
17 | // @Accept json
18 | // @Produce json
19 | // @Success 200 {string} json "{"code":200,"data":{},"msg":"ok"}"
20 | // @Router /log/commits [get]
21 | func (c *commitsController) GetCommits(context *gin.Context) {
22 | commits := repositories.CommitsRepositoryModules.GetCommits()
23 | // 分类提交记录到日期
24 | groupedCommits := utils.GroupCommitsByDate(commits)
25 |
26 | // 格式化为所需的结构
27 | formattedCommits := utils.FormatCommits(groupedCommits)
28 | utils.Response.Success(context, formattedCommits)
29 | }
30 |
31 | // GetCommitsCount 获取Git提交次数
32 | // @Summary 获取Git提交次数
33 | // @Description 获取Git提交次数
34 | // @Tags 日志管理
35 | // @Accept json
36 | // @Produce json
37 | // @Success 200 {string} json "{"code":200,"data":{},"msg":"ok"}"
38 | // @Router /log/commits/count [get]
39 | func (c *commitsController) GetCommitsCount(context *gin.Context) {
40 | count, err := repositories.CommitsRepositoryModules.GetCommitsCount()
41 | if err != nil {
42 | utils.Response.ServerError(context, err.Error())
43 | return
44 | }
45 | utils.Response.Success(context, count)
46 | }
47 |
--------------------------------------------------------------------------------
/micro/shared/token/token.go:
--------------------------------------------------------------------------------
1 | package token
2 |
3 | import (
4 | "fmt"
5 | "github.com/golang-jwt/jwt/v4"
6 | "time"
7 | )
8 |
9 | // 定义一个密钥,用于签名和验证 Token
10 | var jwtKey = []byte("12345699999")
11 |
12 | // Claims 结构定义了 Token 中的声明
13 | type Claims struct {
14 | UserID string `json:"user_id"`
15 | UserAccount string `json:"user_account"`
16 | jwt.StandardClaims
17 | }
18 |
19 | // CreateToken 创建 Token
20 | func CreateToken(userID string, userAccount string) (string, error) {
21 | // 设置 Token 的过期时间
22 | expirationTime := time.Now().Add(24 * 60 * time.Minute)
23 |
24 | // 创建声明
25 | claims := &Claims{
26 | UserID: userID,
27 | UserAccount: userAccount,
28 | StandardClaims: jwt.StandardClaims{
29 | ExpiresAt: expirationTime.Unix(),
30 | },
31 | }
32 |
33 | // 创建 Token 对象并签名
34 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
35 | signedToken, err := token.SignedString(jwtKey)
36 | if err != nil {
37 | return "", err
38 | }
39 |
40 | return signedToken, nil
41 | }
42 |
43 | // VerifyToken 验证
44 | func VerifyToken(tokenString string) (*Claims, error) {
45 | // 解析 Token
46 | token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
47 | return jwtKey, nil
48 | })
49 | if err != nil {
50 | return nil, err
51 | }
52 |
53 | // 检查 Token 的有效性
54 | if claims, ok := token.Claims.(*Claims); ok && token.Valid {
55 | return claims, nil
56 | } else {
57 | return nil, fmt.Errorf("invalid token")
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/server/template/server/service/service.go:
--------------------------------------------------------------------------------
1 | package TableNameService
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/template/server/dto"
5 | "github.com/Xi-Yuer/cms/template/server/repository"
6 | )
7 |
8 | type ServiceInterface interface {
9 | GetTableNameListService(params *TableNameDto.TableNameFindRequestDTO) ([]*TableNameDto.TableNameFindRequestDTO, error)
10 | CreateTableNameRecordService(params *TableNameDto.TableNameCreateRequestDTO) error
11 | UpdateTableNameListService(id string, params *TableNameDto.TableNameUpdateRequestDTO) error
12 | DeleteTableNameRecordService(id string) error
13 | }
14 | type Service struct {
15 | repo TableNameRepository.RepositoryInterface
16 | }
17 |
18 | func NewTableNameService() *Service {
19 | return &Service{
20 | repo: TableNameRepository.NewTableNameRepository(),
21 | }
22 | }
23 |
24 | func (s Service) GetTableNameListService(params *TableNameDto.TableNameFindRequestDTO) ([]*TableNameDto.TableNameFindRequestDTO, error) {
25 | return s.repo.GetTableNameListRepo(params)
26 | }
27 |
28 | func (s Service) CreateTableNameRecordService(params *TableNameDto.TableNameCreateRequestDTO) error {
29 | return s.repo.CreateTableNameRecordRepo(params)
30 | }
31 |
32 | func (s Service) UpdateTableNameListService(id string, params *TableNameDto.TableNameUpdateRequestDTO) error {
33 | return s.repo.UpdateTableNameRecordRepo(id, params)
34 | }
35 |
36 | func (s Service) DeleteTableNameRecordService(id string) error {
37 | return s.repo.DeleteTableNameRecordRepo(id)
38 | }
39 |
--------------------------------------------------------------------------------
/web/src/service/api/interface/index.ts:
--------------------------------------------------------------------------------
1 | import request from '@/service/request';
2 | import { AxiosResponse } from 'axios';
3 |
4 | export interface IInterfaceResponse {
5 | id: string;
6 | interfaceName: string;
7 | interfaceMethod: string;
8 | interfacePageID: string;
9 | interfacePath: string;
10 | interfaceDesc: string;
11 | interfaceDic: string;
12 | createTime: string;
13 | updateTime: string;
14 | }
15 |
16 | export interface IAllPageInterfaceListResponse {
17 | key: string;
18 | children: IInterfaceResponse[];
19 | }
20 |
21 | // 获取页面接口
22 | export const getInterfaceListByPageIDRequest = (id: string) => {
23 | return request.get>({
24 | url: `/interface/page/${id}`,
25 | });
26 | };
27 |
28 | // 按照页面分类获取所有接口
29 | export const getInterfaceAllListRequest = () => {
30 | return request.get>({
31 | url: `/interface`,
32 | });
33 | };
34 |
35 | export const deleteInterfaceRequest = (id: string) => {
36 | return request.delete>({
37 | url: `/interface/${id}`,
38 | });
39 | };
40 |
41 | export const addInterfaceRequest = (data: IInterfaceResponse) => {
42 | return request.post>({
43 | url: `/interface`,
44 | data,
45 | });
46 | };
47 |
48 | export const updateInterfaceRequest = (data: IInterfaceResponse) => {
49 | return request.patch>({
50 | url: `/interface/${data.id}`,
51 | data,
52 | });
53 | };
54 |
--------------------------------------------------------------------------------
/web/src/hooks/useAppRoutes.tsx:
--------------------------------------------------------------------------------
1 | import { RouteObject, useLocation, useNavigate, useRoutes } from 'react-router-dom';
2 | import { useAppSelector } from '@/store';
3 | import { builderMenuRoutes, getFirstMenu } from '@/utils';
4 | import { useEffect, useState } from 'react';
5 | import routes from '@/router';
6 | import NotFond from '@/pages/NotFond';
7 | import { constants } from '@/constant';
8 |
9 | export const useAppRouter = () => {
10 | const navigate = useNavigate();
11 | const { menus, token } = useAppSelector((state) => state.UserStore);
12 | const { pathname } = useLocation();
13 | const [routesWithMenus, setRoutesWithMenus] = useState([]);
14 |
15 | useEffect(() => {
16 | if (!token) {
17 | navigate(constants.routePath.login, { replace: true });
18 | }
19 | }, [token, navigate]);
20 |
21 | useEffect(() => {
22 | const routesWithDynamicMenus = [...routes]; // 假设 routes 是一个外部定义的数组
23 | routesWithDynamicMenus[1].children = builderMenuRoutes(menus);
24 | routesWithDynamicMenus[1].children?.push({
25 | path: '*',
26 | element: ,
27 | });
28 |
29 | setRoutesWithMenus(routesWithDynamicMenus);
30 | if (pathname === constants.routePath.main) {
31 | if (!menus.length) return;
32 | const firstMenuPath = getFirstMenu(menus)?.pagePath || constants.routePath.login;
33 | navigate(firstMenuPath);
34 | }
35 | }, [menus, pathname, navigate]);
36 |
37 | return {
38 | element: useRoutes(routesWithMenus),
39 | };
40 | };
41 |
--------------------------------------------------------------------------------
/server/utils/utils.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/utils/modules/bcrypt"
5 | "github.com/Xi-Yuer/cms/utils/modules/buildTree"
6 | "github.com/Xi-Yuer/cms/utils/modules/buildZip"
7 | "github.com/Xi-Yuer/cms/utils/modules/captcha"
8 | "github.com/Xi-Yuer/cms/utils/modules/contain"
9 | "github.com/Xi-Yuer/cms/utils/modules/exportExcel"
10 | "github.com/Xi-Yuer/cms/utils/modules/file"
11 | "github.com/Xi-Yuer/cms/utils/modules/jwt"
12 | "github.com/Xi-Yuer/cms/utils/modules/logs"
13 | "github.com/Xi-Yuer/cms/utils/modules/response"
14 | "github.com/Xi-Yuer/cms/utils/modules/snowflake"
15 | "github.com/Xi-Yuer/cms/utils/modules/timeTask"
16 | "github.com/Xi-Yuer/cms/utils/modules/translator"
17 | "github.com/Xi-Yuer/cms/utils/modules/unique"
18 | )
19 |
20 | var Log = logsModules.Log
21 | var Response = responseModules.Response
22 | var GenID = snowflake.GenID
23 | var Bcrypt = &bcrypt.Bcrypt{}
24 | var Translator = translator.ValidatorTrans
25 | var Trans = translator.Trans
26 | var Captcha = &captcha.Captcha{}
27 | var Jsonwebtoken = &jwt.Jsonwebtoken{}
28 | var Unique = unique.RemoveDuplicatesAndEmpty
29 | var BuildPages = buildTree.BuildMenu
30 | var BuildDepartment = buildTree.BuildDepartment
31 | var Contain = contain.StringInSlice
32 | var ExportExcel = exportExcel.ExportExcel
33 | var TimeTask = timeTask.TimeTask
34 | var File = file.File
35 | var FormatCommits = buildTree.FormatCommits
36 | var GroupCommitsByDate = buildTree.GroupCommitsByDate
37 | var CreateFilesAndZip = buildZip.CreateFilesAndZip
38 |
--------------------------------------------------------------------------------
/server/services/modules/interface/interface.go:
--------------------------------------------------------------------------------
1 | package interfaceServiceModules
2 |
3 | import (
4 | "errors"
5 | "github.com/Xi-Yuer/cms/dto"
6 | repositories "github.com/Xi-Yuer/cms/repositories/modules"
7 | )
8 |
9 | var InterfaceService = &interfaceService{}
10 |
11 | type interfaceService struct{}
12 |
13 | func (i *interfaceService) CreateInterface(params *dto.CreateInterfaceRequest) error {
14 | return repositories.InterfaceRepository.CreateInterface(params)
15 | }
16 |
17 | func (i *interfaceService) GetInterfaceByPageID(id string) []*dto.GetInterfaceResponse {
18 | return repositories.InterfaceRepository.GetInterfaceByPageID(id)
19 | }
20 |
21 | func (i *interfaceService) UpdateInterfaceByID(id string, params *dto.UpdateInterfaceRequest) error {
22 | inter, exist := repositories.InterfaceRepository.GetInterfaceByID(id)
23 | if !exist {
24 | return errors.New("资源不存在")
25 | }
26 | if !inter.CanEdit {
27 | return errors.New("该资源无法修改")
28 | }
29 | return repositories.InterfaceRepository.UpdateInterfaceByID(id, params)
30 | }
31 |
32 | func (i *interfaceService) DeleteInterfaceByID(id string) error {
33 | inter, exist := repositories.InterfaceRepository.GetInterfaceByID(id)
34 | if !exist {
35 | return errors.New("资源不存在")
36 | }
37 | if !inter.CanEdit {
38 | return errors.New("该资源无法删除")
39 | }
40 | return repositories.InterfaceRepository.DeleteInterfaceByID(id)
41 | }
42 |
43 | func (i *interfaceService) GetAllInterface() ([]*dto.AllInterfaceResponse, error) {
44 | return repositories.InterfaceRepository.GetAllInterface()
45 | }
46 |
--------------------------------------------------------------------------------
/server/middlewares/modules/logs/logs.go:
--------------------------------------------------------------------------------
1 | package systemLogsMiddlewareModule
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/constant"
5 | "github.com/Xi-Yuer/cms/dto"
6 | repositories "github.com/Xi-Yuer/cms/repositories/modules"
7 | "github.com/Xi-Yuer/cms/utils"
8 | "github.com/gin-gonic/gin"
9 | "time"
10 | )
11 |
12 | var SystemLogMiddlewareModule = &systemLogMiddlewareModule{}
13 |
14 | type systemLogMiddlewareModule struct{}
15 |
16 | // SystemLogMiddleware 系统日志中间件
17 | // 用于记录系统日志的中间件
18 | // 例如:记录请求的URL、请求的方法、请求的参数、请求的IP地址等
19 | // 还可以记录响应的状态码、响应的时间等
20 | // 可以根据需要记录更多的信息
21 | // 该中间件可以用于记录系统日志,以便进行问题排查和分析
22 | func (m *systemLogMiddlewareModule) SystemLogMiddleware(context *gin.Context) {
23 | path := context.Request.URL.Path
24 | methods := context.Request.Method
25 | status := context.Writer.Status()
26 | ip := context.ClientIP()
27 | start := time.Now()
28 | context.Next()
29 | duration := time.Since(start)
30 | user := &dto.JWTPayload{}
31 | value, exists := context.Get(constant.JWTPAYLOAD)
32 | if !exists {
33 | user.Account = "未登录用户"
34 | user.ID = ""
35 | } else {
36 | user = value.(*dto.JWTPayload)
37 | }
38 | params := dto.CreateLogRecordRequest{
39 | ID: utils.GenID(),
40 | UserName: user.Account,
41 | UserID: user.ID,
42 | UserIP: ip,
43 | RequestMethod: methods,
44 | RequestPath: path,
45 | RequestStatus: status,
46 | RequestDuration: duration.String(),
47 | }
48 | go func() {
49 | _ = repositories.LogsRepository.CreateLogRecord(¶ms)
50 | }()
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/server/services/service.go:
--------------------------------------------------------------------------------
1 | package services
2 |
3 | import (
4 | authServiceModules "github.com/Xi-Yuer/cms/services/modules/auth"
5 | departmentServiceModules "github.com/Xi-Yuer/cms/services/modules/department"
6 | interfaceServiceModules "github.com/Xi-Yuer/cms/services/modules/interface"
7 | logsServiceModules "github.com/Xi-Yuer/cms/services/modules/logs"
8 | pagesServiceModules "github.com/Xi-Yuer/cms/services/modules/pages"
9 | rolesServiceModules "github.com/Xi-Yuer/cms/services/modules/roles"
10 | rolesAndInterfacesServiceModules "github.com/Xi-Yuer/cms/services/modules/rolesAndInterfaces"
11 | templateServiceModule "github.com/Xi-Yuer/cms/services/modules/template"
12 | timeTaskServiceModules "github.com/Xi-Yuer/cms/services/modules/timeTask"
13 | uploadServiceModules "github.com/Xi-Yuer/cms/services/modules/upload"
14 | userServiceModules "github.com/Xi-Yuer/cms/services/modules/users"
15 | )
16 |
17 | var UserService = userServiceModules.UserService
18 | var AuthService = authServiceModules.AuthService
19 | var RoleService = rolesServiceModules.RolesService
20 | var PageService = pagesServiceModules.PageService
21 | var DepartmentService = departmentServiceModules.DepartmentService
22 | var InterfaceService = interfaceServiceModules.InterfaceService
23 | var LogsService = logsServiceModules.LogsService
24 | var RolesAndInterfacesService = rolesAndInterfacesServiceModules.RolesAndInterfacesService
25 | var TimeTaskService = timeTaskServiceModules.TimeTaskService
26 | var UploadService = uploadServiceModules.UploadService
27 | var TemplateService = templateServiceModule.TemplateService
28 |
--------------------------------------------------------------------------------
/web/src/utils/message/index.tsx:
--------------------------------------------------------------------------------
1 | import { JointContent } from 'antd/es/message/interface';
2 |
3 | export const MESSAGE_EVENT_NAME = 'show_message';
4 |
5 | export enum MESSAGE_TYPES {
6 | SUCCESS = 'success',
7 | ERROR = 'error',
8 | INFO = 'info',
9 | WARNING = 'warning',
10 | LOADING = 'loading',
11 | }
12 |
13 | const dispatch = (type: MESSAGE_TYPES, content: JointContent, duration?: number | VoidFunction, onClose?: VoidFunction) => {
14 | window.dispatchEvent(
15 | new CustomEvent(MESSAGE_EVENT_NAME, {
16 | detail: {
17 | params: {
18 | content,
19 | duration,
20 | onClose,
21 | },
22 | type: type,
23 | },
24 | }),
25 | );
26 | };
27 |
28 | export const message = {
29 | success(content: JointContent, duration?: number | VoidFunction, onClose?: VoidFunction) {
30 | dispatch(MESSAGE_TYPES.SUCCESS, content, duration, onClose);
31 | },
32 | error(content: JointContent, duration?: number | VoidFunction, onClose?: VoidFunction) {
33 | dispatch(MESSAGE_TYPES.ERROR, content, duration, onClose);
34 | },
35 | info(content: JointContent, duration?: number | VoidFunction, onClose?: VoidFunction) {
36 | dispatch(MESSAGE_TYPES.INFO, content, duration, onClose);
37 | },
38 | warning(content: JointContent, duration?: number | VoidFunction, onClose?: VoidFunction) {
39 | dispatch(MESSAGE_TYPES.WARNING, content, duration, onClose);
40 | },
41 | loading(content: JointContent, duration?: number | VoidFunction, onClose?: VoidFunction) {
42 | dispatch(MESSAGE_TYPES.LOADING, content, duration, onClose);
43 | },
44 | };
45 |
--------------------------------------------------------------------------------
/server/dto/modules/roles/roles.go:
--------------------------------------------------------------------------------
1 | package rolesResponsiesModules
2 |
3 | type CreateRoleParams struct {
4 | RoleName string `json:"roleName" form:"roleName" binding:"required"`
5 | Description string `json:"description" form:"description" binding:"required"`
6 | PageID []string `form:"pageID" json:"pageID"`
7 | InterfaceID []string `form:"interfaceID" json:"interfaceID"`
8 | }
9 |
10 | type UpdateRoleParams struct {
11 | RoleName string `json:"roleName" form:"roleName"`
12 | Description string `json:"description" form:"description"`
13 | PageID []string `json:"pageID" form:"pageID"`
14 | InterfaceID []string `form:"interfaceID" json:"interfaceID"`
15 | }
16 |
17 | type QueryRoleListParams struct {
18 | ID string `form:"id"`
19 | Limit int `form:"limit"`
20 | Offset int `form:"offset"`
21 | RoleName string `form:"roleName"`
22 | Description string `form:"description"`
23 | StartTime string `form:"startTime"`
24 | EndTime string `form:"endTime"`
25 | }
26 |
27 | type SingleRoleResponse struct {
28 | ID string `json:"id"`
29 | RoleName string `json:"roleName"`
30 | Description string `json:"description"`
31 | CanEdit int
32 | PageID []string `json:"pageID"`
33 | InterfaceID []string `json:"interfaceID"`
34 | CreateTime string `json:"createTime"`
35 | UpdateTime string `json:"updateTime"`
36 | }
37 |
38 | type CreateOneRecord struct {
39 | UserID string `form:"userID"`
40 | RoleID string `form:"roleID"`
41 | }
42 |
43 | type DeleteOneRecord struct {
44 | UserID string `form:"userID"`
45 | RoleID string `form:"roleID"`
46 | }
47 |
--------------------------------------------------------------------------------
/micro/rpc/captcha/captchaservice/captchaservice.go:
--------------------------------------------------------------------------------
1 | // Code generated by goctl. DO NOT EDIT.
2 | // Source: captcha.proto
3 |
4 | package captchaservice
5 |
6 | import (
7 | "context"
8 |
9 | "micro/rpc/captcha/captcha"
10 |
11 | "github.com/zeromicro/go-zero/zrpc"
12 | "google.golang.org/grpc"
13 | )
14 |
15 | type (
16 | GenerateCaptchaRequest = captcha.GenerateCaptchaRequest
17 | GenerateCaptchaResponse = captcha.GenerateCaptchaResponse
18 | VerifyCaptchaRequest = captcha.VerifyCaptchaRequest
19 | VerifyCaptchaResponse = captcha.VerifyCaptchaResponse
20 |
21 | CaptchaService interface {
22 | GenerateCaptcha(ctx context.Context, in *GenerateCaptchaRequest, opts ...grpc.CallOption) (*GenerateCaptchaResponse, error)
23 | VerifyCaptcha(ctx context.Context, in *VerifyCaptchaRequest, opts ...grpc.CallOption) (*VerifyCaptchaResponse, error)
24 | }
25 |
26 | defaultCaptchaService struct {
27 | cli zrpc.Client
28 | }
29 | )
30 |
31 | func NewCaptchaService(cli zrpc.Client) CaptchaService {
32 | return &defaultCaptchaService{
33 | cli: cli,
34 | }
35 | }
36 |
37 | func (m *defaultCaptchaService) GenerateCaptcha(ctx context.Context, in *GenerateCaptchaRequest, opts ...grpc.CallOption) (*GenerateCaptchaResponse, error) {
38 | client := captcha.NewCaptchaServiceClient(m.cli.Conn())
39 | return client.GenerateCaptcha(ctx, in, opts...)
40 | }
41 |
42 | func (m *defaultCaptchaService) VerifyCaptcha(ctx context.Context, in *VerifyCaptchaRequest, opts ...grpc.CallOption) (*VerifyCaptchaResponse, error) {
43 | client := captcha.NewCaptchaServiceClient(m.cli.Conn())
44 | return client.VerifyCaptcha(ctx, in, opts...)
45 | }
46 |
--------------------------------------------------------------------------------
/micro/rpc/user/internal/logic/updateuserlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | userModel "micro/model/user"
6 |
7 | "micro/rpc/user/internal/svc"
8 | "micro/rpc/user/userRPC"
9 |
10 | "github.com/zeromicro/go-zero/core/logx"
11 | )
12 |
13 | type UpdateUserLogic struct {
14 | ctx context.Context
15 | svcCtx *svc.ServiceContext
16 | logx.Logger
17 | }
18 |
19 | func NewUpdateUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateUserLogic {
20 | return &UpdateUserLogic{
21 | ctx: ctx,
22 | svcCtx: svcCtx,
23 | Logger: logx.WithContext(ctx),
24 | }
25 | }
26 |
27 | func (l *UpdateUserLogic) UpdateUser(in *userRPC.UpdateUserRequest) (*userRPC.CommonResponse, error) {
28 | existLogic := NewUserIDHasBeenExistLogic(l.ctx, l.svcCtx)
29 | exist, err := existLogic.UserIDHasBeenExist(&userRPC.DeleteUserRequest{Id: in.Id})
30 |
31 | if err != nil {
32 | return &userRPC.CommonResponse{
33 | Ok: false,
34 | Msg: err.Error(),
35 | }, err
36 | }
37 | if !exist.Ok {
38 | return &userRPC.CommonResponse{
39 | Ok: false,
40 | Msg: "用户不存在",
41 | }, nil
42 | }
43 |
44 | if err := l.svcCtx.GormDB.Model(&userModel.User{}).Where("id", in.Id).Updates(&userModel.User{
45 | Password: in.Password,
46 | NickName: in.Nickname,
47 | Avatar: in.Avatar,
48 | Status: in.Status,
49 | DepartmentID: in.Department,
50 | IsAdmin: in.IsAdmin,
51 | }).Error; err != nil {
52 | return &userRPC.CommonResponse{
53 | Ok: false,
54 | Msg: err.Error(),
55 | }, nil
56 | }
57 | return &userRPC.CommonResponse{
58 | Ok: true,
59 | Msg: "更新成功",
60 | }, nil
61 | }
62 |
--------------------------------------------------------------------------------
/micro/rpc/role/internal/logic/getrolelistlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "github.com/zeromicro/go-zero/core/logx"
6 | roleModlel "micro/model/role"
7 | "micro/rpc/role/internal/svc"
8 | "micro/rpc/role/roleRPC"
9 | )
10 |
11 | type GetRoleListLogic struct {
12 | ctx context.Context
13 | svcCtx *svc.ServiceContext
14 | logx.Logger
15 | }
16 |
17 | func NewGetRoleListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetRoleListLogic {
18 | return &GetRoleListLogic{
19 | ctx: ctx,
20 | svcCtx: svcCtx,
21 | Logger: logx.WithContext(ctx),
22 | }
23 | }
24 |
25 | func (l *GetRoleListLogic) GetRoleList(in *roleRPC.GetRoleListRequest) (*roleRPC.GetUserListResponse, error) {
26 | total := int64(0)
27 | roleList := make([]*roleModlel.Role, 0)
28 | err := l.svcCtx.GormDB.Find(&roleList).Where(roleModlel.Role{
29 | ID: in.Id,
30 | RoleName: in.RoleName,
31 | Description: in.Description,
32 | CanEdit: in.CanEdit,
33 | }).Offset(int(in.Page)).Limit(int(in.PageSize)).Count(&total).Error
34 |
35 | if err != nil {
36 | return nil, err
37 | }
38 |
39 | roleListRPC := make([]*roleRPC.GetRoleResponse, 0)
40 |
41 | for _, role := range roleList {
42 | roleListRPC = append(roleListRPC, &roleRPC.GetRoleResponse{
43 | Id: role.ID,
44 | RoleName: role.RoleName,
45 | Description: role.Description,
46 | CanEdit: role.CanEdit,
47 | CreateTime: role.CreatedAt.String(),
48 | UpdateTime: role.UpdatedAt.String(),
49 | })
50 | }
51 |
52 | return &roleRPC.GetUserListResponse{
53 | Total: int32(total),
54 | RoleList: roleListRPC,
55 | }, nil
56 | }
57 |
--------------------------------------------------------------------------------
/web/src/service/api/template/index.ts:
--------------------------------------------------------------------------------
1 | import request from '@/service/request';
2 | import { AxiosResponse } from 'axios';
3 |
4 | interface Field {
5 | name: string;
6 | type: string;
7 | default: string;
8 | }
9 |
10 | export interface ICreateTemplateParams {
11 | package: string;
12 | tableName: string;
13 | fields: Field[];
14 | }
15 |
16 | export interface ICreateTemplateResponse {
17 | server: server;
18 | web: web;
19 | }
20 |
21 | export interface server {
22 | controllerFile: code;
23 | serviceFile: code;
24 | repositoryFile: code;
25 | routeFile: code;
26 | dtoFile: code;
27 | }
28 |
29 | export interface web {
30 | react: reactType;
31 | }
32 |
33 | export interface reactType {
34 | searchForm: code;
35 | table: code;
36 | tableHook: code;
37 | }
38 |
39 | export interface code {
40 | code: string;
41 | lang: string;
42 | }
43 |
44 | export interface IDownloadTemplateParams {
45 | tableName: string;
46 | controller: string | undefined;
47 | service: string | undefined;
48 | repository: string | undefined;
49 | route: string | undefined;
50 | dto: string | undefined;
51 | searchForm: string | undefined;
52 | table: string | undefined;
53 | tableHook: string | undefined;
54 | }
55 |
56 | export const createTemplateRequest = (data: ICreateTemplateParams) => {
57 | return request.post>({
58 | url: '/template',
59 | data: data,
60 | });
61 | };
62 |
63 | export const downloadTemplateRequest = (data: IDownloadTemplateParams) => {
64 | return request.post({
65 | url: '/template/download',
66 | data: data,
67 | responseType: 'blob',
68 | });
69 | };
70 |
--------------------------------------------------------------------------------
/web/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { memo, useEffect } from 'react';
2 | import { useAppDispatch, useAppSelector } from '@/store';
3 | import { ConfigProvider, message } from 'antd';
4 | import { constants } from '@/constant';
5 | import { changeThemeMode } from '@/store/UIStore';
6 | import { useAppRouter } from '@/hooks/useAppRoutes.tsx';
7 | import 'dayjs/locale/zh-cn';
8 | import dayjs from 'dayjs';
9 | import { useTheme } from '@/theme';
10 | import { MESSAGE_EVENT_NAME } from '@/utils';
11 | import { MessageInstance } from 'antd/es/message/interface';
12 |
13 | dayjs.locale('zh-cn');
14 |
15 | const APP = () => {
16 | const [theme] = useTheme();
17 | const [api, contextHolder] = message.useMessage();
18 | const { langMode, themeMode } = useAppSelector((state) => state.UIStore);
19 | const dispatch = useAppDispatch();
20 | const { element } = useAppRouter();
21 | useEffect(() => {
22 | dispatch(changeThemeMode(themeMode));
23 | }, [dispatch, themeMode]);
24 |
25 | useEffect(() => {
26 | const bindEvent = (e: CustomEvent | any) => {
27 | const func: keyof MessageInstance = e?.detail?.type || 'info';
28 | const { content, duration, onClose } = e.detail?.params;
29 | api[func](content, duration, onClose);
30 | };
31 |
32 | window.addEventListener(MESSAGE_EVENT_NAME, bindEvent);
33 |
34 | return () => {
35 | window.removeEventListener(MESSAGE_EVENT_NAME, bindEvent);
36 | };
37 | }, [api]);
38 |
39 | return (
40 | <>
41 | {contextHolder}
42 |
43 | {element}
44 |
45 | >
46 | );
47 | };
48 |
49 | export default memo(APP);
50 |
--------------------------------------------------------------------------------
/micro/rpc/user/internal/logic/createuserlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | userModel "micro/model/user"
6 |
7 | "micro/rpc/user/internal/svc"
8 | "micro/rpc/user/userRPC"
9 |
10 | "github.com/zeromicro/go-zero/core/logx"
11 | )
12 |
13 | type CreateUserLogic struct {
14 | ctx context.Context
15 | svcCtx *svc.ServiceContext
16 | logx.Logger
17 | }
18 |
19 | func NewCreateUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateUserLogic {
20 | return &CreateUserLogic{
21 | ctx: ctx,
22 | svcCtx: svcCtx,
23 | Logger: logx.WithContext(ctx),
24 | }
25 | }
26 |
27 | func (l *CreateUserLogic) CreateUser(in *userRPC.CreateUserRequest) (*userRPC.CommonResponse, error) {
28 | beenExistLogic := NewUserAccountHasBeenExistLogic(l.ctx, l.svcCtx)
29 | exist, err := beenExistLogic.UserAccountHasBeenExist(&userRPC.UserAccountHasBeenExistRequest{
30 | Account: in.Account,
31 | })
32 | if err != nil {
33 | return &userRPC.CommonResponse{
34 | Ok: false,
35 | Msg: err.Error(),
36 | }, err
37 | }
38 | if exist.Ok {
39 | return &userRPC.CommonResponse{
40 | Ok: false,
41 | Msg: "用户名已存在",
42 | }, nil
43 | }
44 | if err := l.svcCtx.GormDB.Create(&userModel.User{
45 | ID: in.Id,
46 | Account: in.Account,
47 | Password: in.Password,
48 | Avatar: in.Avatar,
49 | NickName: in.Nickname,
50 | DepartmentID: in.Department,
51 | Status: in.Status,
52 | IsAdmin: in.IsAdmin,
53 | }).Error; err != nil {
54 | return &userRPC.CommonResponse{
55 | Ok: false,
56 | Msg: err.Error(),
57 | }, nil
58 | }
59 | return &userRPC.CommonResponse{
60 | Ok: true,
61 | Msg: "创建成功",
62 | }, nil
63 | }
64 |
--------------------------------------------------------------------------------
/server/dto/modules/interface/interface.go:
--------------------------------------------------------------------------------
1 | package interfaceResponsiesModules
2 |
3 | type CreateInterfaceRequest struct {
4 | InterfaceName string `form:"interfaceName" binding:"required"`
5 | InterfaceMethod string `form:"interfaceMethod" binding:"required"`
6 | InterfacePageID string `form:"interfacePageID" binding:"required"`
7 | InterfacePath string `form:"interfacePath" binding:"required"`
8 | InterfaceDesc string `form:"interfaceDesc" binding:"required"`
9 | InterfaceDic string `form:"interfaceDic" binding:"required"`
10 | }
11 |
12 | type GetInterfaceResponse struct {
13 | ID string `json:"id"`
14 | InterfaceName string `json:"interfaceName"`
15 | InterfaceMethod string `json:"interfaceMethod"`
16 | InterfacePageID string `json:"interfacePageID" `
17 | InterfacePath string `json:"interfacePath" `
18 | InterfaceDesc string `json:"interfaceDesc"`
19 | InterfaceDic string `json:"interfaceDic"`
20 | CanEdit bool `json:"canEdit"`
21 | CreateTime string `json:"createTime"`
22 | UpdateTime string `json:"updateTime"`
23 | }
24 |
25 | type UpdateInterfaceRequest struct {
26 | InterfaceName string `form:"interfaceName" binding:"required"`
27 | InterfaceMethod string `form:"interfaceMethod" binding:"required"`
28 | InterfacePageID string `form:"interfacePageID" binding:"required"`
29 | InterfacePath string `form:"interfacePath" binding:"required"`
30 | InterfaceDesc string `form:"interfaceDesc" binding:"required"`
31 | InterfaceDic string `form:"interfaceDic" binding:"required"`
32 | }
33 |
34 | type AllInterfaceResponse struct {
35 | Key string `json:"key"`
36 | Children []*GetInterfaceResponse `json:"children"`
37 | }
38 |
--------------------------------------------------------------------------------
/web/src/service/api/file/index.ts:
--------------------------------------------------------------------------------
1 | import request from '@/service/request';
2 | import { IHasTotalResponse, Page } from '@/service';
3 | import { AxiosResponse } from 'axios';
4 |
5 | export interface FileResponse {
6 | fileID: string;
7 | fileName: string;
8 | fileSize: number;
9 | uploadUser: string;
10 | uploadTime: string;
11 | }
12 |
13 | export const getFileList = (params: Page) => {
14 | return request.get>>({
15 | url: '/upload',
16 | params,
17 | });
18 | };
19 |
20 | export interface IUploadFileChunk {
21 | identifier: string;
22 | file: Blob;
23 | }
24 |
25 | export const uploadFileChunk = (params: IUploadFileChunk) => {
26 | const formData = new FormData();
27 | formData.append('file', params.file);
28 | formData.append('identifier', params.identifier);
29 | return request.post({
30 | url: '/upload ',
31 | data: formData,
32 | });
33 | };
34 |
35 | export const checkFileUploadSize = (identifier: string) => {
36 | return request.post>({
37 | url: '/upload/check',
38 | data: {
39 | identifier,
40 | },
41 | });
42 | };
43 |
44 | export interface IMergeFileChunk {
45 | identifier: string;
46 | fileName: string;
47 | fileSize: number;
48 | }
49 |
50 | export const mergeFileChunk = (data: IMergeFileChunk) => {
51 | return request.post({
52 | url: '/upload/finish',
53 | data,
54 | });
55 | };
56 |
57 | export const deleteFileRequest = (fileID: string) => {
58 | return request.delete({
59 | url: `/upload/del/${fileID}`,
60 | });
61 | };
62 |
63 | export const getCookie = () => {
64 | return request.get({
65 | url: '/auth/cookie',
66 | });
67 | };
68 |
--------------------------------------------------------------------------------
/server/utils/modules/exportExcel/exportExcel.go:
--------------------------------------------------------------------------------
1 | package exportExcel
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/xuri/excelize/v2"
6 | )
7 |
8 | func ExportExcel(context *gin.Context, data [][]interface{}, fileName string) error {
9 | file := excelize.NewFile()
10 | // 创建一个工作表
11 | sheet := "sheet1"
12 |
13 | if err := file.SetSheetName(sheet, fileName); err != nil {
14 | return err
15 | }
16 | if err := file.SetColWidth(sheet, "A", "Z", 20); err != nil {
17 | return err
18 | }
19 | // 设置标题样式
20 | titleStyle, err := file.NewStyle(&excelize.Style{Font: &excelize.Font{Bold: true, VertAlign: "center"}, Fill: excelize.Fill{Color: []string{"#cccccc"}, Type: "pattern", Pattern: 1}})
21 |
22 | // 设置数据样式
23 | dataStyle, err := file.NewStyle(&excelize.Style{Font: &excelize.Font{Size: 12}, Alignment: &excelize.Alignment{Horizontal: "left", Vertical: "center", WrapText: true}})
24 |
25 | // 将数据写入 Excel 文件
26 | for rowIndex, row := range data {
27 | for colIndex, cell := range row {
28 | cellIndex, _ := excelize.CoordinatesToCellName(colIndex+1, rowIndex+1)
29 | err := file.SetCellValue(sheet, cellIndex, cell)
30 | if err != nil {
31 | return err
32 | }
33 | if rowIndex == 0 {
34 | _ = file.SetCellStyle(sheet, cellIndex, cellIndex, titleStyle)
35 | } else {
36 | _ = file.SetCellStyle(sheet, cellIndex, cellIndex, dataStyle)
37 | }
38 | }
39 | }
40 |
41 | // 将 Excel 文件内容写入 HTTP 响应
42 | context.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
43 | context.Header("Content-Disposition", "attachment; filename="+fileName+".xlsx")
44 | context.Header("Content-Transfer-Encoding", "binary")
45 | err = file.Write(context.Writer)
46 | return err
47 | }
48 |
--------------------------------------------------------------------------------
/server/template/server/service/service.tmpl:
--------------------------------------------------------------------------------
1 | package {{ .TableName }}Service
2 |
3 | import (
4 | {{ .TableName }}Dto "{{ .Package }}/template/dto"
5 | {{ .TableName }}Repository "{{ .Package }}/template/repository"
6 | )
7 |
8 | type ServiceInterface interface {
9 | Get{{ .TableName }}ListService(params *{{ .TableName }}Dto.{{ .TableName }}FindRequestDTO) ([]*{{ .TableName }}Dto.{{ .TableName }}FindRequestDTO, error)
10 | Create{{ .TableName }}RecordService(params *{{ .TableName }}Dto.{{ .TableName }}CreateRequestDTO) error
11 | Update{{ .TableName }}ListService(id string, params *{{ .TableName }}Dto.{{ .TableName }}UpdateRequestDTO) error
12 | Delete{{ .TableName }}RecordService(id string) error
13 | }
14 | type Service struct {
15 | repo {{ .TableName }}Repository.RepositoryInterface
16 | }
17 |
18 | func New{{ .TableName }}Service() *Service {
19 | return &Service{
20 | repo: {{ .TableName }}Repository.New{{ .TableName }}Repository(),
21 | }
22 | }
23 |
24 | func (s Service) Get{{ .TableName }}ListService(params *{{ .TableName }}Dto.{{ .TableName }}FindRequestDTO) ([]*{{ .TableName }}Dto.{{ .TableName }}FindRequestDTO, error) {
25 | return s.repo.Get{{ .TableName }}ListRepo(params)
26 | }
27 |
28 | func (s Service) Create{{ .TableName }}RecordService(params *{{ .TableName }}Dto.{{ .TableName }}CreateRequestDTO) error {
29 | return s.repo.Create{{ .TableName }}RecordRepo(params)
30 | }
31 |
32 | func (s Service) Update{{ .TableName }}ListService(id string, params *{{ .TableName }}Dto.{{ .TableName }}UpdateRequestDTO) error {
33 | return s.repo.Update{{ .TableName }}RecordRepo(id, params)
34 | }
35 |
36 |
37 | func (s Service) Delete{{ .TableName }}RecordService(id string) error {
38 | return s.repo.Delete{{ .TableName }}RecordRepo(id)
39 | }
--------------------------------------------------------------------------------
/server/dto/modules/pages/pages.go:
--------------------------------------------------------------------------------
1 | package pagesResponsiesModules
2 |
3 | type CreatePageParams struct {
4 | PageName string `form:"pageName" binding:"required"`
5 | PagePath string `form:"pagePath"`
6 | PageIcon string `form:"pageIcon" binding:"required"`
7 | PageComponent string `form:"pageComponent"`
8 | ParentPage string `form:"parentPage"`
9 | PageOrder *int `form:"pageOrder" binding:"required"`
10 | IsOutSite bool `form:"isOutSite"`
11 | OutSiteLink *string `form:"outSiteLink"`
12 | }
13 |
14 | type SinglePageResponse struct {
15 | PageID string `json:"pageID"`
16 | PageName string `json:"pageName"`
17 | PagePath string `json:"pagePath"`
18 | PageIcon string `json:"pageIcon"`
19 | PageComponent string `json:"pageComponent"`
20 | ParentPage *string `json:"parentPage"`
21 | Children []*SinglePageResponse `json:"children"`
22 | PageOrder int `json:"pageOrder"`
23 | CanEdit int `json:"canEdit"`
24 | IsOutSite bool `json:"isOutSite"`
25 | OutSiteLink *string `json:"outSiteLink"`
26 | CreatedTime string `json:"createdAt"`
27 | UpdateTime string `json:"updateTime"`
28 | }
29 |
30 | type UpdatePageRequest struct {
31 | PageName string `form:"pageName" binding:"required"`
32 | PagePath string `form:"pagePath"`
33 | PageIcon string `form:"pageIcon" binding:"required"`
34 | PageComponent string `form:"pageComponent"`
35 | PageOrder *int `form:"pageOrder" binding:"required"`
36 | IsOutSite bool `form:"isOutSite"`
37 | OutSiteLink *string `form:"outSiteLink"`
38 | }
39 |
--------------------------------------------------------------------------------
/web/src/service/api/system/index.ts:
--------------------------------------------------------------------------------
1 | import request from '@/service/request';
2 | import { AxiosResponse } from 'axios';
3 |
4 | export interface SystemInfo {
5 | cpuUsage: number;
6 | memUsage: {
7 | total: number; // 总内存 (bytes)
8 | available: number; // 可用内存 (bytes)
9 | used: number; // 已使用内存 (bytes)
10 | usedPercent: number; // 内存使用率 (%)
11 | free: number; // 空闲内存 (bytes)
12 | active: number; // 活跃内存 (bytes)
13 | inactive: number; // 非活跃内存 (bytes)
14 | wired: number; // 已分配内存 (bytes)
15 | laundry: number; // 被回收内存 (bytes)
16 | };
17 | }
18 |
19 | export const MenUsageMap = [
20 | {
21 | key: 'available',
22 | label: '可用内存',
23 | },
24 | {
25 | key: 'used',
26 | label: '已使用内存',
27 | },
28 | {
29 | key: 'free',
30 | label: '空闲内存',
31 | },
32 | {
33 | key: 'active',
34 | label: '活跃内存',
35 | },
36 | {
37 | key: 'inactive',
38 | label: '非活跃内存',
39 | },
40 | {
41 | key: 'wired',
42 | label: '已分配内存',
43 | },
44 | {
45 | key: 'laundry',
46 | label: '被回收内存',
47 | },
48 | ];
49 |
50 | export interface IGitCommit {
51 | date: string;
52 | children: {
53 | author: string;
54 | commitID: string;
55 | date: string;
56 | email: string;
57 | message: string;
58 | }[];
59 | }
60 |
61 | export const getSystemRunTimeInfoRequest = () => {
62 | return request.get>({
63 | url: '/system',
64 | });
65 | };
66 |
67 | export const getGitCommitInfoRequest = () => {
68 | return request.get>({
69 | url: '/log/commits',
70 | });
71 | };
72 |
73 | export const getGitCommitCountRequest = () => {
74 | return request.get>({
75 | url: '/log/commits/count',
76 | });
77 | };
78 |
--------------------------------------------------------------------------------
/micro/rpc/user/internal/logic/getuserlistlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | userModel "micro/model/user"
6 | "micro/rpc/user/internal/svc"
7 | "micro/rpc/user/userRPC"
8 |
9 | "github.com/zeromicro/go-zero/core/logx"
10 | )
11 |
12 | type GetUserListLogic struct {
13 | ctx context.Context
14 | svcCtx *svc.ServiceContext
15 | logx.Logger
16 | }
17 |
18 | func NewGetUserListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserListLogic {
19 | return &GetUserListLogic{
20 | ctx: ctx,
21 | svcCtx: svcCtx,
22 | Logger: logx.WithContext(ctx),
23 | }
24 | }
25 |
26 | func (l *GetUserListLogic) GetUserList(in *userRPC.GetUserListRequest) (*userRPC.GetUserListResponse, error) {
27 | var userList []userModel.User
28 | var total int64
29 | err := l.svcCtx.GormDB.Where(&userModel.User{
30 | ID: in.Id,
31 | Account: in.Account,
32 | NickName: in.Nickname,
33 | Avatar: in.Avatar,
34 | Status: in.Status,
35 | DepartmentID: in.Department,
36 | IsAdmin: in.IsAdmin,
37 | }).Offset(int(in.Page)).Limit(int(in.PageSize)).Find(&userList).Count(&total).Error
38 |
39 | if err != nil {
40 | return nil, err
41 | }
42 | userListRPC := make([]*userRPC.GetUserResponse, 0)
43 |
44 | for _, v := range userList {
45 | userListRPC = append(userListRPC, &userRPC.GetUserResponse{
46 | Id: v.ID,
47 | Account: v.Account,
48 | Nickname: v.NickName,
49 | Avatar: v.Avatar,
50 | Status: v.Status,
51 |
52 | Department: v.DepartmentID,
53 | IsAdmin: v.IsAdmin,
54 | CreateTime: v.CreatedAt.String(),
55 | UpdateTime: v.UpdatedAt.String(),
56 | })
57 | }
58 |
59 | return &userRPC.GetUserListResponse{
60 | UserList: userListRPC,
61 | Total: int32(total),
62 | }, nil
63 | }
64 |
--------------------------------------------------------------------------------
/micro/api/user/internal/logic/getuserlistlogic.go:
--------------------------------------------------------------------------------
1 | package logic
2 |
3 | import (
4 | "context"
5 | "micro/rpc/user/userRPC"
6 |
7 | "micro/api/user/internal/svc"
8 | "micro/api/user/internal/types"
9 |
10 | "github.com/zeromicro/go-zero/core/logx"
11 | )
12 |
13 | type GetUserListLogic struct {
14 | logx.Logger
15 | ctx context.Context
16 | svcCtx *svc.ServiceContext
17 | }
18 |
19 | func NewGetUserListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserListLogic {
20 | return &GetUserListLogic{
21 | Logger: logx.WithContext(ctx),
22 | ctx: ctx,
23 | svcCtx: svcCtx,
24 | }
25 | }
26 |
27 | func (l *GetUserListLogic) GetUserList(req *types.GetUserListRequest) (resp *types.GetUserListResponse, err error) {
28 | list, _ := l.svcCtx.UserService.GetUserList(l.ctx, &userRPC.GetUserListRequest{
29 | Id: req.ID,
30 | Account: req.Account,
31 | Nickname: req.Nickname,
32 | Avatar: req.Avatar,
33 | Status: req.Status,
34 | Department: req.DepartmentID,
35 | IsAdmin: req.IsAdmin,
36 | Page: req.Offset,
37 | PageSize: req.Limit,
38 | })
39 | userList := make([]types.UserResponse, 0)
40 |
41 | for _, user := range list.UserList {
42 | userList = append(userList, types.UserResponse{
43 | ID: user.Id,
44 | Account: user.Account,
45 | Nickname: user.Nickname,
46 | Avatar: user.Avatar,
47 | Status: user.Status,
48 | DepartmentID: user.Department,
49 | IsAdmin: user.IsAdmin,
50 | CreateTime: user.CreateTime,
51 | UpdateTime: user.UpdateTime,
52 | })
53 | }
54 |
55 | return &types.GetUserListResponse{
56 | Code: 200,
57 | Msg: "成功",
58 | Data: types.UserListResponse{
59 | Total: int(list.Total),
60 | List: userList,
61 | },
62 | }, nil
63 | }
64 |
--------------------------------------------------------------------------------
/server/dto/modules/template/template.go:
--------------------------------------------------------------------------------
1 | package templateResponsiesModules
2 |
3 | type CreateTemplateRequestParams struct {
4 | Package string `form:"package" binding:"required"`
5 | TableName string `form:"tableName" binding:"required"`
6 | Fields *[]Fields `form:"fields" binding:"required"`
7 | }
8 |
9 | type DownloadTemplateRequestParams struct {
10 | TableName string `form:"tableName" binding:"required"`
11 | Controller string `form:"controller" binding:"required"`
12 | Service string `form:"service" binding:"required"`
13 | Repository string `form:"repository" binding:"required"`
14 | Route string `form:"route" binding:"required"`
15 | DTO string `form:"dto" binding:"required"`
16 | SearchForm string `form:"searchForm" binding:"required"`
17 | Table string `form:"table" binding:"required"`
18 | TableHook string `form:"tableHook" binding:"required"`
19 | }
20 |
21 | type Fields struct {
22 | Name string `form:"name" binding:"required"`
23 | Type string `form:"type" binding:"required"`
24 | Default string `form:"default" binding:"required"`
25 | }
26 |
27 | type CreateTemplateResponse struct {
28 | Server Server `json:"server"`
29 | Web Web `json:"web"`
30 | }
31 |
32 | type Server struct {
33 | ControllerFile Code `json:"controllerFile"`
34 | ServiceFile Code `json:"serviceFile"`
35 | RepositoryFile Code `json:"repositoryFile"`
36 | RouteFile Code `json:"routeFile"`
37 | DTOFile Code `json:"dtoFile"`
38 | }
39 | type Web struct {
40 | React React `json:"react"`
41 | }
42 |
43 | type React struct {
44 | SearchForm Code `json:"searchForm"`
45 | Table Code `json:"table"`
46 | TableHook Code `json:"tableHook"`
47 | }
48 |
49 | type Code struct {
50 | Code string `json:"code"`
51 | Lang string `json:"lang"`
52 | }
53 |
--------------------------------------------------------------------------------
/web/src/constant/index.ts:
--------------------------------------------------------------------------------
1 | import zhCN from 'antd/locale/zh_CN';
2 | import enUS from 'antd/locale/en_US';
3 | import { Locale } from 'antd/es/locale';
4 |
5 | export const constants = {
6 | localStorage: {
7 | lang: 'lang',
8 | token: 'token',
9 | },
10 | langMap: {
11 | zhCN: zhCN,
12 | enUS: enUS,
13 | } as Record,
14 | routePath: {
15 | login: '/login',
16 | main: '/',
17 | },
18 | module: {
19 | ROLE: 'role',
20 | },
21 | permissionDicMap: {
22 | EXPORT_USER: 'POST:/users/export',
23 | ADD_USER: 'POST:/users',
24 | DELETE_USER: 'DELETE:/users/:id',
25 | UPDATE_USER: 'PATCH:/users/:id',
26 | EXPORT_ROLE: 'POST:/roles/export',
27 | ADD_ROLE: 'POST:/roles',
28 | DELETE_ROLE: 'DELETE:/roles/:id',
29 | UPDATE_ROLE: 'PATCH:/roles/:id',
30 | BIND_USER: 'POST:/roles/bindUser',
31 | UNBIND_USER: 'POST:/roles/deBindUser',
32 | GET_ALL_MENU: 'GET:/pages',
33 | GET_MENU: 'GET:/pages/user',
34 | ADD_MENU: 'POST:/pages',
35 | UPDATE_MENU: 'PATCH:/pages/:id',
36 | GET_ROLE_MENU: 'GET:/pages/role/:id',
37 | ADD_DEPARTMENT: 'POST:/department',
38 | DELETE_DEPARTMENT: 'DELETE:/department/:id',
39 | UPDATE_DEPARTMENT: 'PATCH:/department/:id',
40 | GET_PAGE_INTERFACE: 'GET:/interface/page/:id',
41 | GET_ALL_INTERFACE: 'GET:/interface',
42 | GET_ALL_USER_IS_OUT_ROLE_ID: 'POST:/users/query/role/:id',
43 | ADD_PAGE_INTERFACE: 'POST:/interface',
44 | DELETE_PAGE_INTERFACE: 'DELETE:/interface/:id',
45 | UPDATE_PAGE_INTERFACE: 'PATCH:/interface/:id',
46 | CREATE_TEMPLATE: 'POST:/template',
47 | DOWNLOAD_TEMPLATE: 'POST:/template/download',
48 | UPLOAD_FILE: 'POST:/upload',
49 | DOWNLOAD_FILE: 'GET:/upload/download/aHref/:id',
50 | DELETE_FILE: 'DELETE:/upload/del/:id',
51 | },
52 | };
53 |
--------------------------------------------------------------------------------
/server/controllers/controllers.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | authControllersModules "github.com/Xi-Yuer/cms/controllers/modules/auth"
5 | commitsControllerModules "github.com/Xi-Yuer/cms/controllers/modules/commits"
6 | departmentControllerModules "github.com/Xi-Yuer/cms/controllers/modules/department"
7 | interfaceControllerModules "github.com/Xi-Yuer/cms/controllers/modules/interface"
8 | logsControllerModules "github.com/Xi-Yuer/cms/controllers/modules/logs"
9 | pagesControllerModules "github.com/Xi-Yuer/cms/controllers/modules/pages"
10 | roleControllersModules "github.com/Xi-Yuer/cms/controllers/modules/role"
11 | systemControllerModules "github.com/Xi-Yuer/cms/controllers/modules/system"
12 | templateControllerModules "github.com/Xi-Yuer/cms/controllers/modules/template"
13 | "github.com/Xi-Yuer/cms/controllers/modules/timeTask"
14 | uploadControllerModules "github.com/Xi-Yuer/cms/controllers/modules/upload"
15 | userControllersModules "github.com/Xi-Yuer/cms/controllers/modules/users"
16 | )
17 |
18 | var UserController = userControllersModules.UserController
19 | var AuthController = authControllersModules.AuthController
20 | var RoleController = roleControllersModules.RoleController
21 | var PagesController = pagesControllerModules.PagesController
22 | var DepartmentController = departmentControllerModules.DepartmentController
23 | var InterfaceController = interfaceControllerModules.InterfaceController
24 | var LogsController = logsControllerModules.LogsController
25 | var CommitsController = commitsControllerModules.CommitsController
26 | var SystemController = systemControllerModules.SystemController
27 | var TimeTaskController = timeTaskControllerModules.TimeTaskController
28 | var UploadController = uploadControllerModules.UploadController
29 | var TemplateController = templateControllerModules.TemplateController
30 |
--------------------------------------------------------------------------------
/server/repositories/modules/rolesAndInterfaces/rolesAndInterfaces.go:
--------------------------------------------------------------------------------
1 | package rolesAndInterfacesRepositoryModules
2 |
3 | import (
4 | "fmt"
5 | "github.com/Xi-Yuer/cms/db"
6 | "github.com/Xi-Yuer/cms/dto"
7 | )
8 |
9 | var RolesAndInterfacesRepository = &rolesAndInterfacesRepository{}
10 |
11 | type rolesAndInterfacesRepository struct{}
12 |
13 | func (r *rolesAndInterfacesRepository) CreateRecord(params *dto.CreateRolePermissionRecordParams) error {
14 | tx, err := db.DB.Begin()
15 | if err != nil {
16 | return err
17 | }
18 | // 给角色分配接口权限,需要清空之间的数据
19 | query := `DELETE FROM roles_interfaces WHERE role_id = ?`
20 |
21 | if _, err := db.DB.Exec(query, params.RoleID); err != nil {
22 | if err := tx.Rollback(); err != nil {
23 | return err
24 | }
25 | return err
26 | }
27 | // 接口ID为空
28 | if len(params.InterfaceID) == 0 {
29 | return nil
30 | }
31 | query = `INSERT INTO roles_interfaces (role_id, interface_id) VALUES `
32 | for _, inter := range params.InterfaceID {
33 | query += fmt.Sprintf("('%s', '%s'),", params.RoleID, inter)
34 | }
35 | query = query[:len(query)-1] // Remove the last comma and space
36 |
37 | if _, err := db.DB.Exec(query); err != nil {
38 | if err := tx.Rollback(); err != nil {
39 | return err
40 | }
41 | return err
42 | }
43 | return nil
44 | }
45 | func (r *rolesAndInterfacesRepository) GetRecordByRoleID(roleID string) ([]string, error) {
46 | query := "SELECT interface_id FROM roles_interfaces WHERE role_id = ?"
47 | rows, err := db.DB.Query(query, roleID)
48 | if err != nil {
49 | return nil, err
50 | }
51 | var interfaceIDs []string
52 | for rows.Next() {
53 | var interfaceID string
54 | if err := rows.Scan(&interfaceID); err != nil {
55 | return nil, err
56 | }
57 | interfaceIDs = append(interfaceIDs, interfaceID)
58 |
59 | }
60 | return interfaceIDs, nil
61 | }
62 |
--------------------------------------------------------------------------------
/server/utils/modules/jwt/jwt.go:
--------------------------------------------------------------------------------
1 | package jwt
2 |
3 | import (
4 | "errors"
5 | "github.com/Xi-Yuer/cms/config"
6 | "github.com/Xi-Yuer/cms/dto"
7 | "github.com/golang-jwt/jwt/v5"
8 | "time"
9 | )
10 |
11 | type Jsonwebtoken struct {
12 | }
13 |
14 | func (j *Jsonwebtoken) GenerateTokenUsingHs256(jwtPayload *dto.JWTPayload) (string, error) {
15 | claim := dto.JWTPayload{
16 | ID: jwtPayload.ID,
17 | Account: jwtPayload.Account,
18 | RoleID: jwtPayload.RoleID,
19 | IsAdmin: jwtPayload.IsAdmin,
20 | InterfaceDic: jwtPayload.InterfaceDic,
21 | DepartmentID: jwtPayload.DepartmentID,
22 | RegisteredClaims: jwt.RegisteredClaims{
23 | Issuer: "Xi-Yuer", // 签发者
24 | Subject: jwtPayload.Account, // 签发对象
25 | ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24)), //过期时间
26 | NotBefore: jwt.NewNumericDate(time.Now().Add(time.Second)), //最早使用时间
27 | IssuedAt: jwt.NewNumericDate(time.Now()), //签发时间
28 | ID: jwtPayload.ID, // wt ID, 类似于盐值
29 | },
30 | }
31 | token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claim).SignedString([]byte(config.Config.APP.JWT))
32 | return token, err
33 | }
34 |
35 | func (j *Jsonwebtoken) ParseTokenHs256(tokenStr string) (*dto.JWTPayload, error) {
36 | token, err := jwt.ParseWithClaims(tokenStr, &dto.JWTPayload{}, func(token *jwt.Token) (interface{}, error) {
37 | return []byte(config.Config.APP.JWT), nil //返回签名密钥
38 | })
39 | if err != nil {
40 | return nil, err
41 | }
42 |
43 | if !token.Valid {
44 | return nil, errors.New("claim invalid")
45 | }
46 |
47 | claims, ok := token.Claims.(*dto.JWTPayload)
48 | if !ok {
49 | return nil, errors.New("invalid claim type")
50 | }
51 |
52 | return claims, nil
53 | }
54 |
--------------------------------------------------------------------------------
/server/repositories/modules/repositories.go:
--------------------------------------------------------------------------------
1 | package repositories
2 |
3 | import (
4 | commitsRepositoryModules "github.com/Xi-Yuer/cms/repositories/modules/commits"
5 | departmentRepositoryModules "github.com/Xi-Yuer/cms/repositories/modules/department"
6 | interfaceRepositoryModules "github.com/Xi-Yuer/cms/repositories/modules/interface"
7 | logsRepositoryModules "github.com/Xi-Yuer/cms/repositories/modules/logs"
8 | pagesRepositoryModules "github.com/Xi-Yuer/cms/repositories/modules/pages"
9 | rolesRepositorysModules "github.com/Xi-Yuer/cms/repositories/modules/roles"
10 | rolesAndInterfacesRepositoryModules "github.com/Xi-Yuer/cms/repositories/modules/rolesAndInterfaces"
11 | rolesAndPagesRepositoryModules "github.com/Xi-Yuer/cms/repositories/modules/rolesAndPages"
12 | uploadRepositorysModules "github.com/Xi-Yuer/cms/repositories/modules/upload"
13 | userRepositorysModules "github.com/Xi-Yuer/cms/repositories/modules/users"
14 | usersAndRolesRepositorysModules "github.com/Xi-Yuer/cms/repositories/modules/usersAndRoles"
15 | )
16 |
17 | var UserRepositorysModules = userRepositorysModules.UserRepository
18 | var RoleRepositorysModules = rolesRepositorysModules.RolesRepository
19 | var UsersAndRolesRepositorys = usersAndRolesRepositorysModules.UsersAndRolesRepositorys
20 | var PageRepositorysModules = pagesRepositoryModules.PageRepository
21 | var RolesAndPagesRepository = rolesAndPagesRepositoryModules.RolesAndPagesRepository
22 | var DepartmentRepository = departmentRepositoryModules.DepartmentRepository
23 | var InterfaceRepository = interfaceRepositoryModules.InterfaceRepository
24 | var LogsRepository = logsRepositoryModules.LogsRepository
25 | var RolesAndInterfacesRepository = rolesAndInterfacesRepositoryModules.RolesAndInterfacesRepository
26 | var CommitsRepositoryModules = commitsRepositoryModules.CommitsRepositoryModules
27 | var UploadRepository = uploadRepositorysModules.UploadRepository
28 |
--------------------------------------------------------------------------------
/server/repositories/modules/logs/logs.go:
--------------------------------------------------------------------------------
1 | package logsRepositoryModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/db"
5 | "github.com/Xi-Yuer/cms/dto"
6 | )
7 |
8 | var LogsRepository = logsRepository{}
9 |
10 | type logsRepository struct{}
11 |
12 | func (l *logsRepository) CreateLogRecord(params *dto.CreateLogRecordRequest) error {
13 | query := "INSERT INTO logs (id, user_id, user_account, ip, method, path, status, duration) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
14 | _, err := db.DB.Exec(query, params.ID, params.UserID, params.UserName, params.UserIP, params.RequestMethod, params.RequestPath, params.RequestStatus, params.RequestDuration)
15 | return err
16 | }
17 |
18 | func (l *logsRepository) GetLogRecords(params *dto.Page) (*dto.HasTotalResponseData, error) {
19 | count := "SELECT COUNT(*) FROM logs"
20 | var total int
21 | r, err := db.DB.Query(count)
22 | if err != nil {
23 | return nil, err
24 | }
25 | for r.Next() {
26 | err := r.Scan(&total)
27 | if err != nil {
28 | return nil, err
29 | }
30 | }
31 | query := "SELECT id, user_id, user_account, ip, method, path, status, duration, create_time FROM logs ORDER BY create_time DESC LIMIT ?, ?"
32 | var logs []*dto.GetLogRecordResponse
33 | rows, err := db.DB.Query(query, params.Offset, params.Limit)
34 | if err != nil {
35 | return nil, err
36 | }
37 | for rows.Next() {
38 | var log dto.GetLogRecordResponse
39 | err := rows.Scan(&log.ID, &log.UserID, &log.UserName, &log.UserIP, &log.RequestMethod, &log.RequestPath, &log.RequestStatus, &log.RequestDuration, &log.CreateTime)
40 | if err != nil {
41 | return nil, err
42 | }
43 | logs = append(logs, &log)
44 | }
45 | return &dto.HasTotalResponseData{
46 | List: logs,
47 | Total: total,
48 | }, nil
49 | }
50 |
51 | func (l *logsRepository) DeleteLogRecords() {
52 | query := "DELETE FROM logs WHERE create_time < DATE_SUB(CURDATE(), INTERVAL 7 DAY)"
53 | _, _ = db.DB.Exec(query)
54 | }
55 |
--------------------------------------------------------------------------------
/micro/rpc/role/desc/role.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package roleRPC;
4 |
5 | option go_package = "./roleRPC";
6 |
7 | message CreateRoleRequest {
8 | string id = 1;
9 | string role_name = 2;
10 | string description = 3;
11 | bool can_edit = 4;
12 | }
13 |
14 | message DeleteRoleRequest {
15 | string id = 1;
16 | }
17 | message RoleIDsHasBeenExistRequest {
18 | repeated string ids = 1;
19 | }
20 |
21 | message RoleNamesHasBeenExistRequest {
22 | repeated string names = 1;
23 | }
24 |
25 | message UpdateRoleRequest {
26 | string id = 1;
27 | string role_name = 2;
28 | string description = 3;
29 | bool can_edit = 4;
30 | }
31 |
32 | message GetRoleRequest {
33 | string id = 1;
34 | }
35 |
36 | message GetRoleListRequest {
37 | string id = 1;
38 | string role_name = 2;
39 | string description = 3;
40 | bool can_edit = 4;
41 | string create_time = 9;
42 | string update_time = 10;
43 | int32 page = 11;
44 | int32 page_size = 12;
45 | }
46 |
47 | message GetRoleResponse {
48 | string id = 1;
49 | string role_name = 2;
50 | string description = 3;
51 | bool can_edit = 4;
52 | string create_time = 9;
53 | string update_time = 10;
54 | }
55 |
56 | message GetUserListResponse {
57 | int32 total = 1;
58 | repeated GetRoleResponse role_list = 2;
59 | }
60 |
61 | message CommonResponse {
62 | bool ok = 1;
63 | string msg = 2;
64 | }
65 |
66 | service RoleService {
67 | rpc CreateRole(CreateRoleRequest) returns (CommonResponse) {}
68 | rpc DeleteRole(DeleteRoleRequest) returns (CommonResponse) {}
69 | rpc UpdateRole(UpdateRoleRequest) returns (CommonResponse) {}
70 | rpc GetRole(GetRoleRequest) returns (GetRoleResponse) {}
71 | rpc GetRoleList(GetRoleListRequest) returns (GetUserListResponse) {}
72 | rpc RoleNameHasBeenExist(RoleNamesHasBeenExistRequest) returns (CommonResponse);
73 | rpc RoleIDsHasBeenExist(RoleIDsHasBeenExistRequest) returns (CommonResponse);
74 | }
--------------------------------------------------------------------------------
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | name: Go
2 |
3 | on:
4 | push:
5 | branches: [ "prod" ]
6 |
7 | jobs:
8 |
9 | build:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v3
13 |
14 | - name: Set up Go
15 | uses: actions/setup-go@v4
16 | with:
17 | go-version: '1.21.1'
18 |
19 | - name: Cache dependencies
20 | uses: actions/cache@v2
21 | with:
22 | path: ~/go/pkg/mod
23 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
24 | restore-keys: |
25 | ${{ runner.os }}-go-
26 |
27 | - name: Build
28 | run: go build -v -o ./build/CMS ./main.go
29 | working-directory: ./server
30 |
31 | - name: CMS Build
32 | uses: actions/upload-artifact@v4
33 | with:
34 | name: CMS
35 | path: ./server/build
36 |
37 | release:
38 | runs-on: ubuntu-latest
39 | needs: build
40 | steps:
41 | - name: Download Artifact
42 | uses: actions/download-artifact@v4
43 | with:
44 | name: CMS
45 | path: ./build
46 |
47 | - name: Create Release
48 | id: create_release
49 | uses: actions/create-release@v1
50 | env:
51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52 | with:
53 | tag_name: v1.1.10
54 | release_name: Release v1.1.10
55 | body: |
56 | Release v1.1.10
57 | draft: false
58 | prerelease: false
59 |
60 | - name: Upload Release Asset
61 | id: upload-release-asset
62 | uses: actions/upload-release-asset@v1
63 | env:
64 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
65 | with:
66 | upload_url: ${{ steps.create_release.outputs.upload_url }}
67 | asset_path: ./build/CMS
68 | asset_name: CMS
69 | asset_content_type: application/octet-stream
70 |
--------------------------------------------------------------------------------
/server/utils/modules/timeTask/timeTask.go:
--------------------------------------------------------------------------------
1 | package timeTask
2 |
3 | import (
4 | "errors"
5 | "github.com/robfig/cron/v3"
6 | )
7 |
8 | var c *cron.Cron
9 |
10 | var TimeTask = &timeTask{
11 | taskMap: make(map[string]struct {
12 | TaskID cron.EntryID
13 | Task *cron.Cron
14 | }),
15 | }
16 |
17 | type timeTask struct {
18 | taskMap map[string]struct {
19 | TaskID cron.EntryID
20 | Task *cron.Cron
21 | }
22 | }
23 |
24 | // AddTask 添加任务
25 | func (t *timeTask) AddTask(TimeTaskID string, corn string, task func(), status bool) error {
26 | c = cron.New(cron.WithSeconds())
27 | id, err := c.AddFunc(corn, task)
28 | if status {
29 | go c.Start()
30 | }
31 | if err != nil {
32 | return err
33 | }
34 | t.taskMap[TimeTaskID] = struct {
35 | TaskID cron.EntryID
36 | Task *cron.Cron
37 | }{
38 | TaskID: id,
39 | Task: c,
40 | }
41 | return nil
42 | }
43 |
44 | // StartTask 启动任务
45 | func (t *timeTask) StartTask(TimeTaskID string) error {
46 | if task, ok := t.taskMap[TimeTaskID]; ok {
47 | go task.Task.Start()
48 | return nil
49 | } else {
50 | return errors.New("任务不存在")
51 | }
52 | }
53 |
54 | // StopTask 停止任务
55 | func (t *timeTask) StopTask(TimeTaskID string) error {
56 | if task, ok := t.taskMap[TimeTaskID]; ok {
57 | task.Task.Stop()
58 | return nil
59 | } else {
60 | return errors.New("任务不存在")
61 | }
62 | }
63 |
64 | // RemoveTask 移除任务
65 | func (t *timeTask) RemoveTask(TimeTaskID string) error {
66 | if task, ok := t.taskMap[TimeTaskID]; ok {
67 | task.Task.Stop()
68 | c.Remove(task.TaskID)
69 | delete(t.taskMap, TimeTaskID)
70 | } else {
71 | return errors.New("任务不存在")
72 | }
73 | return nil
74 | }
75 |
76 | // ParseCron 校验 cron 表达式是否正确
77 | func (t *timeTask) ParseCron(s string) error {
78 | c := cron.New(cron.WithSeconds())
79 | id, err := c.AddFunc(s, func() {})
80 | if err != nil {
81 | return errors.New("cron 表达式错误")
82 | } else {
83 | c.Remove(id)
84 | }
85 | return nil
86 | }
87 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 基于RBAC的权限管理系统
2 | 
3 |
4 |
5 | 简体中文 | [English](README_en.md)
6 |
7 | [](https://godoc.org/github.com/Xi-Yuer/GO-CMS)
8 | 
9 | 
10 | 
11 | 
12 | 
13 | 
14 |
15 |
16 | ## 项目介绍
17 | 基于RBAC的权限管理系统,使用Go + Gin框架,Mysql作为数据库,前端采用 React + Antd 实现。支持国际化,主题色切换,权限控制,菜单管理,用户管理,角色管理,数据字典管理,日志管理,系统监控,代码生成器,接口文档等功能。
18 |
19 | ## 项目运行后端
20 |
21 | 1. 克隆项目到本地
22 | ```text
23 | https://github.com/Xi-Yuer/GO-CMS.git
24 | ```
25 |
26 | 2. 安装依赖
27 | ```text
28 | cd server
29 | go mod tidy
30 | ```
31 |
32 | 3. 修改运行项目设置环境变量
33 | server/config/config.go
34 |
35 | {
36 | NAME: "root", // 数据库用户名
37 | PASSWORD: "xxxxxx", // 密码
38 | HOST: "localhost", // 主机地址
39 | DB: "cms", // 数据库名称
40 | PORT: "3306", // 端口
41 | }
42 |
43 | 4. 创建MySQL运行环境
44 | 1. 创建一个名为 cms 的数据库, 执行SQL文件(位置:server/sql/cms_widthData.sql)
45 |
46 | 5. 运行项目
47 | ```text
48 | go run server/main.go
49 | ```
50 |
51 |
52 | ## 项目运行前端
53 |
54 | 1. 克隆项目到本地
55 | ```text
56 | https://github.com/Xi-Yuer/GO-CMS.git
57 | ```
58 |
59 | 2. 安装依赖
60 | ```text
61 | cd web
62 | pnpm install
63 | ```
64 |
65 | 3. 运行项目
66 | ```text
67 | pnpm run dev
68 | ```
69 |
70 | ## 项目部分截图
71 | 
72 |
73 | 
74 |
75 | 
76 |
--------------------------------------------------------------------------------
/server/controllers/modules/system/system.go:
--------------------------------------------------------------------------------
1 | package systemControllerModules
2 |
3 | import (
4 | "github.com/Xi-Yuer/cms/utils"
5 | "github.com/gin-gonic/gin"
6 | "github.com/shirou/gopsutil/cpu"
7 | "github.com/shirou/gopsutil/mem"
8 | "time"
9 | )
10 |
11 | var SystemController = &systemController{}
12 |
13 | type systemController struct{}
14 |
15 | type MemInfo struct {
16 | Total uint64 `json:"total"` // 总内存 (bytes)
17 | Available uint64 `json:"available"` // 可用内存 (bytes)
18 | Used uint64 `json:"used"` // 已使用内存 (bytes)
19 | UsedPercent float64 `json:"usedPercent"` // 内存使用率 (%)
20 | Free uint64 `json:"free"` // 空闲内存 (bytes)
21 | Active uint64 `json:"active"` // 活跃内存 (bytes)
22 | Inactive uint64 `json:"inactive"` // 非活跃内存 (bytes)
23 | Wired uint64 `json:"wired"` // 已分配内存 (bytes)
24 | Laundry uint64 `json:"laundry"` // 被回收内存 (bytes)
25 | }
26 |
27 | var response []systemInfo
28 |
29 | func init() {
30 | initSystemInfo()
31 | }
32 | func initSystemInfo() {
33 | go func() {
34 | ticker := time.Tick(time.Second)
35 | for {
36 | select {
37 | case <-ticker:
38 | // CPU使用率
39 | CPURate, _ := cpu.Percent(time.Second, false)
40 | // 内存信息
41 | MemInfo, _ := mem.VirtualMemory()
42 | info := systemInfo{
43 | CPUUsage: CPURate[0],
44 | MemUsage: MemInfo,
45 | }
46 | response = append(response, info)
47 | if len(response) > 20 {
48 | response = response[1:]
49 | }
50 | }
51 | }
52 | }()
53 | }
54 |
55 | type systemInfo struct {
56 | CPUUsage float64 `json:"cpuUsage"`
57 | MemUsage *mem.VirtualMemoryStat `json:"memUsage"`
58 | }
59 |
60 | // GetSystemInfo 获取系统运行信息
61 | // @Summary 获取系统运行信息
62 | // @Description 获取系统运行信息
63 | // @Tags 系统管理
64 | // @Accept json
65 | // @Produce json
66 | // @Router /system [get]
67 | func (s *systemController) GetSystemInfo(context *gin.Context) {
68 | utils.Response.Success(context, response)
69 | }
70 |
--------------------------------------------------------------------------------
/server/repositories/modules/rolesAndPages/roleAndPages.go:
--------------------------------------------------------------------------------
1 | package rolesAndPagesRepositoryModules
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "github.com/Xi-Yuer/cms/db"
7 | "github.com/Xi-Yuer/cms/dto"
8 | "github.com/Xi-Yuer/cms/utils"
9 | )
10 |
11 | var RolesAndPagesRepository = &rolesAndPagesRepository{}
12 |
13 | type rolesAndPagesRepository struct {
14 | }
15 |
16 | func (r *rolesAndPagesRepository) CreateRecord(params *dto.CreateRolePermissionRecordParams) error {
17 | // 创建角色页面权限之前需要先将之前的记录全部删除,并且要保证事务的一致性
18 | tx, err := db.DB.Begin()
19 | if err != nil {
20 | return err
21 | }
22 | _, err = db.DB.Exec("DELETE FROM roles_pages WHERE role_id = ?", params.RoleID)
23 | if err != nil {
24 | err := tx.Rollback()
25 | if err != nil {
26 | return err
27 | }
28 | return err
29 | }
30 | if len(params.PageID) == 0 {
31 | return nil
32 | }
33 | query := "INSERT INTO roles_pages (role_id, page_id) VALUES "
34 | for _, pageID := range params.PageID {
35 | query += fmt.Sprintf("('%s', '%s'),", params.RoleID, pageID)
36 | }
37 | query = query[:len(query)-1] // Remove the last comma and space
38 |
39 | _, err = db.DB.Exec(query)
40 | if err != nil {
41 | err := tx.Rollback()
42 | if err != nil {
43 | return err
44 | }
45 | return err
46 | }
47 | err = tx.Commit()
48 | if err != nil {
49 | return err
50 | }
51 | return nil
52 | }
53 |
54 | func (r *rolesAndPagesRepository) GetRecordsByRoleID(roleID string) ([]string, error) {
55 | rows, err := db.DB.Query("SELECT page_id FROM roles_pages WHERE role_id = ?", roleID)
56 | if err != nil {
57 | return nil, err
58 | }
59 | defer func(rows *sql.Rows) {
60 | err := rows.Close()
61 | if err != nil {
62 | utils.Log.Error(err)
63 | }
64 | }(rows)
65 |
66 | var pageIDs []string
67 |
68 | for rows.Next() {
69 | var pageID string
70 | err := rows.Scan(&pageID)
71 | if err != nil {
72 | return nil, err
73 | }
74 | pageIDs = append(pageIDs, pageID)
75 | }
76 |
77 | return pageIDs, nil
78 | }
79 |
--------------------------------------------------------------------------------
/web/src/components/AppHeaderTab/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC, memo } from 'react';
2 | import { Popover, Tag } from 'antd';
3 | import { Icon } from '@/components';
4 | import '@/styles/common/index.css';
5 | import { useAppHeaderTab } from '@/components/AppHeaderTab/hooks.tsx';
6 | import { CSSTransition, TransitionGroup } from 'react-transition-group';
7 |
8 | const AppHeaderTab: FC = () => {
9 | const { content, onclick, onclose, TabHeader, pathname } = useAppHeaderTab();
10 | return (
11 |
12 |
13 | {!!TabHeader.length &&
14 | TabHeader?.map((item, index) => {
15 | return (
16 |
26 | content(item, index)}>
27 | }
31 | key={item.pageID}
32 | closable={true}
33 | className='cursor-pointer select-none'
34 | onClose={(e) => onclose(e, item, index)}
35 | onClick={() => onclick(item)}>
36 | {item.pageName}
37 |
38 |
39 |
40 | );
41 | })}
42 |
43 |
44 | );
45 | };
46 |
47 | export default memo(AppHeaderTab);
48 |
--------------------------------------------------------------------------------
/server/utils/modules/captcha/captcha.go:
--------------------------------------------------------------------------------
1 | package captcha
2 |
3 | import (
4 | "bytes"
5 | "github.com/dchest/captcha"
6 | "github.com/gin-contrib/sessions"
7 | "github.com/gin-gonic/gin"
8 | "net/http"
9 | "time"
10 | )
11 |
12 | type Captcha struct{}
13 |
14 | func (c *Captcha) GenerateCaptcha(context *gin.Context, length ...int) {
15 | l := captcha.DefaultLen
16 | w, h := 107, 36
17 | if len(length) == 1 {
18 | l = length[0]
19 | }
20 | if len(length) == 2 {
21 | w = length[1]
22 | }
23 | if len(length) == 3 {
24 | h = length[2]
25 | }
26 | captchaId := captcha.NewLen(l)
27 | session := sessions.Default(context)
28 | session.Set("captcha", captchaId)
29 | _ = session.Save()
30 | _ = serve(context.Writer, context.Request, captchaId, ".png", "zh", false, w, h)
31 | }
32 | func (c *Captcha) VerifyCaptcha(context *gin.Context, code string) bool {
33 | session := sessions.Default(context)
34 | if captchaId := session.Get("captcha"); captchaId != nil {
35 | session.Delete("captcha")
36 | _ = session.Save()
37 | if captcha.VerifyString(captchaId.(string), code) {
38 | return true
39 | } else {
40 | return false
41 | }
42 | } else {
43 | return false
44 | }
45 | }
46 |
47 | func serve(w http.ResponseWriter, r *http.Request, id, ext, lang string, download bool, width, height int) error {
48 | w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
49 | w.Header().Set("Pragma", "no-cache")
50 | w.Header().Set("Expires", "0")
51 |
52 | var content bytes.Buffer
53 | switch ext {
54 | case ".png":
55 | w.Header().Set("Content-Type", "image/png")
56 | _ = captcha.WriteImage(&content, id, width, height)
57 | case ".wav":
58 | w.Header().Set("Content-Type", "audio/x-wav")
59 | _ = captcha.WriteAudio(&content, id, lang)
60 | default:
61 | return captcha.ErrNotFound
62 | }
63 |
64 | if download {
65 | w.Header().Set("Content-Type", "application/octet-stream")
66 | }
67 | http.ServeContent(w, r, id+ext, time.Time{}, bytes.NewReader(content.Bytes()))
68 | return nil
69 | }
70 |
--------------------------------------------------------------------------------
/micro/shared/gorm/gorm.go:
--------------------------------------------------------------------------------
1 | package gormDB
2 |
3 | import (
4 | "gorm.io/driver/mysql"
5 | "gorm.io/gorm"
6 | "gorm.io/gorm/logger"
7 | "log"
8 | roleModlel "micro/model/role"
9 | userModel "micro/model/user"
10 | "os"
11 | "sync"
12 | "time"
13 | )
14 |
15 | var (
16 | DB *gorm.DB
17 | once sync.Once
18 | )
19 |
20 | func NewGorm() *gorm.DB {
21 | once.Do(func() {
22 | newLogger := logger.New(
23 | log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
24 | logger.Config{
25 | SlowThreshold: time.Second, // Slow SQL threshold
26 | LogLevel: logger.Silent, // Log level
27 | IgnoreRecordNotFoundError: false, // Ignore ErrRecordNotFound error for logger
28 | ParameterizedQueries: false, // Don't include params in the SQL log
29 | Colorful: false, // Disable color
30 | },
31 | )
32 | db, err := gorm.Open(mysql.New(mysql.Config{
33 | DSN: "root:2214380963Wx!!@tcp(mysql:3306)/micro_cms?charset=utf8&parseTime=True&loc=Local", // 数据源名称
34 | DefaultStringSize: 256, // string 类型字段的默认长度
35 | DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
36 | DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
37 | DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
38 | SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
39 | }), &gorm.Config{
40 | Logger: newLogger,
41 | })
42 |
43 | if err := db.AutoMigrate(&userModel.User{}, &roleModlel.Role{}); err != nil {
44 | log.Fatalf("数据库迁移失败: %v", err)
45 | }
46 | if err != nil {
47 | panic(err)
48 | }
49 |
50 | DB = db
51 | })
52 |
53 | return DB
54 | }
55 |
--------------------------------------------------------------------------------