Trang thêm biểu mẫu dựa trên WeUI với chức năng tải lên tệp đính kèm

  1. Quy tắc điều hướng trang trong WeChat Mini Program:

/*

  • Quy trình vào trang WeChat:
    1. Gọi API để lấy URL
    1. Chuyển hướng đến URL đã nhận được, hệ thống Tencent sẽ chuyển hướng về trang cục bộ
    1. Giải mã trang chuyển hướng để thu thập tham số code
    1. Gửi code để nhận openid
    1. Openid là định danh duy nhất của người dùng WeChat; sau khi có được, có thể thực hiện các yêu cầu đến backend (lấy danh sách người dùng liên kết, gỡ liên kết, thiết lập liên kết, v.v.) */
  1. Khi tải lên tệp đính kèm: trước tiên gửi tệp lên máy chủ, nhận lại id, src và tên tệp, sau đó hiển thị trực tiếp bằng cách sử dụng base64.
/**
 * Tải lên tệp đính kèm
 * 1. Hiển thị tạm thời bằng base64
 * 2. Gửi yêu cầu tải lên
 * 3. Lưu biểu mẫu
 */
function handleFileUpload() {
    const fileInput = document.querySelector('#upload_file');

    fileInput.addEventListener('change', function () {
        const selectedFile = this.files[0];

        const formData = new FormData();
        formData.append('file', selectedFile);

        $.ajax({
            url: baseUrl + '/wechat/opinion/upload',
            type: 'POST',
            traditional: true,
            headers: { 'token': Sessiontoken },
            data: formData,
            processData: false,
            contentType: false,
            success: function (response) {
                if (response.code !== 0) {
                    $.toast("Tải lên thất bại", 'forbidden');
                    return;
                }

                // Lưu thông tin tệp đã tải lên
                uploadedFiles.push(response.data);

                const reader = new FileReader();
                const mimeType = selectedFile.type;

                reader.readAsDataURL(selectedFile);

                reader.onload = function () {
                    if (/^image\/(jpeg|png|jpg|gif)/.test(mimeType)) {
                        const timestamp = Date.now();
                        const htmlSnippet = `
                            <span>
                                ![](${this.result})
                            </span>
                        `;
                        $('.attachment-preview').append(htmlSnippet);
                    }
                };
            }
        });
    }, false);
}
  1. Một mẹo nhỏ: Xóa phần tử theo chỉ số trong mảng
Array.prototype.removeAt = function(index) {
    const result = [];
    for (let i = 0; i < this.length; i++) {
        if (i !== index) {
            result.push(this[i]);
        }
    }
    return result;
};
// Xóa tệp đã lưu
const indexToRemove = uploadedFiles.findIndex(item => item.id === fileId);
uploadedFiles = uploadedFiles.removeAt(indexToRemove);
  1. Mã nguồn hoàn chỉnh
<!DOCTYPE html>
<html lang="vi">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Type" content="multipart/form-data; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Góp ý & Tư vấn</title>
</head>
<link rel="stylesheet" href="https://cdn.bootcss.com/weui/1.1.3/style/weui.min.css">
<link rel="stylesheet" href="https://cdn.bootcss.com/jquery-weui/1.2.1/css/jquery-weui.min.css">
<link rel="stylesheet" href="../../src/dist/css/page.css">

<body>
<div class="weui-cells user-binding">
    <div class="weui-cells__tips">Góp ý & Tư vấn</div>
    <div class="weui-cell">
        <div class="weui-cell__hd">
            <i class="iconfont iconyonghuming"></i>
        </div>
        <div class="weui-cell__bd">
            <p>Họ tên</p>
        </div>
        <div class="weui-cell__bd">
            <input class="weui-input" type="text" placeholder="Nhập họ tên" id="fullName">
        </div>
        <div class="weui-cell__ft" style="position: absolute; right: 10px;">
            <input type="checkbox" style="position: relative; top: 2px; margin-right: 4px;" id="anonymousToggle"> Ẩn danh
        </div>
    </div>
    <div class="weui-cell">
        <div class="weui-cell__hd">
            <i class="iconfont icondianhua"></i>
        </div>
        <div class="weui-cell__bd">
            <p>Số điện thoại</p>
        </div>
        <div class="weui-cell__bd">
            <input class="weui-input" type="text" placeholder="Nhập số điện thoại" id="phoneNumber">
        </div>
    </div>
    <div class="weui-cell">
        <div class="weui-cell__hd">
            <i class="iconfont icondizhi"></i>
        </div>
        <div class="weui-cell__bd">
            <p>Địa chỉ</p>
        </div>
        <div class="weui-cell__bd">
            <input class="weui-input" type="text" placeholder="Nhập địa chỉ chi tiết" id="address">
        </div>
    </div>
    <div class="weui-cell">
        <div class="weui-cell__hd">
            <i class="iconfont iconSpare"></i>
        </div>
        <div class="weui-cell__bd">
            <p>Loại phản ánh</p>
        </div>
        <div class="weui-cell__bd">
            <input class="weui-input" type="text" placeholder="Chọn loại phản ánh" id="issueType">
        </div>
    </div>
    <div class="weui-cell">
        <div class="weui-cell__hd">
            <i class="iconfont iconleixing"></i>
        </div>
        <div class="weui-cell__bd">
            <p>Nội dung chi tiết</p>
        </div>
        <div class="weui-cell__bd">
            <textarea class="weui-textarea" placeholder="Nhập nội dung chi tiết" rows="3" id="details"></textarea>
        </div>
    </div>
    <div class="weui-cell">
        <div class="weui-cell__hd">
            <i class="iconfont icontec"></i>
        </div>
        <div class="weui-cell__bd">
            <p>Tải lên ảnh</p>
        </div>
        <div class="weui-cell__bd">
            <div class="weui-cell__ft add-cell" onclick="handleFileUpload()">+ Tải lên</div>
        </div>
    </div>
    <div class="weui-cell">
        <div class="attachment-preview"></div>
    </div>

    <div class="button_sp_area">
        <a href="javascript:;" class="weui-btn weui-btn_primary" onclick="submitForm()">Gửi</a>
    </div>
