软件界面如下:

主要源码如下:

<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
    <meta charset="UTF-8">
    <title>密码生成器</title>
    <style>
        html, body {
            margin: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }
    </style>

    <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
    <script src="node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div style="width: 100%;height: 100%;overflow: hidden;padding: 10px;display: flex;flex-direction: column;">
    <div>包括字符:</div>
    <div style="height: 10px"></div>
    <div class="input-group mb-3">
        <div class="input-group-text">
            <input id="cb-include-lower-chars" class="form-check-input mt-0" type="checkbox">
        </div>
        <label class="form-control" for="cb-include-lower-chars">
            abcdefghijklmnopqrstuvwxyz
        </label>
    </div>
    <div class="input-group mb-3">
        <div class="input-group-text">
            <input id="cb-include-upper-chars" class="form-check-input mt-0" type="checkbox">
        </div>
        <label class="form-control" for="cb-include-upper-chars">
            ABCDEFGHIJKLMNOPQRSTUVWXYZ
        </label>
    </div>
    <div class="input-group mb-3">
        <div class="input-group-text">
            <input id="cb-include-numbers" class="form-check-input mt-0" type="checkbox">
        </div>
        <label class="form-control" for="cb-include-numbers">
            1234567890
        </label>
    </div>
    <div class="input-group mb-3">
        <div class="input-group-text">
            <input id="cb-include-symbols" class="form-check-input mt-0" type="checkbox">
        </div>
        <label class="form-control" for="cb-include-symbols">
            !@#$%^&*()_+-={}[]?
        </label>
    </div>
    <div style="text-align: center;">
        <button class="btn btn-primary" id="btn-generate-password">生成密码</button>
    </div>
    <div style="height: 20px"></div>
    <div class="alert alert-dark" role="alert" style="text-align: center;" id="password-output">

    </div>
</div>

<script>
    (function () {
        const cbIncludeLowerChars = document.getElementById('cb-include-lower-chars');
        const cbIncludeUpperChars = document.getElementById('cb-include-upper-chars');
        const cbIncludeNumbers = document.getElementById('cb-include-numbers');
        const cbIncludeSymbols = document.getElementById('cb-include-symbols');
        const btnGeneratePassword = document.getElementById('btn-generate-password');
        const passwordOutput = document.getElementById('password-output');
        const upperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        const lowerChars = "abcdefghijklmnopqrstuvwxyz";
        const numbers = "1234567890";
        const symbols = "!@#$%^&*()_+-={}[]?";

        function readPreferences() {
            cbIncludeLowerChars.checked = localStorage.getItem('cb-include-lower-chars-checked') === 'checked';
            cbIncludeUpperChars.checked = localStorage.getItem('cb-include-upper-chars-checked') === 'checked';
            cbIncludeNumbers.checked = localStorage.getItem('cb-include-numbers-checked') === 'checked';
            cbIncludeSymbols.checked = localStorage.getItem('cb-include-symbols-checked') === 'checked';
        }

        function addListeners() {
            cbIncludeLowerChars.onchange = function () {
                localStorage.setItem('cb-include-lower-chars-checked', this.checked ? 'checked' : '');
                generatePassword();
            }
            cbIncludeUpperChars.onchange = function () {
                localStorage.setItem('cb-include-upper-chars-checked', this.checked ? 'checked' : '');
                generatePassword();
            }
            cbIncludeNumbers.onchange = function () {
                localStorage.setItem('cb-include-numbers-checked', this.checked ? 'checked' : '');
                generatePassword();
            }
            cbIncludeSymbols.onchange = function () {
                localStorage.setItem('cb-include-symbols-checked', this.checked ? 'checked' : '');
                generatePassword();
            }
            btnGeneratePassword.onclick = generatePassword;
        }

        function getWords(original) {
            let words = "";
            let times = Math.floor(Math.random() * 4) + 1;
            for (let i = 0; i < times; i++) {
                words += original.charAt(Math.floor(Math.random() * original.length));
            }
            return words;
        }

        function generatePassword() {
            let oneChecked = false;
            let words = "";
            if (cbIncludeLowerChars.checked) {
                words += getWords(lowerChars);
                oneChecked = true;
            }
            if (cbIncludeUpperChars.checked) {
                words += getWords(upperChars);
                oneChecked = true;
            }
            if (cbIncludeNumbers.checked) {
                words += getWords(numbers);
                oneChecked = true;
            }
            if (cbIncludeSymbols.checked) {
                words += getWords(symbols);
                oneChecked = true;
            }

            if (!oneChecked) {
                passwordOutput.innerHTML = "<span class='text-danger'>至少选择一项</span>";
                return;
            }

            let wordsArr = words.split("");

            for (let i = 0; i < 200; i++) {
                let index = Math.floor(Math.random() * wordsArr.length);
                let w = wordsArr[index];
                wordsArr.splice(index, 1);
                wordsArr.push(w);
            }
            passwordOutput.innerText = wordsArr.join("");
        }

        function main() {
            readPreferences();
            addListeners();
            generatePassword();
        }

        main();
    })();
</script>
</body>
</html>