个人整改后做的html版网页密码管理系统
作者:小编日期:2026-09-02浏览:4389分类:只有源码
| 主要整改: 网址指定浏览器访问: 用于销售助理平时点击添加后客户的ERP的网页进入客户的ERP系统,可以根据自己在后台添加的网址指定浏览器来实现。 点击访问客户ERP 系统的时候,会自动检测指定浏览器是否已经安装,如未安装,会弹窗提示安装浏览器。 管理员后台整改: 主要整改添加客户ERP系统是选择使用什么浏览器。数据自动保存,管理员后台还修改了数据导入及导出JSON功能。 管理员后台密码默认: admin123,员工查看密码默认: employee2024 支持 Excel (.xls, .xlsx) 导入导出 所有数据存储方式改成了 localStorage 可点击「备份数据库」下载完整数据库文件 界面主题增加: 增加有8种颜色主题切换 |
<!DOCTYPE html><html lang="zh-CN"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> <title>企业密码管理系统</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/sql-wasm.js"></script> <script src="https://cdn.sheetjs.com/xlsx-0.20.2/package/dist/xlsx.full.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script> <style id="theme-style"> :root { --bg: #f1f5f9; --card: #ffffff; --border: #e9edf2; --text: #1e293b; --text2: #475569; --shadow: rgba(0,0,0,0.05); --primary: #1e3c72; --primary-hover: #0f2b4f; --input: #ffffff; --input-border: #cfdfed; --table-header: #fafcff; --badge-default: #e2e8f0; --badge-edge: #0078d4; --badge-chrome: #4285f4; --badge-firefox: #ff9400; --success: #10b981; --warning: #f59e0b; --danger: #ef4444; --info: #3b82f6; } .theme-red { --bg: #fef2f2; --card: #ffffff; --primary: #b91c1c; --primary-hover: #7f1d1d; --border: #fecaca; --table-header: #fef2f2; } .theme-orange { --bg: #fff7ed; --card: #ffffff; --primary: #c2410c; --primary-hover: #9a3412; --border: #fed7aa; --table-header: #fff7ed; } .theme-yellow { --bg: #fefce8; --card: #ffffff; --primary: #a16207; --primary-hover: #854d0e; --border: #fde68a; --table-header: #fefce8; } .theme-green { --bg: #f0fdf4; --card: #ffffff; --primary: #15803d; --primary-hover: #166534; --border: #bbf7d0; --table-header: #f0fdf4; } .theme-blue { --bg: #eff6ff; --card: #ffffff; --primary: #1d4ed8; --primary-hover: #1e40af; --border: #bfdbfe; --table-header: #eff6ff; } .theme-purple { --bg: #faf5ff; --card: #ffffff; --primary: #7e22ce; --primary-hover: #6b21a8; --border: #e9d5ff; --table-header: #faf5ff; } .theme-pink { --bg: #fdf2f8; --card: #ffffff; --primary: #be185d; --primary-hover: #9d174d; --border: #fbcfe8; --table-header: #fdf2f8; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', system-ui; background: var(--bg); padding: 20px 16px; transition: 0.3s; } .app { max-width: 1400px; margin: 0 auto; } .header { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; margin-bottom: 20px; } .header h1 { font-size: 1.4rem; font-weight: 600; color: var(--text); } .theme-bar { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; } .theme-bar span { font-size: 0.75rem; color: var(--text2); margin-right: 2px; } .theme-dot { width: 28px; height: 28px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; transition: 0.2s; } .theme-dot:hover { transform: scale(1.1); } .theme-dot.active { border-color: var(--text); box-shadow: 0 0 0 2px var(--bg); } .tab-bar { display: flex; gap: 8px; margin-bottom: 20px; background: var(--card); padding: 6px 16px; border-radius: 40px; width: fit-content; flex-wrap: wrap; border: 1px solid var(--border); } .tab-btn { border: none; background: transparent; padding: 10px 24px; font-size: 0.95rem; font-weight: 500; border-radius: 30px; cursor: pointer; color: var(--text2); transition: 0.2s; } .tab-btn.active { background: var(--primary); color: #fff; } .tab-btn:hover:not(.active) { background: var(--bg); } .card { background: var(--card); border-radius: 20px; border: 1px solid var(--border); overflow: hidden; margin-bottom: 20px; box-shadow: 0 2px 8px var(--shadow); } .card-header { padding: 16px 20px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; } .card-header h2 { font-size: 1.2rem; font-weight: 600; color: var(--text); } .btn { border: none; background: var(--bg); padding: 6px 18px; border-radius: 30px; font-weight: 500; cursor: pointer; transition: 0.2s; font-size: 0.85rem; color: var(--text); } .btn-primary { background: var(--primary); color: #fff; } .btn-primary:hover { background: var(--primary-hover); } .btn-outline { background: transparent; border: 1px solid var(--border); } .btn-outline:hover { background: var(--bg); } .btn-success { background: var(--success); color: #fff; } .btn-success:hover { background: #059669; } .btn-warning { background: var(--warning); color: #fff; } .btn-warning:hover { background: #d97706; } .btn-danger { background: var(--danger); color: #fff; } .btn-danger:hover { background: #dc2626; } .btn-info { background: var(--info); color: #fff; } .btn-info:hover { background: #2563eb; } .btn-sm { padding: 2px 10px; font-size: 0.7rem; } .btn-open { background: #22d3ee; color: #0e7490; } .btn-open:hover { background: #67e8f9; } .btn-auto-backup { background: #8b5cf6; color: #fff; } .btn-auto-backup:hover { background: #7c3aed; } table { width: 100%; border-collapse: collapse; font-size: 0.9rem; } th, td { text-align: left; padding: 12px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; } th { background: var(--table-header); font-weight: 600; color: var(--text); } .url-link { color: var(--primary); text-decoration: none; font-weight: 500; } .url-link:hover { text-decoration: underline; } .url-cell { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } .password-masked { font-family: monospace; background: var(--bg); padding: 2px 12px; border-radius: 20px; display: inline-block; font-size: 0.85rem; } .password-plain { font-family: monospace; background: #dbeafe; padding: 2px 12px; border-radius: 20px; display: inline-block; font-size: 0.85rem; } .input-group { margin-bottom: 14px; display: flex; flex-direction: column; gap: 4px; } .input-group label { font-weight: 600; font-size: 0.8rem; color: var(--text2); } input, select { padding: 8px 14px; border-radius: 16px; border: 1px solid var(--input-border); font-family: inherit; background: var(--input); color: var(--text); } input:focus, select:focus { outline: none; border-color: var(--primary); } .modal { display: none; position: fixed; top:0; left:0; width:100%; height:100%; background: rgba(0,0,0,0.4); align-items: center; justify-content: center; z-index: 1000; } .modal-content { background: var(--card); max-width: 500px; width: 92%; border-radius: 24px; padding: 24px; } .toast { position: fixed; bottom: 24px; right: 24px; background: var(--text); color: #fff; padding: 10px 20px; border-radius: 30px; opacity: 0; transition: 0.25s; z-index: 1100; font-size: 0.85rem; pointer-events: none; max-width: 90%; } .toast.show { opacity: 1; } .toast.error { background: var(--danger); } .toast.success { background: var(--success); } .hidden { display: none; } .flex-btns { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; } .verify-panel { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } .file-input-label { background: var(--bg); border: 1px solid var(--border); padding: 6px 16px; border-radius: 30px; cursor: pointer; font-size: 0.85rem; } input[type="file"] { display: none; } .settings-group { background: var(--bg); border-radius: 16px; padding: 14px 18px; margin: 12px 20px 16px 20px; border: 1px solid var(--border); } .settings-group h4 { margin-bottom: 10px; color: var(--text); font-size: 0.9rem; } .settings-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 6px; } .settings-row span { font-size: 0.85rem; color: var(--text2); min-width: 130px; } .browser-badge { display: inline-block; padding: 2px 10px; border-radius: 16px; font-size: 0.7rem; margin-right: 6px; } .browser-default { background: var(--badge-default); color: var(--text2); } .browser-edge { background: var(--badge-edge); color: #fff; } .browser-chrome { background: var(--badge-chrome); color: #fff; } .browser-firefox { background: var(--badge-firefox); color: #fff; } .copy-url-btn { background: var(--bg); border: none; padding: 2px 8px; border-radius: 14px; cursor: pointer; font-size: 0.6rem; color: var(--text2); } .copy-url-btn:hover { background: var(--border); } .db-status { background: #d1fae5; padding: 6px 16px; border-radius: 10px; font-size: 0.75rem; color: #065f46; margin: 0 20px 12px 20px; display: flex; justify-content: space-between; flex-wrap: wrap; gap: 6px; } .open-btn-group { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; } .open-btn-group .btn { padding: 2px 10px; font-size: 0.65rem; } .empty-row td { text-align: center; padding: 40px; color: var(--text2); } .admin-auth-overlay { position: fixed; top:0; left:0; width:100%; height:100%; background: rgba(0,0,0,0.6); display: flex; align-items: center; justify-content: center; z-index: 2000; } .admin-auth-box { background: var(--card); border-radius: 24px; padding: 28px; width: 92%; max-width: 380px; text-align: center; } .admin-auth-box input { width: 100%; margin: 10px 0; } .admin-auth-box .error { color: var(--danger); font-size: 0.8rem; } .scroll-x { overflow-x: auto; } .browser-hint-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.55); display: none; align-items: center; justify-content: center; z-index: 3000; } .browser-hint-overlay.show { display: flex; } .browser-hint-box { background: var(--card); border-radius: 24px; padding: 32px 28px; max-width: 460px; width: 92%; text-align: center; box-shadow: 0 20px 60px rgba(0,0,0,0.3); animation: fadeIn 0.3s ease; } @keyframes fadeIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } } .browser-hint-box .icon { font-size: 3.2rem; margin-bottom: 12px; } .browser-hint-box h3 { font-size: 1.3rem; color: var(--text); margin-bottom: 10px; } .browser-hint-box p { font-size: 0.9rem; color: var(--text2); line-height: 1.6; margin-bottom: 18px; } .browser-hint-box .btn-group { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } .browser-hint-box .btn-group .btn { min-width: 100px; padding: 10px 24px; font-size: 0.9rem; } .browser-hint-box .checkbox-row { display: flex; align-items: center; justify-content: center; gap: 8px; margin: 12px 0 16px 0; font-size: 0.8rem; color: var(--text2); } .browser-hint-box .checkbox-row input[type="checkbox"] { width: 16px; height: 16px; cursor: pointer; accent-color: var(--primary); } .storage-info { background: var(--bg); border-radius: 12px; padding: 12px 18px; margin: 8px 20px 12px 20px; border: 1px solid var(--border); font-size: 0.8rem; color: var(--text2); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px; } .storage-info .label { font-weight: 600; color: var(--text); } .storage-info .status { color: var(--success); } .storage-info .backup-status { color: var(--info); font-size: 0.75rem; } .backup-settings { background: var(--bg); border-radius: 12px; padding: 12px 18px; margin: 8px 20px 12px 20px; border: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; } .backup-settings .label { font-weight: 600; color: var(--text); font-size: 0.85rem; } .backup-settings .desc { font-size: 0.75rem; color: var(--text2); } .backup-settings .toggle { display: flex; align-items: center; gap: 8px; } .toggle-switch { width: 40px; height: 22px; background: #cbd5e1; border-radius: 12px; cursor: pointer; position: relative; transition: 0.3s; border: none; padding: 0; } .toggle-switch.active { background: var(--success); } .toggle-switch::after { content: ''; width: 18px; height: 18px; background: white; border-radius: 50%; position: absolute; top: 2px; left: 2px; transition: 0.3s; box-shadow: 0 1px 3px rgba(0,0,0,0.2); } .toggle-switch.active::after { left: 20px; } [url=home.php?mod=space&uid=945662]@media[/url] (max-width: 600px) { th, td { padding: 8px 10px; font-size: 0.8rem; } .card-header { padding: 12px 14px; } .browser-hint-box { padding: 24px 18px; } .browser-hint-box .btn-group .btn { min-width: 80px; padding: 8px 16px; font-size: 0.8rem; } .storage-info, .backup-settings { flex-direction: column; align-items: flex-start; } } </style></head><body><div class="app"> <div class="header"> <h1>密码管理系统</h1> <div class="theme-bar"> <span>主题</span> <span class="theme-dot active" data-theme="default" style="background:#64748b;" title="默认"></span> <span class="theme-dot" data-theme="red" style="background:#dc2626;" title="红"></span> <span class="theme-dot" data-theme="orange" style="background:#ea580c;" title="橙"></span> <span class="theme-dot" data-theme="yellow" style="background:#ca8a04;" title="黄"></span> <span class="theme-dot" data-theme="green" style="background:#16a34a;" title="绿"></span> <span class="theme-dot" data-theme="blue" style="background:#2563eb;" title="蓝"></span> <span class="theme-dot" data-theme="purple" style="background:#9333ea;" title="紫"></span> <span class="theme-dot" data-theme="pink" style="background:#db2777;" title="粉"></span> </div> </div> <div class="tab-bar"> <button class="tab-btn active" data-tab="employee">员工门户</button> <button class="tab-btn" data-tab="admin">管理后台</button> </div> <div id="employeePanel"> <div class="card"> <div class="card-header"> <h2>快捷访问</h2> <div class="verify-panel"> <input type="password" id="empViewPwd" placeholder="查看密码" style="width:150px;" autocomplete="off"> <button class="btn btn-primary" id="verifyEmpBtn">显示密码</button> </div> </div> <div class="scroll-x"> <table> <thead><tr><th>网址</th><th>账号</th><th>密码</th><th>打开方式</th></tr></thead> <tbody id="employeeTableBody"></tbody> </table> </div> <div style="padding:10px 20px;border-top:1px solid var(--border);font-size:0.7rem;color:var(--text2);"> <span>查看密码: <strong>employee2024</strong></span> </div> </div> </div> <div id="adminPanel" class="hidden"> <div class="card"> <div class="card-header"> <h2>凭证管理</h2> <div class="flex-btns"> <button class="btn btn-primary" id="openAddCredBtn">新增</button> <button class="btn btn-success" id="exportExcelBtn">导出 Excel</button> <label class="file-input-label" for="importExcelInput">导入 Excel</label> <input type="file" id="importExcelInput" accept=".xls,.xlsx"> <button class="btn btn-info" id="exportJsonBtn">📥 导出 JSON</button> <label class="file-input-label" for="importJsonInput" style="background:var(--primary);color:#fff;">📤 导入 JSON</label> <input type="file" id="importJsonInput" accept=".json"> </div> </div> <div class="db-status"> <span>📀 数据库已连接</span> <span id="dbStatusText">localStorage 持久化存储</span> </div> <!-- 自动备份设置 --> <div class="backup-settings"> <div> <span class="label">💾 自动备份到下载文件夹</span> <span class="desc">每次修改数据后自动导出 JSON 文件到电脑下载目录</span> </div> <div class="toggle"> <span id="autoBackupStatus" style="font-size:0.75rem;color:var(--text2);">已关闭</span> <button class="toggle-switch" id="autoBackupToggle" title="点击切换自动备份"></button> </div> </div> <!-- 存储信息 --> <div class="storage-info"> <span><span class="label">💾 存储位置:</span>浏览器 localStorage</span> <span><span class="label">📊 记录数:</span><span id="recordCount">0</span> 条</span> <span><span class="label">📌 持久化:</span><span class="status">✅ 刷新/关闭不丢失</span></span> <span class="backup-status" id="lastBackupTime">📋 最后备份:无</span> </div> <div class="scroll-x"> <table> <thead><tr><th>网址</th><th>账号</th><th>密码</th><th>浏览器</th><th>操作</th></tr></thead> <tbody id="adminTableBody"></tbody> </table> </div> <div class="settings-group"> <h4>⚙️ 安全设置</h4> <div class="settings-row"><span>员工查看密码</span><input type="password" id="newEmployeePwd" placeholder="新密码" style="width:160px;"><button class="btn btn-warning" id="updateEmployeePwdBtn">修改</button></div> <div class="settings-row"><span>管理员密码</span><input type="password" id="newAdminPwd" placeholder="新密码" style="width:160px;"><button class="btn btn-warning" id="updateAdminPwdBtn">修改</button></div> </div> <div style="padding:14px 20px;border-top:1px solid var(--border);font-size:0.75rem;color:var(--text2);"> <span>管理员: <strong>admin123</strong></span> <span style="margin-left:16px;">员工: <strong>employee2024</strong></span> <span style="margin-left:16px;">💡 开启「自动备份」后每次修改自动导出 JSON 到下载文件夹</span> </div> </div> </div></div><!-- 浏览器提示弹窗 --><div class="browser-hint-overlay" id="browserHintOverlay"> <div class="browser-hint-box"> <div class="icon" id="hintIcon">🌐</div> <h3 id="hintTitle">浏览器</h3> <p id="hintDesc">请先确认电脑已安装该浏览器,如未安装请先下载。</p> <div class="checkbox-row"> <input type="checkbox" id="hintDontShowAgain"> <label for="hintDontShowAgain">下次不再提示</label> </div> <div class="btn-group"> <button class="btn btn-outline" id="hintCancel">取消</button> <button class="btn btn-warning" id="hintDownload">⬇ 下载浏览器</button> <button class="btn btn-primary" id="hintConfirm">确定,已安装</button> </div> </div></div><div id="credModal" class="modal"> <div class="modal-content"> <h3 id="modalTitle">添加凭证</h3> <div class="input-group"><label>网址</label><input type="text" id="credUrl" placeholder="https://..."></div> <div class="input-group"><label>账号</label><input type="text" id="credUsername" placeholder="账号"></div> <div class="input-group"><label>密码</label><input type="text" id="credPassword" placeholder="密码"></div> <div class="input-group"> <label>浏览器</label> <select id="credBrowser"> <option value="default">默认</option> <option value="edge">Edge</option> <option value="chrome">Chrome</option> <option value="firefox">Firefox</option> </select> </div> <input type="hidden" id="editId" value=""> <div style="display:flex;gap:10px;justify-content:flex-end;margin-top:16px;"> <button class="btn btn-outline" id="closeModalBtn">取消</button> <button class="btn btn-primary" id="saveCredBtn">保存</button> </div> </div></div><div id="toast" class="toast">操作成功</div><script> function h(s) { return CryptoJS.SHA256(s).toString(); } // ===== 浏览器配置 ===== var BROWSER_CONFIG = { edge: { icon: '🔷', name: 'Edge 浏览器', desc: '使用前提:已安装Edge浏览器。(未安装请先下载安装)。', download: 'https://www.microsoft.com/zh-cn/edge/download', protocol: 'microsoft-edge:' }, chrome: { icon: '🔴', name: '谷歌浏览器', desc: '使用前提:已安装谷歌浏览器。(未安装请先下载安装)。', download: 'https://sw.pcmgr.qq.com/62a4683d5d6deb5f13daf8e29b0d90dd/6a962b0c/spcmgr/download/152.0.7977.65_chrome_installer_uncompressed-win64.exe', protocol: 'googlechrome:' }, firefox: { icon: '🦊', name: '火狐浏览器', desc: '使用前提:已安装火狐浏览器。(未安装请先下载安装)。', download: 'https://sw.pcmgr.qq.com/e38a6e930fd7892da4c3d82d122394cb/6a962af4/spcmgr/download/22931-110819-Firefox-setup-win64_116.0.3.8627.exe', protocol: 'firefox:' } }; // ===== 浏览器提示弹窗控制 ===== var hintOverlay = document.getElementById('browserHintOverlay'); var hintDontShowAgain = document.getElementById('hintDontShowAgain'); var hintIcon = document.getElementById('hintIcon'); var hintTitle = document.getElementById('hintTitle'); var hintDesc = document.getElementById('hintDesc'); var hintDownload = document.getElementById('hintDownload'); var hintConfirm = document.getElementById('hintConfirm'); var hintCancel = document.getElementById('hintCancel'); var pendingBrowser = null; var pendingUrl = null; function getHintSetting(browser) { return localStorage.getItem('hint_dismissed_' + browser) === 'true'; } function setHintSetting(browser, dismissed) { localStorage.setItem('hint_dismissed_' + browser, dismissed ? 'true' : 'false'); } function showBrowserHint(browser, url) { if (getHintSetting(browser)) { doOpenBrowser(browser, url); return; } var config = BROWSER_CONFIG[browser]; if (!config) { window.open(url, '_blank'); return; } pendingBrowser = browser; pendingUrl = url; hintIcon.textContent = config.icon; hintTitle.textContent = config.name; hintDesc.textContent = config.desc; hintDownload.textContent = '⬇ 下载 ' + config.name; hintOverlay.classList.add('show'); hintDontShowAgain.checked = false; } function hideBrowserHint() { hintOverlay.classList.remove('show'); } function doOpenBrowser(b, u) { var config = BROWSER_CONFIG[b]; if (!config) { window.open(u, '_blank'); return; } var url = u; if (!url.startsWith('http://') && !url.startsWith('https://')) { url = 'https://' + url; } var fullUrl = config.protocol + url; try { var currentUrl = window.location.href; window.location.href = fullUrl; setTimeout(function() { if (window.location.href === currentUrl) { tryMethod2(b, url); } }, 800); } catch(e) { tryMethod2(b, url); } } function tryMethod2(b, u) { var config = BROWSER_CONFIG[b]; var url = u; if (!url.startsWith('http://') && !url.startsWith('https://')) { url = 'https://' + url; } var protocols = [ config.protocol + url, config.protocol + '//open?url=' + encodeURIComponent(url), config.protocol + '//' + url ]; for (var i = 0; i < protocols.length; i++) { try { var w = window.open(protocols[i], '_blank'); if (w) { setTimeout(function(win) { try { if (win && win.closed) { tryMethod3(b, u); } } catch(e) { tryMethod3(b, u); } }, 1500, w); return; } } catch(e) {} } tryMethod3(b, u); } function tryMethod3(b, u) { var config = BROWSER_CONFIG[b]; var url = u; if (!url.startsWith('http://') && !url.startsWith('https://')) { url = 'https://' + url; } var fullUrl = config.protocol + url; try { var iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = fullUrl; document.body.appendChild(iframe); setTimeout(function() { try { document.body.removeChild(iframe); } catch(e) {} showDownloadDialog(b, u); }, 2000); } catch(e) { showDownloadDialog(b, u); } } function showDownloadDialog(b, u) { var config = BROWSER_CONFIG[b]; var name = config ? config.name : '该浏览器'; var url = config ? config.download : null; if (url) { if (confirm('未检测到 ' + name + ',是否下载?\n\n点击「确定」前往下载\n点击「取消」使用默认浏览器打开')) { window.open(url, '_blank'); } else { window.open(u, '_blank'); } } else { window.open(u, '_blank'); } } hintConfirm.addEventListener('click', function() { if (hintDontShowAgain.checked && pendingBrowser) { setHintSetting(pendingBrowser, true); } hideBrowserHint(); if (pendingUrl && pendingBrowser) { setTimeout(function() { doOpenBrowser(pendingBrowser, pendingUrl); }, 150); } }); hintCancel.addEventListener('click', function() { hideBrowserHint(); pendingBrowser = null; pendingUrl = null; }); hintDownload.addEventListener('click', function() { if (pendingBrowser) { var config = BROWSER_CONFIG[pendingBrowser]; if (config && config.download) { window.open(config.download, '_blank'); } } }); hintOverlay.addEventListener('click', function(e) { if (e.target === hintOverlay) { hideBrowserHint(); pendingBrowser = null; pendingUrl = null; } }); // ===== 浏览器打开入口 ===== function bn(b) { var map = { edge:'Edge浏览器打开', chrome:'谷歌浏览器打开', firefox:'火狐浏览器打开' }; return map[b] || '默认浏览器打开'; } function bc(b) { var map = { edge:'browser-edge', chrome:'browser-chrome', firefox:'browser-firefox' }; return map[b] || 'browser-default'; } function openWith(b, u) { if (b === 'default' || !b) { window.open(u, '_blank'); return; } showBrowserHint(b, u); } function openHTML(b, u) { var name = bn(b); var cls = bc(b); var su = u.replace(/'/g, "\\'"); var html = '<div class="open-btn-group">'; if (b === 'default') { html += '<button class="btn btn-open btn-sm">打开</button>'; } else { html += '<button class="btn btn-open btn-sm">' + name + '</button>'; html += '<button class="btn btn-outline btn-sm">默认浏览器打开</button>'; } html += '</div>'; return html; } function copyText(t, msg) { try { navigator.clipboard.writeText(t); toast(msg); } catch(e) { var ta = document.createElement('textarea'); ta.value = t; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); toast(msg); } } // ============================================================ // ===== 数据存储层 - localStorage 持久化存储 ===== // ============================================================ var STORAGE_KEY = 'password_manager_data'; var CONFIG_KEY = 'password_manager_config'; var empVisible = false; var adminAuth = false; var empHash = ''; var adminHash = ''; var autoBackupEnabled = false; var lastBackupTime = null; var credentials = []; var nextId = 1; // 默认密码 var DEF_EMP = h('employee2024'); var DEF_ADMIN = h('admin123'); // ===== 数据操作 ===== function loadData() { try { var saved = localStorage.getItem(STORAGE_KEY); if (saved) { var parsed = JSON.parse(saved); credentials = parsed.credentials || []; nextId = parsed.nextId || 1; return true; } } catch(e) { console.error('加载数据失败:', e); } return false; } function saveData() { try { var data = { credentials: credentials, nextId: nextId }; localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); return true; } catch(e) { console.error('保存数据失败:', e); return false; } } function loadConfig() { try { var saved = localStorage.getItem(CONFIG_KEY); if (saved) { var parsed = JSON.parse(saved); empHash = parsed.empHash || DEF_EMP; adminHash = parsed.adminHash || DEF_ADMIN; autoBackupEnabled = parsed.autoBackupEnabled || false; return true; } } catch(e) { console.error('加载配置失败:', e); } return false; } function saveConfig() { try { var data = { empHash: empHash, adminHash: adminHash, autoBackupEnabled: autoBackupEnabled }; localStorage.setItem(CONFIG_KEY, JSON.stringify(data)); return true; } catch(e) { console.error('保存配置失败:', e); return false; } } function initData() { var loaded = loadData(); var configLoaded = loadConfig(); if (!loaded) { credentials = [ { id: 1, url: 'https://mail.company.com', username: 'zhang.san@company.com', password: 'Mail@2024Secure', browser: 'default' }, { id: 2, url: 'https://hrsystem.company.com', username: 'hr_admin', password: 'HrP@ss#2024', browser: 'edge' }, { id: 3, url: 'https://gitlab.company.com', username: 'dev_lihua', password: 'GitLab!7890', browser: 'chrome' }, { id: 4, url: 'https://jira.company.com', username: 'project_manager', password: 'Jira@2025', browser: 'firefox' } ]; nextId = 5; saveData(); } if (!configLoaded) { empHash = DEF_EMP; adminHash = DEF_ADMIN; autoBackupEnabled = false; saveConfig(); } updateStorageInfo(); updateLastBackupTime(); updateAutoBackupUI(); } // ===== 自动备份 ===== function getAutoBackupSetting() { return autoBackupEnabled; } function setAutoBackupSetting(enabled) { autoBackupEnabled = enabled; saveConfig(); updateAutoBackupUI(); } function updateAutoBackupUI() { var toggle = document.getElementById('autoBackupToggle'); var status = document.getElementById('autoBackupStatus'); if (toggle) { toggle.classList.toggle('active', autoBackupEnabled); } if (status) { status.textContent = autoBackupEnabled ? '✅ 已开启' : '⛔ 已关闭'; status.style.color = autoBackupEnabled ? 'var(--success)' : 'var(--text2)'; } } function exportToDownloadFolder() { try { var data = { credentials: credentials, nextId: nextId, exportTime: new Date().toISOString(), version: '1.0' }; var json = JSON.stringify(data, null, 2); var blob = new Blob([json], { type: 'application/json' }); var url = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; var now = new Date(); var dateStr = now.getFullYear() + '-' + String(now.getMonth()+1).padStart(2,'0') + '-' + String(now.getDate()).padStart(2,'0') + '_' + String(now.getHours()).padStart(2,'0') + '-' + String(now.getMinutes()).padStart(2,'0'); a.download = 'password_backup_' + dateStr + '.json'; document.body.appendChild(a); a.click(); document.body.removeChild(a); setTimeout(function() { URL.revokeObjectURL(url); }, 5000); lastBackupTime = now; updateLastBackupTime(); return true; } catch(e) { console.error('自动备份失败:', e); return false; } } function updateLastBackupTime() { var el = document.getElementById('lastBackupTime'); if (!el) return; if (lastBackupTime) { var str = lastBackupTime.getFullYear() + '-' + String(lastBackupTime.getMonth()+1).padStart(2,'0') + '-' + String(lastBackupTime.getDate()).padStart(2,'0') + ' ' + String(lastBackupTime.getHours()).padStart(2,'0') + ':' + String(lastBackupTime.getMinutes()).padStart(2,'0'); el.textContent = '📋 最后备份:' + str; } else { el.textContent = '📋 最后备份:无'; } } // ===== 增删改查 ===== function allCreds() { return credentials.slice().sort(function(a, b) { return b.id - a.id; }); } function getCredById(id) { for (var i = 0; i < credentials.length; i++) { if (credentials[i].id === id) return credentials[i]; } return null; } function upsert(id, url, username, password, browser) { if (!url || !username || !password) return false; if (id === null || id === undefined || id === '') { var newCred = { id: nextId++, url: url, username: username, password: password, browser: browser || 'default' }; credentials.push(newCred); } else { var found = false; for (var i = 0; i < credentials.length; i++) { if (credentials[i].id === id) { credentials[i].url = url; credentials[i].username = username; credentials[i].password = password; credentials[i].browser = browser || 'default'; found = true; break; } } if (!found) return false; } saveData(); updateStorageInfo(); if (autoBackupEnabled) { exportToDownloadFolder(); } return true; } function delCred(id) { for (var i = 0; i < credentials.length; i++) { if (credentials[i].id === id) { credentials.splice(i, 1); saveData(); updateStorageInfo(); if (autoBackupEnabled) { exportToDownloadFolder(); } return true; } } return false; } function batchUpsert(records) { var cnt = 0; for (var i = 0; i < records.length; i++) { var rec = records[i]; if (rec.url && rec.username && rec.password) { var exists = false; for (var j = 0; j < credentials.length; j++) { if (credentials[j].url === rec.url) { credentials[j].username = rec.username; credentials[j].password = rec.password; credentials[j].browser = rec.browser || 'default'; exists = true; cnt++; break; } } if (!exists) { credentials.push({ id: nextId++, url: rec.url, username: rec.username, password: rec.password, browser: rec.browser || 'default' }); cnt++; } } } saveData(); updateStorageInfo(); if (autoBackupEnabled) { exportToDownloadFolder(); } return cnt; } function updateStorageInfo() { var el = document.getElementById('recordCount'); if (el) el.textContent = credentials.length; } // ===== 密码配置 ===== function getEmpHash() { return empHash; } function getAdminHash() { return adminHash; } function setEmpHash(newHash) { empHash = newHash; saveConfig(); } function setAdminHash(newHash) { adminHash = newHash; saveConfig(); } // ===== 导出/导入 JSON ===== function exportJson() { try { var data = { credentials: credentials, nextId: nextId, exportTime: new Date().toISOString(), version: '1.0' }; var json = JSON.stringify(data, null, 2); var blob = new Blob([json], { type: 'application/json' }); var url = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; var now = new Date(); var dateStr = now.getFullYear() + '-' + String(now.getMonth()+1).padStart(2,'0') + '-' + String(now.getDate()).padStart(2,'0') + '_' + String(now.getHours()).padStart(2,'0') + '-' + String(now.getMinutes()).padStart(2,'0'); a.download = 'password_data_' + dateStr + '.json'; document.body.appendChild(a); a.click(); document.body.removeChild(a); setTimeout(function() { URL.revokeObjectURL(url); }, 5000); toast('数据已导出到下载目录', 'success'); } catch(e) { toast('导出失败: ' + e.message, true); } } function importJson(file) { var reader = new FileReader(); reader.onload = function(e) { try { var data = JSON.parse(e.target.result); if (!data.credentials || !Array.isArray(data.credentials)) { toast('无效的数据文件', true); return; } if (!confirm('确定要恢复此数据吗?当前数据将被覆盖!')) { return; } credentials = data.credentials; nextId = data.nextId || (credentials.length > 0 ? Math.max.apply(null, credentials.map(function(c) { return c.id; })) + 1 : 1); saveData(); updateStorageInfo(); if (autoBackupEnabled) { exportToDownloadFolder(); } renderEmp(); renderAdmin(); toast('数据恢复成功', 'success'); } catch(err) { toast('无效的数据文件: ' + err.message, true); } }; reader.readAsText(file); } // ===== 渲染 ===== function renderEmp() { var tbody = document.getElementById('employeeTableBody'); if (!tbody) return; var list = allCreds(); if (!list.length) { tbody.innerHTML = '<tr class="empty-row"><td colspan="4">暂无数据</td></tr>'; return; } var html = ''; for (var i = 0; i < list.length; i++) { var item = list[i]; var name = bn(item.browser); var cls = bc(item.browser); var pwd = empVisible ? '<span class="password-plain">' + esc(item.password) + '</span>' : '<span class="password-masked">●●●●●●●●</span>'; html += '<tr><td><div class="url-cell"><a href="' + esc(item.url) + '" target="_blank" class="url-link">' + esc(item.url) + '</a><button class="copy-url-btn" data-url="' + esc(item.url) + '">复制</button></div></td>'; html += '<td>' + esc(item.username) + '</td><td>' + pwd + '</td>'; html += '<td><span class="browser-badge ' + cls + '">' + name + '</span><br>' + openHTML(item.browser, item.url) + '</td></tr>'; } tbody.innerHTML = html; var btns = document.querySelectorAll('.copy-url-btn'); for (var j = 0; j < btns.length; j++) { btns[j].addEventListener('click', function() { copyText(this.dataset.url, '网址已复制'); }); } } function renderAdmin() { var tbody = document.getElementById('adminTableBody'); if (!tbody) return; if (!adminAuth) { tbody.innerHTML = '<tr class="empty-row"><td colspan="5">请验证管理员权限</td></tr>'; return; } var list = allCreds(); if (!list.length) { tbody.innerHTML = '<tr class="empty-row"><td colspan="5">暂无数据,点击"新增"添加</td></tr>'; return; } var html = ''; for (var i = 0; i < list.length; i++) { var item = list[i]; var name = bn(item.browser); var cls = bc(item.browser); html += '<tr><td><a href="' + esc(item.url) + '" target="_blank" class="url-link">' + esc(item.url) + '</a></td>'; html += '<td>' + esc(item.username) + '</td>'; html += '<td><span class="password-plain">' + esc(item.password) + '</span></td>'; html += '<td><span class="browser-badge ' + cls + '">' + name + '</span><br>' + openHTML(item.browser, item.url) + '</td>'; html += '<td class="flex-btns"><button class="btn btn-outline edit-btn" data-id="' + item.id + '">编辑</button><button class="btn btn-danger delete-btn" data-id="' + item.id + '">删除</button></td></tr>'; } tbody.innerHTML = html; var eds = document.querySelectorAll('.edit-btn'); for (var j = 0; j < eds.length; j++) { eds[j].addEventListener('click', function() { openEdit(parseInt(this.dataset.id)); }); } var dels = document.querySelectorAll('.delete-btn'); for (var k = 0; k < dels.length; k++) { dels[k].addEventListener('click', function() { if (confirm('确定删除?')) { delCred(parseInt(this.dataset.id)); renderAdmin(); renderEmp(); toast('已删除'); } }); } updateStorageInfo(); } function esc(s) { if (!s) return ''; return s.replace(/[&<>]/g, function(m) { return { '&':'&', '<':'<', '>':'>' }[m]; }); } function verifyEmp() { var inp = document.getElementById('empViewPwd'); if (!inp) return; if (h(inp.value) === empHash) { empVisible = true; toast('验证成功', 'success'); renderEmp(); } else { empVisible = false; renderEmp(); toast('密码错误', true); } inp.value = ''; } function openEdit(id) { var item = getCredById(id); if (item) openModal(item); } function toast(msg, err) { var t = document.getElementById('toast'); if (!t) return; t.textContent = msg; t.className = 'toast'; if (err === true) t.classList.add('error'); else if (err === 'success') t.classList.add('success'); t.classList.add('show'); clearTimeout(t._timer); t._timer = setTimeout(function() { t.classList.remove('show'); }, 3000); } // ===== 模态框 ===== var modal = document.getElementById('credModal'); var urlInp = document.getElementById('credUrl'); var userInp = document.getElementById('credUsername'); var pwdInp = document.getElementById('credPassword'); var browserSel = document.getElementById('credBrowser'); var editIdF = document.getElementById('editId'); var modalTitle = document.getElementById('modalTitle'); function openModal(entry) { if (!adminAuth) { toast('请先登录', true); return; } if (entry) { modalTitle.textContent = '编辑凭证'; urlInp.value = entry.url; userInp.value = entry.username; pwdInp.value = entry.password; browserSel.value = entry.browser || 'default'; editIdF.value = entry.id; } else { modalTitle.textContent = '添加凭证'; urlInp.value = ''; userInp.value = ''; pwdInp.value = ''; browserSel.value = 'default'; editIdF.value = ''; } modal.style.display = 'flex'; } function closeModal() { modal.style.display = 'none'; } function saveCred() { if (!adminAuth) { toast('未授权', true); return; } var url = urlInp.value.trim(); var user = userInp.value.trim(); var pwd = pwdInp.value.trim(); var browser = browserSel.value; if (!url || !user || !pwd) { toast('请填完整', true); return; } if (!url.startsWith('http://') && !url.startsWith('https://')) { toast('网址需 http:// 或 https:// 开头', true); return; } var id = editIdF.value; if (upsert(id ? parseInt(id) : null, url, user, pwd, browser)) { toast(id ? '已修改' : '已添加', 'success'); closeModal(); renderAdmin(); renderEmp(); } else { toast('操作失败', true); } } // ===== 导出导入 Excel ===== function exportExcel() { if (!adminAuth) { toast('请先登录', true); return; } var list = allCreds(); if (!list.length) { toast('无数据', true); return; } var data = [['网址', '账号', '密码', '浏览器']]; for (var i = 0; i < list.length; i++) { data.push([list[i].url, list[i].username, list[i].password, list[i].browser]); } var ws = XLSX.utils.aoa_to_sheet(data); var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 'Credentials'); XLSX.writeFile(wb, 'password_export_' + Date.now() + '.xls', { bookType: 'xls' }); toast('导出成功', 'success'); } function importExcel(file) { if (!adminAuth) { toast('请先登录', true); return; } var reader = new FileReader(); reader.onload = function(e) { var data = new Uint8Array(e.target.result); var workbook = XLSX.read(data, { type: 'array' }); var sheet = workbook.Sheets[workbook.SheetNames[0]]; var rows = XLSX.utils.sheet_to_json(sheet, { header: 1, defval: '' }); if (!rows || rows.length < 2) { toast('无效文件', true); return; } var headers = rows[0]; var ui = -1; var ui2 = -1; var pi = -1; var bi = -1; for (var i = 0; i < headers.length; i++) { var s = String(headers[i]).toLowerCase(); if (s.includes('网址') || s.includes('url')) ui = i; if (s.includes('账号') || s.includes('用户名')) ui2 = i; if (s.includes('密码')) pi = i; if (s.includes('浏览器')) bi = i; } if (ui === -1 || ui2 === -1 || pi === -1) { toast('缺少必要列', true); return; } var records = []; for (var j = 1; j < rows.length; j++) { var row = rows[j]; if (row && row.length > Math.max(ui, ui2, pi)) { var url = row[ui] ? String(row[ui]).trim() : ''; var user = row[ui2] ? String(row[ui2]).trim() : ''; var pwd = row[pi] ? String(row[pi]).trim() : ''; var browser = (bi !== -1 && row[bi]) ? String(row[bi]).trim() : 'default'; if (url && user && pwd && (url.startsWith('http://') || url.startsWith('https://'))) { records.push({ url: url, username: user, password: pwd, browser: browser }); } } } if (!records.length) { toast('无有效数据', true); return; } var cnt = batchUpsert(records); renderAdmin(); renderEmp(); toast('导入 ' + cnt + ' 条', 'success'); }; reader.readAsArrayBuffer(file); } // ===== 管理员登录 ===== function showAdminLogin() { if (adminAuth) return; var overlay = document.createElement('div'); overlay.className = 'admin-auth-overlay'; overlay.id = 'adminOverlay'; overlay.innerHTML = '<div class="admin-auth-box"><h3>管理员验证</h3><input type="password" id="adminLoginPwd" placeholder="管理员密码" autocomplete="off"><div id="adminLoginError" class="error"></div><div style="display:flex;gap:10px;margin-top:16px;justify-content:center;"><button class="btn btn-outline" id="adminLoginCancel">取消</button><button class="btn btn-primary" id="adminLoginConfirm">确认</button></div></div>'; document.body.appendChild(overlay); var inp = document.getElementById('adminLoginPwd'); inp.focus(); var doAuth = function() { if (h(inp.value) === adminHash) { adminAuth = true; document.body.removeChild(overlay); toast('验证成功', 'success'); renderAdmin(); var panel = document.getElementById('adminPanel'); if (!panel.classList.contains('hidden')) renderAdmin(); } else { document.getElementById('adminLoginError').textContent = '密码错误'; inp.value = ''; inp.focus(); } }; var cancel = function() { document.body.removeChild(overlay); if (!adminAuth) { switchTab('employee'); toast('已取消', true); } }; document.getElementById('adminLoginConfirm').addEventListener('click', doAuth); document.getElementById('adminLoginCancel').addEventListener('click', cancel); inp.addEventListener('keypress', function(e) { if (e.key === 'Enter') doAuth(); }); } // ===== Tab切换 ===== function switchTab(tab) { var admin = document.getElementById('adminPanel'); var emp = document.getElementById('employeePanel'); var btns = document.querySelectorAll('.tab-btn'); if (tab === 'employee') { admin.classList.add('hidden'); emp.classList.remove('hidden'); renderEmp(); btns.forEach(function(b) { b.classList.remove('active'); }); document.querySelector('.tab-btn[data-tab="employee"]').classList.add('active'); } else { if (!adminAuth) { showAdminLogin(); var iv = setInterval(function() { if (adminAuth) { clearInterval(iv); admin.classList.remove('hidden'); emp.classList.add('hidden'); renderAdmin(); btns.forEach(function(b) { b.classList.remove('active'); }); document.querySelector('.tab-btn[data-tab="admin"]').classList.add('active'); } }, 200); setTimeout(function() { clearInterval(iv); }, 30000); } else { admin.classList.remove('hidden'); emp.classList.add('hidden'); renderAdmin(); btns.forEach(function(b) { b.classList.remove('active'); }); document.querySelector('.tab-btn[data-tab="admin"]').classList.add('active'); } } } // ===== 主题切换 ===== function setTheme(name) { var root = document.documentElement; var prev = document.querySelector('.theme-dot.active'); if (prev) prev.classList.remove('active'); var dot = document.querySelector('.theme-dot[data-theme="' + name + '"]'); if (dot) dot.classList.add('active'); root.className = ''; if (name !== 'default') root.className = 'theme-' + name; localStorage.setItem('pwd_theme', name); } // ===== 事件绑定 ===== document.addEventListener('DOMContentLoaded', function() { var dots = document.querySelectorAll('.theme-dot'); dots.forEach(function(d) { d.addEventListener('click', function() { setTheme(this.dataset.theme); }); }); var saved = localStorage.getItem('pwd_theme'); if (saved) setTheme(saved); // 自动备份开关 var toggleBtn = document.getElementById('autoBackupToggle'); if (toggleBtn) { toggleBtn.addEventListener('click', function() { autoBackupEnabled = !autoBackupEnabled; setAutoBackupSetting(autoBackupEnabled); toast(autoBackupEnabled ? '自动备份已开启' : '自动备份已关闭', 'success'); if (autoBackupEnabled && credentials.length > 0) { exportToDownloadFolder(); toast('已备份到下载文件夹', 'success'); } }); } var btnOpenAdd = document.getElementById('openAddCredBtn'); var btnCloseModal = document.getElementById('closeModalBtn'); var btnSaveCred = document.getElementById('saveCredBtn'); var btnVerifyEmp = document.getElementById('verifyEmpBtn'); var inpEmpPwd = document.getElementById('empViewPwd'); var btnExportExcel = document.getElementById('exportExcelBtn'); var btnExportJson = document.getElementById('exportJsonBtn'); var inpImportExcel = document.getElementById('importExcelInput'); var inpImportJson = document.getElementById('importJsonInput'); var btnUpdateEmpPwd = document.getElementById('updateEmployeePwdBtn'); var btnUpdateAdminPwd = document.getElementById('updateAdminPwdBtn'); if (btnOpenAdd) btnOpenAdd.addEventListener('click', function() { openModal(null); }); if (btnCloseModal) btnCloseModal.addEventListener('click', closeModal); if (btnSaveCred) btnSaveCred.addEventListener('click', saveCred); if (btnVerifyEmp) btnVerifyEmp.addEventListener('click', verifyEmp); if (inpEmpPwd) inpEmpPwd.addEventListener('keypress', function(e) { if (e.key === 'Enter') verifyEmp(); }); if (btnExportExcel) btnExportExcel.addEventListener('click', exportExcel); if (btnExportJson) btnExportJson.addEventListener('click', exportJson); if (inpImportExcel) inpImportExcel.addEventListener('change', function(e) { if (this.files.length) importExcel(this.files[0]); this.value = ''; }); if (inpImportJson) inpImportJson.addEventListener('change', function(e) { if (this.files.length) importJson(this.files[0]); this.value = ''; }); if (btnUpdateEmpPwd) { btnUpdateEmpPwd.addEventListener('click', function() { var inp = document.getElementById('newEmployeePwd'); var p = inp.value; if (!p || p.length < 4) { toast('密码至少4位', true); inp.value = ''; return; } setEmpHash(h(p)); empVisible = false; renderEmp(); toast('员工密码已修改', 'success'); inp.value = ''; }); } if (btnUpdateAdminPwd) { btnUpdateAdminPwd.addEventListener('click', function() { var inp = document.getElementById('newAdminPwd'); var p = inp.value; if (!p || p.length < 4) { toast('密码至少4位', true); inp.value = ''; return; } setAdminHash(h(p)); toast('管理员密码已修改', 'success'); inp.value = ''; }); } document.querySelectorAll('.tab-btn').forEach(function(btn) { btn.addEventListener('click', function() { switchTab(this.dataset.tab); }); }); window.onclick = function(e) { if (e.target === modal) closeModal(); }; }); // ===== 启动 ===== function boot() { try { initData(); empVisible = false; adminAuth = false; renderEmp(); renderAdmin(); switchTab('employee'); updateStorageInfo(); updateLastBackupTime(); toast('系统已启动,数据永久保存在 localStorage', 'success'); } catch(err) { toast('初始化失败: ' + err.message, true); console.error(err); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', boot); } else { boot(); }</script></body></html>复制代码由于个人对HTML网页代码的理解还是欠缺,大家有什么新的建议可提出,或有什么错误的地方,麻烦大家告知,我虚心求教。
相关文章
- 09-02 个人整改后做的html版网页密码管理系统
- 09-02 一款极简的网址导航源码 免服务器部署在cloudflare上
- 08-29 16合一代付小程序源码
- 08-28 智能客服官网引导页HTML源码——零依赖、自适应、开箱即用的通用官网
- 08-26 基于Python+RAG智能客服系统源码
- 08-26 php奇云多应用授权系统|万能在线更新页面
- 08-25 资源发布网同款引导发布页源码
- 08-25 SaaS 电子合同整套源码|多企业入驻 + 小程序签约 + 套餐收费
- 08-22 导航网站html模板多风格
- 08-20 祝天下有情人终成眷属!好日子YL(予邻)社区程序开源啦!!
- 08-15 2026年梦幻个人导航带后台模板可以自动切换
- 08-14 仿link3网站源码有后台可自己设置前台
取消回复欢迎你发表评论:
- 协助本站优化一下
- 最近发表
- 1复制高手搞钱路径(内部资料)
- 2极客-AI编程实战营(2016) 陈天
- 3个人整改后做的html版网页密码管理系统
- 4一款极简的网址导航源码 免服务器部署在cloudflare上
- 5《请去Bar,恋爱吧!》中文版恋爱模拟
- 6视频编辑工具 OpenShot v4.0.0
- 7《恐惧与信仰》中文版
- 8《咩咩启示录》中文版
- 9小米(澎湃OS)系统内置应用卸载工具 v1.0 - 免Root精简小米系统与广告卸载神器
- 10天下游,虚拟定位,钉钉打卡神器
- 11变声工厂v1.7 解锁永久VIP会员 各种语音变声工具
- 12《空之轨迹 the 1st》v1.0中文版
- 13《火影忍者:终极风暴羁绊》中文版
- 14同程摸鱼暗号每天抽随机红包
- 15滴滴限量领酒店无门槛折扣券
Copyright© XGW9.COM版权所有〖小庚资源网〗
〖恒创科技〗为本站提供专业云计算服务
本站发布的内容来源于互联网,如果有侵权内容,请联系我们删除!E-mail:xgzyw6@outlook.com
关于我们|我要投稿|免责声明|XML地图











暂无评论,来添加一个吧。