UNPKG

flexbiz-server

Version:

Flexible Server

572 lines (543 loc) 47 kB
const types=[{code:"String",ten:"String"},{code:"Number",ten:"Number"},{code:"Boolean",ten:"Boolean"},{code:"Date",ten:"Date"},{code:"DateTime",ten:"DateTime",type_data:"Date"},{code:"Time",ten:"Time",type_data:"Date"},{code:"Array",ten:"Array"},{code:"Mixed",ten:"Mixed",type_data:"Json"},{code:"File",ten:"Excel",type_data:"String"},{code:"Pdf",ten:"PDF",type_data:"String"},{code:"Image",ten:"Image",type_data:"String"}],buildJsonSchema=async function($entries_fields_validFields$$,$depth$$=0){if($depth$$> 5)return{};$entries_fields_validFields$$=$entries_fields_validFields$$.filter($f$$=>["ten_vt","ten_kh","ten_kho"].indexOf($f$$.name)>=0||$f$$.not_input!="true"&&$f$$.not_input!=1&&$f$$.type!="Button"&&$f$$.type!="Link"&&types.find($t$$=>$t$$.code==$f$$.type));$entries_fields_validFields$$=await Promise.all($entries_fields_validFields$$.map(async $f$$=>{var $fieldType_typeInfo$$=types.find($t$$=>$t$$.code==$f$$.type);$fieldType_typeInfo$$=$fieldType_typeInfo$$?$fieldType_typeInfo$$.type_data||$fieldType_typeInfo$$.code: $f$$.type;let $fieldDef$$={type:$fieldType_typeInfo$$,required:$f$$.required==1||$f$$.required=="true"?!0:void 0,maxlength:$f$$.maxlength?Number($f$$.maxlength):void 0,ref:$f$$.ref_model||void 0,description:$f$$.api_description||$f$$.header||void 0};Object.keys($fieldDef$$).forEach($key$$=>$fieldDef$$[$key$$]===void 0&&delete $fieldDef$$[$key$$]);let $detailCode$$=$f$$.form||"";if($detailCode$$&&$detailCode$$!=="0")try{const $subList$$=await global.getModel("listinfo").findOne({code:$detailCode$$}).lean(); if($subList$$&&$subList$$.fields){let $subSchema$$=await buildJsonSchema($subList$$.fields,$depth$$+1);$fieldType_typeInfo$$==="Array"||$f$$.type==="Array"?$fieldDef$$.type=[$subSchema$$]:$fieldType_typeInfo$$==="Json"||$fieldType_typeInfo$$==="Mixed"||$f$$.type==="Mixed"?$fieldDef$$.type=$subSchema$$:$fieldDef$$.sub_schema=$subSchema$$}}catch($e$$){console.error($e$$)}return[$f$$.name,$fieldDef$$]}));return Object.fromEntries($entries_fields_validFields$$)},renderSchema=async function($fields$jscomp$1_rows_validFields$$, $id_app$$,$import_yn$$=0,$depth$$=0){let $server_url$$=configs.api_url||configs.domain;if($depth$$>5)return"";var $cleanJson_jsonStr$$=await buildJsonSchema($fields$jscomp$1_rows_validFields$$);$cleanJson_jsonStr$$=JSON.stringify($cleanJson_jsonStr$$,null,2).replace(/</g,"\\u003c").replace(/>/g,"\\u003e");const $tableId$$="schema_"+Math.random().toString(36).substr(2,9);$fields$jscomp$1_rows_validFields$$=$fields$jscomp$1_rows_validFields$$.filter($f$$=>["ten_vt","ten_kh","ten_kho"].indexOf($f$$.name)>= 0||$f$$.not_input!="true"&&$f$$.not_input!=1&&$f$$.type!="Button"&&$f$$.type!="Link"&&types.find($t$$=>$t$$.code==$f$$.type));$fields$jscomp$1_rows_validFields$$=await Promise.all($fields$jscomp$1_rows_validFields$$.map(async $field$$=>{var $h_type$$=types.find($t$$=>$t$$.code==$field$$.type),$formattedJson_isJson_ref_model_html$$="",$description_detailCode$$=$field$$.ref_model||"";if($description_detailCode$$){$formattedJson_isJson_ref_model_html$$=typeof $description_detailCode$$==="string"&&($description_detailCode$$.trim().startsWith("{")|| $description_detailCode$$.trim().startsWith("["));const $hasComma$$=typeof $description_detailCode$$==="string"&&$description_detailCode$$.indexOf(",")>=0;if($formattedJson_isJson_ref_model_html$$||$hasComma$$){$formattedJson_isJson_ref_model_html$$=$description_detailCode$$;try{var $jsonObj$$=typeof $description_detailCode$$==="string"?JSON.parse($description_detailCode$$):$description_detailCode$$;$formattedJson_isJson_ref_model_html$$=JSON.stringify($jsonObj$$,null,2)}catch($e$$){console.error($e$$)}$formattedJson_isJson_ref_model_html$$= ` <div style="margin-top:8px"> <span style="color:#7f8c8d; font-size:0.85em">C\u1ea5u tr\u00fac tham chi\u1ebfu (JSON):</span> <pre style="background:#f4f4f4; padding:8px; border-radius:4px; font-size:11px; color:#2c3e50; border:1px solid #ddd; overflow-x:auto; max-width:350px; margin-top:4px;">${$formattedJson_isJson_ref_model_html$$}</pre> </div>`}else $jsonObj$$=`${$server_url$$}/api-docs-input/${$description_detailCode$$}`,$id_app$$&&($jsonObj$$=$jsonObj$$+"?id_app="+$id_app$$),$formattedJson_isJson_ref_model_html$$=` <div style="margin-top:8px"> <span style="color:#7f8c8d; font-size:0.85em">Tham chi\u1ebfu:</span> <a href='${$jsonObj$$}' target='_blank' style='color:#3498db; text-decoration:none; font-weight:bold; border-bottom:1px dashed #3498db;'>${$description_detailCode$$}</a> </div>`}$description_detailCode$$=$field$$.api_description||$field$$.header;["ten_vt","ten_kh","ten_kho"].indexOf($field$$.name)>=0&&($description_detailCode$$=`${$description_detailCode$$}. N\u1ebfu \u0111\u1ed1i t\u01b0\u1ee3ng n\u00e0y kh\u00f4ng t\u1ed3n t\u1ea1i trong danh m\u1ee5c th\u00ec h\u1ec7 th\u1ed1ng s\u1ebd s\u1eed d\u1ee5ng th\u00f4ng tin n\u00e0y \u0111\u1ec3 t\u1ea1o`);$h_type$$=` <tr style="background:#fff"> <td style="font-weight:bold; color:#e67e22; vertical-align:top; padding:10px;">${$field$$.name}</td> <td style="vertical-align:top; padding:10px;"><code>${$h_type$$.type_data||$h_type$$.code}</code></td> <td style="text-align:center; vertical-align:top; padding:10px;">${$field$$.required==1||$field$$.required=="true"?"<b style='color:red'>Yes</b>":"No"}</td> <td style="text-align:center; vertical-align:top; padding:10px;">${$field$$.type=="String"?$field$$.maxlength||4E3:"-"}</td> <td style="vertical-align:top; padding:10px;"> <div style="font-weight:500">${$description_detailCode$$}</div> ${$field$$.help_text?`<div style='font-size:0.9em;color:#666;font-style:italic;margin-top:4px'>* ${$field$$.help_text}</div>`:""} ${$formattedJson_isJson_ref_model_html$$} </td> </tr>`;if(($description_detailCode$$=$field$$.form||"")&&$description_detailCode$$!=="0")try{const $subList$$=await global.getModel("listinfo").findOne({code:$description_detailCode$$}).lean();if($subList$$&&$subList$$.fields){const $subTable$$=await renderSchema($subList$$.fields,$id_app$$,$import_yn$$,$depth$$+1);$h_type$$+=` <tr> <td colspan="5" style="padding: 0 0 15px 40px; border-top:none; background:#fcfcfc;"> <div style="border-left:3px solid #3498db; padding-left:15px; margin-top:10px"> <div style="margin-bottom:8px; font-weight:bold; color:#3498db">\u21b3 C\u1ea5u tr\u00fac chi ti\u1ebft [${$description_detailCode$$}]:</div> ${$subTable$$} </div> </td> </tr>`}}catch($e$$){console.error($e$$)}return $h_type$$}));return` <div style="position: relative; margin-bottom: 10px;"> <div style="display: flex; justify-content: flex-end; margin-bottom: 8px;"> <button onclick="var t=document.getElementById('${$tableId$$}'); t.select(); document.execCommand('copy'); var b=this; var o=b.innerHTML; b.innerHTML='\u2705 \u0110\u00e3 Copy Mongoose Schema!'; b.style.background='#27ae60'; setTimeout(function(){b.innerHTML=o; b.style.background='#2c3e50';},2000);" style="background: #2c3e50; color: #fff; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 12px; transition: 0.2s; font-weight: bold; box-shadow: 0 1px 2px rgba(0,0,0,0.2);"> \ud83d\udccb Copy Schema JSON </button> </div> <textarea id="${$tableId$$}" style="position:absolute; left:-9999px; top:0;" aria-hidden="true">${$cleanJson_jsonStr$$}</textarea> <table style="width:100%; border-collapse:collapse; font-size:13px; background:#fff" border="1" bordercolor="#ddd"> <tr style="background:#f2f2f2; text-align:left"> <th style="padding:10px; width:150px">Tr\u01b0\u1eddng (Field)</th> <th style="padding:10px; width:100px">Ki\u1ec3u</th> <th style="padding:10px; width:70px; text-align:center">B\u1eaft bu\u1ed9c</th> <th style="padding:10px; width:70px; text-align:center">Max</th> <th style="padding:10px">M\u00f4 t\u1ea3 / Tham chi\u1ebfu</th> </tr> ${$fields$jscomp$1_rows_validFields$$.join("")} </table> </div>`},apiDocs=async function($code$$,$id_app$$){var $endpointsHtml_server_url$$=configs.api_url||configs.domain;$code$$=await global.getModel("listinfo").findOne({$or:[{code:$code$$},{api_code:$code$$}]}).lean();if(!$code$$)return"Kh\u00f4ng t\u00ecm th\u1ea5y t\u00e0i li\u1ec7u API.";var $authLink_controller$$=global.controllers[($code$$.api_code||$code$$.code).toUpperCase()];if(!$authLink_controller$$)return"API Controller ch\u01b0a s\u1eb5n s\u00e0ng.";let $route_name$$=$authLink_controller$$.route_name.replace(":id_app", $id_app$$||"{id_app}");$authLink_controller$$=`${$endpointsHtml_server_url$$}/api-docs-auth`;let $idAppNote$$=$route_name$$.indexOf("id_app")>=0?'<li style="color:#8e44ad; margin-top:4px;"><b>id_app:</b> ID c\u1ee7a c\u00f4ng ty/chi nh\u00e1nh \u0111ang thao t\u00e1c (n\u1eb1m trong URL)</li>':"";$endpointsHtml_server_url$$=` <h3>1. Danh s\u00e1ch c\u00e1c Endpoint</h3> <table style="width:100%; border-collapse:collapse; margin-bottom:30px" border="1" bordercolor="#ddd"> <tr style="background:#eee"> <th style="padding:10px; width:180px;">Ch\u1ee9c n\u0103ng</th> <th style="padding:10px; width:80px;">Method</th> <th style="padding:10px">Chi ti\u1ebft C\u1ea5u h\u00ecnh (URL, Headers, Params, Body)</th> </tr> <tr style="background: #f0f7ff;"> <td style="padding:10px; font-weight:bold; color:#2980b9">Truy xu\u1ea5t d\u1eef li\u1ec7u<br/>(Search)</td> <td style="padding:10px; text-align:center"><b>POST</b></td> <td style="padding:10px"> <code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api/search${$route_name$$}</code> <div style="margin-top:10px; font-size:13px;"> <ul style="padding-left:20px; margin:0 0 10px 0;"> ${$idAppNote$$} </ul> <div style="color:#d35400; font-weight:bold; margin-bottom:3px;">Headers ri\u00eang:</div> <ul style="margin:0 0 10px 0; padding-left:20px; background:#fff3e0; padding:5px 20px; border-radius:4px;"> <li><b>listinfo-code:</b> <code>${$code$$.code}</code></li> </ul> <div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Body (JSON):</div> <ul style="margin:0; padding-left:20px;"> <li><b>page:</b> <code>Number</code>. Trang c\u1ea7n truy xu\u1ea5t (M\u1eb7c \u0111\u1ecbnh 1).</li> <li><b>limit:</b> <code>Number</code>. S\u1ed1 d\u00f2ng tr\u00ean m\u1ed9t trang (M\u1eb7c \u0111\u1ecbnh 20).</li> <li><b>fields:</b> <code>String</code>. C\u00e1c tr\u01b0\u1eddng c\u1ea7n l\u1ea5y, c\u00e1ch nhau d\u1ea5u ph\u1ea9y (M\u1eb7c \u0111\u1ecbnh l\u1ea5y t\u1ea5t c\u1ea3).</li> <li><b>count:</b> <code>Number</code>. Gi\u00e1 tr\u1ecb 0 ho\u1eb7c 1. N\u1ebfu = 1 s\u1ebd tr\u1ea3 v\u1ec1 t\u1ed5ng s\u1ed1 k\u1ebft qu\u1ea3 \u0111\u1ebfm \u0111\u01b0\u1ee3c.</li> <li style="background: #e8f4f8; padding: 5px; border-radius: 3px; margin: 5px 0;"> <b>pagination:</b> <code>Number</code>. Gi\u00e1 tr\u1ecb <code>1</code> ho\u1eb7c <code>0</code>. N\u1ebfu truy\u1ec1n <code>1</code>, API s\u1ebd tr\u1ea3 v\u1ec1 d\u1eef li\u1ec7u d\u1ea1ng Object c\u00f3 th\u00f4ng tin ph\u00e2n trang: <br/> <code style="display:inline-block; margin-top:4px; background:#fff;">{ data: [d\u1eef li\u1ec7u trang hi\u1ec7n t\u1ea1i], pagination: { limit,total, page, totalPages } }</code> </li> <li><b>q:</b> <code>Json</code>. \u0110i\u1ec1u ki\u1ec7n l\u1ecdc (MongoDB Query). Tham kh\u1ea3o c\u1ea5u tr\u00fac t\u1ea1i b\u1ea3ng Schema.</li> </ul> </div> </td> </tr> <tr> <td style="padding:10px; font-weight:bold">L\u1ea5y chi ti\u1ebft 01 b\u1ea3n ghi<br/>(Get By ID)</td> <td style="padding:10px; text-align:center"><b>GET</b></td> <td style="padding:10px"> <code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api${$route_name$$}/:_id</code> <div style="margin-top:10px; font-size:13px;"> <ul style="margin:0; padding-left:20px;"> ${$idAppNote$$} <li><b>_id:</b> ID c\u1ee7a b\u1ea3n ghi c\u1ea7n l\u1ea5y d\u1eef li\u1ec7u (n\u1eb1m trong URL)</li> </ul> </div> </td> </tr> ${$code$$.not_add?"":` <tr> <td style="padding:10px; font-weight:bold">Th\u00eam m\u1edbi<br/>(Create)</td> <td style="padding:10px; text-align:center"><b>POST</b></td> <td style="padding:10px"> <code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api${$route_name$$}</code> <div style="margin-top:10px; font-size:13px;"> <ul style="margin:0 0 10px 0; padding-left:20px;">${$idAppNote$$}</ul> <div style="color:#d35400; font-weight:bold; margin-bottom:3px;">Headers ri\u00eang:</div> <ul style="margin:0 0 10px 0; padding-left:20px; background:#fff3e0; padding:5px 20px; border-radius:4px;"> <li><b>listinfo-code:</b> <code>${$code$$.code}</code></li> </ul> <div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Body (JSON):</div> <ul style="margin:0; padding-left:20px;"> <li>M\u1ed9t Object ch\u1ee9a d\u1eef li\u1ec7u c\u1ee7a b\u1ea3n ghi m\u1edbi. Tham kh\u1ea3o c\u1ea5u tr\u00fac t\u1ea1i b\u1ea3ng Schema.</li> </ul> </div> </td> </tr> <tr> <td style="padding:10px; font-weight:bold">Import d\u1eef li\u1ec7u<br/>(JSON Array)</td> <td style="padding:10px; text-align:center"><b>POST</b></td> <td style="padding:10px"> <code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api${$route_name$$}/import/json</code> <div style="margin-top:10px; font-size:13px;"> <ul style="margin:0 0 10px 0; padding-left:20px;">${$idAppNote$$}</ul> <div style="color:#d35400; font-weight:bold; margin-bottom:3px;">Headers ri\u00eang:</div> <ul style="margin:0 0 10px 0; padding-left:20px; background:#fff3e0; padding:5px 20px; border-radius:4px;"> <li><b>listinfo-code:</b> <code>${$code$$.code}</code></li> </ul> <div style="color:#16a085; font-weight:bold; margin-bottom:3px;">Query Parameters:</div> <ul style="margin:0 0 10px 0; padding-left:20px; background:#e8f8f5; padding:5px 20px; border-radius:4px;"> <li><b>update:</b> <code>true</code> ho\u1eb7c <code>false</code>. C\u00f3 c\u1eadp nh\u1eadt gi\u00e1 tr\u1ecb m\u1edbi n\u1ebfu \u0111\u1ed1i t\u01b0\u1ee3ng \u0111\u00e3 t\u1ed3n t\u1ea1i hay kh\u00f4ng?</li> </ul> <div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Body (JSON):</div> <ul style="margin:0; padding-left:20px;"> <li>L\u00e0 m\u1ed9t <b>m\u1ea3ng (Array)</b> ch\u1ee9a danh s\u00e1ch c\u00e1c b\u1ea3n ghi c\u1ea7n import.</li> </ul> </div> </td> </tr>`} ${$code$$.not_update?"":` <tr> <td style="padding:10px; font-weight:bold">C\u1eadp nh\u1eadt d\u1eef li\u1ec7u<br/>(Update)</td> <td style="padding:10px; text-align:center"><b>PUT</b></td> <td style="padding:10px"> <code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api${$route_name$$}/:_id</code> <div style="margin-top:10px; font-size:13px;"> <ul style="margin:0 0 10px 0; padding-left:20px;"> ${$idAppNote$$} <li><b>_id:</b> ID c\u1ee7a b\u1ea3n ghi c\u1ea7n c\u1eadp nh\u1eadt (n\u1eb1m trong URL)</li> </ul> <div style="color:#d35400; font-weight:bold; margin-bottom:3px;">Headers ri\u00eang:</div> <ul style="margin:0 0 10px 0; padding-left:20px; background:#fff3e0; padding:5px 20px; border-radius:4px;"> <li><b>listinfo-code:</b> <code>${$code$$.code}</code></li> </ul> <div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Body (JSON):</div> <ul style="margin:0; padding-left:20px;"> <li>C\u00e1c tr\u01b0\u1eddng d\u1eef li\u1ec7u c\u1ea7n thay \u0111\u1ed5i. C\u00f3 th\u1ec3 c\u1eadp nh\u1eadt 1 ho\u1eb7c nhi\u1ec1u tr\u01b0\u1eddng c\u00f9ng l\u00fac.</li> </ul> </div> </td> </tr>`} ${$code$$.not_delete?"":` <tr> <td style="padding:10px; font-weight:bold; color:#c0392b">Xo\u00e1 d\u1eef li\u1ec7u<br/>(Delete By ID)</td> <td style="padding:10px; text-align:center"><b>DELETE</b></td> <td style="padding:10px"> <code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api${$route_name$$}/:_id</code> <div style="margin-top:10px; font-size:13px;"> <ul style="margin:0; padding-left:20px;"> ${$idAppNote$$} <li><b>_id:</b> ID c\u1ee7a b\u1ea3n ghi c\u1ea7n xo\u00e1 (n\u1eb1m trong URL)</li> </ul> <div style="color:#d35400; font-weight:bold; margin-bottom:3px;">Headers ri\u00eang:</div> <ul style="margin:0 0 10px 0; padding-left:20px; background:#fff3e0; padding:5px 20px; border-radius:4px;"> <li><b>listinfo-code:</b> <code>${$code$$.code}</code></li> </ul> </div> </td> </tr> <tr style="background-color: #fff5f5;"> <td style="padding:10px; font-weight:bold; color:#c0392b">Xo\u00e1 h\u00e0ng lo\u1ea1t<br/>(Delete Many)</td> <td style="padding:10px; text-align:center"><b>POST</b></td> <td style="padding:10px"> <code style="font-size:14px; background:#fdeced; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api${$route_name$$}/action/delete</code> <div style="margin-top:10px; font-size:13px;"> <ul style="margin:0 0 10px 0; padding-left:20px;">${$idAppNote$$}</ul> <div style="color:#c0392b; font-weight:bold; margin-bottom:3px;">Body (JSON):</div> <ul style="margin:0; padding-left:20px;"> <li><b>condition:</b> <code>Json</code>. \u0110i\u1ec1u ki\u1ec7n xo\u00e1 d\u1eef li\u1ec7u (MongoDB Query).</li> </ul> </div> </td> </tr>`} </table> `;$id_app$$=await renderSchema($code$$.fields,$id_app$$);return` <!DOCTYPE html> <html lang="vi"> <head> <meta charset="utf-8"> <title>T\u00e0i li\u1ec7u API - ${$code$$.title}</title> <style> body { font-family: 'Segoe UI', Tahoma, sans-serif; line-height: 1.5; color: #333; padding: 30px; max-width: 1200px; margin: 0 auto; background: #fafafa; } h2 { color: #2c3e50; border-bottom: 3px solid #3498db; padding-bottom: 15px; margin-top:0; } h3 { color: #2980b9; margin-top: 40px; font-size: 1.2em; text-transform: uppercase; } code { font-family: 'Consolas', monospace; color: #c7254e; } .auth-box { background:#fff; padding:15px 20px; border-left: 5px solid #3498db; border-radius:4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 30px; } .schema-wrapper { background:#fff; padding:15px; border:1px solid #ddd; border-radius:6px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); overflow-x: auto;} </style> </head> <body> <h2>T\u00c0I LI\u1ec6U API: ${$code$$.title}</h2> <div class="auth-box"> <strong style="font-size:1.1em;">Th\u00f4ng tin Headers d\u00f9ng chung cho T\u1ea4T C\u1ea2 request:</strong> <ul style="margin-top:10px; list-style: none; padding-left: 0;"> <li style="margin-bottom:8px;">\ud83d\udd11 <b>access-token:</b> Token x\u00e1c th\u1ef1c. <a href="${$authLink_controller$$}" target="_blank" style="color:#3498db; text-decoration:none; font-weight:bold;">Xem h\u01b0\u1edbng d\u1eabn l\u1ea5y Token &rarr;</a></li> <li>\ud83d\udcc4 <b>Content-Type:</b> <code>application/json</code></li> </ul> </div> ${$endpointsHtml_server_url$$} <h3>2. B\u1ea3n \u0111\u1ed3 D\u1eef li\u1ec7u (Schema)</h3> <p style="color:#555; font-size:0.95em;"> C\u1ea5u tr\u00fac d\u01b0\u1edbi \u0111\u00e2y li\u1ec7t k\u00ea to\u00e0n b\u1ed9 c\u00e1c tr\u01b0\u1eddng (fields) c\u1ee7a \u0111\u1ed1i t\u01b0\u1ee3ng. B\u1ea1n s\u1ebd d\u00f9ng c\u00e1c tr\u01b0\u1eddng n\u00e0y \u0111\u1ec3 g\u1eedi trong <b>Body</b> khi Th\u00eam/S\u1eeda, ho\u1eb7c d\u00f9ng \u0111\u1ec3 t\u1ea1o \u0111i\u1ec1u ki\u1ec7n l\u1ecdc trong tr\u01b0\u1eddng <code>q</code> (khi Search) v\u00e0 <code>condition</code> (khi Xo\u00e1 h\u00e0ng lo\u1ea1t). </p> <div class="schema-wrapper"> ${$id_app$$} </div> </body> </html> `},renderReportColumns=function($columns$$){return $columns$$&&$columns$$.length!==0?` <table style="width:100%; border-collapse:collapse; font-size:13px; background:#fff" border="1" bordercolor="#ddd"> <tr style="background:#f2f2f2; text-align:left"> <th style="padding:10px; width:250px">T\u00ean tr\u01b0\u1eddng tr\u1ea3 v\u1ec1 (Field)</th> <th style="padding:10px; width:150px">Ki\u1ec3u d\u1eef li\u1ec7u (Datatype)</th> <th style="padding:10px">Ti\u00eau \u0111\u1ec1 c\u1ed9t (Header)</th> </tr> ${[...$columns$$].sort(($a$$,$b$$)=>($a$$.stt||0)-($b$$.stt||0)).map($col$$=>{let $typeColor$$="#c7254e";$col$$.datatype==="Number"&&($typeColor$$="#2980b9");if($col$$.datatype==="Date"||$col$$.datatype==="DateTime")$typeColor$$="#27ae60";return` <tr style="background:#fff"> <td style="font-weight:bold; color:#e67e22; padding:10px;">${$col$$.field||""}</td> <td style="padding:10px;"><code style="color:${$typeColor$$}; background:#f9f2f4; padding:2px 4px; border-radius:3px;">${$col$$.datatype||"String"}</code></td> <td style="padding:10px; font-weight:500;">${$col$$.header||""}</td> </tr>`}).join("")} </table>`:""},apiReport=async function($code$$,$id_app$jscomp$2_schemaHtml$$){var $endpointsHtml$jscomp$1_server_url$$=configs.api_url||configs.domain;$code$$=await global.getModel("reportinfo").findOne({code:$code$$}).lean();if(!$code$$)return"Kh\u00f4ng t\u00ecm th\u1ea5y t\u00e0i li\u1ec7u cho b\u00e1o c\u00e1o n\u00e0y.";var $columnsHtml_listinfo$$;$code$$.form_condition_info&&($columnsHtml_listinfo$$=await global.getModel("listinfo").findOne({code:$code$$.form_condition_info}).lean());$columnsHtml_listinfo$$= $columnsHtml_listinfo$$||{fields:[]};var $authLink$jscomp$1_controller$$=global.report_controllers[($code$$.api_code||$code$$.code).toUpperCase()];if(!$authLink$jscomp$1_controller$$)return"Report Controller ch\u01b0a s\u1eb5n s\u00e0ng.";let $route_name$$=`${$authLink$jscomp$1_controller$$.base_path}${$authLink$jscomp$1_controller$$.module}`.replace(":id_app",$id_app$jscomp$2_schemaHtml$$||"{id_app}");$authLink$jscomp$1_controller$$=`${$endpointsHtml$jscomp$1_server_url$$}/api-docs-auth`;let $idAppNote$$= $route_name$$.indexOf("id_app")>=0?'<li style="color:#8e44ad; margin-top:4px;"><b>id_app:</b> ID c\u1ee7a c\u00f4ng ty/chi nh\u00e1nh \u0111ang thao t\u00e1c (n\u1eb1m trong URL)</li>':"";$endpointsHtml$jscomp$1_server_url$$=` <h3>1. Th\u00f4ng tin Endpoint B\u00e1o c\u00e1o</h3> <table style="width:100%; border-collapse:collapse; margin-bottom:30px" border="1" bordercolor="#ddd"> <tr style="background:#eee"> <th style="padding:10px; width:180px;">Ch\u1ee9c n\u0103ng</th> <th style="padding:10px; width:80px;">Method</th> <th style="padding:10px">Chi ti\u1ebft C\u1ea5u h\u00ecnh (URL, Headers, Body)</th> </tr> <tr style="background: #fdfaf0;"> <td style="padding:10px; font-weight:bold; color:#d35400">Xu\u1ea5t b\u00e1o c\u00e1o<br/>(Generate Report)</td> <td style="padding:10px; text-align:center"><b>POST</b></td> <td style="padding:10px"> <code style="font-size:14px; background:#fbeee6; color:#000; padding:4px 8px;">${$endpointsHtml$jscomp$1_server_url$$}/api${$route_name$$}</code> <div style="margin-top:10px; font-size:13px;"> <ul style="padding-left:20px; margin:0 0 10px 0;"> ${$idAppNote$$} </ul> <div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Body (JSON) - \u0110i\u1ec1u ki\u1ec7n l\u1ecdc:</div> <ul style="margin:0; padding-left:20px;"> <li>G\u1eedi m\u1ed9t Object ch\u1ee9a c\u00e1c tham s\u1ed1 l\u1ecdc. Xem c\u1ea5u tr\u00fac t\u1ea1i <b>M\u1ee5c 2</b>.</li> </ul> <div style="color:#16a085; font-weight:bold; margin-top:8px; margin-bottom:3px;">D\u1eef li\u1ec7u tr\u1ea3 v\u1ec1 (Response):</div> <ul style="margin:0; padding-left:20px;"> <li>M\u1ed9t m\u1ea3ng JSON (Array) ch\u1ee9a c\u00e1c d\u00f2ng d\u1eef li\u1ec7u. Xem c\u1ea5u tr\u00fac c\u00e1c c\u1ed9t t\u1ea1i <b>M\u1ee5c 3</b>.</li> </ul> </div> </td> </tr> </table> `;$id_app$jscomp$2_schemaHtml$$=$columnsHtml_listinfo$$.fields&&$columnsHtml_listinfo$$.fields.length>0?await renderSchema($columnsHtml_listinfo$$.fields,$id_app$jscomp$2_schemaHtml$$):'<div style="padding: 15px; background: #f9f9f9; color: #666; font-style: italic; border-left: 3px solid #ccc;">B\u00e1o c\u00e1o n\u00e0y kh\u00f4ng y\u00eau c\u1ea7u tham s\u1ed1 l\u1ecdc (G\u1eedi Body l\u00e0 m\u1ed9t Object r\u1ed7ng <code>{}</code>).</div>';$columnsHtml_listinfo$$=$code$$.columns&&$code$$.columns.length> 0?renderReportColumns($code$$.columns):'<div style="padding: 15px; background: #fdfaf0; color: #d35400; font-style: italic; border-left: 3px solid #e67e22;">Ch\u01b0a c\u00f3 c\u1ea5u h\u00ecnh chi ti\u1ebft c\u00e1c c\u1ed9t tr\u1ea3 v\u1ec1 cho b\u00e1o c\u00e1o n\u00e0y.</div>';return` <!DOCTYPE html> <html lang="vi"> <head> <meta charset="utf-8"> <title>T\u00e0i li\u1ec7u API Report - ${$code$$.title}</title> <style> body { font-family: 'Segoe UI', Tahoma, sans-serif; line-height: 1.5; color: #333; padding: 30px; max-width: 1200px; margin: 0 auto; background: #fafafa; } h2 { color: #2c3e50; border-bottom: 3px solid #e67e22; padding-bottom: 15px; margin-top:0; } h3 { color: #d35400; margin-top: 40px; font-size: 1.2em; text-transform: uppercase; } code { font-family: 'Consolas', monospace; } .auth-box { background:#fff; padding:15px 20px; border-left: 5px solid #e67e22; border-radius:4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 30px; } .schema-wrapper { background:#fff; padding:15px; border:1px solid #ddd; border-radius:6px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); overflow-x: auto; margin-bottom: 20px;} </style> </head> <body> <h2>API REPORT: ${$code$$.title}</h2> <div class="auth-box"> <strong style="font-size:1.1em;">Th\u00f4ng tin Headers b\u1eaft bu\u1ed9c cho Request:</strong> <ul style="margin-top:10px; list-style: none; padding-left: 0;"> <li style="margin-bottom:8px;">\ud83d\udd11 <b>access-token:</b> Token x\u00e1c th\u1ef1c. <a href="${$authLink$jscomp$1_controller$$}" target="_blank" style="color:#d35400; text-decoration:none; font-weight:bold;">Xem h\u01b0\u1edbng d\u1eabn l\u1ea5y Token &rarr;</a></li> <li>\ud83d\udcc4 <b>Content-Type:</b> <code>application/json</code></li> </ul> </div> ${$endpointsHtml$jscomp$1_server_url$$} <h3>2. B\u1ea3n \u0111\u1ed3 D\u1eef ki\u1ec7n L\u1ecdc (Body Request)</h3> <p style="color:#555; font-size:0.95em;"> G\u1eedi Object JSON ch\u1ee9a c\u00e1c tr\u01b0\u1eddng n\u00e0y l\u00ean API \u0111\u1ec3 l\u00e0m <b>\u0111i\u1ec1u ki\u1ec7n l\u1ecdc</b> cho b\u00e1o c\u00e1o. </p> <div class="schema-wrapper"> ${$id_app$jscomp$2_schemaHtml$$} </div> <h3>3. C\u1ea5u tr\u00fac D\u1eef li\u1ec7u Tr\u1ea3 v\u1ec1 (Response Columns)</h3> <p style="color:#555; font-size:0.95em;"> D\u1eef li\u1ec7u tr\u1ea3 v\u1ec1 (Response) l\u00e0 m\u1ed9t danh s\u00e1ch (Array) c\u00e1c b\u1ea3n ghi. M\u1ed7i b\u1ea3n ghi (Object) s\u1ebd bao g\u1ed3m c\u00e1c key \u0111\u01b0\u1ee3c \u0111\u1ecbnh ngh\u0129a d\u01b0\u1edbi \u0111\u00e2y: </p> <div class="schema-wrapper" style="border-top: 3px solid #16a085; padding: 0; border-radius: 4px; overflow: hidden;"> ${$columnsHtml_listinfo$$} </div> <div style="margin-top:60px; border-top:1px solid #eee; padding-top:20px; text-align:center; color:#999; font-size:12px"> T\u00e0i li\u1ec7u API Report t\u1ef1 \u0111\u1ed9ng \u0111\u01b0\u1ee3c t\u1ea1o b\u1edfi h\u1ec7 th\u1ed1ng &copy; 2026 </div> </body> </html> `},apiAuth=function(){let $server_url$$=configs.api_url||configs.domain;return` <!DOCTYPE html> <html lang="vi"> <head> <meta charset="utf-8"> <title>T\u00e0i li\u1ec7u API Auth & \u0110\u0103ng k\u00fd</title> <style> body { font-family: 'Segoe UI', Tahoma, sans-serif; line-height: 1.5; color: #333; padding: 30px; max-width: 1200px; margin: 0 auto; background: #fafafa; } h2 { color: #2c3e50; border-bottom: 3px solid #3498db; padding-bottom: 15px; margin-top:0; } h3 { color: #2980b9; margin-top: 40px; font-size: 1.2em; text-transform: uppercase; } code { font-family: 'Consolas', monospace; color: #c7254e; background: #f9f2f4; padding: 2px 4px; border-radius: 3px; } .info-box { background:#fff; padding:15px 20px; border-left: 5px solid #3498db; border-radius:4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 30px; } </style> </head> <body> <h2>API H\u1ec6 TH\u1ed0NG: X\u00c1C TH\u1ef0C & NG\u01af\u1edcI D\u00d9NG</h2> <div class="info-box"> <p style="margin:0; color: #555;">T\u00e0i li\u1ec7u n\u00e0y h\u01b0\u1edbng d\u1eabn c\u00e1ch l\u1ea5y <b>access-token</b> th\u00f4ng qua API \u0110\u0103ng nh\u1eadp, c\u00e1ch qu\u1ea3n l\u00fd phi\u00ean l\u00e0m vi\u1ec7c (\u0110\u0103ng xu\u1ea5t, \u0110\u1ed5i m\u1eadt kh\u1ea9u) v\u00e0 c\u1ea5u tr\u00fac chi ti\u1ebft c\u1ee7a API \u0110\u0103ng k\u00fd t\u00e0i kho\u1ea3n m\u1edbi.</p> </div> ${` <h3>1. X\u00e1c th\u1ef1c & Qu\u1ea3n l\u00fd t\u00e0i kho\u1ea3n (Auth)</h3> <table style="width:100%; border-collapse:collapse; margin-bottom:30px" border="1" bordercolor="#ddd"> <tr style="background:#eee"> <th style="padding:10px; width:180px;">Ch\u1ee9c n\u0103ng</th> <th style="padding:10px; width:80px;">Method</th> <th style="padding:10px">Chi ti\u1ebft C\u1ea5u h\u00ecnh (URL, Headers, Body)</th> </tr> <tr style="background: #f0f7ff;"> <td style="padding:10px; font-weight:bold; color:#2980b9">\u0110\u0103ng nh\u1eadp<br/>(Login)</td> <td style="padding:10px; text-align:center"><b>GET</b></td> <td style="padding:10px"> <code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$server_url$$}/auth/local</code> <div style="margin-top:10px; font-size:13px;"> <div style="color:#d35400; font-weight:bold; margin-bottom:3px;">Headers b\u1eaft bu\u1ed9c:</div> <ul style="margin:0 0 10px 0; padding-left:20px; background:#fff3e0; padding:5px 20px; border-radius:4px;"> <li><b>Authorization:</b> <span style="color:#e67e22; font-weight:bold;">Basic Auth</span> <span style="color:#666;">(M\u00e3 h\u00f3a Base64 c\u1ee7a <code>email:password</code>)</span></li> </ul> <div style="color:#16a085; font-weight:bold; margin-bottom:3px;">K\u1ebft qu\u1ea3 tr\u1ea3 v\u1ec1:</div> <ul style="margin:0; padding-left:20px;"> <li>Tr\u1ea3 v\u1ec1 <code>access-token</code> v\u00e0 th\u00f4ng tin user. D\u00f9ng token n\u00e0y truy\u1ec1n v\u00e0o Headers cho c\u00e1c API kh\u00e1c.</li> </ul> </div> </td> </tr> <tr> <td style="padding:10px; font-weight:bold;">\u0110\u0103ng xu\u1ea5t<br/>(Logout)</td> <td style="padding:10px; text-align:center"><b>GET</b></td> <td style="padding:10px"> <code style="font-size:14px; background:#f9f9f9; color:#000; padding:4px 8px;">${$server_url$$}/api/user/logout</code> <div style="margin-top:10px; font-size:13px;"> <div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Headers b\u1eaft bu\u1ed9c:</div> <ul style="margin:0; padding-left:20px;"> <li><b>access-token:</b> Token hi\u1ec7n t\u1ea1i \u0111ang s\u1eed d\u1ee5ng c\u1ee7a phi\u00ean l\u00e0m vi\u1ec7c.</li> </ul> </div> </td> </tr> <tr> <td style="padding:10px; font-weight:bold;">\u0110\u1ed5i m\u1eadt kh\u1ea9u<br/>(Change Password)</td> <td style="padding:10px; text-align:center"><b>POST</b></td> <td style="padding:10px"> <code style="font-size:14px; background:#f9f9f9; color:#000; padding:4px 8px;">${$server_url$$}/api/changepassword</code> <div style="margin-top:10px; font-size:13px;"> <div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Headers b\u1eaft bu\u1ed9c:</div> <ul style="margin:0 0 10px 0; padding-left:20px;"> <li><b>access-token:</b> Token x\u00e1c th\u1ef1c.</li> <li><b>Content-Type:</b> <code>application/json</code></li> </ul> <div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Body (JSON):</div> <ul style="margin:0; padding-left:20px;"> <li><b>oldPassword:</b> <code>String</code>. M\u1eadt kh\u1ea9u hi\u1ec7n t\u1ea1i.</li> <li><b>newPassword:</b> <code>String</code>. M\u1eadt kh\u1ea9u m\u1edbi.</li> <li><b>reNewPassword:</b> <code>String</code>. X\u00e1c nh\u1eadn l\u1ea1i m\u1eadt kh\u1ea9u m\u1edbi.</li> </ul> </div> </td> </tr> </table> `} ${` <h3>2. \u0110\u0103ng k\u00fd t\u00e0i kho\u1ea3n (Sign Up)</h3> <p style="color:#555; font-size:0.95em;"> API n\u00e0y d\u00f9ng \u0111\u1ec3 \u0111\u0103ng k\u00fd t\u00e0i kho\u1ea3n ng\u01b0\u1eddi d\u00f9ng m\u1edbi. Ngo\u00e0i ra, API c\u00f2n h\u1ed7 tr\u1ee3: <b>T\u1ef1 \u0111\u1ed9ng th\u00eam user v\u00e0o m\u1ed9t c\u00f4ng ty (App) c\u00f3 s\u1eb5n</b> ho\u1eb7c <b>Kh\u1edfi t\u1ea1o c\u00f4ng ty m\u1edbi</b> khi \u0111\u0103ng k\u00fd. </p> <table style="width:100%; border-collapse:collapse; margin-bottom:20px" border="1" bordercolor="#ddd"> <tr style="background:#fdfaf0;"> <td style="padding:15px; text-align:center; width:80px; font-weight:bold; color:#d35400;">POST</td> <td style="padding:15px;"><code style="font-size:15px; background:none; color:#d35400;">${$server_url$$}/signup</code></td> </tr> </table> <div style="display:flex; gap: 20px; flex-wrap: wrap; margin-bottom: 20px;"> <div style="flex:1; min-width: 300px;"> <h4 style="color:#2c3e50; margin-bottom: 10px;">Query Parameters (T\u00f9y ch\u1ecdn)</h4> <table style="width:100%; border-collapse:collapse; font-size:13px; background:#fff" border="1" bordercolor="#ddd"> <tr style="background:#f2f2f2; text-align:left"> <th style="padding:8px;">Tham s\u1ed1</th> <th style="padding:8px; width:80px;">Ki\u1ec3u</th> <th style="padding:8px;">M\u00f4 t\u1ea3</th> </tr> <tr><td style="padding:8px; font-weight:bold; color:#e67e22;">g-recaptcha-response</td><td style="padding:8px;"><code>String</code></td><td style="padding:8px;">Token c\u1ee7a Google reCAPTCHA</td></tr> <tr><td style="padding:8px; font-weight:bold; color:#e67e22;">once</td><td style="padding:8px;"><code>Boolean</code></td><td style="padding:8px;">\u0110\u00e1nh d\u1ea5u Token ch\u1ec9 s\u1eed d\u1ee5ng m\u1ed9t l\u1ea7n</td></tr> </table> </div> <div style="flex:1; min-width: 300px;"> <h4 style="color:#2c3e50; margin-bottom: 10px;">Headers / Cookies</h4> <ul style="background:#fff; border:1px solid #ddd; padding:15px 20px 15px 40px; border-radius:4px; font-size:13px; margin:0;"> <li style="margin-bottom:8px;"><b>Cookie (uid):</b> Ph\u1ee5c v\u1ee5 Rate Limit - Gi\u1edbi h\u1ea1n m\u1ed7i thi\u1ebft b\u1ecb ch\u1ec9 \u0111\u01b0\u1ee3c t\u1ea1o 1 t\u00e0i kho\u1ea3n.</li> <li><b>User-Agent:</b> \u0110\u01b0\u1ee3c l\u01b0u v\u00e0o log h\u1ec7 th\u1ed1ng \u0111\u1ec3 theo d\u00f5i thi\u1ebft b\u1ecb \u0111\u0103ng k\u00fd.</li> </ul> </div> </div> <h4 style="color:#2c3e50; margin-top:30px; margin-bottom: 10px;">Body Payload (JSON)</h4> <table style="width:100%; border-collapse:collapse; font-size:13px; background:#fff; margin-bottom:30px;" border="1" bordercolor="#ddd"> <tr style="background:#f2f2f2; text-align:left"> <th style="padding:10px; width:180px">Tr\u01b0\u1eddng (Field)</th> <th style="padding:10px; width:80px">Ki\u1ec3u</th> <th style="padding:10px; width:80px; text-align:center">B\u1eaft bu\u1ed9c</th> <th style="padding:10px">M\u00f4 t\u1ea3 chi ti\u1ebft</th> </tr> <tr> <td style="padding:10px; font-weight:bold; color:#e67e22;">email</td> <td style="padding:10px;"><code>String</code></td> <td style="padding:10px; text-align:center; color:red; font-weight:bold;">Yes</td> <td style="padding:10px;">Email ho\u1eb7c S\u1ed1 \u0111i\u1ec7n tho\u1ea1i VN h\u1ee3p l\u1ec7. <i>(T\u1ef1 \u0111\u1ed9ng trim & lowercase)</i></td> </tr> <tr> <td style="padding:10px; font-weight:bold; color:#e67e22;">name</td> <td style="padding:10px;"><code>String</code></td> <td style="padding:10px; text-align:center; color:red; font-weight:bold;">Yes</td> <td style="padding:10px;">H\u1ecd v\u00e0 t\u00ean ng\u01b0\u1eddi d\u00f9ng.</td> </tr> <tr> <td style="padding:10px; font-weight:bold; color:#e67e22;">password</td> <td style="padding:10px;"><code>String</code></td> <td style="padding:10px; text-align:center;">No</td> <td style="padding:10px;">T\u1ed1i thi\u1ec3u 6 k\u00fd t\u1ef1 (g\u1ed3m ch\u1eef hoa, ch\u1eef th\u01b0\u1eddng, s\u1ed1). <b>N\u1ebfu kh\u00f4ng g\u1eedi, h\u1ec7 th\u1ed1ng t\u1ef1 sinh m\u1eadt kh\u1ea9u an to\u00e0n v\u00e0 g\u1eedi qua email.</b></td> </tr> <tr> <td style="padding:10px; font-weight:bold; color:#e67e22;">rePassword</td> <td style="padding:10px;"><code>String</code></td> <td style="padding:10px; text-align:center; color:#e67e22;">(*)</td> <td style="padding:10px;">B\u1eaft bu\u1ed9c n\u1ebfu c\u00f3 truy\u1ec1n <code>password</code>. Ph\u1ea3i kh\u1edbp v\u1edbi password.</td> </tr> <tr> <td style="padding:10px; font-weight:bold; color:#e67e22;">id_app</td> <td style="padding:10px;"><code>String</code></td> <td style="padding:10px; text-align:center;">No</td> <td style="padding:10px;">MongoDB ObjectId c\u1ee7a c\u00f4ng ty. N\u1ebfu truy\u1ec1n, user s\u1ebd \u0111\u01b0\u1ee3c add v\u00e0o c\u00f4ng ty n\u00e0y.</td> </tr> <tr> <td style="padding:10px; font-weight:bold; color:#e67e22;">cty_name</td> <td style="padding:10px;"><code>String</code></td> <td style="padding:10px; text-align:center;">No</td> <td style="padding:10px;">T\u00ean c\u00f4ng ty. D\u00f9ng \u0111\u1ec3 kh\u1edfi t\u1ea1o c\u00f4ng ty m\u1edbi n\u1ebfu ch\u01b0a c\u00f3 <code>id_app</code>.</td> </tr> <tr> <td style="padding:10px; font-weight:bold; color:#e67e22;">introduce_code</td> <td style="padding:10px;"><code>String</code></td> <td style="padding:10px; text-align:center;">No</td> <td style="padding:10px;">M\u00e3 ng\u01b0\u1eddi gi\u1edbi thi\u1ec7u (Referral code).</td> </tr> <tr> <td style="padding:10px; font-weight:bold; color:#e67e22;">g-recaptcha-response</td> <td style="padding:10px;"><code>String</code></td> <td style="padding:10px; text-align:center; color:#e67e22;">(*)</td> <td style="padding:10px;">Token reCAPTCHA. Y\u00eau c\u1ea7u ph\u1ee5 thu\u1ed9c v\u00e0o c\u1ea5u h\u00ecnh b\u1ea3o m\u1eadt c\u1ee7a h\u1ec7 th\u1ed1ng.</td> </tr> <tr> <td style="padding:10px; font-weight:bold; color:#e67e22;">email2</td> <td style="padding:10px;"><code>String</code></td> <td style="padding:10px; text-align:center;">No</td> <td style="padding:10px;">Email ph\u1ee5.</td> </tr> <tr> <td style="padding:10px; font-weight:bold; color:#e67e22;">picture</td> <td style="padding:10px;"><code>String</code></td> <td style="padding:10px; text-align:center;">No</td> <td style="padding:10px;">URL Avatar. M\u1eb7c \u0111\u1ecbnh: <code>/images/avatar.jpg</code></td> </tr> <tr> <td style="padding:10px; font-weight:bold; color:#e67e22;">partner</td> <td style="padding:10px;"><code>String</code></td> <td style="padding:10px; text-align:center;">No</td> <td style="padding:10px;">ID c\u1ee7a \u0111\u1ed1i t\u00e1c li\u00ean k\u1ebft.</td> </tr> </table> <div style="display:flex; gap: 20px; flex-wrap: wrap;"> <div style="flex:1; min-width: 300px;"> <h4 style="color:#2c3e50; margin-bottom: 10px;">K\u1ebft qu\u1ea3 tr\u1ea3 v\u1ec1 (Response)</h4> <div style="background:#2c3e50; padding: 15px; border-radius: 6px; color: #ecf0f1; font-family: monospace; font-size: 13px; line-height:1.4;"> <span style="color: #2ecc71;">// Th\u00e0nh c\u00f4ng (HTTP 200 OK)</span> { "message": "T\u00e0i kho\u1ea3n \u0111\u00e3 \u0111\u01b0\u1ee3c \u0111\u0103ng k\u00fd th\u00e0nh c\u00f4ng", "token": "eyJhbGciOiJIUzI1NiIsInR...", "active": true } <span style="color: #e74c3c;">// Th\u1ea5t b\u1ea1i (HTTP 400 Bad Request)</span> { "error": "T\u00e0i kho\u1ea3n \u0111\u00e3 t\u1ed3n t\u1ea1i / Thi\u1ebft b\u1ecb \u0111\u00e3 \u0111\u01b0\u1ee3c \u0111\u0103ng k\u00fd" } </div> </div> <div style="flex:1; min-width: 300px;"> <h4 style="color:#2c3e50; margin-bottom: 10px;">Business Logic Quan Tr\u1ecdng</h4> <ul style="background:#fff; border:1px solid #ddd; padding:15px 20px 15px 40px; border-radius:4px; font-size:13px; margin:0; line-height: 1.8;"> <li><b>\u0110\u1ecbnh d\u1ea1ng T\u1ef1 \u0111\u1ed9ng:</b> Email v\u00e0 S\u0110T lu\u00f4n \u0111\u01b0\u1ee3c t\u1ef1 \u0111\u1ed9ng lo\u1ea1i b\u1ecf kho\u1ea3ng tr\u1eafng (trim) v\u00e0 chuy\u1ec3n v\u1ec1 in th\u01b0\u1eddng (lowercase).</li> <li><b>Auto Password:</b> N\u1ebfu kh\u00f4ng truy\u1ec1n password, h\u1ec7 th\u1ed1ng t\u1ef1 \u0111\u1ed9ng sinh v\u00e0 g\u1eedi v\u1ec1 email \u0111\u00e3 \u0111\u0103ng k\u00fd.</li> <li><b>Join Company:</b> N\u1ebfu email/S\u0110T \u0111\u00e3 t\u1ed3n t\u1ea1i, thay v\u00ec b\u00e1o l\u1ed7i, h\u1ec7 th\u1ed1ng cho ph\u00e9p th\u00eam t\u00e0i kho\u1ea3n \u0111\u00f3 v\u00e0o m\u1ed9t App (c\u00f4ng ty) m\u1edbi.</li> <li><b>B\u1ea3o v\u1ec7 ch\u1ed1ng Spam:</b> T\u00edch h\u1ee3p Rate limit d\u1ef1a tr\u00ean Cookie (uid) v\u00e0 IP \u0111\u1ec3 ng\u0103n ch\u1eb7n \u0111\u0103ng k\u00fd h\u00e0ng lo\u1ea1t.</li> </ul> </div> </div> `} <div style="margin-top:60px; border-top:1px solid #eee; padding-top:20px; text-align:center; color:#999; font-size:12px"> T\u00e0i li\u1ec7u API Core/Auth t\u1ef1 \u0111\u1ed9ng \u0111\u01b0\u1ee3c t\u1ea1o b\u1edfi h\u1ec7 th\u1ed1ng &copy; 2026 </div> </body> </html> `};module.exports={apiDocs,apiReport,apiAuth};