完成权限信息管理

dev
truthhun 2 years ago
parent 5906272775
commit 6ff5a0c0f7

@ -0,0 +1,74 @@
syntax = "proto3";
import "google/protobuf/timestamp.proto";
import "gogoproto/gogo.proto";
// import "validate/validate.proto";
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
package api.v1;
option go_package = "moredoc/api/v1;v1";
option java_multiple_files = true;
option java_package = "api.v1";
message Permission {
int64 id = 1;
string method = 2;
string path = 3;
string title = 4;
string description = 5;
google.protobuf.Timestamp created_at = 6 [ (gogoproto.stdtime) = true ];
google.protobuf.Timestamp updated_at = 7 [ (gogoproto.stdtime) = true ];
}
message DeletePermissionRequest { repeated int64 id = 1; }
message GetPermissionRequest { int64 id = 1; }
message GetPermissionReply { Permission permission = 1; }
message ListPermissionRequest {
int64 page = 1;
int64 size = 2;
string wd = 3;
repeated string method = 4;
string path = 5;
}
message ListPermissionReply {
int64 total = 1;
repeated Permission permission = 2;
}
// message PermissionTree {
// Permission permission = 1;
// repeated PermissionTree children = 2;
// }
service PermissionAPI {
rpc UpdatePermission(Permission) returns (google.protobuf.Empty) {
option (google.api.http) = {
put : '/api/v1/permission',
body : '*',
};
}
rpc GetPermission(GetPermissionRequest) returns (Permission) {
option (google.api.http) = {
get : '/api/v1/permission',
};
}
rpc ListPermission(ListPermissionRequest) returns (ListPermissionReply) {
option (google.api.http) = {
get : '/api/v1/permission/list',
};
}
// rpc ListPermissionTree(google.protobuf.Empty) returns (PermissionTree) {
// option (google.api.http) = {
// get : '/api/v1/permission/tree',
// };
// }
}

@ -0,0 +1,108 @@
package biz
import (
"context"
pb "moredoc/api/v1"
"moredoc/middleware/auth"
"moredoc/model"
"moredoc/util"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
)
type PermissionAPIService struct {
pb.UnimplementedPermissionAPIServer
dbModel *model.DBModel
logger *zap.Logger
}
func NewPermissionAPIService(dbModel *model.DBModel, logger *zap.Logger) (service *PermissionAPIService) {
return &PermissionAPIService{dbModel: dbModel, logger: logger.Named("PermissionAPIService")}
}
func (s *PermissionAPIService) checkPermission(ctx context.Context) (*auth.UserClaims, error) {
return checkGRPCPermission(s.dbModel, ctx)
}
// UpdatePermission 编辑权限信息。这里只能更新名称和描述,不能更新权限项。
func (s *PermissionAPIService) UpdatePermission(ctx context.Context, req *pb.Permission) (*emptypb.Empty, error) {
_, err := s.checkPermission(ctx)
if err != nil {
return nil, err
}
err = s.dbModel.UpdatePermission(&model.Permission{
Id: req.Id,
Title: req.Title,
Description: req.Description,
}, "title", "description")
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &emptypb.Empty{}, nil
}
// GetPermission 查询单个权限信息
func (s *PermissionAPIService) GetPermission(ctx context.Context, req *pb.GetPermissionRequest) (*pb.Permission, error) {
_, err := s.checkPermission(ctx)
if err != nil {
return nil, err
}
permission, err := s.dbModel.GetPermission(req.Id)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
pbPermission := &pb.Permission{}
util.CopyStruct(&permission, pbPermission)
return pbPermission, nil
}
// ListPermission 查询权限列表
func (s *PermissionAPIService) ListPermission(ctx context.Context, req *pb.ListPermissionRequest) (*pb.ListPermissionReply, error) {
_, err := s.checkPermission(ctx)
if err != nil {
return nil, err
}
opt := &model.OptionGetPermissionList{
Page: int(req.Page),
Size: int(req.Size_),
WithCount: true,
QueryLike: make(map[string][]interface{}),
QueryIn: make(map[string][]interface{}),
}
if req.Wd != "" {
opt.QueryLike["title"] = []interface{}{req.Wd}
opt.QueryLike["description"] = []interface{}{req.Wd}
}
if req.Path != "" {
opt.QueryLike["path"] = []interface{}{req.Path}
}
if len(req.Method) > 0 {
opt.QueryIn["method"] = util.Slice2Interface(req.Method)
}
permissions, total, err := s.dbModel.GetPermissionList(opt)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
var pbPermissions []*pb.Permission
util.CopyStruct(&permissions, &pbPermissions)
return &pb.ListPermissionReply{
Total: total,
Permission: pbPermissions,
}, nil
}

