fix: 侧边浮窗移到导航配置 tab(index.html 生效版)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
- 从其他配置移到导航配置 tab - 重写 renderSides/collectSides 为类型选择式 UI - 支持 QQ(多客服)/在线客服/群聊/公众号 4 种类型 - 新增 onSideTypeChange/addSideQQ/removeSideQQ 方法
This commit is contained in:
@@ -233,6 +233,16 @@
|
|||||||
<button class="btn btn-secondary" id="addFooterNavBtn">+ 添加栏目</button>
|
<button class="btn btn-secondary" id="addFooterNavBtn">+ 添加栏目</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="section-card">
|
||||||
|
<div class="section-header">
|
||||||
|
<h2>侧边浮窗</h2>
|
||||||
|
<p class="section-desc">配置前台右下角悬浮工具条(QQ客服/在线客服/群聊/公众号)</p>
|
||||||
|
</div>
|
||||||
|
<div class="section-body">
|
||||||
|
<div id="sideList"></div>
|
||||||
|
<button class="btn btn-secondary" id="addSideBtn">+ 添加浮窗模块</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- 其他配置 -->
|
<!-- 其他配置 -->
|
||||||
@@ -246,15 +256,7 @@
|
|||||||
<button class="btn btn-secondary" id="addFriendlyLinkBtn">+ 添加</button>
|
<button class="btn btn-secondary" id="addFriendlyLinkBtn">+ 添加</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="section-card">
|
|
||||||
<div class="section-header">
|
|
||||||
<h2>侧边浮窗</h2>
|
|
||||||
</div>
|
|
||||||
<div class="section-body">
|
|
||||||
<div id="sideList"></div>
|
|
||||||
<button class="btn btn-secondary" id="addSideBtn">+ 添加</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="section-card">
|
<div class="section-card">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h2>反馈类型</h2>
|
<h2>反馈类型</h2>
|
||||||
@@ -578,7 +580,14 @@
|
|||||||
renderFriendlyLinks(links);
|
renderFriendlyLinks(links);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== 侧边浮窗 ==========
|
// ========== 侧边浮窗(类型选择式) ==========
|
||||||
|
const SIDE_TYPES = {
|
||||||
|
qq: 'QQ客服',
|
||||||
|
service: '在线客服',
|
||||||
|
group: '群聊',
|
||||||
|
wechat: '公众号'
|
||||||
|
};
|
||||||
|
|
||||||
function renderSides(sides) {
|
function renderSides(sides) {
|
||||||
const container = document.getElementById('sideList');
|
const container = document.getElementById('sideList');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
@@ -586,28 +595,71 @@
|
|||||||
sides.forEach((side, index) => {
|
sides.forEach((side, index) => {
|
||||||
const item = document.createElement('div');
|
const item = document.createElement('div');
|
||||||
item.className = 'config-item';
|
item.className = 'config-item';
|
||||||
|
const typeName = SIDE_TYPES[side.type] || '浮窗';
|
||||||
|
|
||||||
|
// 类型选择下拉框
|
||||||
|
let typeOptions = Object.entries(SIDE_TYPES).map(([val, label]) =>
|
||||||
|
`<option value="${val}" ${side.type === val ? 'selected' : ''}>${label}</option>`
|
||||||
|
).join('');
|
||||||
|
|
||||||
|
// 根据类型渲染不同表单
|
||||||
|
let extraFields = '';
|
||||||
|
if (side.type === 'qq') {
|
||||||
|
const items = Array.isArray(side.items) ? side.items : [{ qq: '', time: '' }];
|
||||||
|
let qqFields = items.map((qq, qi) => `
|
||||||
|
<div class="config-item" style="margin: 8px 0; padding: 8px 12px; background: rgba(0,0,0,0.02); border-radius: 6px;">
|
||||||
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">
|
||||||
|
<strong style="font-size:13px">客服 ${qi + 1}</strong>
|
||||||
|
<button class="btn-icon btn-icon-danger" onclick="removeSideQQ(${index}, ${qi})" style="font-size:18px">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-fields">
|
||||||
|
<div class="form-item">
|
||||||
|
<label>QQ号</label>
|
||||||
|
<input type="text" class="form-control" data-side="${index}" data-qq="${qi}" data-qqfield="qq" value="${qq.qq || ''}" placeholder="10001">
|
||||||
|
</div>
|
||||||
|
<div class="form-item">
|
||||||
|
<label>在线时间</label>
|
||||||
|
<input type="text" class="form-control" data-side="${index}" data-qq="${qi}" data-qqfield="time" value="${qq.time || ''}" placeholder="09:00 - 22:00">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
extraFields = qqFields + `<button class="btn btn-secondary" onclick="addSideQQ(${index})" style="margin-top:4px">+ 新增QQ客服</button>`;
|
||||||
|
} else if (side.type === 'service') {
|
||||||
|
extraFields = `
|
||||||
|
<div class="form-item">
|
||||||
|
<label>客服链接地址</label>
|
||||||
|
<input type="text" class="form-control" data-side="${index}" data-field="url" value="${side.url || ''}" placeholder="https://客服链接">
|
||||||
|
</div>`;
|
||||||
|
} else if (side.type === 'group' || side.type === 'wechat') {
|
||||||
|
extraFields = `
|
||||||
|
<div class="form-item">
|
||||||
|
<label>二维码图片</label>
|
||||||
|
<div class="upload-control">
|
||||||
|
<input type="text" class="form-control" data-side="${index}" data-field="qrcode" value="${side.qrcode || ''}" placeholder="/upload/qrcode.png">
|
||||||
|
<button class="btn btn-secondary upload-btn" data-target-side="${index}.qrcode">选择文件</button>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
item.innerHTML = `
|
item.innerHTML = `
|
||||||
<div class="config-item__header">
|
<div class="config-item__header">
|
||||||
<h4>浮窗 ${index + 1}</h4>
|
<h4>${typeName} ${index + 1}</h4>
|
||||||
<button class="btn-icon btn-icon-danger" onclick="removeSide(${index})">×</button>
|
<button class="btn-icon btn-icon-danger" onclick="removeSide(${index})">×</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="config-item__body">
|
<div class="config-item__body">
|
||||||
<div class="form-fields">
|
<div class="form-fields">
|
||||||
<div class="form-item">
|
<div class="form-item">
|
||||||
<label>名称</label>
|
<label>模块类型</label>
|
||||||
<input type="text" class="form-control" data-side="${index}" data-field="name" value="${side.name || ''}" placeholder="电话咨询">
|
<select class="form-control" data-side="${index}" data-field="type" onchange="onSideTypeChange(${index}, this.value)">
|
||||||
|
${typeOptions}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-item">
|
<div class="form-item">
|
||||||
<label>图标地址</label>
|
<label>显示名称</label>
|
||||||
<div class="upload-control">
|
<input type="text" class="form-control" data-side="${index}" data-field="label" value="${side.label || ''}" placeholder="如:QQ客服">
|
||||||
<input type="text" class="form-control" data-side="${index}" data-field="icon" value="${side.icon || ''}" placeholder="/upload/icon.png">
|
|
||||||
<button class="btn btn-secondary upload-btn" data-target-side="${index}.icon">选择文件</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-item">
|
|
||||||
<label>内容HTML</label>
|
|
||||||
<textarea class="form-control" data-side="${index}" data-field="content" rows="2" placeholder="HTML内容">${side.content || ''}</textarea>
|
|
||||||
</div>
|
</div>
|
||||||
|
${extraFields}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -616,19 +668,32 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function collectSides() {
|
function collectSides() {
|
||||||
|
const container = document.getElementById('sideList');
|
||||||
|
if (!container) return [];
|
||||||
const sides = [];
|
const sides = [];
|
||||||
document.querySelectorAll('[data-side]').forEach(input => {
|
container.querySelectorAll(':scope > .config-item').forEach((itemEl, index) => {
|
||||||
const index = parseInt(input.dataset.side);
|
const side = {};
|
||||||
const field = input.dataset.field;
|
itemEl.querySelectorAll('[data-side][data-field]').forEach(input => {
|
||||||
if (!sides[index]) sides[index] = {};
|
side[input.dataset.field] = input.tagName === 'SELECT' ? input.value : input.value;
|
||||||
sides[index][field] = input.value;
|
});
|
||||||
|
// 收集 QQ 列表
|
||||||
|
if (side.type === 'qq') {
|
||||||
|
const items = [];
|
||||||
|
itemEl.querySelectorAll('[data-qqfield]').forEach(input => {
|
||||||
|
const qi = parseInt(input.dataset.qq);
|
||||||
|
if (!items[qi]) items[qi] = {};
|
||||||
|
items[qi][input.dataset.qqfield] = input.value;
|
||||||
|
});
|
||||||
|
side.items = items.filter(i => i);
|
||||||
|
}
|
||||||
|
sides.push(side);
|
||||||
});
|
});
|
||||||
return sides.filter(s => s);
|
return sides;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addSide = function () {
|
window.addSide = function () {
|
||||||
const sides = collectSides();
|
const sides = collectSides();
|
||||||
sides.push({ name: '', icon: '', content: '' });
|
sides.push({ type: 'qq', label: '', items: [{ qq: '', time: '' }], url: '', qrcode: '' });
|
||||||
renderSides(sides);
|
renderSides(sides);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -638,6 +703,28 @@
|
|||||||
renderSides(sides);
|
renderSides(sides);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.onSideTypeChange = function (index, newType) {
|
||||||
|
const sides = collectSides();
|
||||||
|
sides[index].type = newType;
|
||||||
|
if (newType === 'qq' && !Array.isArray(sides[index].items)) {
|
||||||
|
sides[index].items = [{ qq: '', time: '' }];
|
||||||
|
}
|
||||||
|
renderSides(sides);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addSideQQ = function (sideIndex) {
|
||||||
|
const sides = collectSides();
|
||||||
|
if (!Array.isArray(sides[sideIndex].items)) sides[sideIndex].items = [];
|
||||||
|
sides[sideIndex].items.push({ qq: '', time: '' });
|
||||||
|
renderSides(sides);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.removeSideQQ = function (sideIndex, qqIndex) {
|
||||||
|
const sides = collectSides();
|
||||||
|
sides[sideIndex].items.splice(qqIndex, 1);
|
||||||
|
renderSides(sides);
|
||||||
|
};
|
||||||
|
|
||||||
// ========== 反馈类型 ==========
|
// ========== 反馈类型 ==========
|
||||||
function renderFeedbackTypes(types) {
|
function renderFeedbackTypes(types) {
|
||||||
const container = document.getElementById('feedbackTypeList');
|
const container = document.getElementById('feedbackTypeList');
|
||||||
|
|||||||
Reference in New Issue
Block a user