- Quy tắc điều hướng trang trong WeChat Mini Program:
/*
- Quy trình vào trang WeChat:
-
- Gọi API để lấy URL
-
- Chuyển hướng đến URL đã nhận được, hệ thống Tencent sẽ chuyển hướng về trang cục bộ
-
- Giải mã trang chuyển hướng để thu thập tham số code
-
- Gửi code để nhận openid
-
- 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.) */
- 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>

</span>
`;
$('.attachment-preview').append(htmlSnippet);
}
};
}
});
}, false);
}
- 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);
- 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>