</div>

<div class="modal-image-viewer">
    ![]()
</div>

<div class="file-upload-trigger" style="display: none;">
    <input type="file" accept="image/*" id="upload_file" capture="camera">
</div>

<script src="https://cdn.bootcss.com/jquery/1.11.0/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/jquery-weui/1.2.1/js/jquery-weui.min.js"></script>

<!-- Custom Scripts -->
<script src="../../src/dist/js/index.js"></script>
<script src="../../src/dist/js/utils.js"></script>
<script src="../../src/dist/js/request.js"></script>
<script src="../../src/dist/js/fileUploader.js"></script>

<script>
    let wxCode = '';
    let userId = '';
    let uploadedFiles = [];

    const issueOptions = [
        { title: "Tư vấn", value: "1" },
        { title: "Phản ánh", value: "2" },
        { title: "Khen ngợi", value: "3" }
    ];

    $(function () {
        const queryString = location.search;
        const params = {};
        const matches = queryString.match(/[^\?&]*=[^&]*/g) || [];

        for (const match of matches) {
            const [key, value] = match.split('=');
            params[key] = value;
        }

        const code = params.code;

        if (code) {
            wxCode = code;
            fetchOpenId();
        } else {
            fetchAuthUrl();
        }

        initForm();
    });

    function initForm() {
        $('#issueType').select({
            title: 'Loại phản ánh',
            items: issueOptions
        });

        handleFileUpload();
    }

    function fetchOpenId() {
        get('/wechat/binding/toIdentityBinding', { code: wxCode }, function (res) {
            if (res.code === 0) {
                userId = res.data;
            } else {
                $.toast('Lỗi lấy openid', 'forbidden');
            }
        }, false, true);
    }

    function fetchAuthUrl() {
        get('/wechat/binding/getAuthUrl', {}, function (res) {
            if (res.code === 0) {
                const redirectUrl = encodeURIComponent(window.location.href);
                const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?redirect_uri=${redirectUrl}&appid=wx60c25e54627b700d&response_type=code&scope=snsapi_base&state=#wechat_redirect`;
                window.location.replace(authUrl);
            } else {
                $.toast('Lỗi lấy URL xác thực', 'forbidden');
            }
        }, false, true);
    }

    function closeModal() {
        $('.modal-image-viewer').hide();
    }

    function isPhoneNumberValid(phone) {
        const pattern = /^[1][3,4,5,7,8][0-9]{9}$/;
        return pattern.test(phone);
    }

    function showImageActions(imgElement, fileId) {
        $.actions({
            actions: [
                {
                    text: "Xóa ảnh",
                    onClick: function () {
                        $(imgElement).parent().remove();
                        const index = uploadedFiles.findIndex(f => f.id === fileId);
                        uploadedFiles = uploadedFiles.removeAt(index);
                    }
                },
                {
                    text: "Xem ảnh lớn",
                    onClick: function () {
                        const src = $(imgElement).attr('src');
                        $('.modal-image-viewer img').attr('src', src);
                        $('.modal-image-viewer').show();
                    }
                }
            ]
        });
    }

    Array.prototype.removeAt = function (index) {
        const result = [];
        for (let i = 0; i < this.length; i++) {
            if (i !== index) result.push(this[i]);
        }
        return result;
    };

    function submitForm() {
        const fullName = $('#fullName').val();
        const phoneNumber = $('#phoneNumber').val();
        const issueType = $('#issueType').val();
        const address = $('#address').val();
        const details = $('#details').val();
        const isAnonymous = $('#anonymousToggle').prop('checked');

        if (!isAnonymous && !fullName.trim()) {
            $.toast("Vui lòng nhập họ tên nếu không chọn ẩn danh", 'text');
            return;
        }

        if (!phoneNumber.trim()) {
            $.toast("Vui lòng nhập số điện thoại", 'text');
            return;
        }

        if (!isPhoneNumberValid(phoneNumber)) {
            $.toast("Số điện thoại không hợp lệ", 'text');
            return;
        }

        if (!issueType.trim()) {
            $.toast("Vui lòng chọn loại phản ánh", 'text');
            return;
        }

        const selectedValue = issueOptions.find(opt => opt.title === issueType)?.value;

        const submissionData = {
            openid: userId,
            name: fullName,
            phone: phoneNumber,
            address: address,
            content: details,
            type: selectedValue,
            attachments: uploadedFiles
        };

        post('/wechat/opinion', JSON.stringify(submissionData), function (res) {
            if (res.code !== 0) {
                $.toast(res.msg, 'forbidden');
                return;
            }
            $.toast("Gửi thành công", 'text');
            setTimeout(() => {
                location.reload();
            }, 2000);
        }, false, true);
    }
</script>
</body>
</html>

Thẻ: weui jQuery ajax file upload base64

Đăng vào ngày 7 tháng 10 lúc 15:38