488 lines
19 KiB
JavaScript
488 lines
19 KiB
JavaScript
class VariableForm extends HTMLElement {
|
||
constructor() {
|
||
super();
|
||
this.attachShadow({ mode: 'open' });
|
||
this.mode = 'add';
|
||
this.interfaceData = null;
|
||
this.planes = [];
|
||
this.ataChapters = [];
|
||
this.modelStructs = [];
|
||
}
|
||
|
||
connectedCallback() {
|
||
this.render();
|
||
this.addEventListeners();
|
||
}
|
||
|
||
// 接收父组件传递的选项数据
|
||
setOptions(planes, atas) {
|
||
this.planes = planes;
|
||
this.ataChapters = atas;
|
||
this.updatePlaneOptions();
|
||
this.updateAtaOptions();
|
||
}
|
||
|
||
updatePlaneOptions() {
|
||
const select = this.shadowRoot.querySelector('#planeName');
|
||
if (select) {
|
||
select.innerHTML = `
|
||
<option value="">请选择机型</option>
|
||
${this.planes.map(plane => `
|
||
<option value="${plane}" ${this.interfaceData?.PlaneName === plane ? 'selected' : ''}>
|
||
${plane}
|
||
</option>
|
||
`).join('')}
|
||
`;
|
||
}
|
||
}
|
||
|
||
updateAtaOptions() {
|
||
const select = this.shadowRoot.querySelector('#ataName');
|
||
if (select) {
|
||
select.innerHTML = `
|
||
<option value="">请选择ATA章节</option>
|
||
${this.ataChapters.map(chapter => `
|
||
<option value="${chapter}" ${this.interfaceData?.ATAName === chapter ? 'selected' : ''}>
|
||
${chapter}
|
||
</option>
|
||
`).join('')}
|
||
`;
|
||
}
|
||
}
|
||
|
||
async loadModelStructs(planeName, ataName) {
|
||
try {
|
||
const savedSelection = localStorage.getItem('xnsim-selection');
|
||
if (!savedSelection) {
|
||
throw new Error('请先选择构型');
|
||
}
|
||
const selection = JSON.parse(savedSelection);
|
||
if (!selection.configurationId) {
|
||
throw new Error('请先选择构型');
|
||
}
|
||
|
||
const response = await fetch(`/api/interface/struct/list?systemName=XNSim&planeName=${planeName}&ataName=${ataName}&confID=${selection.configurationId}`);
|
||
if (!response.ok) {
|
||
throw new Error('获取模型结构体列表失败');
|
||
}
|
||
const data = await response.json();
|
||
this.modelStructs = data.map(item => item.ModelStructName);
|
||
this.updateModelStructSelect();
|
||
} catch (error) {
|
||
console.error('加载模型结构体列表失败:', error);
|
||
alert(error.message || '加载模型结构体列表失败');
|
||
}
|
||
}
|
||
|
||
updateModelStructSelect() {
|
||
const select = this.shadowRoot.querySelector('#modelStructName');
|
||
if (select) {
|
||
select.innerHTML = `
|
||
<option value="">请选择模型结构体</option>
|
||
${this.modelStructs.map(struct => `
|
||
<option value="${struct}" ${this.interfaceData?.ModelStructName === struct ? 'selected' : ''}>
|
||
${struct}
|
||
</option>
|
||
`).join('')}
|
||
`;
|
||
}
|
||
}
|
||
|
||
setMode(mode, data = null) {
|
||
this.mode = mode;
|
||
this.interfaceData = data;
|
||
if (data) {
|
||
// 保存原始数据
|
||
this.originalData = {
|
||
PlaneName: data.PlaneName,
|
||
ATAName: data.ATAName,
|
||
ModelStructName: data.ModelStructName,
|
||
InterfaceName: data.InterfaceName
|
||
};
|
||
// 如果是在编辑模式下,需要先加载模型结构体列表
|
||
this.loadModelStructs(data.PlaneName, data.ATAName).then(() => {
|
||
this.render();
|
||
this.addEventListeners();
|
||
this.show();
|
||
});
|
||
} else {
|
||
this.render();
|
||
this.addEventListeners();
|
||
this.show();
|
||
}
|
||
}
|
||
|
||
show() {
|
||
const overlay = this.shadowRoot.querySelector('.form-overlay');
|
||
if (overlay) {
|
||
overlay.style.display = 'block';
|
||
}
|
||
}
|
||
|
||
hide() {
|
||
const overlay = this.shadowRoot.querySelector('.form-overlay');
|
||
if (overlay) {
|
||
overlay.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
addEventListeners() {
|
||
const form = this.shadowRoot.querySelector('form');
|
||
const cancelBtn = this.shadowRoot.querySelector('.cancel-btn');
|
||
const planeSelect = this.shadowRoot.querySelector('#planeName');
|
||
const ataSelect = this.shadowRoot.querySelector('#ataName');
|
||
const interfaceNameInput = this.shadowRoot.querySelector('#interfaceName');
|
||
const isArrayCheckbox = this.shadowRoot.querySelector('#interfaceIsArray');
|
||
const arraySize1Input = this.shadowRoot.querySelector('#interfaceArraySize_1');
|
||
const arraySize2Input = this.shadowRoot.querySelector('#interfaceArraySize_2');
|
||
|
||
// 监听构型和ATA章节的变化
|
||
planeSelect.addEventListener('change', () => {
|
||
const planeName = planeSelect.value;
|
||
const ataName = ataSelect.value;
|
||
if (planeName && ataName) {
|
||
this.loadModelStructs(planeName, ataName);
|
||
}
|
||
});
|
||
|
||
ataSelect.addEventListener('change', () => {
|
||
const planeName = planeSelect.value;
|
||
const ataName = ataSelect.value;
|
||
if (planeName && ataName) {
|
||
this.loadModelStructs(planeName, ataName);
|
||
}
|
||
});
|
||
|
||
// 验证C++命名规范
|
||
interfaceNameInput.addEventListener('input', (e) => {
|
||
const value = e.target.value;
|
||
// C++命名规范:以字母或下划线开头,只能包含字母、数字和下划线
|
||
const isValid = /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(value);
|
||
if (!isValid) {
|
||
e.target.setCustomValidity('接口名称必须以字母或下划线开头,只能包含字母、数字和下划线');
|
||
} else {
|
||
e.target.setCustomValidity('');
|
||
}
|
||
});
|
||
|
||
// 验证数组大小
|
||
arraySize1Input.addEventListener('input', (e) => {
|
||
const value = parseInt(e.target.value);
|
||
if (value <= 1) {
|
||
e.target.setCustomValidity('第一维大小必须大于1');
|
||
} else {
|
||
e.target.setCustomValidity('');
|
||
}
|
||
});
|
||
|
||
arraySize2Input.addEventListener('input', (e) => {
|
||
const value = e.target.value;
|
||
if (value && parseInt(value) <= 1 && parseInt(value) !== 0) {
|
||
e.target.setCustomValidity('第二维大小必须大于1');
|
||
} else {
|
||
e.target.setCustomValidity('');
|
||
}
|
||
});
|
||
|
||
form.addEventListener('submit', (e) => {
|
||
e.preventDefault();
|
||
|
||
const formData = new FormData(form);
|
||
const isArray = formData.get('interfaceIsArray') ? 1 : 0;
|
||
const arraySize1 = parseInt(formData.get('interfaceArraySize_1')) || 0;
|
||
const arraySize2 = parseInt(formData.get('interfaceArraySize_2')) || 0;
|
||
|
||
const data = {
|
||
SystemName: 'XNSim',
|
||
PlaneName: formData.get('planeName'),
|
||
ATAName: formData.get('ataName'),
|
||
ModelStructName: formData.get('modelStructName'),
|
||
InterfaceName: formData.get('interfaceName'),
|
||
InterfaceType: formData.get('interfaceType'),
|
||
InterfaceOption: 1,
|
||
InterfaceIsArray: isArray,
|
||
InterfaceArraySize_1: isArray && arraySize1 > 1 ? arraySize1 : 0,
|
||
InterfaceArraySize_2: isArray && arraySize1 > 1 ? arraySize2 : 0,
|
||
InterfaceNotes: formData.get('interfaceNotes')
|
||
};
|
||
|
||
// 从 localStorage 获取 ConfID
|
||
const savedSelection = localStorage.getItem('xnsim-selection');
|
||
if (!savedSelection) {
|
||
alert('请先选择机型');
|
||
return;
|
||
}
|
||
const selection = JSON.parse(savedSelection);
|
||
if (!selection.configurationId) {
|
||
alert('请先选择机型');
|
||
return;
|
||
}
|
||
data.ConfID = selection.configurationId;
|
||
|
||
// 如果是编辑模式,添加原始数据
|
||
if (this.mode === 'edit' && this.originalData) {
|
||
data.originalPlaneName = this.originalData.PlaneName;
|
||
data.originalATAName = this.originalData.ATAName;
|
||
data.originalModelStructName = this.originalData.ModelStructName;
|
||
data.originalInterfaceName = this.originalData.InterfaceName;
|
||
}
|
||
|
||
// 验证必填字段
|
||
const requiredFields = [
|
||
'SystemName',
|
||
'PlaneName',
|
||
'ATAName',
|
||
'ModelStructName',
|
||
'InterfaceName',
|
||
'InterfaceType',
|
||
'ConfID'
|
||
];
|
||
|
||
const missingFields = requiredFields.filter(field => !data[field]);
|
||
if (missingFields.length > 0) {
|
||
alert(`请填写以下必填字段:${missingFields.join(', ')}`);
|
||
return;
|
||
}
|
||
|
||
// 如果是数组类型,验证数组大小
|
||
if (data.InterfaceIsArray === 1) {
|
||
if (!data.InterfaceArraySize_1 || data.InterfaceArraySize_1 <= 1) {
|
||
alert('第一维大小必须大于1');
|
||
return;
|
||
}
|
||
if (data.InterfaceArraySize_2 && data.InterfaceArraySize_2 <= 1 && data.InterfaceArraySize_2 !== 0) {
|
||
alert('第二维大小必须大于1或等于0');
|
||
return;
|
||
}
|
||
}
|
||
|
||
this.dispatchEvent(new CustomEvent('save-success', {
|
||
detail: { ...data, mode: this.mode }
|
||
}));
|
||
this.hide();
|
||
});
|
||
|
||
cancelBtn.addEventListener('click', () => {
|
||
this.hide();
|
||
});
|
||
|
||
// 监听数组大小输入框的变化
|
||
isArrayCheckbox.addEventListener('change', () => {
|
||
arraySize1Input.disabled = !isArrayCheckbox.checked;
|
||
arraySize2Input.disabled = !isArrayCheckbox.checked;
|
||
if (!isArrayCheckbox.checked) {
|
||
arraySize1Input.value = '';
|
||
arraySize2Input.value = '';
|
||
}
|
||
});
|
||
}
|
||
|
||
render() {
|
||
const interfaceTypes = [
|
||
'char', 'octet', 'short', 'unsigned short',
|
||
'long', 'unsigned long', 'long long', 'unsigned long long',
|
||
'float', 'double', 'long double', 'boolean'
|
||
];
|
||
|
||
// 从 localStorage 获取机型信息
|
||
const savedSelection = localStorage.getItem('xnsim-selection');
|
||
const selection = savedSelection ? JSON.parse(savedSelection) : null;
|
||
const planeName = selection?.plane || '';
|
||
|
||
this.shadowRoot.innerHTML = `
|
||
<style>
|
||
.form-overlay {
|
||
display: none;
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
z-index: 1000;
|
||
}
|
||
|
||
.form-container {
|
||
position: fixed;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
background-color: white;
|
||
padding: 20px;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||
width: 500px;
|
||
max-height: 90vh;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.form-title {
|
||
margin: 0 0 20px 0;
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
label {
|
||
display: block;
|
||
margin-bottom: 5px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
select, input[type="text"], input[type="number"] {
|
||
width: 100%;
|
||
padding: 8px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.checkbox-group {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
}
|
||
|
||
.checkbox-group input[type="checkbox"] {
|
||
width: auto;
|
||
}
|
||
|
||
.button-group {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 10px;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
button {
|
||
padding: 8px 16px;
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.save-btn {
|
||
background-color: #4CAF50;
|
||
color: white;
|
||
}
|
||
|
||
.cancel-btn {
|
||
background-color: #f44336;
|
||
color: white;
|
||
}
|
||
|
||
button:hover {
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.array-size-group {
|
||
display: flex;
|
||
gap: 10px;
|
||
align-items: center;
|
||
}
|
||
|
||
.array-size-group input[type="number"] {
|
||
width: 100px;
|
||
}
|
||
|
||
.plane-info {
|
||
background-color: #f5f5f5;
|
||
padding: 10px;
|
||
border-radius: 4px;
|
||
margin-bottom: 15px;
|
||
}
|
||
</style>
|
||
<div class="form-overlay">
|
||
<div class="form-container">
|
||
<h2 class="form-title">${this.mode === 'add' ? '添加接口' : '编辑接口'}</h2>
|
||
<div class="plane-info">
|
||
当前机型:${planeName}
|
||
</div>
|
||
<form>
|
||
<input type="hidden" id="planeName" name="planeName" value="${planeName}">
|
||
<div class="form-group">
|
||
<label for="ataName">ATA章节</label>
|
||
<select id="ataName" name="ataName" required>
|
||
<option value="">请选择ATA章节</option>
|
||
${this.ataChapters.map(chapter => `
|
||
<option value="${chapter}" ${this.interfaceData?.ATAName === chapter ? 'selected' : ''}>
|
||
${chapter}
|
||
</option>
|
||
`).join('')}
|
||
</select>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="modelStructName">接口结构体名</label>
|
||
<select id="modelStructName" name="modelStructName" required>
|
||
<option value="">请选择接口结构体</option>
|
||
${this.modelStructs.map(struct => `
|
||
<option value="${struct}" ${this.interfaceData?.ModelStructName === struct ? 'selected' : ''}>
|
||
${struct}
|
||
</option>
|
||
`).join('')}
|
||
</select>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="interfaceName">接口名称</label>
|
||
<input type="text" id="interfaceName" name="interfaceName" required
|
||
value="${this.interfaceData?.InterfaceName || ''}">
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="interfaceType">数据类型</label>
|
||
<select id="interfaceType" name="interfaceType" required>
|
||
<option value="">请选择数据类型</option>
|
||
${interfaceTypes.map(type => `
|
||
<option value="${type}" ${this.interfaceData?.InterfaceType === type ? 'selected' : ''}>
|
||
${type}
|
||
</option>
|
||
`).join('')}
|
||
</select>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<div class="checkbox-group">
|
||
<input type="checkbox" id="interfaceIsArray" name="interfaceIsArray"
|
||
${this.interfaceData?.InterfaceIsArray === 1 ? 'checked' : ''}>
|
||
<label for="interfaceIsArray">是否为数组</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>数组大小</label>
|
||
<div class="array-size-group">
|
||
<input type="number" id="interfaceArraySize_1" name="interfaceArraySize_1"
|
||
value="${this.interfaceData?.InterfaceArraySize_1 || ''}"
|
||
${this.interfaceData?.InterfaceIsArray !== 1 ? 'disabled' : ''}
|
||
placeholder="第一维">
|
||
<span>×</span>
|
||
<input type="number" id="interfaceArraySize_2" name="interfaceArraySize_2"
|
||
value="${this.interfaceData?.InterfaceArraySize_2 || ''}"
|
||
${this.interfaceData?.InterfaceIsArray !== 1 ? 'disabled' : ''}
|
||
placeholder="第二维">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="interfaceNotes">备注</label>
|
||
<input type="text" id="interfaceNotes" name="interfaceNotes"
|
||
value="${this.interfaceData?.InterfaceNotes || ''}">
|
||
</div>
|
||
|
||
<div class="button-group">
|
||
<button type="button" class="cancel-btn">取消</button>
|
||
<button type="submit" class="save-btn">保存</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
}
|
||
|
||
customElements.define('variable-form', VariableForm);
|