show more style
import { apiAxios, showError } from '../../../js/portal/api';
import { removeDisabledOptions } from '../../../js/portal/main';
import swal from 'sweetalert';
/**
* Creates a new selectpicker dropdown including a label and a refresh button. The dropdown list will be populated
* automatically with all APP IDs from our caching DB.
*
* @param {string} label - name label on the left side of the dropdown menu
* @param {string} id - the id of the selectpicker
* @param {function} onchange - a function that will be triggered once the selectpicker value changes
* @param {type[]} selectedValues - a list of app ids that should be selected if available
* @param {boolean} deselect - defines if the deselect user button is added to the end of the selectpicker
* @param {boolean} multiple - defines if you can select one or multiple items in the user dropdown
* @param {boolean} disableUrlParams - by default, the component updates the query parameters for the current URL, "?email=<selectedOption>"
* @param {boolean} ownUser - Whether BMW internal user email
*
* @returns div including a label, the dropdown and a refresh button
*/
export default function AppDropdown({ label, id, onchange, selectedValues, deselect, multiple, disableUrlParams, ownUser }) {
const selectId = id ? id : 'appDropdown';
const disableParamsUpdate = disableUrlParams ? true : false;
const headers = { 'Cache-Control': 'max-age=0, must-revalidate' };
const params = {};
// all app list data store
let appDataStore = {}
// 产品信息map
let productMap = {}
// 存储上一次选中的值
let previousSelectedValues = [];
// selectpicker options: https://developer.snapappointments.com/bootstrap-select/options/
const select = (
<select
required
class="form-control form-select selectpicker"
data-live-search="true"
data-show-subtext="true"
id={selectId}
name={selectId}
data-size="10"
data-max-options="5"
data-none-selected-text="- Select one or more APP IDs -"
data-selected-text-format="count > 1"
data-count-selected-text="{0} Application(s) selected"
data-dropdown-align-right="auto"
multiple={multiple ? true : false}>
<option class="defaultDisabled" value="" disabled selected={multiple ? false : true}>
- Select one or more APP IDs -
</option>
</select>
);
// Refresh button to reload the user data
const refreshIcon = <i class="fas fa-sync" />;
const refreshButton = (
<button
type="button"
class="btn btn-light-grey input-group-btn portal-selectpicker-end"
id="refresh-users"
title="Reload User List">
{refreshIcon}
</button>
);
// De-select button
const deselectButton = (
<button
type="button"
class="btn btn-light-grey input-group-btn portal-selectpicker-mid"
id="deselect-users"
title="De-select all users">
<i class="fa fa-user-alt-slash" />
</button>
);
// Represents the whole row including the label, the selectpicker and the refresh button
const AppDropdown = (
<div class="form-group row portal-dropdown">
<div class="col input-group">
{select}
{deselect ? deselectButton : undefined}
{refreshButton}
</div>
</div>
);
// Refresh the selectpicker and add an on change event
$(select).selectpicker('refresh');
// 修改 select 的 change 事件处理
$(select).on('changed.bs.select', async (event, clickedIndex, isSelected, previousValue) => {
/**
* 1.event: jQuery 事件对象
* 3.clickedIndex: 被点击的选项的索引值
* 3.isSelected: 布尔值,true 表示选中,false 表示取消选中
* 4.previousValue: 改变之前的值
*/
console.log('Clicked index:', clickedIndex);
console.log('Is selected:', isSelected); // true 或 false
console.log('Previous value:', previousValue);
// 获取当前所有选中的值
const currentSelectedValues = $(`#${selectId}`).val() || [];
// 找出新增的值(当前选中的 appId)
let currentAppId;
if (isSelected) {
// 如果是选中操作,找出新增的值
currentAppId = $(select).find('option').eq(clickedIndex).val();
} else {
// 如果是取消选中操作,找出被移除的值
currentAppId = previousSelectedValues.find(id => !currentSelectedValues.includes(id));
}
console.log('Current operation appId:', currentAppId);
console.log('Is selected:', isSelected);
// 获取当前操作的 app 完整信息
const currentAppInfo = appDataStore[currentAppId];
console.log('Current app info:', currentAppInfo);
// 如果是选中操作,需要进行产品ID检查
if (isSelected) {
// EG 检查
try {
const isValidEG = await getTicketByAppIds(select, refreshIcon, currentAppId);
if (!isValidEG) {
return;
}
} catch (error) {
showError(error);
return;
}
// 检查是否是无产品ID的选项
if (currentAppInfo && (!currentAppInfo.productId || currentAppInfo.productId === "product")) {
// 如果是无产品ID的选项,强制单选
$(select).selectpicker('deselectAll');
$(`#${selectId} option[value="${currentAppId}"]`).prop('selected', true);
$(select).selectpicker('refresh');
previousSelectedValues = [currentAppId];
} else {
// 获取所有当前选中项的产品ID
const selectedApps = currentSelectedValues.map(appId => appDataStore[appId]);
const productIds = new Set(selectedApps.map(app => app.productId).filter(Boolean));
// 如果产品ID数量大于1,说明不是同一个产品
if (productIds.size > 1) {
swal({
title: 'Warning',
text: 'The applications you have selected do not belong to the same product.',
icon: 'warning',
buttons: {
okay: {
text: 'OK',
value: true,
visible: true,
},
},
}).then(() => {
// 清空所有选择
$(select).selectpicker('deselectAll');
$(select).selectpicker('refresh');
previousSelectedValues = [];
// 如果需要,也可以触发 onchange 回调通知选择已清空
if (onchange) {
onchange({
currentApp: null,
isSelected: false,
allSelectedApps: []
});
}
});
return; // 不继续执行后续代码
}
}
}
// 更新上一次的选中值
previousSelectedValues = currentSelectedValues;
// 调用回调函数,传递当前操作的 app 信息和选中状态
if (onchange) {
onchange({
currentApp: currentAppInfo,
isSelected: isSelected,
allSelectedApps: currentSelectedValues.map(appId => appDataStore[appId])
});
}
});
// Reload the account records from the REST API (with cache-control headers)
$(refreshButton).on('click', () => {
getAppResponsibleRole(select, refreshIcon, selectedValues, multiple, disableParamsUpdate, headers, params);
});
// De-select all users from the selectpicker
$(deselectButton).on('click', () => {
$(select).selectpicker('deselectAll');
$(select).selectpicker('refresh');
});
// Load the app list from the OPCP REST API (without cache-control headers)
getAppResponsibleRole(select, refreshIcon, selectedValues, multiple, disableParamsUpdate, {}, {})
/**
* Get Application Responsible Role in ConnectIT.
* Populates the selectpicker dropdown with the values from the REST API endpoint.
* Deletes all active dropdown items before adding the new items.
*
*
* @param {JSX.IntrinsicElements.select} select
* @param {JSX.Element} refreshIcon
* @param {type[]} selectedValues
* @param {boolean} multiple
* @param {object} headers
* @param {object} params
*/
function getAppResponsibleRole(select, refreshIcon, headers, params) {
$(refreshIcon).addClass('fa-spin');
$(select).attr('disabled', true).selectpicker('refresh');
$(refreshIcon).addClass('fa-spin');
$(select).attr('disabled', true).selectpicker('refresh');
// 清空全局存储
appDataStore = {};
apiAxios
.post('/opcp2/umps/app/getAppResponsibilitiesByUser', { headers, params })
.then(async response => {
removeDisabledOptions(select);
const body = response.data.body;
// body[0].productId = "SWP-1982"
// 首先处理所有直接返回的应用
body.forEach(item => {
// 储存应用信息
appDataStore[item.appId] = {
appId: item.appId,
appName: item.appName,
productId: item.productId === "" ? "product" : item.productId,
productName: item.productName || "Unknown",
roles: item.roles
};
//存储产品信息
if (item.productId) {
productMap[item.productId] = {
productId: item.productId,
productName: item.productName,
}
}
});
// 收集非空的productIds
const productIds = new Set();
body.forEach(item => {
if (item.productId) {
productIds.add(item.productId);
}
});
// 获取每个产品下的应用列表
try {
const productApps = await Promise.all(
Array.from(productIds).map(async productId => {
const response = await apiAxios.post('/opcp2/umps/app/getAppListByProduct', { productId })
if(response.data.code==="200") {
return response.data.body.map(app => ({
...app,
appName: app.application,
productId: productId,
productName: productMap[productId]?.productName || "Unknown"
}))
}
})
);
// console.log(productApps,'----productApps123----')
// 合并产品下的应用列表
if(productApps?.length) {
console.log(productApps,'----productApps----')
productApps.flat().forEach(app => {
console.log(app,'----app----')
if (!appDataStore[app.appId]) {
appDataStore[app.appId] = {
appId: app.appId,
appName: app.appName,
productId: app.productId,
productName: app.productName
};
}
});
}
// 更新下拉框选项
const options = Object.values(appDataStore).map(item => {
const opt = document.createElement('option');
opt.value = item.appId;
opt.innerText = `${item.appId} ${item.appName}`;
opt.setAttribute('data-subtext', item.productName || 'No Product');
return opt;
});
// 清空并添加新选项
$(select).find('option:not(.defaultDisabled)').remove();
options.forEach(option => {
select.appendChild(option);
});
// 如果有预选值,设置选中状态
if (selectedValues && selectedValues.length) {
selectedValues.forEach(value => {
$(select).find(`option[value="${value}"]`).prop('selected', true);
});
}
$(select).selectpicker('refresh');
} catch (error) {
showError(error);
}
})
.catch(error => {
showError(error);
})
.finally(() => {
// Refresh the selectpicker to show the new options
$(refreshIcon).removeClass('fa-spin');
$(select).attr('disabled', false);
$(select).selectpicker('refresh');
});
}
return AppDropdown;
}
// 通过appid 获取对应EG infomation
function getTicketByAppIds(select, refreshIcon, appId) {
return new Promise((resolve, reject) => {
$(refreshIcon).addClass('fa-spin');
$(select).attr('disabled', true).selectpicker('refresh');
let params = {
appIds: [appId]
}
let validEGCount = 0;
apiAxios
.post('/cloud/entryGateway/v1/GetTicketByAppIds', params)
.then(response => {
const data = response.data.body;
if (data.length) {
data.forEach(item => {
if (item.platform === "TSP (AWS)" && item.entryStatus === 3) {
++validEGCount;
}
});
if (validEGCount === 0) {
swal({
title: 'Warning',
icon: 'warning',
content: {
element: "div",
attributes: {
innerHTML: `There is no valid entry gateway record for ${appId}, please check your application's Entry Gateway status: (<a href="https://opcp.bmwgroup.net/prod/#/TSPCloud/EntryGateway" target="_blank">Entry Gateway</a>)`
}
},
buttons: {
okay: {
text: 'OK',
value: true,
visible: true,
},
},
}).then(function (response) {
$(`#appDropdown option[value="${appId}"]`).prop('selected', false);
$(select).selectpicker('refresh');
resolve(false); // EG 检查不通过
});
} else {
resolve(true); // EG 检查通过
}
} else {
swal({
title: 'Warning',
icon: 'warning',
content: {
element: "div",
attributes: {
innerHTML: `There is no valid entry gateway record for ${appId}, please check your application's Entry Gateway status: (<a href="https://opcp.bmwgroup.net/prod/#/TSPCloud/EntryGateway" target="_blank">Entry Gateway</a>)`
}
},
buttons: {
okay: {
text: 'OK',
value: true,
visible: true,
},
},
}).then(function (response) {
$(`#appDropdown option[value="${appId}"]`).prop('selected', false);
$(select).selectpicker('refresh');
resolve(false); // EG 检查不通过
});
}
})
.catch(error => {
showError(error);
reject(error);
})
.finally(() => {
$(refreshIcon).removeClass('fa-spin');
$(select).attr('disabled', false);
$(select).selectpicker('refresh');
});
});
}
11
Clicked index: 1
AppDropdown.jsx:103 Is selected: true
AppDropdown.jsx:104 Previous value: []
AppDropdown.jsx:118 Current operation appId: APP-26162
AppDropdown.jsx:119 Is selected: true
AppDropdown.jsx:123 Current app info: {appId: 'APP-26162', appName: 'TSP Cloud Platform', productId: 'product', productName: 'Unknown', roles: Array(2)}
AppDropdown.jsx:102 Clicked index: null
AppDropdown.jsx:103 Is selected: null
AppDropdown.jsx:104 Previous value: ['APP-26162']
AppDropdown.jsx:118 Current operation appId: undefined
AppDropdown.jsx:119 Is selected: null
AppDropdown.jsx:123 Current app info: undefined
OrderAdditionalPage.jsx:403 undefined null [] '-----回调事件'
OrderAdditionalPage.jsx:403 {appId: 'APP-26162', appName: 'TSP Cloud Platform', productId: 'product', productName: 'Unknown', roles: Array(2)} true [{…}] '-----回调事件'