You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
590 lines
23 KiB
590 lines
23 KiB
<!doctype html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
<title>落地页管理</title>
|
|
<style>
|
|
/* ---- 基本布局(源自你的 vue 样式) ---- */
|
|
body, html { margin:0; padding:0; height:100%; font-family: Arial, "Helvetica Neue", "PingFang SC", "Microsoft Yahei"; background:#f4f6f8; color:#333; }
|
|
.page-container { width:100%; height:100vh; display:flex; flex-direction:column; }
|
|
.top-bar { height:60px; background-color:#1890ff; color:#fff; padding:0 20px; display:flex; align-items:center; font-size:18px; font-weight:500; box-shadow:0 2px 4px rgba(0,0,0,0.1); z-index:10; }
|
|
.main-container { display:flex; flex:1; overflow:hidden; }
|
|
.sidebar { width:220px; background:#f5f7fa; border-right:1px solid #e8e8e8; padding:16px; box-sizing:border-box; }
|
|
.sidebar h3 { margin:0 0 12px 0; font-size:14px; color:#333; }
|
|
.content-area { flex:1; padding:20px; overflow:auto; background:#fff; }
|
|
.content-header { display:flex; justify-content:space-between; align-items:center; margin-bottom:20px; padding-bottom:10px; border-bottom:1px solid #e8e8e8; }
|
|
.btn { display:inline-block; padding:8px 12px; border-radius:6px; border:0; cursor:pointer; }
|
|
.btn-primary { background:#1890ff; color:#fff; }
|
|
.btn-text { background:transparent; color:#1890ff; border:1px solid transparent; }
|
|
table { width:100%; border-collapse:collapse; background:#fff; }
|
|
th, td { padding:12px 8px; border-bottom:1px solid #f0f0f0; text-align:center; font-size:14px; }
|
|
th { background:#fafafa; font-weight:600; }
|
|
.pagination-container { display:flex; justify-content:flex-end; align-items:center; margin-top:10px; gap:8px; }
|
|
select, input[type="number"] { padding:6px; border-radius:4px; border:1px solid #dcdcdc; }
|
|
/* 弹窗(模态) */
|
|
.modal-mask { position:fixed; left:0; top:0; right:0; bottom:0; background:rgba(0,0,0,0.4); display:none; align-items:center; justify-content:center; z-index:999; }
|
|
.modal { width:620px; background:#fff; border-radius:6px; padding:18px; box-shadow:0 8px 24px rgba(0,0,0,0.2); max-height:90vh; overflow:auto; }
|
|
.form-row { display:flex; gap:12px; margin-bottom:12px; align-items:center; }
|
|
.form-row label { width:110px; text-align:right; margin-right:8px; font-size:14px; color:#333; }
|
|
.form-row .field { flex:1; }
|
|
input[type="text"], textarea, input[type="datetime-local"] { width:100%; padding:8px; border:1px solid #dcdcdc; border-radius:4px; box-sizing:border-box; }
|
|
textarea { min-height:70px; resize:vertical; }
|
|
.upload-tip, .intro-tip { font-size:12px; color:#999; margin-top:6px; }
|
|
.dialog-footer { display:flex; justify-content:flex-end; gap:8px; padding-top:8px; border-top:1px solid #f0f0f0; margin-top:10px; }
|
|
.img-preview { display:inline-block; max-width:120px; max-height:80px; margin-right:8px; vertical-align:middle; border:1px solid #eee; padding:4px; border-radius:4px; }
|
|
.loading { display:inline-block; margin-left:8px; color:#1890ff; font-size:13px; }
|
|
.actions button { margin-right:6px; }
|
|
#msgBoxTop {
|
|
position: fixed;
|
|
top: 16px; /* 距离顶部距离,可调整 */
|
|
left: 50%;
|
|
transform: translateX(-50%) translateY(-8px);
|
|
z-index: 2147483647; /* 尽可能置顶 */
|
|
min-width: 220px;
|
|
max-width: 92%;
|
|
padding: 10px 16px;
|
|
border-radius: 8px;
|
|
color: #fff;
|
|
box-shadow: 0 8px 28px rgba(0,0,0,0.18);
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 14px;
|
|
text-align: center;
|
|
white-space: pre-wrap;
|
|
pointer-events: none; /* 不阻塞下方交互;如果需要可改为 auto */
|
|
}
|
|
|
|
/* 显示时的动画 */
|
|
#msgBoxTop.show {
|
|
display: flex;
|
|
animation: msg-slide-down 220ms cubic-bezier(.2,.9,.2,1);
|
|
transform: translateX(-50%) translateY(0);
|
|
}
|
|
|
|
/* 轻微淡出(移除 show 时也会自然消失)*/
|
|
@keyframes msg-slide-down {
|
|
from { opacity: 0; transform: translateX(-50%) translateY(-8px); }
|
|
to { opacity: 1; transform: translateX(-50%) translateY(0); }
|
|
}
|
|
|
|
/* 颜色主题 */
|
|
#msgBoxTop.msg-success { background: #67c23a; }
|
|
#msgBoxTop.msg-error { background: #f56c6c; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="page-container">
|
|
<div class="top-bar"><span>落地页管理</span></div>
|
|
<div class="main-container">
|
|
<div class="sidebar">
|
|
<h3>管理菜单</h3>
|
|
<div>• 落地页管理</div>
|
|
</div>
|
|
|
|
<div class="content-area">
|
|
<div class="content-header">
|
|
<div>
|
|
<strong>活动列表</strong>
|
|
</div>
|
|
<div>
|
|
<button id="btnAdd" class="btn btn-primary">+ 新增落地页</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="tableWrap">
|
|
<table id="landingTable" aria-describedby="活动列表">
|
|
<thead>
|
|
<tr>
|
|
<th style="width:80px">序号</th>
|
|
<th>活动名称</th>
|
|
<th style="min-width:220px">活动简介</th>
|
|
<th style="min-width:220px">活动时间</th>
|
|
<th style="min-width:180px">编辑时间</th>
|
|
<th style="width:280px">操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="tableBody">
|
|
<!-- JS 渲染 -->
|
|
</tbody>
|
|
</table>
|
|
<div id="loadingIndicator" style="padding:10px 0; display:none;"><span class="loading">加载中...</span></div>
|
|
<div id="noData" style="padding:20px 0; display:none; color:#666; text-align:center;">暂无数据</div>
|
|
</div>
|
|
|
|
<div class="pagination-container" style="margin-top:14px;">
|
|
<div>共 <span id="totalCount">0</span> 条</div>
|
|
<div style="margin-left:12px;">
|
|
每页
|
|
<select id="pageSizeSelect">
|
|
<option value="10">10</option>
|
|
<option value="20">20</option>
|
|
<option value="50">50</option>
|
|
</select>
|
|
条
|
|
</div>
|
|
<div style="margin-left:12px;">
|
|
<button id="prevBtn" class="btn">上一页</button>
|
|
<span style="margin:0 8px">第 <span id="currentPage">1</span> 页</span>
|
|
<button id="nextBtn" class="btn">下一页</button>
|
|
</div>
|
|
<!-- <div style="margin-left:12px;">
|
|
跳到 <input id="gotoInput" type="number" min="1" style="width:70px" /> 页
|
|
<button id="gotoBtn" class="btn">跳转</button>
|
|
</div> -->
|
|
</div>
|
|
|
|
<!-- 模态框:新增 / 编辑 -->
|
|
<div id="modalMask" class="modal-mask" role="dialog" aria-modal="true">
|
|
<div class="modal" role="document">
|
|
<h3 id="modalTitle">添加活动</h3>
|
|
|
|
<div style="padding-top:8px;">
|
|
<div class="form-row">
|
|
<label>活动名称</label>
|
|
<div class="field"><input id="fldName" type="text" /></div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<label>活动简介</label>
|
|
<div class="field">
|
|
<textarea id="fldIntro" maxlength="80" placeholder="活动简介(用于分享展示)"></textarea>
|
|
<div class="intro-tip">活动简介会给分享后客户展示,请注意填写内容(最多80字)。</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<label>活动时间</label>
|
|
<div class="field">
|
|
<input id="fldStart" type="datetime-local" style="width:200px" />
|
|
<span style="margin:0 8px">至</span>
|
|
<input id="fldEnd" type="datetime-local" style="width:200px" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<label>活动落地页</label>
|
|
<div class="field">
|
|
<div id="landingPreviewContainer" style="margin-top:8px;"></div>
|
|
<input id="inputLanding" type="file" accept="image/*" />
|
|
<div class="upload-tip">支持 PNG / JPG / GIF。</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<label>落地页弹窗</label>
|
|
<div class="field">
|
|
<div id="popupPreviewContainer" style="margin-top:8px;"></div>
|
|
<input id="inputPopup" type="file" accept="image/*" />
|
|
<div class="upload-tip">支持 PNG / JPG / GIF。</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="dialog-footer">
|
|
<button id="cancelBtn" class="btn">取消</button>
|
|
<button id="saveBtn" class="btn btn-primary">确定</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="module">
|
|
import { getLandingListApi, addLandingApi } from './src/api/member.js';
|
|
(function () {
|
|
const FILE_UPLOAD_URL = 'https://tjapi.hlquant.com/hljwgo/api/file/upload';
|
|
// 状态
|
|
let tableData = [];
|
|
let currentPage = 1;
|
|
let pageSize = 10;
|
|
let totalCount = 0;
|
|
|
|
// 上传图片临时状态
|
|
let landingFile = null;
|
|
let popupFile = null;
|
|
let landingUploadedUrl = ''; // 上传后得到的 URL(或编辑模式中已有的 url)
|
|
let popupUploadedUrl = '';
|
|
|
|
// 编辑上下文
|
|
let editId = null;
|
|
|
|
// DOM
|
|
const tableBody = document.getElementById('tableBody');
|
|
const totalCountEl = document.getElementById('totalCount');
|
|
const currentPageEl = document.getElementById('currentPage');
|
|
const pageSizeSelect = document.getElementById('pageSizeSelect');
|
|
const prevBtn = document.getElementById('prevBtn');
|
|
const nextBtn = document.getElementById('nextBtn');
|
|
// const gotoInput = document.getElementById('gotoInput');
|
|
// const gotoBtn = document.getElementById('gotoBtn');
|
|
const btnAdd = document.getElementById('btnAdd');
|
|
const modalMask = document.getElementById('modalMask');
|
|
const modalTitle = document.getElementById('modalTitle');
|
|
const cancelBtn = document.getElementById('cancelBtn');
|
|
const saveBtn = document.getElementById('saveBtn');
|
|
const fldName = document.getElementById('fldName');
|
|
const fldIntro = document.getElementById('fldIntro');
|
|
const fldStart = document.getElementById('fldStart');
|
|
const fldEnd = document.getElementById('fldEnd');
|
|
const inputLanding = document.getElementById('inputLanding');
|
|
const inputPopup = document.getElementById('inputPopup');
|
|
const landingPreviewContainer = document.getElementById('landingPreviewContainer');
|
|
const popupPreviewContainer = document.getElementById('popupPreviewContainer');
|
|
const loadingIndicator = document.getElementById('loadingIndicator');
|
|
const noData = document.getElementById('noData');
|
|
// 工具:显示消息(简单替代 ElMessage)
|
|
function showMessage(text, type = 'success', duration = 3000) {
|
|
let el = document.getElementById('msgBoxTop');
|
|
if (!el) {
|
|
el = document.createElement('div');
|
|
el.id = 'msgBoxTop';
|
|
el.setAttribute('role', 'status');
|
|
el.setAttribute('aria-live', 'polite');
|
|
document.body.appendChild(el);
|
|
}
|
|
|
|
// 更新内容与样式
|
|
el.textContent = text;
|
|
el.classList.remove('msg-success', 'msg-error', 'show');
|
|
el.classList.add(type === 'error' ? 'msg-error' : 'msg-success');
|
|
|
|
// 触发显示(重新触发动画)
|
|
// pointer-events: none 允许消息不阻塞下层交互;若想阻塞改为 auto
|
|
requestAnimationFrame(() => {
|
|
el.classList.add('show');
|
|
});
|
|
|
|
// 清除旧定时器并设置新定时器隐藏
|
|
if (el._timer) {
|
|
clearTimeout(el._timer);
|
|
}
|
|
el._timer = setTimeout(() => {
|
|
el.classList.remove('show');
|
|
// 可选:在动画结束后彻底隐藏(防止 display:flex 仍在)
|
|
setTimeout(() => {
|
|
if (!el.classList.contains('show')) {
|
|
el.style.display = 'none';
|
|
// 恢复 display 控制以便再次显示时通过 .show 控制显示
|
|
el.style.display = '';
|
|
}
|
|
}, 240);
|
|
}, Math.max(800, duration)); // 最少保留 800ms,避免闪烁
|
|
}
|
|
// 列表加载
|
|
async function getLandingList() {
|
|
loadingIndicator.style.display = 'inline-block';
|
|
noData.style.display = 'none';
|
|
tableBody.innerHTML = '';
|
|
try {
|
|
// 如果你已有后端接口,解除下面注释并使用真实接口(带 page & pageSize)
|
|
const res =await getLandingListApi({
|
|
page: currentPage,
|
|
page_size: pageSize
|
|
})
|
|
// const json = await res.json();
|
|
if (res.code == 200 && res.data) {
|
|
tableData = res.data.list
|
|
totalCount = res.data.total
|
|
renderTable();
|
|
} else {
|
|
showMessage('获取数据失败', 'error');
|
|
}
|
|
} catch (err) {
|
|
console.error(err);
|
|
showMessage('网络异常,请稍后重试', 'error');
|
|
} finally {
|
|
loadingIndicator.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
// 更严格的判断(使用 Date)
|
|
function isDialogTimeRangeValid() {
|
|
if (!fldStart.value || !fldEnd.value) return true; // 有空值不强制
|
|
const s = new Date(fldStart.value);
|
|
const e = new Date(fldEnd.value);
|
|
return e >= s;
|
|
}
|
|
function renderTable() {
|
|
tableBody.innerHTML = '';
|
|
if (!tableData || tableData.length === 0) {
|
|
noData.style.display = 'block';
|
|
} else {
|
|
noData.style.display = 'none';
|
|
}
|
|
tableData.forEach((row, idx) => {
|
|
const tr = document.createElement('tr');
|
|
|
|
const tdIndex = document.createElement('td'); tdIndex.textContent = (currentPage - 1) * pageSize + idx + 1; tr.appendChild(tdIndex);
|
|
|
|
const tdName = document.createElement('td'); tdName.textContent = row.name || ''; tr.appendChild(tdName);
|
|
|
|
const tdIntro = document.createElement('td'); tdIntro.textContent = row.introduction || ''; tr.appendChild(tdIntro);
|
|
|
|
const tdTime = document.createElement('td'); tdTime.textContent = (row.start_time || '') + ' - ' + (row.end_time || ''); tr.appendChild(tdTime);
|
|
|
|
const tdUpdated = document.createElement('td'); tdUpdated.textContent = row.updated_at || ''; tr.appendChild(tdUpdated);
|
|
|
|
const tdOps = document.createElement('td');
|
|
tdOps.className = 'actions';
|
|
const btnEdit = document.createElement('button'); btnEdit.className = 'btn btn-text'; btnEdit.textContent = '编辑';
|
|
btnEdit.addEventListener('click', () => openEditDialog(row));
|
|
tdOps.appendChild(btnEdit);
|
|
|
|
const btnDetail = document.createElement('button'); btnDetail.className = 'btn'; btnDetail.textContent = '详情';
|
|
btnDetail.addEventListener('click', () => {
|
|
window.location.href = `/parkActivity/adminDetail.html?id=${row.id}`;
|
|
});
|
|
tdOps.appendChild(btnDetail);
|
|
|
|
tr.appendChild(tdOps);
|
|
|
|
tableBody.appendChild(tr);
|
|
});
|
|
|
|
totalCountEl.textContent = totalCount;
|
|
currentPageEl.textContent = currentPage;
|
|
}
|
|
|
|
// 分页事件
|
|
prevBtn.addEventListener('click', () => {
|
|
if (currentPage > 1) {
|
|
currentPage--;
|
|
getLandingList();
|
|
}
|
|
});
|
|
nextBtn.addEventListener('click', () => {
|
|
// 简单判断:如果能跳到下一页,则允许(若你有 totalCount 可严格限制)
|
|
const maxPage = Math.max(1, Math.ceil((totalCount || 1) / pageSize));
|
|
if (currentPage < maxPage) {
|
|
currentPage++;
|
|
getLandingList();
|
|
}
|
|
});
|
|
pageSizeSelect.addEventListener('change', (e) => {
|
|
pageSize = Number(e.target.value);
|
|
currentPage = 1;
|
|
getLandingList();
|
|
});
|
|
// 打开新增弹窗
|
|
btnAdd.addEventListener('click', () => {
|
|
openAddDialog();
|
|
});
|
|
|
|
// 弹窗打开 / 关闭
|
|
function openAddDialog() {
|
|
editId = null;
|
|
modalTitle.textContent = '添加活动';
|
|
fldName.value = '';
|
|
fldIntro.value = '';
|
|
fldStart.value = '';
|
|
fldEnd.value = '';
|
|
landingFile = null; popupFile = null;
|
|
landingUploadedUrl = ''; popupUploadedUrl = '';
|
|
landingPreviewContainer.innerHTML = '';
|
|
popupPreviewContainer.innerHTML = '';
|
|
inputLanding.value = '';
|
|
inputPopup.value = '';
|
|
showModal();
|
|
}
|
|
|
|
function openEditDialog(row) {
|
|
editId = row.id;
|
|
modalTitle.textContent = '编辑活动';
|
|
fldName.value = row.name || '';
|
|
fldIntro.value = row.introduction || '';
|
|
// 尝试解析 row.start_time / end_time 为 datetime-local 格式(YYYY-MM-DDTHH:MM)
|
|
fldStart.value = toInputDatetime(row.start_time);
|
|
fldEnd.value = toInputDatetime(row.end_time);
|
|
landingUploadedUrl = row.landing_page || '';
|
|
popupUploadedUrl = row.landing_page_popup || '';
|
|
landingPreviewContainer.innerHTML = landingUploadedUrl ? `<img class="img-preview" src="${landingUploadedUrl}" alt="landing"> <button data-remove="landing">删除</button>` : '';
|
|
popupPreviewContainer.innerHTML = popupUploadedUrl ? `<img class="img-preview" src="${popupUploadedUrl}" alt="popup"> <button data-remove="popup">删除</button>` : '';
|
|
showModal();
|
|
}
|
|
|
|
function toInputDatetime(str) {
|
|
if (!str) return '';
|
|
// 如果 str 是 "2025-11-01 00:00" 或带秒,替换空格为 T
|
|
// 如果已经是 ISO 可直接 substring
|
|
const s = str.replace(' ', 'T');
|
|
// 截取到分钟
|
|
return s.length >= 16 ? s.substring(0,16) : s;
|
|
}
|
|
|
|
function showModal() {
|
|
modalMask.style.display = 'flex';
|
|
}
|
|
function closeModal() {
|
|
modalMask.style.display = 'none';
|
|
}
|
|
cancelBtn.addEventListener('click', () => {
|
|
closeModal();
|
|
});
|
|
|
|
// 删除预览的图片(编辑时的删除)
|
|
landingPreviewContainer.addEventListener('click', (e) => {
|
|
if (e.target && e.target.dataset.remove === 'landing') {
|
|
landingUploadedUrl = ''; landingFile = null; landingPreviewContainer.innerHTML = '';
|
|
}
|
|
});
|
|
popupPreviewContainer.addEventListener('click', (e) => {
|
|
if (e.target && e.target.dataset.remove === 'popup') {
|
|
popupUploadedUrl = ''; popupFile = null; popupPreviewContainer.innerHTML = '';
|
|
}
|
|
});
|
|
|
|
// 文件选择处理(预览 + 校验)
|
|
inputLanding.addEventListener('change', (e) => {
|
|
const f = e.target.files[0];
|
|
if (!f) return;
|
|
if (f.size > 2 * 1024 * 1024) {
|
|
showMessage('图片大小不能超过 2MB', 'error');
|
|
e.target.value = '';
|
|
if (typeof landingFile !== 'undefined') landingFile = null;
|
|
if (landingPreviewContainer) landingPreviewContainer.innerHTML = '';
|
|
return;
|
|
}
|
|
const reader = new FileReader();
|
|
reader.onload = function (ev) {
|
|
const img = new Image();
|
|
img.onload = function () {
|
|
// if (img.width > 375) {
|
|
// showMessage('落地页图片宽度应 ≤ 375px,请使用合适宽度的图片。', 'error');
|
|
// inputLanding.value = '';
|
|
// landingFile = null;
|
|
// landingPreviewContainer.innerHTML = '';
|
|
// return;
|
|
// }
|
|
landingFile = f;
|
|
landingPreviewContainer.innerHTML = '';
|
|
const imgEl = document.createElement('img');
|
|
imgEl.src = ev.target.result;
|
|
imgEl.className = 'img-preview';
|
|
landingPreviewContainer.appendChild(imgEl);
|
|
};
|
|
img.src = ev.target.result;
|
|
};
|
|
reader.readAsDataURL(f);
|
|
});
|
|
|
|
inputPopup.addEventListener('change', (e) => {
|
|
const f = e.target.files[0];
|
|
if (!f) return;
|
|
if (f.size > 2 * 1024 * 1024) {
|
|
showMessage('图片大小不能超过 2MB', 'error');
|
|
e.target.value = '';
|
|
if (typeof popupFile !== 'undefined') popupFile = null;
|
|
if (popupPreviewContainer) popupPreviewContainer.innerHTML = '';
|
|
return;
|
|
}
|
|
const reader = new FileReader();
|
|
reader.onload = function (ev) {
|
|
popupFile = f;
|
|
popupPreviewContainer.innerHTML = '';
|
|
const imgEl = document.createElement('img');
|
|
imgEl.src = ev.target.result;
|
|
imgEl.className = 'img-preview';
|
|
popupPreviewContainer.appendChild(imgEl);
|
|
};
|
|
reader.readAsDataURL(f);
|
|
});
|
|
|
|
saveBtn.addEventListener('click', async () => {
|
|
// 简单校验
|
|
const name = fldName.value.trim();
|
|
const introduction = fldIntro.value.trim();
|
|
const startTime = fldStart.value;
|
|
const endTime = fldEnd.value;
|
|
if (!name) { showMessage('请输入活动名称', 'error'); return; }
|
|
if (!introduction) { showMessage('请输入活动简介', 'error'); return; }
|
|
if (!startTime) { showMessage('请选择开始时间', 'error'); return; }
|
|
if (!endTime) { showMessage('请选择结束时间', 'error'); return; }
|
|
if (!isDialogTimeRangeValid()) {
|
|
showMessage('结束时间不能早于开始时间,请调整后保存', 'error');
|
|
return;
|
|
}
|
|
// 如果既没有已上传的 url,也没有本地文件,则提示
|
|
if (!landingUploadedUrl && !landingFile) { showMessage('请上传活动落地页', 'error'); return; }
|
|
if (!popupUploadedUrl && !popupFile) { showMessage('请上传落地页弹窗', 'error'); return; }
|
|
|
|
saveBtn.disabled = true;
|
|
saveBtn.textContent = '提交中...';
|
|
|
|
try {
|
|
// 1) 若用户选择了新的图片文件则先上传图片
|
|
if (landingFile) {
|
|
const uploaded = await uploadFile(landingFile);
|
|
if (!uploaded.success) { showMessage('落地页图片上传失败', 'error'); saveBtn.disabled = false; saveBtn.textContent = '确定'; return; }
|
|
landingUploadedUrl = uploaded.url;
|
|
}
|
|
if (popupFile) {
|
|
const uploaded = await uploadFile(popupFile);
|
|
if (!uploaded.success) { showMessage('弹窗图片上传失败', 'error'); saveBtn.disabled = false; saveBtn.textContent = '确定'; return; }
|
|
popupUploadedUrl = uploaded.url;
|
|
}
|
|
|
|
const res = await addLandingApi({
|
|
id: editId,
|
|
name:name,
|
|
introduction:introduction,
|
|
start_time: formatDatetimeLocal(startTime),
|
|
end_time: formatDatetimeLocal(endTime),
|
|
landing_page: landingUploadedUrl,
|
|
landing_page_popup: popupUploadedUrl
|
|
})
|
|
if (res.code == 200) {
|
|
showMessage('操作成功');
|
|
closeModal();
|
|
getLandingList();
|
|
} else {
|
|
showMessage(json.msg || '操作失败', 'error');
|
|
}
|
|
|
|
} catch (err) {
|
|
console.error(err);
|
|
showMessage('网络异常', 'error');
|
|
} finally {
|
|
saveBtn.disabled = false;
|
|
saveBtn.textContent = '确定';
|
|
}
|
|
});
|
|
|
|
async function uploadFile(file) {
|
|
const fd = new FormData();
|
|
fd.append('file', file);
|
|
fd.append('type', 'image');
|
|
fd.append('app_from', 'toujiao');
|
|
try {
|
|
const resp = await fetch(FILE_UPLOAD_URL, {
|
|
method: 'POST',
|
|
body: fd
|
|
});
|
|
const json = await resp.json();
|
|
if (json && ((json.code && json.code === 200) || json.data)) {
|
|
const url = (json.data && (json.data.url || json.data.file_name)) || json.url || '';
|
|
return { success: true, url: url };
|
|
} else {
|
|
return { success: false };
|
|
}
|
|
} catch (err) {
|
|
console.error('uploadFile error', err);
|
|
return { success: false };
|
|
}
|
|
}
|
|
|
|
function formatDatetimeLocal(v) {
|
|
// v like "2025-10-23T14:00" -> "2025-10-23 14:00"
|
|
return v ? v.replace('T', ' ') : '';
|
|
}
|
|
|
|
// 初始加载
|
|
getLandingList();
|
|
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|