Merge remote-tracking branch 'origin/main_laptop_1' into main_desktop_1
This commit is contained in:
@@ -179,6 +179,15 @@
|
||||
"default": 2.5,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "revet_foundation",
|
||||
"label": "기슭막이 기초",
|
||||
"input": "select",
|
||||
"choices": ["기초유", "기초버림"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -202,6 +211,15 @@
|
||||
"default": 2.0,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"key": "revet_foundation",
|
||||
"label": "기슭막이 기초",
|
||||
"input": "select",
|
||||
"choices": ["기초유", "기초버림"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "body_height_m",
|
||||
"label": "본체 높이",
|
||||
@@ -779,6 +797,24 @@
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "stone_coeff_basis",
|
||||
"label": "야면석 계수",
|
||||
"input": "select",
|
||||
"choices": ["품셈", "실무 관행"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "fill_concrete_mpa",
|
||||
"label": "채움 강도",
|
||||
"input": "select",
|
||||
"choices": ["180", "210"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "face_slope_ratio",
|
||||
"label": "전면 기울기 (1:n 의 n)",
|
||||
@@ -879,6 +915,24 @@
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "stone_coeff_basis",
|
||||
"label": "야면석 계수",
|
||||
"input": "select",
|
||||
"choices": ["품셈", "실무 관행"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "fill_concrete_mpa",
|
||||
"label": "채움 강도",
|
||||
"input": "select",
|
||||
"choices": ["180", "210"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "face_slope_ratio",
|
||||
"label": "전면 기울기 (1:n 의 n)",
|
||||
@@ -1044,6 +1098,24 @@
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "stone_coeff_basis",
|
||||
"label": "야면석 계수",
|
||||
"input": "select",
|
||||
"choices": ["품셈", "실무 관행"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "fill_concrete_mpa",
|
||||
"label": "채움 강도",
|
||||
"input": "select",
|
||||
"choices": ["180", "210"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "face_slope_ratio",
|
||||
"label": "전면 기울기 (1:n 의 n)",
|
||||
@@ -1166,6 +1238,24 @@
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "stone_coeff_basis",
|
||||
"label": "야면석 계수",
|
||||
"input": "select",
|
||||
"choices": ["품셈", "실무 관행"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "fill_concrete_mpa",
|
||||
"label": "채움 강도",
|
||||
"input": "select",
|
||||
"choices": ["180", "210"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "face_slope_ratio",
|
||||
"label": "전면 기울기 (1:n 의 n)",
|
||||
@@ -1228,6 +1318,24 @@
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "stone_coeff_basis",
|
||||
"label": "야면석 계수",
|
||||
"input": "select",
|
||||
"choices": ["품셈", "실무 관행"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "fill_concrete_mpa",
|
||||
"label": "채움 강도",
|
||||
"input": "select",
|
||||
"choices": ["180", "210"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "face_slope_ratio",
|
||||
"label": "전면 기울기 (1:n 의 n)",
|
||||
@@ -1353,6 +1461,24 @@
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "stone_coeff_basis",
|
||||
"label": "야면석 계수",
|
||||
"input": "select",
|
||||
"choices": ["품셈", "실무 관행"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "fill_concrete_mpa",
|
||||
"label": "채움 강도",
|
||||
"input": "select",
|
||||
"choices": ["180", "210"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail"
|
||||
},
|
||||
{
|
||||
"key": "face_slope_ratio",
|
||||
"label": "전면 기울기 (1:n 의 n)",
|
||||
|
||||
@@ -233,6 +233,9 @@ export interface CulvertSet {
|
||||
side?: string;
|
||||
/** 독립 기슭막이 다단 요청 수(1이면 단일 벽). */
|
||||
tiers?: number;
|
||||
/** 기초 축 — "기초유" | "기초버림"(실무 정본 탭 제목). **비어 있으면 터파기를 안 그린다**
|
||||
* — 고르기 전에는 근거가 없다(2026-09-09 사용자 확정 ④). */
|
||||
foundation?: string | null;
|
||||
}
|
||||
|
||||
/** 세월교 날개벽 한쪽 — 횡단면엔 안 보이고 바닥판 연장량만 넘긴다. */
|
||||
|
||||
@@ -213,6 +213,12 @@ def _culvert_set(options: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"pipe_kind": str(kind) if kind else None,
|
||||
"diameter_m": round((diameter_mm or 1000.0) / 1000.0, 3),
|
||||
"min_cover_m": MIN_PIPE_COVER_M,
|
||||
# 관 기슭막이 기초 축 — **유입·유출 한 칸으로** 받는다(2026-09-09). 한쪽만 기초유로
|
||||
# 하는 일이 드물어 폼을 둘로 늘리지 않았다. 실무가 갈라 쓰면 그때 나눌 것.
|
||||
"foundation": (
|
||||
str(values.get("revet_foundation") or defaults.get("revet_foundation") or "").strip()
|
||||
or None
|
||||
),
|
||||
"inlet": _side_spec(values, defaults, "inlet"),
|
||||
"outlet": _side_spec(values, defaults, "outlet"),
|
||||
}
|
||||
@@ -263,6 +269,8 @@ def _revet_set(options: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"hidden_pipe": True,
|
||||
"side": str(values.get("side") or "양쪽"),
|
||||
"tiers": int(_number(values.get("tiers"), 1.0) or 1),
|
||||
# 기초 축(기초유/기초버림) — 터파기 그림·물량이 같이 쓴다. 비어 있으면 안 그린다.
|
||||
"foundation": (str(values.get("foundation") or "").strip() or None),
|
||||
"pipe_kind": None,
|
||||
"diameter_m": 0.3,
|
||||
"min_cover_m": 0.0,
|
||||
|
||||
@@ -73,6 +73,9 @@ def load_wall_structures(project_root: Path) -> list[dict[str, Any]]:
|
||||
# C군 폼에는 설치 측 칸이 없다 — 비워 두면 화면이 **성토가 나는 쪽**으로
|
||||
# 세운다(`computeRevetmentLayout`). 사용자가 정하고 싶어지면 그때 칸을 낸다.
|
||||
"side": options.get("side"),
|
||||
# 기초 축(기초유/기초버림) — 터파기 그림·물량이 같이 쓴다.
|
||||
# 비어 있으면 화면이 터파기를 안 그린다(근거 없음).
|
||||
"foundation": options.get("foundation"),
|
||||
"tiers": options.get("tiers"),
|
||||
"lift_m": options.get("lift_m"),
|
||||
"shift_m": options.get("shift_m"),
|
||||
|
||||
@@ -23,6 +23,11 @@ import type {
|
||||
PipeEnd,
|
||||
WallLayout,
|
||||
} from "./B06_Section_UI_Cross_Culvert_Geom";
|
||||
import {
|
||||
appendPipeTrench,
|
||||
appendWallTrench,
|
||||
foundationChoice,
|
||||
} from "./B06_Section_UI_Cross_Excavation";
|
||||
import { appendWallHatch } from "./B06_Section_UI_Cross_Wall_Hatch";
|
||||
|
||||
// 기하 계산 진입점과 공개 상수·타입은 여기서 재수출한다 — B05(최소 토피)와 횡단 뷰가
|
||||
@@ -162,6 +167,12 @@ export function appendCulvertOverlay(
|
||||
const revetShapes = new Map<RevetKey, SVGPolygonElement>();
|
||||
/** 집수정 부재 도형 — 유입 선택 강조에 쓴다(2026-08-22 사용자 ③). */
|
||||
const basinShapes: SVGPolygonElement[] = [];
|
||||
// 터파기는 구조물보다 **먼저** 그린다 — 파선이 벽 밑에 깔려야 도면처럼 보인다.
|
||||
// 저장 제원 `foundation`(기초유/기초버림)이 비어 있으면 그리지 않는다 — 근거가 없다.
|
||||
const wallFoundation = foundationChoice(culvert.foundation);
|
||||
for (const { wall } of wallsInOrder) {
|
||||
appendWallTrench(layer, wall, wallFoundation, x, toDisplayY);
|
||||
}
|
||||
for (const { wall, key: wallKey } of wallsInOrder) {
|
||||
// 합성 단면(하부 사다리꼴 + 상부 평행사변형) — 상단 배면이 사면선 접점(사용자 ①·②).
|
||||
const revetShape = polygon(
|
||||
@@ -272,6 +283,26 @@ export function appendCulvertOverlay(
|
||||
const inletFinal = pushOut(pipeCorners.inlet, -1);
|
||||
const outletFinal = pushOut(pipeCorners.outlet, 1);
|
||||
|
||||
// 관 터파기 — 표값 폭으로 관 위 지반선에서 관 바닥까지 수직(KCS 44 40 10 그림 3.2-1).
|
||||
if (!hidePipe) {
|
||||
const invert = Math.min(
|
||||
pipeCorners.inlet.bottom.elevation,
|
||||
pipeCorners.outlet.bottom.elevation,
|
||||
);
|
||||
const centerOffset = (pipeCorners.inlet.bottom.offset + pipeCorners.outlet.bottom.offset) / 2;
|
||||
appendPipeTrench(
|
||||
layer,
|
||||
{
|
||||
centerOffsetM: centerOffset,
|
||||
invertM: invert,
|
||||
topM: invert + diameter + culvert.min_cover_m,
|
||||
diameterMm: Math.round(diameter * 1000),
|
||||
},
|
||||
x,
|
||||
toDisplayY,
|
||||
);
|
||||
}
|
||||
|
||||
const kindLabel = culvert.pipe_kind ? `${culvert.pipe_kind} ` : "";
|
||||
const wallThickness = pipeWallThicknessM(culvert.pipe_kind, diameter);
|
||||
const tip =
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/* =============================================================================
|
||||
* B06_Section_UI_Cross_Excavation.ts
|
||||
* 횡단도에 **터파기 선**을 얹는다 — 관·벽 두 갈래(2026-09-09 사용자 확정 ④).
|
||||
*
|
||||
* 왜 있나 — 「터파기가 현재 횡단도에서 표현이 안 된다」가 사용자 지적이었다. 수량을
|
||||
* 세기 전에 **도면에 그것이 보여야** 한다.
|
||||
*
|
||||
* ⚠ 근거의 급이 다르므로 **노티스를 갈라 적는다** — 값은 `common_util_excavation` 한 곳에서
|
||||
* 온다(파이썬 짝과 거울 시험으로 묶여 있다). 여기서는 **그리기만** 한다.
|
||||
* 관 : 법정 시방서 표(KCS 44 40 10 그림 3.2-1)
|
||||
* 벽 : 법정 근거 없음 — 실무 정본 식(구조도 기슭막이 xls)
|
||||
* ⚠ **비탈을 주지 않는다 — 수직으로 그린다.** 정본 식에 기울기 항이 없다.
|
||||
* ========================================================================== */
|
||||
|
||||
import {
|
||||
BASIS_PIPE,
|
||||
BASIS_WALL,
|
||||
WALL_BLINDING_DEPTH_M,
|
||||
WALL_BLINDING_WIDTH_M,
|
||||
WALL_FOUNDATION_DEPTH_M,
|
||||
WALL_FOUNDATION_WIDTH_M,
|
||||
WALL_TRENCH_CLEARANCE_M,
|
||||
pipeTrenchWidthM,
|
||||
} from "@util/common_util_excavation";
|
||||
import type { WallLayout } from "./B06_Section_UI_Cross_Culvert_Types";
|
||||
|
||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||||
|
||||
/** 「기초유」인가 — 저장 제원 `foundation` 의 값. 비어 있으면 **그리지 않는다**(근거 없음). */
|
||||
export function foundationChoice(value: unknown): "기초유" | "기초버림" | null {
|
||||
const text = typeof value === "string" ? value.trim() : "";
|
||||
if (text === "기초유") return "기초유";
|
||||
if (text === "기초버림") return "기초버림";
|
||||
return null;
|
||||
}
|
||||
|
||||
function trenchPath(layer: SVGElement, corners: Array<[number, number]>, tooltip: string): void {
|
||||
const line = document.createElementNS(SVG_NS, "polyline");
|
||||
line.setAttribute("points", corners.map(([px, py]) => `${px},${py}`).join(" "));
|
||||
line.setAttribute("class", "b06-chart__excavation");
|
||||
const title = document.createElementNS(SVG_NS, "title");
|
||||
title.textContent = tooltip;
|
||||
line.append(title);
|
||||
layer.append(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* 관 터파기 — **표값 폭**으로 관 위 지반선에서 관 바닥까지 수직으로 판다.
|
||||
* 표에 없는 관경이면 **아무것도 그리지 않는다**(폭을 지어내지 않는다).
|
||||
*/
|
||||
export function appendPipeTrench(
|
||||
layer: SVGElement,
|
||||
input: {
|
||||
/** 관 중심 offset(m). */
|
||||
centerOffsetM: number;
|
||||
/** 관 바닥(invert) 표고. */
|
||||
invertM: number;
|
||||
/** 터파기 윗면 표고 — 관 위 지반(또는 노면)선. */
|
||||
topM: number;
|
||||
diameterMm: number | null | undefined;
|
||||
},
|
||||
x: (offset: number) => number,
|
||||
toDisplayY: (elevation: number) => number,
|
||||
): number | null {
|
||||
const width = pipeTrenchWidthM(input.diameterMm);
|
||||
if (width === null || !(input.topM > input.invertM)) return null;
|
||||
const half = width / 2;
|
||||
const left = input.centerOffsetM - half;
|
||||
const right = input.centerOffsetM + half;
|
||||
trenchPath(
|
||||
layer,
|
||||
[
|
||||
[x(left), toDisplayY(input.topM)],
|
||||
[x(left), toDisplayY(input.invertM)],
|
||||
[x(right), toDisplayY(input.invertM)],
|
||||
[x(right), toDisplayY(input.topM)],
|
||||
],
|
||||
`관 터파기 폭 ${width.toFixed(2)}m · 깊이 ${(input.topM - input.invertM).toFixed(2)}m\n` +
|
||||
`Φ${Math.round(Number(input.diameterMm))}㎜ — ${BASIS_PIPE}`,
|
||||
);
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* 벽 터파기 — 벽 바닥선 아래로 **수직**. 폭은 바닥 폭 + 여유 0.2, 깊이는 기초 몫.
|
||||
* `foundation` 이 비어 있으면 **그리지 않는다** — 사용자가 고르기 전에는 근거가 없다.
|
||||
*/
|
||||
export function appendWallTrench(
|
||||
layer: SVGElement,
|
||||
wall: WallLayout,
|
||||
foundation: "기초유" | "기초버림" | null,
|
||||
x: (offset: number) => number,
|
||||
toDisplayY: (elevation: number) => number,
|
||||
): { widthM: number; depthM: number } | null {
|
||||
if (foundation === null) return null;
|
||||
const hasFoundation = foundation === "기초유";
|
||||
const depth = hasFoundation ? WALL_FOUNDATION_DEPTH_M : WALL_BLINDING_DEPTH_M;
|
||||
// 폭: 기초 몫은 정본이 정한 값(0.9 / 0.7), 다만 벽 바닥이 그보다 넓으면 그 폭 + 여유.
|
||||
const baseWidth = Math.abs(wall.bottomFront.offset - wall.bottomBack.offset);
|
||||
const minWidth = hasFoundation ? WALL_FOUNDATION_WIDTH_M : WALL_BLINDING_WIDTH_M;
|
||||
const width = Math.max(minWidth, baseWidth + (hasFoundation ? WALL_TRENCH_CLEARANCE_M : 0));
|
||||
const center = (wall.bottomFront.offset + wall.bottomBack.offset) / 2;
|
||||
const top = Math.max(wall.bottomFront.elevation, wall.bottomBack.elevation);
|
||||
const bottom = top - depth;
|
||||
const left = center - width / 2;
|
||||
const right = center + width / 2;
|
||||
trenchPath(
|
||||
layer,
|
||||
[
|
||||
[x(left), toDisplayY(top)],
|
||||
[x(left), toDisplayY(bottom)],
|
||||
[x(right), toDisplayY(bottom)],
|
||||
[x(right), toDisplayY(top)],
|
||||
],
|
||||
`${foundation} 터파기 폭 ${width.toFixed(2)}m · 깊이 ${depth.toFixed(2)}m (수직)\n` +
|
||||
`품셈에 규정이 없어 실무 관행으로 정한 값 — ${BASIS_WALL}`,
|
||||
);
|
||||
return { widthM: width, depthM: depth };
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
type WallAdjust,
|
||||
type WallLayout,
|
||||
} from "./B06_Section_UI_Cross_Culvert_Types";
|
||||
import { appendWallTrench, foundationChoice } from "./B06_Section_UI_Cross_Excavation";
|
||||
import { appendPlanLine, buildRevetWallGeometry, drawRevetWall } from "./B06_Section_UI_Cross_Wall";
|
||||
|
||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||||
@@ -53,6 +54,8 @@ export interface RevetmentSpec {
|
||||
height_m?: number | null;
|
||||
/** 사용자가 고른 설치 측 — "좌" | "우". */
|
||||
side?: string | null;
|
||||
/** 기초 축 — "기초유" | "기초버림". **비어 있으면 터파기를 안 그린다**(근거 없음). */
|
||||
foundation?: string | null;
|
||||
/** 단 수(다단). 1이면 단일 벽. */
|
||||
tiers?: number | null;
|
||||
/** (구 모델) 기준 올림·좌우 이동 — 배관식 전환 뒤 자리는 조정창 4축(x·d)이 정한다. */
|
||||
@@ -89,6 +92,8 @@ export interface RevetmentLayout {
|
||||
top: RevetPoint;
|
||||
/** 벽 목록(1단 + 다단) — 배관 벽과 같은 `WallLayout`, 그리기가 그대로 쓴다. */
|
||||
walls: WallLayout[];
|
||||
/** 기초 축 — 저장 칸과 **같은 글자**(`foundation`). 터파기 그림이 이 값으로 갈린다. */
|
||||
foundation: string | null;
|
||||
/** 벽 사이·벽 아래 성토부선(배관 다단과 같은 체계). */
|
||||
fillSegments: OutletFillSegment[];
|
||||
/** 성토 설계선을 벽 상단에서 끊고 노견→벽 성토선을 대신 그리는 트림. */
|
||||
@@ -304,6 +309,7 @@ export function computeRevetmentLayout(
|
||||
requestedTiers,
|
||||
top: jt,
|
||||
walls,
|
||||
foundation: typeof spec.foundation === "string" ? spec.foundation.trim() || null : null,
|
||||
fillSegments: extras.segments,
|
||||
designTrim,
|
||||
appliedAdjust: { x: appliedX, d: appliedDrop, h: adjust?.h ?? null, m: null },
|
||||
@@ -359,6 +365,11 @@ export function appendRevetmentOverlay(
|
||||
` · 성토 물매 1:${(segment.ratio ?? 1.2).toFixed(2)}`,
|
||||
);
|
||||
}
|
||||
// 터파기는 벽보다 **먼저** — 파선이 벽 밑에 깔린다. 기초 축이 비어 있으면 안 그린다.
|
||||
const trenchFoundation = foundationChoice(layout.foundation);
|
||||
for (const wall of layout.walls) {
|
||||
appendWallTrench(svg, wall, trenchFoundation, x, y);
|
||||
}
|
||||
const drawn: SVGPolygonElement[] = [];
|
||||
layout.walls.forEach((wall, index) => {
|
||||
const keyId = index === 0 ? "own" : `own-extra${index - 1}`;
|
||||
|
||||
@@ -379,3 +379,12 @@
|
||||
stroke-dasharray: 4 3;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
/* 터파기 선(2026-09-09 사용자 확정 ④) — **파선**으로 그린다. 구조물 실체가 아니라
|
||||
「여기를 판다」는 표시이고, 근거의 급(법정 표 / 실무 관행)은 말풍선에 적힌다. */
|
||||
.b06-chart__excavation {
|
||||
fill: none;
|
||||
stroke: #8a5c3c;
|
||||
stroke-dasharray: 4 3;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
@@ -138,6 +138,10 @@ function culvertSet(
|
||||
pipe_kind: text(options.pipe_kind) ?? text(defaults.pipe_kind),
|
||||
diameter_m: pipeDiameterM(diameterMm),
|
||||
min_cover_m: MIN_PIPE_COVER_M,
|
||||
// 관 기슭막이 기초 축 — **유입·유출 한 칸으로** 받는다. 한 공사에서 한쪽만 기초유로
|
||||
// 하는 일은 드물어 폼을 둘로 늘리지 않았다(2026-09-09). 실무가 갈라 쓰는 것이
|
||||
// 확인되면 그때 나눌 것.
|
||||
foundation: text(options.revet_foundation) ?? text(defaults.revet_foundation),
|
||||
inlet: sideSpec(options, defaults, "inlet"),
|
||||
outlet: sideSpec(options, defaults, "outlet"),
|
||||
};
|
||||
@@ -174,6 +178,8 @@ function revetSet(values: Record<string, unknown>): CulvertSetSpec {
|
||||
hidden_pipe: true,
|
||||
side: String(values.side ?? "양쪽"),
|
||||
tiers: Math.trunc(num(values.tiers, 1.0) || 1),
|
||||
// 기초 축(기초유/기초버림) — 터파기 그림·물량이 같이 쓴다. 비어 있으면 안 그린다.
|
||||
foundation: text(values.foundation),
|
||||
pipe_kind: null,
|
||||
diameter_m: 0.3,
|
||||
min_cover_m: 0.0,
|
||||
|
||||
Reference in New Issue
Block a user