Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80f05e481b | ||
|
|
6ff5322353 |
@@ -7,7 +7,7 @@
|
||||
},
|
||||
"server": {
|
||||
"file": "server-v1.openapi.json",
|
||||
"sha256": "19961572fad04f8545a4f607d4bf7276de64a84b266daecbb21d74e0975f97ef"
|
||||
"sha256": "1edfd78405cfe2a50022afe70a4c4f32caa4e98e3b5b54b40841d532058f2fd6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,6 @@
|
||||
"map_extent": {
|
||||
"anyOf": [
|
||||
{
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
@@ -152,7 +151,6 @@
|
||||
"map_extent": {
|
||||
"anyOf": [
|
||||
{
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
@@ -234,7 +232,6 @@
|
||||
"map_extent": {
|
||||
"anyOf": [
|
||||
{
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
@@ -381,7 +378,6 @@
|
||||
"request_data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
@@ -574,7 +570,6 @@
|
||||
"link_result_list": {
|
||||
"description": "管道模拟结果列表",
|
||||
"items": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Link Result List",
|
||||
@@ -583,7 +578,6 @@
|
||||
"node_result_list": {
|
||||
"description": "节点模拟结果列表",
|
||||
"items": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Node Result List",
|
||||
@@ -608,7 +602,6 @@
|
||||
"iforest_params": {
|
||||
"anyOf": [
|
||||
{
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
@@ -635,7 +628,6 @@
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
@@ -775,7 +767,6 @@
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
@@ -802,7 +793,6 @@
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
@@ -855,7 +845,6 @@
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
@@ -877,7 +866,6 @@
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
@@ -1316,7 +1304,6 @@
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
@@ -1911,7 +1898,6 @@
|
||||
"properties": {
|
||||
"items": {
|
||||
"items": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Items",
|
||||
@@ -1986,7 +1972,6 @@
|
||||
"title": "Duration"
|
||||
},
|
||||
"pump_control": {
|
||||
"additionalProperties": true,
|
||||
"description": "泵控制策略",
|
||||
"title": "Pump Control",
|
||||
"type": "object"
|
||||
@@ -2005,7 +1990,6 @@
|
||||
"tank_init_level": {
|
||||
"anyOf": [
|
||||
{
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
@@ -2037,7 +2021,6 @@
|
||||
},
|
||||
"errors": {
|
||||
"items": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Errors",
|
||||
@@ -2324,7 +2307,6 @@
|
||||
"map_extent": {
|
||||
"anyOf": [
|
||||
{
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
@@ -4701,7 +4683,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Patch Admin Projects Project Id Model Imports",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -4809,7 +4790,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Post Admin Projects Project Id Model Imports",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -6618,7 +6598,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Audit Logs Count",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -6890,7 +6869,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Backdrops Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -6987,7 +6965,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -7273,7 +7250,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Post Burst Detections",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -7384,7 +7360,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Post Burst Locations",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -7655,7 +7630,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Controls Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -7752,7 +7726,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -8092,7 +8065,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -8324,7 +8296,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Curves Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -8432,7 +8403,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -8554,7 +8524,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Demands Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -8662,7 +8631,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -8765,7 +8733,7 @@
|
||||
"required": true,
|
||||
"schema": {
|
||||
"description": "总需水量(m³/h)",
|
||||
"exclusiveMinimum": 0,
|
||||
"exclusiveMinimum": 0.0,
|
||||
"title": "Demand",
|
||||
"type": "number"
|
||||
}
|
||||
@@ -8886,7 +8854,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -9000,7 +8967,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -9126,7 +9092,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Element Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -9248,7 +9213,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Element Properties With Types",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -9579,7 +9543,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Emitters Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -9687,7 +9650,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -9797,7 +9759,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -10168,7 +10129,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Post Geocoding Requests",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -11676,7 +11636,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Junctions Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -11784,7 +11743,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -12350,7 +12308,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -12451,7 +12408,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -12584,7 +12540,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Labels Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -12681,7 +12636,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -12803,7 +12757,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Post Leakage Identifications",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -12914,7 +12867,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Link Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -13692,7 +13644,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -13793,7 +13744,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -13901,7 +13851,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -14023,7 +13972,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Mixing Configurations Detail",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -14167,7 +14115,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Network In Extents",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -14376,7 +14323,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Network Options",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -14473,7 +14419,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -14584,7 +14529,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Network Options Energy",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -14695,7 +14639,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Network Options Pump Energy",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -14803,7 +14746,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -14914,7 +14856,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Network Options Time",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -15015,7 +14956,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Backdrop",
|
||||
@@ -15118,7 +15058,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Control",
|
||||
@@ -15221,7 +15160,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Curve",
|
||||
@@ -15324,7 +15262,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Demand",
|
||||
@@ -15427,7 +15364,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Emitter",
|
||||
@@ -15530,7 +15466,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Energy",
|
||||
@@ -15633,7 +15568,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Junction",
|
||||
@@ -15736,7 +15670,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Label",
|
||||
@@ -15839,7 +15772,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Mixing",
|
||||
@@ -15942,7 +15874,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Option",
|
||||
@@ -16045,7 +15976,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Pattern",
|
||||
@@ -16148,7 +16078,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Pipe",
|
||||
@@ -16251,7 +16180,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Pipe Reaction",
|
||||
@@ -16354,7 +16282,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Pump",
|
||||
@@ -16457,7 +16384,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Pump Energy",
|
||||
@@ -16560,7 +16486,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Quality",
|
||||
@@ -16663,7 +16588,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Reaction",
|
||||
@@ -16765,7 +16689,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Region",
|
||||
@@ -16868,7 +16791,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Reservoir",
|
||||
@@ -16970,7 +16892,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Scada Device",
|
||||
@@ -17073,7 +16994,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Source",
|
||||
@@ -17176,7 +17096,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Tag",
|
||||
@@ -17279,7 +17198,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Tank",
|
||||
@@ -17382,7 +17300,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Tank Reaction",
|
||||
@@ -17485,7 +17402,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Time",
|
||||
@@ -17588,7 +17504,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Valve",
|
||||
@@ -17691,7 +17606,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Network Schemas Vertex",
|
||||
@@ -18056,7 +17970,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Node Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -18826,7 +18739,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -19058,7 +18970,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Patterns Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -19166,7 +19077,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -19276,7 +19186,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -19398,7 +19307,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Pipe Reactions Detail",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -21314,7 +21222,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Pipes Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -21422,7 +21329,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -22113,7 +22019,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Post Project Return Dict Runs",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -23779,7 +23684,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Pumps Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -23887,7 +23791,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -24009,7 +23912,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Quality Configurations Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -24106,7 +24008,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -24216,7 +24117,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -24327,7 +24227,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Reactions Detail",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -24425,7 +24324,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -24643,7 +24541,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -24750,7 +24647,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -24871,7 +24767,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Regions Detail",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -26303,7 +26198,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Reservoirs Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -26411,7 +26305,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -26998,7 +26891,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Rule Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -27095,7 +26987,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -27207,7 +27098,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Rule Schemas",
|
||||
@@ -27546,7 +27436,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Scada Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -28530,7 +28419,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -28638,7 +28526,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -28760,7 +28647,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Sources Detail",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -28871,7 +28757,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Status",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -28981,7 +28866,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -29093,7 +28977,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Status Schemas",
|
||||
@@ -29313,7 +29196,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -29446,7 +29328,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Tags Detail",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -29545,7 +29426,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -29667,7 +29547,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Tank Reactions Detail",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -32196,7 +32075,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Tanks Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -32304,7 +32182,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -33105,7 +32982,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -35760,7 +35636,6 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"title": "Response Get Title Schemas",
|
||||
@@ -35862,7 +35737,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Titles",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -35959,7 +35833,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -37706,7 +37579,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Valves Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -37814,7 +37686,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -38394,7 +38265,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -38495,7 +38365,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -38738,7 +38607,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Get Visual Elements Properties",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -38835,7 +38703,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Payload",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -38956,7 +38823,6 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"title": "Response Post Web Searches",
|
||||
"type": "object"
|
||||
}
|
||||
|
||||
@@ -31,6 +31,12 @@ test("已认证但未授权的账号会看到明确说明", async ({ page }) =>
|
||||
await expect(
|
||||
page.getByText("身份认证已成功,但当前账号尚未由系统管理员启用"),
|
||||
).toBeVisible();
|
||||
await expect(page.getByText("TJWater 智慧水务平台")).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "退出登录" })).toBeVisible();
|
||||
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await expect(page.getByText("账号尚未获得访问权限")).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "退出登录" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("系统管理员可以手动同步 Keycloak 用户目录", async ({ page }) => {
|
||||
|
||||
@@ -120,6 +120,7 @@ describe("RefineContext access authentication", () => {
|
||||
ok: false,
|
||||
status: 403,
|
||||
headers: new Headers(),
|
||||
json: async () => ({ detail: "User authorization pending" }),
|
||||
} as Response);
|
||||
|
||||
render(
|
||||
@@ -131,6 +132,10 @@ describe("RefineContext access authentication", () => {
|
||||
expect(
|
||||
await screen.findByText("账号尚未获得访问权限"),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("button", { name: "退出登录" }),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText("Test User")).toBeInTheDocument();
|
||||
expect(screen.queryByText("应用内容")).not.toBeInTheDocument();
|
||||
expect(useAuthStore.getState()).toMatchObject({
|
||||
sessionExpired: false,
|
||||
@@ -138,6 +143,27 @@ describe("RefineContext access authentication", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps project recovery available when the selected project is denied", async () => {
|
||||
global.fetch = jest.fn().mockResolvedValue({
|
||||
ok: false,
|
||||
status: 403,
|
||||
headers: new Headers(),
|
||||
json: async () => ({ detail: "No access to project" }),
|
||||
} as Response);
|
||||
|
||||
render(
|
||||
<App>
|
||||
<div>应用内容</div>
|
||||
</App>,
|
||||
);
|
||||
|
||||
expect(await screen.findByText("无权访问当前项目")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("button", { name: "切换项目" }),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText("应用内容")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("prioritizes an unauthenticated session over route permissions", async () => {
|
||||
mockSessionState = { data: null, status: "unauthenticated" };
|
||||
|
||||
|
||||
+49
-24
@@ -68,6 +68,7 @@ export const App = (props: React.PropsWithChildren<AppProps>) => {
|
||||
const markSessionExpired = useAuthStore((state) => state.markSessionExpired);
|
||||
const clearSessionExpired = useAuthStore((state) => state.clearSessionExpired);
|
||||
const currentProjectId = useProjectStore((state) => state.currentProjectId);
|
||||
const setCurrentProject = useProjectStore((state) => state.setCurrentProject);
|
||||
const currentProjectCode = useProjectStore(
|
||||
(state) => state.currentProjectCode,
|
||||
);
|
||||
@@ -75,7 +76,9 @@ export const App = (props: React.PropsWithChildren<AppProps>) => {
|
||||
const setAccessContext = useAccessStore((state) => state.setContext);
|
||||
const setAccessLoading = useAccessStore((state) => state.setLoading);
|
||||
const resetAccess = useAccessStore((state) => state.reset);
|
||||
const [accessDenied, setAccessDenied] = useState(false);
|
||||
const [accessDeniedReason, setAccessDeniedReason] = useState<
|
||||
"account" | "project" | null
|
||||
>(null);
|
||||
const can = (permission: string) => permissions.includes(permission);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -104,13 +107,13 @@ export const App = (props: React.PropsWithChildren<AppProps>) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (status !== "authenticated") {
|
||||
setAccessDenied(false);
|
||||
setAccessDeniedReason(null);
|
||||
resetAccess();
|
||||
return;
|
||||
}
|
||||
|
||||
let cancelled = false;
|
||||
setAccessDenied(false);
|
||||
setAccessDeniedReason(null);
|
||||
setAccessLoading(true);
|
||||
apiFetch(`${config.BACKEND_URL}/api/v1/access-context`, {
|
||||
projectHeaderMode: currentProjectId ? "include" : "omit",
|
||||
@@ -118,7 +121,17 @@ export const App = (props: React.PropsWithChildren<AppProps>) => {
|
||||
.then(async (response) => {
|
||||
if (cancelled) return;
|
||||
if (response.status === 403) {
|
||||
setAccessDenied(true);
|
||||
let detail = "";
|
||||
try {
|
||||
const payload = await response.json();
|
||||
detail = typeof payload?.detail === "string" ? payload.detail : "";
|
||||
} catch {
|
||||
// Treat an unparseable 403 as a project access failure so the user
|
||||
// keeps a recovery path instead of being trapped in the account shell.
|
||||
}
|
||||
setAccessDeniedReason(
|
||||
detail === "User authorization pending" ? "account" : "project",
|
||||
);
|
||||
resetAccess();
|
||||
return;
|
||||
}
|
||||
@@ -126,7 +139,7 @@ export const App = (props: React.PropsWithChildren<AppProps>) => {
|
||||
resetAccess();
|
||||
return;
|
||||
}
|
||||
setAccessDenied(false);
|
||||
setAccessDeniedReason(null);
|
||||
setAccessContext(await response.json());
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -166,6 +179,32 @@ export const App = (props: React.PropsWithChildren<AppProps>) => {
|
||||
return <span>loading...</span>;
|
||||
}
|
||||
|
||||
const handleLogout = () =>
|
||||
completeLogout({
|
||||
reportAudit: () =>
|
||||
reportLogoutAudit({
|
||||
endpoint: `${config.BACKEND_URL}/api/v1/audit-events`,
|
||||
accessToken:
|
||||
typeof data?.accessToken === "string"
|
||||
? data.accessToken
|
||||
: useAuthStore.getState().accessToken,
|
||||
}),
|
||||
clearLocalState: () => {
|
||||
if (data?.user?.id) {
|
||||
sessionStorage.removeItem(`tjwater-login-audit:${data.user.id}`);
|
||||
}
|
||||
clearSessionRecoveryDrafts();
|
||||
},
|
||||
navigate: (path) => window.location.assign(path),
|
||||
});
|
||||
|
||||
const handleChooseAnotherProject = () => {
|
||||
setCurrentProject(null, null);
|
||||
localStorage.removeItem("MAP_WORKSPACE");
|
||||
localStorage.removeItem("MAP_EXTENT");
|
||||
window.location.assign("/");
|
||||
};
|
||||
|
||||
const authProvider: AuthProvider = {
|
||||
login: async () => {
|
||||
signIn("keycloak", {
|
||||
@@ -174,24 +213,7 @@ export const App = (props: React.PropsWithChildren<AppProps>) => {
|
||||
});
|
||||
return { success: true };
|
||||
},
|
||||
logout: () =>
|
||||
completeLogout({
|
||||
reportAudit: () =>
|
||||
reportLogoutAudit({
|
||||
endpoint: `${config.BACKEND_URL}/api/v1/audit-events`,
|
||||
accessToken:
|
||||
typeof data?.accessToken === "string"
|
||||
? data.accessToken
|
||||
: useAuthStore.getState().accessToken,
|
||||
}),
|
||||
clearLocalState: () => {
|
||||
if (data?.user?.id) {
|
||||
sessionStorage.removeItem(`tjwater-login-audit:${data.user.id}`);
|
||||
}
|
||||
clearSessionRecoveryDrafts();
|
||||
},
|
||||
navigate: (path) => window.location.assign(path),
|
||||
}),
|
||||
logout: handleLogout,
|
||||
onError: async (error) => {
|
||||
return { error };
|
||||
},
|
||||
@@ -403,7 +425,10 @@ export const App = (props: React.PropsWithChildren<AppProps>) => {
|
||||
<SessionExpiryDialog expiresAt={data?.sessionExpiresAt} />
|
||||
<RoutePermissionGuard
|
||||
authenticated={status === "authenticated"}
|
||||
accessDenied={accessDenied}
|
||||
accessDeniedReason={accessDeniedReason}
|
||||
userName={data?.user?.name ?? data?.user?.username}
|
||||
onLogout={() => void handleLogout()}
|
||||
onChooseAnotherProject={handleChooseAnotherProject}
|
||||
>
|
||||
{props.children}
|
||||
</RoutePermissionGuard>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
|
||||
import { useAccessStore } from "@/store/accessStore";
|
||||
import { useAuthStore } from "@/store/authStore";
|
||||
@@ -52,6 +52,46 @@ describe("RoutePermissionGuard", () => {
|
||||
expect(screen.getByText(/simulation\.view/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("keeps a minimal identity header and logout action for pending accounts", () => {
|
||||
const onLogout = jest.fn();
|
||||
|
||||
render(
|
||||
<RoutePermissionGuard
|
||||
authenticated
|
||||
accessDeniedReason="account"
|
||||
userName="zjb"
|
||||
onLogout={onLogout}
|
||||
>
|
||||
<div>受保护内容</div>
|
||||
</RoutePermissionGuard>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("TJWater 智慧水务平台")).toBeInTheDocument();
|
||||
expect(screen.getByText("当前登录账号")).toBeInTheDocument();
|
||||
expect(screen.getByText("zjb")).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole("button", { name: "退出登录" }));
|
||||
expect(onLogout).toHaveBeenCalledTimes(1);
|
||||
expect(screen.queryByText("受保护内容")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("keeps project recovery available when only the selected project is denied", () => {
|
||||
const onChooseAnotherProject = jest.fn();
|
||||
|
||||
render(
|
||||
<RoutePermissionGuard
|
||||
authenticated
|
||||
accessDeniedReason="project"
|
||||
onChooseAnotherProject={onChooseAnotherProject}
|
||||
>
|
||||
<div>受保护内容</div>
|
||||
</RoutePermissionGuard>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("无权访问当前项目")).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole("button", { name: "切换项目" }));
|
||||
expect(onChooseAnotherProject).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("checks authentication before the expired state effect runs", () => {
|
||||
render(
|
||||
<RoutePermissionGuard authenticated={false}>
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
|
||||
import { Alert, Box, CircularProgress, Stack, Typography } from "@mui/material";
|
||||
import LogoutIcon from "@mui/icons-material/Logout";
|
||||
import SwapHorizIcon from "@mui/icons-material/SwapHoriz";
|
||||
import {
|
||||
Alert,
|
||||
AppBar,
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
CircularProgress,
|
||||
Stack,
|
||||
Toolbar,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { usePathname } from "next/navigation";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import { Title } from "@/components/title";
|
||||
import { permissionForPath } from "@/lib/permissions";
|
||||
import { useAccessStore } from "@/store/accessStore";
|
||||
import { useAuthStore } from "@/store/authStore";
|
||||
@@ -12,11 +25,17 @@ import { useAuthStore } from "@/store/authStore";
|
||||
export const RoutePermissionGuard = ({
|
||||
children,
|
||||
authenticated,
|
||||
accessDenied = false,
|
||||
accessDeniedReason = null,
|
||||
userName,
|
||||
onLogout,
|
||||
onChooseAnotherProject,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
authenticated: boolean;
|
||||
accessDenied?: boolean;
|
||||
accessDeniedReason?: "account" | "project" | null;
|
||||
userName?: string | null;
|
||||
onLogout?: () => void;
|
||||
onChooseAnotherProject?: () => void;
|
||||
}) => {
|
||||
const pathname = usePathname();
|
||||
const permissions = useAccessStore((state) => state.permissions);
|
||||
@@ -39,17 +58,94 @@ export const RoutePermissionGuard = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (accessDenied) {
|
||||
if (accessDeniedReason) {
|
||||
const displayName = userName?.trim() || "已登录账号";
|
||||
const accountPending = accessDeniedReason === "account";
|
||||
|
||||
return (
|
||||
<Box sx={{ p: { xs: 2, md: 4 } }}>
|
||||
<Alert severity="warning" icon={<LockOutlinedIcon />}>
|
||||
<Stack spacing={0.5}>
|
||||
<Typography fontWeight={700}>账号尚未获得访问权限</Typography>
|
||||
<Typography variant="body2">
|
||||
身份认证已成功,但当前账号尚未由系统管理员启用,或无权访问所选项目。请联系系统管理员完成授权后重试。
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Alert>
|
||||
<Box sx={{ minHeight: "100vh", bgcolor: "background.default" }}>
|
||||
<AppBar
|
||||
color="inherit"
|
||||
elevation={0}
|
||||
position="static"
|
||||
sx={{ borderBottom: 1, borderColor: "divider" }}
|
||||
>
|
||||
<Toolbar sx={{ gap: 2, justifyContent: "space-between" }}>
|
||||
<Title />
|
||||
<Stack direction="row" spacing={1.5} alignItems="center">
|
||||
<Avatar sx={{ width: 32, height: 32, bgcolor: "primary.main" }}>
|
||||
{displayName.slice(0, 1).toUpperCase()}
|
||||
</Avatar>
|
||||
<Box sx={{ display: { xs: "none", sm: "block" } }}>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
当前登录账号
|
||||
</Typography>
|
||||
<Typography variant="body2" fontWeight={600}>
|
||||
{displayName}
|
||||
</Typography>
|
||||
</Box>
|
||||
{!accountPending && (
|
||||
<Button
|
||||
aria-label="切换项目"
|
||||
color="inherit"
|
||||
onClick={onChooseAnotherProject}
|
||||
sx={{
|
||||
gap: { xs: 0, sm: 1 },
|
||||
minWidth: { xs: 40, sm: "auto" },
|
||||
px: { xs: 1, sm: 2 },
|
||||
"&:active": { transform: "translateY(1px)" },
|
||||
}}
|
||||
variant="outlined"
|
||||
>
|
||||
<SwapHorizIcon fontSize="small" />
|
||||
<Box component="span" sx={{ display: { xs: "none", sm: "inline" } }}>
|
||||
切换项目
|
||||
</Box>
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
aria-label="退出登录"
|
||||
color="inherit"
|
||||
onClick={onLogout}
|
||||
sx={{
|
||||
gap: { xs: 0, sm: 1 },
|
||||
minWidth: { xs: 40, sm: "auto" },
|
||||
px: { xs: 1, sm: 2 },
|
||||
"&:active": { transform: "translateY(1px)" },
|
||||
}}
|
||||
variant="outlined"
|
||||
>
|
||||
<LogoutIcon fontSize="small" />
|
||||
<Box component="span" sx={{ display: { xs: "none", sm: "inline" } }}>
|
||||
退出登录
|
||||
</Box>
|
||||
</Button>
|
||||
</Stack>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
<Box
|
||||
component="main"
|
||||
sx={{
|
||||
width: "100%",
|
||||
maxWidth: 840,
|
||||
mx: "auto",
|
||||
px: { xs: 2, sm: 3 },
|
||||
py: { xs: 4, md: 8 },
|
||||
}}
|
||||
>
|
||||
<Alert severity="warning" icon={<LockOutlinedIcon />}>
|
||||
<Stack spacing={0.5}>
|
||||
<Typography fontWeight={700}>
|
||||
{accountPending ? "账号尚未获得访问权限" : "无权访问当前项目"}
|
||||
</Typography>
|
||||
<Typography variant="body2">
|
||||
{accountPending
|
||||
? "身份认证已成功,但当前账号尚未由系统管理员启用。请联系系统管理员完成授权后重试。"
|
||||
: "当前账号无法访问所选项目。请选择其他已授权项目,或联系系统管理员调整项目权限。"}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Alert>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
+134
-402
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user