@ -1,8 +1,6 @@
package model
import (
"fmt"
"strings"
"time"
"go.uber.org/zap"
@ -23,17 +21,6 @@ func (Permission) TableName() string {
return tablePrefix + "permission"
}
// 这里是proto文件中的结构体可以根据需要删除或者调整
//message Permission {
// int64 id = 1;
// string category = 2;
// string title = 3;
// string description = 4;
// string identifier = 5;
// = 0;
// = 0;
//}
// CreatePermission 创建Permission
func (m *DBModel) CreatePermission(permission *Permission) (err error) {
err = m.db.Create(permission).Error
@ -86,7 +73,7 @@ func (m *DBModel) GetPermissionByMethodPath(method, path string, createIfNotExis
if method != "" {
db = db.Where("method = ?", method)
} else {
db = db.Where("method IS NULL or method = ''")
db = db.Where("method IS NULL or method = '' or method = 'GRPC'")
}
err = db.First(&permission).Error
@ -100,6 +87,9 @@ func (m *DBModel) GetPermissionByMethodPath(method, path string, createIfNotExis
}
if createIfNotExist {
if method == "" {
method = "GRPC"
}
permission.Method = method
permission.Path = path
err = m.CreatePermission(&permission)
@ -175,51 +165,19 @@ func (m *DBModel) CheckPermissionByGroupId(groupId []int64, method, path string)
type OptionGetPermissionList struct {
Page int
Size int
WithCount bool // 是否返回总数
Ids []interface{} // id列表
SelectFields []string // 查询字段
QueryRange map[string][2]interface{} // map[field][]{min,max}
QueryIn map[string][]interface{} // map[field][]{value1,value2,...}
QueryLike map[string][]interface{} // map[field][]{value1,value2,...}
Sort []string
WithCount bool // 是否返回总数
SelectFields []string // 查询字段
QueryIn map[string][]interface{} // map[field][]{value1,value2,...}
QueryLike map[string][]interface{} // map[field][]{value1,value2,...}
}
// GetPermissionList 获取Permission列表
func (m *DBModel) GetPermissionList(opt OptionGetPermissionList) (permissionList []Permission, total int64, err error) {
func (m *DBModel) GetPermissionList(opt *OptionGetPermissionList) (permissionList []Permission, total int64, err error) {
db := m.db.Model(&Permission{})
tableName := Permission{}.TableName()
for field, rangeValue := range opt.QueryRange {
fields := m.FilterValidFields(Permission{}.TableName(), field)
if len(fields) == 0 {
continue
}
if rangeValue[0] != nil {
db = db.Where(fmt.Sprintf("%s >= ?", field), rangeValue[0])
}
if rangeValue[1] != nil {
db = db.Where(fmt.Sprintf("%s <= ?", field), rangeValue[1])
}
}
for field, values := range opt.QueryIn {
fields := m.FilterValidFields(Permission{}.TableName(), field)
if len(fields) == 0 {
continue
}
db = db.Where(fmt.Sprintf("%s in (?)", field), values)
}
for field, values := range opt.QueryLike {
fields := m.FilterValidFields(Permission{}.TableName(), field)
if len(fields) == 0 {
continue
}
db = db.Where(strings.TrimSuffix(fmt.Sprintf(strings.Join(make([]string, len(values)+1), "%s like ? or"), field), "or"), values...)
}
if len(opt.Ids) > 0 {
db = db.Where("id in (?)", opt.Ids)
}
db = m.generateQueryIn(db, tableName, opt.QueryIn)
db = m.generateQueryLike(db, tableName, opt.QueryLike)
if opt.WithCount {
err = db.Count(&total).Error
@ -229,31 +187,12 @@ func (m *DBModel) GetPermissionList(opt OptionGetPermissionList) (permissionList
}
}
opt.SelectFields = m.FilterValidFields(Permission{}.TableName(), opt.SelectFields...)
opt.SelectFields = m.FilterValidFields(tableName, opt.SelectFields...)
if len(opt.SelectFields) > 0 {
db = db.Select(opt.SelectFields)
}
if len(opt.Sort) > 0 {
var sorts []string
for _, sort := range opt.Sort {
slice := strings.Split(sort, " ")
if len(m.FilterValidFields(Permission{}.TableName(), slice[0])) == 0 {
continue
}
if len(slice) == 2 {
sorts = append(sorts, fmt.Sprintf("%s %s", slice[0], slice[1]))
} else {
sorts = append(sorts, fmt.Sprintf("%s desc", slice[0]))
}
}
if len(sorts) > 0 {
db = db.Order(strings.Join(sorts, ","))
}
}
db = db.Offset((opt.Page - 1) * opt.Size).Limit(opt.Size)
db = db.Order("path asc").Offset((opt.Page - 1) * opt.Size).Limit(opt.Size)
err = db.Find(&permissionList).Error
if err != nil && err != gorm.ErrRecordNotFound {

@ -59,5 +59,14 @@ func RegisterGRPCService(dbModel *model.DBModel, logger *zap.Logger, endpoint st
return
}
// 权限API接口服务
permissionAPIService := biz.NewPermissionAPIService(dbModel, logger)
v1.RegisterPermissionAPIServer(grpcServer, permissionAPIService)
err = v1.RegisterPermissionAPIHandlerFromEndpoint(context.Background(), gwmux, endpoint, dialOpts)
if err != nil {
logger.Error("RegisterPermissionAPIHandlerFromEndpoint", zap.Error(err))
return
}
return
}

@ -0,0 +1,27 @@
import service from '~/utils/request'
export const updatePermission = (data) => {
return service({
url: '/api/v1/permission',
method: 'put',
data,
})
}
export const getPermission = (params) => {
return service({
url: '/api/v1/permission',
method: 'get',
params,
})
}
export const listPermission = (params) => {
return service({
url: '/api/v1/permission/list',
method: 'get',
params,
})
}

@ -0,0 +1,121 @@
<template>
<div class="com-form-permission">
<el-form
ref="formPermission"
label-position="top"
label-width="80px"
:model="permission"
>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="Method" prop="method">
<el-input v-model="permission.method" :disabled="true"></el-input>
</el-form-item>
</el-col>
<el-col :span="18">
<el-form-item label="API" prop="path">
<el-input v-model="permission.path" :disabled="true"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-form-item
label="名称"
prop="title"
:rules="[
{ required: true, trigger: 'blur', message: '请输入权限名称' },
]"
>
<el-input
v-model="permission.title"
placeholder="请输入权限名称"
clearable
></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input
v-model="permission.description"
type="textarea"
rows="5"
placeholder="请输入权限相关描述或备注"
></el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
class="btn-block"
icon="el-icon-check"
:loading="loading"
@click="onSubmit"
>提交</el-button
>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { updatePermission } from '~/api/permission'
export default {
name: 'FormPermission',
props: {
initPermission: {
type: Object,
default: () => {
return {}
},
},
},
data() {
return {
loading: false,
permission: {
id: 0,
title: '',
description: '',
},
}
},
watch: {
initPermission: {
handler(val) {
this.permission = val
},
immediate: true,
},
},
created() {
this.permission = this.initPermission
},
methods: {
onSubmit() {
this.$refs.formPermission.validate(async (valid) => {
if (!valid) {
return
}
this.loading = true
const permission = { ...this.permission }
if (this.permission.id > 0) {
const res = await updatePermission(permission)
if (res.status === 200) {
this.$message.success('修改成功')
this.resetFields()
this.$emit('success', res.data)
} else {
this.$message.error(res.data.message)
}
}
this.loading = false
})
},
clearValidate() {
this.$refs.formPermission.clearValidate()
},
resetFields() {
this.$refs.formPermission.resetFields()
},
reset() {
this.resetFields()
this.clearValidate()
},
},
}
</script>

@ -44,14 +44,16 @@
<span v-else-if="item.type === 'bytes'">
{{ formatBytes(scope.row[item.prop]) }}
</span>
<!-- 枚举 -->
<!-- 枚举键为数字 -->
<span v-else-if="item.type === 'enum'">
<el-tag
:type="item.enum[scope.row[item.prop] || 0].type"
v-if="item.enum[scope.row[item.prop] || 0]"
:type="item.enum[scope.row[item.prop] || 0].type || 'info'"
:effect="item.enum[scope.row[item.prop] || 0].effect || 'dark'"
>
{{ item.enum[scope.row[item.prop] || 0].label }}
</el-tag>
<span v-else>-</span>
</span>
<span v-else-if="item.type === 'datetime'">
{{ formatDatetime(scope.row[item.prop]) || '0000-00-00 00:00:00' }}

@ -1,10 +1,183 @@
<template>
<div>{{ $route.name }}</div>
<div>
<el-card shadow="never" class="search-card">
<FormSearch
:fields="searchFormFields"
:loading="loading"
:show-create="false"
:show-delete="false"
:disabled-delete="selectedRow.length === 0"
@onSearch="onSearch"
/>
</el-card>
<el-card shadow="never" class="mgt-20px">
<TableList
:table-data="listData"
:fields="tableListFields"
:show-actions="true"
:show-view="false"
:show-edit="true"
:show-delete="false"
:show-select="false"
:actions-min-width="'70px'"
@editRow="editRow"
/>
</el-card>
<el-card shadow="never" class="mgt-20px">
<div class="text-right">
<el-pagination
background
:current-page="search.page"
:page-sizes="[10, 20, 50, 100]"
:page-size="search.size"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handlePageChange"
>
</el-pagination>
</div>
</el-card>
<el-dialog title="编辑附件" width="640px" :visible.sync="formVisible">
<FormPermission :init-permission="permission" @success="formSuccess" />
</el-dialog>
</div>
</template>
<script>
import { listPermission, getPermission } from '~/api/permission'
import TableList from '~/components/TableList.vue'
import FormSearch from '~/components/FormSearch.vue'
import FormPermission from '~/components/FormPermission.vue'
import { methodOptions } from '~/utils/enum'
export default {
components: { TableList, FormSearch, FormPermission },
layout: 'admin',
created() {},
data() {
return {
loading: false,
formVisible: false,
search: {
wd: '',
page: 1,
size: 10,
},
listData: [],
total: 0,
searchFormFields: [],
tableListFields: [],
selectedRow: [],
permission: {},
methodOptions,
}
},
async created() {
this.initSearchForm()
this.initTableListFields()
await this.listPermission()
},
methods: {
async listPermission() {
this.loading = true
const res = await listPermission(this.search)
if (res.status === 200) {
this.listData = res.data.permission
this.total = res.data.total
} else {
this.$message.error(res.data.message)
}
this.loading = false
},
handleSizeChange(val) {
this.search.size = val
this.listPermission()
},
handlePageChange(val) {
this.search.page = val
this.listPermission()
},
onSearch(search) {
this.search = { ...this.search, page: 1, ...search }
this.listPermission()
},
async editRow(row) {
const res = await getPermission({ id: row.id })
if (res.status === 200) {
this.permission = res.data
this.formVisible = true
} else {
this.$message.error(res.data.message)
}
},
formSuccess() {
this.formVisible = false
this.listPermission()
},
initSearchForm() {
this.searchFormFields = [
{
type: 'text',
label: '关键字',
name: 'wd',
placeholder: '请输入关键字',
},
{
type: 'text',
label: 'API',
name: 'path',
placeholder: '请输入API',
},
{
type: 'select',
label: 'Method',
name: 'method',
placeholder: '请选择Method',
multiple: true,
options: this.methodOptions,
},
]
},
initTableListFields() {
const methodEnum = {
GET: {
label: 'GET',
type: 'info',
},
POST: {
label: 'POST',
type: 'success',
},
GRPC: {
label: 'GRPC',
type: 'primary',
},
PUT: {
label: 'PUT',
type: 'warning',
},
DELETE: {
label: 'DELETE',
type: 'danger',
},
}
this.tableListFields = [
// { prop: 'id', label: 'ID', width: 80, type: 'number', fixed: 'left' },
{ prop: 'title', label: '名称', width: 240, fixed: 'left' },
{ prop: 'description', label: '描述', minWidth: 150 },
{
prop: 'method',
label: 'Method',
width: 80,
type: 'enum',
enum: methodEnum,
},
{ prop: 'path', label: 'API', minWidth: 150 },
{ prop: 'created_at', label: '创建时间', width: 160, type: 'datetime' },
{ prop: 'updated_at', label: '更新时间', width: 160, type: 'datetime' },
]
},
},
}
</script>
<style></style>

@ -21,3 +21,31 @@ export const bannerTypeOptions = [
{ label: '小程序横幅', value: 1, type: 'success' },
{ label: 'APP横幅', value: 2, type: 'warning' },
]
export const methodOptions = [
{
label: 'GET',
value: 'GET',
type: 'success',
},
{
label: 'POST',
value: 'POST',
type: 'primary',
},
{
label: 'PUT',
value: 'PUT',
type: 'warning',
},
{
label: 'DELETE',
value: 'DELETE',
type: 'danger',
},
{
label: 'GRPC',
value: 'GRPC',
type: 'primary',
},
]

Loading…
Cancel
Save