[agent-pipeline] pipe-20260329080516-zyud round-2
This commit is contained in:
@@ -32,7 +32,7 @@ import { useTabId } from "@/contexts/TabIdContext";
|
||||
|
||||
interface ScreenModalState {
|
||||
isOpen: boolean;
|
||||
screenId: number | null;
|
||||
screen_id: number | null;
|
||||
title: string;
|
||||
description?: string;
|
||||
size: "sm" | "md" | "lg" | "xl";
|
||||
@@ -50,7 +50,7 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||
|
||||
const [modalState, setModalState] = useState<ScreenModalState>({
|
||||
isOpen: false,
|
||||
screenId: null,
|
||||
screen_id: null,
|
||||
title: "",
|
||||
description: "",
|
||||
size: "md",
|
||||
@@ -417,7 +417,7 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||
|
||||
setModalState({
|
||||
isOpen: true,
|
||||
screenId,
|
||||
screen_id: screenId,
|
||||
title,
|
||||
description: description || "",
|
||||
size,
|
||||
@@ -435,7 +435,7 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||
|
||||
setModalState({
|
||||
isOpen: false,
|
||||
screenId: null,
|
||||
screen_id: null,
|
||||
title: "",
|
||||
description: "",
|
||||
size: "md",
|
||||
@@ -465,8 +465,8 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||
setResetKey((prev) => prev + 1);
|
||||
|
||||
// 화면 데이터 다시 로드 (채번 규칙 새로 생성)
|
||||
if (modalState.screenId) {
|
||||
loadScreenData(modalState.screenId);
|
||||
if (modalState.screen_id) {
|
||||
loadScreenData(modalState.screen_id);
|
||||
}
|
||||
|
||||
toast.success("저장되었습니다. 계속 입력하세요.");
|
||||
@@ -489,10 +489,10 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||
|
||||
// 화면 데이터 로딩
|
||||
useEffect(() => {
|
||||
if (modalState.isOpen && modalState.screenId) {
|
||||
loadScreenData(modalState.screenId);
|
||||
if (modalState.isOpen && modalState.screen_id) {
|
||||
loadScreenData(modalState.screen_id);
|
||||
}
|
||||
}, [modalState.isOpen, modalState.screenId]);
|
||||
}, [modalState.isOpen, modalState.screen_id]);
|
||||
|
||||
const loadScreenData = async (screenId: number) => {
|
||||
try {
|
||||
@@ -921,7 +921,7 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||
|
||||
setModalState({
|
||||
isOpen: false,
|
||||
screenId: null,
|
||||
screen_id: null,
|
||||
title: "",
|
||||
size: "md",
|
||||
});
|
||||
@@ -980,11 +980,11 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||
let newModalId: string | undefined;
|
||||
|
||||
// 1순위: screenId (가장 안정적)
|
||||
if (modalState.screenId) {
|
||||
newModalId = `screen-modal-${modalState.screenId}`;
|
||||
if (modalState.screen_id) {
|
||||
newModalId = `screen-modal-${modalState.screen_id}`;
|
||||
// console.log("🔑 ScreenModal modalId 생성:", {
|
||||
// method: "screenId",
|
||||
// screenId: modalState.screenId,
|
||||
// screenId: modalState.screen_id,
|
||||
// result: newModalId,
|
||||
// });
|
||||
}
|
||||
@@ -1022,7 +1022,7 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||
}
|
||||
}, [
|
||||
modalState.isOpen,
|
||||
modalState.screenId,
|
||||
modalState.screen_id,
|
||||
modalState.title,
|
||||
screenData?.screenInfo?.tableName,
|
||||
screenData?.screenInfo?.screenName,
|
||||
@@ -1075,7 +1075,7 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||
</div>
|
||||
) : screenData ? (
|
||||
<ScreenContextProvider
|
||||
screenId={modalState.screenId || undefined}
|
||||
screenId={modalState.screen_id || undefined}
|
||||
tableName={screenData.screenInfo?.tableName}
|
||||
>
|
||||
<ActiveTabProvider>
|
||||
@@ -1251,13 +1251,13 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||
window.dispatchEvent(new CustomEvent("refreshTable"));
|
||||
}}
|
||||
screenInfo={{
|
||||
id: modalState.screenId!,
|
||||
id: modalState.screen_id!,
|
||||
tableName: screenData.screenInfo?.tableName,
|
||||
}}
|
||||
groupedData={selectedData}
|
||||
userId={userId}
|
||||
userName={userName}
|
||||
companyCode={user?.company_code || user?.companyCode}
|
||||
companyCode={user?.company_code}
|
||||
isInModal={true}
|
||||
/>
|
||||
);
|
||||
@@ -1296,12 +1296,12 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||
window.dispatchEvent(new CustomEvent("refreshTable"));
|
||||
}}
|
||||
screenInfo={{
|
||||
id: modalState.screenId!,
|
||||
id: modalState.screen_id!,
|
||||
tableName: screenData?.screenInfo?.tableName,
|
||||
}}
|
||||
userId={userId}
|
||||
userName={userName}
|
||||
companyCode={user?.company_code || user?.companyCode}
|
||||
companyCode={user?.company_code}
|
||||
isInModal={true}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -38,8 +38,8 @@ interface Vehicle {
|
||||
status: "active" | "inactive" | "maintenance" | "warning" | "off";
|
||||
speed: number;
|
||||
destination: string;
|
||||
userId?: string; // 이동경로 조회용
|
||||
tripId?: string; // 현재 운행 ID
|
||||
user_id?: string; // 이동경로 조회용
|
||||
trip_id?: string; // 현재 운행 ID
|
||||
}
|
||||
|
||||
// 이동경로 좌표
|
||||
@@ -137,8 +137,8 @@ export default function VehicleMapOnlyWidget({ element, refreshInterval = 30000
|
||||
: "inactive",
|
||||
speed: parseFloat(row.speed) || 0,
|
||||
destination: row.destination || "대기 중",
|
||||
userId: row.user_id || undefined,
|
||||
tripId: row.trip_id || undefined,
|
||||
user_id: row.user_id || undefined,
|
||||
trip_id: row.trip_id || undefined,
|
||||
};
|
||||
})
|
||||
// 유효한 위도/경도가 있는 차량만 필터링
|
||||
@@ -160,7 +160,7 @@ export default function VehicleMapOnlyWidget({ element, refreshInterval = 30000
|
||||
|
||||
// 이동경로 로드 함수
|
||||
const loadRoute = async (vehicle: Vehicle) => {
|
||||
if (!vehicle.userId && !vehicle.tripId) {
|
||||
if (!vehicle.user_id && !vehicle.trip_id) {
|
||||
console.log("🛣️ 이동경로 조회 불가: userId 또는 tripId 없음");
|
||||
return;
|
||||
}
|
||||
@@ -175,15 +175,15 @@ export default function VehicleMapOnlyWidget({ element, refreshInterval = 30000
|
||||
|
||||
// trip_id가 있으면 해당 운행만, 없으면 user_id로 오늘 전체 조회
|
||||
let query = "";
|
||||
if (vehicle.tripId) {
|
||||
query = `SELECT latitude, longitude, speed, recorded_at
|
||||
FROM vehicle_location_history
|
||||
WHERE trip_id = '${vehicle.tripId}'
|
||||
if (vehicle.trip_id) {
|
||||
query = `SELECT latitude, longitude, speed, recorded_at
|
||||
FROM vehicle_location_history
|
||||
WHERE trip_id = '${vehicle.trip_id}'
|
||||
ORDER BY recorded_at ASC`;
|
||||
} else if (vehicle.userId) {
|
||||
query = `SELECT latitude, longitude, speed, recorded_at
|
||||
FROM vehicle_location_history
|
||||
WHERE user_id = '${vehicle.userId}'
|
||||
} else if (vehicle.user_id) {
|
||||
query = `SELECT latitude, longitude, speed, recorded_at
|
||||
FROM vehicle_location_history
|
||||
WHERE user_id = '${vehicle.user_id}'
|
||||
AND recorded_at >= '${startOfDay}'
|
||||
ORDER BY recorded_at ASC`;
|
||||
}
|
||||
@@ -352,7 +352,7 @@ export default function VehicleMapOnlyWidget({ element, refreshInterval = 30000
|
||||
<strong>목적지:</strong> {vehicle.destination}
|
||||
</div>
|
||||
{/* 이동경로 버튼 */}
|
||||
{(vehicle.userId || vehicle.tripId) && (
|
||||
{(vehicle.user_id || vehicle.trip_id) && (
|
||||
<div className="mt-2 border-t pt-2">
|
||||
<button
|
||||
onClick={() => loadRoute(vehicle)}
|
||||
|
||||
@@ -221,8 +221,8 @@ const convertSingleMenu = (menu: MenuItem, allMenus: MenuItem[], userInfo: Exten
|
||||
icon: getMenuIcon(menu.menu_name_kor || menu.MENU_NAME_KOR || "", menu.menu_icon || menu.MENU_ICON),
|
||||
url: menuUrl,
|
||||
screenCode,
|
||||
screenId,
|
||||
menuType,
|
||||
screen_id: screenId,
|
||||
menu_type: menuType,
|
||||
children: children.length > 0 ? children : undefined,
|
||||
hasChildren: children.length > 0,
|
||||
};
|
||||
@@ -369,14 +369,14 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
||||
}
|
||||
|
||||
const menuObjid = parseInt((menu.objid || menu.id)?.toString() || "0");
|
||||
const isAdminMenu = menu.menuType === "0";
|
||||
const isAdminMenu = menu.menu_type === "0";
|
||||
|
||||
console.log("[handleMenuClick] 메뉴 클릭:", {
|
||||
menuName,
|
||||
menuObjid,
|
||||
menuType: menu.menuType,
|
||||
menu_type: menu.menu_type,
|
||||
isAdminMenu,
|
||||
screenId: menu.screenId,
|
||||
screen_id: menu.screen_id,
|
||||
screenCode: menu.screenCode,
|
||||
url: menu.url,
|
||||
fullMenu: menu,
|
||||
@@ -396,9 +396,9 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
||||
|
||||
// 사용자 메뉴 (menu_type = 1, 2): 화면/대시보드 할당
|
||||
// 1) screenId가 메뉴 URL에서 추출된 경우 바로 screen 탭
|
||||
if (menu.screenId) {
|
||||
console.log("[handleMenuClick] → screen 탭 (URL에서 screenId 추출):", menu.screenId);
|
||||
openTab({ type: "screen", title: menuName, screenId: menu.screenId, menuObjid });
|
||||
if (menu.screen_id) {
|
||||
console.log("[handleMenuClick] → screen 탭 (URL에서 screenId 추출):", menu.screen_id);
|
||||
openTab({ type: "screen", title: menuName, screenId: menu.screen_id, menuObjid });
|
||||
if (isMobile) setSidebarOpen(false);
|
||||
return;
|
||||
}
|
||||
@@ -410,8 +410,9 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
||||
const assignedScreens = await menuScreenApi.getScreensByMenu(menuObjid);
|
||||
console.log("[handleMenuClick] → 조회 결과:", assignedScreens);
|
||||
if (assignedScreens.length > 0) {
|
||||
console.log("[handleMenuClick] → screen 탭 (assignments):", assignedScreens[0].screenId);
|
||||
openTab({ type: "screen", title: menuName, screenId: assignedScreens[0].screenId, menuObjid });
|
||||
const assignedScreenId = assignedScreens[0].screen_id;
|
||||
console.log("[handleMenuClick] → screen 탭 (assignments):", assignedScreenId);
|
||||
openTab({ type: "screen", title: menuName, screenId: assignedScreenId, menuObjid });
|
||||
if (isMobile) setSidebarOpen(false);
|
||||
return;
|
||||
}
|
||||
@@ -436,7 +437,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.warn("[handleMenuClick] 어떤 조건에도 매칭 안 됨:", { menuName, menuType: menu.menuType, url: menu.url, screenId: menu.screenId });
|
||||
console.warn("[handleMenuClick] 어떤 조건에도 매칭 안 됨:", { menuName, menu_type: menu.menu_type, url: menu.url, screen_id: menu.screen_id });
|
||||
toast.warning("이 메뉴에 할당된 화면이 없습니다. 메뉴 설정을 확인해주세요.");
|
||||
};
|
||||
|
||||
@@ -503,7 +504,8 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
||||
}
|
||||
if (activeTab.type === "screen") {
|
||||
if (activeTab.menuObjid != null && menuObjid === activeTab.menuObjid) return true;
|
||||
if (activeTab.screenId != null && menu.screenId === activeTab.screenId) return true;
|
||||
const { screenId: activeTabScreenId } = activeTab;
|
||||
if (activeTabScreenId != null && menu.screen_id === activeTabScreenId) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -91,8 +91,8 @@ interface ProfileModalProps {
|
||||
selectedImage: string;
|
||||
isSaving: boolean;
|
||||
departments: Array<{
|
||||
deptCode: string;
|
||||
deptName: string;
|
||||
dept_code: string;
|
||||
dept_name: string;
|
||||
}>;
|
||||
alertModal: {
|
||||
isOpen: boolean;
|
||||
@@ -233,7 +233,7 @@ export function ProfileModal({
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-full w-full items-center justify-center rounded-full bg-slate-200 text-2xl font-semibold text-slate-700">
|
||||
{formData.userName?.substring(0, 1)?.toUpperCase() || "U"}
|
||||
{formData.user_name?.substring(0, 1)?.toUpperCase() || "U"}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -284,8 +284,8 @@ export function ProfileModal({
|
||||
<Label htmlFor="userName">이름</Label>
|
||||
<Input
|
||||
id="userName"
|
||||
value={formData.userName}
|
||||
onChange={(e) => onFormChange("userName", e.target.value)}
|
||||
value={formData.user_name}
|
||||
onChange={(e) => onFormChange("user_name", e.target.value)}
|
||||
placeholder="이름을 입력하세요"
|
||||
/>
|
||||
</div>
|
||||
@@ -305,15 +305,15 @@ export function ProfileModal({
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="deptName">부서</Label>
|
||||
<Select value={formData.deptName} onValueChange={(value) => onFormChange("deptName", value)}>
|
||||
<Select value={formData.dept_name} onValueChange={(value) => onFormChange("dept_name", value)}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="부서 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{Array.isArray(departments) && departments.length > 0 ? (
|
||||
departments.map((department) => (
|
||||
<SelectItem key={department.deptCode} value={department.deptName}>
|
||||
{department.deptName}
|
||||
<SelectItem key={department.dept_code} value={department.dept_name}>
|
||||
{department.dept_name}
|
||||
</SelectItem>
|
||||
))
|
||||
) : (
|
||||
|
||||
@@ -183,7 +183,7 @@ export function TabBar() {
|
||||
const screens = await menuScreenApi.getScreensByMenu(numericObjid);
|
||||
if (screens.length > 0) {
|
||||
openTab(
|
||||
{ type: "screen", title: menuName, screenId: screens[0].screenId, menuObjid: numericObjid },
|
||||
{ type: "screen", title: menuName, screenId: screens[0].screen_id, menuObjid: numericObjid },
|
||||
insertIndex,
|
||||
);
|
||||
return;
|
||||
|
||||
@@ -238,19 +238,20 @@ function TabPageRenderer({
|
||||
tab: { id: string; type: string; screenId?: number; menuObjid?: number; adminUrl?: string };
|
||||
refreshKey: number;
|
||||
}) {
|
||||
const { screenId: tabScreenId } = tab;
|
||||
console.log("[TabPageRenderer] 탭 렌더링:", {
|
||||
tabId: tab.id,
|
||||
type: tab.type,
|
||||
screenId: tab.screenId,
|
||||
screenId: tabScreenId,
|
||||
adminUrl: tab.adminUrl,
|
||||
menuObjid: tab.menuObjid,
|
||||
});
|
||||
|
||||
if (tab.type === "screen" && tab.screenId != null) {
|
||||
if (tab.type === "screen" && tabScreenId != null) {
|
||||
return (
|
||||
<ScreenViewPageWrapper
|
||||
key={`${tab.id}-${refreshKey}`}
|
||||
screenIdProp={tab.screenId}
|
||||
screenIdProp={tabScreenId}
|
||||
menuObjidProp={tab.menuObjid}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
import { toast } from "sonner";
|
||||
|
||||
interface LinkedScreenInfo {
|
||||
screenId: number;
|
||||
screen_id: number;
|
||||
screenName: string;
|
||||
screenCode: string;
|
||||
references: Array<{
|
||||
@@ -42,7 +42,7 @@ interface LinkedScreenInfo {
|
||||
}
|
||||
|
||||
interface ScreenEntry {
|
||||
screenId: number;
|
||||
screen_id: number;
|
||||
screenName: string;
|
||||
newScreenName: string;
|
||||
newScreenCode: string;
|
||||
@@ -107,7 +107,7 @@ export function PopDeployModal({
|
||||
if (isGroupMode && groupScreens) {
|
||||
setGroupEntries(
|
||||
groupScreens.map((s) => ({
|
||||
screenId: s.screen_id ?? s.screenId,
|
||||
screen_id: s.screen_id!,
|
||||
screenName: s.screen_name ?? s.screenName,
|
||||
newScreenName: s.screen_name ?? s.screenName,
|
||||
newScreenCode: "",
|
||||
@@ -120,7 +120,7 @@ export function PopDeployModal({
|
||||
setScreenName(screen.screen_name ?? screen.screenName);
|
||||
setScreenCode("");
|
||||
setGroupEntries([]);
|
||||
analyzeLinks(screen.screen_id ?? screen.screenId);
|
||||
analyzeLinks(screen.screen_id!);
|
||||
}
|
||||
}, [open, screen, groupScreens, isGroupMode]);
|
||||
|
||||
@@ -169,13 +169,13 @@ export function PopDeployModal({
|
||||
const linked: LinkedScreenInfo[] = result.linkedScreenIds.map(
|
||||
(linkedId) => {
|
||||
const linkedScreen = allScreens.find(
|
||||
(s) => (s.screen_id ?? s.screenId) === linkedId,
|
||||
(s) => s.screen_id === linkedId,
|
||||
);
|
||||
const refs = result.references.filter(
|
||||
(r) => r.targetScreenId === linkedId,
|
||||
);
|
||||
return {
|
||||
screenId: linkedId,
|
||||
screen_id: linkedId,
|
||||
screenName: (linkedScreen?.screen_name ?? linkedScreen?.screenName) || `화면 ${linkedId}`,
|
||||
screenCode: (linkedScreen?.screen_code ?? linkedScreen?.screenCode) || "",
|
||||
references: refs.map((r) => ({
|
||||
@@ -211,7 +211,7 @@ export function PopDeployModal({
|
||||
screensToSend = groupEntries
|
||||
.filter((e) => e.included && e.newScreenCode)
|
||||
.map((e) => ({
|
||||
sourceScreenId: e.screenId,
|
||||
sourceScreenId: e.screen_id,
|
||||
screenName: e.newScreenName,
|
||||
screenCode: e.newScreenCode,
|
||||
}));
|
||||
@@ -219,14 +219,14 @@ export function PopDeployModal({
|
||||
if (!screen || !screenName || !screenCode) return;
|
||||
screensToSend = [
|
||||
{
|
||||
sourceScreenId: screen.screen_id ?? screen.screenId,
|
||||
sourceScreenId: screen.screen_id!,
|
||||
screenName,
|
||||
screenCode,
|
||||
},
|
||||
...linkedScreens
|
||||
.filter((ls) => ls.deploy)
|
||||
.map((ls) => ({
|
||||
sourceScreenId: ls.screenId,
|
||||
sourceScreenId: ls.screen_id,
|
||||
screenName: ls.newScreenName,
|
||||
screenCode: ls.newScreenCode,
|
||||
})),
|
||||
@@ -283,7 +283,7 @@ export function PopDeployModal({
|
||||
{isGroupMode
|
||||
? `"${groupName}" 카테고리의 화면 ${groupScreens!.length}개를 다른 회사로 복사합니다.`
|
||||
: screen
|
||||
? `"${screen.screen_name ?? screen.screenName}" (ID: ${screen.screen_id ?? screen.screenId}) 화면을 다른 회사로 복사합니다.`
|
||||
? `"${screen.screen_name ?? screen.screenName}" (ID: ${screen.screen_id}) 화면을 다른 회사로 복사합니다.`
|
||||
: "화면을 선택해주세요."}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
@@ -340,10 +340,10 @@ export function PopDeployModal({
|
||||
</div>
|
||||
{/* 메인 카테고리의 직접 화면 */}
|
||||
{groupEntries
|
||||
.filter((e) => groupInfo.screenIds.includes(e.screenId))
|
||||
.filter((e) => groupInfo.screenIds.includes(e.screen_id))
|
||||
.map((entry) => (
|
||||
<div
|
||||
key={entry.screenId}
|
||||
key={entry.screen_id}
|
||||
className="flex items-center gap-2 rounded p-1.5 pl-6 text-xs hover:bg-muted/50"
|
||||
>
|
||||
<Checkbox
|
||||
@@ -351,7 +351,7 @@ export function PopDeployModal({
|
||||
onCheckedChange={(checked) => {
|
||||
setGroupEntries((prev) =>
|
||||
prev.map((e) =>
|
||||
e.screenId === entry.screenId
|
||||
e.screen_id === entry.screen_id
|
||||
? { ...e, included: !!checked }
|
||||
: e,
|
||||
),
|
||||
@@ -363,7 +363,7 @@ export function PopDeployModal({
|
||||
{entry.screenName}
|
||||
</span>
|
||||
<span className="shrink-0 text-muted-foreground">
|
||||
#{entry.screenId}
|
||||
#{entry.screen_id}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -376,11 +376,11 @@ export function PopDeployModal({
|
||||
</div>
|
||||
{groupEntries
|
||||
.filter((e) =>
|
||||
child.screenIds.includes(e.screenId),
|
||||
child.screenIds.includes(e.screen_id),
|
||||
)
|
||||
.map((entry) => (
|
||||
<div
|
||||
key={entry.screenId}
|
||||
key={entry.screen_id}
|
||||
className="flex items-center gap-2 rounded p-1.5 pl-10 text-xs hover:bg-muted/50"
|
||||
>
|
||||
<Checkbox
|
||||
@@ -388,7 +388,7 @@ export function PopDeployModal({
|
||||
onCheckedChange={(checked) => {
|
||||
setGroupEntries((prev) =>
|
||||
prev.map((e) =>
|
||||
e.screenId === entry.screenId
|
||||
e.screen_id === entry.screen_id
|
||||
? { ...e, included: !!checked }
|
||||
: e,
|
||||
),
|
||||
@@ -400,7 +400,7 @@ export function PopDeployModal({
|
||||
{entry.screenName}
|
||||
</span>
|
||||
<span className="shrink-0 text-muted-foreground">
|
||||
#{entry.screenId}
|
||||
#{entry.screen_id}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -411,7 +411,7 @@ export function PopDeployModal({
|
||||
<div className="space-y-1">
|
||||
{groupEntries.map((entry) => (
|
||||
<div
|
||||
key={entry.screenId}
|
||||
key={entry.screen_id}
|
||||
className="flex items-center gap-2 rounded p-1.5 text-xs hover:bg-muted/50"
|
||||
>
|
||||
<Checkbox
|
||||
@@ -419,7 +419,7 @@ export function PopDeployModal({
|
||||
onCheckedChange={(checked) => {
|
||||
setGroupEntries((prev) =>
|
||||
prev.map((e) =>
|
||||
e.screenId === entry.screenId
|
||||
e.screen_id === entry.screen_id
|
||||
? { ...e, included: !!checked }
|
||||
: e,
|
||||
),
|
||||
@@ -431,7 +431,7 @@ export function PopDeployModal({
|
||||
{entry.screenName}
|
||||
</span>
|
||||
<span className="shrink-0 text-muted-foreground">
|
||||
#{entry.screenId}
|
||||
#{entry.screen_id}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -484,13 +484,13 @@ export function PopDeployModal({
|
||||
<div className="space-y-1.5">
|
||||
{linkedScreens.map((ls) => (
|
||||
<div
|
||||
key={ls.screenId}
|
||||
key={ls.screen_id}
|
||||
className="flex items-center justify-between rounded bg-background p-2 text-xs"
|
||||
>
|
||||
<div className="flex-1">
|
||||
<div className="font-medium">{ls.screenName}</div>
|
||||
<div className="text-muted-foreground">
|
||||
ID: {ls.screenId} |{" "}
|
||||
ID: {ls.screen_id} |{" "}
|
||||
{ls.references
|
||||
.map((r) => r.referenceType)
|
||||
.join(", ")}
|
||||
@@ -502,7 +502,7 @@ export function PopDeployModal({
|
||||
onCheckedChange={(checked) => {
|
||||
setLinkedScreens((prev) =>
|
||||
prev.map((item) =>
|
||||
item.screenId === ls.screenId
|
||||
item.screen_id === ls.screen_id
|
||||
? { ...item, deploy: !!checked }
|
||||
: item,
|
||||
),
|
||||
|
||||
@@ -46,7 +46,7 @@ export function PopScreenPreview({ screen, className }: PopScreenPreviewProps) {
|
||||
const checkLayout = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const layout = await screenApi.getLayoutPop(screen.screen_id ?? screen.screenId);
|
||||
const layout = await screenApi.getLayoutPop(screen.screen_id);
|
||||
|
||||
// v2 레이아웃: sections는 객체 (Record<string, PopSectionDefinition>)
|
||||
// v1 레이아웃: sections는 배열
|
||||
@@ -71,7 +71,7 @@ export function PopScreenPreview({ screen, className }: PopScreenPreviewProps) {
|
||||
}, [screen]);
|
||||
|
||||
// 미리보기 URL
|
||||
const previewUrl = screen ? `/pop/screens/${screen.screen_id ?? screen.screenId}?preview=true&device=${deviceType}` : null;
|
||||
const previewUrl = screen ? `/pop/screens/${screen.screen_id}?preview=true&device=${deviceType}` : null;
|
||||
|
||||
// 새 탭에서 열기
|
||||
const openInNewTab = () => {
|
||||
|
||||
@@ -114,7 +114,7 @@ export function PopScreenSettingModal({
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
const layout = await screenApi.getLayoutPop(screen.screen_id ?? screen.screenId);
|
||||
const layout = await screenApi.getLayoutPop(screen.screen_id);
|
||||
|
||||
if (layout && layout.subScreens) {
|
||||
setSubScreens(
|
||||
@@ -173,7 +173,7 @@ export function PopScreenSettingModal({
|
||||
|
||||
// screen_definitions 테이블에 화면명/설명 업데이트
|
||||
if (screenName !== (screen.screen_name ?? screen.screenName) || screenDescription !== (screen.description || "")) {
|
||||
await screenApi.updateScreenInfo(screen.screen_id ?? screen.screenId, {
|
||||
await screenApi.updateScreenInfo(screen.screen_id, {
|
||||
screenName,
|
||||
description: screenDescription,
|
||||
isActive: "Y",
|
||||
@@ -181,7 +181,7 @@ export function PopScreenSettingModal({
|
||||
}
|
||||
|
||||
// 레이아웃에 하위 화면 정보 저장
|
||||
const currentLayout = await screenApi.getLayoutPop(screen.screen_id ?? screen.screenId);
|
||||
const currentLayout = await screenApi.getLayoutPop(screen.screen_id);
|
||||
const updatedLayout = {
|
||||
...currentLayout,
|
||||
version: "pop-1.0",
|
||||
@@ -192,7 +192,7 @@ export function PopScreenSettingModal({
|
||||
})),
|
||||
};
|
||||
|
||||
await screenApi.saveLayoutPop(screen.screen_id ?? screen.screenId, updatedLayout);
|
||||
await screenApi.saveLayoutPop(screen.screen_id, updatedLayout);
|
||||
|
||||
toast.success("화면 설정이 저장되었습니다.");
|
||||
onSave?.(screenUpdate);
|
||||
|
||||
@@ -142,19 +142,19 @@ export default function PopViewerWithModals({
|
||||
|
||||
const unsubNavigate = subscribe("__pop_navigate__", (payload: unknown) => {
|
||||
const data = payload as {
|
||||
screenId?: string;
|
||||
screen_id?: string;
|
||||
params?: Record<string, string>;
|
||||
};
|
||||
|
||||
if (!data?.screenId) return;
|
||||
if (!data?.screen_id) return;
|
||||
|
||||
if (data.screenId === "back") {
|
||||
if (data.screen_id === "back") {
|
||||
router.back();
|
||||
} else {
|
||||
const query = data.params
|
||||
? "?" + new URLSearchParams(data.params).toString()
|
||||
: "";
|
||||
window.location.href = `/pop/screens/${data.screenId}${query}`;
|
||||
window.location.href = `/pop/screens/${data.screen_id}${query}`;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ interface LinkedModalScreen {
|
||||
}
|
||||
|
||||
interface CompanyInfo {
|
||||
companyCode: string;
|
||||
company_code: string;
|
||||
companyName: string;
|
||||
}
|
||||
|
||||
@@ -263,10 +263,10 @@ export default function CopyScreenModal({
|
||||
|
||||
// 원본 회사와 같은 회사가 선택되어 있으면 다른 회사로 변경
|
||||
if (sourceCompanyCode && targetCompanyCode === sourceCompanyCode) {
|
||||
const otherCompany = companies.find(c => c.companyCode !== sourceCompanyCode);
|
||||
const otherCompany = companies.find(c => c.company_code !== sourceCompanyCode);
|
||||
if (otherCompany) {
|
||||
console.log("🔄 원본 회사 선택됨 → 다른 회사로 자동 변경:", otherCompany.companyCode);
|
||||
setTargetCompanyCode(otherCompany.companyCode);
|
||||
console.log("🔄 원본 회사 선택됨 → 다른 회사로 자동 변경:", otherCompany.company_code);
|
||||
setTargetCompanyCode(otherCompany.company_code);
|
||||
}
|
||||
}
|
||||
}, [companies, isOpen, mode, sourceGroup, sourceScreen, targetCompanyCode]);
|
||||
@@ -317,7 +317,7 @@ export default function CopyScreenModal({
|
||||
const data = response.data.data || response.data || [];
|
||||
console.log("📋 회사 목록 데이터:", data);
|
||||
const mappedCompanies = data.map((c: any) => ({
|
||||
companyCode: c.company_code,
|
||||
company_code: c.company_code,
|
||||
companyName: c.company_name,
|
||||
}));
|
||||
console.log("📋 매핑된 회사 목록:", mappedCompanies);
|
||||
@@ -783,8 +783,8 @@ export default function CopyScreenModal({
|
||||
company_code: sourceGroupData.company_code || '',
|
||||
} as any;
|
||||
}
|
||||
return { screenId, displayOrder, screenRole, screenData };
|
||||
}).filter(item => item.screenData && item.screenId); // screenId가 유효한 것만
|
||||
return { screen_id: screenId, displayOrder, screenRole, screenData };
|
||||
}).filter(item => item.screenData && item.screen_id); // screen_id가 유효한 것만
|
||||
|
||||
// display_order 순으로 정렬
|
||||
screensWithOrder.sort((a, b) => (a.displayOrder || 0) - (b.displayOrder || 0));
|
||||
@@ -970,11 +970,11 @@ export default function CopyScreenModal({
|
||||
} else {
|
||||
console.log(` ❌ 화면 정보 없음: screenId=${screenId}, screenName=${screenName}`);
|
||||
}
|
||||
return { screenId, displayOrder, screenRole, screenData };
|
||||
}).filter(item => item.screenData && item.screenId); // screenId가 유효한 것만
|
||||
|
||||
return { screen_id: screenId, displayOrder, screenRole, screenData };
|
||||
}).filter(item => item.screenData && item.screen_id); // screen_id가 유효한 것만
|
||||
|
||||
console.log(`🔍 매핑 완료: ${screensWithOrder.length}개 화면 복사 예정`);
|
||||
screensWithOrder.forEach(item => console.log(` - ${item.screenId}: ${item.screenData?.screen_name}`));
|
||||
screensWithOrder.forEach(item => console.log(` - ${item.screen_id}: ${item.screenData?.screen_name}`));
|
||||
|
||||
// display_order 순으로 정렬
|
||||
screensWithOrder.sort((a, b) => (a.displayOrder || 0) - (b.displayOrder || 0));
|
||||
@@ -1532,10 +1532,10 @@ export default function CopyScreenModal({
|
||||
className="mt-1 flex h-8 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-xs ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 sm:h-10 sm:text-sm"
|
||||
>
|
||||
{companies
|
||||
.filter((company) => company.companyCode !== sourceGroup?.company_code)
|
||||
.filter((company) => company.company_code !== sourceGroup?.company_code)
|
||||
.map((company) => (
|
||||
<option key={company.companyCode} value={company.companyCode}>
|
||||
{company.companyName} ({company.companyCode})
|
||||
<option key={company.company_code} value={company.company_code}>
|
||||
{company.companyName} ({company.company_code})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
@@ -1758,9 +1758,9 @@ export default function CopyScreenModal({
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{companies
|
||||
.filter((company) => company.companyCode !== sourceScreen?.company_code)
|
||||
.filter((company) => company.company_code !== sourceScreen?.company_code)
|
||||
.map((company) => (
|
||||
<SelectItem key={company.companyCode} value={company.companyCode}>
|
||||
<SelectItem key={company.company_code} value={company.company_code}>
|
||||
{company.companyName}
|
||||
</SelectItem>
|
||||
))}
|
||||
|
||||
@@ -60,7 +60,7 @@ export default function CreateScreenModal({ open, onOpenChange, onCreated, isPop
|
||||
// 화면 코드 자동 생성
|
||||
const generateCode = async () => {
|
||||
try {
|
||||
const companyCode = (user as any)?.company_code || (user as any)?.companyCode || "*";
|
||||
const companyCode = (user as any)?.company_code || "*";
|
||||
const generatedCode = await screenApi.generateScreenCode(companyCode);
|
||||
setScreenCode(generatedCode);
|
||||
} catch (e) {
|
||||
@@ -220,7 +220,7 @@ export default function CreateScreenModal({ open, onOpenChange, onCreated, isPop
|
||||
if (!isValid || submitting) return;
|
||||
try {
|
||||
setSubmitting(true);
|
||||
const companyCode = (user as any)?.company_code || (user as any)?.companyCode || "*";
|
||||
const companyCode = (user as any)?.company_code || "*";
|
||||
|
||||
// 데이터 소스 타입에 따라 다른 정보 전달
|
||||
const createData: any = {
|
||||
@@ -248,9 +248,9 @@ export default function CreateScreenModal({ open, onOpenChange, onCreated, isPop
|
||||
const created = await screenApi.createScreen(createData);
|
||||
|
||||
// POP 모드일 경우 빈 POP 레이아웃 자동 생성
|
||||
if (isPop && created.screenId) {
|
||||
if (isPop && created.screen_id) {
|
||||
try {
|
||||
await screenApi.saveLayoutPop(created.screenId, {
|
||||
await screenApi.saveLayoutPop(created.screen_id, {
|
||||
version: "2.0",
|
||||
components: [],
|
||||
});
|
||||
|
||||
@@ -62,7 +62,8 @@ const findSaveButtonInComponents = (components: any[]): any | null => {
|
||||
// conditional-container의 sections 내부 탐색
|
||||
if (comp.componentType === "conditional-container" && comp.componentConfig?.sections) {
|
||||
for (const section of comp.componentConfig.sections) {
|
||||
if (section.screenId) {
|
||||
const { screenId: sectionScreenId } = section;
|
||||
if (sectionScreenId) {
|
||||
// 조건부 컨테이너의 내부 화면은 별도로 로드해야 함
|
||||
// 여기서는 null 반환하고, loadSaveButtonConfig에서 처리
|
||||
continue;
|
||||
@@ -203,19 +204,20 @@ export const EditModal: React.FC<EditModalProps> = ({ className }) => {
|
||||
for (const comp of layoutData.components) {
|
||||
if (comp.componentType === "conditional-container" && comp.componentConfig?.sections) {
|
||||
for (const section of comp.componentConfig.sections) {
|
||||
if (section.screenId) {
|
||||
const { screenId: sectionScreenId } = section;
|
||||
if (sectionScreenId) {
|
||||
try {
|
||||
const innerLayoutData = await screenApi.getLayout(section.screenId);
|
||||
const innerLayoutData = await screenApi.getLayout(sectionScreenId);
|
||||
saveButton = findSaveButtonInComponents(innerLayoutData?.components || []);
|
||||
if (saveButton) {
|
||||
// console.log("[EditModal] 조건부 컨테이너 내부에서 저장 버튼 발견:", {
|
||||
// sectionScreenId: section.screenId,
|
||||
// sectionScreenId: sectionScreenId,
|
||||
// sectionLabel: section.label,
|
||||
// });
|
||||
break;
|
||||
}
|
||||
} catch (innerError) {
|
||||
// console.warn("[EditModal] 내부 화면 레이아웃 조회 실패:", section.screenId);
|
||||
// console.warn("[EditModal] 내부 화면 레이아웃 조회 실패:", sectionScreenId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1205,7 +1205,7 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
|
||||
});
|
||||
|
||||
// SaveModal 열기 (등록 모드)
|
||||
const screenId = component.addModalConfig?.screenId;
|
||||
const screenId = component.addModalConfig?.screen_id;
|
||||
|
||||
if (!screenId) {
|
||||
toast.error("화면 설정이 필요합니다. 테이블 설정에서 추가 모달 화면을 지정해주세요.");
|
||||
@@ -1227,7 +1227,7 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
|
||||
|
||||
if (!selectedRowData) return;
|
||||
|
||||
const screenId = component.addModalConfig?.screenId;
|
||||
const screenId = component.addModalConfig?.screen_id;
|
||||
|
||||
if (!screenId) {
|
||||
toast.error("화면 설정이 필요합니다. 테이블 설정에서 수정 모달 화면을 지정해주세요.");
|
||||
|
||||
@@ -103,11 +103,11 @@ export const InteractiveScreenViewerDynamic: React.FC<InteractiveScreenViewerPro
|
||||
// 외부에서 전달받은 사용자 정보가 있으면 우선 사용 (ScreenModal 등에서)
|
||||
const userName = externalUserName || authUserName;
|
||||
const user =
|
||||
externalUserId && externalUserId !== authUser?.userId
|
||||
externalUserId && externalUserId !== authUser?.user_id
|
||||
? {
|
||||
userId: externalUserId,
|
||||
userName: externalUserName || authUserName || "",
|
||||
companyCode: externalCompanyCode || authUser?.companyCode || "",
|
||||
user_id: externalUserId,
|
||||
user_name: externalUserName || authUserName || "",
|
||||
company_code: externalCompanyCode || authUser?.company_code || "",
|
||||
isAdmin: authUser?.isAdmin || false,
|
||||
}
|
||||
: authUser;
|
||||
|
||||
@@ -32,9 +32,9 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, refr
|
||||
const [modalState, setModalState] = useState<ProfileModalState>({
|
||||
isOpen: false,
|
||||
formData: {
|
||||
userName: "",
|
||||
user_name: "",
|
||||
email: "",
|
||||
deptName: "",
|
||||
dept_name: "",
|
||||
positionName: "",
|
||||
locale: "",
|
||||
},
|
||||
@@ -155,9 +155,9 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, refr
|
||||
...prev,
|
||||
isOpen: true,
|
||||
formData: {
|
||||
userName: user.user_name || "",
|
||||
user_name: user.user_name || "",
|
||||
email: user.email || "",
|
||||
deptName: user.dept_name || "",
|
||||
dept_name: user.dept_name || "",
|
||||
positionName: user.position_name || "",
|
||||
locale: user.locale || "KR", // 기본값을 KR로 설정
|
||||
},
|
||||
@@ -416,7 +416,7 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, refr
|
||||
|
||||
// 사용자 정보 저장 데이터 준비
|
||||
const updateData: any = {
|
||||
userName: modalState.formData.userName,
|
||||
userName: modalState.formData.user_name,
|
||||
email: modalState.formData.email,
|
||||
locale: modalState.formData.locale,
|
||||
};
|
||||
@@ -432,7 +432,7 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, refr
|
||||
// 운전자 정보도 저장 (운전자인 경우)
|
||||
if (isDriver) {
|
||||
const driverResponse = await updateDriverProfile({
|
||||
userName: modalState.formData.userName,
|
||||
userName: modalState.formData.user_name,
|
||||
phoneNumber: driverFormData.phoneNumber,
|
||||
licenseNumber: driverFormData.licenseNumber,
|
||||
vehicleNumber: driverFormData.vehicleNumber,
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
*/
|
||||
|
||||
export interface ProfileFormData {
|
||||
userName: string;
|
||||
user_name: string;
|
||||
email: string;
|
||||
deptName: string;
|
||||
dept_name: string;
|
||||
positionName: string;
|
||||
locale: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user