国内市场双十一活动仓库
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.

548 lines
15 KiB

3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>管理后台</title>
  7. <style>
  8. /* 基础样式 */
  9. * {
  10. margin: 0;
  11. padding: 0;
  12. box-sizing: border-box;
  13. font-family: "Microsoft YaHei", sans-serif;
  14. }
  15. body {
  16. background-color: #f5f7fa;
  17. color: #333;
  18. }
  19. .container {
  20. display: flex;
  21. min-height: 100vh;
  22. }
  23. /* 侧边栏样式 */
  24. .sidebar {
  25. width: 220px;
  26. background-color: #2c3e50;
  27. color: #fff;
  28. padding: 20px 0;
  29. }
  30. .sidebar-logo {
  31. text-align: center;
  32. padding: 0 20px 20px;
  33. border-bottom: 1px solid rgba(255,255,255,0.1);
  34. margin-bottom: 20px;
  35. }
  36. .sidebar-logo h2 {
  37. font-size: 18px;
  38. margin-top: 10px;
  39. }
  40. .sidebar-menu {
  41. list-style: none;
  42. }
  43. .sidebar-menu li a {
  44. display: flex;
  45. align-items: center;
  46. padding: 12px 20px;
  47. color: rgba(255,255,255,0.8);
  48. text-decoration: none;
  49. transition: all 0.3s;
  50. }
  51. .sidebar-menu li a:hover,
  52. .sidebar-menu li a.active {
  53. background-color: #34495e;
  54. color: #fff;
  55. }
  56. .sidebar-menu li a i {
  57. margin-right: 10px;
  58. font-size: 16px;
  59. }
  60. /* 主内容区样式 */
  61. .main-content {
  62. flex: 1;
  63. padding: 20px;
  64. overflow-y: auto;
  65. }
  66. .page-header {
  67. display: flex;
  68. justify-content: space-between;
  69. align-items: center;
  70. margin-bottom: 20px;
  71. padding-bottom: 15px;
  72. border-bottom: 1px solid #eee;
  73. }
  74. .page-header h2 {
  75. font-size: 20px;
  76. font-weight: 600;
  77. color: #333;
  78. }
  79. .btn {
  80. padding: 6px 12px;
  81. border: 1px solid #ddd;
  82. border-radius: 4px;
  83. background-color: #fff;
  84. cursor: pointer;
  85. color: #333;
  86. text-decoration: none;
  87. }
  88. .btn-primary {
  89. background-color: #3498db;
  90. color: #fff;
  91. border-color: #3498db;
  92. }
  93. .btn-danger {
  94. background-color: #e74c3c;
  95. color: #fff;
  96. border-color: #e74c3c;
  97. }
  98. /* 查询区域样式 */
  99. .search-area {
  100. display: flex;
  101. align-items: center;
  102. gap: 10px;
  103. margin-bottom: 20px;
  104. flex-wrap: wrap; /* 适配小屏幕 */
  105. }
  106. .search-area input,
  107. .search-area select {
  108. padding: 6px 10px;
  109. border: 1px solid #ddd;
  110. border-radius: 4px;
  111. outline: none;
  112. }
  113. .search-area .date-picker {
  114. display: flex;
  115. align-items: center;
  116. gap: 5px;
  117. }
  118. /* 表格样式 */
  119. .table-container {
  120. background-color: #fff;
  121. border-radius: 4px;
  122. box-shadow: 0 2px 12px rgba(0,0,0,0.1);
  123. overflow: hidden;
  124. }
  125. .data-table {
  126. width: 100%;
  127. border-collapse: collapse;
  128. }
  129. .data-table th,
  130. .data-table td {
  131. padding: 12px 15px;
  132. text-align: left;
  133. border-bottom: 1px solid #f0f0f0;
  134. }
  135. .data-table th {
  136. background-color: #f9fafb;
  137. font-weight: 600;
  138. color: #666;
  139. }
  140. .data-table tbody tr:hover {
  141. background-color: #f5f7fa;
  142. }
  143. /* 分页样式 */
  144. .pagination {
  145. display: flex;
  146. justify-content: space-between;
  147. align-items: center;
  148. padding: 15px;
  149. border-top: 1px solid #f0f0f0;
  150. }
  151. .pagination-info {
  152. color: #666;
  153. font-size: 14px;
  154. }
  155. .pagination-list {
  156. display: flex;
  157. list-style: none;
  158. padding: 0;
  159. margin: 0;
  160. }
  161. .pagination-list li {
  162. margin: 0 2px;
  163. }
  164. .pagination-list a,
  165. .pagination-list span {
  166. display: inline-block;
  167. width: 45px;
  168. height: 45px;
  169. line-height: 45px;
  170. text-align: center;
  171. border: 1px solid #ddd;
  172. border-radius: 4px;
  173. text-decoration: none;
  174. color: #333;
  175. font-size: 14px;
  176. box-sizing: border-box;
  177. }
  178. .pagination-list a {
  179. cursor: pointer;
  180. }
  181. .pagination-list a:hover,
  182. .pagination-list a.active {
  183. background-color: #3498db;
  184. color: #fff;
  185. border-color: #3498db;
  186. }
  187. .pagination-list span {
  188. background-color: #f5f5f5;
  189. color: #999;
  190. cursor: not-allowed;
  191. }
  192. .pagination-jump {
  193. display: flex;
  194. align-items: center;
  195. font-size: 14px;
  196. gap: 5px;
  197. }
  198. .pagination-jump input {
  199. width: 50px;
  200. height: 32px;
  201. margin: 0 5px;
  202. padding: 0 5px;
  203. border: 1px solid #ddd;
  204. border-radius: 4px;
  205. text-align: center;
  206. box-sizing: border-box;
  207. }
  208. .pagination-jump button {
  209. padding: 6px 12px;
  210. border: 1px solid #ddd;
  211. border-radius: 4px;
  212. background-color: #fff;
  213. cursor: pointer;
  214. height: 32px;
  215. box-sizing: border-box;
  216. }
  217. /* 加载中样式 */
  218. .loading {
  219. text-align: center;
  220. padding: 50px 0;
  221. color: #666;
  222. }
  223. .loading i {
  224. font-size: 24px;
  225. margin-bottom: 10px;
  226. animation: spin 1s linear infinite;
  227. }
  228. @keyframes spin {
  229. from { transform: rotate(0deg); }
  230. to { transform: rotate(360deg); }
  231. }
  232. </style>
  233. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
  234. </head>
  235. <body>
  236. <div class="container">
  237. <div class="sidebar">
  238. <div class="sidebar-logo">
  239. <i class="fa fa-line-chart" style="font-size: 24px;"></i>
  240. <h2>后台管理系统</h2>
  241. </div>
  242. <ul class="sidebar-menu">
  243. <li><a href="#" class="active"><i class="fa fa-file-text-o"></i> 落地页管理</a></li>
  244. </ul>
  245. </div>
  246. <!-- 主内容区 -->
  247. <div class="main-content">
  248. <div class="page-header">
  249. <div class="page-header h2">详情</div>
  250. <a href="adminConfig.html" class="btn">返回上一级页面</a>
  251. </div>
  252. <!-- 查询区域 -->
  253. <div class="search-area">
  254. <label class="date-picker">
  255. 打开网页时间
  256. <input type="date" id="startTime" placeholder="请选择开始时间" />
  257. <input type="date" id="endTime" placeholder="请选择结束时间" />
  258. </label>
  259. <div>
  260. <label for="statusSelect">收下状态</label>
  261. <select id="statusSelect">
  262. <option value="">请选择状态</option>
  263. <option value="1"></option>
  264. <option value="0"></option>
  265. </select>
  266. </div>
  267. <button id="searchBtn" class="btn btn-primary">查询</button>
  268. <button class="btn btn-danger">导出</button>
  269. </div>
  270. <!-- 数据表格 -->
  271. <div class="table-container">
  272. <table class="data-table">
  273. <thead>
  274. <tr>
  275. <th>序号</th>
  276. <th>打开网页时间</th>
  277. <th>收下状态</th>
  278. </tr>
  279. </thead>
  280. <tbody id="tableBody">
  281. <tr>
  282. <td colspan="3" class="loading"> <!-- 注意:表格列数是3,colspan改为3 -->
  283. <i class="fa fa-spinner"></i>
  284. <p>加载中...</p>
  285. </td>
  286. </tr>
  287. </tbody>
  288. </table>
  289. <!-- 分页控件 -->
  290. <div class="pagination" id="paginationContainer">
  291. </div>
  292. </div>
  293. </div>
  294. </div>
  295. <script type="module">
  296. // 导入API函数(假设接口定义)
  297. import { getLandingDetailApi } from './src/api/member.js';
  298. // DOM元素
  299. const tableBody = document.getElementById('tableBody');
  300. const paginationContainer = document.getElementById('paginationContainer');
  301. const searchBtn = document.getElementById('searchBtn');
  302. const startTimeInput = document.getElementById('startTime');
  303. const endTimeInput = document.getElementById('endTime');
  304. const statusSelect = document.getElementById('statusSelect');
  305. // 分页参数
  306. let currentPage = 1;
  307. const pageSize = 20;
  308. let totalCount = 0;
  309. let totalPages = 0;
  310. // URL获取的id参数
  311. let landingId = '';
  312. // 初始化页面:从URL获取页码,请求后端数据
  313. async function initPage() {
  314. const urlParams = new URLSearchParams(window.location.search);
  315. landingId = urlParams.get('id');
  316. if (!landingId) {
  317. renderEmptyState('缺少必要的参数');
  318. return;
  319. }
  320. // 从后端请求数据
  321. await fetchDataFromBackend();
  322. }
  323. // 核心:从后端API请求数据
  324. async function fetchDataFromBackend() {
  325. // 显示加载状态
  326. tableBody.innerHTML = `
  327. <tr>
  328. <td colspan="3" class="loading">
  329. <i class="fa fa-spinner"></i>
  330. <p>加载中...</p>
  331. </td>
  332. </tr>
  333. `;
  334. paginationContainer.innerHTML = '';
  335. try {
  336. // 1. 构造请求参数(分页+查询条件)
  337. const requestParams = {
  338. id: landingId,
  339. page: currentPage, // 当前页码
  340. size: pageSize, // 每页条数
  341. startTime: startTimeInput.value || '', // 开始时间(查询条件)
  342. endTime: endTimeInput.value || '', // 结束时间(查询条件)
  343. receiveStatus: statusSelect.value || '' // 收下状态(查询条件)
  344. };
  345. // 2. 调用导入的API函数
  346. const result = await getLandingDetailApi(requestParams);
  347. // 3. 处理API返回结果
  348. if (result.code === 200) {
  349. const { list, total } = result.data;
  350. totalCount = total;
  351. totalPages = Math.ceil(totalCount / pageSize);
  352. renderTable(list);
  353. renderPagination();
  354. } else {
  355. renderEmptyState('获取数据失败');
  356. }
  357. } catch (error) {
  358. // 捕获异常
  359. console.error('请求数据异常:', error);
  360. renderEmptyState('网络错误,请稍后重试');
  361. }
  362. }
  363. // 渲染表格数据
  364. function renderTable(dataList) {
  365. if (!dataList || dataList.length === 0) {
  366. renderEmptyState('暂无符合条件的数据');
  367. return;
  368. }
  369. let html = '';
  370. dataList.forEach((item, index) => {
  371. // 计算序号:(当前页-1)*每页条数 + 索引+1
  372. const serialNumber = (currentPage - 1) * pageSize + index + 1;
  373. // 注意:item的字段名需与后端返回的字段一致
  374. html += `
  375. <tr>
  376. <td>${serialNumber}</td>
  377. <td>${formatDate(item.openTime || '')}</td>
  378. <td>${item.receiveStatus === '1' ? '是' : item.receiveStatus === '0' ? '否' : ''}</td>
  379. </tr>
  380. `;
  381. });
  382. tableBody.innerHTML = html;
  383. }
  384. // 渲染空状态
  385. function renderEmptyState(message) {
  386. tableBody.innerHTML = `
  387. <tr>
  388. <td colspan="3" style="text-align: center; padding: 30px;">
  389. <i class="fa fa-inbox" style="font-size: 24px; color: #ddd; margin-bottom: 10px;"></i>
  390. <p>${message}</p>
  391. </td>
  392. </tr>
  393. `;
  394. paginationContainer.innerHTML = '';
  395. }
  396. // 渲染分页控件
  397. function renderPagination() {
  398. if (totalCount === 0) return;
  399. // 生成页码列表
  400. const pageNumbers = [];
  401. let startPage = Math.max(1, currentPage - 2);
  402. let endPage = Math.min(totalPages, currentPage + 2);
  403. if (endPage - startPage < 4 && totalPages >= 5) {
  404. if (startPage === 1) endPage = 5;
  405. else if (endPage === totalPages) startPage = totalPages - 4;
  406. }
  407. for (let i = startPage; i <= endPage; i++) {
  408. pageNumbers.push(i);
  409. }
  410. // 分页HTML
  411. const html = `
  412. <div class="pagination-info">
  413. 共 ${totalCount} 条记录,当前第 ${currentPage} / ${totalPages} 页
  414. </div>
  415. <ul class="pagination-list">
  416. <li>
  417. ${currentPage === 1
  418. ? `<span>首页</span>`
  419. : `<a href="?page=1">首页</a>`
  420. }
  421. </li>
  422. <li>
  423. ${currentPage > 1
  424. ? `<a href="?page=${currentPage - 1}">上一页</a>`
  425. : `<span>上一页</span>`
  426. }
  427. </li>
  428. ${pageNumbers.map(num => `
  429. <li>
  430. <a href="?page=${num}" class="${num === currentPage ? 'active' : ''}">
  431. ${num}
  432. </a>
  433. </li>
  434. `).join('')}
  435. <li>
  436. ${currentPage < totalPages
  437. ? `<a href="?page=${currentPage + 1}">下一页</a>`
  438. : `<span>下一页</span>`
  439. }
  440. </li>
  441. <li>
  442. ${currentPage === totalPages
  443. ? `<span>尾页</span>`
  444. : `<a href="?page=${totalPages}">尾页</a>`
  445. }
  446. </li>
  447. </ul>
  448. <div class="pagination-jump">
  449. <span>跳至</span>
  450. <input type="number" min="1" max="${totalPages}" value="${currentPage}" id="jumpPageInput">
  451. <span></span>
  452. <button id="jumpBtn">确定</button>
  453. </div>
  454. `;
  455. paginationContainer.innerHTML = html;
  456. // 绑定跳转事件
  457. document.getElementById('jumpBtn').addEventListener('click', handlePageJump);
  458. document.getElementById('jumpPageInput').addEventListener('keypress', (e) => {
  459. if (e.key === 'Enter') handlePageJump();
  460. });
  461. }
  462. // 处理页码跳转
  463. function handlePageJump() {
  464. const pageInput = document.getElementById('jumpPageInput');
  465. const page = parseInt(pageInput.value);
  466. if (page && !isNaN(page) && page >= 1 && page <= totalPages && page !== currentPage) {
  467. window.location.href = `?page=${page}`;
  468. } else {
  469. alert('请输入有效的页码');
  470. }
  471. }
  472. // 查询按钮事件:点击后重新请求数据
  473. searchBtn.addEventListener('click', async () => {
  474. currentPage = 1; // 重置为第一页
  475. await fetchDataFromBackend(); // 重新请求后端数据
  476. });
  477. // 工具函数:格式化日期(适配后端返回的时间格式)
  478. function formatDate(dateString) {
  479. if (!dateString) return '';
  480. const date = new Date(dateString);
  481. // 处理无效日期
  482. if (isNaN(date.getTime())) return dateString;
  483. // 格式化显示:年-月-日 时:分:秒
  484. return date.toLocaleString('zh-CN', {
  485. year: 'numeric',
  486. month: '2-digit',
  487. day: '2-digit',
  488. hour: '2-digit',
  489. minute: '2-digit',
  490. second: '2-digit'
  491. }).replace(/\//g, '-');
  492. }
  493. // 工具函数:HTML转义(防止XSS攻击)
  494. function escapeHtml(str) {
  495. if (!str) return '';
  496. return str
  497. .replace(/&/g, '&amp;')
  498. .replace(/</g, '&lt;')
  499. .replace(/>/g, '&gt;')
  500. .replace(/"/g, '&quot;')
  501. .replace(/'/g, '&#039;');
  502. }
  503. // 页面加载时初始化
  504. window.addEventListener('DOMContentLoaded', initPage);
  505. </script>
  506. </body>
  507. </html>