Open kirin-ri opened 1 month ago
import React, { useEffect, useState, useLayoutEffect } from 'react';
import { commonAjax } from '../../../components/commonAjax';
import { Spacer } from '../spacer';
import * as Defs from './apiDefs';
import ApiUpdateResultModal from './apiUpdateResultModal';
import CreateNewApi from './createNewApi';
import EditApiList from './editApiList';
import NewAPIDtlModal from './newAPIDtlModal';
import NewSampleDataModal from './newSampleDataModal';
import SelectDeployApi from './selectDeployApi';
import { DialogModalOK, hideDialog, showDialog } from './dialogModal';
import { Link } from 'react-router-dom';
// main
function NewApiList() {
// useState
const [apiList, setApiList] = useState<Defs.Api[]>([]);
const [tagList, setTags] = useState<Defs.Tag[]>([]);
const [changeStatus, setChangeStatus] = useState<boolean>(false);
const [enableDplApi, setEnableDplApi] = useState<boolean>(false);
const [errorMsg, setErrorMsg] = useState<{}>({});
const [deployJobId, setDeployJobId] = useState<string>('');
const [isModalOpen, setIsModalOpen] = useState(false);
const [expandedApis, setExpandedApis] = useState<Set<string>>(new Set()); // 记录展开状态
/* API情報取得のリクエスト */
useEffect(() => {
(async () => {
commonAjax
.axios({ swalFire: false, loading: true })
.get('/api/api')
.then((res) => {
const data = res.data.api;
const resTags: React.SetStateAction<Defs.Tag[]> = [];
let tmpTags: string[] = [];
data.map((item: any) => {
tmpTags = tmpTags.concat(item.tags);
});
tmpTags = Array.from(new Set(tmpTags));
tmpTags.map((t: string) => {
resTags.push({ tag_name: t, select: false }); // 初期设为 false
});
setApiList(data);
setTags(resTags);
setEnableDplApi(res.data.enableDplApi);
});
})();
}, [changeStatus]);
useLayoutEffect(() => {
if (deployJobId) {
// ジョブ開始ダイアログ表示
showDialog('api-deploy-job-start-notification');
}
}, [deployJobId]);
// 标签切换时重置展开状态
const handleTagChange = (updatedTags: Defs.Tag[]) => {
setTags(updatedTags);
setExpandedApis(new Set()); // 重置展开的API状态,收起所有
};
const metricsProcess = process.env.REACT_APP_METRICS_PROCESS;
const title = `${metricsProcess} データセット一覧`;
return (
<div className="content-wrapper api-list">
<section className="page-cover">
<h1>{title}</h1>
</section>
{/* Content Header (Page header) */}
<section className="content-header">
<div className="content-header-left">
<h1>{title}</h1>
<div className="content-header-desc">
現在、設定されているデータセット一覧です
</div>
</div>
{enableDplApi && (
<div className="content-header-right">
<button
type="button"
className="btn btn-secondary"
data-toggle="modal"
data-target="#editApiListModal"
onClick={() => {
setIsModalOpen(true);
}}
>
編集
</button>
<button
type="button"
className="btn btn-primary"
data-toggle="modal"
data-target="#api-dtl-modal"
onClick={() => {
setIsModalOpen(true);
}}
>
追加
</button>
<button
type="button"
className="btn-long-text btn-primary"
data-toggle="modal"
data-target="#selectDeployApiModal"
onClick={() => {
setIsModalOpen(true);
}}
>
一括有効化
</button>
</div>
)}
</section>
<section className="content">
{/* filter tag */}
<div className="inline-form">
<div className="inline-form-cat">フィルタータグ</div>
{FilterTags(tagList, handleTagChange)}
</div>
{Spacer({ size: 30 })}
{/* API List (Grid) */}
{viewList(
apiList,
tagList,
changeStatus,
setChangeStatus,
setErrorMsg,
errorMsg,
setDeployJobId,
expandedApis,
setExpandedApis // 传递展开状态控制函数
)}
</section>
{isModalOpen && (
<>
<CreateNewApi
changeStatus={changeStatus}
setChangeStatus={setChangeStatus}
/>
<EditApiList
val={apiList}
changeStatus={changeStatus}
setChangeStatus={setChangeStatus}
/>
<SelectDeployApi
val={apiList}
changeStatus={changeStatus}
setChangeStatus={setChangeStatus}
/>
</>
)}
<ApiDeployJobStartNotification jobId={deployJobId} />
</div>
);
}
// filter tags 逻辑修改
function FilterTags(tags: Defs.Tag[], handleTagChange: (updatedTags: Defs.Tag[]) => void) {
return (
<div className="inline-form-group">
<div className="inline-form-label">分類</div>
{tags.map((item: Defs.Tag) => (
<div
className={`btn btn-tag ${item.select ? 'active' : ''}`}
key={item.tag_name}
onClick={() => {
item.select = !item.select; // 切换选择状态
const t = tags.slice(0, tags.length);
handleTagChange(t); // 标签切换时重置展开状态
}}
>
{item.tag_name}
</div>
))}
</div>
);
}
// 过滤显示逻辑修改
function viewList(
apiList: Defs.Api[],
tagList: Defs.Tag[],
changeStatus: boolean,
setChangeStatus: any,
setErrorMsg: any,
errorMsg: any,
setDeployJobId: any,
expandedApis: Set<string>, // 展开的API状态
setExpandedApis: React.Dispatch<React.SetStateAction<Set<string>>>, // 控制展开状态的函数
) {
let filteredList = apiList;
// 检查是否有选中的标签
const selectedTags = tagList.filter((tag) => tag.select).map((tag) => tag.tag_name);
// 如果有选中的标签,按标签过滤API列表
if (selectedTags.length > 0) {
filteredList = apiList.filter((api) =>
api.tags.some((tag) => selectedTags.includes(tag)),
);
}
const length = Math.ceil(filteredList.length / 3);
let listItem: any = [];
if (length != 0) {
listItem = transpose(
new Array(length).fill(0).map((_, i) => filteredList.slice(i * 3, (i + 1) * 3)),
);
}
return (
<div className="list-wrapper">
<div className="apiList">
{0 >= 0 && listItem.length > 0
? listItem[0].map((val: Defs.Api) =>
ApiCard(
val,
tagList,
changeStatus,
setChangeStatus,
setErrorMsg,
errorMsg,
setDeployJobId,
expandedApis,
setExpandedApis // 传递展开状态控制函数
),
)
: null}
</div>
<div className="apiList">
{1 >= 0 && listItem.length > 1
? listItem[1].map((val: Defs.Api) =>
ApiCard(
val,
tagList,
changeStatus,
setChangeStatus,
setErrorMsg,
errorMsg,
setDeployJobId,
expandedApis,
setExpandedApis // 传递展开状态控制函数
),
)
: null}
</div>
<div className="apiList">
{2 >= 0 && listItem.length > 2
? listItem[2].map((val: Defs.Api) =>
ApiCard(
val,
tagList,
changeStatus,
setChangeStatus,
setErrorMsg,
errorMsg,
setDeployJobId,
expandedApis,
setExpandedApis // 传递展开状态控制函数
),
)
: null}
</div>
</div>
);
}
// API Card
function ApiCard(
api: Defs.Api,
tagList: Defs.Tag[],
changeStatus: boolean,
setChangeStatus: any,
setErrorMsg: any,
errorMsg: any,
setDeployJobId: any,
expandedApis: Set<string>, // 传入已展开的API
setExpandedApis: React.Dispatch<React.SetStateAction<Set<string>>>, // 控制展开状态的函数
) {
let selected = false;
// 检查是否有选中的标签
const selectedTags = tagList.filter((tag) => tag.select).map((tag) => tag.tag_name);
// 如果没有选中的标签,默认所有API都被选中显示
if (selectedTags.length === 0) {
selected = true;
} else {
// 否则根据标签选择状态来决定是否显示灰色
api.tags.forEach((apiTag: string) => {
tagList.forEach((item: Defs.Tag) => {
if (apiTag === item.tag_name && item.select) {
selected = true;
}
});
});
}
// 切换展开状态
const toggleExpand = () => {
const newExpandedApis = new Set(expandedApis);
if (newExpandedApis.has(api.physical_name)) {
newExpandedApis.delete(api.physical_name);
} else {
newExpandedApis.add(api.physical_name);
}
setExpandedApis(newExpandedApis);
};
const isExpanded = expandedApis.has(api.physical_name); // 当前API是否已展开
return (
<div
className={`card ${
selected ? 'card-primary' : 'card-not-applicable not-applicable'
} card-collapse-sample`}
>
<div
className={`card-header ${isExpanded ? '' : 'collapsed'}`}
data-toggle="collapse"
data-target={`#card-body-${api.physical_name}`}
onClick={toggleExpand} // 点击时切换展开状态
>
<div
className="api-name-font"
style={{
fontSize: `clamp(0.6rem, ${
29 / `${api.physical_name} / ${api.logical_name}`.length
}vw, 1rem)`,
}}
>
<i
className={`fa fa-circle provide-icon-size ${
selected
? api.provide
? 'provide-icon-color'
: 'no-provide-icon-color'
: ''
}`}
aria-hidden="true"
/>
{Spacer({ size: 10, horizontal: true })}
{`${api.physical_name} / ${api.logical_name}`}
</div>
</div>
<div className={`card-body collapse ${isExpanded ? 'show' : ''}`} id={`card-body-${api.physical_name}`}>
<div className="api-list-title">
<p>データセット 連携項目 一覧</p>
{Spacer({ size: 20 })}
</div>
{api.outinfo.map((val: Defs.TableInfo) => {
return val.column.map((item: Defs.Column) => (
<div className="list-contents-grid" key={item.physicalName}>
<p>{item.logicalName}</p>
</div>
));
})}
{Spacer({ size: 20 })}
<div className="text-danger error-msg">
{errorMsg[api.physical_name]}
</div>
<br />
{api.provide ? (
<>
<div className="btn-center">
<button
className="btn btn-secondary btn-secondary"
data-toggle="modal"
data-target={`#${api.physical_name}-dtl-modal`} // 确保 modal 的 target id 绑定正确
data-backdrop="true"
>
サンプルデータ挿入 / データセット連携項目追加
</button>
</div>
</>
) : (
<div className="btn-center">
<button
className="btn btn-secondary btn-secondary"
onClick={() => {
putDeploy(
api,
changeStatus,
setChangeStatus,
setErrorMsg,
setDeployJobId,
);
}}
>
有効化
</button>
</div>
)}
</div>
</div>
);
}
// main
function NewApiList() {
// useState
const [apiList, setApiList] = useState<Defs.Api[]>([]);
const [tagList, setTags] = useState<Defs.Tag[]>([]);
const [changeStatus, setChangeStatus] = useState<boolean>(false);
const [enableDplApi, setEnableDplApi] = useState<boolean>(false);
const [errorMsg, setErrorMsg] = useState<{}>({});
const [deployJobId, setDeployJobId] = useState<string>('');
const [isModalOpen, setIsModalOpen] = useState(false);
const [expandedApis, setExpandedApis] = useState<Set<string>>(new Set()); // 记录展开状态
/* API情報取得のリクエスト */
useEffect(() => {
(async () => {
commonAjax
.axios({ swalFire: false, loading: true })
.get('/api/api')
.then((res) => {
const data = res.data.api;
const resTags: React.SetStateAction<Defs.Tag[]> = [];
let tmpTags: string[] = [];
data.map((item: any) => {
tmpTags = tmpTags.concat(item.tags);
});
tmpTags = Array.from(new Set(tmpTags));
tmpTags.map((t: string) => {
resTags.push({ tag_name: t, select: false }); // 初期设为 false
});
setApiList(data);
setTags(resTags);
setEnableDplApi(res.data.enableDplApi);
});
})();
}, [changeStatus]);
useLayoutEffect(() => {
if (deployJobId) {
// ジョブ開始ダイアログ表示
showDialog('api-deploy-job-start-notification');
}
}, [deployJobId]);
// 标签切换时重置展开状态,确保所有卡片收起
const handleTagChange = (updatedTags: Defs.Tag[]) => {
setTags(updatedTags);
setExpandedApis(new Set()); // 重置展开的API状态,收起所有
};
const metricsProcess = process.env.REACT_APP_METRICS_PROCESS;
const title = `${metricsProcess} データセット一覧`;
return (
<div className="content-wrapper api-list">
<section className="page-cover">
<h1>{title}</h1>
</section>
{/* Content Header (Page header) */}
<section className="content-header">
<div className="content-header-left">
<h1>{title}</h1>
<div className="content-header-desc">
現在、設定されているデータセット一覧です
</div>
</div>
{enableDplApi && (
<div className="content-header-right">
<button
type="button"
className="btn btn-secondary"
data-toggle="modal"
data-target="#editApiListModal"
onClick={() => {
setIsModalOpen(true);
}}
>
編集
</button>
<button
type="button"
className="btn btn-primary"
data-toggle="modal"
data-target="#api-dtl-modal"
onClick={() => {
setIsModalOpen(true);
}}
>
追加
</button>
<button
type="button"
className="btn-long-text btn-primary"
data-toggle="modal"
data-target="#selectDeployApiModal"
onClick={() => {
setIsModalOpen(true);
}}
>
一括有効化
</button>
</div>
)}
</section>
<section className="content">
{/* filter tag */}
<div className="inline-form">
<div className="inline-form-cat">フィルタータグ</div>
{FilterTags(tagList, handleTagChange)}
</div>
{Spacer({ size: 30 })}
{/* API List (Grid) */}
{viewList(
apiList,
tagList,
changeStatus,
setChangeStatus,
setErrorMsg,
errorMsg,
setDeployJobId,
expandedApis,
setExpandedApis // 传递展开状态控制函数
)}
</section>
{isModalOpen && (
<>
<CreateNewApi
changeStatus={changeStatus}
setChangeStatus={setChangeStatus}
/>
<EditApiList
val={apiList}
changeStatus={changeStatus}
setChangeStatus={setChangeStatus}
/>
<SelectDeployApi
val={apiList}
changeStatus={changeStatus}
setChangeStatus={setChangeStatus}
/>
</>
)}
<ApiDeployJobStartNotification jobId={deployJobId} />
</div>
);
}
// filter tags 逻辑修改
function FilterTags(tags: Defs.Tag[], handleTagChange: (updatedTags: Defs.Tag[]) => void) {
return (
<div className="inline-form-group">
<div className="inline-form-label">分類</div>
{tags.map((item: Defs.Tag) => (
<div
className={`btn btn-tag ${item.select ? 'active' : ''}`}
key={item.tag_name}
onClick={() => {
item.select = !item.select; // 切换选择状态
const t = tags.slice(0, tags.length);
handleTagChange(t); // 标签切换时重置展开状态
}}
>
{item.tag_name}
</div>
))}
</div>
);
}
// 过滤显示逻辑修改
function viewList(
apiList: Defs.Api[],
tagList: Defs.Tag[],
changeStatus: boolean,
setChangeStatus: any,
setErrorMsg: any,
errorMsg: any,
setDeployJobId: any,
expandedApis: Set<string>, // 展开的API状态
setExpandedApis: React.Dispatch<React.SetStateAction<Set<string>>>, // 控制展开状态的函数
) {
let filteredList = apiList;
// 检查是否有选中的标签
const selectedTags = tagList.filter((tag) => tag.select).map((tag) => tag.tag_name);
// 如果有选中的标签,按标签过滤API列表
if (selectedTags.length > 0) {
filteredList = apiList.filter((api) =>
api.tags.some((tag) => selectedTags.includes(tag)),
);
}
const length = Math.ceil(filteredList.length / 3);
let listItem: any = [];
if (length != 0) {
listItem = transpose(
new Array(length).fill(0).map((_, i) => filteredList.slice(i * 3, (i + 1) * 3)),
);
}
return (
<div className="list-wrapper">
<div className="apiList">
{0 >= 0 && listItem.length > 0
? listItem[0].map((val: Defs.Api) =>
ApiCard(
val,
tagList,
changeStatus,
setChangeStatus,
setErrorMsg,
errorMsg,
setDeployJobId,
expandedApis,
setExpandedApis // 传递展开状态控制函数
),
)
: null}
</div>
<div className="apiList">
{1 >= 0 && listItem.length > 1
? listItem[1].map((val: Defs.Api) =>
ApiCard(
val,
tagList,
changeStatus,
setChangeStatus,
setErrorMsg,
errorMsg,
setDeployJobId,
expandedApis,
setExpandedApis // 传递展开状态控制函数
),
)
: null}
</div>
<div className="apiList">
{2 >= 0 && listItem.length > 2
? listItem[2].map((val: Defs.Api) =>
ApiCard(
val,
tagList,
changeStatus,
setChangeStatus,
setErrorMsg,
errorMsg,
setDeployJobId,
expandedApis,
setExpandedApis // 传递展开状态控制函数
),
)
: null}
</div>
</div>
);
}
// API Card
function ApiCard(
api: Defs.Api,
tagList: Defs.Tag[],
changeStatus: boolean,
setChangeStatus: any,
setErrorMsg: any,
errorMsg: any,
setDeployJobId: any,
expandedApis: Set<string>, // 传入已展开的API
setExpandedApis: React.Dispatch<React.SetStateAction<Set<string>>>, // 控制展开状态的函数
) {
let selected = false;
// 检查是否有选中的标签
const selectedTags = tagList.filter((tag) => tag.select).map((tag) => tag.tag_name);
// 如果没有选中的标签,默认所有API都被选中显示
if (selectedTags.length === 0) {
selected = true;
} else {
// 否则根据标签选择状态来决定是否显示灰色
api.tags.forEach((apiTag: string) => {
tagList.forEach((item: Defs.Tag) => {
if (apiTag === item.tag_name && item.select) {
selected = true;
}
});
});
}
// 切换展开状态
const toggleExpand = () => {
const newExpandedApis = new Set(expandedApis);
if (newExpandedApis.has(api.physical_name)) {
newExpandedApis.delete(api.physical_name);
} else {
newExpandedApis.add(api.physical_name);
}
setExpandedApis(newExpandedApis);
};
const isExpanded = expandedApis.has(api.physical_name); // 当前API是否已展开
return (
<div
className={`card ${
selected ? 'card-primary' : 'card-not-applicable not-applicable'
} card-collapse-sample`}
>
<div
className={`card-header ${isExpanded ? '' : 'collapsed'}`}
data-toggle="collapse"
data-target={`#card-body-${api.physical_name}`}
onClick={toggleExpand} // 点击时切换展开状态
>
<div
className="api-name-font"
style={{
fontSize: `clamp(0.6rem, ${
29 / `${api.physical_name} / ${api.logical_name}`.length
}vw, 1rem)`,
}}
>
<i
className={`fa fa-circle provide-icon-size ${
selected
? api.provide
? 'provide-icon-color'
: 'no-provide-icon-color'
: ''
}`}
aria-hidden="true"
/>
{Spacer({ size: 10, horizontal: true })}
{`${api.physical_name} / ${api.logical_name}`}
</div>
</div>
<div className={`card-body collapse ${isExpanded ? 'show' : ''}`} id={`card-body-${api.physical_name}`}>
<div className="api-list-title">
<p>データセット 連携項目 一覧</p>
{Spacer({ size: 20 })}
</div>
{api.outinfo.map((val: Defs.TableInfo) => {
return val.column.map((item: Defs.Column) => (
<div className="list-contents-grid" key={item.physicalName}>
<p>{item.logicalName}</p>
</div>
));
})}
{Spacer({ size: 20 })}
<div className="text-danger error-msg">
{errorMsg[api.physical_name]}
</div>
<br />
{api.provide ? (
<>
<div className="btn-center">
<button
className="btn btn-secondary btn-secondary"
data-toggle="modal"
data-target={`#${api.physical_name}-dtl-modal`} // 确保 modal 的 target id 绑定正确
data-backdrop="true"
>
サンプルデータ挿入 / データセット連携項目追加
</button>
</div>
</>
) : (
<div className="btn-center">
<button
className="btn btn-secondary btn-secondary"
onClick={() => {
putDeploy(
api,
changeStatus,
setChangeStatus,
setErrorMsg,
setDeployJobId,
);
}}
>
有効化
</button>
</div>
)}
</div>
</div>
);
}
import React, { useEffect, useLayoutEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { commonAjax } from '../../../components/commonAjax';
import { Spacer } from '../spacer';
import * as Defs from './apiDefs';
import ApiUpdateResultModal from './apiUpdateResultModal';
import CreateNewApi from './createNewApi';
import { DialogModalOK, hideDialog, showDialog } from './dialogModal';
import EditApiList from './editApiList';
import NewAPIDtlModal from './newAPIDtlModal';
import NewSampleDataModal from './newSampleDataModal';
import SelectDeployApi from './selectDeployApi';
function NewApiList() {
// useState
const [apiList, setApiList] = useState<Defs.Api[]>([]);
const [tagList, setTags] = useState<Defs.Tag[]>([]);
const [changeStatus, setChangeStatus] = useState<boolean>(false);
const [enableDplApi, setEnableDplApi] = useState<boolean>(false);
const [errorMsg, setErrorMsg] = useState<{}>({});
const [deployJobId, setDeployJobId] = useState<string>('');
const [isModalOpen, setIsModalOpen] = useState(false);
/* API情報取得のリクエスト */
useEffect(() => {
(async () => {
commonAjax
.axios({ swalFire: false, loading: true })
.get('/api/api')
.then((res) => {
const data = res.data.api;
const resTags: React.SetStateAction<Defs.Tag[]> = [];
let tmpTags: string[] = [];
data.map((item: any) => {
tmpTags = tmpTags.concat(item.tags);
});
tmpTags = Array.from(new Set(tmpTags));
tmpTags.map((t: string) => {
resTags.push({ tag_name: t, select: false }); // 初期设为 false
});
setApiList(data);
setTags(resTags);
setEnableDplApi(res.data.enableDplApi);
});
})();
}, [changeStatus]);
useLayoutEffect(() => {
if (deployJobId) {
// ジョブ開始ダイアログ表示
showDialog('api-deploy-job-start-notification');
}
}, [deployJobId]);
const metricsProcess = process.env.REACT_APP_METRICS_PROCESS;
const title = `${metricsProcess} データセット一覧`;
return (
<div className="content-wrapper api-list">
<section className="page-cover">
<h1>{title}</h1>
</section>
{/* Content Header (Page header) */}
<section className="content-header">
<div className="content-header-left">
<h1>{title}</h1>
<div className="content-header-desc">
現在、設定されているデータセット一覧です
</div>
</div>
{enableDplApi && (
<div className="content-header-right">
<button
type="button"
className="btn btn-secondary"
data-toggle="modal"
data-target="#editApiListModal"
onClick={() => {
setIsModalOpen(true);
}}
>
編集
</button>
<button
type="button"
className="btn btn-primary"
data-toggle="modal"
data-target="#api-dtl-modal"
onClick={() => {
setIsModalOpen(true);
}}
>
追加
</button>
<button
type="button"
className="btn-long-text btn-primary"
data-toggle="modal"
data-target="#selectDeployApiModal"
onClick={() => {
setIsModalOpen(true);
}}
>
一括有効化
</button>
</div>
)}
</section>
<section className="content">
{/* filter tag */}
<div className="inline-form">
<div className="inline-form-cat">フィルタータグ</div>
{FilterTags(tagList, setTags)}
</div>
{Spacer({ size: 30 })}
{/* API List (Grid) */}
{viewList(
apiList,
tagList,
changeStatus,
setChangeStatus,
setErrorMsg,
errorMsg,
setDeployJobId,
)}
</section>
{isModalOpen && (
<>
<CreateNewApi
changeStatus={changeStatus}
setChangeStatus={setChangeStatus}
/>
<EditApiList
val={apiList}
changeStatus={changeStatus}
setChangeStatus={setChangeStatus}
/>
<SelectDeployApi
val={apiList}
changeStatus={changeStatus}
setChangeStatus={setChangeStatus}
/>
</>
)}
<ApiDeployJobStartNotification jobId={deployJobId} />
</div>
);
}
// filter tags 逻辑修改
function FilterTags(tags: Defs.Tag[], setTags: any) {
return (
<div className="inline-form-group">
<div className="inline-form-label">分類</div>
{tags.map((item: Defs.Tag) => (
<div
className={`btn btn-tag ${item.select ? 'active' : ''}`}
key={item.tag_name}
onClick={() => {
item.select = !item.select; // 切换选择状态
const t = tags.slice(0, tags.length);
setTags(t);
}}
>
{item.tag_name}
</div>
))}
</div>
);
}
// 过滤显示逻辑修改
function viewList(
apiList: Defs.Api[],
tagList: Defs.Tag[],
changeStatus: boolean,
setChangeStatus: any,
setErrorMsg: any,
errorMsg: any,
setDeployJobId: any,
) {
let filteredList = apiList;
// 检查是否有选中的标签
const selectedTags = tagList.filter((tag) => tag.select).map((tag) => tag.tag_name);
// 如果有选中的标签,按标签过滤API列表
if (selectedTags.length > 0) {
filteredList = apiList.filter((api) =>
api.tags.some((tag) => selectedTags.includes(tag)),
);
}
// 渲染所有 Modal 保证初始化
const modals = apiList.map((val) => (
<>
<NewAPIDtlModal val={val} />
<NewSampleDataModal
id={val.physical_name}
logicalName={val.logical_name}
/>
<ApiUpdateResultModal val={val} />
</>
));
const length = Math.ceil(filteredList.length / 3);
let listItem: any = [];
if (length != 0) {
listItem = transpose(
new Array(length).fill(0).map((_, i) => filteredList.slice(i * 3, (i + 1) * 3)),
);
}
return (
<div className="list-wrapper">
<div className="apiList">
{0 >= 0 && listItem.length > 0
? listItem[0].map((val: Defs.Api) =>
ApiCard(
val,
tagList,
changeStatus,
setChangeStatus,
setErrorMsg,
errorMsg,
setDeployJobId,
),
)
: null}
</div>
<div className="apiList">
{1 >= 0 && listItem.length > 1
? listItem[1].map((val: Defs.Api) =>
ApiCard(
val,
tagList,
changeStatus,
setChangeStatus,
setErrorMsg,
errorMsg,
setDeployJobId,
),
)
: null}
</div>
<div className="apiList">
{2 >= 0 && listItem.length > 2
? listItem[2].map((val: Defs.Api) =>
ApiCard(
val,
tagList,
changeStatus,
setChangeStatus,
setErrorMsg,
errorMsg,
setDeployJobId,
),
)
: null}
</div>
{/* 渲染所有 Modal */}
{modals}
</div>
);
}
// API Card
// API Card
function ApiCard(
api: Defs.Api,
tagList: Defs.Tag[],
changeStatus: boolean,
setChangeStatus: any,
setErrorMsg: any,
errorMsg: any,
setDeployJobId: any,
) {
let selected = false;
// 检查是否有选中的标签
const selectedTags = tagList.filter((tag) => tag.select).map((tag) => tag.tag_name);
// 如果没有选中的标签,默认所有API都被选中显示
if (selectedTags.length === 0) {
selected = true;
} else {
// 否则根据标签选择状态来决定是否显示灰色
api.tags.forEach((apiTag: string) => {
tagList.forEach((item: Defs.Tag) => {
if (apiTag === item.tag_name && item.select) {
selected = true;
}
});
});
}
// 确保未被选中时,仍可以打开 modal
if (!errorMsg) {
$(`#${api.physical_name}`).collapse('hide');
}
return (
<div
className={`card ${
selected ? 'card-primary' : 'card-not-applicable not-applicable'
} card-collapse-sample`}
>
<div
className="card-header collapsed"
data-toggle="collapse"
data-target={`#card-body-${api.physical_name}`}
>
<div
className="api-name-font"
style={{
fontSize: `clamp(0.6rem, ${
29 / `${api.physical_name} / ${api.logical_name}`.length
}vw, 1rem)`,
}}
>
<i
className={`fa fa-circle provide-icon-size ${
selected
? api.provide
? 'provide-icon-color'
: 'no-provide-icon-color'
: ''
}`}
aria-hidden="true"
/>
{Spacer({ size: 10, horizontal: true })}
{`${api.physical_name} / ${api.logical_name}`}
</div>
</div>
<div className="card-body collapse" id={`card-body-${api.physical_name}`}>
<div className="api-list-title">
<p>データセット 連携項目 一覧</p>
{Spacer({ size: 20 })}
</div>
{api.outinfo.map((val: Defs.TableInfo) => {
return val.column.map((item: Defs.Column) => (
<div className="list-contents-grid" key={item.physicalName}>
<p>{item.logicalName}</p>
</div>
));
})}
{Spacer({ size: 20 })}
<div className="text-danger error-msg">
{errorMsg[api.physical_name]}
</div>
<br />
{api.provide ? (
<>
<div className="btn-center">
<button
className="btn btn-secondary btn-secondary"
data-toggle="modal"
data-target={`#${api.physical_name}-dtl-modal`} // 确保 modal 的 target id 绑定正确
data-backdrop="true"
>
サンプルデータ挿入 / データセット連携項目追加
</button>
</div>
</>
) : (
<div className="btn-center">
<button
className="btn btn-secondary btn-secondary"
onClick={() => {
putDeploy(
api,
changeStatus,
setChangeStatus,
setErrorMsg,
setDeployJobId,
);
}}
>
有効化
</button>
</div>
)}
</div>
</div>
);
}
// transpose columns and rows
const transpose = (a: any[]) =>
a[0].map((_: any, c: string | number) => a.map((r) => r[c]).filter(Boolean));
// put api(deploy)
function putDeploy(
api: Defs.Api,
changeStatus: boolean,
setChangeStatus: any,
setErrorMsg: any,
setDeployJobId: any,
) {
if (api) {
if (!api.provide) {
(async () => {
const errorMsgList: { [key: string]: string } = {
[api.physical_name]: '',
};
commonAjax
.axios({ swalFire: false, loading: true })
.put('/api/api/deploy', { id: [api.physical_name] })
.then((res) => {
if (res.data.errorMsg != null) {
const { errorMsg } = res.data;
console.log({ errorMsg });
errorMsgList[api.physical_name] = errorMsg;
setErrorMsg(errorMsgList);
} else {
setChangeStatus(!changeStatus);
setErrorMsg(errorMsgList);
setDeployJobId(res.data.jobId);
}
});
})();
}
}
}
function ApiDeployJobStartNotification({ jobId }: { jobId?: string }) {
return (
<DialogModalOK
id="api-deploy-job-start-notification"
title="処理を開始しました"
>
<p>
データセット有効化処理を開始しました。
<br />
完了には時間がかかりますのでお待ちください。
<br />
処理の状況は下記画面で確認できます。
</p>
<Link
to={`/jobs/${jobId}`}
className="btn btn-secondary"
target="_blank"
onClick={() => hideDialog('api-deploy-job-start-notification')}
>
ジョブステータス確認
</Link>
</DialogModalOK>
);
}
export default NewApiList;
const collapseAllCards = () => {
apiList.forEach((api) => {
// 使用 jQuery 将所有展开的 card 收起
$(`#card-body-${api.physical_name}`).collapse('hide');
});
};
return (
<div className="inline-form-group">
<div className="inline-form-label">分類</div>
{tags.map((item: Defs.Tag) => (
<div
className={`btn btn-tag ${item.select ? 'active' : ''}`}
key={item.tag_name}
onClick={() => {
item.select = !item.select; // 切换选择状态
const t = tags.slice(0, tags.length);
setTags(t);
collapseAllCards(); // 标签变化时收起所有 API card
}}
>
{item.tag_name}
</div>
))}
</div>
);
}
ERROR in src/app2/components/pages/apiList.tsx:153:5
TS2304: Cannot find name 'apiList'.
151 | function FilterTags(tags: Defs.Tag[], setTags: any) {
152 | const collapseAllCards = () => {
> 153 | apiList.forEach((api) => {
| ^^^^^^^
154 | // 使用 jQuery 将所有展开的 card 收起
155 | $(`#card-body-${api.physical_name}`).collapse('hide');
156 | });
ERROR in src/app2/components/pages/apiList.tsx:153:22
TS7006: Parameter 'api' implicitly has an 'any' type.
151 | function FilterTags(tags: Defs.Tag[], setTags: any) {
152 | const collapseAllCards = () => {
> 153 | apiList.forEach((api) => {
| ^^^
154 | // 使用 jQuery 将所有展开的 card 收起
155 | $(`#card-body-${api.physical_name}`).collapse('hide');
156 | });
function FilterTags(tags: Defs.Tag[], setTags: any, apiList: Defs.Api[]) {
const collapseAllCards = () => {
apiList.forEach((api) => {
// 使用 jQuery 将所有展开的 card 收起
$(`#card-body-${api.physical_name}`).collapse('hide');
});
};
return (
<div className="inline-form-group">
<div className="inline-form-label">分類</div>
{tags.map((item: Defs.Tag) => (
<div
className={`btn btn-tag ${item.select ? 'active' : ''}`}
key={item.tag_name}
onClick={() => {
item.select = !item.select; // 切换选择状态
const t = tags.slice(0, tags.length);
setTags(t);
collapseAllCards(); // 标签变化时收起所有 API card
}}
>
{item.tag_name}
</div>
))}
</div>
);
}
{/ filter tag /}