590 lines
22 KiB
HTML
590 lines
22 KiB
HTML
{include file="public/head"}
|
||
<style>
|
||
|
||
/* ---- Card ---- */
|
||
.lookup-card{
|
||
background:#fff;
|
||
border:1px solid rgba(0,0,0,.06);
|
||
box-shadow: 0 2px 10px rgba(0,0,0,.06);
|
||
border-radius: 6px;
|
||
margin: 18px 0 26px;
|
||
overflow:hidden;
|
||
max-width: 100%;
|
||
}
|
||
.lookup-bar{
|
||
background: var(--main-color);
|
||
color:#fff;
|
||
font-size: 24px;
|
||
font-weight: 900;
|
||
padding: 8px 16px;
|
||
line-height: 1.2;
|
||
}
|
||
.lookup-body{
|
||
padding: 18px 22px 8px;
|
||
}
|
||
|
||
/* ---- Form labels above ---- */
|
||
.label-above .layui-form-label{
|
||
display:block;
|
||
float:none;
|
||
width:auto !important;
|
||
text-align:left;
|
||
padding: 0 0 6px 0;
|
||
font-weight: 800;
|
||
font-size: 18px; /* PC 默认就用 18,避免过大 */
|
||
color:#3a3a3a;
|
||
}
|
||
.label-above .layui-form-label span{
|
||
color:#e53935;
|
||
margin-left:4px;
|
||
font-weight:900;
|
||
}
|
||
.layui-input-block{
|
||
margin-left:0;
|
||
min-height: auto;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* ---- Inputs ---- */
|
||
.layui-form input.layui-input{
|
||
height: 50px; /* 统一高度 */
|
||
border: 1px solid #d6d6d6;
|
||
border-radius: 2px;
|
||
padding: 10px 12px;
|
||
font-size: 14px; /* PC 默认 14 */
|
||
color:#333;
|
||
background:#fff;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* Layui date input background keep */
|
||
.layui-input-wrap .layui-input-prefix + .layui-input,
|
||
.layui-input-wrap .layui-input-prefix ~ * .layui-input{
|
||
background:#fff;
|
||
}
|
||
|
||
/* ---- Date prefix icon vertical align ---- */
|
||
.layui-input-wrap{
|
||
display: flex;
|
||
align-items: center; /* 关键:prefix 与 input 垂直居中 */
|
||
}
|
||
.layui-input-wrap .layui-input-prefix{
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 50px;
|
||
line-height: 50px;
|
||
}
|
||
|
||
/* ---- Help tip ---- */
|
||
.help-tip{
|
||
margin-top: 8px;
|
||
display:flex;
|
||
align-items:flex-start;
|
||
gap: 6px;
|
||
color:#666;
|
||
font-size: 13px;
|
||
line-height: 1.6;
|
||
}
|
||
.help-tip i{
|
||
font-size: 14px;
|
||
color:#333;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
/* ---- Button ---- */
|
||
.btn-row{ margin-top: 8px; }
|
||
|
||
.layui-btn{
|
||
background:#153854;
|
||
border:1px solid #153854;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,.35);
|
||
border-radius: 6px;
|
||
font-size: 20px;
|
||
font-weight: 900;
|
||
height: 50px;
|
||
line-height: 50px;
|
||
padding: 0 28px;
|
||
letter-spacing: .5px;
|
||
box-sizing: border-box;
|
||
}
|
||
.btn-fixed{
|
||
width: 520px;
|
||
max-width: 100%;
|
||
}
|
||
|
||
/* ---- Result area ---- */
|
||
#result{ padding: 0 22px 22px; }
|
||
.container-tit{
|
||
font-size: 18px;
|
||
font-weight: 900;
|
||
color:#153854;
|
||
margin: 12px 0 8px;
|
||
}
|
||
.container-con{
|
||
font-size: 14px;
|
||
color:#555;
|
||
margin-bottom: 12px;
|
||
}
|
||
.layui-table thead{
|
||
color:#fff;
|
||
background:#153854;
|
||
}
|
||
.layui-laydate .layui-this,
|
||
.layui-laydate .layui-this > div{
|
||
background-color:#153854 !important;
|
||
color:#fff !important;
|
||
}
|
||
|
||
/* ---- Prevent overflow caused by row negative margin / fixed width elements ---- */
|
||
.layui-row{
|
||
max-width: 100%;
|
||
box-sizing: border-box;
|
||
}
|
||
img, table, .layui-table-view{
|
||
max-width: 100% !important;
|
||
}
|
||
|
||
/* ===============================
|
||
Mobile adjustments
|
||
=============================== */
|
||
@media (max-width: 768px){
|
||
/* 容器左右留白,防止撑破 */
|
||
.layui-container{
|
||
padding-left: 12px !important;
|
||
padding-right: 12px !important;
|
||
}
|
||
|
||
/* row 可能有负 margin,清掉 */
|
||
.layui-row{
|
||
margin-left: 0 !important;
|
||
margin-right: 0 !important;
|
||
}
|
||
|
||
/* 卡片内部 padding 更紧凑 */
|
||
.lookup-bar{
|
||
font-size: 22px;
|
||
padding: 12px 14px;
|
||
}
|
||
.lookup-body{
|
||
padding: 14px 14px 6px;
|
||
}
|
||
|
||
.label-above .layui-form-label{
|
||
font-size: 18px;
|
||
}
|
||
|
||
.layui-form input.layui-input{
|
||
height: 50px;
|
||
font-size: 15px;
|
||
}
|
||
|
||
.layui-input-wrap .layui-input-prefix{
|
||
height: 50px;
|
||
line-height: 50px;
|
||
}
|
||
|
||
.layui-btn{
|
||
font-size: 22px;
|
||
height: 62px;
|
||
line-height: 62px;
|
||
width: 100%;
|
||
}
|
||
|
||
.layui-table-header{ display:none; }
|
||
}
|
||
|
||
/* ===============================
|
||
Desktop fine-tune (optional)
|
||
=============================== */
|
||
@media (min-width: 992px){
|
||
/* 大屏让卡片更像截图:稍微增加左右 padding */
|
||
.lookup-body{ padding: 18px 22px 8px; }
|
||
}
|
||
|
||
</style>
|
||
|
||
<body>
|
||
<div class="zh_content">
|
||
{include file="public/newnav" }
|
||
</div>
|
||
|
||
<div class="layui-container">
|
||
<div class="lookup-card">
|
||
<div class="lookup-bar">{:lang('lookup.status_query_title')}</div>
|
||
|
||
<div class="lookup-body">
|
||
<form class="layui-form label-above" lay-filter="Form1" id="Form1" autocomplete="off">
|
||
<div class="layui-row layui-col-space30" style="margin-top: 10px;">
|
||
|
||
<!-- 护照号 -->
|
||
<div class="layui-col-xs12 layui-col-md6">
|
||
<div class="layui-form-item">
|
||
<label class="layui-form-label" for="passport_number">
|
||
{:lang('lookup.passport_number')}<span>*</span>
|
||
</label>
|
||
<div class="layui-input-block passport-wrap">
|
||
<input type="text" name="passport_number" lay-verify="required"
|
||
placeholder="{:lang('lookup.passport_number_placeholder')}"
|
||
class="layui-input" value="">
|
||
<!-- 关键:给 file 一个 id,并隐藏 -->
|
||
<input id="passport_file" class="passport-file" type="file" accept="image/*"
|
||
onchange="uploadPassport(this,'passport')">
|
||
|
||
<!-- 关键:label 的 for 指向 file 的 id -->
|
||
<label class="passport-upload" for="passport_file" title="拍照/上传有效护照照片">
|
||
<i class="layui-icon layui-icon-camera"></i>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 出生日期 -->
|
||
<div class="layui-col-xs12 layui-col-md6">
|
||
<div class="layui-form-item">
|
||
<label class="layui-form-label" for="birth_date">
|
||
{:lang('lookup.birth_date')}<span>*</span>
|
||
</label>
|
||
<div class="layui-input-block">
|
||
<div class="layui-input-wrap">
|
||
<div class="layui-input-prefix">
|
||
<i class="layui-icon layui-icon-date"></i>
|
||
</div>
|
||
<input type="text" name="birth_date" id="birth_date" lay-verify="required"
|
||
placeholder="{:lang('lookup.birth_date_placeholder')}"
|
||
class="layui-input layui-time" value="">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 姓 -->
|
||
<div class="layui-col-xs12 layui-col-md6">
|
||
<div class="layui-form-item">
|
||
<label class="layui-form-label">{:lang('lookup.last_name')}<span>*</span></label>
|
||
<div class="layui-input-block">
|
||
<input type="text" name="last_name" lay-verify="required|english"
|
||
placeholder="{:lang('lookup.last_name_placeholder')}"
|
||
class="layui-input" value="">
|
||
<div class="help-tip">
|
||
<i class="layui-icon layui-icon-tips-fill"></i>
|
||
<span>{:lang('lookup.last_name_tooltip')}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 名 -->
|
||
<div class="layui-col-xs12 layui-col-md6">
|
||
<div class="layui-form-item">
|
||
<label class="layui-form-label">{:lang('lookup.first_name')}<span>*</span></label>
|
||
<div class="layui-input-block">
|
||
<input type="text" name="first_name" lay-verify="required|english"
|
||
placeholder="{:lang('lookup.first_name_placeholder')}"
|
||
class="layui-input" value="">
|
||
<div class="help-tip">
|
||
<i class="layui-icon layui-icon-tips-fill"></i>
|
||
<span>{:lang('lookup.first_name_tooltip')}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 按钮:半宽且不铺满 -->
|
||
<div class="layui-col-xs12 layui-col-md6 btn-row">
|
||
<div class="layui-form-item">
|
||
<div class="layui-input-block">
|
||
<button class="layui-btn btn-fixed" lay-submit lay-filter="formSubmit" id="submit">
|
||
{:lang('lookup.query_status_button')}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="layui-row container" style="display:none" id="result">
|
||
<div class="layui-col-xs12 layui-col-md12" style="display:none" id="result1">
|
||
<div class="container-tit">{:lang('lookup.registered_status')}</div>
|
||
<div class="container-con">{:lang('lookup.approval_message')}</div>
|
||
</div>
|
||
<div class="layui-col-xs12 layui-col-md12">
|
||
<table class="layui-hide" id="demo"></table>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
{include file="public/newfooter" }
|
||
|
||
<script>
|
||
var layer = layui.layer, form = layui.form, laydate = layui.laydate, table = layui.table;
|
||
|
||
var ocrConfigRaw = '{$ocr_config|default = ''}'.replace(/"/g, '"');
|
||
var ocrConfig = {};
|
||
var sdk = null;
|
||
try {
|
||
ocrConfig = ocrConfigRaw ? JSON.parse(ocrConfigRaw) : {};
|
||
} catch (e) {
|
||
console.error('Failed to parse OCR config', e);
|
||
}
|
||
if (window.PassportOCRSDK && ocrConfig.base_url && ocrConfig.app_id && ocrConfig.signature && ocrConfig.timestamp) {
|
||
try {
|
||
sdk = PassportOCRSDK.create({
|
||
apiBase: ocrConfig.base_url,
|
||
appId: ocrConfig.app_id,
|
||
sign: ocrConfig
|
||
});
|
||
} catch (e) {
|
||
console.error('Failed to init OCR sdk', e);
|
||
}
|
||
}
|
||
// 更稳的手机判断
|
||
function isMobile() {
|
||
return window.matchMedia && window.matchMedia('(max-width: 767.98px)').matches;
|
||
}
|
||
|
||
// 日期控件(建议固定格式)
|
||
$(".layui-form-item").find(".layui-time").each(function () {
|
||
laydate.render({
|
||
elem: this,
|
||
trigger: 'click',
|
||
format: 'yyyy-MM-dd'
|
||
});
|
||
});
|
||
|
||
// ✅兼容你 onchange 传了第二个参数
|
||
function uploadPassport(_this, type) {
|
||
var file = _this.files && _this.files[0];
|
||
var loadingIndex = null;
|
||
|
||
var closeLoading = function () {
|
||
if (loadingIndex !== null) {
|
||
layer.close(loadingIndex);
|
||
loadingIndex = null;
|
||
}
|
||
};
|
||
var resetFileInput = function () {
|
||
$(_this).val('');
|
||
};
|
||
|
||
if (!file) {
|
||
layer.msg('{:lang("controller.upload_missing")}', {icon: 5});
|
||
return false;
|
||
}
|
||
if (!/image\/\w+/.test(file.type || '')) {
|
||
layer.msg("{:lang('js.upload_image_only')}", {icon: 5});
|
||
return false;
|
||
}
|
||
if (!FileReader) {
|
||
layer.msg("{:lang('js.browser_not_supported')}", {icon: 5});
|
||
return false;
|
||
}
|
||
|
||
var url = "/home/upload/upload_passport";
|
||
loadingIndex = layer.load(2, {shade: 0.3});
|
||
compressImage(file, 0.2, async function (compressedFile) {
|
||
try {
|
||
if (!compressedFile) {
|
||
closeLoading();
|
||
resetFileInput();
|
||
layer.msg('{:lang("js.upload_retry")}', {icon: 5});
|
||
return false;
|
||
}
|
||
|
||
var ocrWarningMsg = '';
|
||
if (sdk) {
|
||
try {
|
||
var ocrData = await sdk.recognizePassport(compressedFile, {
|
||
auto_rotate: true,
|
||
return_debug: false
|
||
});
|
||
|
||
if (ocrData && ocrData.code === 1 && ocrData.data) {
|
||
var ocr = ocrData.data || {};
|
||
var pad2 = function (n) {
|
||
return String(n || '').padStart(2, '0');
|
||
};
|
||
var buildDate = function (y, m, d) {
|
||
if (!y || !m || !d) return '';
|
||
return y + '-' + pad2(m) + '-' + pad2(d);
|
||
};
|
||
|
||
$('input[name="last_name"]').val(ocr.last_name || '');
|
||
$('input[name="first_name"]').val(ocr.first_name || '');
|
||
$('input[name="passport_number"]').val(ocr.passport_number || '');
|
||
|
||
var birthDate = buildDate(ocr.birth_date_year, ocr.birth_date_month, ocr.birth_date_day);
|
||
if (birthDate) {
|
||
$('input[name="birth_date"]').val(birthDate);
|
||
}
|
||
} else {
|
||
ocrWarningMsg = '{:lang("js.manual_entry_required")}';
|
||
}
|
||
} catch (ocrErr) {
|
||
ocrWarningMsg = '{:lang("js.manual_entry_required")}';
|
||
}
|
||
} else {
|
||
ocrWarningMsg = '{:lang("js.manual_entry_required")}';
|
||
}
|
||
|
||
var formData = new FormData();
|
||
formData.append('file', compressedFile);
|
||
formData.append('path', 'thailand');
|
||
|
||
$.ajax({
|
||
url: url,
|
||
type: "post",
|
||
data: formData,
|
||
dataType: "json",
|
||
contentType: false,
|
||
processData: false,
|
||
mimeType: "multipart/form-data",
|
||
success: function (res) {
|
||
closeLoading();
|
||
resetFileInput();
|
||
if (res.code != 1) {
|
||
//layer.msg('{:lang("js.manual_entry_required")}', {icon: 5});
|
||
//return;
|
||
}
|
||
},
|
||
error: function () {
|
||
closeLoading();
|
||
resetFileInput();
|
||
//layer.msg('{:lang("js.manual_entry_required")}', {icon: 5});
|
||
}
|
||
});
|
||
if (ocrWarningMsg) {
|
||
layer.msg(ocrWarningMsg, {icon: 5});
|
||
}
|
||
} catch (e) {
|
||
closeLoading();
|
||
resetFileInput();
|
||
layer.msg('{:lang("js.manual_entry_required")}', {icon: 5});
|
||
}
|
||
});
|
||
}
|
||
function compressImage(file, quality, callback) {
|
||
const reader = new FileReader();
|
||
reader.readAsDataURL(file);
|
||
reader.onload = function (event) {
|
||
const img = new Image();
|
||
img.src = event.target.result;
|
||
img.onload = function () {
|
||
const canvas = document.createElement('canvas');
|
||
const ctx = canvas.getContext('2d');
|
||
let maxWidth = 1200;
|
||
let width = img.width;
|
||
let height = img.height;
|
||
if (width > maxWidth) {
|
||
height *= maxWidth / width;
|
||
width = maxWidth;
|
||
}
|
||
canvas.width = width;
|
||
canvas.height = height;
|
||
ctx.drawImage(img, 0, 0, width, height);
|
||
canvas.toBlob(function (blob) {
|
||
const newFile = new File([blob], file.name, { type: file.type });
|
||
callback(newFile);
|
||
}, file.type, quality);
|
||
};
|
||
};
|
||
}
|
||
|
||
// 监听提交
|
||
form.on('submit(formSubmit)', function (data) {
|
||
$('#result').hide();
|
||
$('#result1').hide();
|
||
|
||
$.ajax({
|
||
type: "POST",
|
||
url: "/home/lookup/enrollment",
|
||
data: data.field,
|
||
beforeSend: function () {
|
||
window.index1 = layer.load(1, {shade: [0.3, '#fff']});
|
||
},
|
||
success: function (_data) {
|
||
layer.close(window.index1);
|
||
|
||
if (_data.code == 0) {
|
||
layer.msg(_data.msg, {icon: 5});
|
||
return;
|
||
}
|
||
|
||
$('#result').show();
|
||
var row = _data.data || {};
|
||
var hasFile = !!(row.file_url && row.file_url !== '');
|
||
|
||
if (isMobile()) {
|
||
// 手机:字段-值
|
||
var mobileData = [
|
||
{field: '{:lang("lookup.passport_number")}', value: row.passport_number || ''},
|
||
{field: '{:lang("lookup.birth_date")}', value: row.birth_date || ''},
|
||
{field: '{:lang("lookup.last_name")}', value: row.last_name || ''},
|
||
{field: '{:lang("lookup.first_name")}', value: row.first_name || ''},
|
||
{field: hasFile ? '{:lang("lookup.document")}' : '{:lang("lookup.status")}', value: row.file_url || ''}
|
||
];
|
||
|
||
if (hasFile) $('#result1').show();
|
||
|
||
table.render({
|
||
elem: '#demo',
|
||
data: mobileData,
|
||
cols: [[
|
||
{field:'field', title:'{:lang("lookup.field")}', width:110},
|
||
{
|
||
field:'value',
|
||
title:'{:lang("lookup.value")}',
|
||
templet: function(d){
|
||
if (d.field === '{:lang("lookup.document")}') {
|
||
return '<a href="'+ row.file_url +'?'+ Math.random() +'" target="_blank"><img src="/static/image/pdf.png" alt="{:lang("lookup.click_download")}"></a>';
|
||
}
|
||
if (d.field === '{:lang("lookup.status")}') {
|
||
return '{:lang("lookup.in_progress")}';
|
||
}
|
||
return d.value;
|
||
}
|
||
}
|
||
]]
|
||
});
|
||
|
||
} else {
|
||
if (hasFile) $('#result1').show();
|
||
|
||
table.render({
|
||
elem: '#demo',
|
||
data: [row],
|
||
cols: [[
|
||
{field:'last_name', title:'{:lang("lookup.last_name")}', width:200},
|
||
{field:'first_name', title:'{:lang("lookup.first_name")}', width:200},
|
||
{field:'birth_date', title:'{:lang("lookup.birth_date")}', width:200},
|
||
{field:'passport_number', title:'{:lang("lookup.passport_number")}'},
|
||
{
|
||
field:'file_url',
|
||
title: hasFile ? '{:lang("lookup.document")}' : '{:lang("lookup.status")}',
|
||
templet: function(){
|
||
if (hasFile) {
|
||
return '<a href="'+ row.file_url +'?'+ Math.random() +'" target="_blank"><img src="/static/image/pdf.png" alt="{:lang("lookup.click_download")}"></a>';
|
||
}
|
||
return '{:lang("lookup.in_progress")}';
|
||
}
|
||
}
|
||
]]
|
||
});
|
||
}
|
||
}
|
||
});
|
||
|
||
return false;
|
||
});
|
||
|
||
form.verify({
|
||
english: [/^[A-Za-z]+$/, '{:lang("lookup.english_only")}']
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|