平时老要用随机密码、二维码,懒得切来切去,就用gpt搓了个小页面。
前端 + Workers
在线用:
👉 http://pw.gpq.qzz.io/
功能:
UUID 生成
随机密码(可选字符集)
二维码
Cloudflare Workers 一键可部署
代码如下

// Cloudflare Workers 完整脚本(中文注释 + 中文 UI)// 功能:UUID / 密码 / 二维码 生成器// 技术栈:Alpine.js + Tailwind CDN(轻量、无打包)// 说明:可直接粘贴到 Workers 编辑器并部署// ---------------------------// 工具类:安全随机与二维码生成// ---------------------------class UtilityGenerator {  // 生成 UUID(使用浏览器 / worker 环境的 crypto)  static generateUUID() {    return crypto.randomUUID();  }  // 生成随机密码  // length: 密码长度(8-256)  // options: {lowercase, uppercase, numbers, symbols, excludeSimilar, excludeAmbiguous}  static generatePassword(length = 16, options = {}) {    const charsets = {      lowercase: 'abcdefghijklmnopqrstuvwxyz',      uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',      numbers: '0123456789',      symbols: '!@#$%^&*()_+~`|}{[]:;?><,./-='    };    // 常被混淆的字符,如 o O 0 i l 1 等    const similarChars = 'oOiIlL10';    // 模糊字符(有些字体下不易辨认)    const ambiguousChars = '{}[]()/\'"`~,;:.<>';    if (length < 8 || length > 256) {      throw new Error('密码长度必须在 8 到 256 之间');    }    // 根据选项拼接字符集    let chars = Object.entries(options)      .filter(([key, value]) => value && charsets[key])      .map(([key]) => charsets[key])      .join('');    // 如果没有选择任何字符集,则全部启用    if (!chars) {      chars = Object.values(charsets).join('');    }    // 排除相似字符    if (options.excludeSimilar) {      chars = chars.split('').filter(c => !similarChars.includes(c)).join('');    }    // 排除模糊字符    if (options.excludeAmbiguous) {      chars = chars.split('').filter(c => !ambiguousChars.includes(c)).join('');    }    // 使用强随机数生成密码    const array = new Uint8Array(length);    crypto.getRandomValues(array);    return Array.from(array, byte => chars[byte % chars.length]).join('');  }  // 返回第三方二维码生成器的 URL(免费服务)  static async getQRCodeURL(text, size = 350) {    return `https://api.qrserver.com/v1/create-qr-code/?size=${size}x${size}&data=${encodeURIComponent(text)}`;  }}// ---------------------------// 生成页面 HTML(中文)// 使用 Tailwind CDN + Alpine.js CDN(无需构建)// ---------------------------const getHTML = () => `<!DOCTYPE html><html lang="zh-CN" x-data="app" x-init="initTheme()" class="antialiased"><head>  <meta charset="utf-8" />  <meta name="viewport" content="width=device-width,initial-scale=1" />  <title>实用工具箱 — UUID / 密码 / 二维码 生成器</title>  <!-- Tailwind CDN(轻量 config) -->  <script src="https://cdn.tailwindcss.com"></script>  <!-- Alpine.js CDN -->  <script src="https://unpkg.com/[email protected]/dist/cdn.min.js" defer></script>  <script>    // Tailwind 配置(扩展主题色)    tailwind.config = {      darkMode: 'class',      theme: {        extend: {          colors: {            glass: {              DEFAULT: 'rgba(255,255,255,0.6)',              dark: 'rgba(255,255,255,0.06)'            },            primary: {              50: '#f0f9ff',              100: '#e0f2fe',              200: '#bae6fd',              300: '#7dd3fc',              400: '#38bdf8',              500: '#0ea5e9',              600: '#0284c7',              700: '#0369a1',              800: '#075985',              900: '#0c4a6e'            }          },          backdropBlur: {            xs: '2px',          }        }      }    }  </script>  <style>    /* 隐藏 x-cloak 元素直到 Alpine 初始化完毕 */    [x-cloak] { display: none !important; }    /* 小屏幕优化 */    @media (max-width: 640px) {      .glass-card { padding: 1rem; }    }  </style></head><body class="min-h-screen bg-gradient-to-br from-gray-100 to-gray-50 dark:from-gray-900 dark:to-gray-800 text-gray-800 dark:text-gray-100">  <div class="max-w-4xl mx-auto p-6">    <!-- 顶部标题 -->    <header class="flex items-center justify-between mb-6">      <div>        <h1 class="text-2xl font-extrabold tracking-tight text-primary-700 dark:text-primary-300">实用工具箱</h1>        <p class="text-sm text-gray-600 dark:text-gray-300 mt-1">UUID、密码、二维码 —— 一键生成,轻量安全</p>      </div>      <div class="flex items-center space-x-3">        <!-- 主题切换 -->        <button @click="toggleTheme()" class="p-2 rounded-full bg-white/60 dark:bg-gray-700/40 backdrop-blur-xs border border-gray-200 dark:border-gray-700 shadow-sm hover:scale-105 transition-transform">          <svg x-show="theme === 'light'" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-yellow-500" viewBox="0 0 20 20" fill="currentColor">            <path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1z"/>          </svg>          <svg x-show="theme === 'dark'" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-100" viewBox="0 0 20 20" fill="currentColor">            <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"/>          </svg>        </button>        <!-- 说明按钮 -->        <button @click="showInfo = !showInfo" class="px-3 py-1 rounded-md bg-primary-500 text-white shadow hover:opacity-90 transition">使用说明</button>      </div>    </header>    <!-- 说明卡片 -->    <div x-show="showInfo" x-cloak class="mb-6 p-4 rounded-xl glass-card bg-white/60 dark:bg-gray-800/50 border border-gray-200 dark:border-gray-700 backdrop-blur-sm shadow-sm">      <div class="flex items-start space-x-3">        <div>          <p class="text-sm text-gray-700 dark:text-gray-200">这是一个轻量的工具箱,包含:</p>          <ul class="mt-2 text-sm text-gray-600 dark:text-gray-300 list-disc ml-5">            <li>UUID(随机唯一标识符)</li>            <li>密码生成器(可选择字符集与长度)</li>            <li>二维码生成(调用公开 API)</li>          </ul>          <p class="mt-2 text-xs text-gray-500 dark:text-gray-400">不传输敏感数据到第三方(仅二维码图片使用第三方生成服务)。</p>        </div>      </div>    </div>    <!-- 主内容网格 -->    <main class="grid grid-cols-1 md:grid-cols-3 gap-6">      <!-- UUID 卡片 -->      <section class="col-span-1 md:col-span-1 bg-white/60 dark:bg-gray-800/60 border border-gray-200 dark:border-gray-700 rounded-2xl p-6 glass-card shadow transform hover:-translate-y-1 transition">        <h2 class="text-lg font-semibold text-primary-700 dark:text-primary-300 mb-3">生成 UUID</h2>        <p class="text-sm text-gray-600 dark:text-gray-300 mb-4">快速生成符合标准的随机 UUID(v4)。</p>        <button @click="generateUUID()" class="w-full py-2 rounded-md bg-gradient-to-r from-primary-500 to-primary-600 text-white font-medium shadow">生成 UUID</button>        <div x-show="uuidResult" x-cloak class="mt-4">          <div class="p-3 rounded bg-white dark:bg-gray-900 border border-gray-100 dark:border-gray-800 break-all text-sm">            <code x-text="uuidResult"></code>          </div>          <div class="mt-3 grid grid-cols-2 gap-2">            <button @click="copy(uuidResult, 'UUID 已复制')" class="py-2 rounded-md bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200">复制</button>            <button @click="clear('uuid')" class="py-2 rounded-md bg-red-50 dark:bg-red-800/30 text-red-700 dark:text-red-300">清除</button>          </div>        </div>      </section>      <!-- 密码生成 卡片 -->      <section class="col-span-1 md:col-span-1 bg-white/60 dark:bg-gray-800/60 border border-gray-200 dark:border-gray-700 rounded-2xl p-6 glass-card shadow transform hover:-translate-y-1 transition">        <h2 class="text-lg font-semibold text-primary-700 dark:text-primary-300 mb-3">生成 密码</h2>        <p class="text-sm text-gray-600 dark:text-gray-300 mb-3">支持长度与字符集自定义,安全随机生成。</p>        <div class="space-y-3">          <label class="text-xs text-gray-600 dark:text-gray-300">长度</label>          <select x-model.number="pwd.length" class="w-full p-2 rounded border bg-white dark:bg-gray-700 dark:border-gray-600">            <option value="16">16 位</option>            <option value="24">24 位</option>            <option value="32">32 位</option>            <option value="64">64 位</option>            <option value="128">128 位</option>          </select>          <div class="grid grid-cols-2 gap-2">            <label class="inline-flex items-center space-x-2 text-sm">              <input type="checkbox" x-model="pwd.options.lowercase" class="rounded" />              <span>包含小写字母</span>            </label>            <label class="inline-flex items-center space-x-2 text-sm">              <input type="checkbox" x-model="pwd.options.uppercase" class="rounded" />              <span>包含大写字母</span>            </label>            <label class="inline-flex items-center space-x-2 text-sm">              <input type="checkbox" x-model="pwd.options.numbers" class="rounded" />              <span>包含数字</span>            </label>            <label class="inline-flex items-center space-x-2 text-sm">              <input type="checkbox" x-model="pwd.options.symbols" class="rounded" />              <span>包含符号</span>            </label>            <label class="inline-flex items-center space-x-2 text-sm col-span-2">              <input type="checkbox" x-model="pwd.options.excludeSimilar" class="rounded" />              <span>排除相似字符(如 o O 0 l 1)</span>            </label>          </div>          <div class="grid grid-cols-2 gap-2">            <button @click="generatePassword()" class="py-2 rounded-md bg-gradient-to-r from-primary-500 to-primary-600 text-white">生成 密码</button>            <button @click="clear('password')" class="py-2 rounded-md bg-gray-100 dark:bg-gray-700">清除</button>          </div>          <div x-show="pwd.result" x-cloak class="mt-2">            <div class="p-3 rounded bg-white dark:bg-gray-900 border border-gray-100 dark:border-gray-800 break-all text-sm">              <code x-text="pwd.result"></code>            </div>            <div class="mt-2 grid grid-cols-2 gap-2">              <button @click="copy(pwd.result, '密码 已复制')" class="py-2 rounded-md bg-gray-100 dark:bg-gray-700">复制</button>              <button @click="useAsPassword(pwd.result)" class="py-2 rounded-md bg-yellow-50 dark:bg-yellow-800/30 text-yellow-700">另存/使用</button>            </div>          </div>        </div>      </section>      <!-- 二维码 卡片(横跨两列) -->      <section class="col-span-1 md:col-span-1 lg:col-span-1 bg-white/60 dark:bg-gray-800/60 border border-gray-200 dark:border-gray-700 rounded-2xl p-6 glass-card shadow transform hover:-translate-y-1 transition">        <h2 class="text-lg font-semibold text-primary-700 dark:text-primary-300 mb-3">生成 二维码</h2>        <p class="text-sm text-gray-600 dark:text-gray-300 mb-3">输入文本或链接,快速生成二维码图片(使用第三方公开服务)。</p>        <input x-model="qr.text" type="text" placeholder="在此输入要生成二维码的文本或链接" class="w-full p-2 rounded border bg-white dark:bg-gray-700 dark:border-gray-600 mb-3" />        <div class="grid grid-cols-2 gap-2">          <button @click="generateQR()" class="py-2 rounded-md bg-gradient-to-r from-primary-500 to-primary-600 text-white">生成 二维码</button>          <button @click="clear('qr')" class="py-2 rounded-md bg-gray-100 dark:bg-gray-700">清除</button>        </div>        <div x-show="qr.url" x-cloak class="mt-3 text-center">          <img :src="qr.url" alt="二维码" class="mx-auto w-48 h-48 rounded shadow" />          <div class="mt-2 flex items-center justify-center gap-2">            <a :href="qr.url" target="_blank" rel="noreferrer" class="text-sm underline">在新窗口打开</a>            <button @click="copy(qr.url, '二维码链接 已复制')" class="text-sm px-2 py-1 rounded bg-gray-100 dark:bg-gray-700">复制链接</button>          </div>        </div>      </section>    </main>    <!-- 页脚与版权 -->    <footer class="mt-8 text-center text-xs text-gray-500 dark:text-gray-400">      <div>© 实用工具箱 · 仅供测试与开发使用</div>      <div class="mt-1">二维码由第三方服务生成;请勿用于隐私敏感用途。</div>    </footer>  </div>  <!-- 全局 Toast(提示) -->  <div x-data="{ toasts: [] }" x-cloak>    <template x-for="(t,i) in toasts" :key="i">      <div x-text="t" class="fixed right-6 bottom-6 bg-gray-900 text-white px-4 py-2 rounded shadow-lg opacity-90"></div>    </template>  </div>  <!-- Alpine 初始化逻辑与事件 -->  <script>    document.addEventListener('alpine:init', () => {      // 全局应用状态(主题、提示)      Alpine.data('app', () => ({        theme: localStorage.getItem('theme') || 'light',        showInfo: false,        // 存储当前生成结果        uuidResult: '',        pwd: {          length: 16,          options: {            lowercase: true,            uppercase: true,            numbers: true,            symbols: false,            excludeSimilar: false,            excludeAmbiguous: false          },          result: ''        },        qr: {          text: '',          url: ''        },        // 简单的 toast 列表(本地显示)        toasts: [],        // 初始化 theme        initTheme() {          if (this.theme === 'dark') document.documentElement.classList.add('dark');          else document.documentElement.classList.remove('dark');        },        toggleTheme() {          this.theme = this.theme === 'dark' ? 'light' : 'dark';          localStorage.setItem('theme', this.theme);          document.documentElement.classList.toggle('dark');        },        // 添加 toast(持续 2 秒)        pushToast(msg = '') {          this.toasts.push(msg);          const idx = this.toasts.length - 1;          setTimeout(() => {            this.toasts.splice(idx, 1);          }, 2000);        },        // 生成 UUID(调用 API)        async generateUUID() {          try {            const res = await fetch('/generate-uuid');            const data = await res.json();            this.uuidResult = data.uuid;          } catch (e) {            this.pushToast('生成失败:网络错误');          }        },        // 生成密码(调用 API)        async generatePassword() {          try {            const params = new URLSearchParams({              length: this.pwd.length,              lowercase: this.pwd.options.lowercase,              uppercase: this.pwd.options.uppercase,              numbers: this.pwd.options.numbers,              symbols: this.pwd.options.symbols,              excludeSimilar: this.pwd.options.excludeSimilar,              excludeAmbiguous: this.pwd.options.excludeAmbiguous            });            const res = await fetch('/generate-password?' + params.toString());            const data = await res.json();            if (data.password) {              this.pwd.result = data.password;            } else {              this.pushToast('生成失败:' + (data.error || '未知错误'));            }          } catch (e) {            this.pushToast('生成失败:网络错误');          }        },        // 生成二维码(调用 API)        async generateQR() {          try {            const text = this.qr.text || 'Hello World';            const res = await fetch('/generate-qrcode?text=' + encodeURIComponent(text));            const data = await res.json();            if (data.qrCodeURL) {              this.qr.url = data.qrCodeURL;            } else {              this.pushToast('二维码生成失败');            }          } catch (e) {            this.pushToast('二维码生成失败:网络错误');          }        },        // 复制到剪贴板并提示        async copy(text, successMsg = '已复制') {          try {            await navigator.clipboard.writeText(text);            this.pushToast(successMsg);          } catch (e) {            this.pushToast('复制失败(浏览器不支持)');          }        },        // 清除指定内容        clear(name) {          if (name === 'uuid') this.uuidResult = '';          if (name === 'password') this.pwd.result = '';          if (name === 'qr') {            this.qr.text = '';            this.qr.url = '';          }        },        // 在这里可以把密码推到别处(示例)        useAsPassword(pwd) {          // 仅示例:将密码复制到剪贴板并提示          this.copy(pwd, '密码已复制,可以粘贴使用');        }      }));    });  </script></body></html>`;// ---------------------------// Workers 请求处理(API 部分)// 路由:/ 、/generate-uuid 、/generate-password 、/generate-qrcode// ---------------------------async function handleRequest(request) {  try {    const url = new URL(request.url);    // 根路径返回 HTML 页面    if (url.pathname === '/' || url.pathname === '') {      return new Response(getHTML(), {        headers: { "Content-Type": "text/html; charset=utf-8" },      });    }    // 生成 UUID API    if (url.pathname === '/generate-uuid') {      return new Response(JSON.stringify({        uuid: UtilityGenerator.generateUUID()      }), {        headers: { "Content-Type": "application/json; charset=utf-8" }      });    }    // 生成密码 API    if (url.pathname === '/generate-password') {      try {        const length = parseInt(url.searchParams.get('length')) || 16;        const options = {          lowercase: url.searchParams.get('lowercase') === 'true' || url.searchParams.get('lowercase') === '1',          uppercase: url.searchParams.get('uppercase') === 'true' || url.searchParams.get('uppercase') === '1',          numbers: url.searchParams.get('numbers') === 'true' || url.searchParams.get('numbers') === '1',          symbols: url.searchParams.get('symbols') === 'true' || url.searchParams.get('symbols') === '1',          excludeSimilar: url.searchParams.get('excludeSimilar') === 'true' || url.searchParams.get('excludeSimilar') === '1',          excludeAmbiguous: url.searchParams.get('excludeAmbiguous') === 'true' || url.searchParams.get('excludeAmbiguous') === '1'        };        const password = UtilityGenerator.generatePassword(length, options);        return new Response(JSON.stringify({ password }), {          headers: { "Content-Type": "application/json; charset=utf-8" }        });      } catch (error) {        return new Response(JSON.stringify({ error: error.message }), {          status: 400,          headers: { "Content-Type": "application/json; charset=utf-8" }        });      }    }    // 生成二维码 API(返回二维码图片 URL)    if (url.pathname === '/generate-qrcode') {      const text = url.searchParams.get('text') || 'Hello World';      const size = parseInt(url.searchParams.get('size')) || 350;      const qrCodeURL = await UtilityGenerator.getQRCodeURL(text, size);      return new Response(JSON.stringify({ qrCodeURL }), {        headers: { "Content-Type": "application/json; charset=utf-8" }      });    }    // 其它路径 404    return new Response('未找到', { status: 404 });  } catch (err) {    return new Response(JSON.stringify({      error: '服务器内部错误',      details: err.message    }), {      status: 500,      headers: { "Content-Type": "application/json; charset=utf-8" }    });  }}// 监听 fetch 事件addEventListener('fetch', event => {  event.respondWith(handleRequest(event.request));});

需要的拿去用,不需要当我路过。