forked from baron/baron-sso
Merge pull request '이슈 #868: 총괄기획실 우선순위 적용 및 슬러그 유추 로직 강화' (#889) from feature/issue-868-gpd-priority into dev
Reviewed-on: baron/baron-sso#889
This commit is contained in:
@@ -579,10 +579,37 @@ function suggestUniqueTenantSlug(value: string, tenants: TenantSummary[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function slugify(value: string) {
|
function slugify(value: string) {
|
||||||
return value
|
// 한글 조직명을 영어로 유추하거나 정규화하는 맵 (자주 쓰이는 단어)
|
||||||
.trim()
|
const commonMappings: Record<string, string> = {
|
||||||
|
총괄기획실: "gpd",
|
||||||
|
기술개발센터: "tdc",
|
||||||
|
경영기획: "planning",
|
||||||
|
영업: "sales",
|
||||||
|
인프라: "infra",
|
||||||
|
건설: "construction",
|
||||||
|
운영: "ops",
|
||||||
|
환경: "env",
|
||||||
|
사업: "biz",
|
||||||
|
본부: "hq",
|
||||||
|
부: "dept",
|
||||||
|
팀: "team",
|
||||||
|
지원: "support",
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = value.trim();
|
||||||
|
|
||||||
|
// 1. 전체 매칭 확인
|
||||||
|
if (commonMappings[result]) {
|
||||||
|
return commonMappings[result];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 부분 단어 치환 및 정규화
|
||||||
|
return result
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace(/[^a-z0-9가-힣ㄱ-ㅎㅏ-ㅣ]+/g, "-")
|
.replace(/[^a-z0-9가-힣ㄱ-ㅎㅏ-ㅣ]+/g, "-") // 특수문자 제거
|
||||||
|
.split("-")
|
||||||
|
.map((part) => commonMappings[part] || part) // 부분 단어 변환
|
||||||
|
.join("-")
|
||||||
.replace(/^-+|-+$/g, "");
|
.replace(/^-+|-+$/g, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { ScrollArea } from "../../../components/ui/scroll-area";
|
|||||||
import {
|
import {
|
||||||
type BulkUserItem,
|
type BulkUserItem,
|
||||||
type BulkUserResult,
|
type BulkUserResult,
|
||||||
|
type TenantSummary,
|
||||||
bulkCreateUsers,
|
bulkCreateUsers,
|
||||||
createTenant,
|
createTenant,
|
||||||
fetchAllTenants,
|
fetchAllTenants,
|
||||||
@@ -124,6 +125,19 @@ function hanmacEmailStatusClass(preview?: HanmacImportEmailPreview) {
|
|||||||
return "text-muted-foreground";
|
return "text-muted-foreground";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isUnderGeneralPlanningOffice(
|
||||||
|
tenantSlug: string,
|
||||||
|
tenants: TenantSummary[],
|
||||||
|
): boolean {
|
||||||
|
let current = tenants.find((t) => t.slug === tenantSlug);
|
||||||
|
while (current) {
|
||||||
|
if (current.name === "총괄기획실") return true;
|
||||||
|
if (!current.parentId) break;
|
||||||
|
current = tenants.find((t) => t.id === current?.parentId);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
export const downloadUserTemplate = () => {
|
export const downloadUserTemplate = () => {
|
||||||
const headers =
|
const headers =
|
||||||
"email,name,phone,role,tenant_slug,department,grade,position,jobTitle,employee_id,tenant_slug1,department1,grade1,position1,jobTitle1,employee_id1";
|
"email,name,phone,role,tenant_slug,department,grade,position,jobTitle,employee_id,tenant_slug1,department1,grade1,position1,jobTitle1,employee_id1";
|
||||||
@@ -278,10 +292,73 @@ export function UserBulkUploadModal({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return previewData.map((user, index) => {
|
return previewData.map((user, index) => {
|
||||||
const key = tenantImportKeyFromUser(user);
|
let finalUser = { ...user };
|
||||||
|
|
||||||
|
// [Issue 868] Swap logic for '총괄기획실' (General Planning Office)
|
||||||
|
// 만약 두 번째 테넌트가 '총괄기획실' 산하이고, 첫 번째 테넌트가 아니면 서로 맞바꿉니다.
|
||||||
|
if (
|
||||||
|
finalUser.additionalAppointments &&
|
||||||
|
finalUser.additionalAppointments.length > 0
|
||||||
|
) {
|
||||||
|
const firstAdditional = finalUser.additionalAppointments[0];
|
||||||
|
const secondarySlug = firstAdditional.tenantSlug;
|
||||||
|
|
||||||
|
if (
|
||||||
|
secondarySlug &&
|
||||||
|
isUnderGeneralPlanningOffice(secondarySlug, tenants)
|
||||||
|
) {
|
||||||
|
if (!isUnderGeneralPlanningOffice(finalUser.tenantSlug || "", tenants)) {
|
||||||
|
// Perform swap
|
||||||
|
const primary = {
|
||||||
|
tenantSlug: finalUser.tenantSlug,
|
||||||
|
tenantImport: finalUser.tenantImport,
|
||||||
|
department: finalUser.department,
|
||||||
|
grade: finalUser.grade,
|
||||||
|
position: finalUser.position,
|
||||||
|
jobTitle: finalUser.jobTitle,
|
||||||
|
employee_id: finalUser.metadata?.employee_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
finalUser.tenantSlug = firstAdditional.tenantSlug;
|
||||||
|
if (finalUser.tenantImport) {
|
||||||
|
finalUser.tenantImport = {
|
||||||
|
...finalUser.tenantImport,
|
||||||
|
slug: firstAdditional.tenantSlug || "",
|
||||||
|
name: firstAdditional.tenantName || firstAdditional.tenantSlug || "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
finalUser.department = firstAdditional.department;
|
||||||
|
finalUser.grade = firstAdditional.grade;
|
||||||
|
finalUser.position = firstAdditional.position;
|
||||||
|
finalUser.jobTitle = firstAdditional.jobTitle;
|
||||||
|
if (finalUser.metadata) {
|
||||||
|
finalUser.metadata.employee_id =
|
||||||
|
firstAdditional.metadata?.employee_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
finalUser.additionalAppointments = [
|
||||||
|
{
|
||||||
|
...firstAdditional,
|
||||||
|
tenantSlug: primary.tenantSlug,
|
||||||
|
department: primary.department,
|
||||||
|
grade: primary.grade,
|
||||||
|
position: primary.position,
|
||||||
|
jobTitle: primary.jobTitle,
|
||||||
|
metadata: {
|
||||||
|
...firstAdditional.metadata,
|
||||||
|
employee_id: primary.employee_id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...finalUser.additionalAppointments.slice(1),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = tenantImportKeyFromUser(finalUser);
|
||||||
const resolvedTenant = key ? tenantByKey.get(key) : undefined;
|
const resolvedTenant = key ? tenantByKey.get(key) : undefined;
|
||||||
const emailPreview = hanmacEmailPreviews[index];
|
const emailPreview = hanmacEmailPreviews[index];
|
||||||
const { tenantImport: _tenantImport, ...payload } = user;
|
const { tenantImport: _tenantImport, ...payload } = finalUser;
|
||||||
return {
|
return {
|
||||||
...payload,
|
...payload,
|
||||||
email: emailPreview?.finalEmail ?? payload.email,
|
email: emailPreview?.finalEmail ?? payload.email,
|
||||||
|
|||||||
Reference in New Issue
Block a user