<!doctype html>
<html>
<head>
<script nonce="6gcAAhboxMGqtF5FU-9aYg">window['ppConfig'] = {productName: '26981ed0d57bbad37e728ff58134270c', deleteIsEnforced:  false , sealIsEnforced:  false , heartbeatRate:  0.5 , periodicReportingRateMillis:  60000.0 , disableAllReporting:  false };(function(){'use strict';function k(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}}function l(a){var b=typeof Symbol!="undefined"&&Symbol.iterator&&a[Symbol.iterator];if(b)return b.call(a);if(typeof a.length=="number")return{next:k(a)};throw Error(String(a)+" is not an iterable or ArrayLike");}var m=typeof Object.defineProperties=="function"?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a};
function n(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}throw Error("Cannot find global object");}var p=n(this);function q(a,b){if(b)a:{var c=p;a=a.split(".");for(var d=0;d<a.length-1;d++){var e=a[d];if(!(e in c))break a;c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&b!=null&&m(c,a,{configurable:!0,writable:!0,value:b})}}
q("Object.is",function(a){return a?a:function(b,c){return b===c?b!==0||1/b===1/c:b!==b&&c!==c}});q("Array.prototype.includes",function(a){return a?a:function(b,c){var d=this;d instanceof String&&(d=String(d));var e=d.length;c=c||0;for(c<0&&(c=Math.max(c+e,0));c<e;c++){var f=d[c];if(f===b||Object.is(f,b))return!0}return!1}});
q("String.prototype.includes",function(a){return a?a:function(b,c){if(this==null)throw new TypeError("The 'this' value for String.prototype.includes must not be null or undefined");if(b instanceof RegExp)throw new TypeError("First argument to String.prototype.includes must not be a regular expression");return this.indexOf(b,c||0)!==-1}});function r(a,b,c){a("https://csp.withgoogle.com/csp/proto/"+encodeURIComponent(b),JSON.stringify(c))}function t(){var a;if((a=window.ppConfig)==null?0:a.disableAllReporting)return function(){};var b,c,d,e;return(e=(b=window)==null?void 0:(c=b.navigator)==null?void 0:(d=c.sendBeacon)==null?void 0:d.bind(navigator))!=null?e:u}function u(a,b){var c=new XMLHttpRequest;c.open("POST",a);c.send(b)}
function v(){var a=(w=Object.prototype)==null?void 0:w.__lookupGetter__("__proto__"),b=x,c=y;return function(){var d=a.call(this),e,f,g,h;r(c,b,{type:"ACCESS_GET",origin:(f=window.location.origin)!=null?f:"unknown",report:{className:(g=d==null?void 0:(e=d.constructor)==null?void 0:e.name)!=null?g:"unknown",stackTrace:(h=Error().stack)!=null?h:"unknown"}});return d}}
function z(){var a=(A=Object.prototype)==null?void 0:A.__lookupSetter__("__proto__"),b=x,c=y;return function(d){d=a.call(this,d);var e,f,g,h;r(c,b,{type:"ACCESS_SET",origin:(f=window.location.origin)!=null?f:"unknown",report:{className:(g=d==null?void 0:(e=d.constructor)==null?void 0:e.name)!=null?g:"unknown",stackTrace:(h=Error().stack)!=null?h:"unknown"}});return d}}function B(a,b){C(a.productName,b);setInterval(function(){C(a.productName,b)},a.periodicReportingRateMillis)}
var D="constructor __defineGetter__ __defineSetter__ hasOwnProperty __lookupGetter__ __lookupSetter__ isPrototypeOf propertyIsEnumerable toString valueOf __proto__ toLocaleString x_ngfn_x".split(" "),E=D.concat,F=navigator.userAgent.match(/Firefox\/([0-9]+)\./),G=(!F||F.length<2?0:Number(F[1])<75)?["toSource"]:[],H;if(G instanceof Array)H=G;else{for(var I=l(G),J,K=[];!(J=I.next()).done;)K.push(J.value);H=K}var L=E.call(D,H),M=[];
function C(a,b){for(var c=[],d=l(Object.getOwnPropertyNames(Object.prototype)),e=d.next();!e.done;e=d.next())e=e.value,L.includes(e)||M.includes(e)||c.push(e);e=Object.prototype;d=[];for(var f=0;f<c.length;f++){var g=c[f];d[f]={name:g,descriptor:Object.getOwnPropertyDescriptor(Object.prototype,g),type:typeof e[g]}}if(d.length!==0){c=l(d);for(e=c.next();!e.done;e=c.next())M.push(e.value.name);var h;r(b,a,{type:"SEAL",origin:(h=window.location.origin)!=null?h:"unknown",report:{blockers:d}})}};var N=Math.random(),O=t(),P=window.ppConfig;P&&(P.disableAllReporting||P.deleteIsEnforced&&P.sealIsEnforced||N<P.heartbeatRate&&r(O,P.productName,{origin:window.location.origin,type:"HEARTBEAT"}));var y=t(),Q=window.ppConfig;if(Q)if(Q.deleteIsEnforced)delete Object.prototype.__proto__;else if(!Q.disableAllReporting){var x=Q.productName;try{var w,A;Object.defineProperty(Object.prototype,"__proto__",{enumerable:!1,get:v(),set:z()})}catch(a){}}
(function(){var a=t(),b=window.ppConfig;b&&(b.sealIsEnforced?Object.seal(Object.prototype):b.disableAllReporting||(document.readyState!=="loading"?B(b,a):document.addEventListener("DOMContentLoaded",function(){B(b,a)})))})();}).call(this);
</script><meta name="chromevox" content-script="no">
<title>上傳數字表</title>
<meta name="viewport"content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" nonce="l8bn0pA4oA9QCNS1Lu1MpQ"><link rel="stylesheet" href="/static/macros/client/css/2208734863-mae_html_css_ltr.css">
<script type="text/javascript" src="/static/macros/client/js/1525577830-warden_bin_i18n_warden__zh_tw.js"></script>
</head>
<body>
<table id="warning-bar-table" class="full_size" cellspacing="0" cellpadding="0"><tr><td><div id="warning" class="warning-bar"></div></td></tr><tr><td style="height: 100%"><iframe id="sandboxFrame" title="上傳數字表" allow="accelerometer *; autoplay *; clipboard-read *; clipboard-write *; encrypted-media *; fullscreen *; geolocation *; gyroscope *; local-network-access *; magnetometer *; midi *; payment *; picture-in-picture *; screen-wake-lock *; sync-xhr *; web-share *" sandbox="allow-downloads allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-top-navigation-by-user-activation allow-storage-access-by-user-activation">
</iframe>
</td></tr></table><script nonce="6gcAAhboxMGqtF5FU-9aYg">
(function() {
var el = document.getElementById('sandboxFrame');
el.onload = function() {
goog.script.init("\x7b\x22functionNames\x22:\x5b\x22verifySheetStructure\x22,\x22resetRitualSheet\x22,\x22fixRitualHeader\x22,\x22fixAll\x22,\x22addMember\x22,\x22checkMemberStatus\x22,\x22isMemberNoDuplicate\x22,\x22generateUploadId\x22,\x22fixAllUploadIds\x22,\x22autoFillMemberNameForUpload\x22,\x22autoFillDate\x22,\x22autoFillMonth\x22,\x22recalcMemberStats\x22,\x22updateAllStats\x22,\x22refreshSummaryStats\x22,\x22debugSummarySheet\x22,\x22updateMemberStats\x22,\x22checkDeleteRow\x22,\x22setRitualTypeDropdown\x22,\x22updateRitualRemark\x22,\x22updateRitualRecord\x22,\x22generateRitualId\x22,\x22autoFillSendTime\x22,\x22autoFillMemberNameForRitual\x22,\x22getMemberListByGroup\x22,\x22getMemberAllMonthsUpload\x22,\x22getRemarksByGroup\x22,\x22getAllRemarks\x22,\x22markRemarkAsRead\x22,\x22isMemberRitualExists\x22,\x22getMemberRitualRecords\x22,\x22getRitualRecordById\x22,\x22quickAddMember\x22,\x22saveQuickMember\x22,\x22chooseGroupStats\x22,\x22chooseGroupMonthStats\x22,\x22quickBackup\x22,\x22safeFixAll\x22,\x22safeRebuildAll\x22,\x22showAllGroupsReport\x22,\x22generateAllGroupsMainHTML\x22,\x22getAllGroupsReportData\x22,\x22getGroupStatsReport\x22,\x22maskNameForGS\x22,\x22generateAllGroupsTableHTML\x22,\x22debugMemberStructure\x22,\x22debugUploadSheet\x22,\x22showLeaderSummary\x22,\x22showGroupDetailReport\x22,\x22generateGroupDetailUploadHTML\x22,\x22getGroupDetailUploadData\x22,\x22generateGroupDetailTableHTML\x22,\x22showGroupDetailReportWithGroup\x22,\x22getGroupDetailReportWithStats\x22,\x22getAllGroupsSummary\x22,\x22generateReportTableHTML\x22,\x22generateGroupDetailHTMLV3\x22,\x22getGroupDetailReportData\x22,\x22rebuildAll\x22,\x22submitMemberForm\x22,\x22showUploadForm\x22,\x22getMemberInfo\x22,\x22getUploadCount\x22,\x22getMemberIdByNo\x22,\x22getMemberIdByNoCN\x22,\x22submitUploadData\x22,\x22getUploadRecordsByMember\x22,\x22getMemberHistory\x22,\x22findMemberRow\x22,\x22clearTestUploadData\x22,\x22showAllUploadData\x22,\x22clearUploadRow2\x22,\x22clearUploadRow28\x22,\x22clearUploadCellA302\x22,\x22viewRow28\x22,\x22deleteRowByNumber\x22,\x22setCellValue\x22,\x22doGet\x22,\x22doPost\x22,\x22fixMonthStats\x22,\x22fixFirstHalfStats\x22,\x22fixSecondHalfStats\x22,\x22fixYearTotalColumn\x22,\x22fixAllYearTotals\x22,\x22fixAQColumn\x22,\x22fixBDColumn\x22,\x22fixBQColumn\x22,\x22fixCDColumn\x22,\x22fixCQColumn\x22,\x22onOpen\x22,\x22quickFix10\x22,\x22quickFix20\x22,\x22quickFix30\x22,\x22quickFix50\x22,\x22quickFix100\x22,\x22quickFixByRange\x22,\x22deleteSelectedRowsAndUpdate\x22,\x22quickFixWithRange\x22,\x22addMemberByMode\x22,\x22checkMemberNoExists\x22,\x22getGroupsList\x22,\x22getMemberInfoByNo\x22,\x22forceFixMColumn\x22,\x22saveMemberUploadsData\x22,\x22getUploadCountCN\x22,\x22addLeaderMemberCN\x22,\x22getMemberDetail\x22,\x22updateMember\x22,\x22getFullMemberListByGroup\x22,\x22getMemberInfoForLeaderUpload\x22,\x22getMemberUploadRecordsForLeader\x22,\x22updateMemberUploadRecord\x22,\x22getAllRemarksCN\x22,\x22cnGetMemberInfo\x22,\x22getCnUploadLocation\x22,\x22cnSubmitUpload\x22,\x22updateCnMemberTotal\x22,\x22getCnCurrentYearMonth\x22,\x22getMemberInfoForForm\x22,\x22addUserMember\x22,\x22addLeaderMember\x22,\x22getNewMembersByGroup\x22,\x22getNewMembersByGroupCN\x22,\x22getAllNewMembers\x22,\x22getAllNewMembersCN\x22,\x22sendUploadRemarkNotificationCN\x22,\x22sendUploadRemarkNotification\x22,\x22submitUserUpload\x22,\x22getMonthColumn\x22,\x22getYearTotalColumn\x22,\x22copyDateFormatToNewColumns\x22,\x22resetAllMColumns\x22,\x22resetAQColumn\x22,\x22updateMemberUploadRecordWithRemark\x22,\x22getMonthIndex\x22,\x22getYearTotalColumnByYear\x22,\x22registerMember\x22,\x22submitLeaderUpload\x22,\x22submitUploadFormData\x22,\x22onEdit\x22,\x22batchImportFullYearData\x22,\x22showYearlySummary\x22,\x22batchImportCustomMembers\x22,\x22batchImport300Members\x22,\x22recalculateAllTotals\x22,\x22flushDataToSheet\x22,\x22createUploadSheet\x22,\x22getCurrentBatch\x22,\x22isBatchOpen\x22,\x22addRitualRecord\x22,\x22testBatch\x22,\x22testAdd\x22,\x22forceInsertUploadSameRow\x22,\x22batchAdd2026\x22,\x22batchAdd2027\x22,\x22batchAdd2028\x22,\x22batchAdd2029\x22,\x22batchAdd2030\x22,\x22batchAdd2031\x22,\x22batchAddYearAllMembers\x22,\x22batchAddYear\x22,\x22batchQuick\x22,\x22generateMassUploadRecords\x22,\x22quickGenerate500\x22,\x22quickGenerate\x22,\x22clearMemberRowsFrom45\x22,\x22testSendEmail\x22,\x22authorizeMailApp\x22,\x22copyJ43ToJ41J42\x22,\x22emergencyStop\x22,\x22setupBalancedSync\x22,\x22incrementalSync\x22,\x22autoFullSync\x22,\x22updateSingleMemberFast\x22,\x22updateSingleMemberFastCN\x22,\x22checkSyncStatus\x22,\x22checkEmailQuota\x22\x5d,\x22sandboxMode\x22:\x22IFRAME_SANDBOX\x22,\x22callbackTimeout\x22:390000,\x22deploymentId\x22:\x22AKfycbxqdFwA4g3SftznJybl4N4dQIbCkO9UgAPF83mkox3MRuZHOQMycsz-xik8Vs7oEvTB\x22,\x22eei\x22:\x22\x22,\x22sandboxHost\x22:\x22https:\/\/n-65hr6nufvavzrcori3cp2m5pvuuwxchjnykofga-0lu-script.googleusercontent.com\x22,\x22clientSideProperties\x22:\x7b\x22google.script.sandbox.mode\x22:\x22IFRAME_SANDBOX\x22,\x22google.script.use_fetch_for_post_form\x22:false,\x22google.script.host.origin\x22:\x22https:\/\/docs.google.com\x22\x7d,\x22actionPrefix\x22:\x22\/macros\/s\/AKfycbxqdFwA4g3SftznJybl4N4dQIbCkO9UgAPF83mkox3MRuZHOQMycsz-xik8Vs7oEvTB\x22,\x22userHtml\x22:\x22\x3c!DOCTYPE html\x3e\\n\x3chtml lang\x3d\\\x22zh-Hant\\\x22\x3e\\n\x3chead\x3e\\n    \x3cmeta charset\x3d\\\x22UTF-8\\\x22\x3e\\n    \x3cmeta name\x3d\\\x22viewport\\\x22 content\x3d\\\x22width\x3ddevice-width, initial-scale\x3d1.0, user-scalable\x3dyes\\\x22\x3e\\n    \x3ctitle\x3e5次上傳測試區 📤 上傳數字表\x3c\\\/title\x3e\\n    \x3cstyle\x3e\\n        * \x7b box-sizing: border-box; font-family: system-ui, -apple-system, BlinkMacSystemFont, \x27Segoe UI\x27, Roboto, \x27Helvetica Neue\x27, Arial, \x27Noto Sans\x27, \x27PingFang SC\x27, \x27Microsoft YaHei\x27, sans-serif; \x7d\\n        \\n        body \x7b \\n            background: linear-gradient(145deg, #e0e7ff 0%, #c7d2fe 100%); \\n            margin: 0; \\n            padding: 20px 16px 40px 16px;\\n        \x7d\\n        .app-container \x7b \\n            max-width: 900px; \\n            width: 100%; \\n            margin: 0 auto; \\n            background: white; \\n            border-radius: 40px; \\n            box-shadow: 0 25px 45px -12px rgba(0,0,0,0.35); \\n            overflow: hidden; \\n        \x7d\\n        .hero-header \x7b background: #1e293b; color: white; padding: 24px 20px; position: relative; \x7d\\n        .hero-header h1 \x7b margin: 0; font-size: 28px; font-weight: 700; \x7d\\n        .hero-header p \x7b margin: 8px 0 0; opacity: 0.8; font-size: 16px; \x7d\\n        .tab-pane \x7b padding: 20px 16px; background: white; \x7d\\n        .form-row \x7b margin-bottom: 20px; \x7d\\n        label \x7b display: block; font-weight: 600; margin-bottom: 10px; color: #0f172a; font-size: 16px; \x7d\\n        input, select, textarea \x7b width: 100%; padding: 14px 18px; border: 1.5px solid #e2e8f0; border-radius: 28px; font-size: 16px; background: #fefefe; line-height: 1.4; \x7d\\n        input:disabled \x7b background: #f1f5f9; color: #94a3b8; cursor: not-allowed; \x7d\\n        button \x7b width: 100%; padding: 16px; background: #f97316; border: none; border-radius: 40px; font-weight: bold; font-size: 16px; color: white; cursor: pointer; margin-top: 20px; \x7d\\n        button.primary \x7b background: #f97316; \x7d\\n        button.primary:hover \x7b background: #ea580c; \x7d\\n        button.query-btn \x7b background: #0369a1; margin-top: 0; \x7d\\n        button.query-btn:hover \x7b background: #258BC9; \x7d\\n        button:disabled \x7b background: #cbd5e1; cursor: not-allowed; \x7d\\n        .message \x7b margin-top: 16px; padding: 14px; border-radius: 40px; text-align: center; font-size: 16px; display: none; line-height: 1.5; \x7d\\n        .message.success \x7b background: #dcfce7; color: #15803d; display: block; \x7d\\n        .message.error \x7b background: #fee2e2; color: #b91c1c; display: block; \x7d\\n        .message.warning \x7b background: #fff3e0; color: #e65100; display: block; \x7d\\n        .message.info \x7b background: #e0f2fe; color: #0369a1; display: block; \x7d\\n        .info-card \x7b background: #fef9e8; border-left: 5px solid #f97316; padding: 16px; border-radius: 24px; margin-bottom: 20px; font-size: 14px; line-height: 1.3; \x7d\\n        .warning-badge \x7b background: #ffedd5; color: #9a3412; padding: 14px; border-radius: 30px; text-align: center; font-weight: bold; margin-bottom: 20px; display: none; font-size: 16px; \x7d\\n        .history-item \x7b font-size: 16px; background: #fff7ed; margin: 5px 0; padding: 12px 16px; border-radius: 40px; display: flex; justify-content: space-between; flex-wrap: wrap; gap: 10px; line-height: 1.5; \x7d\\n        .history-time \x7b font-size: 14px; color: #8d6e63; background: #f0e4c6; padding: 5px 10px; border-radius: 20px; font-family: monospace; \x7d\\n        footer \x7b text-align: center; font-size: 16px; padding: 14px; color: #94a3b8; background: #f8fafc; \x7d\\n        \\n        .reminder-box \x7b\\n            background: #e3f2fd;\\n            border-left: 4px solid #2196f3;\\n            padding: 16px 20px;\\n            border-radius: 16px;\\n            margin-bottom: 20px;\\n            font-size: 15px;\\n            color: #1565c0;\\n            line-height: 1.6;\\n        \x7d\\n        .reminder-box .emoji \x7b font-size: 22px; display: inline-block; margin-right: 10px; \x7d\\n        .reminder-box .text \x7b flex: 1; \x7d\\n        .reminder-box .text strong \x7b color: #0d47a1; \x7d\\n        \\n        .rule-box \x7b\\n            background: #fef9e8;\\n            border-left: 4px solid #f97316;\\n            padding: 16px 20px;\\n            border-radius: 16px;\\n            margin-bottom: 20px;\\n            font-size: 15px;\\n            color: #5d4037;\\n            line-height: 1.6;\\n        \x7d\\n        .rule-box .title \x7b\\n            font-weight: bold;\\n            font-size: 16px;\\n            margin-bottom: 8px;\\n            color: #e65100;\\n        \x7d\\n        .rule-box ul \x7b\\n            margin: 5px 0;\\n            padding-left: 20px;\\n        \x7d\\n        .rule-box li \x7b\\n            margin: 5px 0;\\n        \x7d\\n        \\n        .loading-spinner \x7b\\n            display: inline-block;\\n            width: 20px;\\n            height: 20px;\\n            border: 3px solid #f3f3f3;\\n            border-top: 3px solid #f97316;\\n            border-radius: 50%;\\n            animation: spin 0.8s linear infinite;\\n            vertical-align: middle;\\n            margin-right: 10px;\\n        \x7d\\n        @keyframes spin \x7b\\n            0% \x7b transform: rotate(0deg); \x7d\\n            100% \x7b transform: rotate(360deg); \x7d\\n        \x7d\\n        \\n        .query-status-area \x7b\\n            margin-bottom: 20px;\\n            display: none;\\n        \x7d\\n        .query-status-card \x7b\\n            background: #f1f5f9;\\n            border-radius: 32px;\\n            padding: 14px 18px;\\n            text-align: center;\\n            font-size: 16px;\\n            font-weight: 500;\\n            color: #1e293b;\\n            border-left: 6px solid #f97316;\\n        \x7d\\n        .query-status-card.loading \x7b\\n            background: #e0f2fe;\\n            color: #0369a1;\\n            border-left-color: #0284c7;\\n        \x7d\\n        .query-status-card.success \x7b\\n            background: #dcfce7;\\n            color: #15803d;\\n            border-left-color: #22c55e;\\n        \x7d\\n        .query-status-card.error \x7b\\n            background: #fee2e2;\\n            color: #b91c1c;\\n            border-left-color: #ef4444;\\n        \x7d\\n        .query-status-card.warning \x7b\\n            background: #ffedd5;\\n            color: #9a3412;\\n            border-left-color: #f97316;\\n        \x7d\\n        \\n        .query-btn-wrapper \x7b\\n            margin: 10px 0 20px 0;\\n            display: flex;\\n            gap: 10px;\\n        \x7d\\n        .query-btn-wrapper button \x7b\\n            flex: 1;\\n            margin-top: 0;\\n        \x7d\\n        \\n        @keyframes fadeInUp \x7b\\n            from \x7b opacity: 0; transform: translateY(-30px); \x7d\\n            to \x7b opacity: 1; transform: translateY(0); \x7d\\n        \x7d\\n\\n         \\n        .month-slider-container \x7b\\n            position: relative;\\n            overflow: hidden;\\n            border-radius: 12px;\\n            margin: 10px 0;\\n            background: #f0e8df;\\n            padding: 4px 0;\\n        \x7d\\n\\n        .month-slider-wrapper \x7b\\n            display: flex;\\n            overflow-x: auto;\\n            scroll-snap-type: x mandatory;\\n            -webkit-overflow-scrolling: touch;\\n            scroll-behavior: smooth;\\n            padding: 8px 4px 12px 4px;\\n            gap: 10px;\\n            mask-image: linear-gradient(to right, transparent 0%, black 6%, black 94%, transparent 100%);\\n            -webkit-mask-image: linear-gradient(to right, transparent 0%, black 6%, black 94%, transparent 100%);\\n        \x7d\\n\\n        .month-slider-wrapper::-webkit-scrollbar \x7b\\n            height: 4px;\\n        \x7d\\n        .month-slider-wrapper::-webkit-scrollbar-track \x7b\\n            background: #d4c5b2;\\n            border-radius: 4px;\\n        \x7d\\n        .month-slider-wrapper::-webkit-scrollbar-thumb \x7b\\n            background: #a89080;\\n            border-radius: 4px;\\n        \x7d\\n\\n        .month-card \x7b\\n            flex: 0 0 260px;\\n            scroll-snap-align: start;\\n            background: #fefcf8;\\n            border-radius: 12px;\\n            padding: 14px 16px;\\n            box-shadow: 0 1px 4px rgba(80, 50, 30, 0.08);\\n            border: 1px solid #e0d5c8;\\n            transition: all 0.2s ease;\\n            min-width: 220px;\\n        \x7d\\n        .month-card:hover \x7b\\n            border-color: #b8a898;\\n            box-shadow: 0 2px 10px rgba(80, 50, 30, 0.12);\\n        \x7d\\n        .month-card .month-header \x7b\\n            display: flex;\\n            justify-content: space-between;\\n            align-items: center;\\n            margin-bottom: 8px;\\n            padding-bottom: 6px;\\n            border-bottom: 1px solid #e8ddd0;\\n        \x7d\\n        .month-card .month-title \x7b\\n            font-weight: 600;\\n            font-size: 15px;\\n            color: #3d2b1f;\\n        \x7d\\n        .month-card .month-total \x7b\\n            font-weight: 600;\\n            font-size: 16px;\\n            color: #6d4c41;\\n            background: #f0e8df;\\n            padding: 1px 12px;\\n            border-radius: 12px;\\n        \x7d\\n\\n         \\n        .month-card .record-item \x7b\\n            display: flex;\\n            flex-wrap: wrap;\\n            align-items: center;\\n            padding: 4px 0;\\n            border-bottom: 1px solid #f0e8df;\\n            font-size: 13px;\\n            gap: 2px 6px;\\n        \x7d\\n        .month-card .record-item:last-child \x7b\\n            border-bottom: none;\\n        \x7d\\n        .month-card .record-item .record-index \x7b\\n            color: #a89080;\\n            font-size: 12px;\\n            min-width: 48px;\\n        \x7d\\n        .month-card .record-item .record-amount \x7b\\n            font-weight: 600;\\n            color: #6d4c41;\\n            min-width: 50px;\\n            text-align: right;\\n        \x7d\\n        .month-card .record-item .record-time \x7b\\n            font-size: 11px;\\n            color: #b8a898;\\n            min-width: 120px;\\n        \x7d\\n        .month-card .record-item .record-remark \x7b\\n            font-size: 11px;\\n            color: #6d4c41;\\n            background: #f0e8df;\\n            padding: 1px 10px;\\n            border-radius: 10px;\\n            border: 1px solid #e0d5c8;\\n            white-space: nowrap;\\n            text-align: left;\\n            display: inline-block;\\n        \x7d\\n\\n        .month-card .no-record \x7b\\n            text-align: center;\\n            color: #c8b8a8;\\n            padding: 12px 0;\\n            font-size: 13px;\\n        \x7d\\n\\n         \\n        .year-jump-buttons \x7b\\n            display: flex;\\n            gap: 6px;\\n            flex-wrap: wrap;\\n            margin: 8px 0 4px 0;\\n        \x7d\\n        .year-jump-buttons button \x7b\\n            background: #f0e8df;\\n            border: 1px solid #d4c5b2;\\n            border-radius: 20px;\\n            padding: 4px 14px;\\n            font-size: 13px;\\n            font-weight: 500;\\n            cursor: pointer;\\n            color: #6d4c41;\\n            width: auto;\\n            margin: 0;\\n            transition: all 0.2s ease;\\n        \x7d\\n        .year-jump-buttons button:hover \x7b\\n            background: #e0d5c8;\\n            border-color: #b8a898;\\n        \x7d\\n        .year-jump-buttons button.active \x7b\\n            background: #8d6e63;\\n            border-color: #8d6e63;\\n            color: white;\\n        \x7d\\n\\n         \\n        .year-table \x7b\\n            width: 100%;\\n            border-collapse: collapse;\\n            font-size: 13px;\\n            margin: 8px 0;\\n            background: #fefcf8;\\n            border-radius: 10px;\\n            overflow: hidden;\\n            box-shadow: 0 1px 3px rgba(80, 50, 30, 0.06);\\n        \x7d\\n        .year-table th \x7b\\n            background: #d4c5b2;\\n            color: #3d2b1f;\\n            padding: 6px 4px;\\n            text-align: center;\\n            font-weight: 600;\\n            font-size: 12px;\\n            white-space: nowrap;\\n        \x7d\\n        .year-table td \x7b\\n            padding: 6px 4px;\\n            text-align: center;\\n            border-bottom: 1px solid #f0e8df;\\n            font-size: 12px;\\n            color: #4a3520;\\n        \x7d\\n        .year-table tr:hover td \x7b\\n            background: #f5ede4;\\n        \x7d\\n        .year-table .year-total \x7b\\n            font-weight: 700;\\n            color: #6d4c41;\\n            background: #f0e8df;\\n        \x7d\\n        .year-table .empty-cell \x7b\\n            color: #d4c5b2;\\n        \x7d\\n        .year-table .month-cell \x7b\\n            font-family: \x27Courier New\x27, monospace;\\n            font-weight: 500;\\n        \x7d\\n\\n         \\n        .year-table td .upload-count-badge \x7b\\n            display: inline-block;\\n            font-size: 9px;\\n            color: #a89080;\\n            background: #f0e8df;\\n            padding: 0 5px;\\n            border-radius: 8px;\\n            margin-left: 2px;\\n        \x7d\\n\\n         \\n        .slider-hint \x7b\\n            display: flex;\\n            justify-content: space-between;\\n            align-items: center;\\n            padding: 0 2px 6px 2px;\\n            font-size: 12px;\\n            color: #b8a898;\\n        \x7d\\n        .slider-hint .hint-text \x7b\\n            display: flex;\\n            align-items: center;\\n            gap: 6px;\\n        \x7d\\n        .slider-hint .hint-arrow \x7b\\n            animation: bounceArrow 1.5s ease-in-out infinite;\\n        \x7d\\n        .slider-hint .hint-arrow-left \x7b\\n            animation: bounceArrowLeft 1.5s ease-in-out infinite;\\n        \x7d\\n        @keyframes bounceArrow \x7b\\n            0%, 100% \x7b transform: translateX(0); \x7d\\n            50% \x7b transform: translateX(6px); \x7d\\n        \x7d\\n        @keyframes bounceArrowLeft \x7b\\n            0%, 100% \x7b transform: translateX(0); \x7d\\n            50% \x7b transform: translateX(-6px); \x7d\\n        \x7d\\n\\n         \\n        #historyResultArea \x7b\\n            display: none;\\n            margin-top: 20px;\\n        \x7d\\n        #historyResultArea.visible \x7b\\n            display: block;\\n        \x7d\\n        #historyResultArea .info-card \x7b\\n            background: #f5ede4;\\n            border-left: 4px solid #8d6e63;\\n            padding: 16px;\\n            border-radius: 12px;\\n        \x7d\\n        #historyResultArea .close-btn \x7b\\n            background: #e8ddd0;\\n            border: none;\\n            border-radius: 20px;\\n            padding: 4px 14px;\\n            font-size: 13px;\\n            cursor: pointer;\\n            width: auto;\\n            margin: 0;\\n            color: #6d4c41;\\n        \x7d\\n        #historyResultArea .close-btn:hover \x7b\\n            background: #d4c5b2;\\n        \x7d\\n\\n         \\n        #userMemberInfo.hidden \x7b\\n            display: none !important;\\n        \x7d\\n\\n         \\n        @media (max-width: 600px) \x7b\\n            .hero-header .title-row \x7b\\n                flex-direction: column;\\n                align-items: flex-start;\\n            \x7d\\n            .hero-header .title-group \x7b\\n                width: 100%;\\n            \x7d\\n            .hero-header h1 \x7b\\n                font-size: 22px;\\n            \x7d\\n            \\n            .hero-header .subtitle-row \x7b\\n                flex-direction: row;\\n                flex-wrap: nowrap;\\n                align-items: center;\\n                gap: 8px;\\n                width: 100%;\\n            \x7d\\n            .hero-header .subtitle-row p \x7b\\n                flex: 1;\\n                min-width: 0;\\n                font-size: 15px;\\n                white-space: nowrap;\\n                overflow: hidden;\\n                text-overflow: ellipsis;\\n            \x7d\\n            .lang-switch \x7b\\n                width: 40px;\\n                height: 40px;\\n                font-size: 16px;\\n                border-radius: 6px;\\n                flex-shrink: 0;\\n            \x7d\\n        \x7d\\n        \\n        @media (max-width: 380px) \x7b\\n            .hero-header .subtitle-row p \x7b\\n                font-size: 12px;\\n            \x7d\\n            .lang-switch \x7b\\n                width: 34px;\\n                height: 34px;\\n                font-size: 11px;\\n                border-radius: 5px;\\n            \x7d\\n        \x7d\\n\\n\\n\\n\\n        \\n    \x3c\\\/style\x3e\\n\x3c\\\/head\x3e\\n\x3cbody\x3e\\n\x3cdiv class\x3d\\\x22app-container\\\x22\x3e\\n    \x3cdiv class\x3d\\\x22hero-header\\\x22\x3e\\n        \x3ch1\x3e5次上傳測試區 📤 上傳數字表\x3c\\\/h1\x3e\\n        \x3cp\x3e請先查詢會員，確認資料後再上傳\x3c\\\/p\x3e\\n    \x3c\\\/div\x3e\\n    \x3cdiv class\x3d\\\x22tab-pane\\\x22\x3e\\n        \\n        \x3cdiv class\x3d\\\x22rule-box\\\x22\x3e\\n            \x3cdiv class\x3d\\\x22title\\\x22\x3e📌 上傳注意事項\x3c\\\/div\x3e\\n            \x3cul\x3e\\n                \x3cli\x3e📊 \x3cstrong\x3e只統計當月份上傳數字\x3c\\\/strong\x3e，每月1日重新計算，次月不累計\x3c\\\/li\x3e\\n                \x3cli\x3e✏️ \x3cstrong\x3e系統無法扣除上傳數字\x3c\\\/strong\x3e，請在5次上傳內仔細確認數字\x3c\\\/li\x3e\\n                \x3cli\x3e💬 若填寫錯誤，請直接向\x3cstrong\x3e組長反映\x3c\\\/strong\x3e，由組長協助修改\x3c\\\/li\x3e\\n                \x3cli\x3e📈 每月最多可上傳 \x3cstrong\x3e5 次\x3c\\\/strong\x3e，超過次數無法再上傳\x3c\\\/li\x3e\\n            \x3c\\\/ul\x3e\\n        \x3c\\\/div\x3e\\n        \\n        \x3cdiv class\x3d\\\x22reminder-box\\\x22\x3e\\n            \x3cspan class\x3d\\\x22emoji\\\x22\x3e💡\x3c\\\/span\x3e\\n            \x3cspan class\x3d\\\x22text\\\x22\x3e\x3cstrong\x3e操作步驟：\x3c\\\/strong\x3e\x3cbr\x3e\\n            ① 輸入會員編號後按「🔍 查詢會員」\x3cbr\x3e\\n            ② 確認會員資料（查詢成功後數字欄位才會啟用）\x3cbr\x3e\\n            ③ 輸入數字\x3cbr\x3e\\n            ④ 點擊「📤 確認上傳」\x3c\\\/span\x3e\\n        \x3c\\\/div\x3e\\n        \\n        \x3cdiv class\x3d\\\x22form-row\\\x22\x3e\\n            \x3clabel\x3e🔢 測試會員編號：01001\x3c\\\/label\x3e\\n            \x3cinput type\x3d\\\x22text\\\x22 id\x3d\\\x22userMemberNo\\\x22 placeholder\x3d\\\x22請輸入會員編號\\\x22\x3e\\n        \x3c\\\/div\x3e\\n        \\n        \\n        \x3cdiv class\x3d\\\x22query-btn-wrapper\\\x22 style\x3d\\\x22display: flex; gap: 10px;\\\x22\x3e\\n            \x3cbutton id\x3d\\\x22userCheckBtn\\\x22 class\x3d\\\x22query-btn\\\x22 style\x3d\\\x22flex: 1;\\\x22 onclick\x3d\\\x22queryMember()\\\x22\x3e🔍 查詢會員\x3c\\\/button\x3e\\n            \x3cbutton id\x3d\\\x22userHistoryBtn\\\x22 class\x3d\\\x22query-btn\\\x22 style\x3d\\\x22flex: 1; background: #94a3b8; opacity: 0.6; cursor: not-allowed;\\\x22 onclick\x3d\\\x22queryMemberHistory()\\\x22 disabled\x3e\\n                📋 查詢歷史\\n            \x3c\\\/button\x3e\\n        \x3c\\\/div\x3e\\n        \\n        \x3cdiv id\x3d\\\x22queryStatusArea\\\x22 class\x3d\\\x22query-status-area\\\x22\x3e\\n            \x3cdiv id\x3d\\\x22queryStatusCard\\\x22 class\x3d\\\x22query-status-card\\\x22\x3e\x3c\\\/div\x3e\\n        \x3c\\\/div\x3e\\n        \\n        \\n        \x3cdiv id\x3d\\\x22userMemberInfo\\\x22 style\x3d\\\x22display:none;\\\x22 class\x3d\\\x22info-card\\\x22\x3e\\n            \x3cdiv\x3e\x3cstrong\x3e📌 會員姓名：\x3c\\\/strong\x3e \x3cspan id\x3d\\\x22showMemberName\\\x22\x3e-\x3c\\\/span\x3e\x3c\\\/div\x3e\\n            \x3cdiv\x3e\x3cstrong\x3e📊 已上傳次數：\x3c\\\/strong\x3e \x3cspan id\x3d\\\x22uploadCountSpan\\\x22\x3e0\x3c\\\/span\x3e \/ 5\x3c\\\/div\x3e\\n            \x3cdiv id\x3d\\\x22historyArea\\\x22\x3e\x3c\\\/div\x3e\\n        \x3c\\\/div\x3e\\n        \\n        \\n        \x3cdiv id\x3d\\\x22historyResultArea\\\x22 style\x3d\\\x22display:none; margin-top: 20px;\\\x22\x3e\\n            \x3cdiv class\x3d\\\x22info-card\\\x22 style\x3d\\\x22background: #f5f3ff; border-left-color: #7c3aed;\\\x22\x3e\\n                \x3cdiv style\x3d\\\x22display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; flex-wrap: wrap; gap: 10px;\\\x22\x3e\\n                    \x3cstrong style\x3d\\\x22font-size: 20px;\\\x22\x3e📋 歷史紀錄總覽\x3c\\\/strong\x3e\\n                    \x3cdiv style\x3d\\\x22display: flex; gap: 10px; align-items: center;\\\x22\x3e\\n                        \x3cspan id\x3d\\\x22historyRecordCount\\\x22 style\x3d\\\x22background: #ede9fe; padding: 4px 16px; border-radius: 20px; font-size: 14px;\\\x22\x3e📊 0 筆\x3c\\\/span\x3e\\n                        \x3cbutton onclick\x3d\\\x22closeHistory()\\\x22 style\x3d\\\x22background: #e2e8f0; border: none; border-radius: 30px; padding: 6px 16px; font-size: 14px; cursor: pointer; width: auto; margin: 0;\\\x22\x3e✕ 關閉\x3c\\\/button\x3e\\n                    \x3c\\\/div\x3e\\n                \x3c\\\/div\x3e\\n                \\n                \\n                \x3cdiv id\x3d\\\x22yearlyTableContainer\\\x22\x3e\x3c\\\/div\x3e\\n                \\n                \\n                \x3cdiv class\x3d\\\x22year-jump-buttons\\\x22 id\x3d\\\x22yearJumpButtons\\\x22\x3e\x3c\\\/div\x3e\\n                \\n                \\n                \x3cdiv class\x3d\\\x22slider-hint\\\x22\x3e\\n                    \x3cspan class\x3d\\\x22hint-text\\\x22\x3e\\n                        \x3cspan class\x3d\\\x22hint-arrow-left\\\x22\x3e◀\x3c\\\/span\x3e 左右滑動瀏覽\\n                    \x3c\\\/span\x3e\\n                    \x3cspan class\x3d\\\x22hint-text\\\x22\x3e\\n                        共 \x3cspan id\x3d\\\x22totalMonthsCount\\\x22\x3e0\x3c\\\/span\x3e 個月\\n                        \x3cspan class\x3d\\\x22hint-arrow\\\x22\x3e▶\x3c\\\/span\x3e\\n                    \x3c\\\/span\x3e\\n                \x3c\\\/div\x3e\\n                \\n                \\n                \x3cdiv class\x3d\\\x22month-slider-container\\\x22\x3e\\n                    \x3cdiv class\x3d\\\x22month-slider-wrapper\\\x22 id\x3d\\\x22monthSliderWrapper\\\x22\x3e\x3c\\\/div\x3e\\n                \x3c\\\/div\x3e\\n            \x3c\\\/div\x3e\\n        \x3c\\\/div\x3e\\n        \\n        \x3cdiv id\x3d\\\x22userLimitWarning\\\x22 class\x3d\\\x22warning-badge\\\x22\x3e⚠️ 本月已達5次上傳上限！\x3c\\\/div\x3e\\n        \\n        \x3cdiv class\x3d\\\x22form-row\\\x22\x3e\\n            \x3clabel\x3e💰 上傳數字\x3c\\\/label\x3e\\n            \x3cinput type\x3d\\\x22number\\\x22 id\x3d\\\x22userAmount\\\x22 placeholder\x3d\\\x22請先查詢會員\\\x22 disabled\x3e\\n        \x3c\\\/div\x3e\\n        \\n        \x3cdiv class\x3d\\\x22form-row\\\x22\x3e\\n            \x3clabel\x3e📝 備註\x3c\\\/label\x3e\\n            \x3cinput type\x3d\\\x22text\\\x22 id\x3d\\\x22userRemark\\\x22 placeholder\x3d\\\x22備註說明\\\x22 disabled\x3e\\n        \x3c\\\/div\x3e\\n        \\n        \x3cbutton id\x3d\\\x22userUploadBtn\\\x22 class\x3d\\\x22primary\\\x22 onclick\x3d\\\x22uploadAmount()\\\x22 disabled\x3e📤 確認上傳\x3c\\\/button\x3e\\n        \x3cdiv id\x3d\\\x22userUploadMsg\\\x22 class\x3d\\\x22message\\\x22\x3e\x3c\\\/div\x3e\\n    \x3c\\\/div\x3e\\n    \x3cfooter\x3e© 會員上傳系統\x3c\\\/footer\x3e\\n\x3c\\\/div\x3e\\n\\n\x3cscript\x3e\\n    var currentUser \x3d null;\\n    var isQuerying \x3d false;\\n\\n    \\n    \\n    \\n    function maskName(name) \x7b\\n        if (!name) return \x27\x27;\\n        var n \x3d name.trim();\\n        if (n.length \x3c\x3d 2) return n;\\n        return n.charAt(0) + \x27O\x27 + n.charAt(n.length - 1);\\n    \x7d\\n\\n    function showSuccessModal(message) \x7b\\n    var existing \x3d document.getElementById(\x27customSuccessModal\x27);\\n    if (existing) existing.remove();\\n    var modal \x3d document.createElement(\x27div\x27);\\n    modal.id \x3d \x27customSuccessModal\x27;\\n    modal.style.cssText \x3d \x27position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); display:flex; align-items:flex-start; justify-content:center; z-index:10000; padding-top:120px;\x27;\\n    \\n    \\n    modal.innerHTML \x3d \x27\x3cdiv style\x3d\\\x22background:white; border-radius:32px; padding:24px 22px; width:280px; text-align:center; animation:fadeInUp 0.3s ease; box-shadow:0 20px 60px rgba(0,0,0,0.3);\\\x22\x3e\x27 +\\n                        \x27\x3cdiv style\x3d\\\x22font-size:40px; margin-bottom:10px;\\\x22\x3e🎉\x3c\\\/div\x3e\x27 +\\n                        \x27\x3ch3 style\x3d\\\x22color:#1e293b; margin-bottom:12px; font-size:20px;\\\x22\x3e通知！\x3c\\\/h3\x3e\x27 +\\n                        \x27\x3cdiv style\x3d\\\x22color:#475569; line-height:1.8; margin-bottom:18px; text-align:left; white-space:pre-line; font-size:14px;\\\x22\x3e\x27 + \\n                            message.replace(\/\\\\n\/g, \x27\x3cbr\x3e\x27) + \\n                        \x27\x3c\\\/div\x3e\x27 +\\n                        \x27\x3cbutton id\x3d\\\x22closeSuccessModalBtn\\\x22 style\x3d\\\x22background:#f97316; color:white; border:none; padding:12px 20px; border-radius:32px; font-size:15px; font-weight:600; cursor:pointer; width:100%;\\\x22\x3e我知道了\x3c\\\/button\x3e\x27 +\\n                    \x27\x3c\\\/div\x3e\x27;\\n    document.body.appendChild(modal);\\n    document.getElementById(\x27closeSuccessModalBtn\x27).onclick \x3d function() \x7b modal.remove(); \x7d;\\n    modal.onclick \x3d function(e) \x7b if (e.target \x3d\x3d\x3d modal) modal.remove(); \x7d;\\n\x7d\\n\\n    function showMsg(msg, type) \x7b\\n        var el \x3d document.getElementById(\x27userUploadMsg\x27);\\n        if (el) \x7b\\n            el.className \x3d \x27message \x27 + type;\\n            el.innerText \x3d msg;\\n            el.style.display \x3d \x27block\x27;\\n            setTimeout(function() \x7b if (el) el.style.display \x3d \x27none\x27; \x7d, 4000);\\n        \x7d\\n    \x7d\\n\\n    function showQueryStatus(status, message) \x7b\\n        var area \x3d document.getElementById(\x27queryStatusArea\x27);\\n        var card \x3d document.getElementById(\x27queryStatusCard\x27);\\n        \\n        area.style.display \x3d \x27block\x27;\\n        card.innerHTML \x3d \x27\x27;\\n        \\n        switch(status) \x7b\\n            case \x27loading\x27:\\n                card.className \x3d \x27query-status-card loading\x27;\\n                card.innerHTML \x3d \x27\x3cspan class\x3d\\\x22loading-spinner\\\x22\x3e\x3c\\\/span\x3e 🔍 \x27 + message;\\n                break;\\n            case \x27success\x27:\\n                card.className \x3d \x27query-status-card success\x27;\\n                card.innerHTML \x3d \x27✅ \x27 + message;\\n                setTimeout(function() \x7b\\n                    var areaEl \x3d document.getElementById(\x27queryStatusArea\x27);\\n                    if (areaEl) areaEl.style.display \x3d \x27none\x27;\\n                \x7d, 3000);\\n                break;\\n            case \x27error\x27:\\n                card.className \x3d \x27query-status-card error\x27;\\n                card.innerHTML \x3d \x27❌ \x27 + message;\\n                break;\\n            case \x27warning\x27:\\n                card.className \x3d \x27query-status-card warning\x27;\\n                card.innerHTML \x3d \x27⚠️ \x27 + message;\\n                break;\\n            default:\\n                card.className \x3d \x27query-status-card\x27;\\n                card.innerHTML \x3d message;\\n        \x7d\\n    \x7d\\n    \\n    function hideQueryStatus() \x7b\\n        var area \x3d document.getElementById(\x27queryStatusArea\x27);\\n        if (area) area.style.display \x3d \x27none\x27;\\n    \x7d\\n    \\n    function setInputsEnabled(enabled) \x7b\\n        var amountInput \x3d document.getElementById(\x27userAmount\x27);\\n        var remarkInput \x3d document.getElementById(\x27userRemark\x27);\\n        if (enabled) \x7b\\n            amountInput.disabled \x3d false;\\n            remarkInput.disabled \x3d false;\\n        \x7d else \x7b\\n            amountInput.disabled \x3d true;\\n            remarkInput.disabled \x3d true;\\n            amountInput.value \x3d \x27\x27;\\n        \x7d\\n    \x7d\\n\\n    function enableHistoryButton() \x7b\\n        var btn \x3d document.getElementById(\x27userHistoryBtn\x27);\\n        btn.disabled \x3d false;\\n        btn.style.background \x3d \x27#7c3aed\x27;\\n        btn.style.opacity \x3d \x271\x27;\\n        btn.style.cursor \x3d \x27pointer\x27;\\n    \x7d\\n\\n    function disableHistoryButton() \x7b\\n        var btn \x3d document.getElementById(\x27userHistoryBtn\x27);\\n        btn.disabled \x3d true;\\n        btn.style.background \x3d \x27#94a3b8\x27;\\n        btn.style.opacity \x3d \x270.6\x27;\\n        btn.style.cursor \x3d \x27not-allowed\x27;\\n    \x7d\\n\\n    \\n    \\n    \\n    function closeHistory() \x7b\\n        document.getElementById(\x27historyResultArea\x27).style.display \x3d \x27none\x27;\\n        \\n        \\n        if (currentUser) \x7b\\n            var memberInfo \x3d document.getElementById(\x27userMemberInfo\x27);\\n            if (memberInfo) \x7b\\n                memberInfo.style.display \x3d \x27block\x27;\\n            \x7d\\n        \x7d\\n        \\n        \\n        enableHistoryButton();\\n    \x7d\\n\\n    \\n    \\n    \\n    function queryMember() \x7b\\n        var no \x3d document.getElementById(\x27userMemberNo\x27).value.trim();\\n        if (!no) \x7b\\n            showSuccessModal(\x27⚠️ 請輸入會員編號\x27);\\n            return;\\n        \x7d\\n        if (isQuerying) return;\\n        isQuerying \x3d true;\\n        \\n        setInputsEnabled(false);\\n        document.getElementById(\x27userUploadBtn\x27).disabled \x3d true;\\n        document.getElementById(\x27userMemberInfo\x27).style.display \x3d \x27none\x27;\\n        document.getElementById(\x27userLimitWarning\x27).style.display \x3d \x27none\x27;\\n        document.getElementById(\x27historyResultArea\x27).style.display \x3d \x27none\x27;\\n        \\n        showQueryStatus(\x27loading\x27, \x27查詢會員編號：\x27 + no + \x27，請稍候...\x27);\\n        \\n        google.script.run\\n            .withSuccessHandler(function(r) \x7b\\n                isQuerying \x3d false;\\n                if (r.success) \x7b\\n                    currentUser \x3d r;\\n                    document.getElementById(\x27userMemberInfo\x27).style.display \x3d \x27block\x27;\\n                    document.getElementById(\x27showMemberName\x27).innerText \x3d r.name;\\n                    var cnt \x3d r.uploadInfo.uploadedCount;\\n                    document.getElementById(\x27uploadCountSpan\x27).innerText \x3d cnt;\\n                    \\n                    var monthlyTotal \x3d 0;\\n                    if (r.uploadInfo.history \x26\x26 r.uploadInfo.history.length) \x7b\\n                        for (var i \x3d 0; i \x3c r.uploadInfo.history.length; i++) \x7b\\n                            monthlyTotal +\x3d r.uploadInfo.history\x5bi\x5d.amount;\\n                        \x7d\\n                    \x7d\\n                    r.uploadInfo.monthlyTotal \x3d monthlyTotal;\\n                    currentUser \x3d r;\\n\\n                    var html \x3d \x27\x3cdiv\x3e\x3cstrong\x3e📋 歷史上傳：\x3c\\\/strong\x3e\x3c\\\/div\x3e\x27;\\n                    if (r.uploadInfo.history \x26\x26 r.uploadInfo.history.length) \x7b\\n                        for (var i \x3d 0; i \x3c r.uploadInfo.history.length; i++) \x7b\\n                            var h \x3d r.uploadInfo.history\x5bi\x5d;\\n                            var timeStr \x3d h.date ? h.date : \x27時間未記錄\x27;\\n                            html +\x3d \x27\x3cdiv class\x3d\\\x22history-item\\\x22\x3e\x27 +\\n                                        \x27\x3cspan\x3e📌 第 \x27 + h.number + \x27 次：數字 \x27 + h.amount.toLocaleString() + \x27\x3c\\\/span\x3e\x27 +\\n                                        \x27\x3cspan class\x3d\\\x22history-time\\\x22\x3e🕘 \x27 + timeStr + \x27\x3c\\\/span\x3e\x27 +\\n                                    \x27\x3c\\\/div\x3e\x27;\\n                        \x7d\\n                    \x7d else \x7b \\n                        html +\x3d \x27\x3cdiv\x3e無紀錄\x3c\\\/div\x3e\x27; \\n                    \x7d\\n                    \\n                    var totalHtml \x3d \x27\x3cdiv style\x3d\\\x22background:#f97316; color:white; padding:14px 18px; border-radius:35px; margin-top:15px; margin-bottom:15px; text-align:center; font-weight:700; font-size:16px;\\\x22\x3e📊 當月累計總額：\x27 + monthlyTotal.toLocaleString() + \x27\x3c\\\/div\x3e\x27;\\n                    document.getElementById(\x27historyArea\x27).innerHTML \x3d totalHtml + html;\\n                    \\n                    var full \x3d cnt \x3e\x3d 5;\\n                    var isDisabled \x3d r.status \x26\x26 r.status.includes(\x27停用\x27);\\n                    \\n                    if (isDisabled) \x7b\\n                        document.getElementById(\x27userLimitWarning\x27).style.display \x3d \x27block\x27;\\n                        document.getElementById(\x27userLimitWarning\x27).innerHTML \x3d \x27⚠️ 該會員已停用，無法上傳！\x27;\\n                        document.getElementById(\x27userUploadBtn\x27).disabled \x3d true;\\n                        setInputsEnabled(false);\\n                        showQueryStatus(\x27error\x27, \x27會員已停用，無法上傳數字\x27);\\n                        showSuccessModal(\x27⚠️ 會員已停用，無法上傳數字\x27);\\n                        disableHistoryButton();\\n                    \x7d else if (full) \x7b\\n                        document.getElementById(\x27userLimitWarning\x27).style.display \x3d \x27block\x27;\\n                        document.getElementById(\x27userLimitWarning\x27).innerHTML \x3d \x27⚠️ 本月已達5次上傳上限！\x27;\\n                        document.getElementById(\x27userUploadBtn\x27).disabled \x3d true;\\n                        setInputsEnabled(false);\\n                        showQueryStatus(\x27warning\x27, \x27本月已達5次上傳上限，無法繼續上傳\x27);\\n                        showSuccessModal(\x27⚠️ 本月已達5次上傳上限，無法繼續上傳\x27);\\n                        enableHistoryButton();\\n                    \x7d else \x7b\\n                        document.getElementById(\x27userLimitWarning\x27).style.display \x3d \x27none\x27;\\n                        document.getElementById(\x27userUploadBtn\x27).disabled \x3d false;\\n                        setInputsEnabled(true);\\n                        showQueryStatus(\x27success\x27, \x27會員驗證成功！姓名：\x27 + r.name + \x27，剩餘上傳次數：\x27 + (5 - cnt));\\n                        showSuccessModal(\x27✅ 會員驗證成功！\\\\n\\\\n姓名：\x27 + r.name + \x27\\\\n剩餘上傳次數：\x27 + (5 - cnt) + \x27\\\\n請輸入數字後點擊「確認上傳」\x27);\\n                        enableHistoryButton();\\n                    \x7d\\n                \x7d else \x7b\\n                    currentUser \x3d null;\\n                    document.getElementById(\x27userMemberInfo\x27).style.display \x3d \x27none\x27;\\n                    document.getElementById(\x27userUploadBtn\x27).disabled \x3d true;\\n                    setInputsEnabled(false);\\n                    showQueryStatus(\x27error\x27, r.message);\\n                    showSuccessModal(\x27❌ \x27 + r.message);\\n                    disableHistoryButton();\\n                \x7d\\n            \x7d)\\n            .withFailureHandler(function(err) \x7b\\n                isQuerying \x3d false;\\n                currentUser \x3d null;\\n                document.getElementById(\x27userMemberInfo\x27).style.display \x3d \x27none\x27;\\n                document.getElementById(\x27userUploadBtn\x27).disabled \x3d true;\\n                setInputsEnabled(false);\\n                showQueryStatus(\x27error\x27, \x27查詢失敗：\x27 + err.message);\\n                showSuccessModal(\x27❌ 查詢失敗：\x27 + err.message);\\n                disableHistoryButton();\\n            \x7d)\\n            .getMemberInfoByNo(no);\\n    \x7d\\n\\n    \\n    \\n    \\n    function convertToHistoryFormat(r) \x7b\\n        var records \x3d \x5b\x5d;\\n        var monthlySummary \x3d \x7b\x7d;\\n        var yearlySummary \x3d \x7b\x7d;\\n        var totalAmount \x3d 0;\\n        \\n        var history \x3d r.uploadInfo \x26\x26 r.uploadInfo.history ? r.uploadInfo.history : \x5b\x5d;\\n        \\n        console.log(\x27📊 原始歷史資料：\x27, history);\\n        \\n        for (var i \x3d 0; i \x3c history.length; i++) \x7b\\n            var h \x3d history\x5bi\x5d;\\n            \\n            \\n            var year \x3d 2026;\\n            var month \x3d 1;\\n            var dateObj \x3d null;\\n            \\n            if (h.date) \x7b\\n                var dateStr \x3d String(h.date);\\n                console.log(\x27🔍 解析日期：\x27, dateStr);\\n                \\n                \\n                var match \x3d dateStr.match(\/(\\\\d\x7b4\x7d)\x5b\\\\\/\\\\-\x5d(\\\\d\x7b1,2\x7d)\x5b\\\\\/\\\\-\x5d(\\\\d\x7b1,2\x7d)\/);\\n                if (match) \x7b\\n                    year \x3d parseInt(match\x5b1\x5d);\\n                    month \x3d parseInt(match\x5b2\x5d);\\n                    console.log(\x27✅ 正則匹配成功：\x27, year, month);\\n                \x7d else \x7b\\n                    \\n                    try \x7b\\n                        var parsedDate \x3d new Date(dateStr);\\n                        if (!isNaN(parsedDate.getTime())) \x7b\\n                            year \x3d parsedDate.getFullYear();\\n                            month \x3d parsedDate.getMonth() + 1;\\n                            console.log(\x27✅ new Date 解析成功：\x27, year, month);\\n                        \x7d else \x7b\\n                            console.log(\x27❌ new Date 解析失敗\x27);\\n                        \x7d\\n                    \x7d catch(e) \x7b\\n                        console.log(\x27❌ new Date 拋出錯誤：\x27, e);\\n                    \x7d\\n                \x7d\\n            \x7d else \x7b\\n                console.log(\x27⚠️ h.date 為空或 undefined\x27);\\n            \x7d\\n            \\n            var record \x3d \x7b\\n                year: year,\\n                month: month,\\n                amount: h.amount || 0,\\n                date: h.date || null,\\n                index: h.number || (i + 1)\\n            \x7d;\\n            records.push(record);\\n            \\n            totalAmount +\x3d record.amount;\\n            var monthKey \x3d record.year + \x27-\x27 + String(record.month).padStart(2, \x270\x27);\\n            monthlySummary\x5bmonthKey\x5d \x3d (monthlySummary\x5bmonthKey\x5d || 0) + record.amount;\\n            yearlySummary\x5brecord.year\x5d \x3d (yearlySummary\x5brecord.year\x5d || 0) + record.amount;\\n            \\n            console.log(\x27📝 紀錄 #\x27 + (i+1) + \x27：\x27, record);\\n        \x7d\\n        \\n        console.log(\x27📊 轉換結果：\x27, \x7b\\n            recordCount: records.length,\\n            yearlySummary: yearlySummary,\\n            monthlySummary: monthlySummary,\\n            records: records\\n        \x7d);\\n        \\n        return \x7b\\n            recordCount: records.length,\\n            yearlySummary: yearlySummary,\\n            monthlySummary: monthlySummary,\\n            records: records,\\n            memberName: r.name || \x27\x27,\\n            memberNo: r.no || \x27\x27\\n        \x7d;\\n    \x7d\\n\\n\\n        \\n        \\n        \\n        function queryMemberHistory() \x7b\\n            var no \x3d document.getElementById(\x27userMemberNo\x27).value.trim();\\n            if (!no) \x7b\\n                showSuccessModal(\x27⚠️ 請輸入會員編號\x27);\\n                return;\\n            \x7d\\n            \\n            if (!currentUser) \x7b\\n                showSuccessModal(\x27⚠️ 請先點擊「🔍 查詢會員」\x27);\\n                return;\\n            \x7d\\n            \\n            if (isQuerying) return;\\n            isQuerying \x3d true;\\n            \\n            \\n            document.getElementById(\x27userMemberInfo\x27).style.display \x3d \x27none\x27;\\n            \\n            \\n            var existingLoading \x3d document.getElementById(\x27customLoadingOverlay\x27);\\n            if (existingLoading) existingLoading.remove();\\n            \\n            var loadingOverlay \x3d document.createElement(\x27div\x27);\\n            loadingOverlay.id \x3d \x27customLoadingOverlay\x27;\\n            loadingOverlay.style.cssText \x3d \x27position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); display:flex; align-items:center; justify-content:center; z-index:99999; backdrop-filter:blur(4px);\x27;\\n            loadingOverlay.innerHTML \x3d `\\n                \x3cdiv style\x3d\\\x22background:white; border-radius:24px; padding:30px 40px; text-align:center; box-shadow:0 20px 60px rgba(0,0,0,0.3); min-width:280px;\\\x22\x3e\\n                    \x3cdiv style\x3d\\\x22font-size:48px; margin-bottom:16px;\\\x22\x3e⏳\x3c\\\/div\x3e\\n                    \x3cdiv style\x3d\\\x22font-size:18px; font-weight:600; color:#1e293b; margin-bottom:8px;\\\x22\x3e查詢歷史紀錄中...\x3c\\\/div\x3e\\n                    \x3cdiv style\x3d\\\x22font-size:14px; color:#94a3b8;\\\x22\x3e請稍候，資料較多可能需要幾秒鐘\x3c\\\/div\x3e\\n                    \x3cdiv style\x3d\\\x22margin-top:16px; display:flex; justify-content:center; gap:8px;\\\x22\x3e\\n                        \x3cdiv style\x3d\\\x22width:12px; height:12px; background:#7c3aed; border-radius:50%; animation:bounceDot 1.2s ease-in-out infinite;\\\x22\x3e\x3c\\\/div\x3e\\n                        \x3cdiv style\x3d\\\x22width:12px; height:12px; background:#7c3aed; border-radius:50%; animation:bounceDot 1.2s ease-in-out infinite 0.2s;\\\x22\x3e\x3c\\\/div\x3e\\n                        \x3cdiv style\x3d\\\x22width:12px; height:12px; background:#7c3aed; border-radius:50%; animation:bounceDot 1.2s ease-in-out infinite 0.4s;\\\x22\x3e\x3c\\\/div\x3e\\n                    \x3c\\\/div\x3e\\n                    \x3cstyle\x3e\\n                        @keyframes bounceDot \x7b\\n                            0%, 80%, 100% \x7b transform: scale(0.6); opacity: 0.4; \x7d\\n                            40% \x7b transform: scale(1); opacity: 1; \x7d\\n                        \x7d\\n                    \x3c\\\/style\x3e\\n                \x3c\\\/div\x3e\\n            `;\\n            document.body.appendChild(loadingOverlay);\\n            \\n            \/\/ 🔥 禁用按鈕防止重複點擊\\n            var historyBtn \x3d document.getElementById(\x27userHistoryBtn\x27);\\n            if (historyBtn) \x7b\\n                historyBtn.disabled \x3d true;\\n                historyBtn.style.opacity \x3d \x270.6\x27;\\n                historyBtn.style.cursor \x3d \x27not-allowed\x27;\\n            \x7d\\n            \\n            \\n            var timeoutId \x3d setTimeout(function() \x7b\\n                if (isQuerying) \x7b\\n                    isQuerying \x3d false;\\n                    var overlay \x3d document.getElementById(\x27customLoadingOverlay\x27);\\n                    if (overlay) overlay.remove();\\n                    if (historyBtn) \x7b\\n                        historyBtn.disabled \x3d false;\\n                        historyBtn.style.opacity \x3d \x271\x27;\\n                        historyBtn.style.cursor \x3d \x27pointer\x27;\\n                    \x7d\\n                    showSuccessModal(\x27⏰ 查詢逾時，請稍後再試\x27);\\n                \x7d\\n            \x7d, 60000);\\n            \\n            google.script.run\\n                .withSuccessHandler(function(r) \x7b\\n                    clearTimeout(timeoutId);\\n                    isQuerying \x3d false;\\n                    \\n                    \\n                    var overlay \x3d document.getElementById(\x27customLoadingOverlay\x27);\\n                    if (overlay) overlay.remove();\\n                    \\n                    \\n                    if (historyBtn) \x7b\\n                        historyBtn.disabled \x3d false;\\n                        historyBtn.style.opacity \x3d \x271\x27;\\n                        historyBtn.style.cursor \x3d \x27pointer\x27;\\n                    \x7d\\n                    \\n                    console.log(\x27📥 getMemberAllMonthsUpload 回傳：\x27, r);\\n                    \\n                    if (!r || !r.success) \x7b\\n                        showEmptyHistory(\x27📭 查無歷史紀錄\x27);\\n                        return;\\n                    \x7d\\n                    \\n                    var records \x3d r.records || \x5b\x5d;\\n                    \\n                    if (records.length \x3d\x3d\x3d 0) \x7b\\n                        showEmptyHistory(\x27📭 該會員尚無歷史上傳紀錄\x27);\\n                        return;\\n                    \x7d\\n                    \\n                    \\n                    var monthlySummary \x3d r.monthlySummary || \x7b\x7d;\\n                    var yearlySummary \x3d r.yearlySummary || \x7b\x7d;\\n                    var formattedRecords \x3d \x5b\x5d;\\n\\n                    for (var i \x3d 0; i \x3c records.length; i++) \x7b\\n                        var rec \x3d records\x5bi\x5d;\\n                        formattedRecords.push(\x7b\\n                            year: rec.year,\\n                            month: rec.month,\\n                            amount: rec.amount,\\n                            date: rec.date || null,\\n                            index: rec.number || (i + 1),\\n                            remark: rec.remark || \x27\x27\\n                        \x7d);\\n                    \x7d\\n                    \\n                    var data \x3d \x7b\\n                        recordCount: records.length,\\n                        yearlySummary: yearlySummary,\\n                        monthlySummary: monthlySummary,\\n                        records: formattedRecords,\\n                        memberName: r.name || currentUser.name || \x27\x27,\\n                        memberNo: no\\n                    \x7d;\\n                    \\n                    displayHistoryResult(data);\\n                    showQueryStatus(\x27success\x27, \x27✅ 查詢成功！共 \x27 + data.recordCount + \x27 筆紀錄\x27);\\n                \x7d)\\n                .withFailureHandler(function(err) \x7b\\n                    clearTimeout(timeoutId);\\n                    isQuerying \x3d false;\\n                    \\n                    \\n                    var overlay \x3d document.getElementById(\x27customLoadingOverlay\x27);\\n                    if (overlay) overlay.remove();\\n                    \\n                    \\n                    if (historyBtn) \x7b\\n                        historyBtn.disabled \x3d false;\\n                        historyBtn.style.opacity \x3d \x271\x27;\\n                        historyBtn.style.cursor \x3d \x27pointer\x27;\\n                    \x7d\\n                    \\n                    console.error(\x27❌ 查詢錯誤：\x27, err);\\n                    showQueryStatus(\x27error\x27, \x27❌ 查詢失敗：\x27 + err.message);\\n                    showSuccessModal(\x27❌ 查詢失敗：\x27 + err.message);\\n                \x7d)\\n                .getMemberAllMonthsUpload(no);\\n        \x7d\\n\\n        \\n        \\n        \\n        function convertLeaderRecordsToHistory(leaderData) \x7b\\n            var records \x3d \x5b\x5d;\\n            var monthlySummary \x3d \x7b\x7d;\\n            var yearlySummary \x3d \x7b\x7d;\\n            var totalAmount \x3d 0;\\n            \\n            \\n            if (leaderData.records \x26\x26 leaderData.records.length \x3e 0) \x7b\\n                for (var i \x3d 0; i \x3c leaderData.records.length; i++) \x7b\\n                    var r \x3d leaderData.records\x5bi\x5d;\\n                    var record \x3d \x7b\\n                        year: r.year || 2026,\\n                        month: r.month || 1,\\n                        amount: r.amount || 0,\\n                        date: r.date || null,\\n                        index: r.number || (i + 1)\\n                    \x7d;\\n                    records.push(record);\\n                    \\n                    totalAmount +\x3d record.amount;\\n                    var monthKey \x3d record.year + \x27-\x27 + String(record.month).padStart(2, \x270\x27);\\n                    monthlySummary\x5bmonthKey\x5d \x3d (monthlySummary\x5bmonthKey\x5d || 0) + record.amount;\\n                    yearlySummary\x5brecord.year\x5d \x3d (yearlySummary\x5brecord.year\x5d || 0) + record.amount;\\n                \x7d\\n            \x7d\\n            \\n            return \x7b\\n                memberNo: leaderData.memberNo || \x27\x27,\\n                memberName: leaderData.memberName || \x27\x27,\\n                group: leaderData.group || \x27\x27,\\n                totalAmount: totalAmount,\\n                recordCount: records.length,\\n                monthlySummary: monthlySummary,\\n                yearlySummary: yearlySummary,\\n                records: records\\n            \x7d;\\n        \x7d\\n\\n    \\n    \\n    \\n    function showEmptyHistory(message) \x7b\\n        var area \x3d document.getElementById(\x27historyResultArea\x27);\\n        area.style.display \x3d \x27block\x27;\\n        document.getElementById(\x27historyRecordCount\x27).textContent \x3d \x27📊 0 筆\x27;\\n        document.getElementById(\x27yearlyTableContainer\x27).innerHTML \x3d \x27\x3cdiv style\x3d\\\x22text-align:center;padding:20px;color:#94a3b8;\\\x22\x3e📭 尚無上傳紀錄\x3c\\\/div\x3e\x27;\\n        document.getElementById(\x27monthSliderWrapper\x27).innerHTML \x3d \x27\x3cdiv style\x3d\\\x22text-align:center;padding:20px;color:#94a3b8;\\\x22\x3e📭 尚無上傳紀錄\x3c\\\/div\x3e\x27;\\n        document.getElementById(\x27totalMonthsCount\x27).textContent \x3d \x270\x27;\\n        document.getElementById(\x27yearJumpButtons\x27).innerHTML \x3d \x27\x27;\\n        showQueryStatus(\x27warning\x27, \x27⚠️ \x27 + message);\\n        showSuccessModal(message);\\n    \x7d\\n\\n    \\n    \\n    \\n    function displayHistoryResult(data) \x7b\\n        console.log(\x27📊 顯示歷史資料：\x27, data);\\n        \\n        var area \x3d document.getElementById(\x27historyResultArea\x27);\\n        area.style.display \x3d \x27block\x27;\\n        \\n        var records \x3d data.records || \x5b\x5d;\\n        var monthlySummary \x3d data.monthlySummary || \x7b\x7d;\\n        var yearlySummary \x3d data.yearlySummary || \x7b\x7d;\\n        var recordCount \x3d data.recordCount || records.length;\\n        \\n        document.getElementById(\x27historyRecordCount\x27).textContent \x3d \x27📊 \x27 + recordCount + \x27 筆\x27;\\n        \\n        \\n        \\n        \\n        var years \x3d Object.keys(yearlySummary).sort();\\n        var tableHtml \x3d \x27\x27;\\n        \\n        if (years.length \x3e 0) \x7b\\n            tableHtml \x3d \x27\x3cdiv style\x3d\\\x22overflow-x: auto; font-size: 13px;\\\x22\x3e\x27;\\n            tableHtml +\x3d \x27\x3ctable class\x3d\\\x22year-table\\\x22\x3e\x27;\\n            tableHtml +\x3d \x27\x3cthead\x3e\x3ctr\x3e\x3cth\x3e年度\x3c\\\/th\x3e\x27;\\n            for (var m \x3d 1; m \x3c\x3d 12; m++) \x7b\\n                tableHtml +\x3d \x27\x3cth\x3e\x27 + m + \x27\x3c\\\/th\x3e\x27;\\n            \x7d\\n            tableHtml +\x3d \x27\x3cth\x3e合計\x3c\\\/th\x3e\x3c\\\/tr\x3e\x3c\\\/thead\x3e\x3ctbody\x3e\x27;\\n            \\n            for (var y \x3d 0; y \x3c years.length; y++) \x7b\\n                var year \x3d years\x5by\x5d;\\n                var yearTotal \x3d yearlySummary\x5byear\x5d || 0;\\n                tableHtml +\x3d \x27\x3ctr\x3e\x3ctd style\x3d\\\x22font-weight:700;background:#f5f3ff;\\\x22\x3e\x27 + year + \x27\x3c\\\/td\x3e\x27;\\n                for (var m \x3d 1; m \x3c\x3d 12; m++) \x7b\\n                    var key \x3d year + \x27-\x27 + String(m).padStart(2, \x270\x27);\\n                    var amount \x3d monthlySummary\x5bkey\x5d || 0;\\n                    \\n                    var monthCount \x3d 0;\\n                    for (var i \x3d 0; i \x3c records.length; i++) \x7b\\n                        if (records\x5bi\x5d.year \x3d\x3d\x3d parseInt(year) \x26\x26 records\x5bi\x5d.month \x3d\x3d\x3d m) \x7b\\n                            monthCount++;\\n                        \x7d\\n                    \x7d\\n                    \\n                    var displayText \x3d amount \x3e 0 ? amount.toLocaleString() : \x27-\x27;\\n                    if (monthCount \x3e 0) \x7b\\n                        displayText +\x3d \x27 \x3cspan class\x3d\\\x22upload-count-badge\\\x22\x3e×\x27 + monthCount + \x27\x3c\\\/span\x3e\x27;\\n                    \x7d\\n                    \\n                    tableHtml +\x3d \x27\x3ctd style\x3d\\\x22padding:8px 4px; text-align:center; border-bottom:1px solid #f1f5f9; \x27 + \\n                        (amount \x3e 0 ? \x27font-weight:600; color:#1e293b;\x27 : \x27color:#cbd5e1;\x27) + \x27\\\x22\x3e\x27 + \\n                        displayText + \\n                        \x27\x3c\\\/td\x3e\x27;\\n                \x7d\\n                tableHtml +\x3d \x27\x3ctd class\x3d\\\x22year-total\\\x22\x3e\x27 + \\n                    (yearTotal \x3e 0 ? yearTotal.toLocaleString() : \x270\x27) + \\n                    \x27\x3c\\\/td\x3e\x27;\\n                tableHtml +\x3d \x27\x3c\\\/tr\x3e\x27;\\n            \x7d\\n            tableHtml +\x3d \x27\x3c\\\/tbody\x3e\x3c\\\/table\x3e\x3c\\\/div\x3e\x27;\\n        \x7d else \x7b\\n            tableHtml \x3d \x27\x3cdiv style\x3d\\\x22text-align:center;padding:12px;color:#94a3b8;font-size:14px;\\\x22\x3e📭 尚無上傳紀錄\x3c\\\/div\x3e\x27;\\n        \x7d\\n        document.getElementById(\x27yearlyTableContainer\x27).innerHTML \x3d tableHtml;\\n        \\n        \\n        \\n        \\n        var yearJumpHtml \x3d \x27\x27;\\n        var yearsWithData \x3d Object.keys(yearlySummary).sort();\\n\\n        if (yearsWithData.length \x3e 0) \x7b\\n            for (var y \x3d 0; y \x3c yearsWithData.length; y++) \x7b\\n                var year \x3d yearsWithData\x5by\x5d;\\n                yearJumpHtml +\x3d \x27\x3cbutton class\x3d\\\x22year-jump-btn\\\x22 data-year\x3d\\\x22\x27 + year + \x27\\\x22\x3e\x27 + \\n                    year + \x27年\x27 + \\n                    \x27\x3c\\\/button\x3e\x27;\\n            \x7d\\n        \x7d\\n        document.getElementById(\x27yearJumpButtons\x27).innerHTML \x3d yearJumpHtml;\\n        \\n        \\n        \\n        \\n        var sliderWrapper \x3d document.getElementById(\x27monthSliderWrapper\x27);\\n        var sliderHtml \x3d \x27\x27;\\n        var monthNames \x3d \x5b\x271月\x27, \x272月\x27, \x273月\x27, \x274月\x27, \x275月\x27, \x276月\x27, \x277月\x27, \x278月\x27, \x279月\x27, \x2710月\x27, \x2711月\x27, \x2712月\x27\x5d;\\n        var currentDate \x3d new Date();\\n        var currentYear \x3d currentDate.getFullYear();\\n        var currentMonth \x3d currentDate.getMonth() + 1;\\n        \\n        \\n        var monthsWithData \x3d \x5b\x5d;\\n        var seen \x3d \x7b\x7d;\\n        \\n        for (var i \x3d 0; i \x3c records.length; i++) \x7b\\n            var r \x3d records\x5bi\x5d;\\n            var key \x3d r.year + \x27-\x27 + String(r.month).padStart(2, \x270\x27);\\n            if (!seen\x5bkey\x5d) \x7b\\n                seen\x5bkey\x5d \x3d true;\\n                monthsWithData.push(\x7b year: r.year, month: r.month \x7d);\\n            \x7d\\n        \x7d\\n        \\n        \\n        monthsWithData.sort(function(a, b) \x7b\\n            if (a.year !\x3d\x3d b.year) return a.year - b.year;\\n            return a.month - b.month;\\n        \x7d);\\n        \\n        document.getElementById(\x27totalMonthsCount\x27).textContent \x3d monthsWithData.length;\\n        \\n        if (monthsWithData.length \x3d\x3d\x3d 0) \x7b\\n            sliderHtml \x3d \x27\x3cdiv style\x3d\\\x22text-align:center;padding:20px;color:#94a3b8;\\\x22\x3e📭 尚無上傳紀錄\x3c\\\/div\x3e\x27;\\n        \x7d else \x7b\\n            for (var idx \x3d 0; idx \x3c monthsWithData.length; idx++) \x7b\\n                var y \x3d monthsWithData\x5bidx\x5d.year;\\n                var m \x3d monthsWithData\x5bidx\x5d.month;\\n                var key \x3d y + \x27-\x27 + String(m).padStart(2, \x270\x27);\\n                var amount \x3d monthlySummary\x5bkey\x5d || 0;\\n                var isCurrent \x3d (y \x3d\x3d\x3d currentYear \x26\x26 m \x3d\x3d\x3d currentMonth);\\n                \\n                var monthRecords \x3d \x5b\x5d;\\n                for (var i \x3d 0; i \x3c records.length; i++) \x7b\\n                    var r \x3d records\x5bi\x5d;\\n                    if (r.year \x3d\x3d\x3d y \x26\x26 r.month \x3d\x3d\x3d m) \x7b\\n                        monthRecords.push(r);\\n                    \x7d\\n                \x7d\\n                monthRecords.sort(function(a, b) \x7b return a.index - b.index; \x7d);\\n                \\n                sliderHtml +\x3d \x27\x3cdiv class\x3d\\\x22month-card\\\x22 data-year\x3d\\\x22\x27 + y + \x27\\\x22 data-month\x3d\\\x22\x27 + m + \x27\\\x22 style\x3d\\\x22\x27 + \\n                    (isCurrent ? \x27border-color: #f97316; background: #fff7ed;\x27 : \x27\x27) + \x27\\\x22\x3e\x27;\\n                sliderHtml +\x3d \x27\x3cdiv class\x3d\\\x22month-header\\\x22\x3e\x27;\\n                sliderHtml +\x3d \x27\x3cspan class\x3d\\\x22month-title\\\x22\x3e\x27 + y + \x27年 \x27 + monthNames\x5bm-1\x5d + (isCurrent ? \x27 ⭐\x27 : \x27\x27) + \x27\x3c\\\/span\x3e\x27;\\n                sliderHtml +\x3d \x27\x3cspan class\x3d\\\x22month-total\\\x22\x3e\x27 + (amount \x3e 0 ? amount.toLocaleString() : \x270\x27) + \x27\x3c\\\/span\x3e\x27;\\n                sliderHtml +\x3d \x27\x3c\\\/div\x3e\x27;\\n                \\n                if (monthRecords.length \x3e 0) \x7b\\n                    for (var ri \x3d 0; ri \x3c monthRecords.length; ri++) \x7b\\n                        var r \x3d monthRecords\x5bri\x5d;\\n                        var dateStr \x3d r.date || \x27日期未記錄\x27;\\n                        \\n                        sliderHtml +\x3d \x27\x3cdiv class\x3d\\\x22record-item\\\x22\x3e\x27;\\n                        sliderHtml +\x3d \x27\x3cspan class\x3d\\\x22record-index\\\x22\x3e📌 第\x27 + r.index + \x27次\x3c\\\/span\x3e\x27;\\n                        sliderHtml +\x3d \x27\x3cspan class\x3d\\\x22record-amount\\\x22\x3e\x27 + r.amount.toLocaleString() + \x27\x3c\\\/span\x3e\x27;\\n                        sliderHtml +\x3d \x27\x3cspan class\x3d\\\x22record-time\\\x22\x3e\x27 + dateStr + \x27\x3c\\\/span\x3e\x27;\\n                        if (r.remark \x26\x26 r.remark.trim() !\x3d\x3d \x27\x27) \x7b\\n                            sliderHtml +\x3d \x27\x3cspan class\x3d\\\x22record-remark\\\x22\x3e💬 \x27 + r.remark + \x27\x3c\\\/span\x3e\x27;\\n                        \x7d\\n                        sliderHtml +\x3d \x27\x3c\\\/div\x3e\x27;\\n                    \x7d\\n                \x7d else \x7b\\n                    sliderHtml +\x3d \x27\x3cdiv class\x3d\\\x22no-record\\\x22\x3e📭 本月無上傳紀錄\x3c\\\/div\x3e\x27;\\n                \x7d\\n                sliderHtml +\x3d \x27\x3c\\\/div\x3e\x27;\\n            \x7d\\n        \x7d\\n        sliderWrapper.innerHTML \x3d sliderHtml;\\n        \\n        \\n        \\n        \\n        function updateActiveYear() \x7b\\n            var cards \x3d sliderWrapper.querySelectorAll(\x27.month-card\x27);\\n            if (cards.length \x3d\x3d\x3d 0) return;\\n            \\n            var wrapperWidth \x3d sliderWrapper.clientWidth;\\n            var scrollLeft \x3d sliderWrapper.scrollLeft;\\n            var centerX \x3d scrollLeft + wrapperWidth \/ 2;\\n            var targetIndex \x3d 0;\\n            var minDistance \x3d Infinity;\\n            \\n            for (var i \x3d 0; i \x3c cards.length; i++) \x7b\\n                var card \x3d cards\x5bi\x5d;\\n                var cardLeft \x3d card.offsetLeft;\\n                var cardWidth \x3d card.offsetWidth;\\n                var cardCenter \x3d cardLeft + cardWidth \/ 2;\\n                var distance \x3d Math.abs(cardCenter - centerX);\\n                \\n                if (distance \x3c minDistance) \x7b\\n                    minDistance \x3d distance;\\n                    targetIndex \x3d i;\\n                \x7d\\n            \x7d\\n            \\n            if (targetIndex \x3c cards.length) \x7b\\n                var visibleYear \x3d parseInt(cards\x5btargetIndex\x5d.dataset.year);\\n                \\n                document.querySelectorAll(\x27.year-jump-btn\x27).forEach(function(btn) \x7b\\n                    btn.classList.remove(\x27active\x27);\\n                    if (parseInt(btn.dataset.year) \x3d\x3d\x3d visibleYear) \x7b\\n                        btn.classList.add(\x27active\x27);\\n                    \x7d\\n                \x7d);\\n            \x7d\\n        \x7d\\n        \\n        \\n        var scrollTimer \x3d null;\\n        sliderWrapper.addEventListener(\x27scroll\x27, function() \x7b\\n            if (scrollTimer) \x7b\\n                clearTimeout(scrollTimer);\\n            \x7d\\n            scrollTimer \x3d setTimeout(function() \x7b\\n                updateActiveYear();\\n                scrollTimer \x3d null;\\n            \x7d, 50);\\n        \x7d);\\n        \\n        \\n        sliderWrapper.addEventListener(\x27touchend\x27, function() \x7b\\n            setTimeout(updateActiveYear, 200);\\n        \x7d);\\n        \\n        \\n        sliderWrapper.addEventListener(\x27mouseup\x27, function() \x7b\\n            setTimeout(updateActiveYear, 100);\\n        \x7d);\\n        \\n        \\n        \\n        \\n        document.querySelectorAll(\x27.year-jump-btn\x27).forEach(function(btn) \x7b\\n            btn.addEventListener(\x27click\x27, function() \x7b\\n                var year \x3d parseInt(this.dataset.year);\\n                \\n                var cards \x3d sliderWrapper.querySelectorAll(\x27.month-card\x27);\\n                var cardWidth \x3d 280 + 12;\\n                for (var i \x3d 0; i \x3c cards.length; i++) \x7b\\n                    var cardYear \x3d parseInt(cards\x5bi\x5d.dataset.year);\\n                    if (cardYear \x3d\x3d\x3d year) \x7b\\n                        sliderWrapper.scrollLeft \x3d i * cardWidth - 20;\\n                        break;\\n                    \x7d\\n                \x7d\\n                \\n                document.querySelectorAll(\x27.year-jump-btn\x27).forEach(function(b) \x7b\\n                    b.classList.remove(\x27active\x27);\\n                \x7d);\\n                this.classList.add(\x27active\x27);\\n            \x7d);\\n        \x7d);\\n        \\n        \\n        \\n        \\n        setTimeout(function() \x7b\\n            var targetIndex \x3d -1;\\n            var cards \x3d sliderWrapper.querySelectorAll(\x27.month-card\x27);\\n            for (var i \x3d 0; i \x3c cards.length; i++) \x7b\\n                var y \x3d parseInt(cards\x5bi\x5d.dataset.year);\\n                var m \x3d parseInt(cards\x5bi\x5d.dataset.month);\\n                if (y \x3d\x3d\x3d currentYear \x26\x26 m \x3d\x3d\x3d currentMonth) \x7b\\n                    targetIndex \x3d i;\\n                    break;\\n                \x7d\\n            \x7d\\n            if (targetIndex \x3d\x3d\x3d -1 \x26\x26 cards.length \x3e 0) \x7b\\n                targetIndex \x3d 0;\\n            \x7d\\n            if (targetIndex !\x3d\x3d -1) \x7b\\n                var cardWidth \x3d 280 + 12;\\n                sliderWrapper.scrollLeft \x3d targetIndex * cardWidth - 20;\\n            \x7d\\n            \\n            setTimeout(updateActiveYear, 300);\\n        \x7d, 200);\\n    \x7d\\n\\n\\n\\n\\n\\n    function scrollToYear(year) \x7b\\n        var sliderWrapper \x3d document.getElementById(\x27monthSliderWrapper\x27);\\n        var cards \x3d sliderWrapper.querySelectorAll(\x27.month-card\x27);\\n        var cardWidth \x3d 280 + 12;\\n        \\n        for (var i \x3d 0; i \x3c cards.length; i++) \x7b\\n            var cardYear \x3d parseInt(cards\x5bi\x5d.dataset.year);\\n            if (cardYear \x3d\x3d\x3d year) \x7b\\n                sliderWrapper.scrollLeft \x3d i * cardWidth - 20;\\n                break;\\n            \x7d\\n        \x7d\\n    \x7d\\n\\n    \\n    \\n    \\n    function uploadAmount() \x7b\\n        if (!currentUser) \x7b\\n            showSuccessModal(\x27❌ 尚未驗證會員！請先點擊「🔍 查詢會員」\x27);\\n            return;\\n        \x7d\\n        \\n        var amountInput \x3d document.getElementById(\x27userAmount\x27);\\n        var remarkInput \x3d document.getElementById(\x27userRemark\x27);\\n        var amount \x3d parseFloat(amountInput.value);\\n        var remark \x3d remarkInput.value;\\n        var no \x3d document.getElementById(\x27userMemberNo\x27).value.trim();\\n        \\n        if (isNaN(amount) || amount \x3c\x3d 0) \x7b \\n            showSuccessModal(\x27⚠️ 請輸入有效的數字（大於0）\x27);\\n            return; \\n        \x7d\\n        \\n        if (currentUser.uploadInfo.uploadedCount \x3e\x3d 5) \x7b\\n            showSuccessModal(\x27⚠️ 本月已達5次上傳上限，無法再上傳\x27);\\n            return;\\n        \x7d\\n        \\n        if (currentUser.status \x26\x26 currentUser.status.includes(\x27停用\x27)) \x7b\\n            showSuccessModal(\x27⚠️ 會員已停用，無法上傳\x27);\\n            return;\\n        \x7d\\n        \\n        var currentTotal \x3d currentUser.uploadInfo.monthlyTotal || 0;\\n        var newTotal \x3d currentTotal + amount;\\n        var newCount \x3d currentUser.uploadInfo.uploadedCount + 1;\\n        \\n        currentUser.uploadInfo.history.push(\x7b\\n            number: newCount,\\n            amount: amount,\\n            date: new Date().toLocaleString()\\n        \x7d);\\n        currentUser.uploadInfo.uploadedCount \x3d newCount;\\n        currentUser.uploadInfo.monthlyTotal \x3d newTotal;\\n        \\n        var totalHtml \x3d \x27\x3cdiv style\x3d\\\x22background:#f97316; color:white; padding:14px 18px; border-radius:35px;margin-top:15px;margin-bottom:15px; text-align:center; font-weight:700; font-size:16px;\\\x22\x3e📊 當月累計總額：\x27 + newTotal.toLocaleString() + \x27\x3c\\\/div\x3e\x27;\\n        var historyHtml \x3d \x27\x3cdiv\x3e\x3cstrong\x3e📋 歷史上傳：\x3c\\\/strong\x3e\x3c\\\/div\x3e\x27;\\n        for (var i \x3d 0; i \x3c currentUser.uploadInfo.history.length; i++) \x7b\\n            var h \x3d currentUser.uploadInfo.history\x5bi\x5d;\\n            historyHtml +\x3d \x27\x3cdiv class\x3d\\\x22history-item\\\x22\x3e\x27 +\\n                                \x27\x3cspan\x3e📌 第 \x27 + h.number + \x27 次：數字 \x27 + h.amount.toLocaleString() + \x27\x3c\\\/span\x3e\x27 +\\n                                \x27\x3cspan class\x3d\\\x22history-time\\\x22\x3e🕘 \x27 + h.date + \x27\x3c\\\/span\x3e\x27 +\\n                            \x27\x3c\\\/div\x3e\x27;\\n        \x7d\\n        document.getElementById(\x27historyArea\x27).innerHTML \x3d totalHtml + historyHtml;\\n        document.getElementById(\x27uploadCountSpan\x27).innerText \x3d newCount;\\n        \\n        var full \x3d newCount \x3e\x3d 5;\\n        if (full) \x7b\\n            document.getElementById(\x27userLimitWarning\x27).style.display \x3d \x27block\x27;\\n            document.getElementById(\x27userLimitWarning\x27).innerHTML \x3d \x27⚠️ 本月已達5次上傳上限！\x27;\\n            document.getElementById(\x27userUploadBtn\x27).disabled \x3d true;\\n            setInputsEnabled(false);\\n        \x7d\\n        \\n        var remarkText \x3d remark \x26\x26 remark.trim() !\x3d\x3d \x27\x27 ? \x27\\\\n📝 備註：\x27 + remark : \x27\x27;\\n        showSuccessModal(\x27✅ 上傳成功！\\\\n🔢 編號：\x27 + no + \x27\\\\n👤 姓名：\x27 + currentUser.name + \x27\\\\n📌 第 \x27 + newCount + \x27 次上傳\\\\n💰 數字：\x27 + amount.toLocaleString() + \x27\\\\n📊 當月累計：\x27 + newTotal.toLocaleString() + remarkText);\\n        \\n        amountInput.value \x3d \x27\x27;\\n        var rInput \x3d document.getElementById(\x27userRemark\x27); \\n        if (rInput) rInput.value \x3d \x27\x27;\\n        \\n        google.script.run\\n            .withFailureHandler(function(err) \x7b\\n                showSuccessModal(\x27⚠️ 畫面已更新，但後端錯誤：\x27 + err.message + \x27，請聯絡管理員\x27);\\n            \x7d)\\n            .submitUserUpload(no, currentUser.name, amount, remark);\\n    \x7d\\n    \\n    \\n    \\n    \\n    var amountField \x3d document.getElementById(\x27userAmount\x27);\\n    if (amountField) \x7b\\n        amountField.addEventListener(\x27focus\x27, function() \x7b\\n            \\n            if (!currentUser) \x7b\\n                var no \x3d document.getElementById(\x27userMemberNo\x27).value.trim();\\n                if (no) \x7b\\n                    showSuccessModal(\x27🔍 尚未查詢，自動為您查詢會員...\x27);\\n                    queryMember();\\n                    this.blur();\\n                \x7d else \x7b\\n                    showSuccessModal(\x27⚠️ 請先輸入會員編號並點擊「查詢」\x27);\\n                    this.blur();\\n                \x7d\\n                return;\\n            \x7d\\n            \\n            \\n            var historyArea \x3d document.getElementById(\x27historyResultArea\x27);\\n            if (historyArea \x26\x26 historyArea.style.display \x3d\x3d\x3d \x27block\x27) \x7b\\n                historyArea.style.display \x3d \x27none\x27;\\n                \\n                \\n                var memberInfo \x3d document.getElementById(\x27userMemberInfo\x27);\\n                if (memberInfo) \x7b\\n                    memberInfo.style.display \x3d \x27block\x27;\\n                \x7d\\n            \x7d\\n        \x7d);\\n    \x7d\\n\\n    document.getElementById(\x27userCheckBtn\x27).onclick \x3d queryMember;\\n    document.getElementById(\x27userUploadBtn\x27).onclick \x3d uploadAmount;\\n\\n    var memberNoInput \x3d document.getElementById(\x27userMemberNo\x27);\\n    memberNoInput.addEventListener(\x27keypress\x27, function(e) \x7b\\n        if (e.key \x3d\x3d\x3d \x27Enter\x27) \x7b\\n            e.preventDefault();\\n            queryMember();\\n        \x7d\\n    \x7d);\\n\\n    memberNoInput.addEventListener(\x27input\x27, function() \x7b\\n        if (currentUser) \x7b\\n            currentUser \x3d null;\\n            document.getElementById(\x27userMemberInfo\x27).style.display \x3d \x27none\x27;\\n            document.getElementById(\x27userUploadBtn\x27).disabled \x3d true;\\n            document.getElementById(\x27userLimitWarning\x27).style.display \x3d \x27none\x27;\\n            setInputsEnabled(false);\\n            hideQueryStatus();\\n            disableHistoryButton();\\n        \x7d\\n    \x7d);\\n\\n   \\n\\n    \\n    disableHistoryButton();\\n\x3c\\\/script\x3e\\n\x3c\\\/body\x3e\\n\x3c\\\/html\x3e\x22,\x22ncc\x22:\x22\x7b\\\x22awhs\\\x22:true\x7d\x22\x7d", "", undefined, true , false  , "false", "https:\/\/n-65hr6nufvavzrcori3cp2m5pvuuwxchjnykofga-0lu-script.googleusercontent.com", "https:\/\/drive.google.com\/abuse?id\x3dAAMpA0Q7ANaEzXRry00KACGm5YFeCGpO5Mkx1b6aPMRV5IndQchK89BNUlAcbNbLtuqb45jTPRMguZ8aj_t8dZ874R_o1vAMiFGZQ-p-%3A0\x26docurl\x3dhttps%3A%2F%2Fscript.google.com%2Fmacros%2Fs%2FAKfycbxqdFwA4g3SftznJybl4N4dQIbCkO9UgAPF83mkox3MRuZHOQMycsz-xik8Vs7oEvTB%2Fexec");}
el.src = 'https:\/\/n-65hr6nufvavzrcori3cp2m5pvuuwxchjnykofga-0lu-script.googleusercontent.com\/userCodeAppPanel';
}());
</script>
</body>
</html>
