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>
|
||||
</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>
|
||||
|
||||
<!-- 其他配置 -->
|
||||
@@ -246,15 +256,7 @@
|
||||
<button class="btn btn-secondary" id="addFriendlyLinkBtn">+ 添加</button>
|
||||
</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-header">
|
||||
<h2>反馈类型</h2>
|
||||
@@ -578,7 +580,14 @@
|
||||
renderFriendlyLinks(links);
|
||||
};
|
||||
|
||||
// ========== 侧边浮窗 ==========
|
||||
// ========== 侧边浮窗(类型选择式) ==========
|
||||
const SIDE_TYPES = {
|
||||
qq: 'QQ客服',
|
||||
service: '在线客服',
|
||||
group: '群聊',
|
||||
wechat: '公众号'
|
||||
};
|
||||
|
||||
function renderSides(sides) {
|
||||
const container = document.getElementById('sideList');
|
||||
if (!container) return;
|
||||
@@ -586,28 +595,71 @@
|
||||
sides.forEach((side, index) => {
|
||||
const item = document.createElement('div');
|
||||
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 = `
|
||||
<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>
|
||||
</div>
|
||||
<div class="config-item__body">
|
||||
<div class="form-fields">
|
||||
<div class="form-item">
|
||||
<label>名称</label>
|
||||
<input type="text" class="form-control" data-side="${index}" data-field="name" value="${side.name || ''}" placeholder="电话咨询">
|
||||
<label>模块类型</label>
|
||||
<select class="form-control" data-side="${index}" data-field="type" onchange="onSideTypeChange(${index}, this.value)">
|
||||
${typeOptions}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>图标地址</label>
|
||||
<div class="upload-control">
|
||||
<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>
|
||||
<label>显示名称</label>
|
||||
<input type="text" class="form-control" data-side="${index}" data-field="label" value="${side.label || ''}" placeholder="如:QQ客服">
|
||||
</div>
|
||||
${extraFields}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -616,19 +668,32 @@
|
||||
}
|
||||
|
||||
function collectSides() {
|
||||
const container = document.getElementById('sideList');
|
||||
if (!container) return [];
|
||||
const sides = [];
|
||||
document.querySelectorAll('[data-side]').forEach(input => {
|
||||
const index = parseInt(input.dataset.side);
|
||||
const field = input.dataset.field;
|
||||
if (!sides[index]) sides[index] = {};
|
||||
sides[index][field] = input.value;
|
||||
container.querySelectorAll(':scope > .config-item').forEach((itemEl, index) => {
|
||||
const side = {};
|
||||
itemEl.querySelectorAll('[data-side][data-field]').forEach(input => {
|
||||
side[input.dataset.field] = input.tagName === 'SELECT' ? input.value : input.value;
|
||||
});
|
||||
return sides.filter(s => s);
|
||||
// 收集 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;
|
||||
}
|
||||
|
||||
window.addSide = function () {
|
||||
const sides = collectSides();
|
||||
sides.push({ name: '', icon: '', content: '' });
|
||||
sides.push({ type: 'qq', label: '', items: [{ qq: '', time: '' }], url: '', qrcode: '' });
|
||||
renderSides(sides);
|
||||
};
|
||||
|
||||
@@ -638,6 +703,28 @@
|
||||
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) {
|
||||
const container = document.getElementById('feedbackTypeList');
|
||||
|
||||
Reference in New Issue
Block a user