398 lines
11 KiB
Go
398 lines
11 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"git.5iot.com/iotlcm-public/iotlcm-app/internal/consts"
|
|
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/contexts"
|
|
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/mcache"
|
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
)
|
|
|
|
type appFeatureAccessRule struct {
|
|
Feature string
|
|
Permissions []string
|
|
Routes []string
|
|
}
|
|
|
|
// appFeatureAccessRules maps mini-program business features to existing console
|
|
// menu permissions in sys_menu.perms. It deliberately avoids role names so the
|
|
// app follows the same role-menu binding model as the admin console.
|
|
var appFeatureAccessRules = []appFeatureAccessRule{
|
|
{
|
|
Feature: "card:list",
|
|
Permissions: []string{"cpa:terminal:user", "cpm:iot:tSimCardInfo:list"},
|
|
Routes: []string{"/pages/card/index"},
|
|
},
|
|
{
|
|
Feature: "card:detail",
|
|
Permissions: []string{"cpm:iot:tSimCardInfo:view", "cpm:iot:tSimCardInfo:list"},
|
|
Routes: []string{"/pages/card/views/detail/index"},
|
|
},
|
|
{
|
|
Feature: "package:view",
|
|
Permissions: []string{
|
|
"cpm:iot:tSimCardBindPkg:list",
|
|
"cpm:iot:tSimFlowPackageInfo:list",
|
|
"cpm:iot:tSimFlowPackageInfo:view",
|
|
"cpm:iot:tSimCardBindPkg:getPkgInfo",
|
|
},
|
|
Routes: []string{"/pages/card/views/packageDetail/index"},
|
|
},
|
|
{
|
|
Feature: "card:bind",
|
|
Permissions: []string{consts.SysCheckPermissionCurrentUser},
|
|
},
|
|
{
|
|
Feature: "card:renew",
|
|
Permissions: []string{"cpm:iot:tSimCardRenew:batch:confirm"},
|
|
Routes: []string{
|
|
"/pages/business/views/renew/index",
|
|
"/pages/business/views/cardRenew/index",
|
|
},
|
|
},
|
|
{
|
|
Feature: "card:renew:submit",
|
|
Permissions: []string{"cpm:iot:tSimCardRenew:batch:confirm"},
|
|
},
|
|
{
|
|
Feature: "card:addon",
|
|
Permissions: []string{
|
|
"cpm:iot:tSimCardBindPkg:list",
|
|
"cpm:iot:tSimFlowPackageInfo:view",
|
|
"cpm:iot:tSimCardBindPkg:getPkgInfo",
|
|
},
|
|
Routes: []string{"/pages/business/views/addon/index"},
|
|
},
|
|
{
|
|
Feature: "card:change",
|
|
Permissions: []string{"cpm:iot:tSimCardChange:batch:submit"},
|
|
Routes: []string{"/pages/business/views/change/index"},
|
|
},
|
|
{
|
|
Feature: "card:change:submit",
|
|
Permissions: []string{"cpm:iot:tSimCardChange:batch:submit"},
|
|
},
|
|
{
|
|
Feature: "card:allocate",
|
|
Permissions: []string{
|
|
"cpm:iot:tSimCardAllocate:targets&cpm:iot:tSimCardAllocate:input:prepare&cpm:iot:tSimCardAllocate:batch:submit",
|
|
},
|
|
Routes: []string{"/pages/business/views/allocate/index"},
|
|
},
|
|
{
|
|
Feature: "card:stop",
|
|
Permissions: []string{"cpm:iot:tSimCardStop:input:submit"},
|
|
},
|
|
{
|
|
Feature: "card:start",
|
|
Permissions: []string{"cpm:iot:tSimCardStart:input:submit"},
|
|
},
|
|
{
|
|
Feature: "card:restart",
|
|
Permissions: []string{"cpm:iot:tSimCardRestart:input:submit"},
|
|
},
|
|
{
|
|
Feature: "card:dataStart",
|
|
Permissions: []string{"cpm:iot:tSimCardDataStart:input:submit"},
|
|
},
|
|
{
|
|
Feature: "card:dataStop",
|
|
Permissions: []string{"cpm:iot:tSimCardDataStop:input:submit"},
|
|
},
|
|
{
|
|
Feature: "card:diagnosis",
|
|
Permissions: []string{
|
|
"cpm:iot:tSimdiagnose:info",
|
|
"cpm:iot:tSimdiagnose:flow",
|
|
"cpm:iot:tSimCardInfo:querySimSession",
|
|
"cpm:iot:tSimCardInfo:querySimStatus",
|
|
},
|
|
Routes: []string{"/pages/business/views/diagnosis/index"},
|
|
},
|
|
{
|
|
Feature: "warn:view",
|
|
Permissions: []string{
|
|
"cpm:iot:simWarningConfig:list",
|
|
"cpm:iot:simWarningConfig:view",
|
|
"cpm:iot:simWarningConfig:save",
|
|
"cpm:iot:tSimWarningConfig:input:submit",
|
|
"cpm:iot:tSimWarningConfig:range:submit",
|
|
"cpm:iot:tSimWarningConfig:excel:submit",
|
|
},
|
|
Routes: []string{"/pages/business/views/warning/index"},
|
|
},
|
|
{
|
|
Feature: "order:list",
|
|
Permissions: []string{
|
|
"cpm:common:tBalanceDetail:list",
|
|
"cpm:common:tFinanceApply:list",
|
|
"cpm:gen:tFinanceApply:list",
|
|
},
|
|
Routes: []string{"/pages/business/views/order/index"},
|
|
},
|
|
{
|
|
Feature: "order:detail",
|
|
Permissions: []string{
|
|
"cpm:common:tBalanceDetail:view",
|
|
"cpm:common:tBalanceDetail:list",
|
|
"cpm:common:tFinanceApply:view",
|
|
"cpm:common:tFinanceApply:list",
|
|
"cpm:gen:tFinanceApply:list",
|
|
},
|
|
},
|
|
{
|
|
Feature: "customer:list",
|
|
Permissions: []string{"cpm:agent:dept:list", "cpm:agent:tAgentEnterprise:list"},
|
|
Routes: []string{"/pages/business/views/customer/index"},
|
|
},
|
|
{
|
|
Feature: "customer:detail",
|
|
Permissions: []string{"cpm:agent:tAgentEnterprise:view", "cpm:agent:tAgentEnterprise:list"},
|
|
Routes: []string{"/pages/business/views/customerDetail/index"},
|
|
},
|
|
{
|
|
Feature: "message:view",
|
|
Permissions: []string{consts.SysCheckPermissionCurrentUser, "cpm:system:notice:list"},
|
|
Routes: []string{"/pages/message/index", "/pages/message/views/cardDetail/index", "/pages/message/views/systemDetail/index"},
|
|
},
|
|
{Feature: "workorder:reply", Permissions: []string{"cpm:gen:tWoCommunication:message"}},
|
|
{Feature: "workorder:resolve", Permissions: []string{"cpm:gen:tWoMain:resolve"}},
|
|
{Feature: "workorder:transfer", Permissions: []string{"cpm:gen:tWoMain:transfer"}},
|
|
{Feature: "workorder:close", Permissions: []string{"cpm:gen:tWoMain:close"}},
|
|
{
|
|
Feature: "workorder:list",
|
|
Permissions: []string{"cpm:gen:tWoMain:list"},
|
|
Routes: []string{"/pages/business/views/workOrder/index"},
|
|
},
|
|
{
|
|
Feature: "workorder:create",
|
|
Permissions: []string{"cpm:gen:tWoMain:edit"},
|
|
Routes: []string{"/pages/business/views/workOrder/index", "/pages/business/views/workOrderCreate/index"},
|
|
},
|
|
{
|
|
Feature: "workorder:detail",
|
|
Permissions: []string{"cpm:gen:tWoMain:view", "cpm:gen:tWoMain:list"},
|
|
Routes: []string{"/pages/business/views/workOrderDetail/index"},
|
|
},
|
|
}
|
|
|
|
func appEnsureFeatureAccess(ctx context.Context, feature string) error {
|
|
feature = strings.TrimSpace(feature)
|
|
if feature == "" {
|
|
return nil
|
|
}
|
|
configured, err := appAccessConfigured(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !configured || contexts.IsSuperAdmin(ctx) {
|
|
return nil
|
|
}
|
|
userId := contexts.GetUserId(ctx)
|
|
if userId == 0 {
|
|
return gerror.New("登录已过期")
|
|
}
|
|
requiredCodes := appFeaturePermissionCandidates(feature)
|
|
if len(requiredCodes) == 0 {
|
|
return nil
|
|
}
|
|
accessCodes, _, err := mcache.GetUserAccessCodeList(ctx, userId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, requiredCode := range requiredCodes {
|
|
if appAccessCodesMatchExpression(accessCodes, requiredCode) {
|
|
return nil
|
|
}
|
|
}
|
|
return gerror.New("暂无操作权限")
|
|
}
|
|
|
|
func appAccessCodesMatchExpression(accessCodes []string, expression string) bool {
|
|
parts := appPermissionExpressionParts(expression)
|
|
if len(parts) == 0 {
|
|
return false
|
|
}
|
|
for _, part := range parts {
|
|
matched := false
|
|
for _, accessCode := range accessCodes {
|
|
if appMatchAccessCode(accessCode, part) {
|
|
matched = true
|
|
break
|
|
}
|
|
}
|
|
if !matched {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func appMatchAccessCode(pattern string, code string) bool {
|
|
pattern = appNormalizePermissionCode(pattern)
|
|
code = appNormalizePermissionCode(code)
|
|
if pattern == "" || code == "" {
|
|
return false
|
|
}
|
|
if pattern == code || pattern == "*" || pattern == "cpm:*" {
|
|
return true
|
|
}
|
|
if strings.HasSuffix(pattern, "*") {
|
|
return strings.HasPrefix(code, pattern[:len(pattern)-1])
|
|
}
|
|
return false
|
|
}
|
|
|
|
func appFeaturePermissionCandidates(feature string) []string {
|
|
feature = appNormalizeFeatureKey(feature)
|
|
if feature == "" {
|
|
return nil
|
|
}
|
|
if feature == "*" {
|
|
return []string{"*"}
|
|
}
|
|
codes := make([]string, 0)
|
|
for _, rule := range appFeatureAccessRules {
|
|
if rule.Feature != feature {
|
|
continue
|
|
}
|
|
for _, permission := range rule.Permissions {
|
|
codes = appendUniqueString(codes, appNormalizePermissionExpression(permission))
|
|
}
|
|
}
|
|
if len(codes) == 0 && strings.HasPrefix(feature, consts.SysCheckPermissionPrefix) {
|
|
codes = appendUniqueString(codes, appNormalizePermissionCode(feature))
|
|
}
|
|
return codes
|
|
}
|
|
|
|
func appFeaturesByPermission(permission string) []string {
|
|
permission = appNormalizePermissionCode(permission)
|
|
if permission == "" {
|
|
return nil
|
|
}
|
|
features := make([]string, 0)
|
|
for _, rule := range appFeatureAccessRules {
|
|
for _, rulePermission := range rule.Permissions {
|
|
if strings.Contains(rulePermission, "&") {
|
|
continue
|
|
}
|
|
if appMatchAccessCode(permission, rulePermission) || appMatchAccessCode(rulePermission, permission) {
|
|
features = appendUniqueString(features, rule.Feature)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return features
|
|
}
|
|
|
|
func appRoutesByFeature(feature string) []string {
|
|
feature = appNormalizeFeatureKey(feature)
|
|
routes := make([]string, 0)
|
|
for _, rule := range appFeatureAccessRules {
|
|
if rule.Feature != feature {
|
|
continue
|
|
}
|
|
for _, route := range rule.Routes {
|
|
routes = appendUniqueString(routes, route)
|
|
}
|
|
}
|
|
return routes
|
|
}
|
|
|
|
func appKnownPermissionCodes() []string {
|
|
codes := make([]string, 0)
|
|
for _, rule := range appFeatureAccessRules {
|
|
for _, permission := range rule.Permissions {
|
|
for _, part := range appPermissionExpressionParts(permission) {
|
|
codes = appendUniqueString(codes, appNormalizePermissionCode(part))
|
|
}
|
|
}
|
|
}
|
|
return codes
|
|
}
|
|
|
|
func appAppendFeaturesByPermissionSet(accessPermissions []string, appendFeature func(string)) {
|
|
if len(accessPermissions) == 0 || appendFeature == nil {
|
|
return
|
|
}
|
|
for _, rule := range appFeatureAccessRules {
|
|
for _, permission := range rule.Permissions {
|
|
if appAccessCodesMatchExpression(accessPermissions, permission) {
|
|
appendFeature(rule.Feature)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func appMenuPermCandidates() []string {
|
|
values := make([]string, 0)
|
|
for _, permission := range appKnownPermissionCodes() {
|
|
if permission == "" || permission == consts.SysCheckPermissionCurrentUser {
|
|
continue
|
|
}
|
|
values = appendUniqueString(values, permission)
|
|
if strings.HasPrefix(permission, consts.SysCheckPermissionMenuPrefix) {
|
|
values = appendUniqueString(values, strings.TrimPrefix(permission, consts.SysCheckPermissionMenuPrefix))
|
|
}
|
|
}
|
|
return values
|
|
}
|
|
|
|
func appNormalizeFeatureKey(value string) string {
|
|
value = strings.TrimSpace(value)
|
|
if value == "" {
|
|
return ""
|
|
}
|
|
if value == "*" || value == "cpm:*" {
|
|
return "*"
|
|
}
|
|
return value
|
|
}
|
|
|
|
func appNormalizePermissionCode(value string) string {
|
|
value = strings.TrimSpace(value)
|
|
if value == "" {
|
|
return ""
|
|
}
|
|
for strings.HasPrefix(value, consts.SysCheckPermissionMenuPrefix+consts.SysCheckPermissionMenuPrefix) {
|
|
value = strings.TrimPrefix(value, consts.SysCheckPermissionMenuPrefix)
|
|
}
|
|
if value == "*" ||
|
|
value == consts.SysCheckPermissionCurrentUser ||
|
|
value == consts.SysCheckPermissionTerminalUser ||
|
|
strings.HasPrefix(value, consts.SysCheckPermissionMenuPrefix) ||
|
|
strings.HasPrefix(value, "cpa:") ||
|
|
strings.HasPrefix(value, consts.SysCheckPermissionRolePrefix) ||
|
|
strings.HasPrefix(value, consts.SysCheckPermissionDeptPrefix) ||
|
|
strings.HasPrefix(value, consts.SysCheckPermissionPostPrefix) ||
|
|
strings.HasPrefix(value, consts.SysCheckPermissionUserPrefix) {
|
|
return value
|
|
}
|
|
return consts.SysCheckPermissionMenuPrefix + value
|
|
}
|
|
|
|
func appNormalizePermissionExpression(value string) string {
|
|
parts := appPermissionExpressionParts(value)
|
|
if len(parts) == 0 {
|
|
return ""
|
|
}
|
|
return strings.Join(parts, "&")
|
|
}
|
|
|
|
func appPermissionExpressionParts(value string) []string {
|
|
rawParts := strings.Split(strings.TrimSpace(value), "&")
|
|
parts := make([]string, 0, len(rawParts))
|
|
for _, part := range rawParts {
|
|
part = appNormalizePermissionCode(part)
|
|
if part != "" {
|
|
parts = appendUniqueString(parts, part)
|
|
}
|
|
}
|
|
return parts
|
|
}
|