Skip to content

Instantly share code, notes, and snippets.

@arm64x
Last active April 13, 2026 07:14
Show Gist options
  • Select an option

  • Save arm64x/2cd3840343bd23dd1df8101fb262e64f to your computer and use it in GitHub Desktop.

Select an option

Save arm64x/2cd3840343bd23dd1df8101fb262e64f to your computer and use it in GitHub Desktop.
Shopee Order Statistics
// ==UserScript==
// @name Shopee Order Statistics
// @namespace http://tampermonkey.net/
// @version 1.2
// @description Thống kê đơn hàng Shopee dựa theo https://github.com/Tiencp93/Shopee
// @author Lê Tí
// @match https://shopee.vn/user/purchase*
// @grant none
// @require https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js
// ==/UserScript==
(function() {
'use strict';
const style = document.createElement('style');
style.textContent = `
.shopee-stats-container {
font-family: Arial, sans-serif;
position: fixed;
bottom: 20px;
right: 20px;
width: 400px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
z-index: 999999;
}
.shopee-stats-header {
background: #ee4d2d;
color: white;
padding: 15px;
border-radius: 8px 8px 0 0;
position: relative;
}
.shopee-stats-body {
padding: 15px;
}
.shopee-stats-list {
list-style: none;
padding: 0;
margin: 0;
border: 1px solid #dee2e6;
border-radius: 0.375rem;
}
.shopee-stats-item {
padding: 0.5rem 1rem;
border-bottom: 1px solid #eee;
}
.shopee-stats-item:last-child {
border-bottom: none;
}
.shopee-stats-label {
font-size: 1rem;
color: #555;
margin-bottom: 5px;
}
.shopee-stats-value {
font-size: 18px;
color: #ee4d2d;
font-weight: bold;
margin: 0;
}
.shopee-stats-close {
position: absolute;
right: 10px;
top: 10px;
color: white;
border: none;
background: none;
font-size: 20px;
cursor: pointer;
}
.shopee-stats-btn {
position: fixed;
bottom: 100px;
right: 8px;
background: #ee4d2d;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
z-index: 999998;
font-family: Arial, sans-serif;
}
.loading-spinner {
border: 3px solid #f3f3f3;
border-top: 3px solid #ee4d2d;
border-radius: 50%;
width: 30px;
height: 30px;
animation: spin 1s linear infinite;
margin: 20px auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.text-center { text-align: center; }
.d-none { display: none; }
.shopee-stats-alert {
color: #664d03;
background: #fff3cd;
border: 1px solid #ffe69c;
padding: 1rem;
margin-bottom: 1rem;
border-radius: 0.375rem;
}
.h5, h5 {
margin-top: 0;
margin-bottom: .5rem;
font-weight: 550;
line-height: 1.2;
font-size: 1.25rem;
}
.h4, h4 {
font-size: 1.5rem;
}
.text-danger { color: rgb(220,53,69) }
.text-success { color: rgb(25,135,84) }
.text-primary { color: rgb(13,110,253) }
.text-success { color: rgb(25,135,84) }
/* Nút chụp ảnh */
.shopee-stats-footer {
padding: 0 15px 15px 15px;
}
.shopee-screenshot-btn {
width: 100%;
background: #ee4d2d;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-family: Arial, sans-serif;
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
transition: background 0.2s;
}
.shopee-screenshot-btn:hover {
background: #d43f22;
}
.shopee-screenshot-btn:disabled {
background: #aaa;
cursor: not-allowed;
}
/* Toast thông báo */
.shopee-toast {
position: fixed;
bottom: 80px;
right: 20px;
background: #333;
color: white;
padding: 10px 18px;
border-radius: 6px;
font-family: Arial, sans-serif;
font-size: 13px;
z-index: 9999999;
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
}
.shopee-toast.show {
opacity: 1;
}
`;
document.head.appendChild(style);
// Hàm hiển thị toast
function showToast(msg, duration = 2500) {
let toast = document.getElementById('shopeeToast');
if (!toast) {
toast = document.createElement('div');
toast.id = 'shopeeToast';
toast.className = 'shopee-toast';
document.body.appendChild(toast);
}
toast.textContent = msg;
toast.classList.add('show');
setTimeout(() => toast.classList.remove('show'), duration);
}
// Hàm chụp ảnh cửa sổ thống kê
async function chupAnhThongKe() {
const btn = document.getElementById('screenshotBtn');
const container = document.querySelector('.shopee-stats-container');
if (!container) return;
btn.disabled = true;
btn.textContent = '⏳ Đang chụp...';
const padding = 24; // padding nền 4 cạnh
const footer = document.getElementById('screenshotFooter');
// Ẩn nút trước khi chụp
footer.style.display = 'none';
// Chờ 1 frame để DOM cập nhật xong rồi mới chụp
await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r)));
try {
// Render canvas từ container
const canvas = await html2canvas(container, {
backgroundColor: null,
scale: 2,
useCORS: true,
logging: false,
});
// Tạo canvas mới có thêm padding nền
const paddedCanvas = document.createElement('canvas');
paddedCanvas.width = canvas.width + padding * 2;
paddedCanvas.height = canvas.height + padding * 2;
const ctx = paddedCanvas.getContext('2d');
// Vẽ nền trắng với bo tròn nhẹ
ctx.fillStyle = '#f5f5f5';
ctx.fillRect(0, 0, paddedCanvas.width, paddedCanvas.height);
// Vẽ nội dung vào giữa (có padding)
ctx.drawImage(canvas, padding, padding);
// Thử copy vào clipboard trước
const clipboardSupported =
typeof ClipboardItem !== 'undefined' &&
navigator.clipboard &&
typeof navigator.clipboard.write === 'function';
if (clipboardSupported) {
paddedCanvas.toBlob(async (blob) => {
try {
await navigator.clipboard.write([
new ClipboardItem({ 'image/png': blob })
]);
showToast('✅ Đã copy ảnh vào clipboard!');
} catch (e) {
// Clipboard bị từ chối (ví dụ thiếu quyền) → tải về
taiVe(paddedCanvas);
}
footer.style.display = 'block';
btn.disabled = false;
btn.innerHTML = '📷 Chụp ảnh thống kê';
}, 'image/png');
} else {
// Trình duyệt không hỗ trợ clipboard API → tải về
taiVe(paddedCanvas);
footer.style.display = 'block';
btn.disabled = false;
btn.innerHTML = '📷 Chụp ảnh thống kê';
}
} catch (err) {
console.error('Chụp ảnh thất bại:', err);
showToast('❌ Chụp ảnh thất bại!');
footer.style.display = 'block';
btn.disabled = false;
btn.innerHTML = '📷 Chụp ảnh thống kê';
}
}
function taiVe(canvas) {
const link = document.createElement('a');
link.download = `shopee-thong-ke-${Date.now()}.png`;
link.href = canvas.toDataURL('image/png');
link.click();
showToast('💾 Đã tải ảnh về máy!');
}
// Cập nhật HTML template
const createUI = () => {
const div = document.createElement('div');
div.setAttribute('id', 'shopeeStats');
div.innerHTML = `
<div class="shopee-stats-container">
<div class="shopee-stats-header">
<h3 style="margin:0">Thống kê đơn hàng Shopee</h3>
<button class="shopee-stats-close" onclick="document.getElementById('shopeeStats').remove();">×</button>
</div>
<div class="shopee-stats-body">
<div id="loadingStats" class="text-center d-none">
<div class="loading-spinner"></div>
<p id="loadingText">Đã thống kê được: 0 đơn hàng</p>
</div>
<div id="statsResult" class="d-none">
<div class="shopee-stats-alert h5 text-center" id="certResult"></div>
<div class="shopee-stats-list">
<div class="shopee-stats-item">
<div class="shopee-stats-label">Tổng tiền đã chi</div>
<p class="shopee-stats-value h4 text-danger" id="totalSpent">0 VNĐ</p>
</div>
<div class="shopee-stats-item">
<div class="shopee-stats-label">Tổng đơn hàng</div>
<p class="shopee-stats-value h5 text-success" id="totalOrders">0 đơn</p>
</div>
<div class="shopee-stats-item">
<div class="shopee-stats-label">Tổng sản phẩm</div>
<p class="shopee-stats-value h5 text-primary" id="totalProducts">0 sản phẩm</p>
</div>
<div class="shopee-stats-item">
<div class="shopee-stats-label">Tiết kiệm được</div>
<p class="shopee-stats-value h5 text-success" id="totalSaved">0 VNĐ</p>
</div>
</div>
</div>
</div>
<div class="shopee-stats-footer" id="screenshotFooter" style="display:none;">
<button class="shopee-screenshot-btn" id="screenshotBtn" onclick="window.__shopeeScreenshot()">
📷 Chụp ảnh thống kê
</button>
</div>
</div>
`;
document.body.appendChild(div);
// Gắn hàm chụp ảnh ra global để onclick trong HTML gọi được
window.__shopeeScreenshot = chupAnhThongKe;
};
// Các biến thống kê
let tongDonHang = 0;
let tongTienTietKiem = 0;
let tongtienhang = 0;
let tongtienhangchuagiam = 0;
let tongSanPhamDaMua = 0;
let trangThaiDonHangConKhong = true;
let offset = 0;
const si = 20;
// Format số
function pxgPrice(number, fixed = 0) {
if(isNaN(number)) return 0;
number = number.toFixed(fixed);
let delimeter = ',';
number += '';
let rgx = /(\d+)(\d{3})/;
while (rgx.test(number)) {
number = number.replace(rgx, '$1' + delimeter + '$2');
}
return number;
}
// Xác định cấp độ nghiện
function PXGCert(pri) {
if(pri <= 10000000) {
return "HÊN QUÁ! BẠN CHƯA BỊ SHOPEE GÂY NGHIỆN 😍";
} else if(pri > 10000000 && pri <= 50000000) {
return "THÔI XONG! BẠN BẮT ĐẦU NGHIỆN SHOPEE RỒI 😂";
} else if(pri > 50000000 && pri < 80000000) {
return "ỐI GIỜI ƠI! BẠN LÀ CON NGHIỆN SHOPEE CHÍNH HIỆU 😱";
} else {
return "XÓA APP SHOPEE THÔI! BẠN NGHIỆN SHOPEE NẶNG QUÁ RỒI 😝";
}
}
// Hàm lấy dữ liệu
function xemBaoCaoThongKe() {
document.getElementById('loadingStats').classList.remove('d-none');
document.getElementById('statsResult').classList.add('d-none');
fetch(`https://shopee.vn/api/v4/order/get_order_list?list_type=3&offset=${offset}&limit=${si}`)
.then(response => response.json())
.then(data => {
const orders = data.data.details_list;
tongDonHang += orders.length;
trangThaiDonHangConKhong = orders.length >= si;
orders.forEach(order => {
let t31 = order.info_card.final_total / 100000;
tongtienhang += t31;
order.info_card.order_list_cards.forEach(item => {
item.product_info.item_groups.forEach(itemGroups => {
itemGroups.items.forEach(data => {
let t5 = data.order_price / 100000;
tongSanPhamDaMua += data.amount;
tongtienhangchuagiam += t5;
});
});
});
});
document.getElementById('loadingText').textContent =
'Đã thống kê được: ' + tongDonHang + ' đơn hàng. Đang lấy thêm dữ liệu....';
offset += si;
if(trangThaiDonHangConKhong) {
xemBaoCaoThongKe();
} else {
tongTienTietKiem = tongtienhangchuagiam - tongtienhang;
// Cập nhật UI
document.getElementById('loadingStats').classList.add('d-none');
document.getElementById('statsResult').classList.remove('d-none');
document.getElementById('certResult').textContent = PXGCert(tongtienhang);
document.getElementById('totalSpent').textContent = pxgPrice(tongtienhang) + ' VNĐ';
document.getElementById('totalOrders').textContent = pxgPrice(tongDonHang) + ' đơn';
document.getElementById('totalProducts').textContent = pxgPrice(tongSanPhamDaMua) + ' sản phẩm';
document.getElementById('totalSaved').textContent = pxgPrice(tongTienTietKiem) + ' VNĐ';
// Hiện nút chụp ảnh sau khi có kết quả
document.getElementById('screenshotFooter').style.display = 'block';
}
});
}
// Thêm nút để mở thống kê
const addButton = () => {
const btn = document.createElement('button');
btn.className = 'shopee-stats-btn';
btn.textContent = 'Thống kê';
btn.onclick = () => {
createUI();
xemBaoCaoThongKe();
btn.remove();
};
document.body.appendChild(btn);
};
// Khởi tạo
window.addEventListener('load', () => {
addButton();
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment