├── .gitattributes
├── QMPlusVuePage
├── .env.production
├── .env.development
├── babel.config.js
├── src
│ ├── utils
│ │ ├── _import.js
│ │ ├── asyncRouter.js
│ │ ├── bus.js
│ │ ├── downloadImg.js
│ │ ├── data.js
│ │ └── request.js
│ ├── assets
│ │ ├── qm.png
│ │ ├── logo.png
│ │ └── notFound.png
│ ├── view
│ │ ├── example
│ │ │ ├── index.vue
│ │ │ ├── rte
│ │ │ │ └── rte.vue
│ │ │ ├── excel
│ │ │ │ └── excel.vue
│ │ │ ├── table
│ │ │ │ └── table.vue
│ │ │ ├── upload
│ │ │ │ └── upload.vue
│ │ │ └── form
│ │ │ │ └── form.vue
│ │ ├── workflow
│ │ │ ├── index.vue
│ │ │ └── workflowCreate
│ │ │ │ └── workflowCreate.vue
│ │ ├── superAdmin
│ │ │ ├── index.vue
│ │ │ ├── authority
│ │ │ │ ├── components
│ │ │ │ │ ├── menus.vue
│ │ │ │ │ ├── apis.vue
│ │ │ │ │ └── datas.vue
│ │ │ │ └── authority.vue
│ │ │ ├── system
│ │ │ │ └── system.vue
│ │ │ ├── user
│ │ │ │ └── user.vue
│ │ │ ├── menu
│ │ │ │ └── menu.vue
│ │ │ └── api
│ │ │ │ └── api.vue
│ │ ├── test
│ │ │ └── index.vue
│ │ ├── layout
│ │ │ ├── aside
│ │ │ │ ├── asideComponent
│ │ │ │ │ ├── menuItem.vue
│ │ │ │ │ ├── asyncSubmenu.vue
│ │ │ │ │ └── index.vue
│ │ │ │ └── index.vue
│ │ │ └── index.vue
│ │ ├── error
│ │ │ └── index.vue
│ │ ├── dashbord
│ │ │ ├── index.vue
│ │ │ └── component
│ │ │ │ └── animition.vue
│ │ ├── person
│ │ │ └── person.vue
│ │ └── login
│ │ │ ├── login.vue
│ │ │ └── regist.vue
│ ├── App.vue
│ ├── api
│ │ ├── jwt.js
│ │ ├── workflow.js
│ │ ├── system.js
│ │ ├── fileUploadAndDownload.js
│ │ ├── casbin.js
│ │ ├── user.js
│ │ ├── authority.js
│ │ ├── menu.js
│ │ └── api.js
│ ├── store
│ │ ├── index.js
│ │ └── module
│ │ │ ├── router.js
│ │ │ └── user.js
│ ├── router
│ │ └── index.js
│ ├── components
│ │ └── mixins
│ │ │ └── infoList.js
│ ├── style
│ │ └── base.scss
│ ├── main.js
│ └── permission.js
├── public
│ ├── favicon.ico
│ ├── qm-plus-img
│ │ ├── 132604444.png
│ │ └── 86891839.png
│ └── index.html
├── README.md
├── package.json
└── vue.config.js
├── tools
├── md5.go
├── array_to_string.go
├── directory.go
├── struct_to_map.go
├── hasGap.go
├── des.go
└── str.go
├── static
├── rbacmodel
│ └── rbac_model.conf
└── config
│ └── config.json
├── controller
├── servers
│ ├── reportformat.go
│ ├── paging.go
│ ├── upload.go
│ └── breakpoint_continue.go
└── api
│ ├── sys_workFlow.go
│ ├── sys_jwt_blacklist.go
│ ├── sys_casbin.go
│ ├── sys_system.go
│ ├── sys_authority.go
│ ├── exa_fileUploadAndDownload.go
│ ├── exa_breakpoint_continue.go
│ ├── sys_api.go
│ └── sys_menu.go
├── model
├── modelInterface
│ └── interface.go
├── sysModel
│ ├── sys_workFlowProcess.go
│ ├── sys_system.go
│ ├── sys_jwt_blacklist.go
│ ├── sys_worfFlow.go
│ ├── sys_menu_authority.go
│ ├── sys_api.go
│ ├── sys_authority.go
│ ├── sys_casbin.go
│ ├── sys_user.go
│ └── sys_base_menu.go
└── dbModel
│ ├── exa_fileUploadAndDownload.go
│ └── exa_breakpoint_continue.go
├── router
├── sys_base.go
├── sys_jwt.go
├── sys_workflow.go
├── sys_casbin.go
├── sys_system.go
├── sys_user.go
├── sys_authority.go
├── sys_api.go
├── sys_menu.go
└── exp_fileUploadAndDownload.go
├── .gitignore
├── middleware
├── loadtls.go
├── casbin_rcba.go
├── cors.go
├── logger.go
└── jwt.go
├── init
├── registTable
│ └── regist_table.go
├── qmsql
│ └── initMysql.go
├── initRedis
│ └── init_redis.go
├── qmlog
│ └── qmlog.go
└── initRouter
│ └── init_router.go
├── cmd
└── windows.go
├── main.go
├── go.mod
├── config
└── config.go
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.sql linguist-language=GO
--------------------------------------------------------------------------------
/QMPlusVuePage/.env.production:
--------------------------------------------------------------------------------
1 | ENV = 'production'
2 | VUE_APP_BASE_API = '/'
--------------------------------------------------------------------------------
/QMPlusVuePage/.env.development:
--------------------------------------------------------------------------------
1 | ENV = 'development'
2 | VUE_APP_BASE_API = '/api'
--------------------------------------------------------------------------------
/QMPlusVuePage/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/utils/_import.js:
--------------------------------------------------------------------------------
1 | module.exports = file => () => {
2 | return import ('@/' + file)
3 | }
--------------------------------------------------------------------------------
/QMPlusVuePage/src/assets/qm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hairichuhe/nideshop-admin/HEAD/QMPlusVuePage/src/assets/qm.png
--------------------------------------------------------------------------------
/QMPlusVuePage/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hairichuhe/nideshop-admin/HEAD/QMPlusVuePage/public/favicon.ico
--------------------------------------------------------------------------------
/QMPlusVuePage/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hairichuhe/nideshop-admin/HEAD/QMPlusVuePage/src/assets/logo.png
--------------------------------------------------------------------------------
/QMPlusVuePage/src/assets/notFound.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hairichuhe/nideshop-admin/HEAD/QMPlusVuePage/src/assets/notFound.png
--------------------------------------------------------------------------------
/QMPlusVuePage/public/qm-plus-img/132604444.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hairichuhe/nideshop-admin/HEAD/QMPlusVuePage/public/qm-plus-img/132604444.png
--------------------------------------------------------------------------------
/QMPlusVuePage/public/qm-plus-img/86891839.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hairichuhe/nideshop-admin/HEAD/QMPlusVuePage/public/qm-plus-img/86891839.png
--------------------------------------------------------------------------------
/tools/md5.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "crypto/md5"
5 | "encoding/hex"
6 | )
7 |
8 | func MD5V(str []byte) string {
9 | h := md5.New()
10 | h.Write(str)
11 | return hex.EncodeToString(h.Sum(nil))
12 | }
13 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/example/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/workflow/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/tools/array_to_string.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | )
7 |
8 | func ArrayToString(array []interface{}) string {
9 | return strings.Replace(strings.Trim(fmt.Sprint(array), "[]"), " ", ",", -1)
10 | }
11 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/superAdmin/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/test/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 动态路由测试
4 |
5 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/tools/directory.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import "os"
4 |
5 | func PathExists(path string) (bool, error) {
6 | _, err := os.Stat(path)
7 | if err == nil {
8 | return true, nil
9 | }
10 | if os.IsNotExist(err) {
11 | return false, nil
12 | }
13 | return false, err
14 | }
15 |
--------------------------------------------------------------------------------
/static/rbacmodel/rbac_model.conf:
--------------------------------------------------------------------------------
1 | [request_definition]
2 | r = sub, obj, act
3 |
4 | [policy_definition]
5 | p = sub, obj, act
6 |
7 | [role_definition]
8 | g = _, _
9 |
10 | [policy_effect]
11 | e = some(where (p.eft == allow))
12 |
13 | [matchers]
14 | m = r.sub == p.sub && ParamsMatch(r.obj, p.obj) && r.act == p.act
15 |
--------------------------------------------------------------------------------
/controller/servers/reportformat.go:
--------------------------------------------------------------------------------
1 | package servers
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | func ReportFormat(c *gin.Context, success bool, msg string, json gin.H) {
10 | // 开始时间
11 | c.JSON(http.StatusOK, gin.H{
12 | "success": success,
13 | "msg": msg,
14 | "data": json,
15 | })
16 | }
17 |
--------------------------------------------------------------------------------
/model/modelInterface/interface.go:
--------------------------------------------------------------------------------
1 | package modelInterface
2 |
3 | // 因为我也不确定项目要不要多人维护 所以定义了CURD接口 作为接口参考
4 | // 由于很多接口使用Restful模式 暂时不用泛型 有需要可以iss提供示例
5 |
6 | type PageInfo struct {
7 | Page int
8 | PageSize int
9 | }
10 |
11 | //分页接口
12 | type Paging interface {
13 | GetInfoList(PageInfo) (err error, list interface{}, total int)
14 | }
15 |
--------------------------------------------------------------------------------
/router/sys_base.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "nideshop-admin/controller/api"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func InitBaseRouter(Router *gin.RouterGroup) (R gin.IRoutes) {
9 | BaseRouter := Router.Group("base")
10 | {
11 | BaseRouter.POST("regist", api.Regist)
12 | BaseRouter.POST("login", api.Login)
13 | }
14 | return BaseRouter
15 | }
16 |
--------------------------------------------------------------------------------
/router/sys_jwt.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "nideshop-admin/controller/api"
5 | "nideshop-admin/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | func InitJwtRouter(Router *gin.RouterGroup) {
10 | ApiRouter := Router.Group("jwt").Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
11 | {
12 | ApiRouter.POST("jsonInBlacklist", api.JsonInBlacklist) //jwt加入黑名单
13 | }
14 | }
--------------------------------------------------------------------------------
/tools/struct_to_map.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import "reflect"
4 |
5 | // 利用反射将结构体转化为map
6 | func StructToMap(obj interface{}) map[string]interface{}{
7 | obj1 := reflect.TypeOf(obj)
8 | obj2 := reflect.ValueOf(obj)
9 |
10 | var data = make(map[string]interface{})
11 | for i := 0; i < obj1.NumField(); i++ {
12 | data[obj1.Field(i).Name] = obj2.Field(i).Interface()
13 | }
14 | return data
15 | }
--------------------------------------------------------------------------------
/QMPlusVuePage/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
23 |
--------------------------------------------------------------------------------
/model/sysModel/sys_workFlowProcess.go:
--------------------------------------------------------------------------------
1 | package sysModel
2 |
3 | import "github.com/jinzhu/gorm"
4 |
5 | // 工作流流转表
6 | type SysWorkFlowProcess struct {
7 | gorm.Model
8 | ApplicationID uint // 当前工作流所属申请的ID
9 | CurrentNode string // 当前进度节点
10 | HistoricalNode string //上一个进度节点
11 | CurrentUser string // 当前进度操作人
12 | HistoricalUser string // 上一个进度的操作人
13 | State bool // 状态 是否是正在进行的状态
14 | }
15 |
--------------------------------------------------------------------------------
/router/sys_workflow.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "nideshop-admin/controller/api"
5 | "nideshop-admin/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | func InitWorkflowRouter(Router *gin.RouterGroup) {
10 | WorkflowRouter := Router.Group("workflow").Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
11 | {
12 | WorkflowRouter.POST("createWorkFlow", api.CreateWorkFlow) // 创建工作流
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/utils/asyncRouter.js:
--------------------------------------------------------------------------------
1 | const _import = require('./_import') //获取组件的方法
2 | export const asyncRouterHandle = (asyncRouter) => {
3 | asyncRouter.map(item => {
4 | if (item.component) {
5 | item.component = _import(item.component)
6 | } else {
7 | delete item['component']
8 | }
9 | if (item.children) {
10 | asyncRouterHandle(item.children)
11 | }
12 | })
13 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | go.sum
2 | .idea/
3 | log/
4 | *.exe
5 | /QMPlusVuePage/node_modules/
6 | /QMPlusVuePage/package-lock.json
7 | # Compiled Object files, Static and Dynamic libs (Shared Objects)
8 | *.o
9 | *.a
10 | *.so
11 |
12 | # Folders
13 | _obj
14 | _test
15 |
16 | # Architecture specific extensions/prefixes
17 | *.[568vq]
18 | [568vq].out
19 |
20 | *.cgo1.go
21 | *.cgo2.c
22 | _cgo_defun.c
23 | _cgo_gotypes.go
24 | _cgo_export.*
25 |
26 | _testmain.go
27 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/api/jwt.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | // @Tags jwt
4 | // @Summary jwt加入黑名单
5 | // @Security ApiKeyAuth
6 | // @accept application/json
7 | // @Produce application/json
8 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"拉黑成功"}"
9 | // @Router /jwt/jsonInBlacklist [post]
10 |
11 | export const jsonInBlacklist = () => {
12 | return service({
13 | url: "/jwt/jsonInBlacklist",
14 | method: 'post',
15 | })
16 | }
--------------------------------------------------------------------------------
/router/sys_casbin.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "nideshop-admin/controller/api"
5 | "nideshop-admin/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | func InitCasbinRouter(Router *gin.RouterGroup) {
10 | BaseRouter := Router.Group("casbin").Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
11 | {
12 | BaseRouter.POST("casbinPUpdata", api.CasbinPUpdata)
13 | BaseRouter.POST("getPolicyPathByAuthorityId", api.GetPolicyPathByAuthorityId)
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/utils/bus.js:
--------------------------------------------------------------------------------
1 | const install = (Vue) => {
2 | const Bus = new Vue({
3 | methods: {
4 | emit(event, ...args) {
5 | this.$emit(event, ...args)
6 | },
7 | on(event, cb) {
8 | this.$on(event, cb)
9 | },
10 | off(event, cb) {
11 | this.$off(event, cb)
12 | }
13 | },
14 | })
15 | Vue.prototype.$bus = Bus
16 | }
17 |
18 | export default install
--------------------------------------------------------------------------------
/router/sys_system.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "nideshop-admin/controller/api"
5 | "nideshop-admin/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | func InitSystemRouter(Router *gin.RouterGroup) {
10 | UserRouter := Router.Group("system").Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
11 | {
12 | UserRouter.POST("getSystemConfig", api.GetSystemConfig) // 获取配置文件内容
13 | UserRouter.POST("setSystemConfig", api.SetSystemConfig) // 设置配置文件内容
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/QMPlusVuePage/README.md:
--------------------------------------------------------------------------------
1 | # qm-plus-vue-page
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Run your tests
19 | ```
20 | npm run test
21 | ```
22 |
23 | ### Lints and fixes files
24 | ```
25 | npm run lint
26 | ```
27 |
28 | ### Customize configuration
29 | See [Configuration Reference](https://cli.vuejs.org/config/).
30 |
--------------------------------------------------------------------------------
/model/sysModel/sys_system.go:
--------------------------------------------------------------------------------
1 | package sysModel
2 |
3 | import (
4 | "nideshop-admin/config"
5 | "nideshop-admin/tools"
6 | )
7 |
8 | type System struct {
9 | Config config.Config
10 | }
11 |
12 | func (s *System)GetSystemConfig()(err error,conf config.Config){
13 | return nil,config.GinVueAdminconfig
14 | }
15 |
16 | func (s *System)SetSystemConfig()(err error){
17 | confs:= tools.StructToMap(s.Config)
18 | for k,v:= range confs {
19 | config.VTool.Set(k,v)
20 | }
21 | err = config.VTool.WriteConfig()
22 | return err
23 | }
--------------------------------------------------------------------------------
/QMPlusVuePage/src/api/workflow.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Summary 删除角色
3 | // @Security ApiKeyAuth
4 | // @accept application/json
5 | // @Produce application/json
6 | // @Param data body {authorityId uint} true "删除角色"
7 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
8 | // @Router /authority/deleteAuthority [post]
9 | export const createWorkFlow = (data) => {
10 | return service({
11 | url: "/workflow/createWorkFlow",
12 | method: 'post',
13 | data
14 | })
15 | }
--------------------------------------------------------------------------------
/QMPlusVuePage/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import VuexPersistence from 'vuex-persist'
4 |
5 | import { user } from "@/store/module/user"
6 | import { router } from "@/store/module/router"
7 |
8 | Vue.use(Vuex)
9 |
10 |
11 |
12 | const vuexLocal = new VuexPersistence({
13 | storage: window.localStorage,
14 | modules: ['user']
15 | })
16 | export const store = new Vuex.Store({
17 | modules: {
18 | user,
19 | router
20 | },
21 | plugins: [vuexLocal.plugin]
22 | })
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/layout/aside/asideComponent/menuItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{routerInfo.meta.title}}
5 |
6 |
7 |
8 |
21 |
--------------------------------------------------------------------------------
/middleware/loadtls.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | "github.com/unrolled/secure"
7 | )
8 |
9 | // 用https把这个中间件在router里面use一下就好
10 |
11 | func LoadTls() gin.HandlerFunc {
12 | return func(c *gin.Context) {
13 | middleware := secure.New(secure.Options{
14 | SSLRedirect: true,
15 | SSLHost: "localhost:443",
16 | })
17 | err := middleware.Process(c.Writer, c.Request)
18 | if err != nil {
19 | //如果出现错误,请不要继续。
20 | fmt.Println(err)
21 | return
22 | }
23 | // 继续往下处理
24 | c.Next()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/controller/servers/paging.go:
--------------------------------------------------------------------------------
1 | package servers
2 |
3 | import (
4 | "nideshop-admin/init/qmsql"
5 | "nideshop-admin/model/modelInterface"
6 | "github.com/jinzhu/gorm"
7 | )
8 |
9 | //获取分页功能 接收实现了分页接口的结构体 返回搜索完成的结果 许需要自行scan 或者find
10 | func PagingServer(paging modelInterface.Paging, info modelInterface.PageInfo) (err error, db *gorm.DB, total int) {
11 | limit := info.PageSize
12 | offset := info.PageSize * (info.Page - 1)
13 | err = qmsql.DEFAULTDB.Model(paging).Count(&total).Error
14 | db = qmsql.DEFAULTDB.Limit(limit).Offset(offset).Order("id desc")
15 | return err, db, total
16 | }
17 |
--------------------------------------------------------------------------------
/init/registTable/regist_table.go:
--------------------------------------------------------------------------------
1 | package registTable
2 |
3 | import (
4 | "nideshop-admin/model/dbModel"
5 | "nideshop-admin/model/sysModel"
6 | "github.com/jinzhu/gorm"
7 | )
8 |
9 | //注册数据库表专用
10 | func RegistTable(db *gorm.DB) {
11 | db.AutoMigrate(sysModel.SysUser{},
12 | sysModel.SysAuthority{},
13 | sysModel.SysMenu{},
14 | sysModel.SysApi{},
15 | sysModel.SysBaseMenu{},
16 | sysModel.JwtBlacklist{},
17 | sysModel.SysWorkflow{},
18 | sysModel.SysWorkflowStepInfo{},
19 | dbModel.ExaFileUploadAndDownload{},
20 | dbModel.ExaFile{},
21 | dbModel.ExaFileChunk{},
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/router/sys_user.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "nideshop-admin/controller/api"
5 | "nideshop-admin/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | func InitUserRouter(Router *gin.RouterGroup) {
10 | UserRouter := Router.Group("user").Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
11 | {
12 | UserRouter.POST("changePassword", api.ChangePassword) // 修改密码
13 | UserRouter.POST("uploadHeaderImg", api.UploadHeaderImg) //上传头像
14 | UserRouter.POST("getUserList", api.GetUserList) // 分页获取用户列表
15 | UserRouter.POST("setUserAuthority", api.SetUserAuthority) //设置用户权限
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/init/qmsql/initMysql.go:
--------------------------------------------------------------------------------
1 | package qmsql
2 |
3 | import (
4 | "nideshop-admin/config"
5 | "github.com/jinzhu/gorm"
6 | _ "github.com/jinzhu/gorm/dialects/mysql"
7 | "log"
8 | )
9 |
10 | var DEFAULTDB *gorm.DB
11 |
12 | //初始化数据库并产生数据库全局变量
13 | func InitMysql(admin config.MysqlAdmin) *gorm.DB {
14 | if db, err := gorm.Open("mysql", admin.Username+":"+admin.Password+"@("+admin.Path+")/"+admin.Dbname+"?"+admin.Config); err != nil {
15 | log.Printf("DEFAULTDB数据库启动异常%S", err)
16 | } else {
17 | DEFAULTDB = db
18 | DEFAULTDB.DB().SetMaxIdleConns(10)
19 | DEFAULTDB.DB().SetMaxOpenConns(100)
20 | }
21 | return DEFAULTDB
22 | }
23 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/layout/aside/asideComponent/asyncSubmenu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{routerInfo.meta.title}}
6 |
7 |
8 |
9 |
10 |
11 |
24 |
--------------------------------------------------------------------------------
/QMPlusVuePage/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | qm-plus-vue-page
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/router/sys_authority.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "nideshop-admin/controller/api"
5 | "nideshop-admin/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | func InitAuthorityRouter(Router *gin.RouterGroup) {
10 | AuthorityRouter := Router.Group("authority").Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
11 | {
12 | AuthorityRouter.POST("createAuthority", api.CreateAuthority) //创建角色
13 | AuthorityRouter.POST("deleteAuthority", api.DeleteAuthority) //删除角色
14 | AuthorityRouter.POST("getAuthorityList", api.GetAuthorityList) //获取角色列表
15 | AuthorityRouter.POST("setDataAuthority", api.SetDataAuthority) //设置角色资源权限
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/router/sys_api.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "nideshop-admin/controller/api"
5 | "nideshop-admin/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | func InitApiRouter(Router *gin.RouterGroup) {
10 | ApiRouter := Router.Group("api").Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
11 | {
12 | ApiRouter.POST("createApi", api.CreateApi) //创建Api
13 | ApiRouter.POST("deleteApi", api.DeleteApi) //删除Api
14 | ApiRouter.POST("getApiList", api.GetApiList) //获取Api列表
15 | ApiRouter.POST("getApiById", api.GetApiById) //获取单条Api消息
16 | ApiRouter.POST("updataApi", api.UpdataApi) //更新api
17 | ApiRouter.POST("getAllApis", api.GetAllApis) // 获取所有api
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/init/initRedis/init_redis.go:
--------------------------------------------------------------------------------
1 | package initRedis
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/config"
6 | "github.com/go-redis/redis"
7 | )
8 |
9 | var DEFAULTREDIS *redis.Client
10 |
11 | func InitRedis() (client *redis.Client) {
12 | client = redis.NewClient(&redis.Options{
13 | Addr: config.GinVueAdminconfig.RedisAdmin.Addr,
14 | Password: config.GinVueAdminconfig.RedisAdmin.Password, // no password set
15 | DB: config.GinVueAdminconfig.RedisAdmin.DB, // use default DB
16 | })
17 | pong, err := client.Ping().Result()
18 | if err != nil {
19 | fmt.Println(pong, err)
20 | } else {
21 | fmt.Println(pong, err)
22 | DEFAULTREDIS = client
23 | }
24 | return client
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/windows.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/config"
6 | "github.com/gin-gonic/gin"
7 | "net/http"
8 | "time"
9 | )
10 |
11 | func RunWindowsServer(Router *gin.Engine) {
12 | s := &http.Server{
13 | Addr: fmt.Sprintf(":%d", config.GinVueAdminconfig.System.Addr),
14 | Handler: Router,
15 | ReadTimeout: 10 * time.Second,
16 | WriteTimeout: 10 * time.Second,
17 | MaxHeaderBytes: 1 << 20,
18 | }
19 | time.Sleep(10 * time.Microsecond)
20 | fmt.Printf(`欢迎使用 Gin-Vue-Admin
21 | 作者:奇淼 And Spike666
22 | 微信:shouzi_1994
23 | 默认自动化文档地址:http://127.0.0.1%s/swagger/index.html
24 | 默认前端文件运行地址:http://127.0.0.1:8080
25 | `, s.Addr)
26 | _ = s.ListenAndServe()
27 | }
28 |
--------------------------------------------------------------------------------
/middleware/casbin_rcba.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/controller/servers"
6 | "nideshop-admin/model/sysModel"
7 | "github.com/gin-gonic/gin"
8 | )
9 |
10 | //拦截器
11 | func CasbinHandler() gin.HandlerFunc {
12 | return func(c *gin.Context) {
13 | claims, _ := c.Get("claims")
14 | waitUse := claims.(*CustomClaims)
15 | //获取请求的URI
16 | obj := c.Request.URL.RequestURI()
17 | //获取请求方法
18 | act := c.Request.Method
19 | //获取用户的角色
20 | sub := waitUse.AuthorityId
21 | e := sysModel.Casbin()
22 | //判断策略中是否存在
23 | if e.Enforce(sub, obj, act) {
24 | c.Next()
25 | } else {
26 | servers.ReportFormat(c, false, fmt.Sprintf("权限不足"), gin.H{})
27 | c.Abort()
28 | return
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/controller/api/sys_workFlow.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/controller/servers"
6 | "nideshop-admin/model/sysModel"
7 | "github.com/gin-gonic/gin"
8 | )
9 |
10 | // @Tags workflow
11 | // @Summary 注册工作流
12 | // @Produce application/json
13 | // @Param data body sysModel.SysWorkflow true "注册工作流接口"
14 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"注册成功"}"
15 | // @Router /workflow/createWorkFlow [post]
16 | func CreateWorkFlow(c *gin.Context) {
17 | var wk sysModel.SysWorkflow
18 | _ = c.ShouldBind(&wk)
19 | err := wk.Create()
20 | if err != nil {
21 | servers.ReportFormat(c, false, fmt.Sprintf("获取失败:%v", err), gin.H{})
22 | } else {
23 | servers.ReportFormat(c, true, "获取成功", gin.H{})
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/static/config/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "casbinconfig": {
3 | "modelPath": "./static/rbacmodel/rbac_model.conf"
4 | },
5 | "jwt": {
6 | "signingKey": "nideshop"
7 | },
8 | "mysqladmin": {
9 | "username": "root",
10 | "password": "xwkj123",
11 | "path": "127.0.0.1:3306",
12 | "dbname": "nideshop",
13 | "config": "charset=utf8mb4\u0026parseTime=True\u0026loc=Local"
14 | },
15 | "upload": {
16 | "domain": "http://localhost:8080/",
17 | "path": "B:/gopath/src/nideshop-admin/QMPlusVuePage/public/"
18 | },
19 | "redisadmin": {
20 | "addr": "127.0.0.1:6379",
21 | "password": "xwkj123",
22 | "db": 0
23 | },
24 | "system": {
25 | "useMultipoint": false,
26 | "env": "develop",
27 | "addr": 8888
28 | }
29 | }
--------------------------------------------------------------------------------
/middleware/cors.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "net/http"
6 | )
7 |
8 | // 处理跨域请求,支持options访问
9 | func Cors() gin.HandlerFunc {
10 | return func(c *gin.Context) {
11 | method := c.Request.Method
12 | c.Header("Access-Control-Allow-Origin", "*")
13 | c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
14 | c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
15 | c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
16 | c.Header("Access-Control-Allow-Credentials", "true")
17 |
18 | //放行所有OPTIONS方法
19 | if method == "OPTIONS" {
20 | c.AbortWithStatus(http.StatusNoContent)
21 | }
22 | // 处理请求
23 | c.Next()
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/controller/api/sys_jwt_blacklist.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/controller/servers"
6 | "nideshop-admin/model/sysModel"
7 | "github.com/gin-gonic/gin"
8 | )
9 |
10 | // @Tags jwt
11 | // @Summary jwt加入黑名单
12 | // @Security ApiKeyAuth
13 | // @accept application/json
14 | // @Produce application/json
15 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"拉黑成功"}"
16 | // @Router /jwt/jsonInBlacklist [post]
17 | func JsonInBlacklist(c *gin.Context){
18 | token := c.Request.Header.Get("x-token")
19 | ModelJwt := sysModel.JwtBlacklist{
20 | Jwt:token,
21 | }
22 | err := ModelJwt.JsonInBlacklist()
23 | if err != nil {
24 | servers.ReportFormat(c, false, fmt.Sprintf("jwt作废失败,%v", err), gin.H{})
25 | } else {
26 | servers.ReportFormat(c, true, "jwt作废成功", gin.H{})
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/utils/downloadImg.js:
--------------------------------------------------------------------------------
1 | export const downloadImage = (imgsrc, name) => { //下载图片地址和图片名
2 | var image = new Image();
3 | image.setAttribute("crossOrigin", "anonymous");
4 | image.onload = function() {
5 | var canvas = document.createElement("canvas");
6 | canvas.width = image.width;
7 | canvas.height = image.height;
8 | var context = canvas.getContext("2d");
9 | context.drawImage(image, 0, 0, image.width, image.height);
10 | var url = canvas.toDataURL("image/png"); //得到图片的base64编码数据
11 |
12 | var a = document.createElement("a"); // 生成一个a元素
13 | var event = new MouseEvent("click"); // 创建一个单击事件
14 | a.download = name || "photo"; // 设置图片名称
15 | a.href = url; // 将生成的URL设置为a.href属性
16 | a.dispatchEvent(event); // 触发a的单击事件
17 | };
18 | image.src = imgsrc;
19 | }
--------------------------------------------------------------------------------
/QMPlusVuePage/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 |
4 | Vue.use(Router)
5 |
6 | const baseRouters = [{
7 | path: '/',
8 | redirect: '/login'
9 | },
10 | {
11 | path: '/login',
12 | name: 'login',
13 | component: () =>
14 | import ('@/view/login/login.vue')
15 | },
16 | {
17 | path: '/regist',
18 | name: 'regist',
19 | component: () =>
20 | import ('@/view/login/regist.vue')
21 | },
22 | {
23 | path: "/404",
24 | name: "404",
25 | component: () =>
26 | import ('@/view/error/index.vue')
27 | }
28 | ]
29 |
30 | // 需要通过后台数据来生成的组件
31 |
32 | const createRouter = () => new Router({
33 | routes: baseRouters
34 | })
35 |
36 | const router = createRouter()
37 |
38 | export default router
--------------------------------------------------------------------------------
/QMPlusVuePage/src/api/system.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | // @Tags systrm
4 | // @Summary 获取配置文件内容
5 | // @Security ApiKeyAuth
6 | // @Produce application/json
7 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
8 | // @Router /system/getSystemConfig [post]
9 | export const getSystemConfig = () => {
10 | return service({
11 | url: "/system/getSystemConfig",
12 | method: 'post',
13 | })
14 | }
15 |
16 | // @Tags system
17 | // @Summary 设置配置文件内容
18 | // @Security ApiKeyAuth
19 | // @Produce application/json
20 | // @Param data body sysModel.System true
21 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
22 | // @Router /system/setSystemConfig [post]
23 | export const setSystemConfig = (data) => {
24 | return service({
25 | url: "/system/setSystemConfig",
26 | method: 'post',
27 | data
28 | })
29 | }
--------------------------------------------------------------------------------
/tools/hasGap.go:
--------------------------------------------------------------------------------
1 | // 空值校验工具 仅用于检验空字符串 其余类型请勿使用
2 |
3 | package tools
4 |
5 | import (
6 | "errors"
7 | "fmt"
8 | "reflect"
9 | )
10 |
11 | func HasGap(input interface{}) error {
12 | getType := reflect.TypeOf(input)
13 | getValue := reflect.ValueOf(input)
14 | // 获取方法字段
15 | for i := 0; i < getType.NumField(); i++ {
16 | field := getType.Field(i)
17 | value := getValue.Field(i).Interface()
18 | switch value.(type) {
19 | case string:
20 | if value == "" {
21 | fmt.Printf("%s为空", field.Name)
22 | return errors.New(fmt.Sprintf("%s为空", field.Name))
23 | }
24 | default:
25 | if value == nil {
26 | fmt.Printf("%s为空", field.Name)
27 | return errors.New(fmt.Sprintf("%s为空", field.Name))
28 | }
29 | }
30 | }
31 | // 获取方法
32 | // 1. 先获取interface的reflect.Type,然后通过.NumMethod进行遍历
33 | //for i := 0; i < getType.NumMethod(); i++ {
34 | // m := getType.Method(i)
35 | // fmt.Printf("%s: %v\n", m.Name, m.Type)
36 | //}
37 | return nil
38 | }
39 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/components/mixins/infoList.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | page: 1,
5 | total: 10,
6 | pageSize: 10,
7 | tableData: [],
8 | searchInfo: {}
9 | }
10 | },
11 | methods: {
12 | handleSizeChange(val) {
13 | this.pageSize = val
14 | this.getTableData()
15 | },
16 | handleCurrentChange(val) {
17 | this.page = val
18 | this.getTableData()
19 | },
20 | async getTableData(page = this.page, pageSize = this.pageSize) {
21 | const table = await this.listApi({ page, pageSize, ...this.searchInfo })
22 | this.tableData = table.data[this.listKey]
23 | this.total = table.data.total
24 | this.page = table.data.page
25 | this.pageSize = table.data.pageSize
26 | }
27 | },
28 | mounted() {
29 | this.getTableData()
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/model/sysModel/sys_jwt_blacklist.go:
--------------------------------------------------------------------------------
1 | package sysModel
2 |
3 | import (
4 | "nideshop-admin/init/initRedis"
5 | "nideshop-admin/init/qmsql"
6 | "github.com/jinzhu/gorm"
7 | )
8 |
9 | type JwtBlacklist struct {
10 | gorm.Model
11 | Jwt string `gorm:"type:text"`
12 | }
13 |
14 | func (j *JwtBlacklist) JsonInBlacklist() (err error) {
15 | err = qmsql.DEFAULTDB.Create(j).Error
16 | return
17 | }
18 |
19 | //判断JWT是否在黑名单内部
20 | func (j *JwtBlacklist) IsBlacklist(Jwt string) bool {
21 | isNotFound := qmsql.DEFAULTDB.Where("jwt = ?", Jwt).First(j).RecordNotFound()
22 | return !isNotFound
23 | }
24 |
25 | //判断当前用户是否在线
26 | func (j *JwtBlacklist) GetRedisJWT(userName string) (err error, RedisJWT string) {
27 | RedisJWT, err = initRedis.DEFAULTREDIS.Get(userName).Result()
28 | return err, RedisJWT
29 | }
30 |
31 | //设置当前用户在线
32 | func (j *JwtBlacklist) SetRedisJWT(userName string) (err error) {
33 | err = initRedis.DEFAULTREDIS.Set(userName, j.Jwt, 1000*1000*1000*60*60*24*7).Err()
34 | return err
35 | }
36 |
--------------------------------------------------------------------------------
/tools/des.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "bytes"
5 | "crypto/cipher"
6 | "crypto/des"
7 | )
8 |
9 | func padding(src []byte, blocksize int) []byte {
10 | n := len(src)
11 | padnum := blocksize - n%blocksize
12 | pad := bytes.Repeat([]byte{byte(padnum)}, padnum)
13 | dst := append(src, pad...)
14 | return dst
15 | }
16 |
17 | func unpadding(src []byte) []byte {
18 | n := len(src)
19 | unpadnum := int(src[n-1])
20 | dst := src[:n-unpadnum]
21 | return dst
22 | }
23 |
24 | func EncryptDES(src []byte) []byte {
25 | key := []byte("qimiao66")
26 | block, _ := des.NewCipher(key)
27 | src = padding(src, block.BlockSize())
28 | blockmode := cipher.NewCBCEncrypter(block, key)
29 | blockmode.CryptBlocks(src, src)
30 | return src
31 | }
32 |
33 | func DecryptDES(src []byte) []byte {
34 | key := []byte("qimiao66")
35 | block, _ := des.NewCipher(key)
36 | blockmode := cipher.NewCBCDecrypter(block, key)
37 | blockmode.CryptBlocks(src, src)
38 | src = unpadding(src)
39 | return src
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/layout/aside/asideComponent/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
38 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/style/base.scss:
--------------------------------------------------------------------------------
1 | .clearflex {
2 | *zoom: 1;
3 | }
4 |
5 | .clearflex:after {
6 | content: '';
7 | display: block;
8 | height: 0;
9 | visibility: hidden;
10 | clear: both;
11 | }
12 |
13 | .fl-left {
14 | float: left;
15 | }
16 |
17 | .fl-right {
18 | float: right;
19 | }
20 |
21 | .mg {
22 | margin: 10px !important;
23 | }
24 |
25 | .left-mg-xs {
26 | margin-left: 6px !important;
27 | }
28 |
29 | .left-mg-sm {
30 | margin-left: 10px !important;
31 | }
32 |
33 | .left-mg-md {
34 | margin-left: 14px !important;
35 | }
36 |
37 | .top-mg-lg {
38 | margin-top: 20px !important;
39 | }
40 |
41 | .tb-mg-lg {
42 | margin: 20px 0 !important;
43 | }
44 |
45 | .bottom-mg-lg {
46 | margin-bottom: 20px !important;
47 | }
48 |
49 | .left-mg-lg {
50 | margin-left: 18px !important;
51 | }
52 |
53 | .title-1 {
54 | text-align: center;
55 | font-size: 32px;
56 | margin-bottom: 32px;
57 | }
58 |
59 | .title-3 {
60 | text-align: center;
61 | }
--------------------------------------------------------------------------------
/router/sys_menu.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "nideshop-admin/controller/api"
5 | "nideshop-admin/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | func InitMenuRouter(Router *gin.RouterGroup) (R gin.IRoutes) {
10 | MenuRouter := Router.Group("menu").Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
11 | {
12 | MenuRouter.POST("getMenu", api.GetMenu) //获取菜单树
13 | MenuRouter.POST("getMenuList", api.GetMenuList) // 分页获取基础menu列表
14 | MenuRouter.POST("addBaseMenu", api.AddBaseMenu) // 新增菜单
15 | MenuRouter.POST("getBaseMenuTree", api.GetBaseMenuTree) // 获取用户动态路由
16 | MenuRouter.POST("addMenuAuthority", api.AddMenuAuthority) // 增加menu和角色关联关系
17 | MenuRouter.POST("getMenuAuthority", api.GetMenuAuthority) // 获取指定角色menu
18 | MenuRouter.POST("deleteBaseMenu", api.DeleteBaseMenu) // 删除菜单
19 | MenuRouter.POST("updataBaseMenu", api.UpdataBaseMenu) // 更新菜单
20 | MenuRouter.POST("getBaseMenuById", api.GetBaseMenuById) //根据id获取菜单
21 | }
22 | return MenuRouter
23 | }
24 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | // 引入element
4 | import ElementUI from 'element-ui';
5 | import 'element-ui/lib/theme-chalk/index.css';
6 | Vue.use(ElementUI);
7 | // 引入封装的router
8 | import router from '@/router/index'
9 |
10 | // canvas背景插件
11 | import vueParticleLine from 'vue-particle-line'
12 | import 'vue-particle-line/dist/vue-particle-line.css'
13 | Vue.use(vueParticleLine)
14 |
15 | // 富文本插件
16 | import VueQuillEditor from 'vue-quill-editor'
17 | import 'quill/dist/quill.core.css'
18 | import 'quill/dist/quill.snow.css'
19 | import 'quill/dist/quill.bubble.css'
20 |
21 | Vue.use(VueQuillEditor)
22 |
23 | // markdown插件
24 | import mavonEditor from 'mavon-editor'
25 | import 'mavon-editor/dist/css/index.css'
26 |
27 | Vue.use(mavonEditor)
28 |
29 | import '@/permission'
30 | import { store } from '@/store/index'
31 | Vue.config.productionTip = false
32 |
33 | // 路由守卫
34 | import Bus from '@/utils/bus.js'
35 | Vue.use(Bus)
36 | new Vue({
37 | render: h => h(App),
38 | router,
39 | store
40 | }).$mount('#app')
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/error/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |

6 |
页面被神秘力量吸走了,请联系我们修复
7 |
↓
8 |

9 |
10 |
11 |
12 |
13 |
14 |
20 |
21 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/api/fileUploadAndDownload.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags FileUploadAndDownload
3 | // @Summary 分页文件列表
4 | // @Security ApiKeyAuth
5 | // @accept application/json
6 | // @Produce application/json
7 | // @Param data body modelInterface.PageInfo true "分页获取文件户列表"
8 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
9 | // @Router /fileUploadAndDownload/getFileList [post]
10 | export const getFileList = (data) => {
11 | return service({
12 | url: "/fileUploadAndDownload/getFileList",
13 | method: "post",
14 | data
15 | })
16 | }
17 |
18 | // @Tags FileUploadAndDownload
19 | // @Summary 删除文件
20 | // @Security ApiKeyAuth
21 | // @Produce application/json
22 | // @Param data body dbModel.FileUploadAndDownload true "传入文件里面id即可"
23 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"返回成功"}"
24 | // @Router /fileUploadAndDownload/deleteFile [post]
25 | export const deleteFile = (data) => {
26 | return service({
27 | url: "/fileUploadAndDownload/deleteFile",
28 | method: "post",
29 | data
30 | })
31 | }
--------------------------------------------------------------------------------
/QMPlusVuePage/src/api/casbin.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | // @Tags authority
4 | // @Summary 更改角色api权限
5 | // @Security ApiKeyAuth
6 | // @accept application/json
7 | // @Produce application/json
8 | // @Param data body api.CreateAuthorityPatams true "更改角色api权限"
9 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
10 | // @Router /casbin/casbinPUpdata [post]
11 |
12 | export const casbinPUpdata = (data) => {
13 | return service({
14 | url: "/casbin/casbinPUpdata",
15 | method: 'post',
16 | data
17 | })
18 | }
19 |
20 |
21 | // @Tags casbin
22 | // @Summary 获取权限列表
23 | // @Security ApiKeyAuth
24 | // @accept application/json
25 | // @Produce application/json
26 | // @Param data body api.CreateAuthorityPatams true "获取权限列表"
27 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
28 | // @Router /casbin/getPolicyPathByAuthorityId [post]
29 | export const getPolicyPathByAuthorityId = (data) => {
30 | return service({
31 | url: "/casbin/getPolicyPathByAuthorityId",
32 | method: 'post',
33 | data
34 | })
35 | }
--------------------------------------------------------------------------------
/router/exp_fileUploadAndDownload.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "nideshop-admin/controller/api"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func InitFileUploadAndDownloadRouter(Router *gin.RouterGroup) {
9 | FileUploadAndDownloadGroup := Router.Group("fileUploadAndDownload")
10 | //.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
11 | {
12 | FileUploadAndDownloadGroup.POST("/upload", api.UploadFile) // 上传文件
13 | FileUploadAndDownloadGroup.POST("/getFileList", api.GetFileList) // 获取上传文件列表
14 | FileUploadAndDownloadGroup.POST("/deleteFile", api.DeleteFile) // 删除指定文件
15 | FileUploadAndDownloadGroup.POST("/breakpointContinue", api.BreakpointContinue) // 断点续传
16 | FileUploadAndDownloadGroup.GET("/findFile", api.FindFile) // 查询当前文件成功的切片
17 | FileUploadAndDownloadGroup.POST("/breakpointContinueFinish", api.BreakpointContinueFinish) // 查询当前文件成功的切片
18 | FileUploadAndDownloadGroup.POST("/removeChunk", api.RemoveChunk) // 查询当前文件成功的切片
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/model/sysModel/sys_worfFlow.go:
--------------------------------------------------------------------------------
1 | package sysModel
2 |
3 | import (
4 | "nideshop-admin/init/qmsql"
5 | "github.com/jinzhu/gorm"
6 | )
7 |
8 | //工作流属性表
9 | type SysWorkflow struct {
10 | gorm.Model
11 | WorkflowNickName string `json:"workflowNickName"` // 工作流名称
12 | WorkflowName string `json:"workflowName"` // 工作流英文id
13 | WorkflowDescription string `json:"workflowDescription"` // 工作流描述
14 | WorkflowStepInfo []SysWorkflowStepInfo `json:"workflowStep"` // 工作流步骤
15 | }
16 |
17 | // 工作流状态表
18 | type SysWorkflowStepInfo struct {
19 | gorm.Model
20 | SysWorkflowID uint `json:"workflowID"` // 所属工作流ID
21 | IsStrat bool `json:"isStrat"` // 是否是开始流节点
22 | StepName string `json:"stepName"` // 工作流名称
23 | StepNo float64 `json:"stepNo"` // 步骤id (第几步)
24 | StepAuthorityID string `json:"stepAuthorityID"` // 操作者级别id
25 | IsEnd bool `json:"isEnd"` // 是否是完结流节点
26 | }
27 |
28 | //创建工作流
29 | func (wk *SysWorkflow) Create() error {
30 | err := qmsql.DEFAULTDB.Create(&wk).Error
31 | return err
32 | }
33 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/utils/data.js:
--------------------------------------------------------------------------------
1 | // 对Date的扩展,将 Date 转化为指定格式的String
2 | // 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
3 | // 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
4 | // (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
5 | // (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
6 | Date.prototype.Format = function(fmt) {
7 | var o = {
8 | "M+": this.getMonth() + 1, //月份
9 | "d+": this.getDate(), //日
10 | "h+": this.getHours(), //小时
11 | "m+": this.getMinutes(), //分
12 | "s+": this.getSeconds(), //秒
13 | "q+": Math.floor((this.getMonth() + 3) / 3), //季度
14 | "S": this.getMilliseconds() //毫秒
15 | };
16 | if (/(y+)/.test(fmt))
17 | fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
18 | for (var k in o)
19 | if (new RegExp("(" + k + ")").test(fmt))
20 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
21 | return fmt;
22 | }
23 |
24 | export function formatTimeToStr(times, pattern) {
25 | var d = new Date(times).Format("yyyy-MM-dd hh:mm:ss");
26 | if (pattern) {
27 | d = new Date(times).Format(pattern);
28 | }
29 | return d.toLocaleString();
30 | }
--------------------------------------------------------------------------------
/init/qmlog/qmlog.go:
--------------------------------------------------------------------------------
1 | package qmlog
2 |
3 | // 日志初始化包 调用qmlog.QMLog.Info 记录日志 24小时切割 日志保存7天 可自行设置
4 | import (
5 | "fmt"
6 | "nideshop-admin/tools"
7 | rotatelogs "github.com/lestrrat/go-file-rotatelogs"
8 | "github.com/rifflock/lfshook"
9 | "github.com/sirupsen/logrus"
10 | "os"
11 | "time"
12 | )
13 |
14 | var QMLog = logrus.New()
15 |
16 | //禁止logrus的输出
17 | func InitLog() *logrus.Logger {
18 | src, err := os.OpenFile(os.DevNull, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
19 | if err != nil {
20 | fmt.Println("err", err)
21 | }
22 | QMLog.Out = src
23 | QMLog.SetLevel(logrus.DebugLevel)
24 | if ok, _ := tools.PathExists("./log"); !ok {
25 | // Directory not exist
26 | fmt.Println("Create log.")
27 | _ = os.Mkdir("log", os.ModePerm)
28 | }
29 | apiLogPath := "./log/api.log"
30 | logWriter, err := rotatelogs.New(
31 | apiLogPath+".%Y-%m-%d-%H-%M.log",
32 | rotatelogs.WithLinkName(apiLogPath), // 生成软链,指向最新日志文件
33 | rotatelogs.WithMaxAge(7*24*time.Hour), // 文件最大保存时间
34 | rotatelogs.WithRotationTime(24*time.Hour), // 日志切割时间间隔
35 | )
36 | writeMap := lfshook.WriterMap{
37 | logrus.InfoLevel: logWriter,
38 | logrus.FatalLevel: logWriter,
39 | }
40 | lfHook := lfshook.NewHook(writeMap, &logrus.JSONFormatter{})
41 | QMLog.AddHook(lfHook)
42 | return QMLog
43 | }
44 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "nideshop-admin/cmd"
5 | "nideshop-admin/config"
6 | "nideshop-admin/init/initRedis"
7 | "nideshop-admin/init/initRouter"
8 | "nideshop-admin/init/qmlog"
9 | "nideshop-admin/init/qmsql"
10 | "nideshop-admin/init/registTable"
11 | //"runtime"
12 | )
13 |
14 | // @title Swagger Example API
15 | // @version 0.0.1
16 | // @description This is a sample Server pets
17 | // @securityDefinitions.apikey ApiKeyAuth
18 | // @in header
19 | // @name x-token
20 | // @BasePath /
21 |
22 | func main() {
23 |
24 | qmlog.InitLog() // 初始化日志
25 | db := qmsql.InitMysql(config.GinVueAdminconfig.MysqlAdmin) // 链接初始化数据库
26 | if config.GinVueAdminconfig.System.UseMultipoint {
27 | _ = initRedis.InitRedis() // 初始化redis服务
28 | }
29 | registTable.RegistTable(db) // 注册数据库表
30 | defer qmsql.DEFAULTDB.Close() // 程序结束前关闭数据库链接
31 | Router := initRouter.InitRouter() // 注册路由
32 | qmlog.QMLog.Info("服务器开启") // 日志测试代码
33 | //Router.RunTLS(":443","ssl.pem", "ssl.key") // https支持 需要添加中间件
34 | //sysType := runtime.GOOS
35 | //
36 | //if sysType == "linux" {
37 | // // LINUX系统
38 | // // 借助endless开发无感知重启后台 以及前端接口重启后台功能
39 | //}
40 | //if sysType == "windows" {
41 | // WIN系统
42 | cmd.RunWindowsServer(Router)
43 | //}
44 | }
45 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/dashbord/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
nideshop-admin by 奇淼 And krank666
4 |
点击动画获取联系方式
5 |
6 |
10 |
11 |

12 |
krank666微信
13 |
14 |
15 |

16 |
Mr.奇淼微信
17 |
18 |
19 |
22 |
23 | 当前版本号:v0.1.0
24 |
25 |
26 |
27 |
28 |
46 |
47 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/example/rte/rte.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 | 保存
13 |
14 |
15 |
16 | 发表
17 |
18 |
19 |
20 |
21 |
50 |
--------------------------------------------------------------------------------
/init/initRouter/init_router.go:
--------------------------------------------------------------------------------
1 | package initRouter
2 |
3 | import (
4 | _ "nideshop-admin/docs"
5 | "nideshop-admin/middleware"
6 | "nideshop-admin/router"
7 | "github.com/gin-gonic/gin"
8 | "github.com/swaggo/gin-swagger"
9 | "github.com/swaggo/gin-swagger/swaggerFiles"
10 | )
11 |
12 | //初始化总路由
13 | func InitRouter() *gin.Engine {
14 | var Router = gin.Default()
15 | //Router.Use(middleware.LoadTls()) // 打开就能玩https了
16 | Router.Use(middleware.Logger()) // 如果不需要日志 请关闭这里
17 | Router.Use(middleware.Cors()) // 跨域
18 | Router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
19 | ApiGroup := Router.Group("") // 方便统一添加路由组前缀 多服务器上线使用
20 | //Router.Use(middleware.Logger())
21 | router.InitUserRouter(ApiGroup) // 注册用户路由
22 | router.InitBaseRouter(ApiGroup) // 注册基础功能路由 不做鉴权
23 | router.InitMenuRouter(ApiGroup) // 注册menu路由
24 | router.InitAuthorityRouter(ApiGroup) // 注册角色路由
25 | router.InitApiRouter(ApiGroup) // 注册功能api路由
26 | router.InitFileUploadAndDownloadRouter(ApiGroup) // 文件上传下载功能路由
27 | router.InitWorkflowRouter(ApiGroup) // 工作流相关路由
28 | router.InitCasbinRouter(ApiGroup) // 权限相关路由
29 | router.InitJwtRouter(ApiGroup) // jwt相关路由
30 | router.InitSystemRouter(ApiGroup) // system相关路由
31 | return Router
32 | }
33 |
--------------------------------------------------------------------------------
/model/dbModel/exa_fileUploadAndDownload.go:
--------------------------------------------------------------------------------
1 | package dbModel
2 |
3 | import (
4 | "nideshop-admin/controller/servers"
5 | "nideshop-admin/init/qmsql"
6 | "nideshop-admin/model/modelInterface"
7 | "github.com/jinzhu/gorm"
8 | )
9 |
10 | type ExaFileUploadAndDownload struct {
11 | gorm.Model
12 | Name string `json:"name"`
13 | Url string `json:"url"`
14 | Tag string `json:"tag"`
15 | Key string `json:"key"`
16 | }
17 |
18 | func (f *ExaFileUploadAndDownload) Upload() error {
19 | err := qmsql.DEFAULTDB.Create(f).Error
20 | return err
21 | }
22 |
23 | func (f *ExaFileUploadAndDownload) DeleteFile() error {
24 | err := qmsql.DEFAULTDB.Where("id = ?", f.ID).Unscoped().Delete(f).Error
25 | return err
26 | }
27 |
28 | func (f *ExaFileUploadAndDownload) FindFile() (error, ExaFileUploadAndDownload) {
29 | var file ExaFileUploadAndDownload
30 | err := qmsql.DEFAULTDB.Where("id = ?", f.ID).First(&file).Error
31 | return err, file
32 | }
33 |
34 | // 分页获取数据 需要分页实现这个接口即可
35 | func (f *ExaFileUploadAndDownload) GetInfoList(info modelInterface.PageInfo) (err error, list interface{}, total int) {
36 | // 封装分页方法 调用即可 传入 当前的结构体和分页信息
37 | err, db, total := servers.PagingServer(f, info)
38 | if err != nil {
39 | return
40 | } else {
41 | var fileLists []ExaFileUploadAndDownload
42 | err = db.Order("updated_at desc").Find(&fileLists).Error
43 | return err, fileLists, total
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/store/module/router.js:
--------------------------------------------------------------------------------
1 | import { asyncRouterHandle } from '@/utils/asyncRouter';
2 |
3 | import { asyncMenu } from '@/api/menu'
4 |
5 | export const router = {
6 | namespaced: true,
7 | state: {
8 | asyncRouters: []
9 | },
10 | mutations: {
11 | // 设置动态路由
12 | setAsyncRouter(state, asyncRouters) {
13 | state.asyncRouters = asyncRouters
14 | }
15 | },
16 | actions: {
17 | // 从后台获取动态路由
18 | async SetAsyncRouter({ commit }) {
19 | const baseRouter = [{
20 | path: '/layout',
21 | name: 'layout',
22 | component: "view/layout/index.vue",
23 | meta: {
24 | title: "底层layout"
25 | },
26 | children: []
27 | }]
28 | const asyncRouterRes = await asyncMenu()
29 | const asyncRouter = asyncRouterRes.data.menus
30 | baseRouter[0].children = asyncRouter
31 | baseRouter.push({
32 | path: '*',
33 | redirect: '/404'
34 |
35 | })
36 | asyncRouterHandle(baseRouter)
37 | commit('setAsyncRouter', baseRouter)
38 | return true
39 | }
40 | },
41 | getters: {
42 | // 获取动态路由
43 | asyncRouters(state) {
44 | return state.asyncRouters
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module nideshop-admin
2 |
3 | go 1.12
4 |
5 | require (
6 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc
7 | github.com/casbin/casbin v1.9.1
8 | github.com/casbin/gorm-adapter v1.0.0
9 | github.com/dgrijalva/jwt-go v3.2.0+incompatible
10 | github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
11 | github.com/fsnotify/fsnotify v1.4.7
12 | github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
13 | github.com/gin-gonic/gin v1.4.0
14 | github.com/go-redis/redis v6.15.6+incompatible
15 | github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
16 | github.com/jinzhu/gorm v1.9.10
17 | github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect
18 | github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f
19 | github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
20 | github.com/pkg/errors v0.8.1
21 | github.com/qiniu/api.v7 v7.2.5+incompatible
22 | github.com/qiniu/x v7.0.8+incompatible // indirect
23 | github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
24 | github.com/satori/go.uuid v1.2.0
25 | github.com/sirupsen/logrus v1.2.0
26 | github.com/spf13/viper v1.4.0
27 | github.com/swaggo/gin-swagger v1.2.0
28 | github.com/swaggo/swag v1.5.1
29 | github.com/tebeka/strftime v0.1.3 // indirect
30 | github.com/unrolled/secure v1.0.6
31 | qiniupkg.com/x v7.0.8+incompatible // indirect
32 | )
33 |
--------------------------------------------------------------------------------
/controller/api/sys_casbin.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/controller/servers"
6 | "nideshop-admin/model/sysModel"
7 | "github.com/gin-gonic/gin"
8 | )
9 |
10 | // @Tags casbin
11 | // @Summary 更改角色api权限
12 | // @Security ApiKeyAuth
13 | // @accept application/json
14 | // @Produce application/json
15 | // @Param data body sysModel.CasbinInReceive true "更改角色api权限"
16 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
17 | // @Router /casbin/casbinPUpdata [post]
18 | func CasbinPUpdata(c *gin.Context) {
19 | var cmr sysModel.CasbinInReceive
20 | _ = c.ShouldBind(&cmr)
21 | err := new(sysModel.CasbinModel).CasbinPUpdata(cmr.AuthorityId, cmr.CasbinInfos)
22 | if err != nil {
23 | servers.ReportFormat(c, false, fmt.Sprintf("添加规则失败,%v", err), gin.H{})
24 | } else {
25 | servers.ReportFormat(c, true, "添加规则成功", gin.H{})
26 | }
27 | }
28 |
29 | // @Tags casbin
30 | // @Summary 获取权限列表
31 | // @Security ApiKeyAuth
32 | // @accept application/json
33 | // @Produce application/json
34 | // @Param data body api.CreateAuthorityParams true "获取权限列表"
35 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
36 | // @Router /casbin/getPolicyPathByAuthorityId [post]
37 | func GetPolicyPathByAuthorityId(c *gin.Context) {
38 | var cmr sysModel.CasbinInReceive
39 | _ = c.ShouldBind(&cmr)
40 | paths := new(sysModel.CasbinModel).GetPolicyPathByAuthorityId(cmr.AuthorityId)
41 | servers.ReportFormat(c, true, "获取规则成功", gin.H{"paths": paths})
42 | }
43 |
--------------------------------------------------------------------------------
/controller/servers/upload.go:
--------------------------------------------------------------------------------
1 | package servers
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "mime/multipart"
7 | "nideshop-admin/config"
8 | "nideshop-admin/tools"
9 | "os"
10 | "time"
11 | )
12 |
13 | var domain string = config.GinVueAdminconfig.UpLoad.Domain // 访问的域名设置,为了在数据库中储存使用
14 | var filepath string = config.GinVueAdminconfig.UpLoad.Path // 你在七牛云的secretKey 这里是我个人测试号的key 仅供测试使用 恳请大家不要乱传东西
15 |
16 | // 接收两个参数 一个文件流 一个 bucket 你的七牛云标准空间的名字
17 | func Upload(file *multipart.FileHeader, bucket string) (err error, path string, key string) {
18 | f, e := file.Open()
19 | if e != nil {
20 | fmt.Println(e)
21 | return e, "", ""
22 | }
23 |
24 | suffix := tools.GetSuffix(file.Filename)
25 | mscond := int(time.Now().UnixNano()/1000000) - 1581341955458
26 | fileKey := fmt.Sprintf("%d%s", mscond, suffix) // 文件名格式 自己可以改 建议保证唯一性
27 | dst := filepath + bucket + "/" + fileKey //本地服务器文件保存位置
28 | defer f.Close()
29 | //创建 dst 文件
30 | err = os.MkdirAll(filepath+bucket, 0755)
31 | if err != nil {
32 | return err, "", ""
33 | }
34 | out, err := os.Create(dst)
35 | if err != nil {
36 | return err, "", ""
37 | }
38 | defer out.Close()
39 | // 拷贝文件
40 | _, err = io.Copy(out, f)
41 | if err != nil {
42 | return err, "", ""
43 | }
44 | return err, domain + bucket + "/" + fileKey, fileKey
45 | }
46 |
47 | func DeleteFile(bucket string, key string) error {
48 |
49 | src := filepath + bucket + "/" + key
50 | err := os.Remove(src)
51 | if err != nil {
52 | fmt.Println(err)
53 | return err
54 | }
55 | return nil
56 | }
57 |
--------------------------------------------------------------------------------
/middleware/logger.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "bytes"
5 | "nideshop-admin/init/qmlog"
6 | "net/http/httputil"
7 | "strings"
8 | "time"
9 |
10 | "github.com/gin-gonic/gin"
11 | )
12 |
13 | func Logger() gin.HandlerFunc {
14 | log := qmlog.QMLog
15 | return func(c *gin.Context) {
16 | // request time
17 | start := time.Now()
18 | // request path
19 | path := c.Request.URL.Path
20 | logFlag := true
21 | if strings.Contains(path, "swagger") {
22 | logFlag = false
23 | }
24 | // request ip
25 | clientIP := c.ClientIP()
26 | // method
27 | method := c.Request.Method
28 | // copy request content
29 | req, _ := httputil.DumpRequest(c.Request, true)
30 | if logFlag {
31 | log.Infof(`| %s | %s | %s | %5s | %s\n`,
32 | `Request :`, method, clientIP, path, string(req))
33 | }
34 | // replace writer
35 | cusWriter := &responseBodyWriter{
36 | ResponseWriter: c.Writer,
37 | body: bytes.NewBufferString(""),
38 | }
39 | c.Writer = cusWriter
40 | // handle request
41 | c.Next()
42 | // ending time
43 | end := time.Now()
44 | //execute time
45 | latency := end.Sub(start)
46 | statusCode := c.Writer.Status()
47 | if logFlag {
48 | log.Infof(`| %s | %3d | %13v | %s \n`,
49 | `Response:`,
50 | statusCode,
51 | latency,
52 | cusWriter.body.String())
53 | }
54 | }
55 | }
56 |
57 | type responseBodyWriter struct {
58 | gin.ResponseWriter
59 | body *bytes.Buffer
60 | }
61 |
62 | func (w responseBodyWriter) Write(b []byte) (int, error) {
63 | w.body.Write(b)
64 | return w.ResponseWriter.Write(b)
65 | }
66 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/permission.js:
--------------------------------------------------------------------------------
1 | import router from './router'
2 | import { store } from '@/store/index'
3 |
4 | let asyncRouterFlag = 0
5 |
6 | const whiteList = ['login', 'regist']
7 |
8 | router.beforeEach(async(to, from, next) => {
9 | const token = store.getters['user/token']
10 | // if (token) {
11 | // const expiresAt = store.getters['user/expiresAt']
12 | // const nowUnix = new Date().getTime()
13 | // const hasExpires = (expiresAt - nowUnix) < 0
14 | // if (hasExpires) {
15 | // store.dispatch['user/claerAll']
16 | // }
17 | // }
18 | // 在白名单中的判断情况
19 | if (whiteList.indexOf(to.name) > -1) {
20 | if (token) {
21 | next({ path: '/layout/dashbord' })
22 | } else {
23 | next()
24 | }
25 | } else {
26 | // 不在白名单中并且已经登陆的时候
27 | if (token) {
28 | // 添加flag防止多次获取动态路由和栈溢出
29 | if (!asyncRouterFlag) {
30 | asyncRouterFlag++
31 | await store.dispatch('router/SetAsyncRouter')
32 | const asyncRouters = store.getters['router/asyncRouters']
33 | router.addRoutes(asyncRouters)
34 | next({...to, replace: true })
35 | } else {
36 | next()
37 | }
38 | }
39 | // 不在白名单中并且未登陆的时候
40 | if (!token) {
41 | next({
42 | name: "login",
43 | query: {
44 | redirect: document.location.hash
45 | }
46 | })
47 | }
48 | }
49 | })
--------------------------------------------------------------------------------
/QMPlusVuePage/src/api/user.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | // @Summary 用户登录
4 | // @Produce application/json
5 | // @Param data body {username:"string",password:"string"}
6 | // @Router /base/login [post]
7 | export const login = (data) => {
8 | return service({
9 | url: "/base/login",
10 | method: 'post',
11 | data: data
12 | })
13 | }
14 |
15 | // @Summary 用户注册
16 | // @Produce application/json
17 | // @Param data body {username:"string",password:"string"}
18 | // @Router /base/resige [post]
19 | export const regist = (data) => {
20 | return service({
21 | url: "/base/regist",
22 | method: 'post',
23 | data: data
24 | })
25 | }
26 |
27 | // @Tags User
28 | // @Summary 分页获取用户列表
29 | // @Security ApiKeyAuth
30 | // @accept application/json
31 | // @Produce application/json
32 | // @Param data body modelInterface.PageInfo true "分页获取用户列表"
33 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
34 | // @Router /user/getUserList [post]
35 | export const getUserList = (data) => {
36 | return service({
37 | url: "/user/getUserList",
38 | method: 'post',
39 | data: data
40 | })
41 | }
42 |
43 |
44 | // @Tags User
45 | // @Summary 设置用户权限
46 | // @Security ApiKeyAuth
47 | // @accept application/json
48 | // @Produce application/json
49 | // @Param data body api.SetUserAuth true "设置用户权限"
50 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"修改成功"}"
51 | // @Router /user/setUserAuthority [post]
52 | export const setUserAuthority = (data) => {
53 | return service({
54 | url: "/user/setUserAuthority",
55 | method: 'post',
56 | data: data
57 | })
58 | }
--------------------------------------------------------------------------------
/QMPlusVuePage/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "qm-plus-vue-page",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "axios": "^0.19.0",
12 | "core-js": "^2.6.5",
13 | "element-ui": "^2.12.0",
14 | "mavon-editor": "^2.7.7",
15 | "node-sass": "^4.12.0",
16 | "path": "^0.12.7",
17 | "qs": "^6.8.0",
18 | "quill": "^1.3.7",
19 | "sass-loader": "^8.0.0",
20 | "script-ext-html-webpack-plugin": "^2.1.4",
21 | "vue": "^2.6.10",
22 | "vue-particle-line": "^0.1.4",
23 | "vue-quill-editor": "^3.0.6",
24 | "vue-router": "^3.1.3",
25 | "vuescroll": "^4.14.4",
26 | "vuex": "^3.1.1",
27 | "vuex-persist": "^2.1.0"
28 | },
29 | "devDependencies": {
30 | "@vue/cli-plugin-babel": "^3.11.0",
31 | "@vue/cli-plugin-eslint": "^3.11.0",
32 | "@vue/cli-service": "^3.11.0",
33 | "babel-eslint": "^10.0.1",
34 | "eslint": "^5.16.0",
35 | "eslint-plugin-vue": "^5.0.0",
36 | "vue-template-compiler": "^2.6.10"
37 | },
38 | "eslintConfig": {
39 | "root": true,
40 | "env": {
41 | "node": true
42 | },
43 | "extends": [
44 | "plugin:vue/essential",
45 | "eslint:recommended"
46 | ],
47 | "rules": {},
48 | "parserOptions": {
49 | "parser": "babel-eslint"
50 | }
51 | },
52 | "postcss": {
53 | "plugins": {
54 | "autoprefixer": {}
55 | }
56 | },
57 | "browserslist": [
58 | "> 1%",
59 | "last 2 versions"
60 | ]
61 | }
62 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/layout/aside/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
56 |
57 |
--------------------------------------------------------------------------------
/model/sysModel/sys_menu_authority.go:
--------------------------------------------------------------------------------
1 | package sysModel
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/init/qmsql"
6 | )
7 |
8 | // menu需要构建的点有点多 这里关联关系表直接把所有数据拿过来 用代码实现关联 后期实现主外键模式
9 | type SysMenu struct {
10 | SysBaseMenu
11 | MenuId string `json:"menuId"`
12 | AuthorityId string `json:"-"`
13 | Children []SysMenu `json:"children"`
14 | }
15 |
16 | type Meta struct {
17 | Title string `json:"title"`
18 | Icon string `json:"icon"`
19 | }
20 |
21 | // 为角色增加menu树
22 | func (m *SysMenu) AddMenuAuthority(menus []SysBaseMenu, authorityId string) (err error) {
23 | var menu SysMenu
24 | qmsql.DEFAULTDB.Where("authority_id = ? ", authorityId).Unscoped().Delete(&SysMenu{})
25 | for _, v := range menus {
26 | menu.SysBaseMenu = v
27 | menu.AuthorityId = authorityId
28 | menu.MenuId = fmt.Sprintf("%v", v.ID)
29 | menu.ID = 0
30 | err = qmsql.DEFAULTDB.Create(&menu).Error
31 | if err != nil {
32 | return err
33 | }
34 | }
35 | return nil
36 | }
37 |
38 | // 查看当前角色树
39 | func (m *SysMenu) GetMenuAuthority(authorityId string) (err error, menus []SysMenu) {
40 | err = qmsql.DEFAULTDB.Where("authority_id = ?", authorityId).Find(&menus).Error
41 | return err, menus
42 | }
43 |
44 | //获取动态路由树
45 | func (m *SysMenu) GetMenuTree(authorityId string) (err error, menus []SysMenu) {
46 | err = qmsql.DEFAULTDB.Where("authority_id = ? AND parent_id = ?", authorityId, 0).Order("sort", true).Find(&menus).Error
47 | for i := 0; i < len(menus); i++ {
48 | err = getChildrenList(&menus[i])
49 | }
50 | return err, menus
51 | }
52 |
53 | func getChildrenList(menu *SysMenu) (err error) {
54 | err = qmsql.DEFAULTDB.Where("authority_id = ? AND parent_id = ?", menu.AuthorityId, menu.MenuId).Order("sort", true).Find(&menu.Children).Error
55 | for i := 0; i < len(menu.Children); i++ {
56 | err = getChildrenList(&menu.Children[i])
57 | }
58 | return err
59 | }
60 |
--------------------------------------------------------------------------------
/controller/api/sys_system.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/controller/servers"
6 | "nideshop-admin/model/sysModel"
7 | "github.com/gin-gonic/gin"
8 | )
9 |
10 | // @Tags system
11 | // @Summary 获取配置文件内容
12 | // @Security ApiKeyAuth
13 | // @Produce application/json
14 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
15 | // @Router /system/getSystemConfig [post]
16 | func GetSystemConfig(c *gin.Context) {
17 | err, config := new(sysModel.System).GetSystemConfig()
18 | if err != nil {
19 | servers.ReportFormat(c, false, fmt.Sprintf("获取失败:%v", err), gin.H{})
20 | } else {
21 | servers.ReportFormat(c, true, "获取成功", gin.H{"config": config})
22 | }
23 | }
24 |
25 | // @Tags system
26 | // @Summary 设置配置文件内容
27 | // @Security ApiKeyAuth
28 | // @Produce application/json
29 | // @Param data body sysModel.System true
30 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
31 | // @Router /system/setSystemConfig [post]
32 | func SetSystemConfig(c *gin.Context) {
33 | var sys sysModel.System
34 | _ = c.ShouldBind(&sys)
35 | err := sys.SetSystemConfig()
36 | if err != nil {
37 | servers.ReportFormat(c, false, fmt.Sprintf("设置失败:%v", err), gin.H{})
38 | } else {
39 | servers.ReportFormat(c, true, "设置成功", gin.H{})
40 | }
41 | }
42 |
43 | // @Tags system
44 | // @Summary 设置配置文件内容
45 | // @Security ApiKeyAuth
46 | // @Produce application/json
47 | // @Param data body sysModel.System true
48 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
49 | // @Router /system/ReloadSystem [post]
50 | func ReloadSystem(c *gin.Context) {
51 | var sys sysModel.System
52 | _ = c.ShouldBind(&sys)
53 | err := sys.SetSystemConfig()
54 | if err != nil {
55 | servers.ReportFormat(c, false, fmt.Sprintf("设置失败:%v", err), gin.H{})
56 | } else {
57 | servers.ReportFormat(c, true, "设置成功", gin.H{})
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/api/authority.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | // @Summary 用户登录
4 | // @Produce application/json
5 | // @Param {
6 | // page int
7 | // pageSize int
8 | // }
9 | // @Router /authority/getAuthorityList [post]
10 | export const getAuthorityList = (data) => {
11 | return service({
12 | url: "/authority/getAuthorityList",
13 | method: 'post',
14 | data
15 | })
16 | }
17 |
18 |
19 | // @Summary 删除角色
20 | // @Security ApiKeyAuth
21 | // @accept application/json
22 | // @Produce application/json
23 | // @Param data body {authorityId uint} true "删除角色"
24 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
25 | // @Router /authority/deleteAuthority [post]
26 | export const deleteAuthority = (data) => {
27 | return service({
28 | url: "/authority/deleteAuthority",
29 | method: 'post',
30 | data
31 | })
32 | }
33 |
34 | // @Summary 创建角色
35 | // @Security ApiKeyAuth
36 | // @accept application/json
37 | // @Produce application/json
38 | // @Param data body api.CreateAuthorityPatams true "创建角色"
39 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
40 | // @Router /authority/createAuthority [post]
41 | export const createAuthority = (data) => {
42 | return service({
43 | url: "/authority/createAuthority",
44 | method: 'post',
45 | data
46 | })
47 | }
48 |
49 | // @Summary 设置角色资源权限
50 | // @Security ApiKeyAuth
51 | // @accept application/json
52 | // @Produce application/json
53 | // @Param data body sysModel.SysAuthority true "设置角色资源权限"
54 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
55 | // @Router /authority/setDataAuthority [post]
56 | export const setDataAuthority = (data) => {
57 | return service({
58 | url: "/authority/setDataAuthority",
59 | method: 'post',
60 | data
61 | })
62 | }
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/person/person.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
用户ID:{{userInfo.uuid}}
21 |
用户昵称:{{userInfo.nickName}}
22 |
用户组:{{userInfo.authority&&userInfo.authority.authorityName}}
23 |
24 |
25 |
26 |
47 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/superAdmin/authority/components/menus.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
75 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/example/excel/excel.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 | 点击上传
16 | 未对文件格式及大小做校验
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/model/sysModel/sys_api.go:
--------------------------------------------------------------------------------
1 | package sysModel
2 |
3 | import (
4 | "nideshop-admin/controller/servers"
5 | "nideshop-admin/init/qmsql"
6 | "nideshop-admin/model/modelInterface"
7 | "github.com/jinzhu/gorm"
8 | "github.com/pkg/errors"
9 | )
10 |
11 | type SysApi struct {
12 | gorm.Model
13 | Path string `json:"path"`
14 | Description string `json:"description"`
15 | Group string `json:"group"`
16 | Method string `json:"method" gorm:"default:'POST'"`
17 | }
18 |
19 | func (a *SysApi) CreateApi() (err error) {
20 | findOne := qmsql.DEFAULTDB.Where("path = ?", a.Path).Find(&SysMenu{}).Error
21 | if findOne == nil {
22 | return errors.New("存在相同api")
23 | } else {
24 | err = qmsql.DEFAULTDB.Create(a).Error
25 | }
26 | return err
27 | }
28 |
29 | func (a *SysApi) DeleteApi() (err error) {
30 | err = qmsql.DEFAULTDB.Delete(a).Error
31 | new(CasbinModel).clearCasbin(1, a.Path)
32 | return err
33 | }
34 |
35 | func (a *SysApi) UpdataApi() (err error) {
36 | var oldA SysApi
37 | err = qmsql.DEFAULTDB.Where("id = ?", a.ID).First(&oldA).Error
38 | if err != nil {
39 | return err
40 | } else {
41 | err = new(CasbinModel).CasbinApiUpdata(oldA.Path, a.Path)
42 | if err != nil {
43 | return err
44 | } else {
45 | err = qmsql.DEFAULTDB.Save(a).Error
46 | }
47 | }
48 | return err
49 | }
50 |
51 | func (a *SysApi) GetApiById(id float64) (err error, api SysApi) {
52 | err = qmsql.DEFAULTDB.Where("id = ?", id).First(&api).Error
53 | return
54 | }
55 |
56 | // 获取所有api信息
57 | func (a *SysApi) GetAllApis() (err error, apis []SysApi) {
58 | err = qmsql.DEFAULTDB.Find(&apis).Error
59 | return
60 | }
61 |
62 | // 分页获取数据 需要分页实现这个接口即可
63 | func (a *SysApi) GetInfoList(info modelInterface.PageInfo) (err error, list interface{}, total int) {
64 | // 封装分页方法 调用即可 传入 当前的结构体和分页信息
65 | err, db, total := servers.PagingServer(a, info)
66 | if err != nil {
67 | return
68 | } else {
69 | var apiList []SysApi
70 | err = db.Order("group", true).Where("path LIKE ?", "%"+a.Path+"%").Find(&apiList).Count(&total).Error
71 | return err, apiList, total
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/fsnotify/fsnotify"
7 | "github.com/spf13/viper"
8 | )
9 |
10 | type Config struct {
11 | MysqlAdmin MysqlAdmin `json:"mysqlAdmin"`
12 | UpLoad UpLoad `json:"upload"`
13 | CasbinConfig CasbinConfig `json:"casbinConfig"`
14 | RedisAdmin RedisAdmin `json:"redisAdmin"`
15 | System System `json:"system"`
16 | JWT JWT `json:"jwt"`
17 | }
18 |
19 | type System struct { // 系统配置
20 | UseMultipoint bool `json:"useMultipoint"`
21 | Env string `json:"env"`
22 | Addr int `json:"addr"`
23 | }
24 |
25 | type JWT struct { // jwt签名
26 | SigningKey string `json:"signingKey"`
27 | }
28 |
29 | type CasbinConfig struct { //casbin配置
30 | ModelPath string `json:"modelPath"` // casbin model地址配置
31 | }
32 |
33 | type MysqlAdmin struct { // mysql admin 数据库配置
34 | Username string `json:"username"`
35 | Password string `json:"password"`
36 | Path string `json:"path"`
37 | Dbname string `json:"dbname"`
38 | Config string `json:"config"`
39 | }
40 |
41 | type RedisAdmin struct { // Redis admin 数据库配置
42 | Addr string `json:"addr"`
43 | Password string `json:"password"`
44 | DB int `json:"db"`
45 | }
46 | type UpLoad struct { // 文件上传配置
47 | Domain string `json:"domain"`
48 | Path string `json:"path"`
49 | }
50 |
51 | var GinVueAdminconfig Config
52 | var VTool *viper.Viper
53 |
54 | func init() {
55 | v := viper.New()
56 | v.SetConfigName("config") // 设置配置文件名 (不带后缀)
57 | v.AddConfigPath("./static/config/") // 第一个搜索路径
58 | v.SetConfigType("json")
59 | err := v.ReadInConfig() // 搜索路径,并读取配置数据
60 | if err != nil {
61 | panic(fmt.Errorf("Fatal error config file: %s \n", err))
62 | }
63 | v.WatchConfig()
64 | v.OnConfigChange(func(e fsnotify.Event) {
65 | fmt.Println("Config file changed:", e.Name)
66 | if err := v.Unmarshal(&GinVueAdminconfig); err != nil {
67 | fmt.Println(err)
68 | }
69 | })
70 | if err := v.Unmarshal(&GinVueAdminconfig); err != nil {
71 | fmt.Println(err)
72 | }
73 | VTool = v
74 | }
75 |
--------------------------------------------------------------------------------
/tools/str.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "strings"
5 | )
6 |
7 | func GetSuffix(s string) string {
8 | start := strings.LastIndex(s, ".")
9 | end := len(s)
10 | return SubStr(s, start, end)
11 | }
12 |
13 | func GetFileName(s string) string {
14 | start := strings.LastIndex(s, "/") + 1
15 | end := len(s)
16 | return SubStr(s, start, end)
17 | }
18 |
19 | func SubStr(s string, start, end int) string {
20 | rs := []byte(s)
21 | rl := len(rs)
22 |
23 | if start < 0 {
24 | start = 0
25 | }
26 |
27 | if start > end {
28 | start, end = end, start
29 | }
30 |
31 | if end > rl {
32 | end = rl
33 | }
34 |
35 | if start > rl {
36 | start = rl
37 | }
38 |
39 | if end < 0 {
40 | end = 0
41 | }
42 |
43 | if end > rl {
44 | end = rl
45 | }
46 |
47 | return string(rs[start:end])
48 | }
49 |
50 | func NTos(n string) string {
51 | result := ""
52 | for i := 0; i < len(n); i++ {
53 | result += nTs(string(n[i]))
54 | }
55 | return result
56 | }
57 |
58 | func STon(n string) string {
59 | result := ""
60 | for i := 0; i < len(n); i++ {
61 | result += sTn(string(n[i]))
62 | }
63 | return result
64 | }
65 |
66 | func nTs(n string) string {
67 | switch n {
68 | case "0":
69 | return "f"
70 | case "1":
71 | return "b"
72 | case "2":
73 | return "h"
74 | case "3":
75 | return "w"
76 | case "4":
77 | return "k"
78 | case "5":
79 | return "n"
80 | case "6":
81 | return "a"
82 | case "7":
83 | return "p"
84 | case "8":
85 | return "u"
86 | case "9":
87 | return "s"
88 | default:
89 | return ""
90 | }
91 | }
92 |
93 | func sTn(n string) string {
94 | switch n {
95 | case "f":
96 | return "0"
97 | case "b":
98 | return "1"
99 | case "h":
100 | return "2"
101 | case "w":
102 | return "3"
103 | case "k":
104 | return "4"
105 | case "n":
106 | return "5"
107 | case "a":
108 | return "6"
109 | case "p":
110 | return "7"
111 | case "u":
112 | return "8"
113 | case "s":
114 | return "9"
115 | default:
116 | return ""
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/controller/servers/breakpoint_continue.go:
--------------------------------------------------------------------------------
1 | package servers
2 |
3 | import (
4 | "nideshop-admin/tools"
5 | "io/ioutil"
6 | "os"
7 | "strconv"
8 | )
9 |
10 | // 前端传来文件片与当前片为什么文件的第几片
11 | // 后端拿到以后比较次分片是否上传 或者是否为不完全片
12 | // 前端发送每片多大
13 | // 前端告知是否为最后一片且是否完成
14 |
15 | const breakpointDir = "./breakpointDir/"
16 | const finishDir = "./fileDir/"
17 |
18 | func BreakPointContinue(content []byte, fileName string, contentNumber int, contentTotal int, fileMd5 string) (error, string) {
19 | path := breakpointDir + fileMd5 + "/"
20 | err := os.MkdirAll(path, os.ModePerm)
21 | if err != nil {
22 | return err, path
23 | }
24 | err, pathc := makeFileContent(content, fileName, path, contentNumber)
25 | return err, pathc
26 |
27 | }
28 |
29 | func CheckMd5(content []byte, chunkMd5 string) (CanUpload bool) {
30 | fileMd5 := tools.MD5V(content)
31 | if fileMd5 == chunkMd5 {
32 | return true // "可以继续上传"
33 | } else {
34 | return false // "切片不完整,废弃"
35 | }
36 | }
37 |
38 | func makeFileContent(content []byte, fileName string, FileDir string, contentNumber int) (error, string) {
39 | path := FileDir + fileName + "_" + strconv.Itoa(contentNumber)
40 | f, err := os.Create(path)
41 | defer f.Close()
42 | if err != nil {
43 | return err, path
44 | } else {
45 | _, err = f.Write(content)
46 | if err != nil {
47 | return err, path
48 | }
49 | }
50 | return nil, path
51 | }
52 |
53 | func MakeFile(fileName string, FileMd5 string) (error, string) {
54 | rd, err := ioutil.ReadDir(breakpointDir + FileMd5)
55 | if err != nil {
56 | return err, finishDir + fileName
57 | }
58 | _ = os.MkdirAll(finishDir, os.ModePerm)
59 | fd, _ := os.OpenFile(finishDir+fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
60 | for k, _ := range rd {
61 | content, _ := ioutil.ReadFile(breakpointDir + FileMd5 + "/" + fileName + "_" + strconv.Itoa(k))
62 | _, err = fd.Write(content)
63 | if err != nil {
64 | _ = os.Remove(finishDir + fileName)
65 | return err, finishDir + fileName
66 | }
67 | }
68 | defer fd.Close()
69 | return nil, finishDir + fileName
70 | }
71 |
72 | func RemoveChunk(FileMd5 string) error {
73 | err := os.RemoveAll(breakpointDir + FileMd5)
74 | return err
75 | }
76 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/store/module/user.js:
--------------------------------------------------------------------------------
1 | import { login } from '@/api/user'
2 | import { jsonInBlacklist } from '@/api/jwt'
3 | import router from '@/router/index'
4 | export const user = {
5 | namespaced: true,
6 | state: {
7 | userInfo: {
8 | uuid: "",
9 | nickName: "",
10 | headerImg: "",
11 | authority: "",
12 | },
13 | token: "",
14 | expiresAt: ""
15 | },
16 | mutations: {
17 | setUserInfo(state, userInfo) {
18 | // 这里的 `state` 对象是模块的局部状态
19 | state.userInfo = userInfo
20 | },
21 | setToken(state, token) {
22 | // 这里的 `state` 对象是模块的局部状态
23 | state.token = token
24 | },
25 | setExpiresAt(state, expiresAt) {
26 | // 这里的 `state` 对象是模块的局部状态
27 | state.expiresAt = expiresAt
28 | },
29 | LoginOut(state) {
30 | state.userInfo = {}
31 | state.token = ""
32 | state.expiresAt = ""
33 | router.push({ name: 'login', replace: true })
34 | window.location.reload()
35 | },
36 | ResetUserInfo(state, userInfo = {}) {
37 | state.userInfo = {...state.userInfo,
38 | ...userInfo
39 | }
40 | }
41 | },
42 | actions: {
43 | async LoginIn({ commit }, loginInfo) {
44 | const res = await login(loginInfo)
45 | commit('setUserInfo', res.data.user)
46 | commit('setToken', res.data.token)
47 | commit('setExpiresAt', res.data.expiresAt)
48 | if (res.success) {
49 | const redirect = router.history.current.query.redirect
50 | if (redirect) {
51 | router.push({ path: redirect })
52 | } else {
53 | router.push({ path: '/layout/dashbord' })
54 | }
55 | }
56 | },
57 | async LoginOut({ commit }) {
58 | const res = await jsonInBlacklist()
59 | if (res.success) {
60 | commit("LoginOut")
61 | }
62 | }
63 | },
64 | getters: {
65 | userInfo(state) {
66 | return state.userInfo
67 | },
68 | token(state) {
69 | return state.token
70 | },
71 | expiresAt(state) {
72 | return state.expiresAt
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/QMPlusVuePage/src/utils/request.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'; // 引入axios
2 | import { Message, Loading } from 'element-ui';
3 | import { store } from '@/store/index'
4 | const service = axios.create({
5 | baseURL: process.env.VUE_APP_BASE_API,
6 | timeout: 99999
7 | })
8 | let acitveAxios = 0
9 | let loadingInstance
10 | let timer
11 | const showLoading = () => {
12 | acitveAxios++
13 | if (timer) {
14 | clearTimeout(timer)
15 | }
16 | timer = setTimeout(() => {
17 | if (acitveAxios > 0) {
18 | loadingInstance = Loading.service({ fullscreen: true })
19 | }
20 | }, 400);
21 | }
22 |
23 | const closeLoading = () => {
24 | acitveAxios--
25 | if (acitveAxios <= 0) {
26 | clearTimeout(timer)
27 | loadingInstance && loadingInstance.close()
28 | }
29 | }
30 | //http request 拦截器
31 | service.interceptors.request.use(
32 | config => {
33 | showLoading()
34 | const token = store.getters['user/token']
35 | config.data = JSON.stringify(config.data);
36 | config.headers = {
37 | 'Content-Type': 'application/json',
38 | 'x-token': token
39 | }
40 | return config;
41 | },
42 | error => {
43 | closeLoading()
44 | Message({
45 | showClose: true,
46 | message: error,
47 | type: 'error'
48 | })
49 | return Promise.reject(error);
50 | }
51 | );
52 |
53 |
54 | //http response 拦截器
55 | service.interceptors.response.use(
56 | response => {
57 | closeLoading()
58 | if (response.data.success) {
59 | return response.data
60 | } else {
61 | Message({
62 | showClose: true,
63 | message: response.data.msg,
64 | type: 'error',
65 | onClose: () => {
66 | if (response.data.data && response.data.data.reload) {
67 | store.commit('user/LoginOut')
68 | }
69 | }
70 | })
71 | return Promise.reject(response.data.msg)
72 | }
73 | },
74 | error => {
75 | closeLoading()
76 | Message({
77 | showClose: true,
78 | message: error,
79 | type: 'error'
80 | })
81 | return Promise.reject(error)
82 | }
83 | )
84 |
85 | export default service
--------------------------------------------------------------------------------
/model/dbModel/exa_breakpoint_continue.go:
--------------------------------------------------------------------------------
1 | package dbModel
2 |
3 | import (
4 | "nideshop-admin/init/qmsql"
5 | "github.com/jinzhu/gorm"
6 | )
7 |
8 | //文件结构体
9 | type ExaFile struct {
10 | gorm.Model
11 | FileName string
12 | FileMd5 string
13 | FilePath string
14 | ExaFileChunk []ExaFileChunk
15 | ChunkTotal int
16 | IsFinish bool
17 | }
18 |
19 | //切片结构体
20 | type ExaFileChunk struct {
21 | gorm.Model
22 | ExaFileId uint
23 | FileChunkNumber int
24 | FileChunkPath string
25 | }
26 |
27 | //文件合成完成
28 | func (f *ExaFile) FileCreateComplete(FileMd5 string, FileName string, FilePath string) error {
29 | var file ExaFile
30 | upDateFile := make(map[string]interface{})
31 | upDateFile["FilePath"] = FilePath
32 | upDateFile["IsFinish"] = true
33 | err := qmsql.DEFAULTDB.Where("file_md5 = ? AND file_name = ?", FileMd5, FileName).First(&file).Updates(upDateFile).Error
34 | return err
35 | }
36 |
37 | //第一次上传或者断点续传时候检测当前文件属性,没有则创建,有则返回文件的当前切片
38 | func (f *ExaFile) FindOrCreateFile(FileMd5 string, FileName string, ChunkTotal int) (err error, file ExaFile) {
39 | var cfile ExaFile
40 | cfile.FileMd5 = FileMd5
41 | cfile.FileName = FileName
42 | cfile.ChunkTotal = ChunkTotal
43 | notHaveSameMd5Finish := qmsql.DEFAULTDB.Where("file_md5 = ? AND is_finish = ?", FileMd5, true).First(&file).RecordNotFound()
44 | if notHaveSameMd5Finish {
45 | err = qmsql.DEFAULTDB.Where("file_md5 = ? AND file_name = ?", FileMd5, FileName).Preload("ExaFileChunk").FirstOrCreate(&file, cfile).Error
46 | return err, file
47 | } else {
48 | cfile.IsFinish = true
49 | cfile.FilePath = file.FilePath
50 | err = qmsql.DEFAULTDB.Create(&cfile).Error
51 | return err, cfile
52 | }
53 | }
54 |
55 | // 创建文件切片记录
56 | func (f *ExaFile) CreateFileChunk(FileChunkPath string, FileChunkNumber int) error {
57 | var chunk ExaFileChunk
58 | chunk.FileChunkPath = FileChunkPath
59 | chunk.ExaFileId = f.ID
60 | chunk.FileChunkNumber = FileChunkNumber
61 | err := qmsql.DEFAULTDB.Create(&chunk).Error
62 | return err
63 | }
64 |
65 | // 删除文件切片记录
66 | func (f *ExaFile) DeleteFileChunk(fileMd5 string, fileName string, filePath string) error {
67 | var chunks []ExaFileChunk
68 | var file ExaFile
69 | err := qmsql.DEFAULTDB.Where("file_md5 = ? AND file_name = ?", fileMd5, fileName).First(&file).Update("IsFinish", true).Update("file_path", filePath).Error
70 | err = qmsql.DEFAULTDB.Where("exa_file_id = ?", file.ID).Delete(&chunks).Unscoped().Error
71 | return err
72 | }
73 |
--------------------------------------------------------------------------------
/model/sysModel/sys_authority.go:
--------------------------------------------------------------------------------
1 | package sysModel
2 |
3 | import (
4 | "nideshop-admin/controller/servers"
5 | "nideshop-admin/init/qmsql"
6 | "nideshop-admin/model/modelInterface"
7 | "github.com/jinzhu/gorm"
8 | "github.com/pkg/errors"
9 | )
10 |
11 | type SysAuthority struct {
12 | gorm.Model
13 | AuthorityId string `json:"authorityId" gorm:"not null;unique"`
14 | AuthorityName string `json:"authorityName"`
15 | ParentId string `json:"parentId"`
16 | DataAuthorityId []SysAuthority `json:"dataAuthorityId" gorm:"many2many:sys_data_authority_id;association_jointable_foreignkey:data_id"`
17 | Children []SysAuthority `json:"children"`
18 | }
19 |
20 | // 创建角色
21 | func (a *SysAuthority) CreateAuthority() (err error, authority *SysAuthority) {
22 | err = qmsql.DEFAULTDB.Create(a).Error
23 | return err, a
24 | }
25 |
26 | // 删除角色
27 | func (a *SysAuthority) DeleteAuthority() (err error) {
28 | err = qmsql.DEFAULTDB.Where("authority_id = ?", a.AuthorityId).Find(&SysUser{}).Error
29 | if err != nil {
30 | err = qmsql.DEFAULTDB.Where("parentId = ?", a.AuthorityId).Find(&SysAuthority{}).Error
31 | if err != nil {
32 | err = qmsql.DEFAULTDB.Where("authority_id = ?", a.AuthorityId).First(a).Unscoped().Delete(a).Error
33 | new(CasbinModel).clearCasbin(0, a.AuthorityId)
34 | } else {
35 | err = errors.New("此角色存在子角色不允许删除")
36 | }
37 | } else {
38 | err = errors.New("此角色有用户正在使用禁止删除")
39 | }
40 | return err
41 | }
42 |
43 | // 分页获取数据 需要分页实现这个接口即可
44 | func (a *SysAuthority) GetInfoList(info modelInterface.PageInfo) (err error, list interface{}, total int) {
45 | // 封装分页方法 调用即可 传入 当前的结构体和分页信息
46 | err, db, total := servers.PagingServer(a, info)
47 | if err != nil {
48 | return
49 | } else {
50 | var authority []SysAuthority
51 | err = db.Preload("DataAuthorityId").Where("parent_id = 0").Find(&authority).Error
52 | if len(authority) > 0 {
53 | for k, _ := range authority {
54 | err = findChildrenAuthority(&authority[k])
55 | }
56 | }
57 | return err, authority, total
58 | }
59 | }
60 |
61 | func findChildrenAuthority(authority *SysAuthority) (err error) {
62 | err = qmsql.DEFAULTDB.Preload("DataAuthorityId").Where("parent_id = ?", authority.AuthorityId).Find(&authority.Children).Error
63 | if len(authority.Children) > 0 {
64 | for k, _ := range authority.Children {
65 | err = findChildrenAuthority(&authority.Children[k])
66 | }
67 | }
68 | return err
69 | }
70 |
71 | func (a *SysAuthority) SetDataAuthority() error {
72 | var s SysAuthority
73 | qmsql.DEFAULTDB.Preload("DataAuthorityId").First(&s, "id = ?", a.ID)
74 | err := qmsql.DEFAULTDB.Model(&s).Association("DataAuthorityId").Replace(&a.DataAuthorityId).Error
75 | return err
76 | }
77 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/superAdmin/authority/components/apis.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
98 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/login/login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GIN-VUE-ADMIN
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 | 登 录
21 |
22 |
23 | 测试用户:admin 密码:123456
24 |
25 |
26 |
27 |
28 |
85 |
86 |
--------------------------------------------------------------------------------
/model/sysModel/sys_casbin.go:
--------------------------------------------------------------------------------
1 | package sysModel
2 |
3 | import (
4 | "errors"
5 | "nideshop-admin/config"
6 | "nideshop-admin/init/qmsql"
7 | "github.com/casbin/casbin"
8 | gormadapter "github.com/casbin/gorm-adapter"
9 | "strings"
10 | )
11 |
12 | type CasbinModel struct {
13 | ID uint `json:"id" gorm:"column:_id"`
14 | Ptype string `json:"ptype" gorm:"column:ptype"`
15 | AuthorityId string `json:"rolename" gorm:"column:v0"`
16 | Path string `json:"path" gorm:"column:v1"`
17 | Method string `json:"method" gorm:"column:v2"`
18 | }
19 |
20 | // 供入参使用
21 | type CasbinInfo struct {
22 | Path string `json:"path"`
23 | Method string `json:"method"`
24 | }
25 |
26 | // 供入参使用
27 | type CasbinInReceive struct {
28 | AuthorityId string `json:"authorityId"`
29 | CasbinInfos []CasbinInfo `json:"casbinInfos"`
30 | }
31 |
32 | // 更新权限
33 | func (c *CasbinModel) CasbinPUpdata(AuthorityId string, casbinInfos []CasbinInfo) error {
34 | c.clearCasbin(0, AuthorityId)
35 | for _, v := range casbinInfos {
36 | cm := CasbinModel{
37 | ID: 0,
38 | Ptype: "p",
39 | AuthorityId: AuthorityId,
40 | Path: v.Path,
41 | Method: v.Method,
42 | }
43 | addflag := c.AddCasbin(cm)
44 | if addflag == false {
45 | return errors.New("存在相同api,添加失败,请联系管理员")
46 | }
47 | }
48 | return nil
49 | }
50 |
51 | // API更新随动
52 | func (c *CasbinModel) CasbinApiUpdata(oldPath string, newPath string) error {
53 | var cs []CasbinModel
54 | err := qmsql.DEFAULTDB.Table("casbin_rule").Where("v1 = ?", oldPath).Find(&cs).Update("v1", newPath).Error
55 | return err
56 | }
57 |
58 | //添加权限
59 | func (c *CasbinModel) AddCasbin(cm CasbinModel) bool {
60 | e := Casbin()
61 | return e.AddPolicy(cm.AuthorityId, cm.Path, cm.Method)
62 | }
63 |
64 | //获取权限列表
65 | func (c *CasbinModel) GetPolicyPathByAuthorityId(AuthorityId string) []string {
66 | e := Casbin()
67 | var pathList []string
68 | list := e.GetFilteredPolicy(0, AuthorityId)
69 | for _, v := range list {
70 | pathList = append(pathList, v[1])
71 | }
72 | return pathList
73 | }
74 |
75 | //清除匹配的权限
76 | func (c *CasbinModel) clearCasbin(v int, p string) bool {
77 | e := Casbin()
78 | return e.RemoveFilteredPolicy(v, p)
79 |
80 | }
81 |
82 | // 自定义规则函数
83 | func ParamsMatch(key1 string, key2 string) bool {
84 | k1arr := strings.Split(key1, "?")
85 | return k1arr[0] == key2
86 | }
87 |
88 | // 自定义规则函数
89 | func ParamsMatchFunc(args ...interface{}) (interface{}, error) {
90 | name1 := args[0].(string)
91 | name2 := args[1].(string)
92 |
93 | return (bool)(ParamsMatch(name1, name2)), nil
94 | }
95 |
96 | //持久化到数据库 引入自定义规则
97 | func Casbin() *casbin.Enforcer {
98 | a := gormadapter.NewAdapterByDB(qmsql.DEFAULTDB)
99 | e := casbin.NewEnforcer(config.GinVueAdminconfig.CasbinConfig.ModelPath, a)
100 | e.AddFunction("ParamsMatch", ParamsMatchFunc)
101 | e.LoadPolicy()
102 | return e
103 | }
104 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/api/menu.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | // @Summary 用户登录 获取动态路由
4 | // @Produce application/json
5 | // @Param 可以什么都不填 调一下即可
6 | // @Router /menu/getMenu [post]
7 | export const asyncMenu = () => {
8 | return service({
9 | url: "/menu/getMenu",
10 | method: 'post',
11 | })
12 | }
13 |
14 | // @Summary 获取menu列表
15 | // @Produce application/json
16 | // @Param {
17 | // page int
18 | // pageSize int
19 | // }
20 | // @Router /menu/getMenuList [post]
21 | export const getMenuList = (data) => {
22 | return service({
23 | url: "/menu/getMenuList",
24 | method: 'post',
25 | data
26 | })
27 | }
28 |
29 |
30 | // @Summary 新增基础menu
31 | // @Produce application/json
32 | // @Param menu Object
33 | // @Router /menu/getMenuList [post]
34 | export const addBaseMenu = (data) => {
35 | return service({
36 | url: "/menu/addBaseMenu",
37 | method: 'post',
38 | data
39 | })
40 | }
41 |
42 | // @Summary 获取基础路由列表
43 | // @Produce application/json
44 | // @Param 可以什么都不填 调一下即可
45 | // @Router /menu/getBaseMenuTree [post]
46 | export const getBaseMenuTree = () => {
47 | return service({
48 | url: "/menu/getBaseMenuTree",
49 | method: 'post',
50 | })
51 | }
52 |
53 | // @Summary 添加用户menu关联关系
54 | // @Produce application/json
55 | // @Param menus Object authorityId string
56 | // @Router /menu/getMenuList [post]
57 | export const addMenuAuthority = (data) => {
58 | return service({
59 | url: "/menu/addMenuAuthority",
60 | method: 'post',
61 | data
62 | })
63 | }
64 |
65 | // @Summary 获取用户menu关联关系
66 | // @Produce application/json
67 | // @Param authorityId string
68 | // @Router /menu/getMenuAuthority [post]
69 | export const getMenuAuthority = (data) => {
70 | return service({
71 | url: "/menu/getMenuAuthority",
72 | method: 'post',
73 | data
74 | })
75 | }
76 |
77 | // @Summary 获取用户menu关联关系
78 | // @Produce application/json
79 | // @Param ID float64
80 | // @Router /menu/deleteBaseMenu [post]
81 | export const deleteBaseMenu = (data) => {
82 | return service({
83 | url: "/menu/deleteBaseMenu",
84 | method: 'post',
85 | data
86 | })
87 | }
88 |
89 |
90 | // @Summary 修改menu列表
91 | // @Produce application/json
92 | // @Param menu Object
93 | // @Router /menu/updataBaseMenu [post]
94 | export const updataBaseMenu = (data) => {
95 | return service({
96 | url: "/menu/updataBaseMenu",
97 | method: 'post',
98 | data
99 | })
100 | }
101 |
102 |
103 | // @Tags menu
104 | // @Summary 根据id获取菜单
105 | // @Security ApiKeyAuth
106 | // @accept application/json
107 | // @Produce application/json
108 | // @Param data body api.GetById true "根据id获取菜单"
109 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
110 | // @Router /menu/getBaseMenuById [post]
111 | export const getBaseMenuById = (data) => {
112 | return service({
113 | url: "/menu/getBaseMenuById",
114 | method: 'post',
115 | data
116 | })
117 | }
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/dashbord/component/animition.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
90 |
--------------------------------------------------------------------------------
/model/sysModel/sys_user.go:
--------------------------------------------------------------------------------
1 | package sysModel
2 |
3 | import (
4 | "nideshop-admin/controller/servers"
5 | "nideshop-admin/init/qmsql"
6 | "nideshop-admin/model/modelInterface"
7 | "nideshop-admin/tools"
8 | "github.com/jinzhu/gorm"
9 | "github.com/pkg/errors"
10 | uuid "github.com/satori/go.uuid"
11 | )
12 |
13 | type SysUser struct {
14 | gorm.Model
15 | UUID uuid.UUID `json:"uuid"`
16 | Username string `json:"userName"`
17 | Password string `json:"-"`
18 | NickName string `json:"nickName" gorm:"default:'QMPlusUser'"`
19 | HeaderImg string `json:"headerImg" gorm:"default:'http://www.henrongyi.top/avatar/lufu.jpg'"`
20 | Authority SysAuthority `json:"authority" gorm:"ForeignKey:AuthorityId;AssociationForeignKey:AuthorityId"`
21 | AuthorityId string `json:"authorityId" gorm:"default:888"`
22 | }
23 |
24 | //type Propertie struct {
25 | // gorm.Model
26 | //}
27 |
28 | //注册接口model方法
29 | func (u *SysUser) Regist() (err error, userInter *SysUser) {
30 | var user SysUser
31 | //判断用户名是否注册
32 | notResigt := qmsql.DEFAULTDB.Where("username = ?", u.Username).First(&user).RecordNotFound()
33 | //notResigt为false表明读取到了 不能注册
34 | if !notResigt {
35 | return errors.New("用户名已注册"), nil
36 | } else {
37 | // 否则 附加uuid 密码md5简单加密 注册
38 | u.Password = tools.MD5V([]byte(u.Password))
39 | u.UUID = uuid.NewV4()
40 | err = qmsql.DEFAULTDB.Create(u).Error
41 | }
42 | return err, u
43 | }
44 |
45 | //修改用户密码
46 | func (u *SysUser) ChangePassword(newPassword string) (err error, userInter *SysUser) {
47 | var user SysUser
48 | //后期修改jwt+password模式
49 | u.Password = tools.MD5V([]byte(u.Password))
50 | err = qmsql.DEFAULTDB.Where("username = ? AND password = ?", u.Username, u.Password).First(&user).Update("password", tools.MD5V([]byte(newPassword))).Error
51 | return err, u
52 | }
53 |
54 | //用户更新接口
55 | func (u *SysUser) SetUserAuthority(uuid uuid.UUID, AuthorityId string) (err error) {
56 | err = qmsql.DEFAULTDB.Where("uuid = ?", uuid).First(&SysUser{}).Update("authority_id", AuthorityId).Error
57 | return err
58 | }
59 |
60 | //用户登录
61 | func (u *SysUser) Login() (err error, userInter *SysUser) {
62 | var user SysUser
63 | u.Password = tools.MD5V([]byte(u.Password))
64 | err = qmsql.DEFAULTDB.Where("username = ? AND password = ?", u.Username, u.Password).First(&user).Error
65 | if err != nil {
66 | return err, &user
67 | }
68 | err = qmsql.DEFAULTDB.Where("authority_id = ?", user.AuthorityId).First(&user.Authority).Error
69 | return err, &user
70 | }
71 |
72 | // 用户头像上传更新地址
73 | func (u *SysUser) UploadHeaderImg(uuid uuid.UUID, filePath string) (err error, userInter *SysUser) {
74 | var user SysUser
75 | err = qmsql.DEFAULTDB.Where("uuid = ?", uuid).First(&user).Update("header_img", filePath).First(&user).Error
76 | return err, &user
77 | }
78 |
79 | // 分页获取数据 需要分页实现这个接口即可
80 | func (u *SysUser) GetInfoList(info modelInterface.PageInfo) (err error, list interface{}, total int) {
81 | // 封装分页方法 调用即可 传入 当前的结构体和分页信息
82 | err, db, total := servers.PagingServer(u, info)
83 | if err != nil {
84 | return
85 | } else {
86 | var userList []SysUser
87 | err = db.Preload("Authority").Find(&userList).Error
88 | return err, userList, total
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/superAdmin/authority/components/datas.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 确 定
5 | 全选
6 | 本部门
7 | 部门及以下
8 |
9 |
10 | {{item.authorityName}}
11 |
12 |
13 |
14 |
95 |
--------------------------------------------------------------------------------
/controller/api/sys_authority.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/controller/servers"
6 | "nideshop-admin/model/modelInterface"
7 | "nideshop-admin/model/sysModel"
8 | "github.com/gin-gonic/gin"
9 | )
10 |
11 | type CreateAuthorityParams struct {
12 | AuthorityId string `json:"authorityId"`
13 | AuthorityName string `json:"authorityName"`
14 | }
15 |
16 | // @Tags authority
17 | // @Summary 创建角色
18 | // @Security ApiKeyAuth
19 | // @accept application/json
20 | // @Produce application/json
21 | // @Param data body api.CreateAuthorityParams true "创建角色"
22 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
23 | // @Router /authority/createAuthority [post]
24 | func CreateAuthority(c *gin.Context) {
25 | var auth sysModel.SysAuthority
26 | _ = c.ShouldBind(&auth)
27 | err, authBack := auth.CreateAuthority()
28 | if err != nil {
29 | servers.ReportFormat(c, false, fmt.Sprintf("创建失败:%v", err), gin.H{
30 | "authority": authBack,
31 | })
32 | } else {
33 | servers.ReportFormat(c, true, "创建成功", gin.H{
34 | "authority": authBack,
35 | })
36 | }
37 | }
38 |
39 | type DeleteAuthorityPatams struct {
40 | AuthorityId uint `json:"authorityId"`
41 | }
42 |
43 | // @Tags authority
44 | // @Summary 删除角色
45 | // @Security ApiKeyAuth
46 | // @accept application/json
47 | // @Produce application/json
48 | // @Param data body api.DeleteAuthorityPatams true "删除角色"
49 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
50 | // @Router /authority/deleteAuthority [post]
51 | func DeleteAuthority(c *gin.Context) {
52 | var a sysModel.SysAuthority
53 | _ = c.BindJSON(&a)
54 | //删除角色之前需要判断是否有用户正在使用此角色
55 | err := a.DeleteAuthority()
56 | if err != nil {
57 | servers.ReportFormat(c, false, fmt.Sprintf("删除失败:%v", err), gin.H{})
58 | } else {
59 | servers.ReportFormat(c, true, "删除成功", gin.H{})
60 | }
61 | }
62 |
63 | // @Tags authority
64 | // @Summary 分页获取角色列表
65 | // @Security ApiKeyAuth
66 | // @accept application/json
67 | // @Produce application/json
68 | // @Param data body modelInterface.PageInfo true "分页获取用户列表"
69 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
70 | // @Router /authority/getAuthorityList [post]
71 | func GetAuthorityList(c *gin.Context) {
72 | var pageInfo modelInterface.PageInfo
73 | _ = c.BindJSON(&pageInfo)
74 | err, list, total := new(sysModel.SysAuthority).GetInfoList(pageInfo)
75 | if err != nil {
76 | servers.ReportFormat(c, false, fmt.Sprintf("获取数据失败,%v", err), gin.H{})
77 | } else {
78 | servers.ReportFormat(c, true, "获取数据成功", gin.H{
79 | "list": list,
80 | "total": total,
81 | "page": pageInfo.Page,
82 | "pageSize": pageInfo.PageSize,
83 | })
84 | }
85 | }
86 |
87 | // @Tags authority
88 | // @Summary 设置角色资源权限
89 | // @Security ApiKeyAuth
90 | // @accept application/json
91 | // @Produce application/json
92 | // @Param data body sysModel.SysAuthority true "设置角色资源权限"
93 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
94 | // @Router /authority/setDataAuthority [post]
95 | func SetDataAuthority(c *gin.Context) {
96 | var auth sysModel.SysAuthority
97 | _ = c.ShouldBind(&auth)
98 | err := auth.SetDataAuthority()
99 | if err != nil {
100 | servers.ReportFormat(c, false, fmt.Sprintf("设置关联失败,%v", err), gin.H{})
101 | } else {
102 | servers.ReportFormat(c, true, "设置关联成功", gin.H{})
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/model/sysModel/sys_base_menu.go:
--------------------------------------------------------------------------------
1 | package sysModel
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/controller/servers"
6 | "nideshop-admin/init/qmsql"
7 | "nideshop-admin/model/modelInterface"
8 | "github.com/jinzhu/gorm"
9 | "github.com/pkg/errors"
10 | )
11 |
12 | type SysBaseMenu struct {
13 | gorm.Model
14 | MenuLevel uint `json:"-"`
15 | ParentId string `json:"parentId"`
16 | Path string `json:"path"`
17 | Name string `json:"name"`
18 | Hidden bool `json:"hidden"`
19 | Component string `json:"component"`
20 | Sort string `json:"sort"`
21 | Meta `json:"meta"`
22 | NickName string `json:"nickName"`
23 | Children []SysBaseMenu `json:"children"`
24 | }
25 |
26 | func (b *SysBaseMenu) AddBaseMenu() (err error) {
27 | findOne := qmsql.DEFAULTDB.Where("name = ?", b.Name).Find(&SysBaseMenu{}).Error
28 | if findOne != nil {
29 | b.NickName = b.Title
30 | err = qmsql.DEFAULTDB.Create(b).Error
31 | } else {
32 | err = errors.New("存在重复name,请修改name")
33 | }
34 | return err
35 | }
36 |
37 | func (b *SysBaseMenu) DeleteBaseMenu(id float64) (err error) {
38 | err = qmsql.DEFAULTDB.Where("parent_id = ?", id).First(&SysBaseMenu{}).Error
39 | if err != nil {
40 | err = qmsql.DEFAULTDB.Where("id = ?", id).Delete(&b).Error
41 | err = qmsql.DEFAULTDB.Where("menu_id = ?", id).Unscoped().Delete(&SysMenu{}).Error
42 | } else {
43 | return errors.New("此菜单存在子菜单不可删除")
44 | }
45 | return err
46 | }
47 |
48 | func (b *SysBaseMenu) UpdataBaseMenu() (err error) {
49 | upDataMap := make(map[string]interface{})
50 | upDataMap["parent_id"] = b.ParentId
51 | upDataMap["path"] = b.Path
52 | upDataMap["name"] = b.Name
53 | upDataMap["hidden"] = b.Hidden
54 | upDataMap["component"] = b.Component
55 | upDataMap["title"] = b.Title
56 | upDataMap["icon"] = b.Icon
57 | upDataMap["sort"] = b.Sort
58 | err = qmsql.DEFAULTDB.Where("id = ?", b.ID).Find(&SysBaseMenu{}).Updates(upDataMap).Error
59 | err1 := qmsql.DEFAULTDB.Where("menu_id = ?", b.ID).Find(&[]SysMenu{}).Updates(upDataMap).Error
60 | fmt.Printf("菜单修改时候,关联菜单err1:%v,err:%v", err1, err)
61 | return err
62 | }
63 |
64 | func (b *SysBaseMenu) GetBaseMenuById(id float64) (err error, menu SysBaseMenu) {
65 | err = qmsql.DEFAULTDB.Where("id = ?", id).First(&menu).Error
66 | return
67 | }
68 |
69 | func (b *SysBaseMenu) GetInfoList(info modelInterface.PageInfo) (err error, list interface{}, total int) {
70 | // 封装分页方法 调用即可 传入 当前的结构体和分页信息
71 | err, db, total := servers.PagingServer(b, info)
72 | if err != nil {
73 | return
74 | } else {
75 | var menuList []SysBaseMenu
76 | err = db.Where("parent_id = 0").Order("sort", true).Find(&menuList).Error
77 | for i := 0; i < len(menuList); i++ {
78 | err = getBaseChildrenList(&menuList[i])
79 | }
80 | return err, menuList, total
81 | }
82 | }
83 |
84 | //获取基础路由树
85 | func (m *SysBaseMenu) GetBaseMenuTree() (err error, menus []SysBaseMenu) {
86 | err = qmsql.DEFAULTDB.Where(" parent_id = ?", 0).Order("sort", true).Find(&menus).Error
87 | for i := 0; i < len(menus); i++ {
88 | err = getBaseChildrenList(&menus[i])
89 | }
90 | return err, menus
91 | }
92 |
93 | func getBaseChildrenList(menu *SysBaseMenu) (err error) {
94 | err = qmsql.DEFAULTDB.Where("parent_id = ?", menu.ID).Order("sort", true).Find(&menu.Children).Error
95 | for i := 0; i < len(menu.Children); i++ {
96 | err = getBaseChildrenList(&menu.Children[i])
97 | }
98 | return err
99 | }
100 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/api/api.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags api
3 | // @Summary 分页获取角色列表
4 | // @Security ApiKeyAuth
5 | // @accept application/json
6 | // @Produce application/json
7 | // @Param data body modelInterface.PageInfo true "分页获取用户列表"
8 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
9 | // @Router /api/getApiList [post]
10 | // {
11 | // page int
12 | // pageSize int
13 | // }
14 | export const getApiList = (data) => {
15 | return service({
16 | url: "/api/getApiList",
17 | method: 'post',
18 | data
19 | })
20 | }
21 |
22 |
23 | // @Tags Api
24 | // @Summary 创建基础api
25 | // @Security ApiKeyAuth
26 | // @accept application/json
27 | // @Produce application/json
28 | // @Param data body api.CreateApiParams true "创建api"
29 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
30 | // @Router /api/createApi [post]
31 | export const createApi = (data) => {
32 | return service({
33 | url: "/api/createApi",
34 | method: 'post',
35 | data
36 | })
37 | }
38 |
39 | // @Tags menu
40 | // @Summary 根据id获取菜单
41 | // @Security ApiKeyAuth
42 | // @accept application/json
43 | // @Produce application/json
44 | // @Param data body api.GetById true "根据id获取菜单"
45 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
46 | // @Router /menu/getApiById [post]
47 | export const getApiById = (data) => {
48 | return service({
49 | url: "/api/getApiById",
50 | method: 'post',
51 | data
52 | })
53 | }
54 |
55 |
56 |
57 | // @Tags Api
58 | // @Summary 更新api
59 | // @Security ApiKeyAuth
60 | // @accept application/json
61 | // @Produce application/json
62 | // @Param data body api.CreateApiParams true "更新api"
63 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"更新成功"}"
64 | // @Router /api/updataApi [post]
65 | export const updataApi = (data) => {
66 | return service({
67 | url: "/api/updataApi",
68 | method: 'post',
69 | data
70 | })
71 | }
72 |
73 | // @Tags Api
74 | // @Summary 更新api
75 | // @Security ApiKeyAuth
76 | // @accept application/json
77 | // @Produce application/json
78 | // @Param data body api.CreateApiParams true "更新api"
79 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"更新成功"}"
80 | // @Router /api/setAuthApi [post]
81 | export const setAuthApi = (data) => {
82 | return service({
83 | url: "/api/setAuthApi",
84 | method: 'post',
85 | data
86 | })
87 | }
88 |
89 | // @Tags Api
90 | // @Summary 获取所有的Api 不分页
91 | // @Security ApiKeyAuth
92 | // @accept application/json
93 | // @Produce application/json
94 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
95 | // @Router /api/getAllApis [post]
96 | export const getAllApis = (data) => {
97 | return service({
98 | url: "/api/getAllApis",
99 | method: 'post',
100 | data
101 | })
102 | }
103 |
104 | // @Tags Api
105 | // @Summary 删除指定api
106 | // @Security ApiKeyAuth
107 | // @accept application/json
108 | // @Produce application/json
109 | // @Param data body dbModel.Api true "删除api"
110 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
111 | // @Router /api/deleteApi [post]
112 | export const deleteApi = (data) => {
113 | return service({
114 | url: "/api/deleteApi",
115 | method: 'post',
116 | data
117 | })
118 | }
--------------------------------------------------------------------------------
/controller/api/exa_fileUploadAndDownload.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/controller/servers"
6 | "nideshop-admin/model/dbModel"
7 | "nideshop-admin/model/modelInterface"
8 | "strings"
9 |
10 | "github.com/gin-gonic/gin"
11 | )
12 |
13 | // @Tags ExaFileUploadAndDownload
14 | // @Summary 上传文件示例
15 | // @Security ApiKeyAuth
16 | // @accept multipart/form-data
17 | // @Produce application/json
18 | // @Param file formData file true "上传文件示例"
19 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"上传成功"}"
20 | // @Router /fileUploadAndDownload/upload [post]
21 | func UploadFile(c *gin.Context) {
22 | noSave := c.DefaultQuery("noSave", "0")
23 | _, header, err := c.Request.FormFile("file")
24 | if err != nil {
25 | servers.ReportFormat(c, false, fmt.Sprintf("上传文件失败,%v", err), gin.H{})
26 | } else {
27 | //文件上传后拿到文件路径
28 | err, filePath, key := servers.Upload(header, USER_HEADER_BUCKET)
29 | fmt.Println(filePath)
30 | fmt.Println(key)
31 | if err != nil {
32 | servers.ReportFormat(c, false, fmt.Sprintf("接收返回值失败,%v", err), gin.H{})
33 | } else {
34 | //修改数据库后得到修改后的user并且返回供前端使用
35 | var file dbModel.ExaFileUploadAndDownload
36 | file.Url = filePath
37 | file.Name = header.Filename
38 | s := strings.Split(file.Name, ".")
39 | file.Tag = s[len(s)-1]
40 | file.Key = key
41 | if noSave == "0" {
42 | err = file.Upload()
43 | }
44 | if err != nil {
45 | servers.ReportFormat(c, false, fmt.Sprintf("修改数据库链接失败,%v", err), gin.H{})
46 | } else {
47 | servers.ReportFormat(c, true, "上传成功", gin.H{"file": file})
48 | }
49 | }
50 | }
51 | }
52 |
53 | // @Tags ExaFileUploadAndDownload
54 | // @Summary 删除文件
55 | // @Security ApiKeyAuth
56 | // @Produce application/json
57 | // @Param data body dbModel.ExaFileUploadAndDownload true "传入文件里面id即可"
58 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
59 | // @Router /fileUploadAndDownload/deleteFile [post]
60 | func DeleteFile(c *gin.Context) {
61 | var file dbModel.ExaFileUploadAndDownload
62 | _ = c.ShouldBind(&file)
63 | err, f := file.FindFile()
64 | if err != nil {
65 | servers.ReportFormat(c, false, fmt.Sprintf("删除失败,%v", err), gin.H{})
66 | } else {
67 | err = servers.DeleteFile(USER_HEADER_BUCKET, f.Key)
68 | if err != nil {
69 | servers.ReportFormat(c, false, fmt.Sprintf("删除失败,%v", err), gin.H{})
70 | } else {
71 | err = f.DeleteFile()
72 | if err != nil {
73 | servers.ReportFormat(c, false, fmt.Sprintf("删除失败,%v", err), gin.H{})
74 | } else {
75 | servers.ReportFormat(c, true, fmt.Sprintf("删除成功,%v", err), gin.H{})
76 | }
77 | }
78 | }
79 | }
80 |
81 | // @Tags ExaFileUploadAndDownload
82 | // @Summary 分页文件列表
83 | // @Security ApiKeyAuth
84 | // @accept application/json
85 | // @Produce application/json
86 | // @Param data body modelInterface.PageInfo true "分页获取文件户列表"
87 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
88 | // @Router /fileUploadAndDownload/getFileList [post]
89 | func GetFileList(c *gin.Context) {
90 | var pageInfo modelInterface.PageInfo
91 | _ = c.BindJSON(&pageInfo)
92 | err, list, total := new(dbModel.ExaFileUploadAndDownload).GetInfoList(pageInfo)
93 | if err != nil {
94 | servers.ReportFormat(c, false, fmt.Sprintf("获取数据失败,%v", err), gin.H{})
95 | } else {
96 | servers.ReportFormat(c, true, "获取数据成功", gin.H{
97 | "list": list,
98 | "total": total,
99 | "page": pageInfo.Page,
100 | "pageSize": pageInfo.PageSize,
101 | })
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/example/table/table.vue:
--------------------------------------------------------------------------------
1 | // table 纯前端示例
2 |
3 |
4 |
13 |
14 |
15 | {{ scope.row.date }}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | 按钮1
28 | 按钮2
29 | 按钮3
30 |
31 |
32 |
33 |
34 | 切换第二、第三行的选中状态
35 | 取消选择
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | nideshop-admin
4 |
5 |
6 |

7 |

8 |

9 |

10 |

11 |
12 |
13 |
14 | # nideshop-admin gin+vue开源快速项目模板
15 | 本模板使用前端ui框架为 element-ui https://element.eleme.cn/#/zh-CN 前端组件可查看elementUi文档使用
16 | ## 写在前面
17 | 非常感谢 [@piexlmax](https://github.com/piexlmax)提供项目脚手架,脚手架地址 [gin-vue-admin](https://github.com/piexlmax/gin-vue-admin)
18 |
19 |
20 | ## 环境搭建教学视频
21 |
22 | 腾讯视频:https://v.qq.com/x/page/e3008xjxqtu.html (等待最新视频录制)
23 |
24 | ## 模板使用教学及展示视频
25 |
26 | 腾讯视频:https://v.qq.com/x/page/c3008y2ukba.html (等待最新视频录制)
27 |
28 | ## 技术选型
29 | 1.后端采用golang框架gin,快速搭建基础restful风格API
30 | 2.前端项目采用VUE框架,构建基础页面
31 | 3.数据库采用Mysql(5.6.44)版本不同可能会导致SQL导入失败
32 | 4.使用redis实现记录当前活跃用户的jwt令牌并实现多点登录限制
33 | 5.使用swagger构建自动化文档
34 | 6.使用fsnotify和viper实现json格式配置文件
35 | 7.使用logrus实现日志记录
36 | 8.使用gorm实现对数据库的基本操作
37 |
38 | ## 项目说明
39 | static/config存放mysql相关配置。可以根据自己的mysql数据库名 用户名 密码修改对应配置
40 | vue项目存放于QMPlusVuePage文件夹下
41 | 开源不易,感谢各位支持,错误指出即刻改正,改写纠错,感谢star支持
42 | ## TODO
43 | ###脚手架
44 | 1.基本用户注册登录 √
45 | 2.用户等基础数据CURD √
46 | 3.调用des实现数据加密 √
47 | 4.实现基于jwt的权限管理 √
48 | 6.封装了分页方法,实现分页接口并且复制粘贴就可使用分页 √
49 | 7.前端分页mixin封装 分页方法调用mixins即可 √
50 | 8.图片上传前端下载功能 √
51 | 9.富文本编辑器,MarkDown编辑器功能嵌入 √
52 | 10.增加条件搜索示例 前端文件参考src\view\superAdmin\api\api.vue 后台文件参考 model\dnModel\api.go √
53 | 11.增加了多点登录限制 体验需要再 static\config中 把 system中的useMultipoint 修改为 true(需要自行配置redis和config中的redis参数)(测试阶段,有bug请及时反馈)√
54 | 12.增加了配置文件管理功能 √
55 | ###nideshop-admin
56 | 1.商品管理
57 | 2.商品分类管理
58 | ## 使用说明
59 | 1.golang api server 基于go.mod 如果golang版本低于1.11 请自行升级golang版本
60 | 2.支持go.mod的golang版本在运行go list 和 编译之前都会自动下载所需要的依赖包
61 | 3.前端项目node建议高于V8.6.0
62 | 4.到前端项目目录下运行 npm i 安装所需依赖
63 | 5.依赖安装完成直接运行 npm run serve即可启动项目
64 | 6.如果要使用swagger自动化文档 首先需要安装 swagger
65 | ````
66 | go get -u github.com/swaggo/swag/cmd/swag
67 | ````
68 | 由于国内没法安装到X包下面的东西 如果可以翻墙 上面的命令就可以让你安心使用swagger了
69 | 如果没有翻墙的办法那就先装一下 gopm
70 |
71 | ````
72 | go get -v -u github.com/gpmgo/gopm
73 | ````
74 | 此时你就可以使用 gopm了
75 | 这时候执行
76 | ````
77 | gopm get -g -v github.com/swaggo/swag/cmd/swag
78 | ````
79 | 等待安装完成以后
80 | 到我们GOPATH下面的/src/github.com/swaggo/swag/cmd/swag路径
81 | 执行
82 | ````
83 | go install
84 | ````
85 | 安装完成过后在项目目录下运行
86 | ````
87 | swag init
88 | ````
89 | 项目文件夹下面会有 doc文件夹出现
90 | 这时候登录 localhost:8888/swagger/index.html
91 | 就可以看到 swagger文档啦
92 |
93 | ## docker镜像
94 | 感谢 [@chenlinzhong](https://github.com/chenlinzhong)提供docker镜像
95 |
96 | #启动容器
97 | docker run -itd --net=host --name=go_container shareclz/go_node /bin/bash;
98 |
99 | #进入容器
100 | docker exec -it go_container /bin/bash;
101 | git clone https://github.com/piexlmax/nideshop-admin.git /data1/www/htdocs/go/admin;
102 |
103 | #启动前端
104 | cd /data1/www/htdocs/go/admin/QMPlusVuePage;
105 | cnpm i ;
106 | npm run serve;
107 |
108 | #修改数据库配置
109 | vi /data1/www/htdocs/go/admin/QMPlusServer/static/dbconfig/config.json;
110 |
111 | #启动后端
112 | cd /data1/www/htdocs/go/admin/QMPlusServer;
113 | go run main.go;
114 |
115 |
116 | ## 联系方式
117 |
118 |
119 |
qq交流群:234706951
120 | 微信交流群加微信:14320794 备注"加入nideshop-admin交流群"
121 |
122 |
123 |
124 | ## 更新日志
125 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/superAdmin/system/system.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 系统配置
5 |
6 | 开启
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | jwt签名
15 |
16 |
17 |
18 | casbin配置
19 |
20 |
21 |
22 | mysql admin数据库配置
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | Redis admin数据库配置
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | 七牛密钥配置
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | 立即更新
57 | 重启服务(开发中)
58 |
59 |
60 |
61 |
62 |
63 |
103 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/login/regist.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GIN-VUE-ADMIN
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
29 | 注 册
30 |
31 |
32 |
33 |
34 |
35 |
36 |
108 |
109 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/workflow/workflowCreate/workflowCreate.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 新增
15 |
16 |
17 |
18 |
19 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | 提交
57 |
58 |
59 |
60 |
114 |
116 |
--------------------------------------------------------------------------------
/middleware/jwt.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "errors"
5 | "nideshop-admin/config"
6 | "nideshop-admin/controller/servers"
7 | "nideshop-admin/model/sysModel"
8 | "github.com/dgrijalva/jwt-go"
9 | "github.com/gin-gonic/gin"
10 | uuid "github.com/satori/go.uuid"
11 | "time"
12 | )
13 |
14 | func JWTAuth() gin.HandlerFunc {
15 | return func(c *gin.Context) {
16 | // 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localSstorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录
17 | token := c.Request.Header.Get("x-token")
18 | ModelToken := sysModel.JwtBlacklist{
19 | Jwt: token,
20 | }
21 | if token == "" {
22 | servers.ReportFormat(c, false, "未登录或非法访问", gin.H{
23 | "reload": true,
24 | })
25 | c.Abort()
26 | return
27 | }
28 | if ModelToken.IsBlacklist(token) {
29 | servers.ReportFormat(c, false, "您的帐户异地登陆或令牌失效", gin.H{
30 | "reload": true,
31 | })
32 | c.Abort()
33 | return
34 | }
35 | j := NewJWT()
36 | // parseToken 解析token包含的信息
37 | claims, err := j.ParseToken(token)
38 | if err != nil {
39 | if err == TokenExpired {
40 | servers.ReportFormat(c, false, "授权已过期", gin.H{
41 | "reload": true,
42 | })
43 | c.Abort()
44 | return
45 | }
46 | servers.ReportFormat(c, false, err.Error(), gin.H{
47 | "reload": true,
48 | })
49 | c.Abort()
50 | return
51 | }
52 | c.Set("claims", claims)
53 | c.Next()
54 | }
55 | }
56 |
57 | type JWT struct {
58 | SigningKey []byte
59 | }
60 |
61 | var (
62 | TokenExpired error = errors.New("Token is expired")
63 | TokenNotValidYet error = errors.New("Token not active yet")
64 | TokenMalformed error = errors.New("That's not even a token")
65 | TokenInvalid error = errors.New("Couldn't handle this token:")
66 | )
67 |
68 | type CustomClaims struct {
69 | UUID uuid.UUID
70 | ID uint
71 | NickName string
72 | AuthorityId string
73 | jwt.StandardClaims
74 | }
75 |
76 | func NewJWT() *JWT {
77 | return &JWT{
78 | []byte(config.GinVueAdminconfig.JWT.SigningKey),
79 | }
80 | }
81 |
82 | //创建一个token
83 | func (j *JWT) CreateToken(claims CustomClaims) (string, error) {
84 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
85 | return token.SignedString(j.SigningKey)
86 | }
87 |
88 | //解析 token
89 | func (j *JWT) ParseToken(tokenString string) (*CustomClaims, error) {
90 | token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) {
91 | return j.SigningKey, nil
92 | })
93 | if err != nil {
94 | if ve, ok := err.(*jwt.ValidationError); ok {
95 | if ve.Errors&jwt.ValidationErrorMalformed != 0 {
96 | return nil, TokenMalformed
97 | } else if ve.Errors&jwt.ValidationErrorExpired != 0 {
98 | // Token is expired
99 | return nil, TokenExpired
100 | } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
101 | return nil, TokenNotValidYet
102 | } else {
103 | return nil, TokenInvalid
104 | }
105 | }
106 | }
107 | if token != nil {
108 | if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
109 | return claims, nil
110 | }
111 | return nil, TokenInvalid
112 |
113 | } else {
114 | return nil, TokenInvalid
115 |
116 | }
117 |
118 | }
119 |
120 | // 更新token
121 | func (j *JWT) RefreshToken(tokenString string) (string, error) {
122 | jwt.TimeFunc = func() time.Time {
123 | return time.Unix(0, 0)
124 | }
125 | token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
126 | return j.SigningKey, nil
127 | })
128 | if err != nil {
129 | return "", err
130 | }
131 | if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
132 | jwt.TimeFunc = time.Now
133 | claims.StandardClaims.ExpiresAt = time.Now().Add(1 * time.Hour).Unix()
134 | return j.CreateToken(*claims)
135 | }
136 | return "", TokenInvalid
137 | }
138 |
--------------------------------------------------------------------------------
/QMPlusVuePage/vue.config.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const path = require('path')
4 |
5 | function resolve(dir) {
6 | return path.join(__dirname, dir)
7 | }
8 | module.exports = {
9 | // 基础配置 详情看文档
10 | publicPath: './',
11 | outputDir: 'dist',
12 | assetsDir: 'static',
13 | lintOnSave: process.env.NODE_ENV === 'development',
14 | productionSourceMap: false,
15 | devServer: {
16 | port: 8080,
17 | open: true,
18 | overlay: {
19 | warnings: false,
20 | errors: true
21 | },
22 | proxy: {
23 | // 把key的路径代理到target位置
24 | // detail: https://cli.vuejs.org/config/#devserver-proxy
25 | [process.env.VUE_APP_BASE_API]: { //需要代理的路径 例如 '/api'
26 | target: `http://127.0.0.1:8888`, //代理到 目标路径
27 | changeOrigin: true,
28 | pathRewrite: { // 修改路径数据
29 | ['^' + process.env.VUE_APP_BASE_API]: '' // 举例 '^/api:""' 把路径中的/api字符串删除
30 | }
31 | }
32 | },
33 | },
34 | configureWebpack: {
35 | // @路径走src文件夹
36 | resolve: {
37 | alias: {
38 | '@': resolve('src')
39 | }
40 | }
41 | },
42 | chainWebpack(config) {
43 | // set preserveWhitespace
44 | config.module
45 | .rule('vue')
46 | .use('vue-loader')
47 | .loader('vue-loader')
48 | .tap(options => {
49 | options.compilerOptions.preserveWhitespace = true
50 | return options
51 | })
52 | .end()
53 | config
54 | // https://webpack.js.org/configuration/devtool/#development
55 | .when(process.env.NODE_ENV === 'development',
56 | config => config.devtool('cheap-source-map')
57 | )
58 |
59 | config
60 | .when(process.env.NODE_ENV !== 'development',
61 | config => {
62 | config
63 | .plugin('ScriptExtHtmlWebpackPlugin')
64 | .after('html')
65 | .use('script-ext-html-webpack-plugin', [{
66 | // `runtime` must same as runtimeChunk name. default is `runtime`
67 | inline: /runtime\..*\.js$/
68 | }])
69 | .end()
70 | config
71 | .optimization.splitChunks({
72 | chunks: 'all',
73 | cacheGroups: {
74 | libs: {
75 | name: 'chunk-libs',
76 | test: /[\\/]node_modules[\\/]/,
77 | priority: 10,
78 | chunks: 'initial' // only package third parties that are initially dependent
79 | },
80 | elementUI: {
81 | name: 'chunk-elementUI', // split elementUI into a single package
82 | priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
83 | test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
84 | },
85 | commons: {
86 | name: 'chunk-commons',
87 | test: resolve('src/components'), // can customize your rules
88 | minChunks: 3, // minimum common number
89 | priority: 5,
90 | reuseExistingChunk: true
91 | }
92 | }
93 | })
94 | config.optimization.runtimeChunk('single')
95 | }
96 | )
97 | }
98 | }
--------------------------------------------------------------------------------
/controller/api/exa_breakpoint_continue.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/controller/servers"
6 | "nideshop-admin/model/dbModel"
7 | "github.com/gin-gonic/gin"
8 | "io/ioutil"
9 | "strconv"
10 | )
11 |
12 | // @Tags ExaFileUploadAndDownload
13 | // @Summary 断点续传到服务器
14 | // @Security ApiKeyAuth
15 | // @accept multipart/form-data
16 | // @Produce application/json
17 | // @Param file formData file true "断点续传示例"
18 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"上传成功"}"
19 | // @Router /fileUploadAndDownload/breakpointContinue [post]
20 |
21 | func BreakpointContinue(c *gin.Context) {
22 | fileMd5 := c.Request.FormValue("fileMd5")
23 | fileName := c.Request.FormValue("fileName")
24 | chunkMd5 := c.Request.FormValue("chunkMd5")
25 | chunkNumber, _ := strconv.Atoi(c.Request.FormValue("chunkNumber"))
26 | chunkTotal, _ := strconv.Atoi(c.Request.FormValue("chunkTotal"))
27 | _, FileHeader, err := c.Request.FormFile("file")
28 | if err != nil {
29 | servers.ReportFormat(c, false, fmt.Sprintf("%v", err), gin.H{})
30 | } else {
31 | f, err := FileHeader.Open()
32 | if err != nil {
33 | servers.ReportFormat(c, false, fmt.Sprintf("%v", err), gin.H{})
34 | } else {
35 | cen, _ := ioutil.ReadAll(f)
36 | defer f.Close()
37 | if flag := servers.CheckMd5(cen, chunkMd5); flag {
38 | err, file := new(dbModel.ExaFile).FindOrCreateFile(fileMd5, fileName, chunkTotal)
39 | if err != nil {
40 | servers.ReportFormat(c, false, fmt.Sprintf("%v", err), gin.H{})
41 | } else {
42 | err, pathc := servers.BreakPointContinue(cen, fileName, chunkNumber, chunkTotal, fileMd5)
43 | if err != nil {
44 | servers.ReportFormat(c, false, fmt.Sprintf("%v", err), gin.H{})
45 | } else {
46 | err = file.CreateFileChunk(pathc, chunkNumber)
47 | if err != nil {
48 | servers.ReportFormat(c, false, fmt.Sprintf("%v", err), gin.H{})
49 | } else {
50 | servers.ReportFormat(c, true, "切片创建成功", gin.H{})
51 | }
52 | }
53 | }
54 | } else {
55 | }
56 | }
57 | }
58 | }
59 |
60 | // @Tags ExaFileUploadAndDownload
61 | // @Summary 查找文件
62 | // @Security ApiKeyAuth
63 | // @accept multipart/form-data
64 | // @Produce application/json
65 | // @Param file params file true "查找文件"
66 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"查找成功"}"
67 | // @Router /fileUploadAndDownload/findFile [post]
68 | func FindFile(c *gin.Context) {
69 | fileMd5 := c.Query("fileMd5")
70 | fileName := c.Query("fileName")
71 | chunkTotal, _ := strconv.Atoi(c.Query("chunkTotal"))
72 | err, file := new(dbModel.ExaFile).FindOrCreateFile(fileMd5, fileName, chunkTotal)
73 | if err != nil {
74 | servers.ReportFormat(c, false, fmt.Sprintf("查找失败:%v", err), gin.H{})
75 | } else {
76 | servers.ReportFormat(c, true, "查找成功", gin.H{"file": file})
77 | }
78 | }
79 |
80 | // @Tags ExaFileUploadAndDownload
81 | // @Summary 查找文件
82 | // @Security ApiKeyAuth
83 | // @accept multipart/form-data
84 | // @Produce application/json
85 | // @Param file params file true "查找文件"
86 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"查找成功"}"
87 | // @Router /fileUploadAndDownload/findFile [post]
88 | func BreakpointContinueFinish(c *gin.Context) {
89 | fileMd5 := c.Query("fileMd5")
90 | fileName := c.Query("fileName")
91 | err, filePath := servers.MakeFile(fileName, fileMd5)
92 | if err != nil {
93 | servers.ReportFormat(c, true, fmt.Sprintf("文件创建失败:%v", err), gin.H{})
94 | } else {
95 | servers.ReportFormat(c, true, "文件创建成功", gin.H{"filePath": filePath})
96 | }
97 | }
98 |
99 | // @Tags ExaFileUploadAndDownload
100 | // @Summary 删除切片
101 | // @Security ApiKeyAuth
102 | // @accept multipart/form-data
103 | // @Produce application/json
104 | // @Param file params file true "查找文件"
105 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"查找成功"}"
106 | // @Router /fileUploadAndDownload/removeChunk [post]
107 | func RemoveChunk(c *gin.Context) {
108 | fileMd5 := c.Query("fileMd5")
109 | fileName := c.Query("fileName")
110 | filePath := c.Query("filePath")
111 | err := servers.RemoveChunk(fileMd5)
112 | err = new(dbModel.ExaFile).DeleteFileChunk(fileMd5, fileName, filePath)
113 | if err != nil {
114 | servers.ReportFormat(c, true, fmt.Sprintf("缓存切片删除失败:%v", err), gin.H{})
115 | } else {
116 | servers.ReportFormat(c, true, "缓存切片删除成功", gin.H{})
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/controller/api/sys_api.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/controller/servers"
6 | "nideshop-admin/model/modelInterface"
7 | "nideshop-admin/model/sysModel"
8 | "github.com/gin-gonic/gin"
9 | )
10 |
11 | type CreateApiParams struct {
12 | Path string `json:"path"`
13 | Description string `json:"description"`
14 | }
15 |
16 | type DeleteApiParams struct {
17 | ID uint `json:"id"`
18 | }
19 |
20 | // @Tags SysApi
21 | // @Summary 创建基础api
22 | // @Security ApiKeyAuth
23 | // @accept application/json
24 | // @Produce application/json
25 | // @Param data body api.CreateApiParams true "创建api"
26 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
27 | // @Router /api/createApi [post]
28 | func CreateApi(c *gin.Context) {
29 | var api sysModel.SysApi
30 | _ = c.BindJSON(&api)
31 | err := api.CreateApi()
32 | if err != nil {
33 | servers.ReportFormat(c, false, fmt.Sprintf("创建失败:%v", err), gin.H{})
34 | } else {
35 | servers.ReportFormat(c, true, "创建成功", gin.H{})
36 | }
37 | }
38 |
39 | // @Tags SysApi
40 | // @Summary 删除指定api
41 | // @Security ApiKeyAuth
42 | // @accept application/json
43 | // @Produce application/json
44 | // @Param data body sysModel.SysApi true "删除api"
45 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
46 | // @Router /api/deleteApi [post]
47 | func DeleteApi(c *gin.Context) {
48 | var a sysModel.SysApi
49 | _ = c.BindJSON(&a)
50 | err := a.DeleteApi()
51 | if err != nil {
52 | servers.ReportFormat(c, false, fmt.Sprintf("删除失败:%v", err), gin.H{})
53 | } else {
54 | servers.ReportFormat(c, true, "删除成功", gin.H{})
55 | }
56 | }
57 |
58 | type AuthAndPathIn struct {
59 | AuthorityId string `json:"authorityId"`
60 | ApiIds []uint `json:"apiIds"`
61 | }
62 |
63 | //条件搜索后端看此api
64 |
65 | // @Tags SysApi
66 | // @Summary 分页获取API列表
67 | // @Security ApiKeyAuth
68 | // @accept application/json
69 | // @Produce application/json
70 | // @Param data body modelInterface.PageInfo true "分页获取API列表"
71 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
72 | // @Router /api/getApiList [post]
73 | func GetApiList(c *gin.Context) {
74 | // 此结构体仅本方法使用
75 | type searchParams struct {
76 | sysModel.SysApi
77 | modelInterface.PageInfo
78 | }
79 | var sp searchParams
80 | _ = c.ShouldBindJSON(&sp)
81 | err, list, total := sp.SysApi.GetInfoList(sp.PageInfo)
82 | if err != nil {
83 | servers.ReportFormat(c, false, fmt.Sprintf("获取数据失败,%v", err), gin.H{})
84 | } else {
85 | servers.ReportFormat(c, true, "获取数据成功", gin.H{
86 | "list": list,
87 | "total": total,
88 | "page": sp.PageInfo.Page,
89 | "pageSize": sp.PageInfo.PageSize,
90 | })
91 |
92 | }
93 | }
94 |
95 | // @Tags SysApi
96 | // @Summary 根据id获取api
97 | // @Security ApiKeyAuth
98 | // @accept application/json
99 | // @Produce application/json
100 | // @Param data body modelInterface.PageInfo true "分页获取用户列表"
101 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
102 | // @Router /api/getApiById [post]
103 | func GetApiById(c *gin.Context) {
104 | var idInfo GetById
105 | _ = c.BindJSON(&idInfo)
106 | err, api := new(sysModel.SysApi).GetApiById(idInfo.Id)
107 | if err != nil {
108 | servers.ReportFormat(c, false, fmt.Sprintf("获取数据失败,%v", err), gin.H{})
109 | } else {
110 | servers.ReportFormat(c, true, "获取数据成功", gin.H{
111 | "api": api,
112 | })
113 |
114 | }
115 | }
116 |
117 | // @Tags SysApi
118 | // @Summary 创建基础api
119 | // @Security ApiKeyAuth
120 | // @accept application/json
121 | // @Produce application/json
122 | // @Param data body api.CreateApiParams true "创建api"
123 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
124 | // @Router /api/updataApi [post]
125 | func UpdataApi(c *gin.Context) {
126 | var api sysModel.SysApi
127 | _ = c.BindJSON(&api)
128 | err := api.UpdataApi()
129 | if err != nil {
130 | servers.ReportFormat(c, false, fmt.Sprintf("修改数据失败,%v", err), gin.H{})
131 | } else {
132 | servers.ReportFormat(c, true, "修改数据成功", gin.H{})
133 | }
134 | }
135 |
136 | // @Tags SysApi
137 | // @Summary 获取所有的Api 不分页
138 | // @Security ApiKeyAuth
139 | // @accept application/json
140 | // @Produce application/json
141 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
142 | // @Router /api/getAllApis [post]
143 | func GetAllApis(c *gin.Context) {
144 | err, apis := new(sysModel.SysApi).GetAllApis()
145 | if err != nil {
146 | servers.ReportFormat(c, false, fmt.Sprintf("获取数据失败,%v", err), gin.H{})
147 | } else {
148 | servers.ReportFormat(c, true, "获取数据成功", gin.H{
149 | "apis": apis,
150 | })
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/example/upload/upload.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 | 点击上传
13 | 只能上传jpg/png文件,且不超过500kb
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | {{scope.row.UpdatedAt|formatDate}}
24 |
25 |
26 |
27 |
28 |
29 |
30 | {{scope.row.tag}}
34 |
35 |
36 |
37 |
38 | 下载
39 | 删除
40 |
41 |
42 |
43 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
35 |
36 |
38 |
39 | {{item.meta.title}}
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
86 |
87 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/superAdmin/authority/authority.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 新增角色
5 |
6 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 设置权限
20 | 删除角色
21 | 新增子角色
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
166 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/superAdmin/user/user.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 新增用户
5 |
6 |
7 |
8 |
9 |
10 |
![]()
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
30 |
31 |
32 |
33 |
34 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
84 |
85 |
86 |
87 |
88 |
89 |
159 |
--------------------------------------------------------------------------------
/controller/api/sys_menu.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "fmt"
5 | "nideshop-admin/controller/servers"
6 | "nideshop-admin/middleware"
7 | "nideshop-admin/model/modelInterface"
8 | "nideshop-admin/model/sysModel"
9 | "github.com/gin-gonic/gin"
10 | )
11 |
12 | // @Tags authorityAndMenu
13 | // @Summary 获取用户动态路由
14 | // @Security ApiKeyAuth
15 | // @Produce application/json
16 | // @Param data body api.RegistAndLoginStuct true "可以什么都不填"
17 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
18 | // @Router /menu/getMenu [post]
19 | func GetMenu(c *gin.Context) {
20 | claims, _ := c.Get("claims")
21 | waitUse := claims.(*middleware.CustomClaims)
22 | err, menus := new(sysModel.SysMenu).GetMenuTree(waitUse.AuthorityId)
23 | if err != nil {
24 | servers.ReportFormat(c, false, fmt.Sprintf("获取失败:%v", err), gin.H{"menus": menus})
25 | } else {
26 | servers.ReportFormat(c, true, "获取成功", gin.H{"menus": menus})
27 | }
28 | }
29 |
30 | // @Tags menu
31 | // @Summary 分页获取基础menu列表
32 | // @Security ApiKeyAuth
33 | // @accept application/json
34 | // @Produce application/json
35 | // @Param data body modelInterface.PageInfo true "分页获取基础menu列表"
36 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
37 | // @Router /menu/getMenuList [post]
38 | func GetMenuList(c *gin.Context) {
39 | var pageInfo modelInterface.PageInfo
40 | _ = c.BindJSON(&pageInfo)
41 | err, menuList, total := new(sysModel.SysBaseMenu).GetInfoList(pageInfo)
42 | if err != nil {
43 | servers.ReportFormat(c, false, fmt.Sprintf("获取数据失败,%v", err), gin.H{})
44 | } else {
45 | servers.ReportFormat(c, true, "获取数据成功", gin.H{
46 | "list": menuList,
47 | "total": total,
48 | "page": pageInfo.Page,
49 | "pageSize": pageInfo.PageSize,
50 | })
51 | }
52 | }
53 |
54 | // @Tags menu
55 | // @Summary 新增菜单
56 | // @Security ApiKeyAuth
57 | // @accept application/json
58 | // @Produce application/json
59 | // @Param data body sysModel.SysBaseMenu true "新增菜单"
60 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
61 | // @Router /menu/addBaseMenu [post]
62 | func AddBaseMenu(c *gin.Context) {
63 | var addMenu sysModel.SysBaseMenu
64 | _ = c.BindJSON(&addMenu)
65 | err := addMenu.AddBaseMenu()
66 | if err != nil {
67 | servers.ReportFormat(c, false, fmt.Sprintf("添加失败,%v", err), gin.H{})
68 | } else {
69 | servers.ReportFormat(c, true, fmt.Sprintf("添加成功,%v", err), gin.H{})
70 | }
71 | }
72 |
73 | // @Tags authorityAndMenu
74 | // @Summary 获取用户动态路由
75 | // @Security ApiKeyAuth
76 | // @Produce application/json
77 | // @Param data body api.RegistAndLoginStuct true "可以什么都不填"
78 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
79 | // @Router /menu/getBaseMenuTree [post]
80 | func GetBaseMenuTree(c *gin.Context) {
81 | err, menus := new(sysModel.SysBaseMenu).GetBaseMenuTree()
82 | if err != nil {
83 | servers.ReportFormat(c, false, fmt.Sprintf("获取失败:%v", err), gin.H{"menus": menus})
84 | } else {
85 | servers.ReportFormat(c, true, "获取成功", gin.H{"menus": menus})
86 | }
87 | }
88 |
89 | type AddMenuAuthorityInfo struct {
90 | Menus []sysModel.SysBaseMenu
91 | AuthorityId string
92 | }
93 |
94 | // @Tags authorityAndMenu
95 | // @Summary 增加menu和角色关联关系
96 | // @Security ApiKeyAuth
97 | // @accept application/json
98 | // @Produce application/json
99 | // @Param data body api.AddMenuAuthorityInfo true "增加menu和角色关联关系"
100 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
101 | // @Router /menu/addMenuAuthority [post]
102 | func AddMenuAuthority(c *gin.Context) {
103 | var addMenuAuthorityInfo AddMenuAuthorityInfo
104 | _ = c.BindJSON(&addMenuAuthorityInfo)
105 | err := new(sysModel.SysMenu).AddMenuAuthority(addMenuAuthorityInfo.Menus, addMenuAuthorityInfo.AuthorityId)
106 | if err != nil {
107 | servers.ReportFormat(c, false, fmt.Sprintf("添加失败,%v", err), gin.H{})
108 | } else {
109 | servers.ReportFormat(c, true, fmt.Sprintf("添加成功,%v", err), gin.H{})
110 | }
111 | }
112 |
113 | type AuthorityIdInfo struct {
114 | AuthorityId string
115 | }
116 |
117 | // @Tags authorityAndMenu
118 | // @Summary 获取指定角色menu
119 | // @Security ApiKeyAuth
120 | // @accept application/json
121 | // @Produce application/json
122 | // @Param data body api.AuthorityIdInfo true "增加menu和角色关联关系"
123 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
124 | // @Router /menu/addMenuAuthority [post]
125 | func GetMenuAuthority(c *gin.Context) {
126 | var authorityIdInfo AuthorityIdInfo
127 | _ = c.BindJSON(&authorityIdInfo)
128 | err, menus := new(sysModel.SysMenu).GetMenuAuthority(authorityIdInfo.AuthorityId)
129 | if err != nil {
130 | servers.ReportFormat(c, false, fmt.Sprintf("获取失败:%v", err), gin.H{"menus": menus})
131 | } else {
132 | servers.ReportFormat(c, true, "获取成功", gin.H{"menus": menus})
133 | }
134 | }
135 |
136 | type IdInfo struct {
137 | Id float64
138 | }
139 |
140 | // @Tags menu
141 | // @Summary 删除菜单
142 | // @Security ApiKeyAuth
143 | // @accept application/json
144 | // @Produce application/json
145 | // @Param data body api.IdInfo true "删除菜单"
146 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
147 | // @Router /menu/deleteBaseMenu [post]
148 | func DeleteBaseMenu(c *gin.Context) {
149 | var idInfo IdInfo
150 | _ = c.BindJSON(&idInfo)
151 | err := new(sysModel.SysBaseMenu).DeleteBaseMenu(idInfo.Id)
152 | if err != nil {
153 | servers.ReportFormat(c, false, fmt.Sprintf("删除失败:%v", err), gin.H{})
154 | } else {
155 | servers.ReportFormat(c, true, "删除成功", gin.H{})
156 | }
157 | }
158 |
159 | // @Tags menu
160 | // @Summary 更新菜单
161 | // @Security ApiKeyAuth
162 | // @accept application/json
163 | // @Produce application/json
164 | // @Param data body sysModel.SysBaseMenu true "更新菜单"
165 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
166 | // @Router /menu/updataBaseMen [post]
167 | func UpdataBaseMenu(c *gin.Context) {
168 | var menu sysModel.SysBaseMenu
169 | _ = c.BindJSON(&menu)
170 | err := menu.UpdataBaseMenu()
171 | if err != nil {
172 | servers.ReportFormat(c, false, fmt.Sprintf("修改失败:%v", err), gin.H{})
173 | } else {
174 | servers.ReportFormat(c, true, "修改成功", gin.H{})
175 | }
176 | }
177 |
178 | type GetById struct {
179 | Id float64 `json:"id"`
180 | }
181 |
182 | // @Tags menu
183 | // @Summary 根据id获取菜单
184 | // @Security ApiKeyAuth
185 | // @accept application/json
186 | // @Produce application/json
187 | // @Param data body api.GetById true "根据id获取菜单"
188 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
189 | // @Router /menu/getBaseMenuById [post]
190 | func GetBaseMenuById(c *gin.Context) {
191 | var idInfo GetById
192 | _ = c.BindJSON(&idInfo)
193 | err, menu := new(sysModel.SysBaseMenu).GetBaseMenuById(idInfo.Id)
194 | if err != nil {
195 | servers.ReportFormat(c, false, fmt.Sprintf("查询失败:%v", err), gin.H{})
196 | } else {
197 | servers.ReportFormat(c, true, "查询成功", gin.H{"menu": menu})
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/example/form/form.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | ——
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | 立即创建
76 | 取消
77 |
78 |
79 |
80 |
81 |
132 |
133 |
134 |
135 |
188 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/superAdmin/menu/menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 新增根菜单
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {{scope.row.hidden?"隐藏":"显示"}}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | {{scope.row.meta.title}}
22 |
23 |
24 |
25 |
26 | {{scope.row.meta.icon}}
27 |
28 |
29 |
30 |
31 | 删除菜单
32 | 编辑菜单
33 | 添加子菜单
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
69 |
70 |
71 |
72 |
73 |
212 |
--------------------------------------------------------------------------------
/QMPlusVuePage/src/view/superAdmin/api/api.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 查询
11 |
12 |
13 | 新增api
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | {{scope.row.method|methodFiletr}}
26 |
27 |
28 |
29 |
30 |
31 |
32 | 编辑
33 | 删除
34 |
35 |
36 |
37 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
74 |
75 |
76 |
77 |
78 |
79 |
229 |
--------------------------------------------------------------------------------