设为首页收藏本站 国外访客:

 找回密码
 立即注册
搜索
查看: 6|回复: 0

反馈代码

[复制链接]
灌水成绩
19643
119
20226
主题
帖子
积分

等级头衔

ID : 1

管理员

积分成就 威望 : 8 点
贡献 : 9 次
下载币 : 439 枚
在线时间 : 1998 小时
注册时间 : 2013-9-5
最后登录 : 2026-10-20

发表于 昨天 22:20 | 显示全部楼层 |阅读模式 IP:广东东莞
免责
- 默认密码:`admin123`,代码顶部`ADMIN_PASSWORD`变量直接修改密码
- 点击【管理员后台】,先进入密码登录页;密码正确才可以查看反馈列表、修改状态、删除记录
- 增加**退出登录**按钮,退出后需要重新输入密码
- 密码错误提示文字
  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.     <script src="https://cdn.tailwindcss.com"></script>
  8.     <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  9.     <script>
  10.         tailwind.config = {
  11.             theme: {
  12.                 extend: {
  13.                     colors: {
  14.                         primary: '#1677ff',
  15.                     },
  16.                 }
  17.             }
  18.         }
  19.     </script>
  20.     <style type="text/tailwindcss">
  21.         @layer utilities {
  22.             .form-shadow {
  23.                 box-shadow: 0 2px 12px 0 rgba(0,0,0,0.08);
  24.             }
  25.             .tab-active{
  26.                 border-bottom:2px solid #1677ff;
  27.                 color:#1677ff;
  28.             }
  29.             .status-pending {
  30.                 @apply bg-orange-100 text-orange-600 px-2 py-0.5 rounded;
  31.             }
  32.             .status-doing {
  33.                 @apply bg-blue-100 text-blue-600 px-2 py-0.5 rounded;
  34.             }
  35.             .status-done {
  36.                 @apply bg-green-100 text-green-600 px-2 py-0.5 rounded;
  37.             }
  38.         }
  39.     </style>
  40. </head>
  41. <body class="bg-gray-50 min-h-screen">
  42.     <div class="max-w-4xl mx-auto py-10 px-4">
  43.         <div class="bg-white rounded-lg p-6 md:p-8 form-shadow">
  44.             <div class="text-center mb-6">
  45.                 <h1 class="text-[24px] font-bold text-gray-800">意见反馈系统</h1>
  46.             </div>
  47.             <!-- 顶层大Tab:用户端 / 管理员 -->
  48.             <div class="flex border-b border-gray-200 mb-6">
  49.                 <div id="tabUser" class="flex-1 py-3 text-center cursor-pointer tab-active font-medium">用户反馈</div>
  50.                 <div id="tabAdmin" class="flex-1 py-3 text-center cursor-pointer text-gray-500 font-medium">管理员后台</div>
  51.             </div>

  52.             <!-- ========== 用户面板(提交+查询) ========== -->
  53.             <div id="panelUser">
  54.                 <div class="flex border-b border-gray-200 mb-6">
  55.                     <div id="tabSubmit" class="flex-1 py-3 text-center cursor-pointer tab-active font-medium">提交反馈</div>
  56.                     <div id="tabSearch" class="flex-1 py-3 text-center cursor-pointer text-gray-500 font-medium">查询反馈</div>
  57.                 </div>
  58.                 <!-- 提交反馈表单 -->
  59.                 <div id="panelSubmit">
  60.                     <form id="feedbackForm">
  61.                         <div class="mb-5">
  62.                             <label class="block text-gray-700 mb-2">反馈类型 <span class="text-red-500">*</span></label>
  63.                             <select id="type" class="w-full border border-gray-300 rounded px-3 py-2.5 focus:outline-none focus:border-primary">
  64.                                 <option value="">请选择反馈类型</option>
  65.                                 <option value="bug">功能BUG</option>
  66.                                 <option value="suggest">功能建议</option>
  67.                                 <option value="complain">投诉</option>
  68.                                 <option value="other">其他</option>
  69.                             </select>
  70.                         </div>
  71.                         <div class="mb-5">
  72.                             <label class="block text-gray-700 mb-2">邮箱</label>
  73.                             <input type="email" id="email" placeholder="请输入邮箱(用于回复通知)" class="w-full border border-gray-300 rounded px-3 py-2.5 focus:outline-none focus:border-primary">
  74.                         </div>
  75.                         <div class="mb-5">
  76.                             <label class="block text-gray-700 mb-2">反馈内容 <span class="text-red-500">*</span></label>
  77.                             <textarea id="content" rows="5" placeholder="请详细描述您遇到的问题或建议..." class="w-full border border-gray-300 rounded px-3 py-2.5 focus:outline-none focus:border-primary resize-none"></textarea>
  78.                         </div>
  79.                         <button type="submit" class="w-full bg-primary hover:bg-blue-600 text-white py-3 rounded transition-all">提交反馈</button>
  80.                     </form>
  81.                 </div>
  82.                 <!-- 查询反馈面板 -->
  83.                 <div id="panelSearch" class="hidden">
  84.                     <div class="mb-5">
  85.                         <label class="block text-gray-700 mb-2">反馈单号 <span class="text-red-500">*</span></label>
  86.                         <input type="text" id="searchSn" placeholder="请输入提交反馈后获取的单号" class="w-full border border-gray-300 rounded px-3 py-2.5 focus:outline-none focus:border-primary">
  87.                     </div>
  88.                     <button id="searchBtn" class="w-full bg-primary hover:bg-blue-600 text-white py-3 rounded transition-all mb-6">查询</button>
  89.                     <div id="searchResult" class="hidden border rounded p-4 bg-gray-50">
  90.                         <h3 class="font-bold text-lg mb-3">反馈详情</h3>
  91.                         <div class="space-y-2 text-gray-700">
  92.                             <p>单号:<span id="resSn"></span></p>
  93.                             <p>类型:<span id="resType"></span></p>
  94.                             <p>提交时间:<span id="resTime"></span></p>
  95.                             <p>处理状态:<span id="resStatus"></span></p>
  96.                             <p>反馈内容:<span id="resContent"></span></p>
  97.                         </div>
  98.                     </div>
  99.                     <div id="searchEmpty" class="hidden text-center text-red-500 py-4">未找到该单号的反馈记录</div>
  100.                 </div>
  101.             </div>

  102.             <!-- ========== 管理员登录面板 ========== -->
  103.             <div id="panelAdminLogin" class="hidden">
  104.                 <h3 class="font-bold text-lg mb-4">管理员登录</h3>
  105.                 <div class="max-w-sm mx-auto">
  106.                     <div class="mb-5">
  107.                         <label class="block text-gray-700 mb-2">管理员密码</label>
  108.                         <input type="password" id="adminPwdInput" placeholder="请输入管理员密码" class="w-full border border-gray-300 rounded px-3 py-2.5 focus:outline-none focus:border-primary">
  109.                     </div>
  110.                     <button id="adminLoginBtn" class="w-full bg-primary hover:bg-blue-600 text-white py-3 rounded transition-all">登录后台</button>
  111.                     <p id="loginError" class="text-red-500 mt-3 text-center hidden">密码错误,请重试</p>
  112.                 </div>
  113.             </div>

  114.             <!-- ========== 管理员后台面板(登录成功后显示) ========== -->
  115.             <div id="panelAdmin" class="hidden">
  116.                 <div class="flex justify-between items-center mb-4">
  117.                     <h3 class="font-bold text-lg">全部反馈列表</h3>
  118.                     <button id="adminLogoutBtn" class="bg-gray-200 hover:bg-gray-300 px-3 py-1 rounded text-sm">退出登录</button>
  119.                 </div>
  120.                 <div id="adminList" class="space-y-4 max-h-[600px] overflow-y-auto pr-1">
  121.                     <!-- JS动态渲染列表 -->
  122.                 </div>
  123.                 <div id="adminEmpty" class="text-center text-gray-400 py-8 hidden">暂无反馈记录</div>
  124.             </div>
  125.         </div>
  126.     </div>

  127.     <!-- 提交成功弹窗(显示单号+复制按钮) -->
  128.     <div id="modal" class="fixed inset-0 bg-black/50 hidden items-center justify-center z-50">
  129.         <div class="bg-white p-6 rounded-lg w-80 text-center">
  130.             <div class="text-green-500 text-4xl mb-3"><i class="fa fa-check-circle"></i></div>
  131.             <h3 class="text-lg font-medium">提交成功</h3>
  132.             <p class="text-gray-500 my-2">您的反馈单号:</p>
  133.             <p id="snText" class="text-primary font-bold text-xl mb-3"></p>
  134.             <button id="copySnBtn" class="px-4 py-2 bg-green-500 hover:bg-green-600 text-white rounded mb-4 w-full">
  135.                 <i class="fa fa-copy mr-1"></i>复制单号
  136.             </button>
  137.             <p class="text-gray-400 text-sm mb-4">请保存单号,用于查询处理进度</p>
  138.             <button id="closeModal" class="px-5 py-2 bg-primary text-white rounded w-full">确定</button>
  139.         </div>
  140.     </div>

  141.     <script>
  142.         // ========= 配置区,修改这里改管理员密码 =========
  143.         const ADMIN_PASSWORD = "admin123";

  144.         // 顶层Tab 用户/管理员
  145.         const tabUser = document.getElementById('tabUser');
  146.         const tabAdmin = document.getElementById('tabAdmin');
  147.         const panelUser = document.getElementById('panelUser');
  148.         const panelAdminLogin = document.getElementById('panelAdminLogin');
  149.         const panelAdmin = document.getElementById('panelAdmin');
  150.         const adminLoginBtn = document.getElementById('adminLoginBtn');
  151.         const adminLogoutBtn = document.getElementById('adminLogoutBtn');
  152.         const adminPwdInput = document.getElementById('adminPwdInput');
  153.         const loginError = document.getElementById('loginError');

  154.         let isAdminLogin = false;

  155.         tabUser.onclick = ()=>{
  156.             tabUser.classList.add('tab-active');
  157.             tabAdmin.classList.remove('tab-active');
  158.             panelUser.classList.remove('hidden');
  159.             panelAdminLogin.classList.add('hidden');
  160.             panelAdmin.classList.add('hidden');
  161.         }
  162.         tabAdmin.onclick = ()=>{
  163.             tabAdmin.classList.add('tab-active');
  164.             tabUser.classList.remove('tab-active');
  165.             panelUser.classList.add('hidden');
  166.             if(isAdminLogin){
  167.                 panelAdmin.classList.remove('hidden');
  168.                 panelAdminLogin.classList.add('hidden');
  169.                 renderAdminList();
  170.             }else{
  171.                 panelAdminLogin.classList.remove('hidden');
  172.                 panelAdmin.classList.add('hidden');
  173.                 loginError.classList.add('hidden');
  174.                 adminPwdInput.value = "";
  175.             }
  176.         }

  177.         //管理员登录
  178.         adminLoginBtn.onclick = function(){
  179.             const pwd = adminPwdInput.value.trim();
  180.             if(pwd === ADMIN_PASSWORD){
  181.                 isAdminLogin = true;
  182.                 panelAdminLogin.classList.add('hidden');
  183.                 panelAdmin.classList.remove('hidden');
  184.                 renderAdminList();
  185.             }else{
  186.                 loginError.classList.remove('hidden');
  187.             }
  188.         }
  189.         //退出登录
  190.         adminLogoutBtn.onclick = function(){
  191.             isAdminLogin = false;
  192.             tabUser.click();
  193.         }

  194.         // 用户端内部tab
  195.         const tabSubmit = document.getElementById('tabSubmit');
  196.         const tabSearch = document.getElementById('tabSearch');
  197.         const panelSubmit = document.getElementById('panelSubmit');
  198.         const panelSearch = document.getElementById('panelSearch');
  199.         tabSubmit.onclick = ()=>{
  200.             tabSubmit.classList.add('tab-active');
  201.             tabSearch.classList.remove('tab-active');
  202.             panelSubmit.classList.remove('hidden');
  203.             panelSearch.classList.add('hidden');
  204.         }
  205.         tabSearch.onclick = ()=>{
  206.             tabSearch.classList.add('tab-active');
  207.             tabSubmit.classList.remove('tab-active');
  208.             panelSearch.classList.remove('hidden');
  209.             panelSubmit.classList.add('hidden');
  210.         }

  211.         const form = document.getElementById('feedbackForm');
  212.         const modal = document.getElementById('modal');
  213.         const closeModal = document.getElementById('closeModal');
  214.         const copySnBtn = document.getElementById('copySnBtn');
  215.         let currentSN = "";

  216.         // 模拟数据库
  217.         let feedbackDB = {};
  218.         const typeMap = {
  219.             bug:"功能BUG",
  220.             suggest:"功能建议",
  221.             complain:"投诉",
  222.             other:"其他"
  223.         };
  224.         const statusMap = {
  225.             pending:{text:"待处理", cls:"status-pending"},
  226.             doing:{text:"处理中", cls:"status-doing"},
  227.             done:{text:"已完成", cls:"status-done"}
  228.         };

  229.         // 生成单号
  230.         function createSN(){
  231.             const time = new Date().getTime();
  232.             const rand = Math.floor(Math.random()*1000).toString().padStart(3,'0');
  233.             return `FB${time}${rand}`;
  234.         }

  235.         // 渲染管理员列表
  236.         function renderAdminList(){
  237.             const wrap = document.getElementById('adminList');
  238.             const emptyTip = document.getElementById('adminEmpty');
  239.             wrap.innerHTML = '';
  240.             const keys = Object.keys(feedbackDB);
  241.             if(keys.length === 0){
  242.                 emptyTip.classList.remove('hidden');
  243.                 return;
  244.             }
  245.             emptyTip.classList.add('hidden');
  246.             // 倒序,最新的在最上面
  247.             keys.reverse().forEach(sn=>{
  248.                 const item = feedbackDB[sn];
  249.                 const statusInfo = statusMap[item.status];
  250.                 const html = `
  251.                 <div class="border p-4 rounded bg-gray-50">
  252.                     <div class="flex flex-wrap justify-between items-center gap-2 mb-2">
  253.                         <span class="font-medium">单号:${item.sn}</span>
  254.                         <span class="${statusInfo.cls}">${statusInfo.text}</span>
  255.                     </div>
  256.                     <p class="text-sm text-gray-600 mb-1">类型:${typeMap[item.type]} | 邮箱:${item.email||'未填写'}</p>
  257.                     <p class="text-sm text-gray-600 mb-1">提交时间:${item.time}</p>
  258.                     <p class="text-sm text-gray-700 my-2">反馈内容:${item.content}</p>
  259.                     <div class="flex gap-2 mt-3">
  260.                         <select class="statusSelect border rounded px-2 py-1" data-sn="${sn}">
  261.                             <option value="pending" ${item.status==='pending'?'selected':''}>待处理</option>
  262.                             <option value="doing" ${item.status==='doing'?'selected':''}>处理中</option>
  263.                             <option value="done" ${item.status==='done'?'selected':''}>已完成</option>
  264.                         </select>
  265.                         <button class="delBtn bg-red-500 text-white px-3 py-1 rounded" data-sn="${sn}">删除</button>
  266.                     </div>
  267.                 </div>
  268.                 `;
  269.                 wrap.innerHTML += html;
  270.             })
  271.             // 绑定修改状态事件
  272.             document.querySelectorAll('.statusSelect').forEach(sel=>{
  273.                 sel.onchange = function(){
  274.                     const sn = this.dataset.sn;
  275.                     feedbackDB[sn].status = this.value;
  276.                     renderAdminList();
  277.                 }
  278.             })
  279.             // 删除事件
  280.             document.querySelectorAll('.delBtn').forEach(btn=>{
  281.                 btn.onclick = function(){
  282.                     const sn = this.dataset.sn;
  283.                     if(confirm('确定删除这条反馈?')){
  284.                         delete feedbackDB[sn];
  285.                         renderAdminList();
  286.                     }
  287.                 }
  288.             })
  289.         }

  290.         //表单提交
  291.         form.onsubmit = function(e){
  292.             e.preventDefault();
  293.             const type = document.getElementById('type').value;
  294.             const content = document.getElementById('content').value.trim();
  295.             if(!type){
  296.                 alert("请选择反馈类型");
  297.                 return;
  298.             }
  299.             if(!content){
  300.                 alert("请填写反馈内容");
  301.                 return;
  302.             }
  303.             const sn = createSN();
  304.             currentSN = sn;
  305.             const now = new Date().toLocaleString();
  306.             const data = {
  307.                 sn:sn,
  308.                 type: type,
  309.                 email: document.getElementById('email').value,
  310.                 content: content,
  311.                 time: now,
  312.                 status:"pending"
  313.             }
  314.             feedbackDB[sn] = data;
  315.             document.getElementById('snText').innerText = sn;
  316.             modal.classList.remove('hidden');
  317.             modal.classList.add('flex');
  318.         }

  319.         // 复制单号
  320.         copySnBtn.onclick = async function(){
  321.             try {
  322.                 await navigator.clipboard.writeText(currentSN);
  323.                 this.innerHTML = '<i class="fa fa-check mr-1"></i>已复制';
  324.                 setTimeout(()=>{
  325.                     this.innerHTML = '<i class="fa fa-copy mr-1"></i>复制单号';
  326.                 },1500)
  327.             } catch (err) {
  328.                 alert("复制失败,请手动复制单号");
  329.             }
  330.         }

  331.         closeModal.onclick = function(){
  332.             modal.classList.add('hidden');
  333.             modal.classList.remove('flex');
  334.             form.reset();
  335.             currentSN = "";
  336.         }

  337.         // 查询反馈
  338.         const searchBtn = document.getElementById('searchBtn');
  339.         const searchSn = document.getElementById('searchSn');
  340.         const searchResult = document.getElementById('searchResult');
  341.         const searchEmpty = document.getElementById('searchEmpty');
  342.         searchBtn.onclick = function(){
  343.             const sn = searchSn.value.trim();
  344.             searchResult.classList.add('hidden');
  345.             searchEmpty.classList.add('hidden');
  346.             if(!sn){
  347.                 alert("请输入反馈单号");
  348.                 return;
  349.             }
  350.             if(feedbackDB[sn]){
  351.                 const item = feedbackDB[sn];
  352.                 document.getElementById('resSn').innerText = item.sn;
  353.                 document.getElementById('resType').innerText = typeMap[item.type];
  354.                 document.getElementById('resTime').innerText = item.time;
  355.                 const statusInfo = statusMap[item.status];
  356.                 document.getElementById('resStatus').innerHTML = `<span class="${statusInfo.cls}">${statusInfo.text}</span>`;
  357.                 document.getElementById('resContent').innerText = item.content;
  358.                 searchResult.classList.remove('hidden');
  359.             }else{
  360.                 searchEmpty.classList.remove('hidden');
  361.             }
  362.         }
  363.     </script>
  364. </body>
  365. </html>
复制代码


免责
帖子地址 打造全网最多免费游戏网站,部分资源失效,私聊站长补
今日访客 列表模式
10月上白班,问题处理时间等晚上
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|蔡州手游 |网站地图

GMT+8, 2026-10-20 06:10

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表