china0396 发表于 2026-10-19 22:20:56

反馈代码

- 默认密码:`admin123`,代码顶部`ADMIN_PASSWORD`变量直接修改密码
- 点击【管理员后台】,先进入密码登录页;密码正确才可以查看反馈列表、修改状态、删除记录
- 增加**退出登录**按钮,退出后需要重新输入密码
- 密码错误提示文字
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>意见反馈系统</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
      tailwind.config = {
            theme: {
                extend: {
                  colors: {
                        primary: '#1677ff',
                  },
                }
            }
      }
    </script>
    <style type="text/tailwindcss">
      @layer utilities {
            .form-shadow {
                box-shadow: 0 2px 12px 0 rgba(0,0,0,0.08);
            }
            .tab-active{
                border-bottom:2px solid #1677ff;
                color:#1677ff;
            }
            .status-pending {
                @apply bg-orange-100 text-orange-600 px-2 py-0.5 rounded;
            }
            .status-doing {
                @apply bg-blue-100 text-blue-600 px-2 py-0.5 rounded;
            }
            .status-done {
                @apply bg-green-100 text-green-600 px-2 py-0.5 rounded;
            }
      }
    </style>
</head>
<body class="bg-gray-50 min-h-screen">
    <div class="max-w-4xl mx-auto py-10 px-4">
      <div class="bg-white rounded-lg p-6 md:p-8 form-shadow">
            <div class="text-center mb-6">
                <h1 class="text- font-bold text-gray-800">意见反馈系统</h1>
            </div>
            <!-- 顶层大Tab:用户端 / 管理员 -->
            <div class="flex border-b border-gray-200 mb-6">
                <div id="tabUser" class="flex-1 py-3 text-center cursor-pointer tab-active font-medium">用户反馈</div>
                <div id="tabAdmin" class="flex-1 py-3 text-center cursor-pointer text-gray-500 font-medium">管理员后台</div>
            </div>

            <!-- ========== 用户面板(提交+查询) ========== -->
            <div id="panelUser">
                <div class="flex border-b border-gray-200 mb-6">
                  <div id="tabSubmit" class="flex-1 py-3 text-center cursor-pointer tab-active font-medium">提交反馈</div>
                  <div id="tabSearch" class="flex-1 py-3 text-center cursor-pointer text-gray-500 font-medium">查询反馈</div>
                </div>
                <!-- 提交反馈表单 -->
                <div id="panelSubmit">
                  <form id="feedbackForm">
                        <div class="mb-5">
                            <label class="block text-gray-700 mb-2">反馈类型 <span class="text-red-500">*</span></label>
                            <select id="type" class="w-full border border-gray-300 rounded px-3 py-2.5 focus:outline-none focus:border-primary">
                              <option value="">请选择反馈类型</option>
                              <option value="bug">功能BUG</option>
                              <option value="suggest">功能建议</option>
                              <option value="complain">投诉</option>
                              <option value="other">其他</option>
                            </select>
                        </div>
                        <div class="mb-5">
                            <label class="block text-gray-700 mb-2">邮箱</label>
                            <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">
                        </div>
                        <div class="mb-5">
                            <label class="block text-gray-700 mb-2">反馈内容 <span class="text-red-500">*</span></label>
                            <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>
                        </div>
                        <button type="submit" class="w-full bg-primary hover:bg-blue-600 text-white py-3 rounded transition-all">提交反馈</button>
                  </form>
                </div>
                <!-- 查询反馈面板 -->
                <div id="panelSearch" class="hidden">
                  <div class="mb-5">
                        <label class="block text-gray-700 mb-2">反馈单号 <span class="text-red-500">*</span></label>
                        <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">
                  </div>
                  <button id="searchBtn" class="w-full bg-primary hover:bg-blue-600 text-white py-3 rounded transition-all mb-6">查询</button>
                  <div id="searchResult" class="hidden border rounded p-4 bg-gray-50">
                        <h3 class="font-bold text-lg mb-3">反馈详情</h3>
                        <div class="space-y-2 text-gray-700">
                            <p>单号:<span id="resSn"></span></p>
                            <p>类型:<span id="resType"></span></p>
                            <p>提交时间:<span id="resTime"></span></p>
                            <p>处理状态:<span id="resStatus"></span></p>
                            <p>反馈内容:<span id="resContent"></span></p>
                        </div>
                  </div>
                  <div id="searchEmpty" class="hidden text-center text-red-500 py-4">未找到该单号的反馈记录</div>
                </div>
            </div>

            <!-- ========== 管理员登录面板 ========== -->
            <div id="panelAdminLogin" class="hidden">
                <h3 class="font-bold text-lg mb-4">管理员登录</h3>
                <div class="max-w-sm mx-auto">
                  <div class="mb-5">
                        <label class="block text-gray-700 mb-2">管理员密码</label>
                        <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">
                  </div>
                  <button id="adminLoginBtn" class="w-full bg-primary hover:bg-blue-600 text-white py-3 rounded transition-all">登录后台</button>
                  <p id="loginError" class="text-red-500 mt-3 text-center hidden">密码错误,请重试</p>
                </div>
            </div>

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

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

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

      // 顶层Tab 用户/管理员
      const tabUser = document.getElementById('tabUser');
      const tabAdmin = document.getElementById('tabAdmin');
      const panelUser = document.getElementById('panelUser');
      const panelAdminLogin = document.getElementById('panelAdminLogin');
      const panelAdmin = document.getElementById('panelAdmin');
      const adminLoginBtn = document.getElementById('adminLoginBtn');
      const adminLogoutBtn = document.getElementById('adminLogoutBtn');
      const adminPwdInput = document.getElementById('adminPwdInput');
      const loginError = document.getElementById('loginError');

      let isAdminLogin = false;

      tabUser.onclick = ()=>{
            tabUser.classList.add('tab-active');
            tabAdmin.classList.remove('tab-active');
            panelUser.classList.remove('hidden');
            panelAdminLogin.classList.add('hidden');
            panelAdmin.classList.add('hidden');
      }
      tabAdmin.onclick = ()=>{
            tabAdmin.classList.add('tab-active');
            tabUser.classList.remove('tab-active');
            panelUser.classList.add('hidden');
            if(isAdminLogin){
                panelAdmin.classList.remove('hidden');
                panelAdminLogin.classList.add('hidden');
                renderAdminList();
            }else{
                panelAdminLogin.classList.remove('hidden');
                panelAdmin.classList.add('hidden');
                loginError.classList.add('hidden');
                adminPwdInput.value = "";
            }
      }

      //管理员登录
      adminLoginBtn.onclick = function(){
            const pwd = adminPwdInput.value.trim();
            if(pwd === ADMIN_PASSWORD){
                isAdminLogin = true;
                panelAdminLogin.classList.add('hidden');
                panelAdmin.classList.remove('hidden');
                renderAdminList();
            }else{
                loginError.classList.remove('hidden');
            }
      }
      //退出登录
      adminLogoutBtn.onclick = function(){
            isAdminLogin = false;
            tabUser.click();
      }

      // 用户端内部tab
      const tabSubmit = document.getElementById('tabSubmit');
      const tabSearch = document.getElementById('tabSearch');
      const panelSubmit = document.getElementById('panelSubmit');
      const panelSearch = document.getElementById('panelSearch');
      tabSubmit.onclick = ()=>{
            tabSubmit.classList.add('tab-active');
            tabSearch.classList.remove('tab-active');
            panelSubmit.classList.remove('hidden');
            panelSearch.classList.add('hidden');
      }
      tabSearch.onclick = ()=>{
            tabSearch.classList.add('tab-active');
            tabSubmit.classList.remove('tab-active');
            panelSearch.classList.remove('hidden');
            panelSubmit.classList.add('hidden');
      }

      const form = document.getElementById('feedbackForm');
      const modal = document.getElementById('modal');
      const closeModal = document.getElementById('closeModal');
      const copySnBtn = document.getElementById('copySnBtn');
      let currentSN = "";

      // 模拟数据库
      let feedbackDB = {};
      const typeMap = {
            bug:"功能BUG",
            suggest:"功能建议",
            complain:"投诉",
            other:"其他"
      };
      const statusMap = {
            pending:{text:"待处理", cls:"status-pending"},
            doing:{text:"处理中", cls:"status-doing"},
            done:{text:"已完成", cls:"status-done"}
      };

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

      // 渲染管理员列表
      function renderAdminList(){
            const wrap = document.getElementById('adminList');
            const emptyTip = document.getElementById('adminEmpty');
            wrap.innerHTML = '';
            const keys = Object.keys(feedbackDB);
            if(keys.length === 0){
                emptyTip.classList.remove('hidden');
                return;
            }
            emptyTip.classList.add('hidden');
            // 倒序,最新的在最上面
            keys.reverse().forEach(sn=>{
                const item = feedbackDB;
                const statusInfo = statusMap;
                const html = `
                <div class="border p-4 rounded bg-gray-50">
                  <div class="flex flex-wrap justify-between items-center gap-2 mb-2">
                        <span class="font-medium">单号:${item.sn}</span>
                        <span class="${statusInfo.cls}">${statusInfo.text}</span>
                  </div>
                  <p class="text-sm text-gray-600 mb-1">类型:${typeMap} | 邮箱:${item.email||'未填写'}</p>
                  <p class="text-sm text-gray-600 mb-1">提交时间:${item.time}</p>
                  <p class="text-sm text-gray-700 my-2">反馈内容:${item.content}</p>
                  <div class="flex gap-2 mt-3">
                        <select class="statusSelect border rounded px-2 py-1" data-sn="${sn}">
                            <option value="pending" ${item.status==='pending'?'selected':''}>待处理</option>
                            <option value="doing" ${item.status==='doing'?'selected':''}>处理中</option>
                            <option value="done" ${item.status==='done'?'selected':''}>已完成</option>
                        </select>
                        <button class="delBtn bg-red-500 text-white px-3 py-1 rounded" data-sn="${sn}">删除</button>
                  </div>
                </div>
                `;
                wrap.innerHTML += html;
            })
            // 绑定修改状态事件
            document.querySelectorAll('.statusSelect').forEach(sel=>{
                sel.onchange = function(){
                  const sn = this.dataset.sn;
                  feedbackDB.status = this.value;
                  renderAdminList();
                }
            })
            // 删除事件
            document.querySelectorAll('.delBtn').forEach(btn=>{
                btn.onclick = function(){
                  const sn = this.dataset.sn;
                  if(confirm('确定删除这条反馈?')){
                        delete feedbackDB;
                        renderAdminList();
                  }
                }
            })
      }

      //表单提交
      form.onsubmit = function(e){
            e.preventDefault();
            const type = document.getElementById('type').value;
            const content = document.getElementById('content').value.trim();
            if(!type){
                alert("请选择反馈类型");
                return;
            }
            if(!content){
                alert("请填写反馈内容");
                return;
            }
            const sn = createSN();
            currentSN = sn;
            const now = new Date().toLocaleString();
            const data = {
                sn:sn,
                type: type,
                email: document.getElementById('email').value,
                content: content,
                time: now,
                status:"pending"
            }
            feedbackDB = data;
            document.getElementById('snText').innerText = sn;
            modal.classList.remove('hidden');
            modal.classList.add('flex');
      }

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

      closeModal.onclick = function(){
            modal.classList.add('hidden');
            modal.classList.remove('flex');
            form.reset();
            currentSN = "";
      }

      // 查询反馈
      const searchBtn = document.getElementById('searchBtn');
      const searchSn = document.getElementById('searchSn');
      const searchResult = document.getElementById('searchResult');
      const searchEmpty = document.getElementById('searchEmpty');
      searchBtn.onclick = function(){
            const sn = searchSn.value.trim();
            searchResult.classList.add('hidden');
            searchEmpty.classList.add('hidden');
            if(!sn){
                alert("请输入反馈单号");
                return;
            }
            if(feedbackDB){
                const item = feedbackDB;
                document.getElementById('resSn').innerText = item.sn;
                document.getElementById('resType').innerText = typeMap;
                document.getElementById('resTime').innerText = item.time;
                const statusInfo = statusMap;
                document.getElementById('resStatus').innerHTML = `<span class="${statusInfo.cls}">${statusInfo.text}</span>`;
                document.getElementById('resContent').innerText = item.content;
                searchResult.classList.remove('hidden');
            }else{
                searchEmpty.classList.remove('hidden');
            }
      }
    </script>
</body>
</html>


页: [1]
查看完整版本: 反馈代码