feat separate order creation and contract menus

This commit is contained in:
david
2026-07-29 15:09:54 +08:00
parent 0af4e92c5e
commit 0c94c8033a
5 changed files with 40 additions and 8 deletions

View File

@@ -42,6 +42,7 @@ var PlatformMenus = [][]Menu{
{Identity: "user_account", ParentIdentity: "user", GroupCode: "user", Name: "用户账户", Path: "/user/user-account", SortNo: 1, Status: common.StatusEnable},
{Identity: "user_address", ParentIdentity: "user", GroupCode: "user", Name: "用户地址", Path: "/user/user-address", SortNo: 2, Status: common.StatusEnable},
{Identity: "user_service_relation", ParentIdentity: "user", GroupCode: "user", Name: "服务关系", Path: "/user/service-relation", SortNo: 3, Status: common.StatusEnable},
{Identity: "gasorder_contract", ParentIdentity: "user", GroupCode: "user", Name: "合同管理", Path: "/user/contracts", SortNo: 4, Status: common.StatusEnable},
},
{
{Identity: "device", GroupCode: "device", Name: "智能气阀管理", Icon: "icon-common", Path: "/product", SortNo: 60, Status: common.StatusEnable},
@@ -51,7 +52,7 @@ var PlatformMenus = [][]Menu{
},
{
{Identity: "gasorder", GroupCode: "gasorder", Name: "气体配送订单管理", Icon: "icon-list", Path: "/gasorder", SortNo: 70, Status: common.StatusEnable},
{Identity: "gasorder_contract", ParentIdentity: "gasorder", GroupCode: "gasorder", Name: "合同管理", Path: "/gasorder/contracts", SortNo: 1, Status: common.StatusEnable},
{Identity: "gasorder_create", ParentIdentity: "gasorder", GroupCode: "gasorder", Name: "创建订单", Path: "/gasorder/create", SortNo: 1, Status: common.StatusEnable},
{Identity: "gasorder_basic", ParentIdentity: "gasorder", GroupCode: "gasorder", Name: "配送订单", Path: "/gasorder/orders", SortNo: 2, Status: common.StatusEnable},
{Identity: "gasorder_track", ParentIdentity: "gasorder", GroupCode: "gasorder", Name: "运行轨迹", Path: "/gasorder/tracks", SortNo: 3, Status: common.StatusEnable},
},

View File

@@ -12,6 +12,10 @@ import (
const platformMenusContextKey = "platform_authorized_menus"
func platformMenuAllowsPath(menus []platformbase.Menu, requestPath string) bool {
return platformMenuAllowsRequest(menus, requestPath, "GET")
}
func platformMenuAllowsRequest(menus []platformbase.Menu, requestPath, method string) bool {
marker := "/platform/v1/"
index := strings.Index(requestPath, marker)
if index < 0 {
@@ -20,10 +24,17 @@ func platformMenuAllowsPath(menus []platformbase.Menu, requestPath string) bool
relative := strings.Trim(requestPath[index+len(marker):], "/")
resource := strings.Split(relative, "/")[0]
menuIdentity := platformRouteMenuIdentity(resource)
if resource == "gasorder_basic" && method == "POST" {
menuIdentity = "gasorder_create"
}
for _, menu := range menus {
if menu.Identity == menuIdentity {
return true
}
if method == "GET" && menu.Identity == "gasorder_create" &&
(menuIdentity == "gasorder_contract" || resource == "user_address") {
return true
}
}
return false
}
@@ -75,7 +86,7 @@ func RequirePlatformMenuAccess() gin.HandlerFunc {
return
}
menus, err := platformbase.LoadPlatformMenus(claims.Role)
if err != nil || !platformMenuAllowsPath(menus, ctx.Request.URL.Path) {
if err != nil || !platformMenuAllowsRequest(menus, ctx.Request.URL.Path, ctx.Request.Method) {
infra.Response.Error(ctx, errcode.ErrPermissionDenied)
ctx.Abort()
return

View File

@@ -32,6 +32,20 @@ func TestHiddenGasorderResourcesFollowOwningSecondLevelMenu(t *testing.T) {
}
}
func TestCreateOrderPermissionIsSeparateFromOrderManagement(t *testing.T) {
createMenus := []platformbase.Menu{{Identity: "gasorder_create"}}
if !platformMenuAllowsRequest(createMenus, "/heqi/platform/v1/gasorder_basic", "POST") {
t.Fatal("create-order menu did not grant order creation")
}
if platformMenuAllowsRequest(createMenus, "/heqi/platform/v1/gasorder_basic", "GET") {
t.Fatal("create-order menu granted order list access")
}
orderMenus := []platformbase.Menu{{Identity: "gasorder_basic"}}
if platformMenuAllowsRequest(orderMenus, "/heqi/platform/v1/gasorder_basic", "POST") {
t.Fatal("order-management menu granted order creation")
}
}
func TestLocationScopeValuesAreExplicit(t *testing.T) {
if !validLocationScope("standard") || !validLocationScope("precise") {
t.Fatal("supported location scopes were rejected")

View File

@@ -76,6 +76,9 @@ const routes: AppRouteRecordRaw[] = [
child('user', 'user-account', 'account', '用户账户', '/user_account', 'user_account'),
child('user', 'user-address', 'address', '用户地址', '/user_address', 'user_address'),
child('user', 'service-relation', 'service-relation', '服务关系', '/user_service_relation', 'user_service_relation'),
child('user', 'contracts', 'contracts', '合同管理', '/gasorder_contract', 'gasorder_contract'),
child('user', 'contract-products', 'contract-products', '合同气瓶', '/gasorder_contract_product', 'gasorder_contract', true, 'user-contracts'),
child('user', 'contract-revisions', 'contract-revisions', '合同修订记录', '/gasorder_contract_revision', 'gasorder_contract', true, 'user-contracts'),
]),
group('product', 'product', '智能气阀管理', 'icon-common', 50, [
child('product', 'product-type', 'type', '类型管理', '/product_type', 'product_type'),
@@ -85,9 +88,7 @@ const routes: AppRouteRecordRaw[] = [
child('product', 'owner', 'owner', '智能气阀归属记录', '/product_owner', 'product_info', true, 'product-info'),
], 'device'),
group('gasorder', 'gasorder', '气体配送订单管理', 'icon-list', 60, [
child('gasorder', 'contracts', 'contracts', '合同管理', '/gasorder_contract', 'gasorder_contract'),
child('gasorder', 'contract-products', 'contract-products', '合同气瓶', '/gasorder_contract_product', 'gasorder_contract', true, 'gasorder-contracts'),
child('gasorder', 'contract-revisions', 'contract-revisions', '合同修订记录', '/gasorder_contract_revision', 'gasorder_contract', true, 'gasorder-contracts'),
{ ...child('gasorder', 'create', 'create', '创建订单', '/gasorder_basic', 'gasorder_create'), meta: { title: '创建订单', resource: '/gasorder_basic', requiresAuth: true, menuCode: 'gasorder_create', createMode: true } },
child('gasorder', 'orders', 'orders', '配送订单', '/gasorder_basic', 'gasorder_basic'),
child('gasorder', 'order-items', 'order-items', '订单明细', '/gasorder_item', 'gasorder_basic', true, 'gasorder-orders'),
child('gasorder', 'assignments', 'assignments', '分配记录', '/gasorder_assign', 'gasorder_basic', true, 'gasorder-orders'),

View File

@@ -524,8 +524,13 @@ async function save() {
);
else await resourceApi.create(props.definition.resource, payload);
Message.success('保存成功');
formVisible.value = false;
await load();
if (route.meta.createMode && !editingIdentity.value) {
resetForm();
formVisible.value = true;
} else {
formVisible.value = false;
await load();
}
} catch (error) {
Message.error((error as Error).message);
} finally {
@@ -699,7 +704,7 @@ function searchRelation(resource: string | undefined, keyword: string) {
}
onMounted(async () => {
await load();
if (!route.meta.createMode) await load();
const actionFields = props.definition.detailActions?.flatMap((item) => item.fields ?? []) ?? [];
const relationPaths = new Set(
[...props.definition.fields, ...actionFields]