|
- 默认密码:`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-[24px] 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-[600px] 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[sn];
- const statusInfo = statusMap[item.status];
- 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.type]} | 邮箱:${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[sn].status = this.value;
- renderAdminList();
- }
- })
- // 删除事件
- document.querySelectorAll('.delBtn').forEach(btn=>{
- btn.onclick = function(){
- const sn = this.dataset.sn;
- if(confirm('确定删除这条反馈?')){
- delete feedbackDB[sn];
- 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[sn] = 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[sn]){
- const item = feedbackDB[sn];
- document.getElementById('resSn').innerText = item.sn;
- document.getElementById('resType').innerText = typeMap[item.type];
- document.getElementById('resTime').innerText = item.time;
- const statusInfo = statusMap[item.status];
- 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>
复制代码
|
免责
帖子地址
打造全网最多免费游戏网站,部分资源失效,私聊站长补
|