初始化 EVUS 项目并统一首页及业务页面样式

This commit is contained in:
gaofeng
2026-10-30 13:31:25 +08:00
commit 74f9f2b228
1840 changed files with 303475 additions and 0 deletions

10
.example.env Normal file
View File

@@ -0,0 +1,10 @@
APP_DEBUG = true
DB_TYPE = mysql
DB_HOST = 127.0.0.1
DB_NAME = test
DB_USER = username
DB_PASS = password
DB_PORT = 3306
DB_CHARSET = utf8
DEFAULT_LANG = zh-cn

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
/.idea
/doc
/runtime
/data
/.codegraph
/.serena

0
.htaccess Normal file
View File

42
.travis.yml Normal file
View File

@@ -0,0 +1,42 @@
sudo: false
language: php
branches:
only:
- stable
cache:
directories:
- $HOME/.composer/cache
before_install:
- composer self-update
install:
- composer install --no-dev --no-interaction --ignore-platform-reqs
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip .
- composer require --update-no-dev --no-interaction "topthink/think-image:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0"
- composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0"
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip .
script:
- php think unit
deploy:
provider: releases
api_key:
secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=
file:
- ThinkPHP_Core.zip
- ThinkPHP_Full.zip
skip_cleanup: true
on:
tags: true

32
LICENSE.txt Normal file
View File

@@ -0,0 +1,32 @@
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
版权所有Copyright © 2006-2025 by ThinkPHP (http://thinkphp.cn)
All rights reserved。
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
Apache Licence是著名的非盈利开源组织Apache采用的协议。
该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
允许代码修改,再作为开源或商业软件发布。需要满足
的条件:
1. 需要给代码的用户一份Apache Licence ;
2. 如果你修改了代码,需要在被修改的文件中说明;
3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
带有原来代码中的协议,商标,专利声明和其他原来作者规
定需要包含的说明;
4. 如果再发布的产品中包含一个Notice文件,则在Notice文
件中需要带有本协议内容。你可以在Notice中增加自己的
许可,但不可以表现为对Apache Licence构成更改。
具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

92
README.md Normal file
View File

@@ -0,0 +1,92 @@
![](https://www.thinkphp.cn/uploads/images/20230630/300c856765af4d8ae758c503185f8739.png)
ThinkPHP 8
===============
## 当前项目本地运行
在项目的 `public` 目录启动完整应用,首页及菜单内页都通过 ThinkPHP 路由访问:
```powershell
Set-Location D:\itswork\evus.acvisa.com\public
& 'D:\ruanjian\phpstudy\Extensions\php\php8.2.9nts\php.exe' -S 127.0.0.1:8765 -t . router.php
```
打开 `http://127.0.0.1:8765/`。如果该端口已有本项目服务运行,直接访问即可。
站点配置域名在 `app/home/controller/Base.php` 中指定,当前使用 `evus.acvisa.cn`。首次访问会获取配置并缓存到已忽略版本控制的 `data/config.json`;修改配置域名后需同步刷新该缓存。
`runtime/preview-router.php` 仅用于首页静态样式预览,不提供登记、查询、登录等菜单页面。需要浏览完整网站时,请使用上面的正式应用入口。完整应用会连接已配置的业务后台,本地测试不要提交真实登记或支付。
## 特性
* 基于PHP`8.0+`重构
* 升级`PSR`依赖
* 依赖`think-orm`3.0+版本
* 全新的`think-dumper`服务,支持远程调试
* 支持`6.0`/`6.1`无缝升级
> ThinkPHP8的运行环境要求PHP8.0+
现在开始,你可以使用官方提供的[ThinkChat](https://chat.topthink.com/),让你在学习ThinkPHP的旅途中享受私人AI助理服务!
![](https://www.topthink.com/uploads/assistant/20230630/4d1a3f0ad2958b49bb8189b7ef824cb0.png)
ThinkPHP生态服务由[顶想云](https://www.topthink.com)(TOPThink Cloud)提供,为生态提供专业的开发者服务和价值之选。
## 文档
[完全开发手册](https://doc.thinkphp.cn)
## 赞助
全新的[赞助计划](https://www.thinkphp.cn/sponsor)可以让你通过我们的网站、手册、欢迎页及GIT仓库获得巨大曝光,同时提升企业的品牌声誉,也更好保障ThinkPHP的可持续发展。
[![](https://www.thinkphp.cn/sponsor/special.svg)](https://www.thinkphp.cn/sponsor/special)
[![](https://www.thinkphp.cn/sponsor.svg)](https://www.thinkphp.cn/sponsor)
## 安装
~~~
composer create-project topthink/think tp
~~~
启动服务
~~~
cd tp
php think run
~~~
然后就可以在浏览器中访问
~~~
http://localhost:8000
~~~
如果需要更新框架使用
~~~
composer update topthink/framework
~~~
## 命名规范
`ThinkPHP`遵循PSR-2命名规范和PSR-4自动加载规范。
## 参与开发
直接提交PR或者Issue即可
## 版权信息
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
本项目包含的第三方源码和二进制文件之版权信息另行标注。
版权所有Copyright © 2006-2024 by ThinkPHP (http://thinkphp.cn) All rights reserved。
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
更多细节参阅 [LICENSE.txt](LICENSE.txt)

1
app/.htaccess Normal file
View File

@@ -0,0 +1 @@
deny from all

22
app/AppService.php Normal file
View File

@@ -0,0 +1,22 @@
<?php
declare (strict_types = 1);
namespace app;
use think\Service;
/**
* 应用服务类
*/
class AppService extends Service
{
public function register()
{
// 服务注册
}
public function boot()
{
// 服务启动
}
}

94
app/BaseController.php Normal file
View File

@@ -0,0 +1,94 @@
<?php
declare (strict_types = 1);
namespace app;
use think\App;
use think\exception\ValidateException;
use think\Validate;
/**
* 控制器基础类
*/
abstract class BaseController
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中间件
* @var array
*/
protected $middleware = [];
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, string|array $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
[$validate, $scene] = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
return $v->failException(true)->check($data);
}
}

58
app/ExceptionHandle.php Normal file
View File

@@ -0,0 +1,58 @@
<?php
namespace app;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Response;
use Throwable;
/**
* 应用异常处理类
*/
class ExceptionHandle extends Handle
{
/**
* 不需要记录信息(日志)的异常类列表
* @var array
*/
protected $ignoreReport = [
HttpException::class,
HttpResponseException::class,
ModelNotFoundException::class,
DataNotFoundException::class,
ValidateException::class,
];
/**
* 记录异常信息(包括日志或者其它方式记录)
*
* @access public
* @param Throwable $exception
* @return void
*/
public function report(Throwable $exception): void
{
// 使用内置的方式记录异常日志
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @access public
* @param \think\Request $request
* @param Throwable $e
* @return Response
*/
public function render($request, Throwable $e): Response
{
// 添加自定义异常处理机制
// 其他错误交给系统处理
return parent::render($request, $e);
}
}

8
app/Request.php Normal file
View File

@@ -0,0 +1,8 @@
<?php
namespace app;
// 应用请求对象类
class Request extends \think\Request
{
}

20
app/common.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
// 应用公共文件
use api\Httpcurl;
use think\facade\Db;
const DOMAIN = 'www.evus.cn';
/**
* 发给py进行提交注册
*/
function evusSubmit($order_sn)
{
$data = DB::name('msg')->where(['order_sn' => $order_sn])->where('order_status','in',[1, 3])->find();
if (empty($data)) {
return;
}
$url = 'https://manage.evus.cn/home.php?s=msg/send/id/' . $data['id'] . '.html';
Httpcurl::request($url, 'get', '', [], 3);
return;
}

17
app/event.php Normal file
View File

@@ -0,0 +1,17 @@
<?php
// 事件定义文件
return [
'bind' => [
],
'listen' => [
'AppInit' => [],
'HttpRun' => [],
'HttpEnd' => [],
'LogLevel' => [],
'LogWrite' => [],
],
'subscribe' => [
],
];

575
app/home/common.php Normal file
View File

@@ -0,0 +1,575 @@
<?php
const GET_WEB_CONFIG_URL = 'https://uniuser.jzvisa.com/home/Company/index/model/evus';
const CREATE_EVUS_ORDER_URL = 'https://uniuser.jzvisa.com/home/order/applyevus';
const UPDATE_EVUS_ORDER_URL = 'https://uniuser.jzvisa.com/home/order/updateevus';
const CREATE_ORDER_URL = 'https://uniuser.jzvisa.com/home/order/do_apply';
const NEWS_LIST = 'https://uniuser.jzvisa.com/home/news/lists';
const NEWS_DETAIL = 'https://uniuser.jzvisa.com/home/news/detail';
const YZM_URL = 'https://uniuser.jzvisa.com/home/sms/sendCode';
const GET_ORDER_URL = 'https://uniuser.jzvisa.com/home/order/orderList';
const INCOICETYPE = '1';
const MODEL = 'msg';
const BUCKET = 'jnevus';
const COUNTRY = 'EVUS登记';
const SOURCE = 'cn';
const PAY_MARK = 'evuscn';
const OSS_URL = 'https://files.jzvisa.com/' . BUCKET . '/';
/*esta 配置*/
const ESTA_COUNTRY = 'ESTA登记';
const PAY_ESTA_MARK = 'estacn';
const ESTA_MODEL = 'esta';
const ESTA_INCOICETYPE = '6';
// 公共函数
function formDataToJson($fields, $postData, $kew_key, $checkField)
{
if (!isset($postData[$checkField]) || $postData[$checkField] != 1) {
foreach ($fields as $field) {
unset($postData[$field]);
}
return $postData;
}
$data = [];
foreach ($postData[$fields[0]] as $index => $value) {
$entry = [];
foreach ($fields as $field) {
$entry[$field] = isset($postData[$field][$index]) ? $postData[$field][$index] : null;
}
$data[] = $entry;
}
$postData[$kew_key] = json_encode($data, JSON_UNESCAPED_UNICODE);
foreach ($fields as $field) {
unset($postData[$field]);
}
return $postData;
}
function find_json($json_name, $field, $field_value)
{
$data = file_get_contents($json_name);
$data_arr = json_decode($data, true);
$found = array_filter($data_arr, function ($item) use ($field, $field_value) {
return $item[$field] === $field_value;
});
// 输出结果
if ($found) {
$found = array_values($found); // 获取过滤后的第一个元素
return $found;
} else {
return false;
}
}
function getNameById($json_name, $id)
{
$data = file_get_contents('./json/' . $json_name . '.json');
$data_arr = json_decode($data, true);
foreach ($data_arr as $item) {
if (array_key_exists('data', $item['data'])) {
foreach ($item['data']['data'] as $dataItem) {
if ($dataItem['id'] === $id) {
return $dataItem['name'];
}
}
}
}
return null;
}
function getIdByName($json_name, $id)
{
$data = file_get_contents('./json/' . $json_name . '.json');
$data_arr = json_decode($data, true);
foreach ($data_arr as $item) {
if (array_key_exists('data', $item['data'])) {
foreach ($item['data']['data'] as $dataItem) {
if ($dataItem['name'] === $id) {
return $dataItem['id'];
}
}
}
}
return null;
}
function isMobile()
{
$_SERVER['ALL_HTTP'] = isset($_SERVER['ALL_HTTP']) ? $_SERVER['ALL_HTTP'] : '';
if (preg_match('/(up.browser|up.link|mmp|symbian|smartphone|midp|wap|phone|iphone|ipad|ipod|android|xoom)/i',
strtolower($_SERVER['HTTP_USER_AGENT']))) {
return true;
}
if ((isset($_SERVER['HTTP_ACCEPT'])) and (strpos(strtolower($_SERVER['HTTP_ACCEPT']),
'application/vnd.wap.xhtml+xml') !== false)) {
return true;
}
if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
return true;
}
if (isset($_SERVER['HTTP_PROFILE'])) {
return true;
}
$mobile_ua = strtolower(substr($_SERVER['HTTP_USER_AGENT'], 0, 4));
$mobile_agents = array(
'w3c ',
'acs-',
'alav',
'alca',
'amoi',
'audi',
'avan',
'benq',
'bird',
'blac',
'blaz',
'brew',
'cell',
'cldc',
'cmd-',
'dang',
'doco',
'eric',
'hipt',
'inno',
'ipaq',
'java',
'jigs',
'kddi',
'keji',
'leno',
'lg-c',
'lg-d',
'lg-g',
'lge-',
'maui',
'maxo',
'midp',
'mits',
'mmef',
'mobi',
'mot-',
'moto',
'mwbp',
'nec-',
'newt',
'noki',
'oper',
'palm',
'pana',
'pant',
'phil',
'play',
'port',
'prox',
'qwap',
'sage',
'sams',
'sany',
'sch-',
'sec-',
'send',
'seri',
'sgh-',
'shar',
'sie-',
'siem',
'smal',
'smar',
'sony',
'sph-',
'symb',
't-mo',
'teli',
'tim-',
'tosh',
'tsm-',
'upg1',
'upsi',
'vk-v',
'voda',
'wap-',
'wapa',
'wapi',
'wapp',
'wapr',
'webc',
'winw',
'winw',
'xda',
'xda-'
);
if (in_array($mobile_ua, $mobile_agents)) {
return true;
}
if (strpos(strtolower($_SERVER['ALL_HTTP']), 'operamini') !== false) {
return true;
}
// Pre-final check to reset everything if the user is on Windows
if (strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'windows') !== false) {
return false;
}
// But WP7 is also Windows, with a slightly different characteristic
if (strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'windows phone') !== false) {
return true;
}
return false;
}
function getOrderNumber()
{
return date('YmdHis') . mt_rand(10, 99);
}
function cmf_get_current_user_id()
{
$sessionUserId = session('user.id');
if (empty($sessionUserId)) {
return 0;
}
return $sessionUserId;
}
function getIP()
{
$realip = '';
$unknown = 'unknown';
if (isset($_SERVER)){
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], $unknown)){
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach($arr as $ip){
$ip = trim($ip);
if ($ip != 'unknown'){
$realip = $ip;
break;
}
}
}else if(isset($_SERVER['HTTP_CLIENT_IP']) && !empty($_SERVER['HTTP_CLIENT_IP']) && strcasecmp($_SERVER['HTTP_CLIENT_IP'], $unknown)){
$realip = $_SERVER['HTTP_CLIENT_IP'];
}else if(isset($_SERVER['REMOTE_ADDR']) && !empty($_SERVER['REMOTE_ADDR']) && strcasecmp($_SERVER['REMOTE_ADDR'], $unknown)){
$realip = $_SERVER['REMOTE_ADDR'];
}else{
$realip = $unknown;
}
}else{
if(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), $unknown)){
$realip = getenv("HTTP_X_FORWARDED_FOR");
}else if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), $unknown)){
$realip = getenv("HTTP_CLIENT_IP");
}else if(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), $unknown)){
$realip = getenv("REMOTE_ADDR");
}else{
$realip = $unknown;
}
}
$realip = preg_match("/[\d\.]{7,15}/", $realip, $matches) ? $matches[0] : $unknown;
return $realip;
}
function build_ocr_signature(string $appId, string $secret, ?int $timestamp = null): array
{
$timestamp = $timestamp ?? time();
$signString = $appId . "\n" . (string)$timestamp;
$signature = hash_hmac('sha256', $signString, $secret);
return [
'app_id' => $appId,
'timestamp' => (string)$timestamp,
'signature' => $signature,
'base_url' => config('app.OCR_BASE_URL'),
];
}
// 这是系统自动生成的公共文件
function arrayToJson($params, $values)
{
$datas = [];
$count = count($values[0]);
$valcount = count($params);
for ($i = 0; $i < $count; $i++) {
for ($j = 0; $j < $valcount; $j++) {
$data[$params[$j]] = $values[$j][$i];
}
$datas[] = $data;
}
if (empty($datas)) {
return '';
}
return json_encode($datas);
}
function getCate($val)
{
$cates = explode('-', $val);
if (count($cates) == 1) {
if ($val == 'CNMI') {
return 'CW/E2C';
}
} else {
preg_match_all('/[A-Z]+/', $val, $matches);
return $matches[0][0];
}
}
//非常给力的authcode加密函数,Discuz!经典代码(带详解)
function authcode($string, $operation = 'DECODE', $key = '20241021', $expiry = 0)
{
// 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙
$ckey_length = 4;
// 密匙
$key = md5($key ? $key : $GLOBALS['discuz_auth_key']);
// 密匙a会参与加解密
$keya = md5(substr($key, 0, 16));
// 密匙b会用来做数据完整性验证
$keyb = md5(substr($key, 16, 16));
// 密匙c用于变化生成的密文
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
// 参与运算的密匙
$cryptkey = $keya . md5($keya . $keyc);
$key_length = strlen($cryptkey);
// 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),
//解密时会通过这个密匙验证数据完整性
// 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
// 产生密匙簿
for ($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
// 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度
for ($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
// 核心加解密部分
for ($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
// 从密匙簿得出密匙进行异或,再转成字符
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if ($operation == 'DECODE') {
// 验证数据有效性,请看未加密明文的格式
if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
// 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因
// 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码
return $keyc . str_replace('=', '', base64_encode($result));
}
}
function getChineseCode($code)
{
$url = "http://code.mcdvisa.com/save.php?action=getcode&i=0&w={$code}";
$data = file_get_contents($url);
if (empty($data)){
return [
'code'=>0,
'data'=>[]
];
}
// 创建 DOMDocument 对象并加载 HTML
$dom = new DOMDocument();
libxml_use_internal_errors(true); // 抑制 HTML 解析错误
$dom->loadHTML($data);
libxml_clear_errors();
// 获取所有的 <li> 元素
$lis = $dom->getElementsByTagName('li');
$pattern = '/-?\d+(?:\.\d+)?/';
$datas=[];
foreach ($lis as $li) {
$text = $li->textContent;
preg_match_all($pattern, $text, $matches);
$datas[] = $matches[0][0];
}
return [
'code'=>200,
'data'=>$datas
];
}
/**
* 查询姓名电码。
* @param string $fullName 中文全名
* @param int $surnameLength 姓氏字数:单姓 1,复姓 2
* 依赖第三方网页结构;失败时抛出异常,由调用方转换为用户提示。
*/
function queryNameTelecode(string $fullName, int $surnameLength = 1): array
{
$fullName = trim($fullName);
$length = mb_strlen($fullName, 'UTF-8');
if (!preg_match('/^\p{Han}+$/u', $fullName) || $length > 8) {
throw new InvalidArgumentException('请输入不超过 8 个汉字的姓名');
}
if ($surnameLength < 1 || $surnameLength >= $length) {
throw new InvalidArgumentException('姓氏字数必须小于姓名总字数');
}
if (!extension_loaded('curl') || !extension_loaded('dom')) {
throw new RuntimeException('电码查询服务未就绪,请手动填写或联系管理员');
}
$url = 'https://apps.chasedream.com/chinese-commercial-code/';
// 两次请求共用一个时间预算,避免每次都等待完整超时时间。
$deadline = hrtime(true) + 15 * 1000000000;
$curl = curl_init($url);
if ($curl === false) {
throw new RuntimeException('无法初始化 cURL');
}
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_TIMEOUT => 15,
CURLOPT_COOKIEFILE => '', // 内存 Cookie,会话内复用
CURLOPT_USERAGENT => 'NameTelecodeLookup/1.0',
// 协商压缩响应并自动解压,减少两次查询的网络传输量。
CURLOPT_ENCODING => '',
]);
$request = static function () use ($curl, $deadline): string {
$remainingMs = (int) floor(($deadline - hrtime(true)) / 1000000);
if ($remainingMs <= 0) {
throw new RuntimeException('电码查询超时,请稍后重试或手动填写');
}
curl_setopt($curl, CURLOPT_TIMEOUT_MS, $remainingMs);
$html = curl_exec($curl);
if ($html === false) {
throw new RuntimeException('电码查询连接失败或超时,请稍后重试或手动填写');
}
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($status !== 200) {
throw new RuntimeException('电码查询服务暂时不可用,请稍后重试或手动填写');
}
if (trim($html) === '') {
throw new RuntimeException('电码查询返回空内容,请稍后重试或手动填写');
}
return $html;
};
$parse = static function (string $html): DOMXPath {
$previous = libxml_use_internal_errors(true);
try {
$dom = new DOMDocument();
if (!$dom->loadHTML('<?xml encoding="UTF-8">' . $html)) {
throw new RuntimeException('无法解析网页');
}
return new DOMXPath($dom);
} finally {
libxml_clear_errors();
libxml_use_internal_errors($previous);
}
};
try {
// 获取本次页面的动态隐藏字段。
$xpath = $parse($request());
$payload = [];
foreach ($xpath->query(
'//form[@id="form1"]//input[@type="hidden"][@name]'
) as $input) {
$payload[$input->getAttribute('name')] =
$input->getAttribute('value');
}
if (!isset($payload['__VIEWSTATE'])) {
throw new RuntimeException('查询页面结构发生变化');
}
$payload['txtInput'] = $fullName;
$payload['btnSearch'] = '查询';
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($payload),
CURLOPT_REFERER => $url,
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded',
],
]);
$xpath = $parse($request());
$mapping = [];
// 只接受“一个汉字 + 一个四位电码”的结果行。
foreach ($xpath->query('//table[@id="grvDict"]//tr') as $row) {
$characters = [];
$codes = [];
foreach ($xpath->query('./td', $row) as $cell) {
$text = trim($cell->textContent);
if (preg_match('/^\p{Han}$/u', $text)) {
$characters[] = $text;
} elseif (preg_match('/^[0-9]{4}$/', $text)) {
$codes[] = $text;
}
}
if (count($characters) === 1 && count($codes) === 1) {
$character = $characters[0];
$code = $codes[0];
if (isset($mapping[$character])
&& $mapping[$character] !== $code) {
throw new RuntimeException("“{$character}”返回多个电码");
}
$mapping[$character] = $code;
}
}
$characters = preg_split('//u', $fullName, -1, PREG_SPLIT_NO_EMPTY);
$codes = [];
foreach ($characters as $character) {
if (!isset($mapping[$character])) {
throw new RuntimeException(
"未取得“{$character}”的电码,请人工核实或检查网页结构"
);
}
$codes[] = $mapping[$character];
}
return [
'full_name' => $fullName,
'surname' => mb_substr($fullName, 0, $surnameLength, 'UTF-8'),
'given_name' => mb_substr($fullName, $surnameLength, null, 'UTF-8'),
'surname_code' => implode('', array_slice($codes, 0, $surnameLength)),
'given_name_code' => implode('', array_slice($codes, $surnameLength)),
'full_code' => implode('', $codes),
'characters' => $mapping,
];
} finally {
curl_close($curl);
}
}

View File

@@ -0,0 +1,165 @@
<?php
declare (strict_types=1);
namespace app\home\controller;
use api\Httpcurl;
use app\BaseController;
use app\service\SeoMetaService;
use think\facade\Config;
use think\facade\Cookie;
use think\facade\Lang;
use think\facade\Session;
use think\facade\View;
use think\facade\Request;
/**
* 控制器基础类
*/
class Base extends BaseController
{
protected $_userId;
/**
* 构造方法
*/
public function initialize()
{
parent::initialize();
// 来源
$source = Request::instance()->param('source', '');
$sesson = Session::get('source');
if (empty($sesson)) {
$source = $source ?: SOURCE;
Session::set('source', $source);
}
// 获取 当前用户ID
$this->_userId = cmf_get_current_user_id();
// 网站配置信息获取
if (!file_exists(app()->getRootPath().'data/config.json')) {
// $domain = $_SERVER['HTTP_HOST'];
$domain = "evus.acvisa.cn";
$web_config = Httpcurl::request(GET_WEB_CONFIG_URL . '/domain/' . $domain, 'get');
if ($web_config[3]) {
abort(500, '网站配置信息获取失败');
}
$config_result = json_decode($web_config[0], true);
if (empty($config_result)) {
abort(500, '网站配置信息获取失败');
}
if ($config_result['code'] != 1) {
abort(500, '网站配置信息获取失败');
}
file_put_contents(app()->getRootPath().'data/config.json', json_encode($config_result));
} else {
$config_result = json_decode(file_get_contents(app()->getRootPath().'data/config.json'), true);
}
Config::set(['domain' => $_SERVER['HTTP_HOST']], 'app');
Config::set(['EVUS_GOODS' => $config_result['data']['EVUS_GOODS']], 'app');
Config::set(['ESTA_GOODS' => $config_result['data']['ESTA_GOODS']], 'app');
/*语言切换*/
Lang::setLangSet(Cookie::get('think_var', 'zh-cn'));
/*语言切换*/
/*配置*/
Config::set(['wechatpay' => $config_result['data']['pay']['wechatpay']], 'app');
Config::set(['wechath5pay' => $config_result['data']['pay']['wechath5pay']], 'app');
Config::set(['wechatpcpay' => $config_result['data']['pay']['wechatpcpay']], 'app');
Config::set(['alipcpay' => $config_result['data']['pay']['alipcpay']], 'app');
Config::set(['pay_url' => $config_result['data']['pay']['pay_url']], 'app');
Config::set(['order_url' => $config_result['data']['order_url']], 'app');
Config::set(['user_url' => $config_result['data']['user_url']], 'app');
Config::set(['principals' => $config_result['data']['principals']], 'app');
Config::set(['get_evus_detail_url' => $config_result['data']['get_evus_detail_url']], 'app');
Config::set(['get_order_detail_url' => $config_result['data']['get_order_detail_url']], 'app');
Config::set(['download_evus_url' => $config_result['data']['download_evus_url']], 'app');
Config::set(['update_order_url' => $config_result['data']['update_order_url']], 'app');
/*ocr 识别 配置参数 */
Config::set(['OCR_BASE_URL' => $config_result['data']['ocr_base_url']], 'app');
Config::set(['OCR_APP_ID' => $config_result['data']['ocr_app_id']], 'app');
Config::set(['OCR_SECRET' => $config_result['data']['ocr_secret']], 'app');
Config::set(['LOOKUP_URL' => $config_result['data']['evus_look_url']], 'app');
$ocr_config = build_ocr_signature($config_result['data']['ocr_app_id'], $config_result['data']['ocr_secret']);
View::assign('ocr_config', json_encode($ocr_config));
View::assign('footer', $config_result['data']['footer']);
View::assign('phone', $config_result['data']['phone']);
View::assign('logo_icon', $config_result['data']['logo_icon']);
View::assign('logo', $config_result['data']['logo']);
View::assign('fapiao_kefu', $config_result['data']['fapiao_png']);
View::assign('order_kefu', $config_result['data']['visa_png']);
View::assign('invoice_url', $config_result['data']['invoice_url']);
View::assign('menu_url', strtolower(Request::controller() . '/' . Request::action()));
$this->assignSeo();
}
protected function assignSeo(array $overrides = []): void
{
$query = Request::instance()->get();
if (!is_array($query)) {
$query = [];
}
$seo = (new SeoMetaService())->forRoute(
'home',
(string) Request::controller(),
(string) Request::action(),
$query,
$overrides
);
View::assign('seo', $seo);
View::assign('asset_version', (string) (config('app.asset_version') ?: '1'));
}
public function success($msg = '操作成功', $url = '', $data = [], $wait = 3)
{
if (is_null($url) && isset($_SERVER["HTTP_REFERER"])) {
$url = $_SERVER["HTTP_REFERER"];
} elseif ('' !== $url && is_object($url)) {
$url = $url->build();
}
if (request()->isAjax()) {
return json([
'code' => 1,
'msg' => $msg,
'data' => $data,
'url' => $url
]);
} else {
return View::fetch('public/jump', [
'msg' => $msg,
'url' => $url,
'wait' => $wait,
'type' => 'success',
]);
}
}
public function error($msg = '操作失败', $url = '', $wait = 3, $data = [])
{
if (is_null($url) && isset($_SERVER["HTTP_REFERER"])) {
$url = $_SERVER["HTTP_REFERER"];
} elseif ('' !== $url && is_object($url)) {
$url = $url->build();
}
if (request()->isAjax()) {
return json([
'code' => 0,
'msg' => $msg,
'data' => $data,
'url' => $url
]);
} else {
return View::fetch('public/jump', [
'msg' => $msg,
'url' => $url,
'wait' => $wait,
'type' => 'error',
]);
}
}
}

View File

@@ -0,0 +1,14 @@
<?php
declare (strict_types=1);
namespace app\home\controller;
use think\facade\View;
class Company extends Base
{
public function index()
{
return View::fetch();
}
}

View File

@@ -0,0 +1,211 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\facade\Log;
use think\facade\Request;
use think\facade\Session;
use think\facade\View;
class Detail extends Base
{
public function index()
{
View::assign('country_list', json_decode(file_get_contents('./json/country.json'), true));
View::assign('phone_prefix', json_decode(file_get_contents('./json/phone_prefix.json'), true));
View::assign('us', json_decode(file_get_contents('./json/us.json'), true));
View::assign('goods', config('app.EVUS_GOODS'));
View::assign('ismobile', isMobile() ? 1 : 0);
return View::fetch();
}
public function do_apply()
{
unset($_REQUEST['s']);
$order_sn = $_REQUEST['order_sn'] = getOrderNumber();
$total_price = $_REQUEST['total_price'];
/*判断价格是否正确*/
$config_price = array_map(function($item) {
return $item['value'];
}, config('app.EVUS_GOODS'));
if (!in_array($total_price, $config_price)) {
return $this->error('价格错误');
}
/*判断价格是否正确*/
$_REQUEST['birth_date_day'] = (string)date_parse($_REQUEST['birth_date'])['day'] ?:'0';
$_REQUEST['birth_date_month'] = (string)date_parse($_REQUEST['birth_date'])['month'] ?:'0';
$_REQUEST['birth_date_year'] = (string)date_parse($_REQUEST['birth_date'])['year'] ?:'0';
$_REQUEST['passport_expedition_date_day'] = (string)date_parse($_REQUEST['passport_expedition_date'])['day'] ?:'';
$_REQUEST['passport_expedition_date_month'] = (string)date_parse($_REQUEST['passport_expedition_date'])['month'] ?:'';
$_REQUEST['passport_expedition_date_year'] = (string)date_parse($_REQUEST['passport_expedition_date'])['year'] ?:'';
$_REQUEST['passport_expiration_date_day'] = (string)date_parse($_REQUEST['passport_expiration_date'])['day'] ?:'';
$_REQUEST['passport_expiration_date_month'] = (string)date_parse($_REQUEST['passport_expiration_date'])['month'] ?:'';
$_REQUEST['passport_expiration_date_year'] = (string)date_parse($_REQUEST['passport_expiration_date'])['year'] ?:'';
$_REQUEST['us_visa_passport_issue_date_day'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['day'] ?:'';
$_REQUEST['us_visa_passport_issue_date_month'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['month'] ?:'';
$_REQUEST['us_visa_passport_issue_date_year'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['year'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_day'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['day'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_month'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['month'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_year'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['year'] ?:'';
$_REQUEST['us_visa_birth_date_day'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['day'] ?:'';
$_REQUEST['us_visa_birth_date_month'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['month'] ?:'';
$_REQUEST['us_visa_birth_date_year'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['year'] ?:'';
$_REQUEST = formDataToJson(['vist_country', 'vist_from_date', 'vist_end_date', 'vist_country_des'], $_REQUEST, 'vistitem', 'question_i');
$_REQUEST['other_country_acquired_other'] = isset($_REQUEST['other_country_acquired_other']) ? $_REQUEST['other_country_acquired_other'] : '';
$_REQUEST['source'] = Session::get('source' );
$_REQUEST['is_mobile'] = isMobile() ? 1 : 0;
$_REQUEST['total_price'] = $total_price;
$_REQUEST['origin_price'] = $total_price;
$_REQUEST['ip'] = getIP();
$_REQUEST['coupon_code'] = isset($_REQUEST['coupon_code']) ? $_REQUEST['coupon_code']: '';
$_REQUEST['model'] = MODEL;
$_REQUEST['token'] = md5(MODEL);
$order_res = Httpcurl::request(CREATE_EVUS_ORDER_URL, 'post', $_REQUEST);
Log::info(json_encode($order_res));
$order = json_decode($order_res[0], true);
if (!$order['code']) {
return $this->error("提交失败,请联系管理员!");
}
if ($order['is_pay'] == 1) {
return $this->success('操作成功', url('home/pay/succ', ['order_sn' => $order_sn])->build());
}
return $this->success('操作成功', url('home/pay/index', ['order_sn' => $order_sn])->build());
}
public function wxminievus()
{
$openid = input('openid');
if (empty($openid)) {
return $this->error('请先授权登录');
}
$user_id = input('user_id');
if (empty($user_id)) {
return $this->error('请先授权登录');
}
$price = input('price');
$price = $price * 100;
/*判断价格是否正确*/
$config_price = array_map(function($item) {
return $item['value'];
}, config('app.EVUS_GOODS'));
if (!in_array($price, $config_price)) {
return $this->error('价格错误');
}
View::assign('openid', $openid);
View::assign('user_id', $user_id);
View::assign('price', $price);
View::assign('country_list', json_decode(file_get_contents('./json/country.json'), true));
View::assign('phone_prefix', json_decode(file_get_contents('./json/phone_prefix.json'), true));
View::assign('us', json_decode(file_get_contents('./json/us.json'), true));
View::assign('goods', config('app.EVUS_GOODS'));
View::assign('ismobile', isMobile() ? 1 : 0);
return View::fetch();
}
public function applyminievus()
{
$openid = input('openid');
if (empty($openid)) {
return $this->error('请先授权登录');
}
$user_id = input('user_id');
if (empty($user_id)) {
return $this->error('请先授权登录');
}
$user_id = authcode($user_id);
if (!is_numeric($user_id)) {
return $this->error('请先授权登录');
}
unset($_REQUEST['s']);
unset($_REQUEST['openid']);
$order_sn = $_REQUEST['order_sn'] = getOrderNumber();
$total_price = $_REQUEST['total_price'];
/*判断价格是否正确*/
$config_price = array_map(function($item) {
return $item['value'];
}, config('app.EVUS_GOODS'));
if (!in_array($total_price, $config_price)) {
return $this->error('价格错误');
}
/*判断价格是否正确*/
$_REQUEST['birth_date_day'] = (string)date_parse($_REQUEST['birth_date'])['day'] ?:'0';
$_REQUEST['birth_date_month'] = (string)date_parse($_REQUEST['birth_date'])['month'] ?:'0';
$_REQUEST['birth_date_year'] = (string)date_parse($_REQUEST['birth_date'])['year'] ?:'0';
$_REQUEST['passport_expedition_date_day'] = (string)date_parse($_REQUEST['passport_expedition_date'])['day'] ?:'';
$_REQUEST['passport_expedition_date_month'] = (string)date_parse($_REQUEST['passport_expedition_date'])['month'] ?:'';
$_REQUEST['passport_expedition_date_year'] = (string)date_parse($_REQUEST['passport_expedition_date'])['year'] ?:'';
$_REQUEST['passport_expiration_date_day'] = (string)date_parse($_REQUEST['passport_expiration_date'])['day'] ?:'';
$_REQUEST['passport_expiration_date_month'] = (string)date_parse($_REQUEST['passport_expiration_date'])['month'] ?:'';
$_REQUEST['passport_expiration_date_year'] = (string)date_parse($_REQUEST['passport_expiration_date'])['year'] ?:'';
$_REQUEST['us_visa_passport_issue_date_day'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['day'] ?:'';
$_REQUEST['us_visa_passport_issue_date_month'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['month'] ?:'';
$_REQUEST['us_visa_passport_issue_date_year'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['year'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_day'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['day'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_month'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['month'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_year'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['year'] ?:'';
$_REQUEST['us_visa_birth_date_day'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['day'] ?:'';
$_REQUEST['us_visa_birth_date_month'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['month'] ?:'';
$_REQUEST['us_visa_birth_date_year'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['year'] ?:'';
$_REQUEST = formDataToJson(['vist_country', 'vist_from_date', 'vist_end_date', 'vist_country_des'], $_REQUEST, 'vistitem', 'question_i');
$_REQUEST['other_country_acquired_other'] = isset($_REQUEST['other_country_acquired_other']) ? $_REQUEST['other_country_acquired_other'] : '';
$_REQUEST['source'] = 'qlwxmini';
$_REQUEST['is_mobile'] = isMobile() ? 1 : 0;
$_REQUEST['total_price'] = $total_price;
$_REQUEST['origin_price'] = $total_price;
$_REQUEST['ip'] = getIP();
$_REQUEST['coupon_code'] = isset($_REQUEST['coupon_code']) ? $_REQUEST['coupon_code']: '';
$_REQUEST['model'] = MODEL;
$_REQUEST['token'] = md5(MODEL);
$order_res = Httpcurl::request(CREATE_EVUS_ORDER_URL, 'post', $_REQUEST);
Log::info(json_encode($order_res));
$order = json_decode($order_res[0], true);
if (!$order['code']) {
return $this->error("提交失败,请联系管理员!");
}
$order_url = 'https://pay.qlevisa.com/home/pay/miniwxevuspay';
$response = Httpcurl::request($order_url, 'post', ['order_sn' => $order_sn, 'body' => 'evus登记签证服务费', 'money' => $total_price, 'openid' => $openid, 'attach' => 'msg']);
if ($response[3]) {
return json([
'code' => 0,
'msg' => '异常错误,请重新提交',
]);
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return json([
'code' => 0,
'msg' => '异常错误,请重新提交',
]);
}
if ($pay_result['code'] !== 200) {
return json([
'code' => 0,
'msg' => $pay_result['msg'],
]);
}
$pay_result['data']['package'] = urlencode($pay_result['data']['package']);
return json([
'code' => 1,
'msg' => '提交成功',
'data' => $pay_result['data']
]);
}
}

View File

@@ -0,0 +1,201 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\facade\Cookie;
use think\facade\Request;
use think\facade\Session;
use think\facade\View;
use think\facade\Log;
class Esta extends Base
{
public function index()
{
View::assign('country_list', json_decode(file_get_contents('./json/country.json'), true));
View::assign('phone_prefix', json_decode(file_get_contents('./json/phone_prefix.json'), true));
View::assign('us', json_decode(file_get_contents('./json/us.json'), true));
View::assign('goods', config('app.ESTA_GOODS'));
View::assign('ismobile', isMobile() ? 1 : 0);
View::assign('ppt_sample_url', '/new/assets/images/shili.jpg');
View::assign('per_sample_url', '/new/assets/images/persion2.png');
return View::fetch();
}
public function do_apply()
{
unset($_REQUEST['s']);
unset($_REQUEST['file']);
$order_sn = $_REQUEST['order_sn'] = getOrderNumber();
$total_price = $_REQUEST['total_price'];
/*判断价格是否正确*/
$config_price = array_map(function($item) {
return $item['value'];
}, config('app.ESTA_GOODS'));
if (!in_array($total_price, $config_price)) {
return $this->error('价格错误');
}
/*判断价格是否正确*/
$_REQUEST['birth_date_day'] = (string)date_parse($_REQUEST['birth_date'])['day'] ?:'0';
$_REQUEST['birth_date_month'] = (string)date_parse($_REQUEST['birth_date'])['month'] ?:'0';
$_REQUEST['birth_date_year'] = (string)date_parse($_REQUEST['birth_date'])['year'] ?:'0';
$_REQUEST['passport_expedition_date_day'] = (string)date_parse($_REQUEST['passport_expedition_date'])['day'] ?:'';
$_REQUEST['passport_expedition_date_month'] = (string)date_parse($_REQUEST['passport_expedition_date'])['month'] ?:'';
$_REQUEST['passport_expedition_date_year'] = (string)date_parse($_REQUEST['passport_expedition_date'])['year'] ?:'';
$_REQUEST['passport_expiration_date_day'] = (string)date_parse($_REQUEST['passport_expiration_date'])['day'] ?:'';
$_REQUEST['passport_expiration_date_month'] = (string)date_parse($_REQUEST['passport_expiration_date'])['month'] ?:'';
$_REQUEST['passport_expiration_date_year'] = (string)date_parse($_REQUEST['passport_expiration_date'])['year'] ?:'';
$_REQUEST['other_country_date_day'] = (string)date_parse($_REQUEST['other_country_date'])['day'] ?:'';
$_REQUEST['other_country_date_month'] = (string)date_parse($_REQUEST['other_country_date'])['month'] ?:'';
$_REQUEST['other_country_date_year'] = (string)date_parse($_REQUEST['other_country_date'])['year'] ?:'';
unset($_REQUEST['other_country_date']);
$_REQUEST['other_country_edate_day'] = (string)date_parse($_REQUEST['other_country_edate'])['day'] ?:'';
$_REQUEST['other_country_edate_month'] = (string)date_parse($_REQUEST['other_country_edate'])['month'] ?:'';
$_REQUEST['other_country_edate_year'] = (string)date_parse($_REQUEST['other_country_edate'])['year'] ?:'';
unset($_REQUEST['other_country_edate']);
$_REQUEST['ip'] = getIP();
$_REQUEST['source'] = Session::get('source' );
$_REQUEST['total_price'] = $total_price;
$_REQUEST['model'] = ESTA_MODEL;
$_REQUEST['token'] = md5(ESTA_MODEL);
$_REQUEST['other_country_acquired_other'] = isset($_REQUEST['other_country_acquired_other']) ? $_REQUEST['other_country_acquired_other'] : '';
$order_res = Httpcurl::request(CREATE_ORDER_URL, 'post', $_REQUEST);
Log::info(json_encode($order_res));
$order = json_decode($order_res[0], true);
if (!$order['code']) {
return $this->error("提交失败,请联系管理员!");
}
return $this->success('操作成功', url('home/payesta/index', ['order_sn' => $order_sn])->build());
}
public function wxmini()
{
$openid = input('openid');
if (empty($openid)) {
return $this->error('请先授权登录');
}
$user_id = input('user_id');
if (empty($user_id)) {
return $this->error('请先授权登录');
}
$price = input('price');
$price = $price * 100;
/*判断价格是否正确*/
$config_price = array_map(function($item) {
return $item['value'];
}, config('app.ESTA_GOODS'));
if (!in_array($price, $config_price)) {
return $this->error('价格错误');
}
View::assign('openid', $openid);
View::assign('user_id', $user_id);
View::assign('price', $price);
View::assign('country_list', json_decode(file_get_contents('./json/country.json'), true));
View::assign('phone_prefix', json_decode(file_get_contents('./json/phone_prefix.json'), true));
View::assign('us', json_decode(file_get_contents('./json/us.json'), true));
View::assign('goods', config('app.ESTA_GOODS'));
View::assign('ismobile', isMobile() ? 1 : 0);
View::assign('ppt_sample_url', '/new/assets/images/shili.jpg');
View::assign('per_sample_url', '/new/assets/images/persion2.png');
return View::fetch();
}
public function applymini()
{
$openid = input('openid');
if (empty($openid)) {
return $this->error('请先授权登录');
}
$user_id = input('user_id');
if (empty($user_id)) {
return $this->error('请先授权登录');
}
$user_id = authcode($user_id);
if (!is_numeric($user_id)) {
return $this->error('请先授权登录');
}
unset($_REQUEST['s']);
unset($_REQUEST['openid']);
unset($_REQUEST['file']);
$order_sn = $_REQUEST['order_sn'] = getOrderNumber();
$total_price = $_REQUEST['total_price'];
/*判断价格是否正确*/
$config_price = array_map(function($item) {
return $item['value'];
}, config('app.ESTA_GOODS'));
if (!in_array($total_price, $config_price)) {
return $this->error('价格错误');
}
$_REQUEST['birth_date_day'] = (string)date_parse($_REQUEST['birth_date'])['day'] ?:'0';
$_REQUEST['birth_date_month'] = (string)date_parse($_REQUEST['birth_date'])['month'] ?:'0';
$_REQUEST['birth_date_year'] = (string)date_parse($_REQUEST['birth_date'])['year'] ?:'0';
$_REQUEST['passport_expedition_date_day'] = (string)date_parse($_REQUEST['passport_expedition_date'])['day'] ?:'';
$_REQUEST['passport_expedition_date_month'] = (string)date_parse($_REQUEST['passport_expedition_date'])['month'] ?:'';
$_REQUEST['passport_expedition_date_year'] = (string)date_parse($_REQUEST['passport_expedition_date'])['year'] ?:'';
$_REQUEST['passport_expiration_date_day'] = (string)date_parse($_REQUEST['passport_expiration_date'])['day'] ?:'';
$_REQUEST['passport_expiration_date_month'] = (string)date_parse($_REQUEST['passport_expiration_date'])['month'] ?:'';
$_REQUEST['passport_expiration_date_year'] = (string)date_parse($_REQUEST['passport_expiration_date'])['year'] ?:'';
$_REQUEST['other_country_date_day'] = (string)date_parse($_REQUEST['other_country_date'])['day'] ?:'';
$_REQUEST['other_country_date_month'] = (string)date_parse($_REQUEST['other_country_date'])['month'] ?:'';
$_REQUEST['other_country_date_year'] = (string)date_parse($_REQUEST['other_country_date'])['year'] ?:'';
unset($_REQUEST['other_country_date']);
$_REQUEST['other_country_edate_day'] = (string)date_parse($_REQUEST['other_country_edate'])['day'] ?:'';
$_REQUEST['other_country_edate_month'] = (string)date_parse($_REQUEST['other_country_edate'])['month'] ?:'';
$_REQUEST['other_country_edate_year'] = (string)date_parse($_REQUEST['other_country_edate'])['year'] ?:'';
unset($_REQUEST['other_country_edate']);
$_REQUEST['ip'] = getIP();
$_REQUEST['source'] = 'qlwxmini';
$_REQUEST['total_price'] = $total_price;
$_REQUEST['model'] = ESTA_MODEL;
$_REQUEST['token'] = md5(ESTA_MODEL);
$_REQUEST['other_country_acquired_other'] = isset($_REQUEST['other_country_acquired_other']) ? $_REQUEST['other_country_acquired_other'] : '';
$order_res = Httpcurl::request(CREATE_ORDER_URL, 'post', $_REQUEST);
$order = json_decode($order_res[0], true);
if (!$order['code']) {
return $this->error("提交失败,请联系管理员!");
}
$order_url = 'https://pay.qlevisa.com/home/pay/miniwxevuspay';
$response = Httpcurl::request($order_url, 'post', ['order_sn' => $order_sn, 'body' => 'esta登记签证服务费', 'money' => $total_price, 'openid' => $openid, 'attach' => 'esta']);
if ($response[3]) {
return json([
'code' => 0,
'msg' => '异常错误,请重新提交',
]);
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return json([
'code' => 0,
'msg' => '异常错误,请重新提交',
]);
}
if ($pay_result['code'] !== 200) {
return json([
'code' => 0,
'msg' => $pay_result['msg'],
]);
}
$pay_result['data']['package'] = urlencode($pay_result['data']['package']);
return json([
'code' => 1,
'msg' => '提交成功',
'data' => $pay_result['data']
]);
}
}

View File

@@ -0,0 +1,14 @@
<?php
declare (strict_types=1);
namespace app\home\controller;
use think\facade\View;
class Help extends Base
{
public function index()
{
return View::fetch();
}
}

View File

@@ -0,0 +1,44 @@
<?php
declare (strict_types = 1);
namespace app\home\controller;
use api\Httpcurl;
use think\facade\Log;
use think\facade\View;
class Index extends Base
{
public function index()
{
$news_list = Httpcurl::request(NEWS_LIST, 'post', [
'model' => 'article',
'source_code' => DOMAIN,
'page' => 1,
'size' => 10,
]);
$news_list = json_decode($news_list[0], true);
Log::info(json_encode($news_list));
if (!empty($news_list) && $news_list['code'] == 1) {
View::assign('data', $news_list['data']);
} else {
View::assign('data', []);
}
return View::fetch();
}
public function screen()
{
return View::fetch();
}
public function test()
{
$order_sn = '2026061008342768';
$wechaturl = 'https://pay.qlevisa.cn/home/bjqzpay/wechat';
$wechaturl .= '?order_sn=' . $order_sn . '&mark=qlmsg' . '&body=' . urlencode(COUNTRY . '服务费');
header('location:' . $wechaturl); // 跳转到 user/profile
exit;
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\Config;
use think\exception\HttpResponseException;
use think\facade\Log;
use think\facade\Request;
use think\facade\Session;
class Invoice extends Base
{
public function _initialize()
{
parent::initialize();
if (!Session::has('user') || Session::get('user')['id'] <= 0) {
throw new HttpResponseException(redirect('/home/login'));
}
}
/**个人中心
*/
public function index()
{
$order_sn = Request::instance()->param('order_sn');
if (empty($order_sn)) {
return $this->error('参数错误');
}
$order_url = config('app.get_evus_detail_url');
$response = Httpcurl::request($order_url, 'post', ['order_sn' => $order_sn, 'model' => MODEL]);
if ($response[3]) {
return $this->error('异常错误,请重新提交');
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return $this->error('异常错误,请重新提交');
}
Log::info(json_encode($pay_result));
if (!$pay_result['code']) {
return $this->error($pay_result['msg']);
}
$data = $pay_result['data'];
if (empty($data)) {
return $this->error('无此数据');
}
$total_price = $data['total_price'] ? $data['total_price'] : $data['origin_price'];
$data['total_price'] = ($total_price / 100) . "元";
return view('', [
'data' => $data,
]);
}
public function add_invoice()
{
$res = [
'status' => 0,
'msg' => '操作失败,请重新填写'
];
unset($_REQUEST['s']);
$_REQUEST['invoiceType'] = INCOICETYPE;
$_REQUEST['model'] = MODEL;
$_REQUEST['principals'] = config('app.principals');
$_REQUEST['uid'] = $this->_userId;
$base_url = config('app.order_url');
$order_url = $base_url . 'add_invoice';
$response = Httpcurl::request($order_url, 'post', $_REQUEST);
if ($response[3]) {
return json($res);
}
$pay_result = json_decode($response[0], true);
Log::info(json_encode($pay_result));
if (empty($pay_result)) {
return json($res);
}
if (!$pay_result['code']) {
$res['msg'] = $pay_result['msg'];
return json($res);
}
$res['status'] = 1;
$res['msg'] = $pay_result['msg'];
$res['url'] = '/home/user/order';
return json($res);
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\exception\ValidateException;
use think\facade\Log;
use think\facade\Session;
use think\facade\View;
use think\Model;
class Login extends Base
{
public function index()
{
return View::fetch();
}
public function send_sms()
{
$param = $this->request->post();
try {
$this->validate($param, ['mobile' => 'require'], ['mobile.require' => '手机号不能为空']);
} catch (ValidateException $e) {
return $this->error($e->getError());
}
// $code = 1234;
// $result['code'] = 1;
$code = mt_rand(1001, 9999);
//进行发送验证 走接口
$res = Httpcurl::request(YZM_URL, 'post', [
'mobile' => $param['mobile'],
'code' => $code,
]);
$result = json_decode($res[0], true);
Log::info(json_encode($result));
if (!$result['code']) {
return $this->error('发送验证码失败');
}
// 进行记录
if ($result['code'] == 1) {
//把内容存入session
Session::set($param['mobile'] . '_code', $code);
Session::set($param['mobile'] . '_' . $code, time());
return $this->success('发送成功');
} else {
return $this->error('发送失败');
}
}
// 登录
public function dologin()
{
$param = $this->request->post();
try {
$this->validate($param, ['phone' => 'require', 'vercode' => 'require'], ['phone.require' => '手机号不能为空', 'vercode.require' => '验证码不能为空']);
} catch (ValidateException $e) {
return $this->error($e->getError());
}
$mobile = $param['phone'];
$code = $param['vercode'];
$res = 0;
$sms = Session::get($mobile . '_code');
if (empty($sms)) {
return $this->error('登录失败');
}
if ($sms != $code) {
return $this->error('验证码不正确');
}
$time = time();
$code_time = Session::get($mobile . '_' . $code);
//判断是否已经超时5分钟
if (($time - $code_time) > 300) {
Session::delete($mobile . '_code');
Session::delete($mobile . '_' . $code);
return $this->error('验证码超时,请重新发送');
}
//查询evus账号
$user_url = config('app.user_url');
$res = Httpcurl::request($user_url, 'post', [
'model' => MODEL,
'mobile' => $mobile,
]);
$result = json_decode($res[0], true);
Log::info(json_encode($result));
if (!$result['code']) {
return $this->error('账号不存在');
}
//查询esta账号
$res = Httpcurl::request($user_url, 'post', [
'model' => ESTA_MODEL,
'mobile' => $mobile,
]);
$result = json_decode($res[0], true);
Log::info(json_encode($result));
if (!$result['code']) {
return $this->error('账号不存在');
}
Session::set('user', $result['data']);
return $this->success('登录成功', url('user/order'));
}
public function logout()
{
Session::delete('user');
return redirect('/home/index');
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\facade\Db;
use think\facade\Log;
use think\facade\Request;
use think\facade\View;
class Lookup extends Base
{
public function index()
{
View::assign('country_list', json_decode(file_get_contents('./json/country.json'), true));
return View::fetch();
}
public function enrollment()
{
$data = Request::instance()->param();
$params = [
'passportNum' => $data['passport_number'],
'b1b2Num' => $data['visa_foil_number'],
'surname' => $data['last_name'],
'givenname' => $data['first_name'],
'year_birthday' => (string)date_parse($data['birth_date'])['year'],
'month_birthday' => (string)date_parse($data['birth_date'])['month'],
'day_birthday' => (string)date_parse($data['birth_date'])['day'],
'country_birth' => $data['country_birth'],
];
$result = Httpcurl::request(config('app.LOOKUP_URL'), 'post', json_encode($params),[
'Content-Type: application/json',
]);
$config_result = json_decode($result[0], true);
if (empty($config_result)) {
return json([
'error_code'=>22,
'msg'=>"服务器错误,请稍后重试"
]);
}
return json($config_result);
}
/**
* 微信小程序专用
*/
public function wxmini()
{
View::assign('country_list', json_decode(file_get_contents('./json/country.json'), true));
return View::fetch();
}
}

View File

@@ -0,0 +1,137 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\facade\Db;
use think\facade\View;
class Miniinvoice extends Base
{
public function index()
{
$openid = input('openid');
if (empty($openid)) {
return $this->error('请先授权登录');
}
$origin_userid = $user_id = input('user_id');
if (empty($user_id)) {
return $this->error('请先授权登录');
}
$user_id = authcode($user_id);
if (!is_numeric($user_id)) {
return $this->error('请先授权登录');
}
$principals = Db::name('order_principals')->where(['order_sn' => $_REQUEST['order_sn']])->find();
if (empty($principals)) {
$res['msg'] = '无此数据';
return json($res);
}
if ($principals['type']==1){
$data = Db::name('msg')->where(['order_sn' => $_REQUEST['order_sn']])->where('order_status','>',0)->find();
}elseif ($principals['type']==2){
$data = Db::name('esta')->where(['order_sn' => $_REQUEST['order_sn']])->where('order_status','>',0)->find();
}elseif ($principals['type']==3){
$data = Db::name('visa')->where(['order_sn' => $_REQUEST['order_sn']])->where('order_status','>',0)->find();
}
//获取数据
if (empty($data)) {
return $this->error('无此数据');
}
$total_price = $data['total_price'] ? $data['total_price'] : $data['origin_price'];
$data['total_price'] = ($total_price / 100) . "元";
View::assign('data', $data);
View::assign('openid', $openid);
View::assign('user_id', $origin_userid);
return View::fetch();
}
public function add_invoice()
{
$openid = input('openid');
if (empty($openid)) {
return $this->error('请先授权登录');
}
$user_id = input('user_id');
if (empty($user_id)) {
return $this->error('请先授权登录');
}
$user_id = authcode($user_id);
if (!is_numeric($user_id)) {
return $this->error('请先授权登录');
}
$res = [
'status' => 0,
'msg' => '操作失败,请重新填写'
];
unset($_REQUEST['s'],$_REQUEST['openid'],$_REQUEST['user_id']);
$_REQUEST['uid'] = $user_id;
if(strpos( $_REQUEST['tax_number']," ")){
$res['msg'] = '税号包含空格,请删除后重新填写';
return json($res);
}
$principals = Db::name('order_principals')->where(['order_sn' => $_REQUEST['order_sn']])->find();
if (empty($principals)) {
$res['msg'] = '无此数据';
return json($res);
}
if ($principals['type']==1){
$content = "EVUS有新的发票申请,请及时处理";
$order = Db::name('msg')->where(['order_sn' => $_REQUEST['order_sn']])->where('order_status','>',0)->find();
}elseif ($principals['type']==2){
$content = "ESTA有新的发票申请,请及时处理";
$order = Db::name('esta')->where(['order_sn' => $_REQUEST['order_sn']])->where('order_status','>',0)->find();
}elseif ($principals['type']==3){
$content = "美签有新的发票申请,请及时处理";
$order = Db::name('visa')->where(['order_sn' => $_REQUEST['order_sn']])->where('order_status','>',0)->find();
}
if (empty($order)) {
$res['msg'] = '无此数据';
return json($res);
}
$data = Db::name('userinvoice')->where([ 'order_id' => $order['id'],'type'=>$principals['type'] ])->find();
if (!empty($data)) {
$res['msg'] = '请勿重复开票';
return json($res);
}
$lastyear = date('Y',strtotime($order['reg_time']));
$year = date('Y');
if ($year-$lastyear > 2) {
$res['msg'] = '开票期限已过';
return json($res);
}
$_REQUEST['title'] = trim($_REQUEST['title']);
$_REQUEST['money'] = $order['total_price'] ? $order['total_price'] : $order['origin_price'];
//进行插入
unset($_REQUEST['etype']);
$re = Db::name('userinvoice')->insert($_REQUEST);
if (!$re) {
$res['msg'] = '操作失败,请重新填写';
return json($res);
}
$res = [
'status' => 1,
'msg' => '操作成功',
'url' => url('user/order', [], '', true)->build()
];
//推送发票
$url='https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=a0d594ce-0580-4a9a-bf4f-712193b65531';
$data = array('msgtype' => 'text', 'text' => [
'content' => $content,
]);
Httpcurl::request($url, 'post', json_encode($data), [
'Content-Type: application/json'
]);
return json($res);
}
}

View File

@@ -0,0 +1,217 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\facade\Log;
use think\facade\View;
use think\facade\Session;
use think\facade\Request;
use think\Url;
class Multiple extends Base
{
public function _initialize()
{
parent::_initialize();
if (!Session::has('userinfo') || Session::get('userinfo')['id'] <= 0) {
$this->redirect('login/index');
}
}
/**个人中心
*/
public function index()
{
//获取用户的登记信息
$id = Request::instance()->param('id');
if (empty($id)) {
return $this->error('参数错误');
}
$datas = base64_decode($id);
$order_sns = explode('-', $datas);
//判断是否有重复订单
if (count($order_sns) != count(array_unique($order_sns))) {
return $this->error('有重复订单,请删除后重新提交');
}
$real_ordersn = [];
$total_price = 0;
$base_url = config('app.order_url');
$evus_order_url = config('app.get_evus_detail_url');
$order_url = config('app.get_order_detail_url');
$invoice_url = $base_url . 'getInvoice';
$type = Request::instance()->param('type', 'evus');
foreach ($order_sns as $da) {
//获取信息
if ($type == 'evus') {
$response = Httpcurl::request($evus_order_url, 'post', [
'order_sn' => $da,
'model' => MODEL
]);
} else {
$response = Httpcurl::request($order_url, 'post', [
'order_sn' => $da,
'model' => ESTA_MODEL
]);
}
$data = json_decode($response[0], true);
if (empty($data)) {
continue;
}
//查询是否已经开票了
$invoice = Httpcurl::request($invoice_url, 'post', [
'order_sn' => $da,
'invoiceType' => INCOICETYPE,
'model' => MODEL
]);
if ($invoice[3]) {
$res['msg'] = '参数错误';
return json($res);
}
$order = json_decode($invoice[0], true);
Log::info(json_encode($order));
if (empty($order)) {
$res['msg'] = '系统错误,请联系管理员!';
return json($res);
}
if (!$order['code']) {
$res['msg'] = $order['msg'];
return json($res);
}
if (!empty($order['data'])) {
$res['msg'] = '订单号:' . $da . '已经开票';
return json($res);
}
$real_ordersn[] = $da;
$total_price += $data['data']['total_price'];
}
$data['total_price'] = ($total_price / 100) . "元";
$data['order_sn'] = implode(',', $real_ordersn);
View::assign('data', $data);
View::assign('type', $type);
return View::fetch();
}
public function add_invoice()
{
$res = [
'status' => 0,
'msg' => '操作失败,请重新填写'
];
unset($_REQUEST['s']);
$type = $_REQUEST['type'];
if ($_REQUEST['type'] == 'evus') {
$_REQUEST['type'] = 1;
} else {
$_REQUEST['type'] = 6;
}
$_REQUEST['uid'] = $this->_userId;
if (empty($_REQUEST['order_sn'])) {
$res['msg'] = '请选择订单';
return json($res);
}
if (strpos($_REQUEST['tax_number'], " ")) {
$res['msg'] = '税号包含空格,请删除后重新填写';
return json($res);
}
$order_sns = explode(',', $_REQUEST['order_sn']);
//判断是否有重复订单
if (count($order_sns) != count(array_unique($order_sns))) {
$res['msg'] = '有重复订单,请删除后重新提交';
return json($res);
}
$real_ordersn = [];
$total_price = 0;
$base_url = config('app.order_url');
$evus_order_url = config('app.get_evus_detail_url');
$order_url = config('app.get_order_detail_url');
$invoice_url = $base_url . 'getInvoice';
foreach ($order_sns as $da) {
//获取信息
if ($type == 'evus') {
$response = Httpcurl::request($evus_order_url, 'post', [
'order_sn' => $da,
'model' => MODEL
]);
} else {
$response = Httpcurl::request($order_url, 'post', [
'order_sn' => $da,
'model' => ESTA_MODEL
]);
}
$data = json_decode($response[0], true);
if (empty($data)) {
$res['msg'] = '未找到订单信息';
return json($res);
}
//判断是否已经开票了
$invoice = Httpcurl::request($invoice_url, 'post', [
'order_sn' => $da,
'invoiceType' => INCOICETYPE,
'model' => MODEL
]);
if ($invoice[3]) {
$res['msg'] = '参数错误';
return json($res);
}
$order = json_decode($invoice[0], true);
if (empty($order)) {
$res['msg'] = '系统错误,请联系管理员!';
return json($res);
}
if (!$order['code']) {
$res['msg'] = $order['msg'];
return json($res);
}
if (!empty($order['data'])) {
$res['msg'] = '订单号:' . $da . '已经开票';
return json($res);
}
$real_ordersn[] = $da;
$total_price += $data['data']['total_price'];
}
if (empty($real_ordersn)) {
$res['msg'] = '暂无开票订单';
return json($res);
}
$_REQUEST['invoiceType'] = INCOICETYPE;
$_REQUEST['model'] = MODEL;
$_REQUEST['principals'] = config('app.principals');
$_REQUEST['title'] = trim($_REQUEST['title']);
$_REQUEST['money'] = $total_price;
$_REQUEST['multiple'] = md5(implode(',', $real_ordersn));
$order_urls = $base_url . 'addMultiple';
$response = Httpcurl::request($order_urls, 'post', $_REQUEST);
if ($response[3]) {
return json($res);
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return json($res);
}
if (!$pay_result['code']) {
$res['msg'] = $pay_result['msg'];
return json($res);
}
$res = [
'status' => 1,
'msg' => '操作成功',
'url' => '/home/user/order'
];
return json($res);
}
}

View File

@@ -0,0 +1,228 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use app\service\SeoMetaService;
use think\facade\Log;
use think\facade\Request;
use think\facade\View;
class News extends Base
{
public function index()
{
$page = intval(input('page') ? input('page') : 1);
$size = intval(input('size') ? input('size') : 10);
$page = max(1, $page);
$size = max(1, $size);
$news_list = $this->requestNewsList($page, $size);
if (!empty($news_list) && isset($news_list['code']) && $news_list['code'] == 1) {
$data = $this->normalizeNewsList(isset($news_list['data']) ? $news_list['data'] : []);
$count = isset($news_list['count']) ? intval($news_list['count']) : count($data);
} else {
$data = [];
$count = 0;
}
View::assign('data', $data);
View::assign('count', $count);
View::assign('page', $page);
View::assign('size', $size);
$this->assignSeo([
'title' => $page > 1
? 'EVUS与美国签证新闻资讯 - 第' . $page . '页'
: 'EVUS与美国签证新闻资讯',
'canonical_path' => '/home/news/index',
'canonical_query_keys' => ['page'],
]);
return View::fetch();
}
public function detail()
{
$id = Request::instance()->param('id');
if (
!is_scalar($id)
|| filter_var((string) $id, FILTER_VALIDATE_INT, [
'options' => ['min_range' => 1],
]) === false
) {
abort(404, '新闻不存在');
}
$id = (int) $id;
$info = $this->requestNewsDetail($id);
if ($info === null) {
abort(503, '新闻服务暂时不可用');
}
if (empty($info) || !isset($info['code']) || $info['code'] != 1 || empty($info['data'])) {
abort(404, '新闻不存在');
}
$info_detail = $this->normalizeNewsItem($info['data']);
$latest = $this->requestNewsList(1, 50);
$latest_data = [];
if (!empty($latest) && isset($latest['code']) && $latest['code'] == 1) {
$latest_data = $this->normalizeNewsList(isset($latest['data']) ? $latest['data'] : [], true);
}
$nav = $this->resolveArticleNav($id, $latest_data);
$article = $this->filterRelatedArticles($id, $latest_data, 8);
View::assign('data', $info_detail);
View::assign('last', $nav['last']);
View::assign('next', $nav['next']);
View::assign('article', $article);
$seoService = new SeoMetaService();
$title = $seoService->descriptionFromHtml((string) $info_detail['title'], 60);
$description = $seoService->descriptionFromHtml(
(string) $info_detail['contents']
);
$seo = [
'canonical_path' => '/home/news/detail',
'canonical_query_keys' => ['id'],
];
if ($title !== '') {
$seo['title'] = $title;
}
if ($description !== '') {
$seo['description'] = $description;
}
$this->assignSeo($seo);
return View::fetch();
}
private function requestNewsList($page, $size)
{
$response = Httpcurl::request(NEWS_LIST, 'post', [
'model' => 'article',
'source_code' => DOMAIN,
'page' => $page,
'size' => $size,
]);
return $this->decodeApiResponse($response, 'news list');
}
private function requestNewsDetail($id)
{
$response = Httpcurl::request(NEWS_DETAIL, 'post', [
'model' => 'article',
'id' => $id,
]);
return $this->decodeApiResponse($response, 'news detail');
}
private function decodeApiResponse($response, $scene)
{
if (!is_array($response) || !isset($response[0]) || !empty($response[3])) {
Log::error($scene . ' api request failed: ' . json_encode($response));
return null;
}
$status_code = intval(isset($response[2]['http_code']) ? $response[2]['http_code'] : 0);
if ($status_code < 200 || $status_code >= 300) {
Log::error($scene . ' api returned HTTP status: ' . $status_code);
return null;
}
$result = json_decode($response[0], true);
Log::info(json_encode($result));
return is_array($result) ? $result : null;
}
private function normalizeNewsList($list, $short_date = false)
{
if (!is_array($list)) {
return [];
}
$data = [];
foreach ($list as $item) {
$item = $this->normalizeNewsItem($item);
if ($short_date) {
$item['create_time'] = $this->formatDate($item['create_time']);
}
$data[] = $item;
}
return $data;
}
private function normalizeNewsItem($item)
{
if (!is_array($item)) {
return [];
}
$item['id'] = isset($item['id']) ? $item['id'] : 0;
$item['title'] = isset($item['title']) ? $item['title'] : '';
$contents = isset($item['contents'])
? $item['contents']
: (isset($item['content']) ? $item['content'] : '');
$item['contents'] = is_scalar($contents)
? str_replace('https://www.evus.gov/', '', (string) $contents)
: '';
$item['create_time'] = isset($item['create_time']) ? $item['create_time'] : '';
return $item;
}
private function resolveArticleNav($id, $list)
{
$id = intval($id);
$last = [];
$next = [];
foreach ($list as $item) {
$item_id = intval(isset($item['id']) ? $item['id'] : 0);
if ($item_id <= 0 || $item_id == $id) {
continue;
}
if ($item_id < $id && (empty($last) || $item_id > intval($last['id']))) {
$last = $item;
}
if ($item_id > $id && (empty($next) || $item_id < intval($next['id']))) {
$next = $item;
}
}
return ['last' => $last, 'next' => $next];
}
private function filterRelatedArticles($id, $list, $limit)
{
$data = [];
$id = intval($id);
foreach ($list as $item) {
if (intval($item['id']) == $id) {
continue;
}
$data[] = $item;
if (count($data) >= $limit) {
break;
}
}
return $data;
}
private function formatDate($date)
{
if (empty($date)) {
return '';
}
$timestamp = strtotime($date);
return $timestamp ? date('Y-m-d', $timestamp) : $date;
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace app\home\controller;
class Panel extends Base
{
public function index()
{
//
return $this->fetch();
}
}

240
app/home/controller/Pay.php Normal file
View File

@@ -0,0 +1,240 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Log;
use think\facade\Request;
use think\facade\View;
use think\exception\HttpResponseException;
use think\Response;
class Pay extends Base
{
private $order_sn = '';
public function initialize()
{
parent::initialize();
$this->order_sn = Request::instance()->param('order_sn', '');
if (empty($this->order_sn)) {
throw new HttpResponseException(Response::create($this->error('缺少订单号,请重新填写', url('detail/index'))));
}
}
public function index()
{
if (isMobile()) {
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false) {
return redirect(url('pay/wxpay', ['order_sn' => $this->order_sn])->build());
}
return redirect(url('pay/h5pay', ['order_sn' => $this->order_sn])->build());
}
return redirect(url('pay/pcpay', ['order_sn' => $this->order_sn])->build());
}
/**
* 跳到微信支付
*/
public function wxpay()
{
$wechaturl = config('app.wechatpay');
$wechaturl .= '?order_sn=' . $this->order_sn . '&mark=' . PAY_MARK . '&body=' . urlencode(COUNTRY . '服务费');
header('location:' . $wechaturl); // 跳转到 user/profile
exit;
}
/**
* 跳转到pc支付
*/
public function pcpay()
{
$order_sn = $this->order_sn;
//判断支付是否已完成
$order_url = config('app.get_evus_detail_url');
$response = Httpcurl::request($order_url, 'post', ['order_sn' => $order_sn, 'model' => MODEL]);
if ($response[3]) {
return $this->error("异常错误,请重新提交", url('detail/index'));
}
$pay_result = json_decode($response[0], true);
Log::info(json_encode($pay_result));
if (empty($pay_result)) {
return $this->error("异常错误,请重新提交", url('detail/index'));
}
if (!$pay_result['code']) {
return $this->error($pay_result['msg'], url('detail/index'));
}
$pay_result = $pay_result['data'];
if ($pay_result['pay_status']) {
return $this->success('您已支付成功,请勿重复支付', url('detail/index'));
}
//微信pc
$cfg = config('app.wechatpcpay');
$res = Httpcurl::request($cfg, 'get', array('order_sn' => $order_sn, 'mark' => PAY_MARK, 'body' => COUNTRY . '服务费'));
$wxurl = "";
if (!$res[3]) {
$result = json_decode($res[0], true);
$wxurl = $result['url'];
}
Log::info(json_encode($res));
//支付宝pc
$cfg = config('app.alipcpay');
$res = Httpcurl::request($cfg, 'get', array('order_sn' => $order_sn, 'mark' => PAY_MARK, 'body' => urlencode(COUNTRY . '服务费')));
$aliurl = "";
if (!$res[3]) {
$result = json_decode($res[0], true);
$aliurl = $result['url'];
}
Log::info(json_encode($res));
View::assign('url', $wxurl);
View::assign('aliurl', $aliurl);
View::assign('order_sn', $order_sn);
View::assign('total_fee', number_format($pay_result['total_price'] / 100, 2));
return View::fetch();
}
/**
* 跳转到H5支付
*/
public function h5pay()
{
$wechaturl = config('app.wechath5pay');
$wechaturl .= '?order_sn=' . $this->order_sn . '&mark=' . PAY_MARK . '&body=' . urlencode(COUNTRY . '服务费');
header('location:' . $wechaturl); // 跳转到 user/profile
exit;
}
public function succ()
{
$order_sn = $this->order_sn;
View::assign('order_sn', $order_sn);
return View::fetch();
}
/**
* h5支付结果页面
*/
public function h5result()
{
if (Request::instance()->isAjax()) {
$order_sn = $this->order_sn;
if (!$order_sn) {
return json([
'status' => 0,
'msg' => '订单号不存在,请重新支付',
'url' => url('pay/index', ['order_sn' => $order_sn])->build()
]);
}
$order_url = config('app.get_evus_detail_url');
$response = Httpcurl::request($order_url, 'post', ['order_sn' => $order_sn, 'model' => MODEL]);
if ($response[3]) {
return json([
'status' => 0,
'msg' => '异常错误,请重新提交',
'url' => url('pay/index', ['order_sn' => $order_sn])->build()
]);
}
$pay_result = json_decode($response[0], true);
Log::info(json_encode($pay_result));
if (empty($pay_result)) {
return json([
'status' => 0,
'msg' => '异常错误,请重新提交',
'url' => url('pay/index', ['order_sn' => $order_sn])->build()
]);
}
if (!$pay_result['code']) {
return json([
'status' => 0,
'msg' => $pay_result['msg'],
'url' => url('pay/index', ['order_sn' => $order_sn])->build()
]);
}
$pay_result = $pay_result['data'];
if ($pay_result['pay_status']) {
return json([
'status' => 1,
'msg' => '支付成功',
'url' => url('pay/succ', ['order_sn' => $order_sn])->build()
]);
}
return json([
'status' => 0,
'msg' => '您还未支付,请重新支付',
'url' => url('pay/h5pay', ['order_sn' => $order_sn])->build()
]);
}
return View::fetch();
}
/**
* pc支付结果页面
*/
public function pcresult()
{
if (Request::instance()->isAjax()) {
$order_sn = $this->order_sn;
if (!$order_sn) {
return json([
'status' => 0,
'msg' => '订单号不存在,请重新支付',
'url' => url('pay/index', ['order_sn' => $order_sn])->build()
]);
}
$order_url = config('app.get_evus_detail_url');
$response = Httpcurl::request($order_url, 'post', ['order_sn' => $order_sn, 'model' => MODEL]);
if ($response[3]) {
return json([
'status' => 0,
'msg' => '异常错误,请重新提交',
'url' => url('pay/index', ['order_sn' => $order_sn])->build()
]);
}
$pay_result = json_decode($response[0], true);
Log::info(json_encode($pay_result));
if (empty($pay_result)) {
return json([
'status' => 0,
'msg' => '异常错误,请重新提交',
'url' => url('pay/index', ['order_sn' => $order_sn])->build()
]);
}
if (!$pay_result['code']) {
return json([
'status' => 0,
'msg' => $pay_result['msg'],
'url' => url('pay/index', ['order_sn' => $order_sn])->build()
]);
}
$pay_result = $pay_result['data'];
if ($pay_result['pay_status']) {
return json([
'status' => 1,
'msg' => '支付成功',
'url' => url('pay/succ', ['order_sn' => $order_sn])->build()
]);
}
return json([
'status' => 0,
'msg' => '您还未支付,请重新支付',
'url' => url('pay/pcpay', ['order_sn' => $order_sn])->build()
]);
}
}
}

View File

@@ -0,0 +1,240 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Log;
use think\facade\Request;
use think\facade\View;
use think\exception\HttpResponseException;
use think\Response;
class Payesta extends Base
{
private $order_sn = '';
public function initialize()
{
parent::initialize();
$this->order_sn = Request::instance()->param('order_sn', '');
if (empty($this->order_sn)) {
throw new HttpResponseException(Response::create($this->error('缺少订单号,请重新填写', url('esta/index'))));
}
}
public function index()
{
if (isMobile()) {
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false) {
return redirect(url('payesta/wxpay', ['order_sn' => $this->order_sn])->build());
}
return redirect(url('payesta/h5pay', ['order_sn' => $this->order_sn])->build());
}
return redirect(url('payesta/pcpay', ['order_sn' => $this->order_sn])->build());
}
/**
* 跳到微信支付
*/
public function wxpay()
{
$wechaturl = config('app.wechatpay');
$wechaturl .= '?order_sn=' . $this->order_sn . '&mark=' . PAY_ESTA_MARK . '&body=' . urlencode(ESTA_COUNTRY . '服务费');
header('location:' . $wechaturl); // 跳转到 user/profile
exit;
}
/**
* 跳转到pc支付
*/
public function pcpay()
{
$order_sn = $this->order_sn;
//判断支付是否已完成
$order_url = config('app.get_order_detail_url');
$response = Httpcurl::request($order_url, 'post', ['order_sn' => $order_sn, 'model' => ESTA_MODEL]);
if ($response[3]) {
return $this->error("异常错误,请重新提交", url('detail/index'));
}
$pay_result = json_decode($response[0], true);
Log::info(json_encode($pay_result));
if (empty($pay_result)) {
return $this->error("异常错误,请重新提交", url('detail/index'));
}
if (!$pay_result['code']) {
return $this->error($pay_result['msg'], url('detail/index'));
}
$pay_result = $pay_result['data'];
if ($pay_result['pay_status']) {
return $this->success('您已支付成功,请勿重复支付', url('detail/index'));
}
//微信pc
$cfg = config('app.wechatpcpay');
$res = Httpcurl::request($cfg, 'get', array('order_sn' => $order_sn, 'mark' => PAY_ESTA_MARK, 'body' => ESTA_COUNTRY . '服务费'));
$wxurl = "";
if (!$res[3]) {
$result = json_decode($res[0], true);
$wxurl = $result['url'];
}
Log::info(json_encode($res));
//支付宝pc
$cfg = config('app.alipcpay');
$res = Httpcurl::request($cfg, 'get', array('order_sn' => $order_sn, 'mark' => PAY_ESTA_MARK, 'body' => urlencode(ESTA_COUNTRY . '服务费')));
$aliurl = "";
if (!$res[3]) {
$result = json_decode($res[0], true);
$aliurl = $result['url'];
}
Log::info(json_encode($res));
View::assign('url', $wxurl);
View::assign('aliurl', $aliurl);
View::assign('order_sn', $order_sn);
View::assign('total_fee', number_format($pay_result['total_price'] / 100, 2));
return View::fetch();
}
/**
* 跳转到H5支付
*/
public function h5pay()
{
$wechaturl = config('app.wechath5pay');
$wechaturl .= '?order_sn=' . $this->order_sn . '&mark=' . PAY_ESTA_MARK . '&body=' . urlencode(ESTA_COUNTRY . '服务费');
header('location:' . $wechaturl); // 跳转到 user/profile
exit;
}
public function succ()
{
$order_sn = $this->order_sn;
View::assign('order_sn', $order_sn);
return View::fetch();
}
/**
* h5支付结果页面
*/
public function h5result()
{
if (Request::instance()->isAjax()) {
$order_sn = $this->order_sn;
if (!$order_sn) {
return json([
'status' => 0,
'msg' => '订单号不存在,请重新支付',
'url' => url('payesta/index', ['order_sn' => $order_sn])->build()
]);
}
$order_url = config('app.get_order_detail_url');
$response = Httpcurl::request($order_url, 'post', ['order_sn' => $order_sn, 'model' => ESTA_MODEL]);
if ($response[3]) {
return json([
'status' => 0,
'msg' => '异常错误,请重新提交',
'url' => url('payesta/index', ['order_sn' => $order_sn])->build()
]);
}
$pay_result = json_decode($response[0], true);
Log::info(json_encode($pay_result));
if (empty($pay_result)) {
return json([
'status' => 0,
'msg' => '异常错误,请重新提交',
'url' => url('payesta/index', ['order_sn' => $order_sn])->build()
]);
}
if (!$pay_result['code']) {
return json([
'status' => 0,
'msg' => $pay_result['msg'],
'url' => url('payesta/index', ['order_sn' => $order_sn])->build()
]);
}
$pay_result = $pay_result['data'];
if ($pay_result['pay_status']) {
return json([
'status' => 1,
'msg' => '支付成功',
'url' => url('payesta/succ', ['order_sn' => $order_sn])->build()
]);
}
return json([
'status' => 0,
'msg' => '您还未支付,请重新支付',
'url' => url('payesta/h5pay', ['order_sn' => $order_sn])->build()
]);
}
return View::fetch();
}
/**
* pc支付结果页面
*/
public function pcresult()
{
if (Request::instance()->isAjax()) {
$order_sn = $this->order_sn;
if (!$order_sn) {
return json([
'status' => 0,
'msg' => '订单号不存在,请重新支付',
'url' => url('payesta/index', ['order_sn' => $order_sn])->build()
]);
}
$order_url = config('app.get_order_detail_url');
$response = Httpcurl::request($order_url, 'post', ['order_sn' => $order_sn, 'model' => ESTA_MODEL]);
if ($response[3]) {
return json([
'status' => 0,
'msg' => '异常错误,请重新提交',
'url' => url('payesta/index', ['order_sn' => $order_sn])->build()
]);
}
$pay_result = json_decode($response[0], true);
Log::info(json_encode($pay_result));
if (empty($pay_result)) {
return json([
'status' => 0,
'msg' => '异常错误,请重新提交',
'url' => url('payesta/index', ['order_sn' => $order_sn])->build()
]);
}
if (!$pay_result['code']) {
return json([
'status' => 0,
'msg' => $pay_result['msg'],
'url' => url('payesta/index', ['order_sn' => $order_sn])->build()
]);
}
$pay_result = $pay_result['data'];
if ($pay_result['pay_status']) {
return json([
'status' => 1,
'msg' => '支付成功',
'url' => url('payesta/succ', ['order_sn' => $order_sn])->build()
]);
}
return json([
'status' => 0,
'msg' => '您还未支付,请重新支付',
'url' => url('payesta/pcpay', ['order_sn' => $order_sn])->build()
]);
}
}
}

227
app/home/controller/Seo.php Normal file
View File

@@ -0,0 +1,227 @@
<?php
declare(strict_types=1);
namespace app\home\controller;
use api\Httpcurl;
use app\service\SeoMetaService;
use app\service\SitemapService;
use think\facade\Log;
use Throwable;
final class Seo
{
public function sitemap()
{
$seoConfig = (array) config('seo');
$sitemapConfig = (array) ($seoConfig['sitemap'] ?? []);
$baseUrl = (new SeoMetaService($seoConfig))->baseUrl();
if ($baseUrl === '') {
return response(
'SEO_BASE_URL is not configured.',
503,
['Content-Type' => 'text/plain; charset=UTF-8']
);
}
$cacheSeconds = max(60, (int) ($sitemapConfig['cache_seconds'] ?? 3600));
$cacheDirectory = runtime_path('seo');
$cacheFile = $cacheDirectory
. 'sitemap-'
. substr(hash('sha256', $baseUrl), 0, 16)
. '.xml';
$cachedXml = $this->readCache($cacheFile);
$cacheTime = is_file($cacheFile) ? filemtime($cacheFile) : false;
if (
$cachedXml !== ''
&& $cacheTime !== false
&& $cacheTime + $cacheSeconds > time()
) {
return $this->xmlResponse($cachedXml, $cacheSeconds);
}
$service = new SitemapService($baseUrl);
$entries = $this->staticEntries($seoConfig);
[$newsEntries, $newsComplete] = $this->newsEntries($sitemapConfig);
if (!$newsComplete && $cachedXml !== '') {
return $this->xmlResponse($cachedXml, 300);
}
$xml = $service->render(array_merge($entries, $newsEntries));
if ($newsComplete) {
$this->writeCache($cacheDirectory, $cacheFile, $xml);
}
return $this->xmlResponse($xml, $newsComplete ? $cacheSeconds : 300);
}
public function robots()
{
$seoConfig = (array) config('seo');
$baseUrl = (new SeoMetaService($seoConfig))->baseUrl();
$service = new SitemapService($baseUrl);
$robots = $service->renderRobots($this->disallowPaths($seoConfig));
return response($robots, 200, [
'Content-Type' => 'text/plain; charset=UTF-8',
'Cache-Control' => 'public, max-age=3600',
]);
}
private function staticEntries(array $seoConfig): array
{
$entries = [];
foreach ((array) ($seoConfig['pages'] ?? []) as $route => $page) {
$page = (array) $page;
if (!str_starts_with((string) $route, 'home/')) {
continue;
}
if (!str_starts_with((string) ($page['robots'] ?? ''), 'index')) {
continue;
}
if ($route === 'home/news/detail') {
continue;
}
$path = (string) ($page['canonical_path'] ?? '');
if ($path !== '') {
$entries[] = ['path' => $path];
}
}
return $entries;
}
private function newsEntries(array $sitemapConfig): array
{
$url = trim((string) ($sitemapConfig['news_list_url'] ?? ''));
if (filter_var($url, FILTER_VALIDATE_URL) === false) {
Log::warning('SEO sitemap news URL is invalid.');
return [[], false];
}
$pageSize = max(1, min(500, (int) ($sitemapConfig['news_page_size'] ?? 100)));
$maxPages = max(1, min(500, (int) ($sitemapConfig['max_news_pages'] ?? 100)));
$entries = [];
$fetchedItems = 0;
for ($page = 1; $page <= $maxPages; $page++) {
try {
$response = Httpcurl::request($url, 'post', [
'model' => 'article',
'source_code' => 'cn',
'page' => $page,
'size' => $pageSize,
], [], 5);
} catch (Throwable $exception) {
Log::warning('SEO sitemap news request failed: ' . $exception->getMessage());
return [$entries, false];
}
if (!is_array($response) || !isset($response[0]) || !empty($response[3])) {
Log::warning('SEO sitemap news request returned an invalid response.');
return [$entries, false];
}
$statusCode = (int) ($response[2]['http_code'] ?? 0);
if ($statusCode < 200 || $statusCode >= 300) {
Log::warning('SEO sitemap news request returned an invalid HTTP status.');
return [$entries, false];
}
$result = json_decode((string) $response[0], true);
if (
!is_array($result)
|| (int) ($result['code'] ?? 0) !== 1
|| !is_array($result['data'] ?? null)
) {
Log::warning('SEO sitemap news response could not be decoded.');
return [$entries, false];
}
$items = $result['data'];
$fetchedItems += count($items);
foreach ($items as $item) {
if (!is_array($item)) {
continue;
}
$id = filter_var($item['id'] ?? null, FILTER_VALIDATE_INT, [
'options' => ['min_range' => 1],
]);
if ($id === false) {
continue;
}
$entries[] = [
'path' => '/home/news/detail',
'query' => ['id' => $id],
'lastmod' => $this->articleDate((string) ($item['create_time'] ?? '')),
];
}
$total = max(0, (int) ($result['count'] ?? 0));
if (
$items === []
|| ($total > 0 && $fetchedItems >= $total)
|| ($total === 0 && count($items) < $pageSize)
) {
return [$entries, true];
}
}
Log::warning('SEO sitemap news pagination reached the configured page limit.');
return [$entries, false];
}
private function disallowPaths(array $seoConfig): array
{
$paths = [];
foreach ((array) ($seoConfig['noindex_controllers'] ?? []) as $controller) {
$controller = trim((string) $controller, '/');
if ($controller !== '') {
$paths[] = '/home/' . $controller . '/';
}
}
return $paths;
}
private function articleDate(string $date): string
{
$timestamp = strtotime($date);
return $timestamp === false ? '' : date('Y-m-d', $timestamp);
}
private function readCache(string $cacheFile): string
{
if (!is_file($cacheFile) || !is_readable($cacheFile)) {
return '';
}
$contents = file_get_contents($cacheFile);
return is_string($contents) ? $contents : '';
}
private function writeCache(string $directory, string $cacheFile, string $xml): void
{
if (!is_dir($directory) && !mkdir($directory, 0775, true) && !is_dir($directory)) {
Log::warning('SEO sitemap cache directory could not be created.');
return;
}
if (file_put_contents($cacheFile, $xml, LOCK_EX) === false) {
Log::warning('SEO sitemap cache could not be written.');
}
}
private function xmlResponse(string $xml, int $maxAge)
{
return response($xml, 200, [
'Content-Type' => 'application/xml; charset=UTF-8',
'Cache-Control' => 'public, max-age=' . max(0, $maxAge),
'X-Robots-Tag' => 'noindex',
]);
}
}

View File

@@ -0,0 +1,434 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\facade\Db;
use think\facade\Request;
use think\facade\Session;
use think\facade\View;
class Update extends Base
{
public function index()
{
$id = Request::param('id');
$order_sn = Request::param('order_sn');
if (empty($id) || empty($order_sn)) {
return $this->error('参数错误');
}
//获取数据
$data = Db::name('msg')->where(['id' => $id, 'order_sn' => $order_sn])->find();
if (empty($data)) {
return $this->error('无此数据');
}
$refer_url = isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : '';
if ($refer_url){
Session::set('update_refer_url',$refer_url);
}
View::assign('data', $data);
View::assign('id', $id);
View::assign('order_sn', $order_sn);
return View::fetch();
}
function do_apply()
{
unset($_REQUEST['s']);
$id = Request::param('id');
$order_sn = Request::param('order_sn');
file_put_contents('/www/newevus/update.log',
"{$order_sn}.'-'.{$id}===" . json_encode($_REQUEST) . "\r\n", FILE_APPEND);
$insert_id = Db::name('msg')->where(['id' => $id, 'order_sn' => $order_sn])->update($_REQUEST);
$refer_url= Session::get('update_refer_url');
if ($insert_id >= 0) {
return $this->success('修改成功',$refer_url);
} else {
return $this->error("提交失败,请联系管理员!",$refer_url);
}
}
public function adminindex()
{
$order_sn = Request::param('order_sn');
if (empty($order_sn)) {
return $this->error('参数错误');
}
$response = Httpcurl::request(config('app.get_evus_detail_url'), 'post', ['order_sn' => $order_sn, 'model' => MODEL]);
if ($response[3]) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
if (!$pay_result['code']) {
return $this->error($pay_result['msg'], url('detail/index'));
}
$refer_url = Request::param('return_url');
if ($refer_url) {
Session::set('update_refer_url', $refer_url);
}
View::assign('country_list', json_decode(file_get_contents('./json/country.json'), true));
View::assign('phone_prefix', json_decode(file_get_contents('./json/phone_prefix.json'), true));
View::assign('us', json_decode(file_get_contents('./json/us.json'), true));
View::assign('data', $pay_result['data']);
return View::fetch();
}
public function order_apply()
{
$order_sn = Request::param('order_sn');
if (!$order_sn) {
return $this->error(lang('controller.order_not_exist'));
}
$response = Httpcurl::request(config('app.get_evus_detail_url'), 'post', ['order_sn' => $order_sn, 'model' => MODEL]);
if ($response[3]) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
if (!$pay_result['code']) {
return $this->error($pay_result['msg'], url('detail/index'));
}
unset($_REQUEST['s']);
$_REQUEST['birth_date_day'] = (string)date_parse($_REQUEST['birth_date'])['day'] ?:'0';
$_REQUEST['birth_date_month'] = (string)date_parse($_REQUEST['birth_date'])['month'] ?:'0';
$_REQUEST['birth_date_year'] = (string)date_parse($_REQUEST['birth_date'])['year'] ?:'0';
$_REQUEST['passport_expedition_date_day'] = (string)date_parse($_REQUEST['passport_expedition_date'])['day'] ?:'';
$_REQUEST['passport_expedition_date_month'] = (string)date_parse($_REQUEST['passport_expedition_date'])['month'] ?:'';
$_REQUEST['passport_expedition_date_year'] = (string)date_parse($_REQUEST['passport_expedition_date'])['year'] ?:'';
$_REQUEST['passport_expiration_date_day'] = (string)date_parse($_REQUEST['passport_expiration_date'])['day'] ?:'';
$_REQUEST['passport_expiration_date_month'] = (string)date_parse($_REQUEST['passport_expiration_date'])['month'] ?:'';
$_REQUEST['passport_expiration_date_year'] = (string)date_parse($_REQUEST['passport_expiration_date'])['year'] ?:'';
$_REQUEST['us_visa_passport_issue_date_day'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['day'] ?:'';
$_REQUEST['us_visa_passport_issue_date_month'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['month'] ?:'';
$_REQUEST['us_visa_passport_issue_date_year'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['year'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_day'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['day'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_month'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['month'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_year'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['year'] ?:'';
$_REQUEST['us_visa_birth_date_day'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['day'] ?:'';
$_REQUEST['us_visa_birth_date_month'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['month'] ?:'';
$_REQUEST['us_visa_birth_date_year'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['year'] ?:'';
$_REQUEST = formDataToJson(['vist_country', 'vist_from_date', 'vist_end_date', 'vist_country_des'], $_REQUEST, 'vistitem', 'question_i');
$_REQUEST['other_country_acquired_other'] = isset($_REQUEST['other_country_acquired_other']) ? $_REQUEST['other_country_acquired_other'] : '';
$_REQUEST['model'] = MODEL;
$_REQUEST['token'] = md5(MODEL);
$_REQUEST['order_sn'] = $order_sn;
$_REQUEST['total_price'] = $pay_result['data']['total_price'];
try {
$insert_id = Httpcurl::request(UPDATE_EVUS_ORDER_URL, 'post', $_REQUEST);
$result = json_decode($insert_id[0], true);
$refer_url= Session::get('update_refer_url');
if (empty($result)) {
return $this->error(lang('controller.fail'));
}
if (!$result['code']) {
return $this->error(lang('controller.fail'));
}
return $this->success(lang('controller.success'), $refer_url);
} catch (\Exception $e) {
return $this->error(lang('controller.fail'));
}
}
public function adminesta()
{
$order_sn = Request::param('order_sn');
if (empty($order_sn)) {
return $this->error('参数错误');
}
$response = Httpcurl::request(config('app.get_order_detail_url'), 'post', ['order_sn' => $order_sn, 'model' => ESTA_MODEL]);
if ($response[3]) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
if (!$pay_result['code']) {
return $this->error($pay_result['msg'], url('detail/index'));
}
$refer_url = isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : '';
if ($refer_url) {
Session::set('update_refer_url', $refer_url);
}
View::assign('country_list', json_decode(file_get_contents('./json/country.json'), true));
View::assign('phone_prefix', json_decode(file_get_contents('./json/phone_prefix.json'), true));
View::assign('us', json_decode(file_get_contents('./json/us.json'), true));
View::assign('goods', config('app.ESTA_GOODS'));
View::assign('ismobile', isMobile() ? 1 : 0);
View::assign('ppt_sample_url', '/new/assets/images/shili.jpg');
View::assign('per_sample_url', '/new/assets/images/persion2.png');
View::assign('data', $pay_result['data']);
View::assign('id', $pay_result['data']['id']);
return View::fetch();
}
public function detail()
{
$order_sn = Request::param('id');
if (empty($order_sn)) {
return $this->error('参数错误');
}
$response = Httpcurl::request(config('app.get_evus_detail_url'), 'post', ['order_sn' => $order_sn, 'model' => MODEL]);
if ($response[3]) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
if (!$pay_result['code']) {
return $this->error($pay_result['msg'], url('detail/index'));
}
View::assign('country_list', json_decode(file_get_contents('./json/country.json'), true));
View::assign('phone_prefix', json_decode(file_get_contents('./json/phone_prefix.json'), true));
View::assign('us', json_decode(file_get_contents('./json/us.json'), true));
View::assign('data', $pay_result['data']);
return View::fetch();
}
/**
* 未支付订单去支付
*/
public function do_unpay()
{
$order_sn = Request::param('order_sn');
if (empty($order_sn)) {
return $this->error('参数错误');
}
$response = Httpcurl::request(config('app.get_evus_detail_url'), 'post', ['order_sn' => $order_sn, 'model' => MODEL]);
if ($response[3]) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
if (!$pay_result['code']) {
return $this->error($pay_result['msg'], url('detail/index'));
}
$order_sn = $_REQUEST['order_sn'] = getOrderNumber();
$total_price =$pay_result['data']['total_price'];
/*判断价格是否正确*/
$config_price = array_map(function($item) {
return $item['value'];
}, config('app.EVUS_GOODS'));
if (!in_array($total_price, $config_price)) {
return $this->error('价格错误');
}
/*判断价格是否正确*/
$_REQUEST['birth_date_day'] = (string)date_parse($_REQUEST['birth_date'])['day'] ?:'0';
$_REQUEST['birth_date_month'] = (string)date_parse($_REQUEST['birth_date'])['month'] ?:'0';
$_REQUEST['birth_date_year'] = (string)date_parse($_REQUEST['birth_date'])['year'] ?:'0';
$_REQUEST['passport_expedition_date_day'] = (string)date_parse($_REQUEST['passport_expedition_date'])['day'] ?:'';
$_REQUEST['passport_expedition_date_month'] = (string)date_parse($_REQUEST['passport_expedition_date'])['month'] ?:'';
$_REQUEST['passport_expedition_date_year'] = (string)date_parse($_REQUEST['passport_expedition_date'])['year'] ?:'';
$_REQUEST['passport_expiration_date_day'] = (string)date_parse($_REQUEST['passport_expiration_date'])['day'] ?:'';
$_REQUEST['passport_expiration_date_month'] = (string)date_parse($_REQUEST['passport_expiration_date'])['month'] ?:'';
$_REQUEST['passport_expiration_date_year'] = (string)date_parse($_REQUEST['passport_expiration_date'])['year'] ?:'';
$_REQUEST['us_visa_passport_issue_date_day'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['day'] ?:'';
$_REQUEST['us_visa_passport_issue_date_month'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['month'] ?:'';
$_REQUEST['us_visa_passport_issue_date_year'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['year'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_day'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['day'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_month'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['month'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_year'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['year'] ?:'';
$_REQUEST['us_visa_birth_date_day'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['day'] ?:'';
$_REQUEST['us_visa_birth_date_month'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['month'] ?:'';
$_REQUEST['us_visa_birth_date_year'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['year'] ?:'';
$_REQUEST = formDataToJson(['vist_country', 'vist_from_date', 'vist_end_date', 'vist_country_des'], $_REQUEST, 'vistitem', 'question_i');
$_REQUEST['other_country_acquired_other'] = isset($_REQUEST['other_country_acquired_other']) ? $_REQUEST['other_country_acquired_other'] : '';
$_REQUEST['source'] = Session::get('source' );
$_REQUEST['is_mobile'] = isMobile() ? 1 : 0;
$_REQUEST['total_price'] = $total_price;
$_REQUEST['origin_price'] = $total_price;
$_REQUEST['ip'] = getIP();
$_REQUEST['coupon_code'] = isset($_REQUEST['coupon_code']) ? $_REQUEST['coupon_code']: '';
$_REQUEST['model'] = MODEL;
$_REQUEST['token'] = md5(MODEL);
$_REQUEST['user_id'] = $this->_userId;
$order_res = Httpcurl::request(CREATE_EVUS_ORDER_URL, 'post', $_REQUEST);
$order = json_decode($order_res[0], true);
if (!$order['code']) {
return $this->error("提交失败,请联系管理员!");
}
if ($order['is_pay'] == 1) {
return $this->success('操作成功', url('home/pay/succ', ['order_sn' => $order_sn])->build());
}
return $this->success('操作成功', url('home/pay/index', ['order_sn' => $order_sn])->build());
}
public function upevus()
{
$id = Request::param('id');
if (empty($id)) {
return $this->error('参数错误');
}
$order_sn = base64_decode($id);
$response = Httpcurl::request(config('app.get_evus_detail_url'), 'post', ['order_sn' => $order_sn, 'model' => MODEL]);
if ($response[3]) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
if (!$pay_result['code']) {
return $this->error($pay_result['msg'], url('detail/index'));
}
View::assign('country_list', json_decode(file_get_contents('./json/country.json'), true));
View::assign('phone_prefix', json_decode(file_get_contents('./json/phone_prefix.json'), true));
View::assign('us', json_decode(file_get_contents('./json/us.json'), true));
View::assign('goods', config('app.EVUS_GOODS'));
View::assign('data', $pay_result['data']);
return View::fetch();
}
public function do_update()
{
unset($_REQUEST['s']);
$order_sn = $_REQUEST['order_sn'] = getOrderNumber();
$total_price = $_REQUEST['total_price'];
/*判断价格是否正确*/
$config_price = array_map(function($item) {
return $item['value'];
}, config('app.EVUS_GOODS'));
if (!in_array($total_price, $config_price)) {
return $this->error('价格错误');
}
/*判断价格是否正确*/
$_REQUEST['birth_date_day'] = (string)date_parse($_REQUEST['birth_date'])['day'] ?:'0';
$_REQUEST['birth_date_month'] = (string)date_parse($_REQUEST['birth_date'])['month'] ?:'0';
$_REQUEST['birth_date_year'] = (string)date_parse($_REQUEST['birth_date'])['year'] ?:'0';
$_REQUEST['passport_expedition_date_day'] = (string)date_parse($_REQUEST['passport_expedition_date'])['day'] ?:'';
$_REQUEST['passport_expedition_date_month'] = (string)date_parse($_REQUEST['passport_expedition_date'])['month'] ?:'';
$_REQUEST['passport_expedition_date_year'] = (string)date_parse($_REQUEST['passport_expedition_date'])['year'] ?:'';
$_REQUEST['passport_expiration_date_day'] = (string)date_parse($_REQUEST['passport_expiration_date'])['day'] ?:'';
$_REQUEST['passport_expiration_date_month'] = (string)date_parse($_REQUEST['passport_expiration_date'])['month'] ?:'';
$_REQUEST['passport_expiration_date_year'] = (string)date_parse($_REQUEST['passport_expiration_date'])['year'] ?:'';
$_REQUEST['us_visa_passport_issue_date_day'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['day'] ?:'';
$_REQUEST['us_visa_passport_issue_date_month'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['month'] ?:'';
$_REQUEST['us_visa_passport_issue_date_year'] = (string)date_parse($_REQUEST['us_visa_passport_issue_date'])['year'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_day'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['day'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_month'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['month'] ?:'';
$_REQUEST['us_visa_passport_expiration_date_year'] = (string)date_parse($_REQUEST['us_visa_passport_expiration_date'])['year'] ?:'';
$_REQUEST['us_visa_birth_date_day'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['day'] ?:'';
$_REQUEST['us_visa_birth_date_month'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['month'] ?:'';
$_REQUEST['us_visa_birth_date_year'] = (string)date_parse($_REQUEST['us_visa_birth_date'])['year'] ?:'';
$_REQUEST = formDataToJson(['vist_country', 'vist_from_date', 'vist_end_date', 'vist_country_des'], $_REQUEST, 'vistitem', 'question_i');
$_REQUEST['other_country_acquired_other'] = isset($_REQUEST['other_country_acquired_other']) ? $_REQUEST['other_country_acquired_other'] : '';
$_REQUEST['source'] = Session::get('source' );
$_REQUEST['is_mobile'] = isMobile() ? 1 : 0;
$_REQUEST['total_price'] = $total_price;
$_REQUEST['origin_price'] = $total_price;
$_REQUEST['ip'] = getIP();
$_REQUEST['coupon_code'] = isset($_REQUEST['coupon_code']) ? $_REQUEST['coupon_code']: '';
$_REQUEST['model'] = MODEL;
$_REQUEST['token'] = md5(MODEL);
$_REQUEST['user_id'] = $this->_userId;
$order_res = Httpcurl::request(CREATE_EVUS_ORDER_URL, 'post', $_REQUEST);
$order = json_decode($order_res[0], true);
if (!$order['code']) {
return $this->error("提交失败,请联系管理员!");
}
if ($order['is_pay'] == 1) {
return $this->success('操作成功', url('home/pay/succ', ['order_sn' => $order_sn])->build());
}
return $this->success('操作成功', url('home/pay/index', ['order_sn' => $order_sn])->build());
}
function do_esta_apply()
{
unset($_REQUEST['s']);
unset($_REQUEST['file']);
/*判断价格是否正确*/
$_REQUEST['birth_date_day'] = (string)date_parse($_REQUEST['birth_date'])['day'] ?:'0';
$_REQUEST['birth_date_month'] = (string)date_parse($_REQUEST['birth_date'])['month'] ?:'0';
$_REQUEST['birth_date_year'] = (string)date_parse($_REQUEST['birth_date'])['year'] ?:'0';
$_REQUEST['passport_expedition_date_day'] = (string)date_parse($_REQUEST['passport_expedition_date'])['day'] ?:'';
$_REQUEST['passport_expedition_date_month'] = (string)date_parse($_REQUEST['passport_expedition_date'])['month'] ?:'';
$_REQUEST['passport_expedition_date_year'] = (string)date_parse($_REQUEST['passport_expedition_date'])['year'] ?:'';
$_REQUEST['passport_expiration_date_day'] = (string)date_parse($_REQUEST['passport_expiration_date'])['day'] ?:'';
$_REQUEST['passport_expiration_date_month'] = (string)date_parse($_REQUEST['passport_expiration_date'])['month'] ?:'';
$_REQUEST['passport_expiration_date_year'] = (string)date_parse($_REQUEST['passport_expiration_date'])['year'] ?:'';
$_REQUEST['other_country_date_day'] = (string)date_parse($_REQUEST['other_country_date'])['day'] ?:'';
$_REQUEST['other_country_date_month'] = (string)date_parse($_REQUEST['other_country_date'])['month'] ?:'';
$_REQUEST['other_country_date_year'] = (string)date_parse($_REQUEST['other_country_date'])['year'] ?:'';
unset($_REQUEST['other_country_date']);
$_REQUEST['other_country_edate_day'] = (string)date_parse($_REQUEST['other_country_edate'])['day'] ?:'';
$_REQUEST['other_country_edate_month'] = (string)date_parse($_REQUEST['other_country_edate'])['month'] ?:'';
$_REQUEST['other_country_edate_year'] = (string)date_parse($_REQUEST['other_country_edate'])['year'] ?:'';
unset($_REQUEST['other_country_edate']);
$_REQUEST['model'] = ESTA_MODEL;
$_REQUEST['token'] = md5(ESTA_MODEL);
$_REQUEST['other_country_acquired_other'] = isset($_REQUEST['other_country_acquired_other']) ? $_REQUEST['other_country_acquired_other'] : '';
$refer_url= Session::get('update_refer_url');
$order_res = Httpcurl::request(config('app.update_order_url'), 'post', $_REQUEST);
$order = json_decode($order_res[0], true);
if (!$order['code']) {
return $this->error("提交失败,请联系管理员!");
}
// python($order_sn);
return $this->success('修改成功', $refer_url);
}
function do_admin_apply()
{
unset($_REQUEST['s'],$_REQUEST['id']);
$id = Request::param('id');
$order_sn = think_decrypt($id);
if (empty($_REQUEST['family_name_alias']) || empty($_REQUEST['given_name_alias'])){
$_REQUEST['have_alias'] = 2;
}
$data = Db::name('msg')->where(['order_sn' => $order_sn])->find();
$insert_id = Db::name('msg')->where(['order_sn' => $order_sn])->update($_REQUEST);
// $url = "http://manage.evus.cn/index.php?s=/Immigrant/index.html";
$url='https://manage.evus.cn/index.php?s=/Immigrant/detail/id/'.$data['id'];
Db::name('msg_format')->where(['order_sn' => $order_sn])->delete();
if ($insert_id >= 0) {
// python($order_sn);
return $this->success('修改成功', $url);
// $this->redirect($url);
} else {
return $this->error("提交失败,请联系管理员!", $url);
}
}
}

View File

@@ -0,0 +1,153 @@
<?php
declare (strict_types=1);
namespace app\home\controller;
use api\Httpcurl;
use app\service\SwooleService;
use think\facade\Db;
use think\facade\Request;
use think\facade\View;
class Upload extends Base
{
public function index()
{
$order_sn = Request::instance()->param('id');
!empty($order_sn) or $this->error('参数错误');
//获取数据
$response = Httpcurl::request(config('app.get_evus_detail_url'), 'post', ['order_sn' => $order_sn, 'model' => MODEL]);
if ($response[3]) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return $this->error("订单不存在,请重新提交", url('detail/index'));
}
if (!$pay_result['code']) {
return $this->error($pay_result['msg'], url('detail/index'));
}
Db::name('images_log')->where(['order_sn' => $order_sn, 'type' => 'evus登记信息(护照、签证)有误'])->update([
'is_read' => 1
]);
View::assign('data', $pay_result['data']);
return View::fetch();
}
public function upload_file()
{
// 获取上传的文件
$file = request()->file('file');
if (!$file) {
return json([
'code' => 0,
'msg' => '请选择上传文件',
]);
}
$imgdata = file_get_contents($file->getPathname());
/*同时上传护照文件*/
$fileName = date('YmdHis') . uniqid() . '.' . pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
try {
$client = SwooleService::getInstance();
$client->sendTask([
'type' => 'upload_ali',
'data' => [
'Bucket' => BUCKET,
'Key' => $fileName, //重命名的文件名
'file_content' => base64_encode($imgdata),
]
]);
$client->close();
return json([
'code' => 1,
'msg' => '上传成功',
'path' => OSS_URL . $fileName,
]);
} catch (\Exception $e) {
return json([
'code' => 0,
'msg' => '上传失败',
'path' => ''
]);
}
}
public function file_upload()
{
// 获取上传的文件
$file = request()->file('file');
if (!$file) {
return json([
'code' => 0,
'msg' => '请选择上传文件',
]);
}
$imgdata = file_get_contents($file->getPathname());
$fileName = date('YmdHis') . uniqid() . '.' . pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
try {
$client = SwooleService::getInstance();
$client->sendTask([
'type' => 'upload_ali',
'data' => [
'Bucket' => BUCKET,
'Key' => $fileName, //重命名的文件名
'file_content' => base64_encode($imgdata),
]
]);
$client->close();
return json([
'code' => 1,
'msg' => '上传成功',
'path' => OSS_URL . $fileName,
]);
} catch (\Exception $e) {
return json([
'code' => 0,
'msg' => '上传失败',
'path' => '',
]);
}
}
public function doapply()
{
$params = Request::instance()->param();
!empty($params['order_sn']) or $this->error('参数错误');
$imgs = array_filter($params['imgs']);
if (empty($imgs)) {
return $this->error('请上传照片');
}
$order = Db::name('msg')->where(['order_sn' => $params['order_sn']])->find();
if (empty($order)) {
return $this->error('数据错误,请联系管理员');
}
$data = [];
foreach ($imgs as $ig) {
$data[] = [
'order_id' => $order['id'],
'order_sn' => $order['order_sn'],
'last_name' => $order['last_name'],
'first_name' => $order['first_name'],
'passport_number' => $order['passport_number'],
'visa_foil_number' => $order['visa_foil_number'],
'img' => $ig
];
}
$res = Db::name('images')->insertAll($data);
if ($res > 0) {
//推送发票
$url = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=4c22d454-4abf-48bb-8512-fb591a3ac545';
$data = array('msgtype' => 'text', 'text' => [
'content' => "订单号{$order['order_sn']}已成功更新护照信息,请及时处理",
]);
Httpcurl::request($url, 'post', json_encode($data), [
'Content-Type: application/json'
]);
return $this->success('上传成功', url('home/index/index'));
} else {
return $this->error('数据错误,请联系管理员');
}
}
}

View File

@@ -0,0 +1,278 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\exception\HttpResponseException;
use think\facade\Log;
use think\facade\Request;
use think\facade\Session;
use think\facade\View;
use think\Response;
class User extends Base
{
private $userinfo;
private static $follow_status = [
'0' => '未跟进',
'1' => '跟进中',
'3' => '已完成',
];
public function initialize()
{
parent::initialize();
if (!Session::has('user') || Session::get('user')['id'] <= 0) {
throw new HttpResponseException(redirect('/home/login'));
}
$this->userinfo = Session::get('user');
View::assign('userinfo', $this->userinfo);
View::assign('is_user_center', true);
}
/**个人中心
*/
public function order()
{
$paystatus = Request::instance()->param('paystatus', '');
$paystatus = $paystatus ? $paystatus : 'pay';
if (!in_array($paystatus, ['pay', 'nopay'])) {
return $this->error('参数错误');
}
$list = Httpcurl::request(GET_ORDER_URL, 'post', [
'model' => MODEL,
'user_id' => $this->_userId,
'invoiceType' => INCOICETYPE,
'pay_status' => $paystatus,
]);
$result = json_decode($list[0], true);
Log::info(json_encode($result));
if (empty($result)) {
return $this->error('获取订单失败');
}
if (!$result['code']) {
return $this->error('获取订单失败');
}
return view('', [
'paystauts' => $paystatus,
'data' => $result['data'],
]);
}
public function orderEsta()
{
$paystatus = Request::instance()->param('paystatus', '');
$paystatus = $paystatus ? $paystatus : 'pay';
if (!in_array($paystatus, ['pay', 'nopay'])) {
return $this->error('参数错误');
}
$list = Httpcurl::request(GET_ORDER_URL, 'post', [
'model' => ESTA_MODEL,
'user_id' => $this->_userId,
'invoiceType' => ESTA_INCOICETYPE,
'pay_status' => $paystatus,
]);
$result = json_decode($list[0], true);
Log::info(json_encode($result));
if (empty($result)) {
return $this->error('获取订单失败');
}
if (!$result['code']) {
return $this->error('获取订单失败');
}
return view('', [
'paystauts' => $paystatus,
'data' => $result['data'],
]);
}
public function invoice()
{
return View::fetch();
}
public function multiple()
{
return View::fetch();
}
public function logout()
{
Session::delete('user');
return redirect('/home/index');
}
public function checkInvoice()
{
$res = [
'status' => 0,
'msg' => '操作失败'
];
$passport_number = Request::instance()->param('passport_number');
$order_sn = Request::instance()->param('order_sn');
$last_name = Request::instance()->param('last_name');
$first_name = Request::instance()->param('first_name');
if (empty($passport_number) || empty($order_sn) || empty($last_name) || empty($first_name)) {
$res['msg'] = '参数错误';
return json($res);
}
$base_url = config('app.order_url');
$order_url = $base_url . 'checkInvoice';
$response = Httpcurl::request($order_url, 'post', [
'passport_number' => trim($passport_number),
'order_sn' => trim($order_sn),
'last_name' => trim($last_name),
'first_name' => trim($first_name),
'model' => MODEL
]);
if ($response[3]) {
$res['msg'] = '参数错误';
return json($res);
}
$data = json_decode($response[0], true);
Log::info(json_encode($data));
if (empty($data)) {
$res['msg'] = '系统错误,请联系管理员!';
return json($res);
}
if (!$data['code']) {
$res['msg'] = "暂无订单信息";
return json($res);
}
$invoice_url = $base_url . 'getInvoice';
//判断是否已经开票了
$response = Httpcurl::request($invoice_url, 'post', [
'order_sn' => $order_sn,
'invoiceType' => INCOICETYPE,
'model' => MODEL
]);
if ($response[3]) {
$res['msg'] = '参数错误';
return json($res);
}
$order = json_decode($response[0], true);
Log::info(json_encode($order));
if (empty($order)) {
$res['msg'] = '系统错误,请联系管理员!';
return json($res);
}
if (!$order['code']) {
return json($res);
}
if (!empty($order['data'])) {
$res['msg'] = '发票已受理,请勿重复提交';
return json($res);
}
$res = [
'status' => 1,
'msg' => '操作成功',
'url' => '/home/invoice/index/order_sn/' . $order_sn
];
return json($res);
}
public function checkMultiple()
{
$res = [
'status' => 0,
'msg' => '操作失败'
];
$datas = Request::instance()->param('datas');
if (empty($datas)) {
$res['msg'] = '参数错误';
return json($res);
}
$datas = json_decode(html_entity_decode(stripslashes($datas)), true);
if (empty($datas)) {
$res['msg'] = '数据错误';
return json($res);
}
$order_sns = array_column($datas, 'order_sn');
//判断是否有重复订单
if (count($order_sns) != count(array_unique($order_sns))) {
$res['msg'] = '有重复订单,请删除后重新提交';
return json($res);
}
$base_url = config('app.order_url');
$order_url = $base_url . 'checkInvoice';
$invoice_url = $base_url . 'getInvoice';
foreach ($datas as $da) {
//获取信息
$response = Httpcurl::request($order_url, 'post', [
'passport_number' => trim($da['passport_number']),
'order_sn' => trim($da['order_sn']),
'last_name' => trim($da['last_name']),
'first_name' => trim($da['first_name']),
'model' => MODEL
]);
if ($response[3]) {
$res['msg'] = '参数错误';
return json($res);
}
$data = json_decode($response[0], true);
Log::info(json_encode($data));
if (empty($data)) {
$res['msg'] = '未查到订单信息';
return json($res);
}
//查询是否已经开票了
$response = Httpcurl::request($invoice_url, 'post', [
'order_sn' => trim($da['order_sn']),
'invoiceType' => INCOICETYPE,
'model' => MODEL
]);
if ($response[3]) {
$res['msg'] = '参数错误';
return json($res);
}
$order = json_decode($response[0], true);
Log::info(json_encode($order));
if (empty($order)) {
$res['msg'] = '系统错误,请联系管理员!';
return json($res);
}
if (!$order['code']) {
$res['msg'] = $order['msg'];
return json($res);
}
if (!empty($order['data'])) {
$res['msg'] = '订单号:' . $da['order_sn'] . '已经开票';
return json($res);
}
}
$order_sns = implode('-', $order_sns);
$res = [
'status' => 1,
'msg' => '操作成功',
'url' => url('home/multiple/index', ['id' => base64_encode($order_sns)])->build()
];
return json($res);
}
public function pay()
{
$order_sn = Request::instance()->param('order_sn');
if (empty($order_sn)) {
return $this->error('参数错误');
}
$order_url = config('app.get_evus_detail_url');
$response = Httpcurl::request($order_url, 'post', ['order_sn' => $order_sn, 'model' => MODEL]);
if ($response[3]) {
return $this->error("订单不存在,请重新提交", url('visa/index'));
}
$pay_result = json_decode($response[0], true);
Log::info(json_encode($pay_result));
if (empty($pay_result)) {
return $this->error("订单不存在,请重新提交", url('visa/index'));
}
if (!$pay_result['code']) {
return $this->error($pay_result['msg'], url('visa/index'));
}
return redirect(url('home/pay/index', ['order_sn' => $pay_result['data']['order_sn']])->build());
}
}

View File

@@ -0,0 +1,72 @@
<?php
declare (strict_types=1);
namespace app\home\controller;
use app\service\UsvisaIntakeService;
use think\facade\Log;
use think\facade\Request;
use think\facade\View;
class Usvisa extends Base
{
public function index()
{
$intake = new UsvisaIntakeService();
View::assign($intake->pageContext(Request::instance()->param()));
return View::fetch();
}
public function submit()
{
if (!request()->isPost()) {
return json([
'code' => -1,
'msg' => '请通过页面提交信息',
]);
}
$intake = new UsvisaIntakeService();
$params = Request::instance()->param();
unset($params['s']);
$branch = $intake->branchByCode($params['branch_code'] ?? '');
if (empty($branch)) {
return json([
'code' => -1,
'msg' => '请确认扫码支行信息',
]);
}
$submission = $intake->submissionFrom($params, $branch);
$requiredMessage = $intake->requiredMessage($submission);
if ($requiredMessage !== '') {
return json([
'code' => -1,
'msg' => $requiredMessage,
]);
}
try {
$result = $intake->submitToApi($submission);
} catch (\Throwable $e) {
Log::error('Failed to submit usvisa to OA: ' . $e->getMessage());
return json([
'code' => -1,
'msg' => '提交失败,请稍后再试',
]);
}
if (!$intake->apiSuccess($result)) {
Log::warning('OA usvisa api returned failure: ' . json_encode([
'code' => $result['code'] ?? null,
'msg' => $result['msg'] ?? '',
], JSON_UNESCAPED_UNICODE));
}
return json($result);
}
}

View File

@@ -0,0 +1,783 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\facade\Config;
use think\facade\Db;
use think\facade\Log;
use think\facade\Request;
use think\facade\Session;
use think\facade\View;
class Visa extends Base
{
public function initialize()
{
parent::initialize();
View::assign('keytitle', 'evus登记-EVUS中文网');
View::assign('description', 'evus登记');
View::assign('keywords', 'EVUS中文网为您提供evus登记服务,方便您登记、办理evus,如登记中有任何问题可直接咨询。');
}
public function apply()
{
return View::fetch();
}
public function upvisa()
{
$order_sn = Request::param('order_sn');
$flag = Request::param('flag');
$flag = $flag == '1' ? 1 : 0;
if (empty($order_sn)) {
return $this->error('参数错误');
}
$data = Db::name('visa')->where(['order_sn' => $order_sn])->find();
$data['accom_people'] = $data['accom_people'] ? json_decode($data['accom_people'], true) : [];
$data['to_us_info'] = $data['to_us_info'] ? json_decode($data['to_us_info'], true) : [];
$data['job_info'] = $data['job_info'] ? json_decode($data['job_info'], true) : [];
$data['educational_info'] = $data['educational_info'] ? json_decode($data['educational_info'], true) : [];
$data['language'] = $data['language'] ? json_decode($data['language'], true) : [];
$data['other_countries'] = $data['other_countries'] ? json_decode($data['other_countries'], true) : [];
$data['province'] = $data['province'] ? $data['province'] : '北京市';
$data['city_birth'] = $data['city_birth'] ? $data['city_birth'] : '北京市';
$data['issue_province'] = $data['issue_province'] ? $data['issue_province'] : '北京市';
$data['issue_city'] = $data['issue_city'] ? $data['issue_city'] : '北京市';
$data['home_address_line_spr'] = $data['home_address_line_spr'] ? $data['home_address_line_spr'] : '北京市';
$data['home_address_line_city'] = $data['home_address_line_city'] ? $data['home_address_line_city'] : '北京市';
$data['mail_province'] = $data['mail_province'] ? $data['mail_province'] : '北京市';
$data['mail_city'] = $data['mail_city'] ? $data['mail_city'] : '北京市';
$data['paying_province'] = $data['paying_province'] ? $data['paying_province'] : '北京市';
$data['paying_city'] = $data['paying_city'] ? $data['paying_city'] : '北京市';
$data['paying_other_province'] = $data['paying_other_province'] ? $data['paying_other_province'] : '北京市';
$data['paying_other_city'] = $data['paying_other_city'] ? $data['paying_other_city'] : '北京市';
$data['driver_info'] = $data['driver_info'] ? json_decode($data['driver_info'], true) : [];
$data['professional'] = $data['professional'] ? json_decode($data['professional'], true) : [];
$data['military_country'] = $data['military_country'] ? json_decode($data['military_country'], true) : [];
$data['formers_info'] = $data['formers_info'] ? json_decode($data['formers_info'], true) : [];
$data['immediate_info'] = $data['immediate_info'] ? json_decode($data['immediate_info'], true) : [];
View::assign('data', $data);
View::assign('flag', $flag);
return View::fetch('upvisa');
}
public function submit()
{
$id = Request::param('order_sn');
if (empty($id)) {
return $this->error('参数不能为空!');
}
if (empty($_REQUEST['captcha'])) {
return $this->error('验证码不能为空!');
}
$verify = new \api\Verify();
if (!$verify->check($_REQUEST['captcha'], 1)) {
return $this->error('验证码错误!');
}
unset($_REQUEST['s'], $_REQUEST['file'], $_REQUEST['captcha']);
$res = Db::name('visa')->where(['order_sn' => $id])->find();
if (empty($res)) {
return $this->error('参数错误');
}
if (empty($res['is_effective'])) {
return $this->error('链接已失效');
}
//随行人员信息json
if (isset($_REQUEST['is_accom_people']) && $_REQUEST['is_accom_people'] == 1) {
$_REQUEST['accom_people'] = arrayToJson(['accom_people_last_name', 'accom_people_first_name', 'relationship'], [
$_REQUEST['accom_people_last_name'], $_REQUEST['accom_people_first_name'], $_REQUEST['relationship']
]);
unset($_REQUEST['accom_people_last_name'], $_REQUEST['accom_people_first_name'], $_REQUEST['relationship']);
} else {
unset($_REQUEST['accom_people_last_name'], $_REQUEST['accom_people_first_name'], $_REQUEST['relationship']);
}
if (isset($_REQUEST['is_to_us']) && $_REQUEST['is_to_us'] == 1) {
//去过美国信息
$_REQUEST['to_us_info'] = arrayToJson(['to_us_date', 'to_us_stay_date', 'to_us_stay_type'], [
$_REQUEST['to_us_date'], $_REQUEST['to_us_stay_date'], $_REQUEST['to_us_stay_type']
]);
unset($_REQUEST['to_us_date'], $_REQUEST['to_us_stay_date'], $_REQUEST['to_us_stay_type']);
} else {
unset($_REQUEST['to_us_date'], $_REQUEST['to_us_stay_date'], $_REQUEST['to_us_stay_type']);
}
//是否有驾照信息
if (isset($_REQUEST['is_us_driver']) && !empty($_REQUEST['is_us_driver'])) {
$_REQUEST['driver_info'] = arrayToJson(['driver_number', 'driver_state'], [
$_REQUEST['driver_number'], $_REQUEST['driver_state']
]);
unset($_REQUEST['driver_number'], $_REQUEST['driver_state']);
} else {
unset($_REQUEST['driver_number'], $_REQUEST['driver_state']);
}
if (isset($_REQUEST['is_job']) && $_REQUEST['is_job'] == 1) {
//你以前是否有过工作
$_REQUEST['job_info'] = arrayToJson([
'job_unit_name', 'job_country', 'job_province', 'job_city',
'job_first_address', 'job_second_address', 'job_mobile', 'job_zip_code',
'job_title', 'supervisor_last_name', 'supervisor_first_name', 'job_startime',
'job_endtime', 'job_response'
], [
$_REQUEST['job_unit_name'], $_REQUEST['job_country'], $_REQUEST['job_province'],
$_REQUEST['job_city'], $_REQUEST['job_first_address'], $_REQUEST['job_second_address'],
$_REQUEST['job_mobile'], $_REQUEST['job_zip_code'], $_REQUEST['job_title'],
$_REQUEST['supervisor_last_name'], $_REQUEST['supervisor_first_name'], $_REQUEST['job_startime'],
$_REQUEST['job_endtime'], $_REQUEST['job_response']
]);
unset($_REQUEST['job_unit_name'], $_REQUEST['job_country'], $_REQUEST['job_province']);
unset($_REQUEST['job_city'], $_REQUEST['job_first_address'], $_REQUEST['job_second_address']);
unset($_REQUEST['job_mobile'], $_REQUEST['job_zip_code'], $_REQUEST['job_title']);
unset($_REQUEST['supervisor_last_name'], $_REQUEST['supervisor_first_name'], $_REQUEST['job_startime']);
unset($_REQUEST['job_endtime'], $_REQUEST['job_response']);
} else {
unset($_REQUEST['job_unit_name'], $_REQUEST['job_country'], $_REQUEST['job_province']);
unset($_REQUEST['job_city'], $_REQUEST['job_first_address'], $_REQUEST['job_second_address']);
unset($_REQUEST['job_mobile'], $_REQUEST['job_zip_code'], $_REQUEST['job_title']);
unset($_REQUEST['supervisor_last_name'], $_REQUEST['supervisor_first_name'], $_REQUEST['job_startime']);
unset($_REQUEST['job_endtime'], $_REQUEST['job_response']);
}
if (isset($_REQUEST['is_educational']) && $_REQUEST['is_educational'] == 1) {
//你是否曾就读于任何中学或以上程度的教育机构
$_REQUEST['educational_info'] = arrayToJson([
'edu_name', 'edu_country', 'edu_province', 'edu_city',
'edu_first_address', 'edu_second_address', 'edu_zip_code', 'edu_course', 'edu_startime', 'edu_endtime'
], [
$_REQUEST['edu_name'], $_REQUEST['edu_country'], $_REQUEST['edu_province'], $_REQUEST['edu_city'],
$_REQUEST['edu_first_address'], $_REQUEST['edu_second_address'], $_REQUEST['edu_zip_code'], $_REQUEST['edu_course'],
$_REQUEST['edu_startime'], $_REQUEST['edu_endtime'],
]);
unset($_REQUEST['edu_name'], $_REQUEST['edu_country'], $_REQUEST['edu_province'], $_REQUEST['edu_city']);
unset($_REQUEST['edu_first_address'], $_REQUEST['edu_second_address'], $_REQUEST['edu_zip_code'], $_REQUEST['edu_course'],
$_REQUEST['edu_startime'], $_REQUEST['edu_endtime']);
} else {
unset($_REQUEST['edu_name'], $_REQUEST['edu_country'], $_REQUEST['edu_province'], $_REQUEST['edu_city']);
unset($_REQUEST['edu_first_address'], $_REQUEST['edu_second_address'], $_REQUEST['edu_zip_code'], $_REQUEST['edu_course'],
$_REQUEST['edu_startime'], $_REQUEST['edu_endtime']);
}
if (isset($_REQUEST['language']) && !empty($_REQUEST['language'])) {
//请提供你所使用的语言
$language = array_filter($_REQUEST['language']);
if (empty($language)) {
$_REQUEST['language'] = '';
} else {
$_REQUEST['language'] = json_encode($language);
}
} else {
unset($_REQUEST['language']);
}
if (isset($_REQUEST['professional']) && !empty($_REQUEST['professional'])) {
//请提供你所使用的语言
$language = array_filter($_REQUEST['professional']);
if (empty($language)) {
$_REQUEST['professional'] = '';
} else {
$_REQUEST['professional'] = json_encode($language);
}
} else {
unset($_REQUEST['professional']);
}
//服役的国家
if (isset($_REQUEST['military_country']) && !empty($_REQUEST['military_country'])) {
$_REQUEST['military_country'] = arrayToJson([
'military_country', 'services', 'military_rank', 'military_specialties', 'military_start_date', 'military_end_date'
], [
$_REQUEST['military_country'], $_REQUEST['services'], $_REQUEST['military_rank'], $_REQUEST['military_specialties'], $_REQUEST['military_start_date'], $_REQUEST['military_end_date']
]);
unset($_REQUEST['services'], $_REQUEST['military_rank'], $_REQUEST['military_specialties'], $_REQUEST['military_start_date'], $_REQUEST['military_end_date']);
} else {
unset($_REQUEST['services'], $_REQUEST['military_rank'], $_REQUEST['military_specialties'], $_REQUEST['military_start_date'], $_REQUEST['military_end_date']);
}
//美国是否有不包括父母在内的直系亲属
if (isset($_REQUEST['is_immediate']) && !empty($_REQUEST['is_immediate'])) {
$_REQUEST['immediate_info'] = arrayToJson([
'immediate_last_name', 'immediate_first_name', 'you_ship', 'identity'
], [
$_REQUEST['immediate_last_name'], $_REQUEST['immediate_first_name'], $_REQUEST['you_ship'], $_REQUEST['identity']
]);
unset($_REQUEST['immediate_last_name'], $_REQUEST['immediate_first_name'], $_REQUEST['you_ship'], $_REQUEST['identity']);
} else {
unset($_REQUEST['immediate_last_name'], $_REQUEST['immediate_first_name'], $_REQUEST['you_ship'], $_REQUEST['identity']);
}
if (isset($_REQUEST['is_other_countries']) && $_REQUEST['is_other_countries'] == 1) {
$other_countries = array_filter($_REQUEST['other_countries']);
if (empty($other_countries)) {
$_REQUEST['other_countries'] = '';
} else {
$_REQUEST['other_countries'] = json_encode($other_countries);
}
} else {
unset($_REQUEST['other_countries']);
}
if ($_REQUEST['marital'] == 'D' && !empty($_REQUEST['formers_last_name'])) {
//婚姻状况选择“离异”时 增加前任信息
$_REQUEST['formers_info'] = arrayToJson([
'formers_last_name', 'formers_first_name', 'formers_birth_date', 'formers_nationality',
'formers_birth_country', 'formers_birth_city', 'formers_marriage_date', 'formers_marriage_end_date',
'formers_marriage_end_explain', 'formers_marriage_end_country',
], [
$_REQUEST['formers_last_name'], $_REQUEST['formers_first_name'], $_REQUEST['formers_birth_date'], $_REQUEST['formers_nationality'],
$_REQUEST['formers_birth_country'], $_REQUEST['formers_birth_city'], $_REQUEST['formers_marriage_date'], $_REQUEST['formers_marriage_end_date'],
$_REQUEST['formers_marriage_end_explain'], $_REQUEST['formers_marriage_end_country']
]);
unset(
$_REQUEST['formers_last_name'], $_REQUEST['formers_first_name'], $_REQUEST['formers_birth_date'],
$_REQUEST['formers_nationality'], $_REQUEST['formers_birth_country'], $_REQUEST['formers_birth_city'],
$_REQUEST['formers_marriage_date'], $_REQUEST['formers_marriage_end_date'], $_REQUEST['formers_marriage_end_explain'],
$_REQUEST['formers_marriage_end_country']
);
} else {
unset(
$_REQUEST['formers_last_name'], $_REQUEST['formers_first_name'], $_REQUEST['formers_birth_date'],
$_REQUEST['formers_nationality'], $_REQUEST['formers_birth_country'], $_REQUEST['formers_birth_city'],
$_REQUEST['formers_marriage_date'], $_REQUEST['formers_marriage_end_date'], $_REQUEST['formers_marriage_end_explain'],
$_REQUEST['formers_marriage_end_country']
);
}
// var_dump($_REQUEST);exit;
for ($i = 1; $i < 28; $i++) {
unset($_REQUEST['safety' . $i]);
}
$_REQUEST['visa_cate'] = getCate($_REQUEST['visa_detail']);
$_REQUEST['is_effective'] = 0;
$_REQUEST['progress'] = 100;
$resd = Db::name('visa')->where(['order_sn' => $id])->update($_REQUEST);
if ($resd !== false) {
$url = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=cbe82d37-ede8-474b-81dc-1ca7dcf56d80';
$datas = array('msgtype' => 'text', 'text' => [
'content' => "订单号:{$res['order_sn']},姓名:{$_REQUEST['last_name_zn']}{$_REQUEST['first_name_zn']}美签表单已提交,请及时审核",
]);
Httpcurl::request($url, 'post', json_encode($datas), [
'Content-Type: application/json'
]);
return $this->success("提交成功", url('visa/upvisa')->build());
} else {
return $this->error('提交失败!');
}
}
public function saves()
{
$verify = new \api\Verify();
$id = Request::param('order_sn');
if (empty($id)) {
return $this->error('参数不能为空!');
}
if (empty($_REQUEST['captcha'])) {
return $this->error('验证码不能为空!');
}
if (!$verify->check($_REQUEST['captcha'], 1)) {
return $this->error('验证码错误!');
}
unset($_REQUEST['s'], $_REQUEST['file'], $_REQUEST['captcha']);
$res = Db::name('visa')->where(['order_sn' => $id])->find();
if (empty($res)) {
return $this->error('参数错误');
}
$ip = getIp();
Log::write('ip:' . $ip . '=====id:' . $id);
$disableips = Config::get('disable_ip');
if (in_array($ip, $disableips)) {
return $this->error('非法请求');
}
if (empty($res['is_effective'])) {
return $this->error('链接已失效');
}
//随行人员信息json
if (isset($_REQUEST['is_accom_people']) && $_REQUEST['is_accom_people'] == 1) {
$_REQUEST['accom_people'] = arrayToJson(['accom_people_last_name', 'accom_people_first_name', 'relationship'], [
$_REQUEST['accom_people_last_name'], $_REQUEST['accom_people_first_name'], $_REQUEST['relationship']
]);
unset($_REQUEST['accom_people_last_name'], $_REQUEST['accom_people_first_name'], $_REQUEST['relationship']);
} else {
unset($_REQUEST['accom_people_last_name'], $_REQUEST['accom_people_first_name'], $_REQUEST['relationship']);
}
if (isset($_REQUEST['is_to_us']) && $_REQUEST['is_to_us'] == 1) {
//去过美国信息
$_REQUEST['to_us_info'] = arrayToJson(['to_us_date', 'to_us_stay_date', 'to_us_stay_type'], [
$_REQUEST['to_us_date'], $_REQUEST['to_us_stay_date'], $_REQUEST['to_us_stay_type']
]);
unset($_REQUEST['to_us_date'], $_REQUEST['to_us_stay_date'], $_REQUEST['to_us_stay_type']);
} else {
unset($_REQUEST['to_us_date'], $_REQUEST['to_us_stay_date'], $_REQUEST['to_us_stay_type']);
}
//是否有驾照信息
if (isset($_REQUEST['is_us_driver']) && !empty($_REQUEST['is_us_driver'])) {
$_REQUEST['driver_info'] = arrayToJson(['driver_number', 'driver_state'], [
$_REQUEST['driver_number'], $_REQUEST['driver_state']
]);
unset($_REQUEST['driver_number'], $_REQUEST['driver_state']);
} else {
unset($_REQUEST['driver_number'], $_REQUEST['driver_state']);
}
if (isset($_REQUEST['is_job']) && $_REQUEST['is_job'] == 1) {
//你以前是否有过工作
$_REQUEST['job_info'] = arrayToJson([
'job_unit_name', 'job_country', 'job_province', 'job_city',
'job_first_address', 'job_second_address', 'job_mobile', 'job_zip_code',
'job_title', 'supervisor_last_name', 'supervisor_first_name', 'job_startime',
'job_endtime', 'job_response'
], [
$_REQUEST['job_unit_name'], $_REQUEST['job_country'], $_REQUEST['job_province'],
$_REQUEST['job_city'], $_REQUEST['job_first_address'], $_REQUEST['job_second_address'],
$_REQUEST['job_mobile'], $_REQUEST['job_zip_code'], $_REQUEST['job_title'],
$_REQUEST['supervisor_last_name'], $_REQUEST['supervisor_first_name'], $_REQUEST['job_startime'],
$_REQUEST['job_endtime'], $_REQUEST['job_response']
]);
unset($_REQUEST['job_unit_name'], $_REQUEST['job_country'], $_REQUEST['job_province']);
unset($_REQUEST['job_city'], $_REQUEST['job_first_address'], $_REQUEST['job_second_address']);
unset($_REQUEST['job_mobile'], $_REQUEST['job_zip_code'], $_REQUEST['job_title']);
unset($_REQUEST['supervisor_last_name'], $_REQUEST['supervisor_first_name'], $_REQUEST['job_startime']);
unset($_REQUEST['job_endtime'], $_REQUEST['job_response']);
} else {
unset($_REQUEST['job_unit_name'], $_REQUEST['job_country'], $_REQUEST['job_province']);
unset($_REQUEST['job_city'], $_REQUEST['job_first_address'], $_REQUEST['job_second_address']);
unset($_REQUEST['job_mobile'], $_REQUEST['job_zip_code'], $_REQUEST['job_title']);
unset($_REQUEST['supervisor_last_name'], $_REQUEST['supervisor_first_name'], $_REQUEST['job_startime']);
unset($_REQUEST['job_endtime'], $_REQUEST['job_response']);
}
if (isset($_REQUEST['is_educational']) && $_REQUEST['is_educational'] == 1) {
//你是否曾就读于任何中学或以上程度的教育机构
$_REQUEST['educational_info'] = arrayToJson([
'edu_name', 'edu_country', 'edu_province', 'edu_city',
'edu_first_address', 'edu_second_address', 'edu_zip_code', 'edu_course', 'edu_startime', 'edu_endtime'
], [
$_REQUEST['edu_name'], $_REQUEST['edu_country'], $_REQUEST['edu_province'], $_REQUEST['edu_city'],
$_REQUEST['edu_first_address'], $_REQUEST['edu_second_address'], $_REQUEST['edu_zip_code'], $_REQUEST['edu_course'],
$_REQUEST['edu_startime'], $_REQUEST['edu_endtime'],
]);
unset($_REQUEST['edu_name'], $_REQUEST['edu_country'], $_REQUEST['edu_province'], $_REQUEST['edu_city']);
unset($_REQUEST['edu_first_address'], $_REQUEST['edu_second_address'], $_REQUEST['edu_zip_code'], $_REQUEST['edu_course'],
$_REQUEST['edu_startime'], $_REQUEST['edu_endtime']);
} else {
unset($_REQUEST['edu_name'], $_REQUEST['edu_country'], $_REQUEST['edu_province'], $_REQUEST['edu_city']);
unset($_REQUEST['edu_first_address'], $_REQUEST['edu_second_address'], $_REQUEST['edu_zip_code'], $_REQUEST['edu_course'],
$_REQUEST['edu_startime'], $_REQUEST['edu_endtime']);
}
if (isset($_REQUEST['language']) && !empty($_REQUEST['language'])) {
//请提供你所使用的语言
$language = array_filter($_REQUEST['language']);
if (empty($language)) {
$_REQUEST['language'] = '';
} else {
$_REQUEST['language'] = json_encode($language);
}
} else {
unset($_REQUEST['language']);
}
if (isset($_REQUEST['professional']) && !empty($_REQUEST['professional'])) {
//请提供你所使用的语言
$language = array_filter($_REQUEST['professional']);
if (empty($language)) {
$_REQUEST['professional'] = '';
} else {
$_REQUEST['professional'] = json_encode($language);
}
} else {
unset($_REQUEST['professional']);
}
//服役的国家
if (isset($_REQUEST['military_country']) && !empty($_REQUEST['military_country'])) {
$_REQUEST['military_country'] = arrayToJson([
'military_country', 'services', 'military_rank', 'military_specialties', 'military_start_date', 'military_end_date'
], [
$_REQUEST['military_country'], $_REQUEST['services'], $_REQUEST['military_rank'], $_REQUEST['military_specialties'], $_REQUEST['military_start_date'], $_REQUEST['military_end_date']
]);
unset($_REQUEST['services'], $_REQUEST['military_rank'], $_REQUEST['military_specialties'], $_REQUEST['military_start_date'], $_REQUEST['military_end_date']);
} else {
unset($_REQUEST['services'], $_REQUEST['military_rank'], $_REQUEST['military_specialties'], $_REQUEST['military_start_date'], $_REQUEST['military_end_date']);
}
//美国是否有不包括父母在内的直系亲属
if (isset($_REQUEST['is_immediate']) && !empty($_REQUEST['is_immediate'])) {
$_REQUEST['immediate_info'] = arrayToJson([
'immediate_last_name', 'immediate_first_name', 'you_ship', 'identity'
], [
$_REQUEST['immediate_last_name'], $_REQUEST['immediate_first_name'], $_REQUEST['you_ship'], $_REQUEST['identity']
]);
unset($_REQUEST['immediate_last_name'], $_REQUEST['immediate_first_name'], $_REQUEST['you_ship'], $_REQUEST['identity']);
} else {
unset($_REQUEST['immediate_last_name'], $_REQUEST['immediate_first_name'], $_REQUEST['you_ship'], $_REQUEST['identity']);
}
if (isset($_REQUEST['is_other_countries']) && $_REQUEST['is_other_countries'] == 1) {
$other_countries = array_filter($_REQUEST['other_countries']);
if (empty($other_countries)) {
$_REQUEST['other_countries'] = '';
} else {
$_REQUEST['other_countries'] = json_encode($other_countries);
}
} else {
unset($_REQUEST['other_countries']);
}
if ($_REQUEST['marital'] == 'D' && !empty($_REQUEST['formers_last_name'])) {
//婚姻状况选择“离异”时 增加前任信息
$_REQUEST['formers_info'] = arrayToJson([
'formers_last_name', 'formers_first_name', 'formers_birth_date', 'formers_nationality',
'formers_birth_country', 'formers_birth_city', 'formers_marriage_date', 'formers_marriage_end_date',
'formers_marriage_end_explain', 'formers_marriage_end_country',
], [
$_REQUEST['formers_last_name'], $_REQUEST['formers_first_name'], $_REQUEST['formers_birth_date'], $_REQUEST['formers_nationality'],
$_REQUEST['formers_birth_country'], $_REQUEST['formers_birth_city'], $_REQUEST['formers_marriage_date'], $_REQUEST['formers_marriage_end_date'],
$_REQUEST['formers_marriage_end_explain'], $_REQUEST['formers_marriage_end_country']
]);
unset(
$_REQUEST['formers_last_name'], $_REQUEST['formers_first_name'], $_REQUEST['formers_birth_date'],
$_REQUEST['formers_nationality'], $_REQUEST['formers_birth_country'], $_REQUEST['formers_birth_city'],
$_REQUEST['formers_marriage_date'], $_REQUEST['formers_marriage_end_date'], $_REQUEST['formers_marriage_end_explain'],
$_REQUEST['formers_marriage_end_country']
);
} else {
unset(
$_REQUEST['formers_last_name'], $_REQUEST['formers_first_name'], $_REQUEST['formers_birth_date'],
$_REQUEST['formers_nationality'], $_REQUEST['formers_birth_country'], $_REQUEST['formers_birth_city'],
$_REQUEST['formers_marriage_date'], $_REQUEST['formers_marriage_end_date'], $_REQUEST['formers_marriage_end_explain'],
$_REQUEST['formers_marriage_end_country']
);
}
// var_dump($_REQUEST);exit;
for ($i = 1; $i < 28; $i++) {
unset($_REQUEST['safety' . $i]);
}
$_REQUEST['visa_cate'] = getCate($_REQUEST['visa_detail']);
$res = Db::name('visa')->where(['order_sn' => $id])->update($_REQUEST);
if ($res !== false) {
return $this->success("提交成功", url('visa/upvisa')->build());
} else {
return $this->error('提交失败!');
}
}
public function zancun()
{
$id = Request::param('order_sn');
if (empty($id)) {
return $this->error('参数不能为空!');
}
unset($_REQUEST['s'], $_REQUEST['file'], $_REQUEST['captcha']);
$res = Db::name('visa')->where(['order_sn' => $id])->find();
if (empty($res)) {
return $this->error('参数错误');
}
$ip = getIp();
Log::write('ip:' . $ip . '=====id:' . $id);
$disableips = Config::get('disable_ip');
if (in_array($ip, $disableips)) {
return $this->error('非法请求');
}
if (empty($res['is_effective'])) {
return $this->error('链接已失效');
}
//随行人员信息json
if (isset($_REQUEST['is_accom_people']) && $_REQUEST['is_accom_people'] == 1) {
$_REQUEST['accom_people'] = arrayToJson(['accom_people_last_name', 'accom_people_first_name', 'relationship'], [
$_REQUEST['accom_people_last_name'], $_REQUEST['accom_people_first_name'], $_REQUEST['relationship']
]);
unset($_REQUEST['accom_people_last_name'], $_REQUEST['accom_people_first_name'], $_REQUEST['relationship']);
} else {
unset($_REQUEST['accom_people_last_name'], $_REQUEST['accom_people_first_name'], $_REQUEST['relationship']);
}
if (isset($_REQUEST['is_to_us']) && $_REQUEST['is_to_us'] == 1) {
//去过美国信息
$_REQUEST['to_us_info'] = arrayToJson(['to_us_date', 'to_us_stay_date', 'to_us_stay_type'], [
$_REQUEST['to_us_date'], $_REQUEST['to_us_stay_date'], $_REQUEST['to_us_stay_type']
]);
unset($_REQUEST['to_us_date'], $_REQUEST['to_us_stay_date'], $_REQUEST['to_us_stay_type']);
} else {
unset($_REQUEST['to_us_date'], $_REQUEST['to_us_stay_date'], $_REQUEST['to_us_stay_type']);
}
//是否有驾照信息
if (isset($_REQUEST['is_us_driver']) && !empty($_REQUEST['is_us_driver'])) {
$_REQUEST['driver_info'] = arrayToJson(['driver_number', 'driver_state'], [
$_REQUEST['driver_number'], $_REQUEST['driver_state']
]);
unset($_REQUEST['driver_number'], $_REQUEST['driver_state']);
} else {
unset($_REQUEST['driver_number'], $_REQUEST['driver_state']);
}
if (isset($_REQUEST['is_job']) && $_REQUEST['is_job'] == 1) {
//你以前是否有过工作
$_REQUEST['job_info'] = arrayToJson([
'job_unit_name', 'job_country', 'job_province', 'job_city',
'job_first_address', 'job_second_address', 'job_mobile', 'job_zip_code',
'job_title', 'supervisor_last_name', 'supervisor_first_name', 'job_startime',
'job_endtime', 'job_response'
], [
$_REQUEST['job_unit_name'], $_REQUEST['job_country'], $_REQUEST['job_province'],
$_REQUEST['job_city'], $_REQUEST['job_first_address'], $_REQUEST['job_second_address'],
$_REQUEST['job_mobile'], $_REQUEST['job_zip_code'], $_REQUEST['job_title'],
$_REQUEST['supervisor_last_name'], $_REQUEST['supervisor_first_name'], $_REQUEST['job_startime'],
$_REQUEST['job_endtime'], $_REQUEST['job_response']
]);
unset($_REQUEST['job_unit_name'], $_REQUEST['job_country'], $_REQUEST['job_province']);
unset($_REQUEST['job_city'], $_REQUEST['job_first_address'], $_REQUEST['job_second_address']);
unset($_REQUEST['job_mobile'], $_REQUEST['job_zip_code'], $_REQUEST['job_title']);
unset($_REQUEST['supervisor_last_name'], $_REQUEST['supervisor_first_name'], $_REQUEST['job_startime']);
unset($_REQUEST['job_endtime'], $_REQUEST['job_response']);
} else {
unset($_REQUEST['job_unit_name'], $_REQUEST['job_country'], $_REQUEST['job_province']);
unset($_REQUEST['job_city'], $_REQUEST['job_first_address'], $_REQUEST['job_second_address']);
unset($_REQUEST['job_mobile'], $_REQUEST['job_zip_code'], $_REQUEST['job_title']);
unset($_REQUEST['supervisor_last_name'], $_REQUEST['supervisor_first_name'], $_REQUEST['job_startime']);
unset($_REQUEST['job_endtime'], $_REQUEST['job_response']);
}
if (isset($_REQUEST['is_educational']) && $_REQUEST['is_educational'] == 1) {
//你是否曾就读于任何中学或以上程度的教育机构
$_REQUEST['educational_info'] = arrayToJson([
'edu_name', 'edu_country', 'edu_province', 'edu_city',
'edu_first_address', 'edu_second_address', 'edu_zip_code', 'edu_course', 'edu_startime', 'edu_endtime'
], [
$_REQUEST['edu_name'], $_REQUEST['edu_country'], $_REQUEST['edu_province'], $_REQUEST['edu_city'],
$_REQUEST['edu_first_address'], $_REQUEST['edu_second_address'], $_REQUEST['edu_zip_code'], $_REQUEST['edu_course'],
$_REQUEST['edu_startime'], $_REQUEST['edu_endtime'],
]);
unset($_REQUEST['edu_name'], $_REQUEST['edu_country'], $_REQUEST['edu_province'], $_REQUEST['edu_city']);
unset($_REQUEST['edu_first_address'], $_REQUEST['edu_second_address'], $_REQUEST['edu_zip_code'], $_REQUEST['edu_course'],
$_REQUEST['edu_startime'], $_REQUEST['edu_endtime']);
} else {
unset($_REQUEST['edu_name'], $_REQUEST['edu_country'], $_REQUEST['edu_province'], $_REQUEST['edu_city']);
unset($_REQUEST['edu_first_address'], $_REQUEST['edu_second_address'], $_REQUEST['edu_zip_code'], $_REQUEST['edu_course'],
$_REQUEST['edu_startime'], $_REQUEST['edu_endtime']);
}
if (isset($_REQUEST['language']) && !empty($_REQUEST['language'])) {
//请提供你所使用的语言
$language = array_filter($_REQUEST['language']);
if (empty($language)) {
$_REQUEST['language'] = '';
} else {
$_REQUEST['language'] = json_encode($language);
}
} else {
unset($_REQUEST['language']);
}
if (isset($_REQUEST['professional']) && !empty($_REQUEST['professional'])) {
//请提供你所使用的语言
$language = array_filter($_REQUEST['professional']);
if (empty($language)) {
$_REQUEST['professional'] = '';
} else {
$_REQUEST['professional'] = json_encode($language);
}
} else {
unset($_REQUEST['professional']);
}
//服役的国家
if (isset($_REQUEST['military_country']) && !empty($_REQUEST['military_country'])) {
$_REQUEST['military_country'] = arrayToJson([
'military_country', 'services', 'military_rank', 'military_specialties', 'military_start_date', 'military_end_date'
], [
$_REQUEST['military_country'], $_REQUEST['services'], $_REQUEST['military_rank'], $_REQUEST['military_specialties'], $_REQUEST['military_start_date'], $_REQUEST['military_end_date']
]);
unset($_REQUEST['services'], $_REQUEST['military_rank'], $_REQUEST['military_specialties'], $_REQUEST['military_start_date'], $_REQUEST['military_end_date']);
} else {
unset($_REQUEST['services'], $_REQUEST['military_rank'], $_REQUEST['military_specialties'], $_REQUEST['military_start_date'], $_REQUEST['military_end_date']);
}
//美国是否有不包括父母在内的直系亲属
if (isset($_REQUEST['is_immediate']) && !empty($_REQUEST['is_immediate'])) {
$_REQUEST['immediate_info'] = arrayToJson([
'immediate_last_name', 'immediate_first_name', 'you_ship', 'identity'
], [
$_REQUEST['immediate_last_name'], $_REQUEST['immediate_first_name'], $_REQUEST['you_ship'], $_REQUEST['identity']
]);
unset($_REQUEST['immediate_last_name'], $_REQUEST['immediate_first_name'], $_REQUEST['you_ship'], $_REQUEST['identity']);
} else {
unset($_REQUEST['immediate_last_name'], $_REQUEST['immediate_first_name'], $_REQUEST['you_ship'], $_REQUEST['identity']);
}
if (isset($_REQUEST['is_other_countries']) && $_REQUEST['is_other_countries'] == 1) {
$other_countries = array_filter($_REQUEST['other_countries']);
if (empty($other_countries)) {
$_REQUEST['other_countries'] = '';
} else {
$_REQUEST['other_countries'] = json_encode($other_countries);
}
} else {
unset($_REQUEST['other_countries']);
}
if ($_REQUEST['marital'] == 'D' && !empty($_REQUEST['formers_last_name'])) {
//婚姻状况选择“离异”时 增加前任信息
$_REQUEST['formers_info'] = arrayToJson([
'formers_last_name', 'formers_first_name', 'formers_birth_date', 'formers_nationality',
'formers_birth_country', 'formers_birth_city', 'formers_marriage_date', 'formers_marriage_end_date',
'formers_marriage_end_explain', 'formers_marriage_end_country',
], [
$_REQUEST['formers_last_name'], $_REQUEST['formers_first_name'], $_REQUEST['formers_birth_date'], $_REQUEST['formers_nationality'],
$_REQUEST['formers_birth_country'], $_REQUEST['formers_birth_city'], $_REQUEST['formers_marriage_date'], $_REQUEST['formers_marriage_end_date'],
$_REQUEST['formers_marriage_end_explain'], $_REQUEST['formers_marriage_end_country']
]);
unset(
$_REQUEST['formers_last_name'], $_REQUEST['formers_first_name'], $_REQUEST['formers_birth_date'],
$_REQUEST['formers_nationality'], $_REQUEST['formers_birth_country'], $_REQUEST['formers_birth_city'],
$_REQUEST['formers_marriage_date'], $_REQUEST['formers_marriage_end_date'], $_REQUEST['formers_marriage_end_explain'],
$_REQUEST['formers_marriage_end_country']
);
} else {
unset(
$_REQUEST['formers_last_name'], $_REQUEST['formers_first_name'], $_REQUEST['formers_birth_date'],
$_REQUEST['formers_nationality'], $_REQUEST['formers_birth_country'], $_REQUEST['formers_birth_city'],
$_REQUEST['formers_marriage_date'], $_REQUEST['formers_marriage_end_date'], $_REQUEST['formers_marriage_end_explain'],
$_REQUEST['formers_marriage_end_country']
);
}
// var_dump($_REQUEST);exit;
for ($i = 1; $i < 28; $i++) {
unset($_REQUEST['safety' . $i]);
}
$_REQUEST['visa_cate'] = getCate($_REQUEST['visa_detail']);
$res = Db::name('visa')->where(['order_sn' => $id])->update($_REQUEST);
if ($res !== false) {
return $this->success("提交成功", url('visa/upvisa')->build());
} else {
return $this->error('提交失败!');
}
}
/**
* 跳转到pc
*/
public function feepay()
{
$cfg = Config::get('wxpayvisa');
$app = Factory::payment($cfg);
$order_sn = Request::param('order_sn');
//判断支付是否已完成
$pay_result = Db::name('visa')->where(['order_sn' => $order_sn])->find();
if (empty($pay_result)) {
return ajaxReturn([
'code' => 0,
'msg' => '订单号错误',
]);
}
$order_sn = 'visa' . $order_sn;
$result = $app->order->unify([
'body' => '美国签证登记服务费',
'out_trade_no' => $order_sn,
'total_fee' => $pay_result['other_fee'],
'trade_type' => 'NATIVE',
'product_id' => $order_sn, // $message['product_id'] 则为生成二维码时的产品 ID
// ...
]);
if (!isset($result['result_code']) || ($result['result_code'] == 'FAIL')) {
return $this->error('初始化支付异常,请稍后重试');
}
$url = "/uploads/qrcode/{$order_sn}.png";
QRcode::png($result['code_url'], "." . $url, 'L', 4, 2);
//判断文件是否存在
if (!is_file("." . $url)) {
return ajaxReturn([
'code' => 0,
'msg' => '请重新支付',
]);
}
return ajaxReturn([
'code' => 1,
'msg' => '提交成功',
'data' => $url
]);
return $this->success('');
}
/**
* @return void
* 请求姓名电码
*/
public function telecode()
{
$last_name_zn = Request::param('last_name_zn');
$first_name_zn = Request::param('first_name_zn');
if (empty($last_name_zn) || empty($first_name_zn)) {
return $this->error("姓名为空");
}
try {
$res = queryNameTelecode($last_name_zn . $first_name_zn, mb_strlen($last_name_zn, 'UTF-8'));
} catch (\InvalidArgumentException $e) {
return $this->error($e->getMessage());
} catch (\RuntimeException $e) {
return $this->error($e->getMessage());
} catch (\Throwable $e) {
return $this->error("电码查询暂时不可用,请稍后重试或手动填写");
}
// 保持前端字段和每个汉字四位电码之间的空格,保留前导零。
return $this->success("请求成功", '', [
'code_last_name' => implode(' ', str_split($res['surname_code'], 4)),
'code_first_name' => implode(' ', str_split($res['given_name_code'], 4)),
]);
}
/**
* @return void
* 请求姓名电码
*/
public function addprocess()
{
$process = Request::param('process');
$order_sn = Request::param('order_sn');
if (empty($process) || empty($order_sn)) {
return $this->error("参数错误");
}
$order = Db::name('visa')->where(['order_sn' => $order_sn])->find();
if (empty($order)) {
return $this->error("订单不存在");
}
if ($order['progress'] > $process) {
return $this->error("进度已存在");
}
Db::name('visa')->where(['order_sn' => $order_sn])->update([
'progress' => $process,
]);
return $this->success("请求成功");
}
public function upsucc()
{
// $order_sn = Session::get('visa_order_sn');
// View::assign('order_sn',$order_sn);
return View::fetch('upsucc');
}
public function verify()
{
$verify = new \api\Verify();
$verify->entry(1);
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace app\home\controller;
use api\Httpcurl;
use think\facade\Config;
use think\facade\Request;
class Wechatpay extends Base
{
/**
* 微信jsapi支付结果页面
*/
public function index()
{
$order_sn = Request::instance()->param('order_sn');
if (!$order_sn) {
return $this->error('缺少订单号');
}
//获取订单信息
$order_url = Config::get('app.get_evus_detail_url');
$response = Httpcurl::request($order_url, 'post', ['order_sn'=>$order_sn,'model'=>MODEL]);
if ($response[3]) {
return $this->error('支付失败,请稍后重试', '/home/detail/index');
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return $this->error('支付失败,请稍后重试', '/home/detail/index');
}
if (!$pay_result['code']){
return $this->error('支付失败,请稍后重试', '/home/detail/index');
}
$pay_result = $pay_result['data'];
if ($pay_result['pay_status']) {
return redirect(url('home/pay/succ', ['order_sn' => $order_sn])->build());
}else{
return $this->error('支付失败,请稍后重试', '/home/detail/index');
}
}
public function esta()
{
$order_sn = Request::instance()->param('order_sn');
if (!$order_sn) {
return $this->error('缺少订单号');
}
//获取订单信息
$order_url = Config::get('app.get_order_detail_url');
$response = Httpcurl::request($order_url, 'post', ['order_sn'=>$order_sn,'model'=>ESTA_MODEL]);
if ($response[3]) {
return $this->error('支付失败,请稍后重试', '/home/esta/index');
}
$pay_result = json_decode($response[0], true);
if (empty($pay_result)) {
return $this->error('支付失败,请稍后重试', '/home/esta/index');
}
if (!$pay_result['code']){
return $this->error('支付失败,请稍后重试', '/home/esta/index');
}
$pay_result = $pay_result['data'];
if ($pay_result['pay_status']) {
return redirect(url('home/payesta/succ', ['order_sn' => $order_sn])->build());
}else{
return $this->error('支付失败,请稍后重试', '/home/esta/index');
}
}
}

View File

@@ -0,0 +1,35 @@
<?php
declare (strict_types = 1);
namespace app\home\controller;
use api\Httpcurl;
use think\facade\Log;
use think\facade\View;
class Wxmini extends Base
{
public function index()
{
// $news_list = Httpcurl::request(NEWS_LIST, 'post', [
// 'model' => 'article',
// 'page' => 1,
// 'size' => 10,
// ]);
// $news_list = json_decode($news_list[0], true);
// Log::info(json_encode($news_list));
//
// if (!empty($news_list) && $news_list['code'] == 1) {
// View::assign('data', $news_list['data']);
// } else {
// View::assign('data', []);
// }
return View::fetch();
}
public function screen()
{
return View::fetch();
}
}

5
app/home/event.php Normal file
View File

@@ -0,0 +1,5 @@
<?php
// 这是系统自动生成的event定义文件
return [
];

5
app/home/middleware.php Normal file
View File

@@ -0,0 +1,5 @@
<?php
// 这是系统自动生成的middleware定义文件
return [
];

View File

@@ -0,0 +1,241 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<link rel="stylesheet" href="/static/home/css/info-page.css?v=1">
<body class="main cn home info-page home-layout-page">
<div class="content info-page__menu">
{include file="public/home_menu" /}
</div>
<main class="info-shell">
<section class="info-card company-card">
<h1>关于我们</h1>
<div class="company-section">
<h2>公司简介</h2>
<div class="company-intro">
<p>济南经纬九州出入境服务有限公司,于2014年4月4日经山东省工商局批准成立。2016年5月,我公司职员受邀参加山东省外事机关组织的“EVUS”登记说明会,由当时的现任美国签证官亲自解说指导,我司员工是唯一的非政府机构参会人员。自该业务开展以来,我司的EVUS登记业务,所有的有效签证已全部登记成功;有一部分客户因签证本身无效无法登记成功,我司职员凭借专业的经验引导这部分客户重新获取签证,并登记成功。</p>
<p>多年来,经纬九州出入境始终追求“专业化,规范化”的经营理念,践行“一带一路”伟大倡议,为我国公民提供因私出入境服务,经纬九州员工锐意进取,不断开拓精品项目。独立开发的eVUS大数据模型系统,能够快速的协助客户完成美签电子更新。</p>
<p>历经市场考验,经纬九州人坚守“不忘初心,不辱使命”之愿景,立志成为业务门类齐全、有相当社会知名度的中介服务机构。evus.cn网热忱欢迎中外企业和各类优秀人才加盟合作,共创未来。</p>
</div>
<div class="company-meta">
<p><strong>公司:</strong>济南经纬九州出入境服务有限公司</p>
<p><strong>地址:</strong>山东省 济南市 历下区</p>
<p><strong>邮编:</strong>250013</p>
<p><strong>手机:</strong>4000-878-958</p>
<p><strong>网站:</strong>www.evus.cn</p>
</div>
</div>
<div class="company-section">
<h2>签证服务价目表</h2>
<div class="price-table-wrap">
<table class="price-table">
<colgroup>
<col class="price-table__country">
<col class="price-table__type">
<col class="price-table__time">
<col class="price-table__fee">
<col class="price-table__service">
<col class="price-table__total">
</colgroup>
<thead>
<tr>
<th>国家</th>
<th>签证类型</th>
<th>出签时间(工作日)</th>
<th>签证费</th>
<th>服务费/人(不含签证费及保险)</th>
<th>合计</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="国家">美国</td>
<td data-label="签证类型">B1/B2</td>
<td data-label="出签时间">30</td>
<td data-label="签证费">1369元</td>
<td data-label="服务费">731元</td>
<td data-label="合计">2100元</td>
</tr>
<tr>
<td data-label="国家">美国</td>
<td data-label="签证类型">续签(同类型)</td>
<td data-label="出签时间">30</td>
<td data-label="签证费">1369元</td>
<td data-label="服务费">731元</td>
<td data-label="合计">2100元</td>
</tr>
<tr>
<td data-label="国家">美国</td>
<td data-label="签证类型">留学签</td>
<td data-label="出签时间">30</td>
<td data-label="签证费">1369元</td>
<td data-label="服务费">2131元</td>
<td data-label="合计">3500元</td>
</tr>
<tr>
<td data-label="国家">美国</td>
<td data-label="签证类型">evus</td>
<td data-label="出签时间">6小时内</td>
<td data-label="签证费">-</td>
<td data-label="服务费">350元</td>
<td data-label="合计">350元</td>
</tr>
<tr>
<td data-label="国家">美国</td>
<td data-label="签证类型">evus</td>
<td data-label="出签时间">3小时内</td>
<td data-label="签证费">-</td>
<td data-label="服务费">499元</td>
<td data-label="合计">499元</td>
</tr>
<tr>
<td data-label="国家">美国</td>
<td data-label="签证类型">evus</td>
<td data-label="出签时间">15分钟内</td>
<td data-label="签证费">-</td>
<td data-label="服务费">799元</td>
<td data-label="合计">799元</td>
</tr>
<tr>
<td data-label="国家">加拿大</td>
<td data-label="签证类型">旅游、商务、探亲</td>
<td data-label="出签时间">30</td>
<td data-label="签证费">1000元</td>
<td data-label="服务费">800元</td>
<td data-label="合计">1800元</td>
</tr>
<tr>
<td data-label="国家">澳大利亚</td>
<td data-label="签证类型">旅游、商务、探亲</td>
<td data-label="出签时间">20</td>
<td data-label="签证费">1000元</td>
<td data-label="服务费">600元</td>
<td data-label="合计">1600元</td>
</tr>
<tr>
<td data-label="国家">新西兰</td>
<td data-label="签证类型">旅游、商务、探亲</td>
<td data-label="出签时间">25</td>
<td data-label="签证费">2000元</td>
<td data-label="服务费">700元</td>
<td data-label="合计">2700元</td>
</tr>
<tr>
<td data-label="国家">申根</td>
<td data-label="签证类型">旅游、商务、探亲</td>
<td data-label="出签时间">30</td>
<td data-label="签证费">750元左右签证费(不代收签证费)含14天行程保险</td>
<td data-label="服务费">800元</td>
<td data-label="合计">800元</td>
</tr>
<tr>
<td data-label="国家">英国</td>
<td data-label="签证类型">旅游、商务、探亲</td>
<td data-label="出签时间">30</td>
<td data-label="签证费">1300元(济南、西安、长沙、昆明额外收取800元场地费)</td>
<td data-label="服务费">700元</td>
<td data-label="合计">2000元(不含场地费)</td>
</tr>
<tr>
<td data-label="国家">日本(山东、北京)</td>
<td data-label="签证类型">单次旅游</td>
<td data-label="出签时间">8</td>
<td data-label="签证费">300元</td>
<td data-label="服务费">300元</td>
<td data-label="合计">600元</td>
</tr>
<tr>
<td data-label="国家">日本(山东、北京)</td>
<td data-label="签证类型">3年/5年多次旅游</td>
<td data-label="出签时间">8</td>
<td data-label="签证费">400元</td>
<td data-label="服务费">300元</td>
<td data-label="合计">700元</td>
</tr>
<tr>
<td data-label="国家">韩国</td>
<td data-label="签证类型">单次旅游</td>
<td data-label="出签时间">15</td>
<td data-label="签证费">领馆+签证中心400元</td>
<td data-label="服务费">300元</td>
<td data-label="合计">700元</td>
</tr>
<tr>
<td data-label="国家">韩国</td>
<td data-label="签证类型">5年旅游</td>
<td data-label="出签时间">15</td>
<td data-label="签证费">领馆+签证中心800元</td>
<td data-label="服务费">300元</td>
<td data-label="合计">1100元</td>
</tr>
<tr>
<td data-label="国家">巴西</td>
<td data-label="签证类型">旅游、商务、探亲</td>
<td data-label="出签时间">以网站通知为准</td>
<td data-label="签证费">1100元(不代收签证费)</td>
<td data-label="服务费">700元</td>
<td data-label="合计">700元</td>
</tr>
<tr>
<td data-label="国家">越南</td>
<td data-label="签证类型">单次电子签</td>
<td data-label="出签时间">5</td>
<td data-label="签证费">25美元</td>
<td data-label="服务费">200</td>
<td data-label="合计">398元</td>
</tr>
<tr>
<td data-label="国家">越南</td>
<td data-label="签证类型">多次电子签</td>
<td data-label="出签时间">5</td>
<td data-label="签证费">50美元</td>
<td data-label="服务费">400</td>
<td data-label="合计">598元</td>
</tr>
<tr>
<td data-label="国家">俄罗斯</td>
<td data-label="签证类型">单次电子签</td>
<td data-label="出签时间">8</td>
<td data-label="签证费"></td>
<td data-label="服务费"></td>
<td data-label="合计">558元</td>
</tr>
<tr>
<td data-label="国家">俄罗斯</td>
<td data-label="签证类型">单次电子签</td>
<td data-label="出签时间">4</td>
<td data-label="签证费"></td>
<td data-label="服务费"></td>
<td data-label="合计">768元</td>
</tr>
<tr>
<td data-label="国家">土耳其</td>
<td data-label="签证类型">电子签</td>
<td data-label="出签时间">6小时</td>
<td data-label="签证费"></td>
<td data-label="服务费"></td>
<td data-label="合计">658元</td>
</tr>
<tr>
<td data-label="国家">土耳其</td>
<td data-label="签证类型">电子签</td>
<td data-label="出签时间">15分钟</td>
<td data-label="签证费"></td>
<td data-label="服务费"></td>
<td data-label="合计">988元</td>
</tr>
<tr>
<td class="price-table__note" colspan="6">注:签证费因汇率问题实时波动,费用以每次央行公布汇率为准</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</main>
{include file="public/footer" /}
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,122 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<link rel="stylesheet" href="/static/home/css/info-page.css?v=1">
<body class="main cn home info-page home-layout-page">
<div class="content info-page__menu">
{include file="public/home_menu" /}
</div>
<main class="info-shell">
<section class="info-card help-card">
<h1>使用帮助</h1>
<div class="help-list">
<article class="help-item">
<h2>1) 什么是签证更新电子系统EVUS?</h2>
<p>签证更新电子系统,或EVUS,是指持有十年有效B1/B2、B1或B2签证的中国公民所使用的个人基本信息在线定期更新系统,以协助其赴美旅行。</p>
<p>除了有效签证以外,上述旅客必须完成EVUS登记,才能获得许可进入美国。</p>
</article>
<article class="help-item">
<h2>2) 我的登记申请多久可以出结果?</h2>
<p>在大多数情况下,EVUS将在五分钟内回复登记状态。如遇使馆系统维护,时间将会延长到2-3小时。</p>
<p>在需要额外审查的情况下,答复通常是在72小时内做出。</p>
<p>建议您一个小时之内回来检查,因为大多数“待处理”的状态将在一个小时内更改为“已登记”。</p>
</article>
<article class="help-item">
<h2>3) EVUS登记收费吗?</h2>
<p>美国海关和边境保护局(CBP)现阶段不收取EVUS登记申请的费用。CBP预期EVUS的报名费最终将会执行,但目前并没有何时开始收费的时间表。</p>
</article>
<article class="help-item">
<h2>4) 如何获知EVUS登记是否成功?</h2>
<p>如果查询登记状态显示“已登记”,说明EVUS登记已经成功。</p>
<p>大多数情况下,提交申请后五分钟内系统会发送“EVUS已登记成功”的通知短信到登记时填写的手机号码。</p>
<p>同时会发送登记成功的文档到登记时填写的邮箱。</p>
<p>如进入审核程序,通常72小时内才能给出登记结果。期间会有客服人员联系您进行资料审核,请耐心等候。</p>
</article>
<article class="help-item">
<h2>5) 赴美前未做EVUS登记将会如何?</h2>
<p>2016年11月29日开始,持中华人民共和国签发的护照并同时持有最长有效期(10年期)B1/B2、B1或B2签证的旅客(所有旅客,无论年龄大小),如果在航空公司系统中没有有效的EVUS登记成功记录,航空公司不会为其提供登机牌。</p>
</article>
<article class="help-item">
<h2>6) 出入境时是否需要打印EVUS登记成功的文档?</h2>
<p>EVUS登记成功后,正常情况下登记状态会在海关和航空公司的系统中显示出来,并不需要提供额外的纸质文档。但是会有个别航空公司由于无法获得旅客登记状况,会要求旅客出示登记成功的证明,这时客户需要出示纸质文档或者证明登记成功的电子文档。</p>
<p>建议客户关注“EVUS”微信公众号,随时查询EVUS登记成功的电子文档,出入境时出示此电子文档即可,不需额外打印纸质文档。</p>
</article>
<article class="help-item">
<h2>7) 我应于何时申请EVUS登记?</h2>
<p>美国国土安全部建议您至少在行前72小时申请EVUS登记。但是,您可以在登机前的任何时间申请。在大多数的情况下,您可以在提交申请后五分钟内收到回复。</p>
</article>
<article class="help-item">
<h2>8) EVUS登记的有效期是多长时间?</h2>
<p>成功的EVUS登记一般有效期为两年,可多次往返(从您登记核准日期开始)或直到您的护照或签证到期,以先到者为准。这意味着,只要您的EVUS旅行登记是成功的,在有效期间内不必再申请登记。</p>
<p>成功的EVUS登记有可能改变状态为不成功。这意味着您的EVUS登记不再有效,而且您没有资格使用您现有的访客签证旅行。在EVUS登记成功的文档中会显示您EVUS登记的到期日期。</p>
<p>仅在抵达时,您的EVUS登记必须有效。如果在您入境之后您的EVUS到期,而且人在美国,这将不会影响您离境。</p>
<p>如果您取得一本新的护照或变更您的姓名、性别、或国籍,您需要重新进行EVUS登记。如果任何一个EVUS的问题您的答案有所变化,也需要重新进行EVUS登记。</p>
</article>
<article class="help-item">
<h2>9) 谁必须在EVUS上登记?</h2>
<p>中华人民共和国(PRC)的公民;</p>
<p>持有10年有效期美国B1、B2或B1/B2签证;</p>
<p>计划前往美国进行短期商务、旅游。</p>
</article>
<article class="help-item">
<h2>10) 如果我的签证仍然有效,但在过期的护照上,我可以用我的签证吗?</h2>
<p>如果您的签证仍然有效,但在过期的护照上,您应该使用含有签证的过期护照和另一个新的有效护照去申请EVUS登记。当完成了EVUS的登记,您将使用新的护照作为主要的护照。</p>
<p>当前往美国时,会要求您同时出示有效的护照和含有效签证的过期护照。</p>
</article>
<article class="help-item">
<h2>11) 成功的EVUS登记能否保证入境美国?</h2>
<p>不能。成功的EVUS登记证明您有资格用您10年有效期的B1、B2或B1/B2的美国访客签证前往美国,但这并不保证您能入境美国。当您抵达美国,在入境口岸您将接受Customs &amp; Border Protection官员的检查,该名官员可能根据美国法律的规定因为任何原因决定您无法入境美国。</p>
</article>
<article class="help-item">
<h2>12) 如果我只是过境美国前往另一个国家,我需要申请EVUS登记吗?</h2>
<p>过境美国也需要进行EVUS登记。如果旅客计划只过境美国转往另一个国家,在EVUS登记时,针对“您前往美国是否过境转往另一个国家?”这个问题必须回答“是”。</p>
</article>
<article class="help-item">
<h2>13) B1/B2签证有效期问题</h2>
<p>1,绝大多数申请人的B1/B2签证有效期是10年,所有10年B1/B2签证在前往美国前,必须具备生效的美国签证系统EVUS电子签证更新。</p>
<p>2,只有极个别B1/B2签证低于10年,此种情况下常见1年有效期B1/B2签证,这种情况,不需要进行EVUS登记!</p>
</article>
<article class="help-item">
<h2>14) 护照有效期问题以及有美国签证的护照换发问题</h2>
<p>1,16岁以上的护照有效期是10年。</p>
<p>2,16岁以下护照有效期5年。</p>
<p>3,护照低于6个月有效期的禁止前往美国。</p>
<p>因为签证有效期10年,且护照低于6个月有效期的申请人禁止前往美国;因此存在签证有效,但护照过期或者低于6个月而失效的情况,此种情形申请人需要携带旧护照前往申请人中国所在地的出入境管理局换发新护照,请将旧护照交予出入境管理局,护照首页剪角作废,并保留美国签证。申请人注意,当你在出入境管理局时,所有不携带原始护照或者谎称护照丢失而补发的护照,该护照上面的美国签证全部作废!</p>
</article>
<article class="help-item">
<h2>15) 美国B1/B2签证EVUS有效期时长问题</h2>
<p>1,美国B1/B2十年签证有效,且护照有效期大于2年6个月的,EVUS电子签证有效期2年。</p>
<p>2,美国B1/B2十年签证有效,且护照有效期少于2年6个月的,EVUS电子签证有效期:护照实际有效期减去6个月,即为EVUS电子签证有效期(例如:护照剩余有效期是2年3个月,则EVUS有效期为19个月)。</p>
<p>3,美国B1/B2十年签证有效,但护照有效期低于6个月的,不准予美国EVUS电子签证登记,请换发新护照。</p>
<p>4,美国B1/B2十年签证有效,持有刚刚换发的新护照的,所有有效的EVUS会立即失效,需要立即重新更新,并在更新时填写新旧两本护照的相关信息。</p>
</article>
<article class="help-item">
<h2>16) 美国B1/B2十年签证有效,EVUS失效以及申请人情况有所变更的是否需要登记更新?</h2>
<p>1,从美国返回后,美国签证EVUS电子登记过期失效,近期无前往美国的计划,EVUS可以更新吗?</p>
<p>EVUS过期失效不必然导致美国签证失效,您可以在前往美国前进行登记即可。不过,从既往情况来看,极少量客户出现美国签证被取消或者被要求重新面签的情况;即便没有计划赴美,及时更新EVUS也更稳妥。因此,即便近期无赴美计划,也建议及时更新您的EVUS美国电子更新系统。</p>
<p>2,美国B1/B2十年签证有效,护照有效且无换新护照情况,EVUS电子签证也有效,但是个人信息(住址、工作信息、赴美地址、联系方式等)有变化,需要EVUS电子签证更新吗?</p>
<p>建议更新新的EVUS电子更新。美国EVUS电子更新系统设置的目的就是要掌握并审核申请人的现有情况,并据此来评估是否符合赴美条件。</p>
</article>
</div>
</section>
</main>
{include file="public/footer" /}
</body>
</html>

View File

@@ -0,0 +1,96 @@
{include file="public/head" /}
<body class="ac-home">
<link rel="stylesheet" href="/static/home/css/home-acvisa.css?v=20261030-4">
<a class="ac-skip" href="#main">跳到主要内容</a>
{include file="public/site_nav" /}
<main id="main">
<section class="ac-hero">
<img class="ac-hero-image" src="/static/home/images/index_bj_1.jpg" alt="纽约自由女神像与海湾" width="3888" height="2592" fetchpriority="high">
<div class="ac-wrap ac-hero-inner">
<div class="ac-hero-copy">
<p class="ac-eyebrow"><span></span> YOUR JOURNEY STARTS HERE</p>
<h1>赴美行程,<br>从容<span>准备。</span></h1>
<p class="ac-hero-subtitle">EVUS 中文登记服务</p>
<p class="ac-hero-description">从信息填写到登记查询,清晰指引每一步。<br>提前做好出行准备,把更多时间留给旅程。</p>
<div class="ac-actions">
<a class="ac-button ac-button-primary" href="{:url('home/detail/index')}">开始 EVUS 登记 <span aria-hidden="true">↗</span></a>
<a class="ac-button ac-button-outline" href="{:url('home/lookup/index')}">查询已有登记 <span aria-hidden="true">→</span></a>
</div>
<div class="ac-hero-features"><span>中文填写</span><span>在线办理</span><span>进度查询</span></div>
</div>
</div>
</section>
<div class="ac-wrap">
<aside class="ac-disclosure" aria-label="服务性质与费用说明">
<span class="ac-info" aria-hidden="true">i</span>
<p><strong>服务说明</strong> 本网站为独立运营的商业服务平台,提供有偿代办服务,非任何政府机构或附属部门。收费包含官方费用与服务费,具体金额请在提交前确认。您也可以前往 <a href="https://www.evus.gov/" target="_blank" rel="noopener noreferrer">EVUS 官方网站 <span aria-hidden="true">↗</span></a> 自行登记。</p>
</aside>
<section class="ac-services" aria-label="快捷服务">
<a class="ac-service ac-service-featured" href="{:url('home/detail/index')}">
<div class="ac-service-head"><span class="ac-service-icon"><svg class="ac-line-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="5" y="2.5" width="14" height="19" rx="2"/><circle cx="12" cy="10" r="3.5"/><path d="M8.5 10h7M12 6.5c2 2 2 5 0 7-2-2-2-5 0-7ZM9 17h6"/></svg></span><span class="ac-service-number">01 / EVUS</span></div>
<h2>新登记申请 <span aria-hidden="true">↗</span></h2><p>开始填写,提交您的登记信息</p>
</a>
<a class="ac-service" href="{:url('home/lookup/index')}">
<div class="ac-service-head"><span class="ac-service-icon"><svg class="ac-line-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M11 21H5V3h10l4 4v4M15 3v4h4M8 8h3M8 12h3"/><circle cx="16" cy="16" r="4"/><path d="m19 19 3 3"/></svg></span><span class="ac-service-number">02 / STATUS</span></div>
<h2>查询已有登记 <span aria-hidden="true">↗</span></h2><p>查看登记状态与办理结果</p>
</a>
<a class="ac-service" href="{:url('home/esta/index')}">
<div class="ac-service-head"><span class="ac-service-icon"><svg class="ac-line-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="m3 11 18-8-7 18-3-7-8-3Zm8 3L21 3M3 20l3-3"/></svg></span><span class="ac-service-number">03 / ESTA</span></div>
<h2>ESTA 申请 <span aria-hidden="true">↗</span></h2><p>前往 ESTA 旅行授权申请服务</p>
</a>
<a class="ac-service" href="https://visa.evus.cn/" target="_blank" rel="noopener noreferrer">
<div class="ac-service-head"><span class="ac-service-icon"><svg class="ac-line-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="m3 8 9-5 9 5H3Zm2 3v7m5-7v7m4-7v7m5-7v7M3 18h18M2 21h20"/></svg></span><span class="ac-service-number">04 / VISA</span></div>
<h2>美国签证申请 <span aria-hidden="true">↗</span></h2><p>了解美签申请相关服务</p>
</a>
</section>
<section class="ac-section" aria-labelledby="process-title">
<div class="ac-section-heading"><div><p class="ac-eyebrow">HOW IT WORKS</p><h2 id="process-title">三步,完成在线办理</h2></div><a class="ac-text-link" href="{:url('home/help/index')}">查看办理指南 <span aria-hidden="true">→</span></a></div>
<ol class="ac-steps">
<li><span class="ac-step-number">01</span><div><h3><svg class="ac-line-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M13 4H4v16h16v-9M10 14l1-4 8-8 3 3-8 8-4 1Z"/></svg>填写申请信息</h3><p>准备护照、美国签证及个人资料,<br>按页面指引填写并核对信息。</p></div></li>
<li><span class="ac-step-number">02</span><div><h3><svg class="ac-line-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 9h18m-10 5 2 2 4-4"/></svg>确认并提交</h3><p>确认登记信息与服务费用,<br>完成支付后提交申请。</p></div></li>
<li><span class="ac-step-number">03</span><div><h3><svg class="ac-line-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M6 3h9l4 4v14H6V3Zm9 0v4h4m-10 7 2 2 5-5"/></svg>查询办理结果</h3><p>通过登记查询查看处理状态,<br>按页面提示获取登记文件。</p></div></li>
</ol>
<p class="ac-process-note">请为办理预留充足时间,实际处理进度与结果以审核为准。</p>
</section>
</div>
<section class="ac-preparation" aria-labelledby="prepare-title">
<div class="ac-wrap ac-prepare-grid">
<div><p class="ac-eyebrow">BEFORE YOU BEGIN</p><h2 id="prepare-title">准备好资料,<br>填写更顺畅。</h2><p class="ac-prepare-intro">开始前,将这些信息放在手边。<br>准确、完整的填写,是顺利办理的第一步。</p><a class="ac-text-link" href="{:url('home/detail/index')}">资料已备齐,开始登记 <span aria-hidden="true">→</span></a></div>
<div class="ac-checklist">
<div><span aria-hidden="true">✓</span><div><h3>护照与美国签证</h3><p>核对证件上的姓名、号码及有效期等信息。</p></div></div>
<div><span aria-hidden="true">✓</span><div><h3>个人与联系方式</h3><p>准备个人基本信息、联系地址及紧急联系人资料。</p></div></div>
<div><span aria-hidden="true">✓</span><div><h3>工作与旅行信息</h3><p>根据表格要求,填写就业情况及相关赴美信息。</p></div></div>
<p>填写前请阅读申请说明,并如实回答所有问题。</p>
</div>
</div>
</section>
<div class="ac-wrap">
<section class="ac-section ac-faq-grid" aria-labelledby="faq-title">
<div><p class="ac-eyebrow">QUESTIONS & ANSWERS</p><h2 id="faq-title">有疑问?<br>先看看这里。</h2><p class="ac-section-intro">了解服务与办理方式,<br>再开始您的申请。</p><a class="ac-text-link" href="{:url('home/help/index')}">更多常见问题 <span aria-hidden="true">→</span></a></div>
<div class="ac-faq">
<details open><summary>这个网站是 EVUS 官方网站吗?</summary><p>不是。本网站是独立商业服务平台,提供收费的中文代理登记服务,不隶属于美国政府。您可以选择本平台服务,也可以前往 <a href="https://www.evus.gov/" target="_blank" rel="noopener noreferrer">EVUS 官方网站</a> 自行办理。</p></details>
<details><summary>开始填写前,需要准备哪些信息?</summary><p>请准备护照、美国签证、个人及就业信息、联系方式、紧急联系人和相关旅行信息。具体填写项目以申请表要求为准。</p></details>
<details><summary>已经提交登记,在哪里查看进度?</summary><p>点击 <a href="{:url('home/lookup/index')}">查询已有登记</a>,按查询页面提示填写信息。您也可以进入 <a href="{:url('home/user/order')}">我的订单</a> 查看订单。</p></details>
<details><summary>提交前需要注意什么?</summary><p>请仔细核对证件信息,如实回答表格中的问题,并在支付前确认所选服务及费用。办理进度与结果以实际审核为准,请提前安排出行准备。</p></details>
</div>
</section>
<section class="ac-section ac-news" aria-labelledby="news-title">
<div class="ac-section-heading"><div><p class="ac-eyebrow">TRAVEL UPDATES</p><h2 id="news-title">出行资讯</h2></div><a class="ac-text-link" href="{:url('home/news/index')}">查看全部资讯 <span aria-hidden="true">→</span></a></div>
{notempty name="data"}
<div class="ac-news-list">
{volist name="data" id="vo"}
<a href="{:url('home/news/detail',['id'=>$vo['id']])}"><span class="ac-news-title">{$vo['title']}</span><time>{$vo['create_time']}</time><span aria-hidden="true">↗</span></a>
{/volist}
</div>
{else /}
<div class="ac-news-empty"><p>暂无最新资讯</p><span>您可以先前往帮助中心,了解登记流程与常见问题。</span><a class="ac-text-link" href="{:url('home/help/index')}">前往帮助中心 →</a></div>
{/notempty}
</section>
<section class="ac-closing"><div><p class="ac-eyebrow">READY FOR YOUR NEXT JOURNEY?</p><h2>下一段旅程,从准备开始。</h2></div><a class="ac-button ac-button-light" href="{:url('home/detail/index')}">开始 EVUS 登记 <span aria-hidden="true">↗</span></a></section>
<div class="ac-footer-links"><a class="ac-brand" href="{:url('home/index/index')}"><img src="/static/home/images/logo_113.png" alt="eVUS 代理登记服务" width="2385" height="338" loading="lazy"></a><div><a href="{:url('home/company/index')}">关于我们</a><a href="{:url('home/help/index')}">帮助中心</a><a href="{:url('home/user/order')}">我的订单</a></div></div>
</div>
</main>
{include file="public/footer" /}
</body>
</html>

View File

@@ -0,0 +1,207 @@
<!DOCTYPE html>
<html lang="" style="height:100%;">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="/static/home/js/jquery.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<style>
body {
width: 100%;
height: 100%;
background: url("/static/images/evisabj.jpg") no-repeat;
background-size: cover; /* 让背景图片覆盖整个元素 */
overflow: hidden;
}
.evisa {
height: 100%;
background: url("/static/images/evisa_1.png") no-repeat;
background-size: 100% 100%; /* 让背景图片覆盖整个元素 */
display: flex;
justify-content: center;
align-items: center;
}
.evisa a {
margin: 0 8px;
text-decoration: none;
color: white;
font-size: 22px;
font-weight: bold;
}
.content {
display: flex;
position: relative;
top: 200px;
height: 100%;
justify-content: center;
}
.content-left {
width: 23%;
border-radius: 16px;
height: 75%;
}
.content-right {
display: flex;
flex-direction: column;
height: 75%;
}
.content-right-top {
display: flex;
height: 67%;
}
.right-top-right {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
.right-top-right-top {
height: 50%;
}
.right-top-right-bottom {
display: flex;
margin-top: 16px;
height: 46%;
}
.content-right-bottom {
height: 32.1%;
margin-top: 16px;
}
.right-top-right-bottom-left {
width: 50%;
}
.right-top-right-bottom-right {
margin-left: 12px;
width: 50%;
}
.content-center{
display: flex;
flex-direction: column;
width: 40%;
height: 75%;
margin-left: 3%;
margin-right: 1%;
}
.content-center-top{
height: 67%;
}
.content-center-bottom{
display: flex;
height: 32.1%;
justify-content: space-between;
margin-top: 16px;
}
.content-center-bottom-left{
width: 50%;
}
.content-center-bottom-right{
width: 50%;
margin-left: 16px;
}
img{
width: 100%;
height: 100%;
object-fit: fill;
}
</style>
<body>
<div class="content">
<div class="content-left">
<img src="/static/images/info_2.png">
</div>
<div class="content-center">
<div class="content-center-top">
<a href="https://zxds160.jzvisa.com/home/demo/index.html" target="_blank">
<img src="/static/images/meiguo_4.jpg">
</a>
</div>
<div class="content-center-bottom">
<div class="content-center-bottom-left">
<a href="https://austr.jzvisa.com/" target="_blank">
<img src="/static/images/aoxin_1.png">
</a>
</div>
<div class="content-center-bottom-right">
<a href="https://europe.jzvisa.com/" target="_blank">
<img src="/static/images/shengen_1.png">
</a>
</div>
</div>
</div>
<div class="content-right">
<div class="content-right-top">
<div class="right-top-right">
<div class="right-top-right-top">
<a href="{:url('home/detail/index')}" target="_blank" rel="noopener noreferrer">
<img src="/static/images/evus_4.jpg" alt="EVUS登记">
</a>
</div>
<div class="right-top-right-bottom">
<div class="right-top-right-bottom-left">
<a href="https://ircc.jzvisa.com/home/canform/index" target="_blank">
<img src="/static/images/cannada_2.png">
</a>
</div>
<div class="right-top-right-bottom-right">
<a href="https://japan.jzvisa.com/" target="_blank">
<img src="/static/images/japan.jpg">
</a>
</div>
</div>
</div>
</div>
<div class="content-right-bottom">
<div class="right-bottom-item evisa">
<div style="margin-top: 6px">
<a href="https://turkey.jzvisa.com/" target="_blank">
土耳其
</a>
<a href="https://singapore.jzvisa.com/" target="_blank">
新加坡
</a>
<a href="https://mala.jzvisa.com/" target="_blank">
马来西亚
</a>
<a href="https://vietnam.jzvisa.com/" target="_blank">
越南
</a>
<a href="https://russia.jzvisa.com/" target="_blank">
俄罗斯
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</body>

View File

@@ -0,0 +1,280 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<link rel="stylesheet" href="/static/home/css/weui.min.css">
<link rel="stylesheet" href="/static/home/css/jquery-weui.min.css">
<style>
.layui-form-label {
width: 100px;
}
.layui-form{
margin-right: 10px;
}
.login-bg{
background: #f0f0f0;
}
.login-box{
width: 460px;
height: auto;
padding: 40px 0 20px;
margin: 0 auto;
background: #fff;
box-shadow: 0 0 20px rgba(0,0,0,0.2);
border-radius: 20px;
position: relative;
margin-top: 80px;
}
.login-logo{
width: 180px;
height: 70px;
text-align: center;
background: url(/static/home/images/loginbg3.png) no-repeat;
background-size: 180px 60px;
position: absolute;
left: 50%;
margin-left: -90px;
top: 0;
margin-top: -30px;
color: #fff;
line-height: 60px;
}
.login-con{
padding: 10px 20px;
overflow: hidden;
}
.login-row{
width: 100%;
min-height: 40px;
border-bottom: 1px solid #ddd;
margin-top: 10px;
line-height: 40px;
}
.login-row input{
padding: 0;
box-shadow: none!important;
font-size: 16px;
}
.login-row label{
font-size: 14px;
color: #666;
}
.login-row .login-text{
width: 100%;
height: 40px;
background: none;
border: none;
outline: none;
line-height: 40px;
}
.login-row .login-text2{
width: 75%;
float: left;
}
.login-row .login-get{
float: right;
line-height: 36px;
height: 36px;
width: 25%;
background: var(--banner-color);
border-radius: 5px;
border: none;
outline: none;
text-align: center;
color: #fff;
font-size: 14px;
cursor: pointer;
}
.login-row .login-get:disabled{
background: #999;
}
.login-row .login-get:hover{
opacity: 0.8;
}
.login-row .login-btn{
width: 100%;
height: 50px;
background: var(--banner-color);
border: none;
outline: none;
color: #fff;
font-size: 18px;
border-radius: 10px;
margin-top: 15px;
cursor: pointer;
}
.login-row .login-btn:hover{
opacity: 0.8;
}
.login-row a{
text-align: center;
margin: 0 auto;
font-size: 14px;
line-height: 40px;
}
.login-row .checkbox-inline input[type="checkbox"]:checked:after{
top: 5px;
}
@media(max-width:700px) {
.login-box{
width: 350px;
margin-bottom: 10px;
}
.login-row{ font-size: 14px;}
.login-row .login-text2{ width: 55%;}
.login-row .login-get{ width: 35%;}
}
.layui-btn{
background: var(--banner-color);
}
.layui-layer-content img{
width: 150px;
}
.in-img{
text-align: center;
}
.layui-layer-content img{
width: 150px;
}
</style>
<body class="main cn home home-layout-page login-bg">
<div class="content detail-page__menu" style="padding-bottom: 20px;">
{include file="public/home_menu" /}
</div>
<div class="login-box layui-container" style="text-align:center;">
<div style="margin-bottom: 8px;color: #951e14">注意:如果是个人开票,税号请填写身份证号码</div>
<form class="layui-form" action="">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">开票金额</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" autocomplete="off" class="layui-input" readonly value="{$data.total_price}">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">手机号<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" autocomplete="off" class="layui-input" lay-verify="required|phone" name="phone" placeholder="用于获取发票使用">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">客户名称<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="title" lay-verify="required"placeholder="限55个字符" maxlength="55" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">税号<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="tax_number" lay-verify="required" placeholder="请输入税号" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">联系人<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="link_person" lay-verify="required" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">邮箱<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="link_email" lay-verify="required" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">地址</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="address" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">电话</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="mobile" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">开户行</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="bank" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">账号</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="account" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<input type="hidden" name="order_id" value="{$data.id}">
<input type="hidden" name="order_sn" value="{$data.order_sn}">
<div class="layui-form-item">
<div class="layui-inline">
<button type="submit" class="layui-btn" lay-submit lay-filter="demo1">提交</button>
</div>
</div>
</form>
</div>
</body>
{include file="public/footer" /}
<script type="text/javascript" src="/static/home/js/jquery-weui.min.js"></script>
<script type="text/javascript" src="/static/home/js/invoice-evus-notice.js"></script>
<!--//倒计时-->
<script>
layui.use(['form', 'laydate', 'util'], function(){
var form = layui.form;
var layer = layui.layer;
// 提交事件
form.on('submit(demo1)', function(data){
var field = data.field; // 获取表单字段值
const tax_len = field.tax_number.length;
var arr = [15,17,18,20]
if (arr.indexOf(tax_len)==-1){
layer.msg('仅支持购方税号长度为15,17,18,20,请重新输入');
return false;
}
var load = layer.load(2, {shade: 0.3})
$.ajax({
url: "/home/invoice/add_invoice",
type: 'POST',
data: field,
success: function (res) {
layer.close(load)
if (res.status == 1) {
layer.alert('已提交开票申请,商家会在 1-3个工作日内完成开票,<br>请扫描下方二维码进行添加客服收取发票<br><div class="in-img"><img src="{$fapiao_kefu}"></div>', {
icon: 1,
title:'发票申请',
closeBtn: 0
}, function(index){
layer.close(index);
window.location.href = res.url;
});
} else {
layer.msg(res.msg)
}
}
})
return false; // 阻止默认 form 跳转
});
});
</script>
</html>

View File

@@ -0,0 +1,390 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/weui.min.css">
<link rel="stylesheet" href="/static/home/css/jquery-weui.min.css">
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<style>
.footer {
position: fixed;
bottom: 0;
}
.login-bg{
background: #f0f0f0;
}
.login-box{
width: 460px;
height: auto;
padding: 40px 0 20px;
margin: 0 auto;
background: #fff;
box-shadow: 0 0 20px rgba(0,0,0,0.2);
border-radius: 20px;
position: relative;
margin-top: 80px;
}
.login-logo{
width: 180px;
height: 70px;
text-align: center;
background: url(/static/home/images/loginbg3.png) no-repeat;
background-size: 180px 60px;
position: absolute;
left: 50%;
margin-left: -90px;
top: 0;
margin-top: -30px;
color: #fff;
line-height: 60px;
}
.login-con{
padding: 10px 20px;
overflow: hidden;
}
.login-row{
width: 100%;
min-height: 40px;
border-bottom: 1px solid #ddd;
margin-top: 10px;
line-height: 40px;
}
.login-row input{
padding: 0;
box-shadow: none!important;
font-size: 16px;
}
.login-row label{
font-size: 14px;
color: #666;
}
.login-row .login-text{
width: 100%;
height: 40px;
background: none;
border: none;
outline: none;
line-height: 40px;
}
.login-row .login-text2{
width: 75%;
float: left;
}
.login-row .login-get{
float: right;
line-height: 36px;
height: 36px;
width: 25%;
background: var(--banner-color);
border-radius: 5px;
border: none;
outline: none;
text-align: center;
color: #fff;
font-size: 14px;
cursor: pointer;
}
.login-row .login-get:disabled{
background: #999;
}
.login-row .login-get:hover{
opacity: 0.8;
}
.login-row .login-btn{
width: 100%;
height: 50px;
background: var(--banner-color);
border: none;
outline: none;
color: #fff;
font-size: 18px;
border-radius: 10px;
margin-top: 15px;
cursor: pointer;
}
.login-row .login-btn:hover{
opacity: 0.8;
}
.login-row a{
text-align: center;
margin: 0 auto;
font-size: 14px;
line-height: 40px;
}
.login-row .checkbox-inline input[type="checkbox"]:checked:after{
top: 5px;
}
@media(max-width:700px) {
.login-box{
width: 300px;
}
.login-row{ font-size: 14px;}
.login-row .login-text2{ width: 55%;}
.login-row .login-get{ width: 35%;}
}
</style>
<link rel="stylesheet" href="/static/home/css/login.css?v=2">
<body class="login-bg home-layout-page login-page">
<div class="content login-shell">
{include file="public/home_menu" /}
<div class="login-box">
<div class="login-logo">www.evus.cn</div>
<div class="login-con">
<div class="login-row">
<input class="login-text" type="tel" name="mobile" id="mobile" placeholder="手机号"/>
</div>
<div class="login-row">
<input class="login-text login-text2" type="text" name="code" id="code" placeholder="验证码"/>
<input class="login-get" type="button" id="getcode" value="获取验证码"/>
</div>
<div class="login-row login-agreement" style="border: none;">
<label class="checkbox-inline">
<input type="checkbox" class="" name="loginchk" value="" required/></label>
<span class="login-agreement__text">我已阅读并接受<a href="#" class="js-layer-modal"
data-target="#termsAlert">《条款与条件》</a>及<a href="#" class="js-layer-modal"
data-target="#privacyAlert">《隐私政策》</a>。</span>
</div>
<div class="login-row">
<input class="login-btn" type="button" id="dologin" value="立即登录"/>
</div>
</div>
</div>
<!-- Modal terms -->
<div class="modal fade" id="termsAlert" tabindex="-1" role="dialog"
aria-labelledby="modalTermsAlert">
<div class="modal-dialog modal-txt" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" aria-label="关闭"><span
aria-hidden="true">×</span></button>
<h2 class="modal-title" id="myModalLabel">条款与条件</h2>
</div>
<div class="modal-body alert">
<section class="col-sm-12">
<p>
感谢您选择我们的美国签证办理系统。在使用我们的服务之前,请仔细阅读以下条款与条件:
<p> 1. 用户责任:您必须对您提供的信息的准确性和完整性负责。您必须遵守所有适用法律和规定,并且不得以任何方式滥用我们的服务。 </p>
<p> 2. 服务费用:我们的服务可能会收取一定的费用,具体费用标准将在办理过程中告知。请注意,这些费用可能会根据您的签证类型和申请情况而有所不同。 </p>
<p> 3. 申请流程:您需按照我们提供的指导完成签证申请流程。我们将协助您准备所需的文件和材料,并在必要时向您提供支持和建议。 </p>
<p> 4. 审核和审批:最终签证的审核和批准由美国领事馆或使馆负责。我们无法保证您的签证申请一定会被批准,但我们会尽最大努力帮助您准备充分的申请材料。 </p>
<p> 5. 免责声明:我们对因您的签证申请被拒绝而导致的任何损失或后果概不负责。我们也不对因您提供的不准确或不完整信息而导致的后果承担责任。 </p>
<p> 请注意,这些条款与条件可能会根据实际情况进行调整和变更。如果您有任何疑问或需要进一步的帮助,请随时联系我们的客服团队。感谢您的合作! </p>
<p> 请表明您已阅读并了解上述所提供的信息</p>
</section>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default">关闭</button>
</div>
</div>
</div>
</div>
<!-- Modal privacy -->
<div class="modal fade" id="privacyAlert" tabindex="-1" role="dialog"
aria-labelledby="modalTermsAlert">
<div class="modal-dialog modal-txt" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" aria-label="关闭"><span
aria-hidden="true">×</span></button>
<h2 class="modal-title" id="myModalLabel">隐私政策</h2>
</div>
<div class="modal-body alert">
<p>
本应用尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更有个性化的服务,本应用会按照本隐私权政策的规定使用和披露您的个人信息。但本应用将以高度的勤勉、审慎义务对待这些信息。除本隐私权政策另有规定外,在未征得您事先许可的情况下,本应用不会将这些信息对外披露或向第三方提供。本应用会不时更新本隐私权政策。
您在同意本应用服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私权政策属于本应用服务使用协议不可分割的一部分。
<h3>1. 适用范围</h3>
<p>(a) 在您注册本应用帐号时,您根据本应用要求提供的个人注册信息;
(b)
在您使用本应用网络服务,或访问本应用平台网页时,本应用自动接收并记录的您的浏览器和计算机上的信息,包括但不限于您的IP地址、浏览器的类型、使用的语言、访问日期和时间、软硬件特征信息及您需求的网页记录等数据;
(c) 本应用通过合法途径从商业伙伴处取得的用户个人数据。
您了解并同意,以下信息不适用本隐私权政策:
(a) 您在使用本应用平台提供的搜索服务时输入的关键字信息;
(b) 本应用收集到的您在本应用发布的有关信息数据,包括但不限于参与活动、成交信息及评价详情;
(c) 违反法律规定或违反本应用规则行为及本应用已对您采取的措施。</p>
<h3>2. 信息使用</h3>
<p>
(a)本应用不会向任何无关第三方提供、出售、出租、分享或交易您的个人信息,除非事先得到您的许可,或该第三方和本应用(含本应用关联公司)单独或共同为您提供服务,且在该服务结束后,其将被禁止访问包括其以前能够访问的所有这些资料。
(b)
本应用亦不允许任何第三方以任何手段收集、编辑、出售或者无偿传播您的个人信息。任何本应用平台用户如从事上述活动,一经发现,本应用有权立即终止与该用户的服务协议。
(c)
为服务用户的目的,本应用可能通过使用您的个人信息,向您提供您感兴趣的信息,包括但不限于向您发出产品和服务信息,或者与本应用合作伙伴共享信息以便他们向您发送有关其产品和服务的信息(后者需要您的事先同意)</p>
<h3>3. 信息披露</h3>
<p>在如下情况下,本应用将依据您的个人意愿或法律的规定全部或部分的披露您的个人信息:
(a) 经您事先同意,向第三方披露;
(b)为提供您所要求的产品和服务,而必须和第三方分享您的个人信息;
(c) 根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露;
(d) 如您出现违反中国有关法律、法规或者本应用服务协议或相关规则的情况,需要向第三方披露;
(e) 如您是适格的知识产权投诉人并已提起投诉,应被投诉人要求,向被投诉人披露,以便双方处理可能的权利纠纷;
(f)
在本应用平台上创建的某一交易中,如交易任何一方履行或部分履行了交易义务并提出信息披露请求的,本应用有权决定向该用户提供其交易对方的联络方式等必要信息,以促成交易的完成或纠纷的解决。
(g) 其它本应用根据法律、法规或者网站政策认为合适的披露。</p>
<h3>4. 信息存储和交换</h3>
<p>
本应用收集的有关您的信息和资料将保存在本应用及(或)其关联公司的服务器上,这些信息和资料可能传送至您所在国家、地区或本应用收集信息和资料所在地的境外并在境外被访问、存储和展示。</p>
<h3>5. Cookie的使用</h3>
<p>(a) 在您未拒绝接受cookies的情况下,本应用会在您的计算机上设定或取用cookies
,以便您能登录或使用依赖于cookies的本应用平台服务或功能。本应用使用cookies可为您提供更加周到的个性化服务,包括推广服务。
(b)
您有权选择接受或拒绝接受cookies。您可以通过修改浏览器设置的方式拒绝接受cookies。但如果您选择拒绝接受cookies,则您可能无法登录或使用依赖于cookies的本应用网络服务或功能。
(c) 通过本应用所设cookies所取得的有关信息,将适用本政策。</p>
<h3>6. 信息安全</h3>
<p>(a)
本应用帐号均有安全保护功能,请妥善保管您的用户名及密码信息。本应用将通过对用户密码进行加密等安全措施确保您的信息不丢失,不被滥用和变造。尽管有前述安全措施,但同时也请您注意在信息网络上不存在“完善的安全措施”。
(b) 在使用本应用网络服务进行网上交易时,您不可避免的要向交易对方或潜在的交易对</p>
<h3>7.本隐私政策的更改</h3>
<p>
(a)如果决定更改隐私政策,我们会在本政策中、本公司网站中以及我们认为适当的位置发布这些更改,以便您了解我们如何收集、使用您的个人信息,哪些人可以访问这些信息,以及在什么情况下我们会透露这些信息。
(b)本公司保留随时修改本政策的权利,因此请经常查看。如对本政策作出重大更改,本公司会通过网站通知的形式告知。
方披露自己的个人信息,如联络方式或者邮政地址。请您妥善保护自己的个人信息,仅在必要的情形下向他人提供。如您发现自己的个人信息泄密,尤其是本应用用户名及密码发生泄露,请您立即联络本应用客服,以便本应用采取相应措施。</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default">关闭</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="loginAlert" tabindex="-1" role="dialog"
aria-labelledby="modaloginAlert">
<div class="modal-dialog modal-txt" role="document" style="height: auto;">
<div class="modal-content" style="height: auto;">
<div class="modal-header">
<button type="button" class="close" aria-label="关闭"><span
aria-hidden="true">×</span></button>
<h2 class="modal-title" id="myModalLabel" style="font-size: 18px;">登录</h2>
</div>
<div class="modal-body alert">
<section class="col-sm-12">
<p id="loginalert" style="font-size: 20px; line-height: 40px; color: var(--banner-color); font-weight: bold;"></p>
</section>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default">关闭</button>
</div>
</div>
</div>
</div>
</div>
{include file="public/footer" /}
<script type="text/javascript" src="/static/home/js/jquery-weui.min.js"></script>
<script>
function openLayerModal(target) {
var $target = $(target);
var contentHtml = $target.find('.modal-body').html();
layer.open({
type: 1,
title: $target.find('.modal-title').text() || false,
area: window.getAgreementLayerArea(),
skin: window.agreementLayerSkin,
content: '<div class="agreement-layer__body">' + contentHtml + '</div>'
});
}
function showLoginAlert() {
var message = $("#loginalert").text();
layer.open({
type: 1,
title: $("#loginAlert .modal-title").text() || false,
area: '420px',
content: '<div style="padding:24px 28px;font-size:18px;line-height:32px;color:var(--banner-color);font-weight:bold;text-align:center;box-sizing:border-box;">' + $('<div>').text(message).html() + '</div>'
});
}
$(document).on('click', '.js-layer-modal', function (e) {
e.preventDefault();
openLayerModal($(this).data('target'));
});
</script>
<!--//倒计时-->
<script type="text/javascript">
var wait=60;
function settime() {
if (wait == 0) {
$('#getcode').removeAttr("disabled");
$('#getcode').val("获取验证码");
wait = 60;
} else {
$('#getcode').prop("disabled", true);
$('#getcode').val("重新发送 " + wait);
wait--;
setTimeout(function() {
settime()
}, 1000)
}
}
</script>
<script>
$('#getcode').click(function () {
var mobile = $('#mobile').val();
if(!(/^1[3456789]\d{9}$/.test(mobile))){
$("#loginalert").text("手机号码有误,请重新填写");
showLoginAlert();
return false;
}
$.ajax({
url: "{:Url('send_sms')}",
type: "POST",
data: {mobile: mobile},
dataType:"json",
success: function (data) {
if (data.code == 1){
$("#getcode").prop("disabled","disabled");
settime();
}else{
$("#loginalert").text(data.msg);
showLoginAlert();
}
}
})
});
$('#dologin').click(function () {
var mobile = $('#mobile').val();
if(!(/^1[3456789]\d{9}$/.test(mobile))){
$("#loginalert").text("手机号码有误,请重填");
showLoginAlert();
return false;
}
if(!$("[name=code]").val()){
$("#loginalert").text("请先获取并填写验证码");
showLoginAlert();
return false;
}
if($("[name=loginchk]").is(":checked")!=true){
$("#loginalert").text("请先阅读并接受《条款与条件》及《隐私政策》");
showLoginAlert();
return false;
}
var code = $('#code').val();
$.ajax({
url: "{:Url('dologin')}",
type: "POST",
data: {phone: mobile,vercode:code},
dataType:"json",
success: function (data) {
if (data.code == 1){
window.location.href = data.url;
}else{
$("#loginalert").text(data.msg);
showLoginAlert();
}
}
})
});
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,298 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<link rel="stylesheet" href="/static/home/css/weui.min.css">
<link rel="stylesheet" href="/static/home/css/jquery-weui.min.css">
<style>
.layui-form-label {
width: 100px;
}
.layui-form{
margin-right: 10px;
}
.login-bg{
background: #f0f0f0;
}
.login-box{
width: 460px;
height: auto;
padding: 40px 0 20px;
margin: 0 auto;
background: #fff;
box-shadow: 0 0 20px rgba(0,0,0,0.2);
border-radius: 20px;
position: relative;
margin-top: 80px;
}
.login-logo{
width: 180px;
height: 70px;
text-align: center;
background: url(/static/home/images/loginbg3.png) no-repeat;
background-size: 180px 60px;
position: absolute;
left: 50%;
margin-left: -90px;
top: 0;
margin-top: -30px;
color: #fff;
line-height: 60px;
}
.login-con{
padding: 10px 20px;
overflow: hidden;
}
.login-row{
width: 100%;
min-height: 40px;
border-bottom: 1px solid #ddd;
margin-top: 10px;
line-height: 40px;
}
.login-row input{
padding: 0;
box-shadow: none!important;
font-size: 16px;
}
.login-row label{
font-size: 14px;
color: #666;
}
.login-row .login-text{
width: 100%;
height: 40px;
background: none;
border: none;
outline: none;
line-height: 40px;
}
.login-row .login-text2{
width: 75%;
float: left;
}
.login-row .login-get{
float: right;
line-height: 36px;
height: 36px;
width: 25%;
background: var(--banner-color);
border-radius: 5px;
border: none;
outline: none;
text-align: center;
color: #fff;
font-size: 14px;
cursor: pointer;
}
.login-row .login-get:disabled{
background: #999;
}
.login-row .login-get:hover{
opacity: 0.8;
}
.login-row .login-btn{
width: 100%;
height: 50px;
background: var(--banner-color);
border: none;
outline: none;
color: #fff;
font-size: 18px;
border-radius: 10px;
margin-top: 15px;
cursor: pointer;
}
.login-row .login-btn:hover{
opacity: 0.8;
}
.login-row a{
text-align: center;
margin: 0 auto;
font-size: 14px;
line-height: 40px;
}
.login-row .checkbox-inline input[type="checkbox"]:checked:after{
top: 5px;
}
@media(max-width:700px) {
.login-box{
width: 350px;
margin-bottom: 10px;
}
.login-row{ font-size: 14px;}
.login-row .login-text2{ width: 55%;}
.login-row .login-get{ width: 35%;}
}
.layui-btn{
background: var(--banner-color);
}
.layui-layer-content img{
width: 150px;
}
.in-img{
text-align: center;
}
.layui-layer-content img{
width: 150px;
}
</style>
<body class="main cn home home-layout-page login-bg">
<div class="login-box layui-container" style="text-align:center;">
<div style="margin-bottom: 8px;color: #951e14">注意:如果是个人开票,税号请填写身份证号码</div>
<form class="layui-form" action="">
<input type="hidden" id="openid" name="openid" value="{$openid}">
<input type="hidden" id="user_id" name="user_id" value="{$user_id}">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">开票金额</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" autocomplete="off" class="layui-input" readonly value="{$data.total_price}">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">手机号<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" autocomplete="off" class="layui-input" lay-verify="required|phone" name="phone" placeholder="用于获取发票使用">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">客户名称<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="title" lay-verify="required"placeholder="限55个字符" maxlength="55" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">税号<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="tax_number" lay-verify="required" placeholder="请输入税号" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">联系人<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="link_person" lay-verify="required" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">邮箱<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="link_email" lay-verify="required" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">地址</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="address" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">电话</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="mobile" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">开户行</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="bank" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">账号</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="account" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<input type="hidden" name="order_id" value="{$data.id}">
<input type="hidden" name="order_sn" value="{$data.order_sn}">
<div class="layui-form-item">
<div class="layui-inline">
<button type="submit" class="layui-btn" lay-submit lay-filter="demo1">提交</button>
</div>
</div>
</form>
</div>
</body>
<script type="text/javascript" src="/static/home/js/jquery-weui.min.js"></script>
<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>
<!--//倒计时-->
<script>
var uniAppBridgeReady = false;
document.addEventListener('UniAppJSBridgeReady', function () {
uniAppBridgeReady = true;
});
function backAfterInvoiceSubmit() {
if (window.uni && typeof uni.navigateBack === 'function') {
uni.navigateBack();
return;
}
window.history.back();
}
</script>
<script>
layui.use(['form', 'laydate', 'util'], function(){
var form = layui.form;
var layer = layui.layer;
// 提交事件
form.on('submit(demo1)', function(data){
var field = data.field; // 获取表单字段值
const tax_len = field.tax_number.length;
var arr = [15,17,18,20]
if (arr.indexOf(tax_len)==-1){
layer.msg('仅支持购方税号长度为15,17,18,20,请重新输入');
return false;
}
var load = layer.load(2, {shade: 0.3})
$.ajax({
url: "/home/miniinvoice/add_invoice",
type: 'POST',
data: field,
success: function (res) {
layer.close(load)
if (res.status == 1) {
layer.alert('已提交开票申请,商家会在 1-3个工作日内完成开票,<br>请扫描下方二维码进行添加客服收取发票<br><div class="in-img"><img src="{$fapiao_kefu}"></div>', {
icon: 1,
title:'发票申请',
closeBtn: 0
}, function(index){
layer.close(index);
backAfterInvoiceSubmit();
});
} else {
layer.msg(res.msg)
}
}
})
return false; // 阻止默认 form 跳转
});
});
</script>
</html>

View File

@@ -0,0 +1,277 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<link rel="stylesheet" href="/static/css/weui.min.css">
<link rel="stylesheet" href="/static/css/jquery-weui.min.css">
<link rel="stylesheet" href="/visa/css/layui.css" />
<style>
.layui-form-label {
width: 100px;
}
.layui-form{
margin-right: 10px;
}
.login-bg{
background: #f0f0f0;
}
.login-box{
width: 460px;
height: auto;
padding: 40px 0 20px;
margin: 0 auto;
background: #fff;
box-shadow: 0 0 20px rgba(0,0,0,0.2);
border-radius: 20px;
position: relative;
margin-top: 80px;
}
.login-logo{
width: 180px;
height: 70px;
text-align: center;
background: url(/static/home/images/loginbg3.png) no-repeat;
background-size: 180px 60px;
position: absolute;
left: 50%;
margin-left: -90px;
top: 0;
margin-top: -30px;
color: #fff;
line-height: 60px;
}
.login-con{
padding: 10px 20px;
overflow: hidden;
}
.login-row{
width: 100%;
min-height: 40px;
border-bottom: 1px solid #ddd;
margin-top: 10px;
line-height: 40px;
}
.login-row input{
padding: 0;
box-shadow: none!important;
font-size: 16px;
}
.login-row label{
font-size: 14px;
color: #666;
}
.login-row .login-text{
width: 100%;
height: 40px;
background: none;
border: none;
outline: none;
line-height: 40px;
}
.login-row .login-text2{
width: 75%;
float: left;
}
.login-row .login-get{
float: right;
line-height: 36px;
height: 36px;
width: 25%;
background: var(--banner-color);
border-radius: 5px;
border: none;
outline: none;
text-align: center;
color: #fff;
font-size: 14px;
cursor: pointer;
}
.login-row .login-get:disabled{
background: #999;
}
.login-row .login-get:hover{
opacity: 0.8;
}
.login-row .login-btn{
width: 100%;
height: 50px;
background: var(--banner-color);
border: none;
outline: none;
color: #fff;
font-size: 18px;
border-radius: 10px;
margin-top: 15px;
cursor: pointer;
}
.login-row .login-btn:hover{
opacity: 0.8;
}
.login-row a{
text-align: center;
margin: 0 auto;
font-size: 14px;
line-height: 40px;
}
.login-row .checkbox-inline input[type="checkbox"]:checked:after{
top: 5px;
}
@media(max-width:700px) {
.login-box{
width: 350px;
margin-bottom: 10px;
}
.login-row{ font-size: 14px;}
.login-row .login-text2{ width: 55%;}
.login-row .login-get{ width: 35%;}
}
.layui-btn{
background: var(--banner-color);
}
.in-img{
text-align: center;
}
.layui-layer-content img{
width: 150px;
}
</style>
<body class="main cn home home-layout-page login-bg">
<div class="content detail-page__menu" style="padding-bottom: 20px;">
{include file="public/home_menu" /}
</div>
<div class="login-box layui-container" style="text-align:center;">
<div class="login-logo1">开票信息</div>
<div style="margin-bottom: 8px;color: #951e14">注意:如果是个人开票,税号请填写身份证号码</div>
<form class="layui-form" action="">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">开票金额</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" autocomplete="off" class="layui-input" readonly value="{$data.total_price}">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">手机号<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" autocomplete="off" class="layui-input" lay-verify="required|phone" name="phone" placeholder="用于获取发票使用">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">客户名称<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="title" lay-verify="required" placeholder="限55个字符" maxlength="55" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">税号<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="tax_number" lay-verify="required" placeholder="税号长度为15,17,18,20" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">联系人<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="link_person" lay-verify="required" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">邮箱<span style="color:red">*</span></label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="link_email" lay-verify="required|email" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">地址</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="address" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">电话</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="mobile" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">开户行</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="bank" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">账号</label>
<div class="layui-input-inline layui-input-wrap">
<input type="text" name="account" placeholder="请输入" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<input type="hidden" name="order_sn" value="{$data.order_sn}">
<input type="hidden" name="type" value="{$type}">
<div class="layui-form-item">
<div class="layui-inline">
<button type="submit" class="layui-btn" lay-submit lay-filter="demo1">提交</button>
</div>
</div>
</form>
</div>
</body>
{include file="public/footer" /}
<script type="text/javascript" src="/static/js/jquery-weui.min.js"></script>
<!--//倒计时-->
<script>
layui.use(['form', 'laydate', 'util'], function(){
var form = layui.form;
var layer = layui.layer;
// 提交事件
form.on('submit(demo1)', function(data){
var field = data.field; // 获取表单字段值
const tax_len = field.tax_number.length;
var arr = [15,17,18,20]
if (arr.indexOf(tax_len)==-1){
layer.msg('仅支持购方税号长度为15,17,18,20,请重新输入');
return false;
}
var load = layer.load(2, {shade: 0.3})
$.ajax({
url: "/home/Multiple/add_invoice",
type: 'POST',
data: field,
success: function (res) {
layer.close(load)
if (res.status == 1) {
layer.alert('已提交开票申请,商家会在 1-3个工作日内完成开票,<br>请扫描下方二维码进行添加客服收取发票<br><div class="in-img"><img src="{$fapiao_kefu}"></div>', {
icon: 1,
title:'发票申请',
closeBtn: 0
}, function(index){
layer.close(index);
window.location.href = res.url;
});
} else {
layer.msg(res.msg)
}
}
})
return false; // 阻止默认 form 跳转
});
});
</script>
</html>

View File

@@ -0,0 +1,58 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<link rel="stylesheet" href="/static/home/css/news.css?v=2">
<body class="main cn home news-page news-detail-page home-layout-page">
<div class="content news-page__menu">
{include file="public/home_menu" /}
</div>
<main class="news-shell news-detail-shell">
<article class="news-article">
<div class="news-breadcrumb">
<a href="{:url('home/index/index')}">首页</a>
<span>/</span>
<a href="{:url('home/news/index')}">新闻资讯</a>
</div>
<h1>{$data['title']}</h1>
<div class="news-article__meta">作者:admin&nbsp;&nbsp;时间:{$data['create_time']}</div>
<div class="news-article__content">
<?= html_entity_decode($data['contents'] ?? '') ?>
</div>
<div class="news-nav-links">
{notempty name="last"}
<a href="{:Url('News/detail',['id'=>$last['id']])}">
<span>上一篇</span>
<strong>{$last['title']}</strong>
</a>
{/notempty}
{notempty name="next"}
<a href="{:Url('News/detail',['id'=>$next['id']])}">
<span>下一篇</span>
<strong>{$next['title']}</strong>
</a>
{/notempty}
</div>
</article>
{notempty name="article"}
<section class="news-related">
<div class="news-related__head">
<h2>新闻资讯</h2>
<a href="{:url('home/news/index')}">查看更多</a>
</div>
<div class="news-related__grid">
{volist name="article" id="vo"}
<a class="news-related__item" href="{:Url('News/detail',['id'=>$vo['id']])}">
<span>{$vo['title']}</span>
<time>{$vo['create_time']}</time>
</a>
{/volist}
</div>
</section>
{/notempty}
</main>
{include file="public/footer" /}
</body>
</html>

View File

@@ -0,0 +1,59 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<link rel="stylesheet" href="/static/home/css/news.css?v=3">
<body class="main cn home news-page home-layout-page">
<div class="content news-page__menu">
{include file="public/home_menu" /}
</div>
<main class="news-shell">
<section class="news-hero">
<div>
<p class="news-kicker">News</p>
<h1>新闻资讯</h1>
</div>
</section>
<section class="news-list-panel">
{notempty name="data"}
<div class="news-list">
{volist name="data" id="vo"}
<a class="news-list__item" href="{:Url('News/detail',['id'=>$vo['id']])}">
<div class="news-list__content">
<h2>{$vo['title']}</h2>
<p>{$vo['contents']|strip_tags}</p>
</div>
<time>{$vo['create_time']}</time>
</a>
{/volist}
</div>
{else/}
<div class="news-empty">暂无新闻</div>
{/notempty}
<div class="news-pagination" id="case_page"></div>
</section>
</main>
{include file="public/footer" /}
<script>
layui.use(function () {
var laypage = layui.laypage;
laypage.render({
elem: 'case_page',
count: '{$count}',
curr: '{$page}',
limit: '{$size}',
layout: ['prev', 'page', 'next'],
jump: function (obj, first) {
if (!first) {
window.location.href = '{:Url("news/index")}?page=' + obj.curr;
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,580 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>项目总览</title>
<style>
:root {
--bg: #eef5ff;
--panel: rgba(255,255,255,.88);
--panel-strong: #ffffff;
--text: #0d1b34;
--muted: #7b879d;
--line: rgba(128, 151, 183, .22);
--blue: #1667ff;
--blue-soft: #eaf2ff;
--shadow: 0 28px 80px rgba(22, 64, 120, .12);
--card-shadow: 0 18px 42px rgba(18, 46, 92, .10), 0 1px 0 rgba(255,255,255,.9) inset;
--radius: 28px;
}
* { box-sizing: border-box; }
html, body { min-height: 100%; }
body {
margin: 0;
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;
background:
radial-gradient(circle at 16% 8%, rgba(66, 139, 255, .16), transparent 30%),
radial-gradient(circle at 90% 18%, rgba(119, 178, 255, .20), transparent 32%),
linear-gradient(135deg, #f7fbff 0%, #eef5ff 45%, #f8fbff 100%);
overflow-x: hidden;
}
body::before,
body::after {
content: "";
position: fixed;
width: 460px;
height: 460px;
border-radius: 999px;
background: rgba(22, 103, 255, .08);
filter: blur(20px);
pointer-events: none;
z-index: -1;
}
body::before { left: -190px; top: 140px; }
body::after { right: -220px; bottom: -160px; }
.page {
width: min(1520px, calc(100% - 48px));
margin: 28px auto;
min-height: calc(100vh - 56px);
padding: clamp(28px, 4vw, 58px);
border: 1px solid rgba(255,255,255,.85);
border-radius: var(--radius);
background:
linear-gradient(180deg, rgba(255,255,255,.94), rgba(255,255,255,.82)),
radial-gradient(circle at 0% 0%, rgba(22,103,255,.06), transparent 34%);
box-shadow: var(--shadow);
backdrop-filter: blur(18px);
}
.title {
margin: 0 0 28px;
font-size: clamp(34px, 3.4vw, 52px);
line-height: 1.08;
letter-spacing: .03em;
font-weight: 800;
color: #0a172e;
text-shadow: 0 8px 24px rgba(15, 35, 78, .08);
}
.city-tabs {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 28px;
margin-bottom: 34px;
}
.city-tab {
position: relative;
height: 88px;
border: 1px solid var(--line);
border-radius: 17px;
background:
linear-gradient(180deg, rgba(255,255,255,.90), rgba(248,251,255,.82));
color: #7a879a;
display: flex;
align-items: center;
justify-content: center;
gap: 18px;
cursor: pointer;
font-size: clamp(22px, 2vw, 30px);
font-weight: 750;
letter-spacing: .08em;
box-shadow: 0 12px 26px rgba(36, 71, 125, .05);
transition: transform .22s ease, box-shadow .22s ease, border-color .22s ease, color .22s ease, background .22s ease;
outline: none;
user-select: none;
}
.city-tab:hover {
transform: translateY(-2px);
box-shadow: 0 16px 34px rgba(36, 71, 125, .09);
color: #496071;
}
.city-tab.active {
color: var(--blue);
border-color: rgba(22,103,255,.72);
background:
linear-gradient(180deg, rgba(237, 246, 255, .98), rgba(255,255,255,.88));
box-shadow: 0 16px 38px rgba(22, 103, 255, .15), 0 0 0 1px rgba(22,103,255,.08) inset;
}
.city-icon {
width: 54px;
height: 54px;
stroke: currentColor;
fill: none;
stroke-width: 2.6;
stroke-linecap: round;
stroke-linejoin: round;
opacity: .95;
flex: 0 0 auto;
}
.grid {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 18px 26px;
}
.project-card {
min-height: 152px;
border: 1px solid rgba(117, 141, 174, .13);
border-radius: 14px;
background:
radial-gradient(circle at 50% 8%, rgba(255,255,255,.98), rgba(255,255,255,.86) 70%),
linear-gradient(180deg, #fff, #fbfdff);
box-shadow: var(--card-shadow);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 13px;
padding: 18px 12px 15px;
transition: transform .22s ease, box-shadow .22s ease, border-color .22s ease;
animation: cardIn .42s ease both;
color: inherit;
text-decoration: none;
cursor: pointer;
outline: none;
}
.project-card:hover {
transform: translateY(-5px);
border-color: rgba(22, 103, 255, .26);
box-shadow: 0 28px 58px rgba(18, 46, 92, .15), 0 1px 0 rgba(255,255,255,.9) inset;
}
.project-card:focus-visible {
border-color: rgba(22, 103, 255, .75);
box-shadow: 0 0 0 4px rgba(22, 103, 255, .14), 0 28px 58px rgba(18, 46, 92, .15);
}
.project-card:hover .project-name,
.project-card:focus-visible .project-name {
color: var(--blue);
}
.flag-wrap {
width: 162px;
height: 98px;
display: grid;
place-items: center;
transform: translateZ(0);
}
.flag-svg {
width: 148px;
max-width: 100%;
height: auto;
overflow: visible;
filter: drop-shadow(0 13px 9px rgba(23, 39, 68, .18));
transform: perspective(800px) rotateX(4deg) rotateY(-2deg);
transform-origin: center;
}
.flag-svg.nepal {
width: 112px;
filter: drop-shadow(0 11px 7px rgba(23, 39, 68, .20));
}
.project-name {
margin: 0;
text-align: center;
font-size: clamp(18px, 1.45vw, 23px);
line-height: 1.1;
font-weight: 650;
letter-spacing: .02em;
color: #121a2c;
white-space: nowrap;
}
@keyframes cardIn {
from { opacity: 0; transform: translateY(10px) scale(.985); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
@media (max-width: 1240px) {
.grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.city-tabs { gap: 18px; }
}
@media (max-width: 920px) {
.page { width: min(100% - 28px, 920px); padding: 28px; }
.city-tabs { grid-template-columns: 1fr; gap: 14px; }
.city-tab { height: 72px; }
.grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.flag-wrap { width: 138px; height: 84px; }
.flag-svg { width: 126px; }
}
@media (max-width: 680px) {
.page { width: min(100% - 18px, 680px); margin: 9px auto; padding: 22px 16px; border-radius: 22px; }
.title { margin-bottom: 18px; }
.grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 13px; }
.project-card { min-height: 138px; padding: 14px 8px 12px; }
.flag-wrap { width: 126px; height: 76px; }
.flag-svg { width: 116px; }
.project-name { font-size: 17px; }
.city-icon { width: 42px; height: 42px; }
}
@media (max-width: 420px) {
.grid { grid-template-columns: 1fr; }
.project-card { min-height: 150px; }
}
</style>
</head>
<body>
<main class="page" aria-label="项目总览">
<h1 class="title">项目总览</h1>
<section class="city-tabs" aria-label="主体切换">
<button class="city-tab active" type="button" data-city="jinan" aria-selected="true">
<span class="tab-icon" data-icon="jinan"></span><span>济南</span>
</button>
<button class="city-tab" type="button" data-city="beijing" aria-selected="false">
<span class="tab-icon" data-icon="beijing"></span><span>北京</span>
</button>
<button class="city-tab" type="button" data-city="hangzhou" aria-selected="false">
<span class="tab-icon" data-icon="hangzhou"></span><span>杭州</span>
</button>
</section>
<section id="projectGrid" class="grid" aria-live="polite"></section>
</main>
<script>
const projects = {
jinan: [
{ name: 'EVUS / ESTA', flag: 'us', url: 'https://www.evus.cn/' },
{ name: 'DS160', flag: 'us', url: 'https://ds160.jzvisa.com/' },
{ name: '美国签证', flag: 'us', url: 'https://visa.evus.cn/' },
{ name: '欧盟申根', flag: 'eu', url: 'https://europe.jzvisa.com/' },
{ name: '澳大利亚', flag: 'au', url: 'https://aus.jzvisa.com/' },
{ name: '加拿大', flag: 'ca', url: 'https://can.jzvisa.com/' },
{ name: '新加坡', flag: 'sg', url: 'https://sgp.jzvisa.com/' },
{ name: '马来西亚', flag: 'my', url: 'https://mala.jzvisa.com/' },
{ name: '泰国', flag: 'th', url: 'https://th.jzvisa.com/' },
{ name: '蒙古', flag: 'mn', url: 'https://mn.jzvisa.com/' },
{ name: '越南', flag: 'vn', url: 'https://vietnam.jzvisa.com/' },
{ name: '尼泊尔', flag: 'np', url: 'https://npl.jzvisa.com/' },
{ name: '俄罗斯', flag: 'ru', url: 'https://russia.jzvisa.com/' },
{ name: '肯尼亚', flag: 'ke', url: 'https://ke.jzvisa.com/' },
{ name: '日本', flag: 'jp', url: 'https://japan.jzvisa.com/' },
{ name: '新西兰', flag: 'nz', url: 'http://nzl.jzvisa.com/' },
{ name: '英国', flag: 'uk', url: 'https://ukvisa.jzvisa.com/' }
],
beijing: [
{ name: 'EVUS通品', flag: 'us', url: 'https://evus.qlevisa.com/' },
{ name: 'DS160', flag: 'us', url: 'https://ds160.qlevisa.com/' },
{ name: '澳大利亚', flag: 'au', url: 'https://aus.qlevisa.com/' },
{ name: '加拿大', flag: 'ca', url: 'https://canada.qlevisa.com/' },
{ name: '新加坡', flag: 'sg', url: 'https://sgp.qlevisa.com/' },
{ name: '马来西亚', flag: 'my', url: 'https://mala.qlevisa.com/' },
{ name: '泰国', flag: 'th', url: 'https://th.qlevisa.com/' },
{ name: '蒙古', flag: 'mn', url: 'https://mn.qlevisa.cn/' },
{ name: '越南', flag: 'vn', url: 'https://vietnam.qlevisa.cn/' },
{ name: '尼泊尔', flag: 'np', url: 'https://npl.qlevisa.cn/' },
{ name: '俄罗斯', flag: 'ru', url: 'https://russia.qlevisa.cn/' },
{ name: '沙特', flag: 'sa', url: 'https://saudi.qlevisa.cn/' },
{ name: '埃及', flag: 'eg', url: 'https://egypt.qlevisa.cn/' },
{ name: '印尼', flag: 'id', url: 'https://indonesia.qlevisa.cn/' },
{ name: '肯尼亚', flag: 'ke', url: 'https://ke.qlevisa.cn/' },
],
hangzhou: [
{ name: '新加坡', flag: 'sg', url: 'https://evisa.hkpgsow.cn/sgp' },
{ name: '马来西亚', flag: 'my', url: 'https://evisa.hkpgsow.cn/mys' },
{ name: '泰国', flag: 'th', url: 'https://evisa.hkpgsow.cn/tha' },
]
};
const grid = document.getElementById('projectGrid');
let uidCounter = 0;
function cityIcon(type) {
const shared = 'class="city-icon" viewBox="0 0 64 64" aria-hidden="true"';
if (type === 'beijing') {
return `<svg ${shared}><path d="M12 50h40"/><path d="M18 50V32h28v18"/><path d="M15 32h34L32 21 15 32Z"/><path d="M22 39h20"/><path d="M25 50V39h14v11"/><path d="M24 21 32 12l8 9"/><path d="M18 56h28"/></svg>`;
}
if (type === 'hangzhou') {
return `<svg ${shared}><path d="M10 48c9-16 35-16 44 0"/><path d="M17 48c7-9 23-9 30 0"/><path d="M20 48v7M32 41v14M44 48v7"/><path d="M20 30h24"/><path d="M24 30 32 18l8 12"/><path d="M27 30v8h10v-8"/></svg>`;
}
return `<svg ${shared}><path d="M12 52h40"/><path d="M18 52V34h28v18"/><path d="M16 34h32"/><path d="M21 30h26L32 18 21 30Z"/><path d="M26 52V40h12v12"/><path d="M26 18 32 10l6 8"/><circle cx="20" cy="44" r="3"/><circle cx="44" cy="44" r="3"/></svg>`;
}
document.querySelectorAll('.tab-icon').forEach(icon => {
icon.innerHTML = cityIcon(icon.dataset.icon);
});
function starPoints(cx, cy, outer, inner, points = 5, rotation = -90) {
const step = Math.PI / points;
const start = rotation * Math.PI / 180;
const pts = [];
for (let i = 0; i < points * 2; i++) {
const r = i % 2 === 0 ? outer : inner;
const a = start + i * step;
pts.push(`${(cx + Math.cos(a) * r).toFixed(2)},${(cy + Math.sin(a) * r).toFixed(2)}`);
}
return pts.join(' ');
}
function unionJack(x, y, w, h) {
return `
<g transform="translate(${x} ${y})">
<rect width="${w}" height="${h}" fill="#012169"/>
<path d="M0 0 L${w} ${h} M${w} 0 L0 ${h}" stroke="#fff" stroke-width="${h * .18}"/>
<path d="M0 0 L${w} ${h} M${w} 0 L0 ${h}" stroke="#C8102E" stroke-width="${h * .09}"/>
<path d="M${w / 2} 0 V${h} M0 ${h / 2} H${w}" stroke="#fff" stroke-width="${h * .30}"/>
<path d="M${w / 2} 0 V${h} M0 ${h / 2} H${w}" stroke="#C8102E" stroke-width="${h * .17}"/>
</g>`;
}
function wrapFlag(content, code, nepal = false) {
const uid = `${code}-${++uidCounter}`;
if (nepal) {
return `
<svg class="flag-svg nepal" viewBox="0 0 210 205" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="flag">
<defs>
<linearGradient id="wave-${uid}" x1="0" x2="1" y1="0" y2="0">
<stop offset="0" stop-color="#fff" stop-opacity=".12"/><stop offset=".18" stop-color="#000" stop-opacity=".10"/>
<stop offset=".38" stop-color="#fff" stop-opacity=".22"/><stop offset=".62" stop-color="#000" stop-opacity=".08"/>
<stop offset=".82" stop-color="#fff" stop-opacity=".16"/><stop offset="1" stop-color="#000" stop-opacity=".08"/>
</linearGradient>
</defs>
${content}
<path d="M12 8 H148 L74 74 H154 L12 194 Z" fill="url(#wave-${uid})" opacity=".35"/>
</svg>`;
}
return `
<svg class="flag-svg" viewBox="0 0 320 205" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="flag">
<defs>
<clipPath id="clip-${uid}"><rect x="8" y="8" width="304" height="189" rx="10"/></clipPath>
<linearGradient id="wave-${uid}" x1="0" x2="1" y1="0" y2="0">
<stop offset="0" stop-color="#fff" stop-opacity=".08"/><stop offset=".17" stop-color="#000" stop-opacity=".12"/>
<stop offset=".36" stop-color="#fff" stop-opacity=".25"/><stop offset=".56" stop-color="#000" stop-opacity=".08"/>
<stop offset=".76" stop-color="#fff" stop-opacity=".20"/><stop offset="1" stop-color="#000" stop-opacity=".08"/>
</linearGradient>
</defs>
<g clip-path="url(#clip-${uid})">
${content}
<rect x="8" y="8" width="304" height="189" fill="url(#wave-${uid})" opacity=".38"/>
</g>
<rect x="8" y="8" width="304" height="189" rx="10" fill="none" stroke="rgba(0,0,0,.08)"/>
</svg>`;
}
function flagSvg(code) {
const W = 320, H = 205, x = 8, y = 8, w = 304, h = 189;
let c = '';
switch (code) {
case 'us': {
const stripe = h / 13;
c += `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#fff"/>`;
for (let i = 0; i < 13; i += 2) c += `<rect x="${x}" y="${y + i * stripe}" width="${w}" height="${stripe}" fill="#B22234"/>`;
const cw = w * .42, ch = stripe * 7;
c += `<rect x="${x}" y="${y}" width="${cw}" height="${ch}" fill="#3C3B6E"/>`;
for (let row = 0; row < 5; row++) {
for (let col = 0; col < 6; col++) {
c += `<circle cx="${x + 13 + col * 19}" cy="${y + 12 + row * 19}" r="2.7" fill="#fff"/>`;
}
}
for (let row = 0; row < 4; row++) {
for (let col = 0; col < 5; col++) {
c += `<circle cx="${x + 22 + col * 19}" cy="${y + 21 + row * 19}" r="2.7" fill="#fff"/>`;
}
}
return wrapFlag(c, code);
}
case 'tr':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#E30A17"/>
<circle cx="124" cy="103" r="46" fill="#fff"/><circle cx="139" cy="103" r="36" fill="#E30A17"/>
<polygon points="${starPoints(187, 103, 26, 10)}" fill="#fff"/>`;
return wrapFlag(c, code);
case 'sg':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#fff"/>
<rect x="${x}" y="${y}" width="${w}" height="${h/2}" fill="#EF3340"/>
<circle cx="76" cy="55" r="28" fill="#fff"/><circle cx="88" cy="55" r="23" fill="#EF3340"/>
${[[-8,0],[-2,-17],[14,-10],[14,10],[-2,17]].map(p => `<polygon points="${starPoints(108+p[0],55+p[1],7,3)}" fill="#fff"/>`).join('')}`;
return wrapFlag(c, code);
case 'my': {
const stripe = h / 14;
c += `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#fff"/>`;
for (let i = 0; i < 14; i += 2) c += `<rect x="${x}" y="${y + i * stripe}" width="${w}" height="${stripe}" fill="#CC0001"/>`;
c += `<rect x="${x}" y="${y}" width="142" height="108" fill="#010066"/>
<circle cx="66" cy="62" r="33" fill="#FFCC00"/><circle cx="76" cy="62" r="28" fill="#010066"/>
<polygon points="${starPoints(111, 62, 26, 10, 14)}" fill="#FFCC00"/>`;
return wrapFlag(c, code);
}
case 'th': {
const unit = h / 6;
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#A51931"/>
<rect x="${x}" y="${y + unit}" width="${w}" height="${unit}" fill="#fff"/>
<rect x="${x}" y="${y + unit*2}" width="${w}" height="${unit*2}" fill="#2D2A4A"/>
<rect x="${x}" y="${y + unit*4}" width="${w}" height="${unit}" fill="#fff"/>`;
return wrapFlag(c, code);
}
case 'mn': {
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#0066B3"/>
<rect x="${x}" y="${y}" width="${w/3}" height="${h}" fill="#DA2032"/>
<rect x="${x + w*2/3}" y="${y}" width="${w/3}" height="${h}" fill="#DA2032"/>
<g fill="#FFD700" transform="translate(48 42)">
<circle cx="18" cy="16" r="8"/><path d="M18 29 l13 13H5z"/><rect x="9" y="48" width="18" height="42" rx="4"/>
<circle cx="18" cy="64" r="8" fill="#DA2032"/><path d="M3 103h30M8 94h20" stroke="#FFD700" stroke-width="5"/>
</g>`;
return wrapFlag(c, code);
}
case 'vn':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#DA251D"/>
<polygon points="${starPoints(160, 103, 57, 22)}" fill="#FFFF00"/>`;
return wrapFlag(c, code);
case 'np': {
c = `<path d="M12 8 H148 L74 74 H154 L12 194 Z" fill="#003893"/>
<path d="M26 24 H119 L61 79 H127 L26 167 Z" fill="#DC143C"/>
<circle cx="58" cy="64" r="16" fill="#fff"/><circle cx="65" cy="59" r="14" fill="#DC143C"/>
<polygon points="${starPoints(70, 125, 22, 9, 12)}" fill="#fff"/>`;
return wrapFlag(c, code, true);
}
case 'ru':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#fff"/>
<rect x="${x}" y="${y + h/3}" width="${w}" height="${h/3}" fill="#0039A6"/>
<rect x="${x}" y="${y + h*2/3}" width="${w}" height="${h/3}" fill="#D52B1E"/>`;
return wrapFlag(c, code);
case 'ke':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#007A3D"/>
<rect x="${x}" y="${y}" width="${w}" height="${h/3}" fill="#000"/>
<rect x="${x}" y="${y + h/3 - 5}" width="${w}" height="10" fill="#fff"/>
<rect x="${x}" y="${y + h/3}" width="${w}" height="${h/3}" fill="#CE1126"/>
<rect x="${x}" y="${y + h*2/3 - 5}" width="${w}" height="10" fill="#fff"/>
<g transform="translate(160 103)">
<path d="M-48 -52 L48 52 M48 -52 L-48 52" stroke="#fff" stroke-width="5"/>
<ellipse cx="0" cy="0" rx="24" ry="53" fill="#CE1126" stroke="#fff" stroke-width="4"/>
<path d="M0 -48 C-16 -24 -16 24 0 48 C16 24 16 -24 0 -48Z" fill="#000"/>
<circle cx="0" cy="0" r="8" fill="#fff"/>
</g>`;
return wrapFlag(c, code);
case 'jp':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#fff"/>
<circle cx="160" cy="103" r="55" fill="#BC002D"/>`;
return wrapFlag(c, code);
case 'eu': {
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#003399"/>`;
for (let i = 0; i < 12; i++) {
const a = i * Math.PI * 2 / 12 - Math.PI/2;
const sx = 160 + Math.cos(a) * 55;
const sy = 103 + Math.sin(a) * 55;
c += `<polygon points="${starPoints(sx, sy, 8, 3)}" fill="#FFCC00"/>`;
}
return wrapFlag(c, code);
}
case 'ca':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#fff"/>
<rect x="${x}" y="${y}" width="76" height="${h}" fill="#D80621"/>
<rect x="${x+w-76}" y="${y}" width="76" height="${h}" fill="#D80621"/>
<polygon points="160,42 171,74 199,63 185,91 214,98 181,109 190,138 164,122 160,158 156,122 130,138 139,109 106,98 135,91 121,63 149,74" fill="#D80621"/>`;
return wrapFlag(c, code);
case 'nz':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#00247D"/>
${unionJack(x, y, 132, 76)}
<polygon points="${starPoints(224, 70, 17, 7)}" fill="#fff"/><polygon points="${starPoints(224, 70, 12, 5)}" fill="#CC142B"/>
<polygon points="${starPoints(260, 104, 17, 7)}" fill="#fff"/><polygon points="${starPoints(260, 104, 12, 5)}" fill="#CC142B"/>
<polygon points="${starPoints(220, 142, 17, 7)}" fill="#fff"/><polygon points="${starPoints(220, 142, 12, 5)}" fill="#CC142B"/>
<polygon points="${starPoints(278, 150, 15, 6)}" fill="#fff"/><polygon points="${starPoints(278, 150, 10, 4)}" fill="#CC142B"/>`;
return wrapFlag(c, code);
case 'uk':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#012169"/>
<g transform="translate(${x} ${y})">
<path d="M0 0 L${w} ${h} M${w} 0 L0 ${h}" stroke="#fff" stroke-width="42"/>
<path d="M0 0 L${w} ${h} M${w} 0 L0 ${h}" stroke="#C8102E" stroke-width="22"/>
<path d="M${w/2} 0 V${h} M0 ${h/2} H${w}" stroke="#fff" stroke-width="70"/>
<path d="M${w/2} 0 V${h} M0 ${h/2} H${w}" stroke="#C8102E" stroke-width="38"/>
</g>`;
return wrapFlag(c, code);
case 'sa':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#006C35"/>
<g fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round">
<path d="M78 72 C100 57 122 57 144 72 S188 88 220 70" stroke-width="8"/>
<path d="M88 94 H222" stroke-width="6"/>
<path d="M100 126 H230" stroke-width="8"/>
<path d="M218 122 L248 116" stroke-width="4"/>
</g>`;
return wrapFlag(c, code);
case 'eg':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#000"/>
<rect x="${x}" y="${y}" width="${w}" height="${h*2/3}" fill="#fff"/>
<rect x="${x}" y="${y}" width="${w}" height="${h/3}" fill="#CE1126"/>
<path d="M160 88 l10 22 h-20z" fill="#C09300"/><rect x="155" y="110" width="10" height="28" fill="#C09300"/>`;
return wrapFlag(c, code);
case 'id':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#fff"/>
<rect x="${x}" y="${y}" width="${w}" height="${h/2}" fill="#CE1126"/>`;
return wrapFlag(c, code);
case 'au':
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#012169"/>
${unionJack(x, y, 138, 84)}
<polygon points="${starPoints(84, 145, 25, 10, 7)}" fill="#fff"/>
<polygon points="${starPoints(230, 58, 17, 7, 7)}" fill="#fff"/>
<polygon points="${starPoints(260, 102, 14, 6, 7)}" fill="#fff"/>
<polygon points="${starPoints(220, 132, 16, 7, 7)}" fill="#fff"/>
<polygon points="${starPoints(278, 156, 12, 5, 7)}" fill="#fff"/>`;
return wrapFlag(c, code);
default:
c = `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="#e8eef7"/>`;
return wrapFlag(c, code);
}
}
function escapeAttr(value) {
return String(value)
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}
function render(city) {
uidCounter = 0;
const list = projects[city] || [];
grid.innerHTML = list.map((item, index) => `
<a class="project-card" href="${escapeAttr(item.url)}" target="_blank" rel="noopener noreferrer" title="访问${escapeAttr(item.name)}" aria-label="访问${escapeAttr(item.name)}" style="animation-delay:${Math.min(index * 24, 240)}ms">
<div class="flag-wrap">${flagSvg(item.flag)}</div>
<p class="project-name">${item.name}</p>
</a>
`).join('');
}
document.querySelectorAll('.city-tab').forEach(tab => {
tab.addEventListener('click', () => {
document.querySelectorAll('.city-tab').forEach(btn => {
btn.classList.remove('active');
btn.setAttribute('aria-selected', 'false');
});
tab.classList.add('active');
tab.setAttribute('aria-selected', 'true');
render(tab.dataset.city);
});
});
render('jinan');
</script>
</body>
</html>

View File

@@ -0,0 +1,123 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<body class="main cn home home-layout-page">
<style>
.safe{
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.safe img{
width: 80px;
}
.zh-center{
max-width: 1140px;
margin: 10px auto 0;
border: 1px solid #ddd;
box-shadow: 0 0 10px rgba(0,0,0,0.2);
overflow: hidden;
padding-bottom: 20px;
}
.zh-center .qrcode{
border: 1px solid #ddd;
margin: 10px 0;
}
.zh-ddtit{
width: 100%;
height: 40px;
background: var(--banner-color);
color: #fff;
}
.zh-ddtit span{
font-size: 14px;
line-height: 40px;
}
.zh-topline{
width: 100%;
text-align: left;
min-height: 40px;
overflow: hidden;
padding-top:8px;
font-size: 14px;
border-bottom: 1px solid #ddd;
}
.zh-dd{
float: left;
}
.zh-je{
float: right;
}
.zh-je em{
font-style: normal;
color: #f00;
font-size: 18px;
}
@media screen and (min-width: 1000px){
.zh-sys{
display: block;
}
}
@media screen and (max-width: 1000px){
.zh-sys{
display: none;
}
}
@media screen and (max-width: 600px){
/*.zh-center{
border: none;
box-shadow: none;
}*/
}
</style>
<div class="content detail-page__menu">
{include file="public/home_menu" /}
</div>
<div class="col-md-12 text-center ">
<div class="zh-center">
<div class="zh-ddtit">
<img src="/static/home/images/wxzf.png" style=" height: 24px; margin: 8px auto;"/>
</div>
<div class="zh-topline">
<div class="col-md-6"><span class="zh-dd">{:lang('pay.success_message')}:{$order_sn}</span></div>
<div class="col-md-6"><span class="zh-je">{:lang('pay.payment_amount')}:<em>{$total_fee}</em></span></div>
</div>
<div class="zh-con" style=" margin: 0 auto;">
<div class="col-md-6 text-center " style="padding: 20px 0">
<div style="width: 100%; min-height: 180px;">
{notempty name="url"}
<div style="color:#da8d56; display: inline-block; margin: 0 20px;"><p><img style="height: 40px;" src="/static/home/images/wx.png" alt="" /></p><img class="qrcode" alt="" src="{$url}" style="width:150px;height:150px;"></div>
{/notempty}
{notempty name="aliurl"}
<div style="color:#da8d56; display: inline-block; margin: 0 40px;"><p><img style="height: 45px;" src="/static/home/images/zfb.jpg" alt="" /></p><img class="qrcode" alt="" src="{$aliurl}" style="width:150px;height:150px;"></div>
{/notempty}
</div>
</div>
<div class="col-md-6 text-center zh-sys" style="padding: 20px 0">
<img src="/static/home/images/saoyisao.png" style="width: 200px;"/>
</div>
</div>
</div>
</div>
<!-- footer -->
{include file="public/footer" /}
</body>
<script type="text/javascript">
var interval = setInterval(function(){
$.ajax({
type: "POST",
url: "{:url('pay/pcresult', array('order_sn' => $order_sn))}",//+tab,
dataType: "json",
success: function (data) {
if (data.status==1){
location.href = data.url; // 跳转
}
}
});
}, 1000);
</script>
</html>

111
app/home/view/pay/succ.html Normal file
View File

@@ -0,0 +1,111 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<body class="main cn home home-layout-page" style="background: #f8f8f8;">
<style>
.text-center{
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
}
.text-visa p{
text-align: center;
margin-top: 10px;
font-size: 20px;
color: #880000;
}
.text-center div{
margin: 0 16px;
}
.other{
font-size: 17px;
}
.text-center{
padding: 10px;
}
.success-actions {
display: flex;
justify-content: center;
width: 100%;
margin: 28px 0 10px;
}
.success-primary-btn {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 180px;
height: 46px;
padding: 0 34px;
border-radius: 24px;
background: var(--primary-color) !important;
color: #fff !important;
font-size: 16px;
font-weight: 600;
letter-spacing: 1px;
text-decoration: none;
box-shadow: 0 10px 22px rgba(20, 40, 109, .22);
transition: background .2s ease, box-shadow .2s ease, transform .2s ease;
}
.success-primary-btn:hover,
.success-primary-btn:focus {
background: var(--primary-color) !important;
color: #fff !important;
box-shadow: 0 12px 26px rgba(20, 40, 109, .3);
transform: translateY(-1px);
}
@media screen and (max-width: 768px) {
.text-center{
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
flex-direction: column;
}
.success-actions {
margin: 24px 0 6px;
}
.success-primary-btn {
width: 100%;
max-width: 280px;
}
}
</style>
<div class="content detail-page__menu">
{include file="public/home_menu" /}
</div>
<main>
<div class="container">
<div class="modular-row callout bg-grey">
<div class="container" style="margin-top: 20px">
<div class="row">
<div class="col-md-12 text-left">
<p style="font-size: 20px">eVUS更新:</p>
<p style="font-size: 20px">感谢您的申请:</p>
<p style="font-size: 18px;color: #880000">您的订单已经提交成功,订单号为:{$order_sn}</p>
<p style="font-size: 15px">A.如果您是紧急出行(例如即将登机)需要加急更新,请第一时间联系客服(7*24小时):{$phone},加急申请需要交纳加急费。</p>
<p style="font-size: 15px">
B.通常情况下,你得资料将在1-2个工作日内提交至美国海关和边境保卫局,个别情况下审批结果将在72小时之内做出。届时我们会通过邮件、短信、微信等其中一种方式通知您下载批准文件。如果你的申请被美国海关和边境保护局拒绝,我们会在第一时间内联系您。</p>
<p style="font-size: 15px">
您可通过自助查询方式查询申请状态:
</p>
<p style="font-size: 15px">
自助查询:点击网站首页“eVUS查询”按钮,输入“护照号码”、“签证号码”、“姓氏拼音”、“名字拼音”、“出生日期” 实时查看进度
</p>
<p style="font-size: 15px">
审批完成后,我们也会通过邮件、短信通知您下载批准文件。
</p>
</div>
<div class="col-md-12 success-actions">
<a href="{:url('home/detail/index')}" class="success-primary-btn">EVUS登记</a>
</div>
</div>
</div>
</div>
</div>
</main>
<!-- footer -->
{include file="public/footer" /}

View File

@@ -0,0 +1,123 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<body class="main cn home home-layout-page">
<style>
.safe{
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.safe img{
width: 80px;
}
.zh-center{
max-width: 1140px;
margin: 10px auto 0;
border: 1px solid #ddd;
box-shadow: 0 0 10px rgba(0,0,0,0.2);
overflow: hidden;
padding-bottom: 20px;
}
.zh-center .qrcode{
border: 1px solid #ddd;
margin: 10px 0;
}
.zh-ddtit{
width: 100%;
height: 40px;
background: var(--banner-color);
color: #fff;
}
.zh-ddtit span{
font-size: 14px;
line-height: 40px;
}
.zh-topline{
width: 100%;
text-align: left;
min-height: 40px;
overflow: hidden;
padding-top:8px;
font-size: 14px;
border-bottom: 1px solid #ddd;
}
.zh-dd{
float: left;
}
.zh-je{
float: right;
}
.zh-je em{
font-style: normal;
color: #f00;
font-size: 18px;
}
@media screen and (min-width: 1000px){
.zh-sys{
display: block;
}
}
@media screen and (max-width: 1000px){
.zh-sys{
display: none;
}
}
@media screen and (max-width: 600px){
/*.zh-center{
border: none;
box-shadow: none;
}*/
}
</style>
<div class="content detail-page__menu">
{include file="public/home_menu" /}
</div>
<div class="col-md-12 text-center ">
<div class="zh-center">
<div class="zh-ddtit">
<img src="/static/home/images/wxzf.png" style=" height: 24px; margin: 8px auto;"/>
</div>
<div class="zh-topline">
<div class="col-md-6"><span class="zh-dd">{:lang('pay.success_message')}:{$order_sn}</span></div>
<div class="col-md-6"><span class="zh-je">{:lang('pay.payment_amount')}:<em>{$total_fee}</em></span></div>
</div>
<div class="zh-con" style=" margin: 0 auto;">
<div class="col-md-6 text-center " style="padding: 20px 0">
<div style="width: 100%; min-height: 180px;">
{notempty name="url"}
<div style="color:#da8d56; display: inline-block; margin: 0 20px;"><p><img style="height: 40px;" src="/static/home/images/wx.png" alt="" /></p><img class="qrcode" alt="" src="{$url}" style="width:150px;height:150px;"></div>
{/notempty}
{notempty name="aliurl"}
<div style="color:#da8d56; display: inline-block; margin: 0 40px;"><p><img style="height: 45px;" src="/static/home/images/zfb.jpg" alt="" /></p><img class="qrcode" alt="" src="{$aliurl}" style="width:150px;height:150px;"></div>
{/notempty}
</div>
</div>
<div class="col-md-6 text-center zh-sys" style="padding: 20px 0">
<img src="/static/home/images/saoyisao.png" style="width: 200px;"/>
</div>
</div>
</div>
</div>
<!-- footer -->
{include file="public/footer" /}
</body>
<script type="text/javascript">
var interval = setInterval(function(){
$.ajax({
type: "POST",
url: "{:url('payesta/pcresult', array('order_sn' => $order_sn))}",//+tab,
dataType: "json",
success: function (data) {
if (data.status==1){
location.href = data.url; // 跳转
}
}
});
}, 1000);
</script>
</html>

View File

@@ -0,0 +1,65 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<body class="main cn home home-layout-page" style="background: #f8f8f8;">
<style>
.text-center{
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
}
.text-visa p{
text-align: center;
margin-top: 10px;
font-size: 20px;
color: #880000;
}
.text-center div{
margin: 0 16px;
}
.other{
font-size: 17px;
}
.text-center{
padding: 10px;
}
@media screen and (max-width: 768px) {
.text-center{
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
flex-direction: column;
}
}
</style>
<div class="content detail-page__menu">
{include file="public/home_menu" /}
</div>
<div class="container">
<div class="modular-row callout bg-grey">
<div class="container" style="margin-top: 20px">
<div class="row">
<div class="col-md-12 text-left">
<p style="font-size: 20px">ESTA更新:</p>
<p style="font-size: 20px">感谢您的申请:</p>
<p style="font-size: 18px;color: #880000">您的订单已经提交成功,订单号为:{$order_sn}</p>
<!-- <p ><img src="/static/home/images/euvs.png"></p>-->
<!-- <p style=" text-align: center;">(关注微信,赠送2日旅行意外险)</p>-->
<p style="font-size: 15px">A.如果您是紧急出行(例如即将登机)需要加急更新,请第一时间联系客服(7*24小时):{$phone},加急申请需要交纳加急费。</p>
<p style="font-size: 15px">
B.通常情况下,你得资料将在1-2个工作日内提交至美国海关和边境保卫局,个别情况下审批结果将在72小时之内做出。届时我们会通过邮件、短信、微信等其中一种方式通知您下载批准文件。如果你的申请被美国海关和边境保护局拒绝,我们会在第一时间内联系您。</p>
</div>
<div class="register">
<a href="{:url('home/esta/index')}" class="btn" style="background: #ff8d0e">ESTA登记</a>
</div>
</div>
</div>
</div>
</div>
<!-- footer -->
{include file="public/footer" /}

View File

@@ -0,0 +1,11 @@
<footer class="footer ac-site-footer">
{notempty name="footer"}
{:html_entity_decode($footer)}
{else /}
<p class="ac-footer-disclaimer">免责声明:本网站为专业旅行代理机构,旨在帮助个人和法人申请短期停留所需的旅游文件。服务费包含专家的帮助和协助,以及政府收取的费用,并非附属于政府,申请人亦可选择不使用我们专业的审阅和专家服务。</p>
<p class="ac-footer-company">济南经纬九州出入境服务有限公司</p>
<p><a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer">备案号:鲁ICP备18006241号-8</a></p>
<p>Copyright © 2014-{:date('Y')} All rights reserved</p>
{/notempty}
</footer>
{include file="public/footer_menu" /}

View File

@@ -0,0 +1,5 @@
<div class="evus-foot">
<a class="evus-a" href="{:url('home/detail/index')}">{:lang('menu_apply')}</a>
<a class="evus-a" href="{:url('home/lookup/index')}">{:lang('menu_search')}</a>
<a class="evus-a" href="{:url('home/user/order')}">{:lang('menu_user')}</a>
</div>

View File

@@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="{$seo.lang|default='zh-CN'}" style="height:100%;">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="/static/home/js/jquery.js"></script>
<script src="/static/home/js/pub.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="applicable-device" content="{$seo.applicable_device|default='pc,mobile'}">
<meta name="robots" content="{$seo.robots|default='noindex,follow'}">
<title>{$seo.title}</title>
<meta name="description" content="{$seo.description}">
<meta name="keywords" content="{$seo.keywords}">
{notempty name="seo.canonical"}
<link rel="canonical" href="{$seo.canonical}">
{/notempty}
{notempty name="seo.baidu_site_verification"}
<meta name="baidu-site-verification" content="{$seo.baidu_site_verification}">
{/notempty}
<link rel="icon" type="image/png" href="{$logo_icon|default='/static/home/images/evus-icon.png'}">
<link rel="stylesheet" href="/static/css/self.css?v={$asset_version}">
<link rel="stylesheet" href="/static/home/css/reset.css">
<link rel="stylesheet" href="/static/home/css/style.css?v={$asset_version}">
<link rel="stylesheet" href="/static/ym/detail/main.css?v={$asset_version}">
<link rel="stylesheet" href="/static/layui/css/layui.css?v={$asset_version}" />
<script src="/static/layui/layui.js"></script>
<script src="/static/home/js/jquery-weui.min.js"></script>
<script src="/static/js/passport-ocr-sdk.min.js?v=1"></script>
<script charset="UTF-8" id="LA_COLLECT" src="//sdk.51.la/js-sdk-pro.min.js"></script>
<script>LA.init({id:"3RUd6ZreOhSLFHFI",ck:"3RUd6ZreOhSLFHFI"})</script>
<style>
.agreement-layer {
max-width: calc(100vw - 32px);
border-radius: 10px !important;
overflow: hidden;
}
.agreement-layer .layui-layer-title {
box-sizing: border-box;
height: 48px;
padding: 0 44px 0 22px;
line-height: 48px;
font-weight: 600;
}
.agreement-layer .layui-layer-content {
box-sizing: border-box;
max-height: calc(70vh - 96px);
padding: 18px 22px !important;
overflow-y: auto !important;
-webkit-overflow-scrolling: touch;
line-height: 1.8;
}
.agreement-layer .layui-layer-btn {
padding: 0 16px 16px;
}
@media (max-width: 768px) {
.agreement-layer {
max-width: calc(100vw - 28px);
}
.agreement-layer .layui-layer-title {
height: 44px;
padding: 0 42px 0 16px;
line-height: 44px;
font-size: 16px;
}
.agreement-layer .layui-layer-content {
max-height: calc(76vh - 92px);
padding: 14px 16px !important;
font-size: 14px;
line-height: 1.75;
}
.agreement-layer .layui-layer-btn {
padding: 0 12px 14px;
}
}
</style>
<script>
window.agreementLayerSkin = 'agreement-layer';
window.getAgreementLayerArea = function (hasFooter) {
if (window.innerWidth < 768) {
return ['90%', hasFooter ? '72vh' : '76vh'];
}
return ['720px', hasFooter ? '66vh' : '70vh'];
};
</script>
</head>

View File

@@ -0,0 +1,3 @@
{assign name="ac_legacy_links" value="1" /}
<link rel="stylesheet" href="/static/home/css/inner-acvisa.css?v=20261030-5">
{include file="public/site_nav" /}

View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title>{$msg}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
{include file="public/head" /}
<style>
body { font-family: 'Microsoft YaHei', sans-serif; background: #f7f7f7; margin: 0; padding: 0; }
.container {
max-width: 500px;
margin: 100px auto;
background: #fff;
border-radius: 8px;
padding: 30px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
text-align: center;
}
.message { font-size: 18px; margin-bottom: 20px; }
.success { color: #28a745; }
.error { color: #dc3545; }
.countdown { font-size: 14px; color: #999; margin-top: 10px; }
.btn {
display: inline-block;
padding: 10px 20px;
background: var(--banner-color);
color: white;
border-radius: 4px;
text-decoration: none;
margin-top: 20px;
}
.btn:hover { background: var(--banner-color);color: white }
</style>
<body>
<div class="container">
<div class="message {$type|default='success'}">{$msg}</div>
<div class="countdown">
<span id="countdown">{$wait|default=3}</span> {:lang('jump.auto_redirect')}...
</div>
<a href="{$url ?: 'javascript:history.back();'}" class="btn">{:lang('jump.redirect_now')}</a>
</div>
<script>
// 倒计时显示
let time = {$wait|default=3};
const countdownEl = document.getElementById('countdown');
const targetUrl = "{$url|default=''}";
const timer = setInterval(() => {
time--;
countdownEl.textContent = time;
if (time <= 0) {
clearInterval(timer);
if (targetUrl) {
location.href = targetUrl;
} else {
history.back();
}
}
}, 1000);
</script>
</body>
</html>

View File

@@ -0,0 +1 @@
{include file="public/home_menu" /}

View File

@@ -0,0 +1,50 @@
<div class="float-box">
<div class="float-phone" style="right: -130px;">
<div class="float-icon"><img src="/static/home/images/float_icon2.png" alt="服务电话"></div>
<span class="float-num">{$phone}</span>
</div>
</div>
<script>
$(".float-phone").hover(function(){
$(this).animate({"right":"0"});
},function(){
$(this).animate({"right":"-130px"});
})
</script>
<style>
.float-box {
position: fixed;
right: 0;
top: 40%;
width: auto;
height: 100px;
}
.float-phone {
width: 176px;
position: absolute;
right: -130px;
top: 0;
}
.float-icon {
display: grid;
place-items: center;
float: left;
width: 46px;
height: 48px;
border-bottom-left-radius: 5px;
border-top-left-radius: 5px;
background: rgba(0, 0, 0, 0.8);
}
.float-icon img {
width: 24px;
height: auto;
}
.float-num {
width: 130px;
float: left;
line-height: 48px;
color: #fff;
font-size: 16px;
background: rgba(0, 0, 0, 0.8);
}
</style>

View File

@@ -0,0 +1,46 @@
<link rel="stylesheet" href="/static/home/css/site-shell.css?v=20261030-2">
{php}$ac_section = explode('/', strtolower($menu_url ?? ''))[0];{/php}
<div class="ac-topline"><div class="ac-wrap">EVUS 中文登记服务 <span>独立商业服务平台 · 非美国政府网站</span></div></div>
<header class="ac-header{notempty name="ac_legacy_links"} ac-header-services{/notempty}">
<div class="ac-wrap ac-header-inner">
<a class="ac-brand" href="{:url('home/index/index')}" {eq name="ac_section" value="index"}aria-current="page"{/eq} aria-label="EVUS 中文登记服务首页"><img src="/static/home/images/logo_113.png" alt="eVUS 代理登记服务" width="2385" height="338"></a>
<nav class="ac-nav" aria-label="主导航">
<a href="{:url('home/index/index')}" {eq name="ac_section" value="index"}aria-current="page"{/eq}>首页</a>
<a href="{:url('home/detail/index')}" {eq name="ac_section" value="detail"}aria-current="page"{/eq}>EVUS登记</a>
<a href="{:url('home/lookup/index')}" {eq name="ac_section" value="lookup"}aria-current="page"{/eq}>登记查询</a>
<a href="{:url('home/help/index')}" {eq name="ac_section" value="help"}aria-current="page"{/eq}>帮助中心</a>
<a href="{:url('home/news/index')}" {eq name="ac_section" value="news"}aria-current="page"{/eq}>新闻资讯</a>
<a href="{:url('home/company/index')}" {eq name="ac_section" value="company"}aria-current="page"{/eq}>关于我们</a>
{notempty name="ac_legacy_links"}
<a href="https://visa.evus.cn" target="_blank" rel="noopener noreferrer">{:lang('menu_us_apply')}</a>
<a href="{:url('home/esta/index')}" {eq name="ac_section" value="esta"}aria-current="page"{/eq}>{:lang('menu_esta_apply')}</a>
{/notempty}
</nav>
<a class="ac-account" href="{:url('home/user/order')}" {eq name="ac_section" value="user"}aria-current="page"{/eq}>我的订单 <span aria-hidden="true">↗</span></a>
<details class="ac-mobile-menu">
<summary aria-label="切换导航菜单"><svg class="ac-line-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path class="ac-menu-bars" d="M4 6h16M4 12h16M4 18h16"/><path class="ac-menu-close" d="m6 6 12 12M6 18 18 6"/></svg><span>菜单</span></summary>
<nav aria-label="手机导航">
<a href="{:url('home/index/index')}" {eq name="ac_section" value="index"}aria-current="page"{/eq}>首页</a>
<a href="{:url('home/detail/index')}" {eq name="ac_section" value="detail"}aria-current="page"{/eq}>EVUS登记</a>
<a href="{:url('home/lookup/index')}" {eq name="ac_section" value="lookup"}aria-current="page"{/eq}>登记查询</a>
<a href="{:url('home/help/index')}" {eq name="ac_section" value="help"}aria-current="page"{/eq}>帮助中心</a>
<a href="{:url('home/news/index')}" {eq name="ac_section" value="news"}aria-current="page"{/eq}>新闻资讯</a>
<a href="{:url('home/company/index')}" {eq name="ac_section" value="company"}aria-current="page"{/eq}>关于我们</a>
<a href="{:url('home/user/order')}" {eq name="ac_section" value="user"}aria-current="page"{/eq}>我的订单</a>
{notempty name="ac_legacy_links"}
<a href="https://visa.evus.cn" target="_blank" rel="noopener noreferrer">{:lang('menu_us_apply')}</a>
<a href="{:url('home/esta/index')}" {eq name="ac_section" value="esta"}aria-current="page"{/eq}>{:lang('menu_esta_apply')}</a>
{/notempty}
</nav>
</details>
</div>
</header>
<button class="ac-menu-backdrop" type="button" aria-label="关闭导航菜单" tabindex="-1"></button>
<script id="ac-mobile-menu-dismiss">
const mobileMenu = document.querySelector('.ac-mobile-menu');
document.addEventListener('click', function (event) {
if (mobileMenu.open && !mobileMenu.contains(event.target)) {
mobileMenu.open = false;
}
});
</script>

View File

@@ -0,0 +1,31 @@
<style>
.layui-layer-content{
padding: 10px;
}
@media (max-width: 768px) {
.layui-layer.layui-layer-page{
display: none;
}
}
</style>
<script>
const is_show = sessionStorage.getItem('is_show');
if (!is_show) {
layer.open({
type: 1,
title: false,
closeBtn: 1,
shade: 0,
offset: 'rb',
shadeClose: true,
content: "<p style='font-weight: 600;color: var(--primary-color);'><span style='color:#FF0000;font-weight: 600;'>请注意:</span>本网站为独立运营的商务服务网站,经由相关机构登记和备案后上线,提供有偿代理服务,可享受拍照识别护照信息、中文填写等快速登记服务,但不隶属于任何政府部门。</p>" +
"<p style='font-weight: 600;color: var(--primary-color);'><span style='color:#FF0000;font-weight: 600;'>请注意:</span>美国海关和边境保护局是EVUS的官方机构,现阶段,官方自行登记需信用卡支付30.75美金,且要求使用英文填写。您也可以选择前往官网登记。官方网址https://www.evus.gov/</p>",
cancel: function(){
layer.closeAll();
sessionStorage.setItem('is_show', 1);
}
})
}
</script>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,171 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>EUVS中文网--上传信息</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="/static/ym/logo.png">
<link rel="stylesheet" href="/static/css/weui.min.css">
<link rel="stylesheet" href="/static/css/jquery-weui.min.css">
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
<script src="/static/home/js/jquery.js"></script>
<script src="/static/home/js/ocr-image-compress.js?v=2"></script>
<style>
.weui-cells__title{
color: #0C0C0C;
}
</style>
</head>
<body>
<form id="jbzlform">
<div class="weui-cells__title">有效期为<span style="color: red">10年</span>的美国B1/B2签证</div>
<div class="weui-cells weui-cells_form">
<div class="weui-cell">
<div class="infor-box">
<input type="file" accept="image/*" name="" id="input" onchange="upload(this)"/>
<div class="infor-pic"><img src=""/></div>
<div class="infor-bg">
<div class="infor-icon">+</div>
<div class="infor-pic-tit">上传照片</div>
</div>
<input type="hidden" name="imgs[]" class="fileimgs">
</div>
</div>
</div>
<div class="weui-cells__title">正在使用的护照首页照片(注:有效期需超过6个月)</div>
<div class="weui-cells weui-cells_form">
<div class="weui-cell">
<div class="infor-box">
<input type="file" accept="image/*" name="" onchange="upload(this)"/>
<div class="infor-pic"><img src=""/></div>
<div class="infor-bg">
<div class="infor-icon">+</div>
<div class="infor-pic-tit">上传照片</div>
</div>
<input type="hidden" name="imgs[]" class="fileimgs">
</div>
</div>
</div>
<div class="weui-cells__title">如您的美国签证在旧护照上,请上传“旧护照”首页照片</div>
<div class="weui-cells weui-cells_form">
<div class="weui-cell">
<div class="infor-box">
<input type="file" accept="image/*" name="" onchange="upload(this)"/>
<div class="infor-pic"><img src=""/></div>
<div class="infor-bg">
<div class="infor-icon">+</div>
<div class="infor-pic-tit">上传照片</div>
</div>
<input type="hidden" name="imgs[]" class="fileimgs">
</div>
</div>
</div>
<input type="hidden" name="order_sn" value="{$data.order_sn}">
<div class="weui-cells__tips" style="font-size: 16px"><strong>注明:如果您使用的护照有效期不足6个月, 则暂时无法完成EVUS更新,您可以在申请新护照后再上传“新旧护照”文件;换发新护照时,务必携带旧护照交由出入境管理局“剪角”,领取新护照后再上传本链接照片,你的EVUS申请届时将会自动提交处理</strong></div>
<a href="javascript:;" class="weui-btn weui-btn_primary" style="margin-top: 10px">提 交</a>
</form>
</body>
<script src="/static/js/jquery-weui.min.js"></script>
<script>
async function upload(_this) {
var file = _this.files[0];
if (!file) {
return false;
}
if (!/image\/\w+/.test(file.type)) {
$.toast("文件必须为图片");
return false;
}
if (!window.FileReader) {
$.toast("你的浏览器不支持上传");
return false;
}
const reader = new FileReader()
//readAsDataURL()方法:读取文件内容,结果用data:url的字符串形式表示
reader.readAsDataURL(file) // input.files[0]为第一个文件
// 读取成功回调
reader.onload = ()=>{
// 追加节点
$(_this).next("div").find("img").attr('src', reader.result).css("opacity", "1");
}
$.showLoading('上传中');
try {
var compressedFile = window.OcrImageCompressor
? await window.OcrImageCompressor.prepare(file)
: file;
if (!compressedFile) {
$.hideLoading();
$.toast('请重新上传');
return false;
}
var formData = new FormData();
formData.append('file', compressedFile, compressedFile.name || file.name || 'upload.jpg');
$.ajax({
url: "/home/upload/upload_file",
type: "post",
data: formData,
dataType: "json",
contentType: false,
processData: false,
mimeType: "multipart/form-data",
success: function (data) {
$.hideLoading();
if (data.code == 1 && data.path) {
$(_this).parent().find('.fileimgs').val(data.path);
}else{
$.toast(data.msg);
}
},
error: function () {
$.hideLoading();
$.toast('请重新上传');
}
});
} catch (e) {
$.hideLoading();
$.toast('请重新上传');
}
}
</script>
<script type="text/javascript">
$('.weui-btn_primary').click(function () {
var _this = $(this);
$(_this).addClass('weui-btn_disabled');
$.ajax({
type: "POST",
url: "{:url('doapply')}",
data: $('#jbzlform').serialize(),
dataType: 'json',
success: function (result) {
console.log(result);
if (result.code == 1) {
$.toast("操作成功");
setTimeout(function () {
window.location.href = result.url;
}, 1000);
} else {
$(_this).removeClass('weui-btn_disabled');
$.toast(result.msg);
}
}
});
});
</script>
</html>

View File

@@ -0,0 +1,355 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<link rel="stylesheet" href="/static/home/css/user.css?v=5">
<body class="home-layout-page user-center-page">
<style type="text/css">
.item_desc span {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.productItem-text a{
color: #ffffff;
font-size: 14px;
}
.form-btn{
display: block;
width: 100%;
height: 50px;
text-align: center;
line-height: 50px;
color: #fff;
font-size: 18px;
background: var(--banner-color);
margin: 15px 0;
border-radius: 8px;
border-radius: 2px solid var(--banner-color);
}
.form-btn:hover{
background: var(--banner-color);
}
.checkbox-inline input[type="checkbox"]:checked:after{
top: 7px;
}
@media(min-width:992px) {
.content select{
min-width: 120px !important;
}
}
.input-group{
width: 80%;
}
.djtable table{
width: 100%;
border-collapse: collapse;
border: 2px solid var(--banner-color);
}
.djtable th,.djtable td{
text-align: center;
border: 1px solid var(--banner-color);
height: 40px;
font-size: 14px;
}
.djtable th{
color: #fff;
background: var(--banner-color);
}
.djtable td{
color: #333;
}
.djtable2 table{
width: 100%;
text-align: center;
line-height: 36px;
font-size: 14px;
}
.djtable2 tr{
border-bottom: 1px solid #eee;
}
.djtable2 th{
text-align: center;
}
.djtable2 td{
color: #666;
text-align: center;
}
.formrow{
width: 100%;
overflow: hidden;
}
.m-help ul{
padding: 0 !important;
}
</style>
<style>
.djtable table{
width: 100%;
border-collapse: collapse;
border: 2px solid var(--banner-color);
}
.djtable th,.djtable td{
text-align: center;
border: 1px solid var(--banner-color);
height: 40px;
font-size: 14px;
}
.djtable th{
color: #fff;
background: var(--banner-color);
}
.djtable td{
color: #333;
}
.djtable2 table{
width: 100%;
text-align: center;
line-height: 36px;
font-size: 14px;
}
.djtable2 tr{
border-bottom: 1px solid #eee;
}
.djtable2 th{
text-align: center;
}
.djtable2 td{
color: #666;
text-align: center;
}
.formrow{
width: 100%;
overflow: hidden;
margin-bottom: 10px;
}
.input-button{
width: 40%;
margin: 0 auto;
}
.m-help ul{
padding: 0 !important;
}
.btn-primary:hover{
background: var(--banner-color) !important;
}
.modal-open .modal .modal-dialog.modal-txt{
max-height: 550px;
overflow-y: auto;
}
.input-group input:first-child[type=text]{
padding: 1rem;
}
.nodata a {
width: 30%;
height: 40px;
margin: 10px;
line-height: 40px;
display: inline-block;
border-radius: 4px;
background: var(--banner-color);
color: #fff;
text-align: center;
}
</style>
<div class="u-bg-greylight">
<div class="content">
{include file="public/home_menu" /}
<div class="container">
<div class="usercon">
<div class="user-l">
<div class="user-tit">{:lang('menu_user')}</div>
<a href="{:url('user/order')}" class="user-a">evus订单</a>
<a href="{:url('user/orderEsta')}" class="user-a">esta订单</a>
<a href="{:url('user/invoice')}" class="user-a user-on">{:lang('user_invoice')}</a>
<a href="{:url('user/multiple')}" class="user-a">{:lang('user_multiple_invoice')}</a>
<a href="{:url('user/logout')}" class="user-a">{:lang('user_logout')}</a>
</div>
<div class="user-r">
<form id="lookupform" name="form1">
<p style="color: #951e14;margin-top: 16px;text-align: center; font-size: 16px;">适用单个订单开票,如果有多个订单请点击合并开票</p>
<div class="m-form-application-container col-sm-12 u-pad--t0">
<section class="m-form-application-category-container active">
<div class="m-form-application-inputs-container">
<div class="formrow">
<div id="form-passport_number" class=" j-form-container col-sm-6">
<div class="col-xs-12 col-sm-12">
<label for="passport_number">
护照号码 <span class="m-txt--color-15">*</span> </label>
</div>
<div class="col-xs-12 col-sm-12">
<div class="input-group">
<input type="text" id="passport_number" name="passport_number" class=""
maxlength="9" minlength="9" required=""
placeholder="输入护照号码">
</div>
</div>
</div>
<div id="form-visa_foil_number" class=" j-form-container col-sm-6">
<div class="col-xs-12 col-sm-12">
<label for="order_sn">
订单号 <span class="m-txt--color-15">*</span> </label>
</div>
<div class="col-xs-12 col-sm-12">
<div class="input-group">
<input type="text" id="order_sn" name="order_sn" class=""
required=""
placeholder="输入订单号">
</div>
</div>
</div>
</div>
<div class="formrow">
<div id="form-last_name" class=" j-form-container col-sm-6">
<div class="col-xs-12 col-sm-12">
<label for="last_name">
姓氏 <span class="m-txt--color-15">*</span> </label>
</div>
<div class="col-xs-12 col-sm-12">
<div class="input-group">
<input type="text" id="last_name" name="last_name" class="" maxlength="45"
required=""
placeholder="填写姓氏拼音" pattern="[A-z]*" >
</div>
</div>
<div class="clearfix"></div>
</div>
<div id="form-first_name" class=" j-form-container col-sm-6">
<div class="col-xs-12 col-sm-12">
<label for="first_name">
名字 <span class="m-txt--color-15">*</span> </label>
</div>
<div class="col-xs-12 col-sm-12">
<div class="input-group">
<input type="text" id="first_name" name="first_name" class="" maxlength="40"
required=""
placeholder="填写名字拼音" pattern="[A-z]*">
</div>
</div>
<div class="clearfix"></div>
</div>
</div>
<div class="input-group input-button" style="display: block; padding-right: 44px;">
<input class="form-btn" type="button" value="提交" />
</div>
</div>
</section>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{include file="public/footer" /}
<style type="text/css">
@media(max-width:700px) {
body{ padding: 0;}
.user-xx li span{ min-width: 30% !important; width: auto !important;}
.user-tit2{ display: none;}
.user-l{
width: 100%;
min-height:unset;
display: flex;
}
.user-a{
width: 50%;
}
.user-tit{
display: none;
}
.user-xx li{ width: 100%;}
.user-xx li:nth-child(even){
background: #fff !important;
}
.user-xx li:nth-child(odd){
background: #eee !important;
}
.usercon{
flex-direction: column;
}
.container{
box-sizing: border-box;
}
.user-r{
margin-bottom: 10px;
}
.input-group{
width: 100%;
}
.input-group.input-button{
width: 50%;
padding-right:unset !important;
}
}
@media(min-width:700px) {
.user-xx li span{ min-width: 30% !important; width: auto !important;}
.user-xx li{ width: 50%;float: left;}
.user-xx li a{ float: left; margin: 6px 15px 6px 0;}
}
</style>
<script>
$(".form-btn").click(function(){
if ($("#passport_number").val()==""){
layer.msg('请输入护照号')
return false
}
if ($("#order_sn").val()==""){
layer.msg('请输入订单号')
return false
}
if ($("#last_name").val()==""){
layer.msg('请输入姓氏')
return false
}
if ($("#first_name").val()==""){
layer.msg('请输入名字')
return false
}
var index1;
$.ajax({
type : "POST",
url : "checkInvoice",
data: $('#lookupform').serialize(),
beforeSend: function () {
index1 = layer.load(1, {
shade: [0.3,'#fff'] //0.1透明度的白色背景
});
},
success : function (data) {
layer.close(index1);
if(data.status==1){
layer.msg('查询成功');
window.location.href= data.url;
}else{
layer.msg(data.msg);
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,509 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/css/weui.min.css">
<link rel="stylesheet" href="/static/css/jquery-weui.min.css">
<script type="text/javascript" src="/static/js/jquery-weui.min.js"></script>
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<link rel="stylesheet" href="/static/home/css/user.css?v=5">
<link rel="stylesheet" href="/visa/css/layui.css">
<script src="/static/home/js/layer/layer.js"></script>
<body class="home-layout-page user-center-page">
<style type="text/css">
.item_desc span {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.productItem-text a {
color: #ffffff;
font-size: 14px;
}
.form-btn {
display: block;
width: 100%;
height: 50px;
text-align: center;
line-height: 50px;
color: #fff;
font-size: 18px;
background: var(--banner-color);
margin: 15px 0;
border-radius: 8px;
border-radius: 2px solid var(--banner-color);
}
.form-btn:hover {
background: var(--banner-color);
}
.checkbox-inline input[type="checkbox"]:checked:after {
top: 7px;
}
@media (min-width: 992px) {
.content select {
min-width: 120px !important;
}
}
.input-group {
width: 80%;
}
.djtable table {
width: 100%;
border-collapse: collapse;
border: 2px solid var(--banner-color);
}
.djtable th, .djtable td {
text-align: center;
border: 1px solid var(--banner-color);
height: 40px;
font-size: 14px;
}
.djtable th {
color: #fff;
background: var(--banner-color);
}
.djtable td {
color: #333;
}
.djtable2 table {
width: 100%;
text-align: center;
line-height: 36px;
font-size: 14px;
}
.djtable2 tr {
border-bottom: 1px solid #eee;
}
.djtable2 th {
text-align: center;
}
.djtable2 td {
color: #666;
text-align: center;
}
.formrow {
width: 100%;
overflow: hidden;
}
.m-help ul {
padding: 0 !important;
}
</style>
<style>
.djtable table {
width: 100%;
border-collapse: collapse;
border: 2px solid var(--banner-color);
}
.djtable th, .djtable td {
text-align: center;
border: 1px solid var(--banner-color);
height: 40px;
font-size: 14px;
}
.djtable th {
color: #fff;
background: var(--banner-color);
}
.djtable td {
color: #333;
}
.djtable2 table {
width: 100%;
text-align: center;
line-height: 36px;
font-size: 14px;
}
.djtable2 tr {
border-bottom: 1px solid #eee;
}
.djtable2 th {
text-align: center;
}
.djtable2 td {
color: #666;
text-align: center;
}
.formrow {
width: 100%;
overflow: hidden;
margin-bottom: 10px;
}
.input-button {
width: 40%;
margin: 0 auto;
}
.m-help ul {
padding: 0 !important;
}
.btn-primary:hover {
background: #337ab7 !important;
}
.modal-open .modal .modal-dialog.modal-txt {
max-height: 550px;
overflow-y: auto;
}
.input-group input:first-child[type=text] {
padding: .8rem;
}
.nodata a {
width: 30%;
height: 40px;
margin: 10px;
line-height: 40px;
display: inline-block;
border-radius: 4px;
background: var(--banner-color);
color: #fff;
text-align: center;
}
</style>
<style>
.addBox {
width: 90%;
text-align: right;
margin-top: 5px;
}
.addBox .layui-icon {
font-size: 14px;
color: #666;
cursor: pointer;
margin-left: 10px;
}
.layui-icon-add-circle:before {
content: "\e61f";
}
</style>
<div class="u-bg-greylight">
<div class="content">
{include file="public/home_menu" /}
<div class="container">
<div class="usercon">
<div class="user-l">
<div class="user-tit">{:lang('menu_user')}</div>
<a href="{:url('user/order')}" class="user-a">evus订单</a>
<a href="{:url('user/orderEsta')}" class="user-a">esta订单</a>
<a href="{:url('user/invoice')}" class="user-a">{:lang('user_invoice')}</a>
<a href="{:url('user/multiple')}" class="user-a user-on">{:lang('user_multiple_invoice')}</a>
<a href="{:url('user/logout')}" class="user-a">{:lang('user_logout')}</a>
</div>
<div class="user-r">
<form id="lookupform" name="form1">
<p style="color: #951e14;margin-top: 16px;text-align: center; font-size: 16px;">
适用于多个订单合并开票,如果只有单个订单请点击自助开票</p>
<div class="m-form-application-container col-sm-12 u-pad--t0">
<div class="formrow" style="margin-top: 16px; font-size: 16px;">
<div id="form-type" class=" j-form-container col-sm-6">
<div class="col-xs-12 col-sm-12">
<label for="type">
类型 <span class="m-txt--color-15">*</span> </label>
</div>
<div class="col-xs-12 col-sm-12">
<div class="input-group">
<select class=" select-countries" name="type" id="type" autocomplete="off"
required="">
<option value="evus">EVUS</option>
<option value="esta">ESTA</option>
</select>
</div>
</div>
</div>
</div>
<section class="m-form-application-category-container active">
<div class="m-form-application-inputs-container">
<div class="formrow">
<div class=" j-form-container col-sm-6">
<div class="col-xs-12 col-sm-12">
<label>
护照号码 <span class="m-txt--color-15">*</span> </label>
</div>
<div class="col-xs-12 col-sm-12">
<div class="input-group">
<input type="text" name="passport_number" class=""
maxlength="9" minlength="9" required=""
placeholder="输入护照号码">
</div>
</div>
</div>
<div class=" j-form-container col-sm-6">
<div class="col-xs-12 col-sm-12">
<label>
订单号 <span class="m-txt--color-15">*</span> </label>
</div>
<div class="col-xs-12 col-sm-12">
<div class="input-group">
<input type="text" name="order_sn" class=""
required="" placeholder="输入订单号">
</div>
</div>
</div>
</div>
<div class="formrow">
<div class=" j-form-container col-sm-6">
<div class="col-xs-12 col-sm-12">
<label>
姓氏 <span class="m-txt--color-15">*</span> </label>
</div>
<div class="col-xs-12 col-sm-12">
<div class="input-group">
<input type="text" name="last_name" class="" maxlength="45"
required="" placeholder="填写姓氏拼音" pattern="[A-z]*">
</div>
</div>
<div class="clearfix"></div>
</div>
<div class=" j-form-container col-sm-6">
<div class="col-xs-12 col-sm-12">
<label>
名字 <span class="m-txt--color-15">*</span> </label>
</div>
<div class="col-xs-12 col-sm-12">
<div class="input-group">
<input type="text" name="first_name" class="" maxlength="40"
required="" placeholder="填写名字拼音" pattern="[A-z]*">
</div>
</div>
<div class="clearfix"></div>
</div>
</div>
<div class="addBox">
<span class="layui-icon layui-icon-add-circle layui-add layui-add-tous">添加</span>
<span class="layui-icon layui-icon-reduce-circle layui-reduce">删除</span>
</div>
</div>
</section>
<div class="input-group input-button" style="display: block; padding-right: 44px;">
<input class="form-btn" type="button" value="提交"/>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{include file="public/footer" /}
<style type="text/css">
@media (max-width: 700px) {
body {
padding: 0;
}
.user-xx li span {
min-width: 30% !important;
width: auto !important;
}
.user-tit2 {
display: none;
}
.user-l {
width: 100%;
min-height: unset;
display: flex;
}
.user-a {
width: 50%;
}
.user-tit {
display: none;
}
.user-xx li {
width: 100%;
}
.user-xx li:nth-child(even) {
background: #fff !important;
}
.user-xx li:nth-child(odd) {
background: #eee !important;
}
.usercon {
flex-direction: column;
}
.container {
box-sizing: border-box;
}
.user-r {
margin-bottom: 10px;
}
.input-group {
width: 100%;
margin-bottom: 16px;
}
.input-group.input-button {
width: 50%;
padding-right: unset !important;
}
.input-group input:first-child[type=text] {
padding: 1rem;
}
}
@media (min-width: 700px) {
.user-xx li span {
min-width: 30% !important;
width: auto !important;
}
.user-xx li {
width: 50%;
float: left;
}
.user-xx li a {
float: left;
margin: 6px 15px 6px 0;
}
}
</style>
<script>
var formersHtml = $(".m-form-application-category-container").html();
$('.m-form-application-inputs-container').eq(0).find('.layui-reduce').hide()
$(document).on("click", ".layui-add", function () {
var passport_number = $(this).parent('.addBox').parent().find("input[name='passport_number']").val();
var order_sn = $(this).parent('.addBox').parent().find("input[name='order_sn']").val();
var last_name = $(this).parent('.addBox').parent().find("input[name='last_name']").val();
var first_name = $(this).parent('.addBox').parent().find("input[name='first_name']").val();
var is_check = check(passport_number, order_sn, last_name, first_name);
if (is_check == false) {
return false;
}
$(".m-form-application-category-container").append(formersHtml)
})
$(document).on("click", ".layui-reduce", function () {
$(this).parent('.addBox').parent().remove()
})
</script>
<script>
var datas = [];
$(".form-btn").click(function () {
datas = [];
$('.m-form-application-inputs-container').each(function (i, v) {
var passport_number = $(v).find("input[name='passport_number']").val();
var order_sn = $(v).find("input[name='order_sn']").val();
var last_name = $(v).find("input[name='last_name']").val();
var first_name = $(v).find("input[name='first_name']").val();
datas.push({
passport_number: passport_number,
order_sn: order_sn,
last_name: last_name,
first_name: first_name
})
});
var index1;
var type = $('#type').val()
$.ajax({
type: "POST",
url: "checkMultiple",
data: {datas: JSON.stringify(datas), type: type},
beforeSend: function () {
index1 = layer.load(1, {
shade: [0.3, '#fff'] //0.1透明度的白色背景
});
},
success: function (data) {
layer.close(index1);
if (data.status == 1) {
layer.msg('查询成功');
window.location.href = data.url;
} else {
layer.msg(data.msg);
}
}
});
});
function check(passport_number, order_sn, last_name, first_name) {
if (passport_number == "") {
layer.msg('请输入护照号')
return false
}
if (order_sn == "") {
layer.msg('请输入订单号')
return false
}
if (last_name == "") {
layer.msg('请输入姓氏')
return false
}
if (first_name == "") {
layer.msg('请输入名字')
return false
}
var res = false;
$.ajax({
type: "POST",
url: "checkInvoice",
async: false,
data: {passport_number: passport_number, order_sn: order_sn, last_name: last_name, first_name: first_name},
success: function (data) {
if (data.status == 1) {
res = true;
} else {
res = false;
layer.msg(data.msg);
}
}
});
return res;
}
</script>
</body>
</html>

View File

@@ -0,0 +1,367 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<link rel="stylesheet" href="/static/home/css/user.css?v=5">
<body class="home-layout-page user-center-page">
<style>
.add{
float: right;
padding: 0 25px;
line-height: 34px;
margin: 10px 3% 0 0;
display: inline-block;
border-radius: 4px;
background: var(--banner-color);
color: #fff;
text-align: center
}
.cont2,.cont3,.cont4,.cont5{
display: none;
}
/*@media(min-width:992px) {
.djtable{
display: block;
}
.djtable2{
display: none;
}
}
@media(max-width:992px) {
.djtable{
display: none;
}
.djtable2{
display: block;
}
}*/
.djtable{
display: none;
}
.djtable2{
display: block;
}
.container-tit{
width: 100%;
font-size: 20px;
color: var(--banner-color);
line-height: 50px;
}
.container-con{
width: 100%;
line-height: 24px;
margin-bottom: 10px;
font-size: 14px;
}
.djtable{
width: 100%;
}
.djtable table{
width: 100%;
border-collapse: collapse;
border: 2px solid var(--banner-color);
}
.djtable th,.djtable td{
text-align: center;
border: 1px solid var(--banner-color);
height: 40px;
font-size: 14px;
}
.djtable th{
color: #fff;
background: var(--banner-color);
}
.djtable td{
color: #333;
}
.djtable2 table{
width: 100%;
text-align: center;
line-height: 36px;
font-size: 14px;
}
.djtable2 tr{
border-bottom: 1px solid #eee;
}
.djtable2 th{
text-align: center;
}
.djtable2 td{
color: #666;
text-align: center;
}
.formrow{
width: 100%;
overflow: hidden;
}
.m-help ul{
padding: 0 !important;
}
.btn-primary:hover{
background: #337ab7 !important;
}
.modal-open .modal .modal-dialog.modal-txt{
max-height: 550px;
overflow-y: auto;
}
.nodata {
width: 100%;
text-align:center;
padding: 20px 0px;
margin:0 auto;
}
.nodata a {
width: 30%;
height: 40px;
margin: 10px;
line-height: 40px;
display: inline-block;
border-radius: 4px;
background: var(--banner-color);
color: #fff;
text-align: center;
}
.bac-color{
background: #FFFFFF;
}
@media (max-width: 700px) {
.user-l {
width: 100%;
min-height: unset;
display: flex;
}
.user-tit{
display: none;
}
}
</style>
<div class="u-bg-greylight">
<div class="content">
{include file="public/home_menu" /}
<div class="container">
<div class="usercon">
<div class="user-l">
<div class="user-tit">{:lang('menu_user')}</div>
<a href="{:url('user/order')}" class="user-a user-on">evus订单</a>
<a href="{:url('user/orderEsta')}" class="user-a">esta订单</a>
<a href="{:url('user/invoice')}" class="user-a">{:lang('user_invoice')}</a>
<a href="{:url('user/multiple')}" class="user-a">{:lang('user_multiple_invoice')}</a>
<a href="{:url('user/logout')}" class="user-a">{:lang('user_logout')}</a>
</div>
<div class="user-r">
<div class="user-tit user-tit2">evus订单</div>
<div class="user-c">
<div class="dd-type">
<a href="{:url('home/user/order',array('paystatus'=>'pay'))}">
<span {eq name="paystauts" value="pay"} class="dd-type-on" {/eq}>{:lang('order_paid')}</span>
</a>
<a href="{:url('home/user/order',array('paystatus'=>'nopay'))}">
<span {eq name="paystauts" value="nopay"} class="dd-type-on" {/eq}>{:lang('order_unpaid')}</span>
</a>
</div>
{empty name="data"}
<div class="nodata">
<a href="{:url('home/detail/index')}">
去登记
</a>
<a href="{:url('home/lookup/index')}">
查询
</a>
</div>
{/empty}
<div class="xx-con xx-con1">
{volist name="data" id="vo"}
<ul class="user-xx">
<li class="user-actions">
{eq name="vo['order_status']" value="3"}
<a href="{:url('home/update/upevus',array('id'=>$vo['base_id']))}">去修改</a>
{/eq}
{eq name="vo['pay_status']" value="0"}
<a href="{:url('home/user/pay',array('order_sn'=>$vo['order_sn']))}">去支付</a>
<a href="{:url('home/update/upevus',array('id'=>$vo['base_id']))}">去修改</a>
{else/}
<a href="{:url('home/update/upevus',array('id'=>$vo['base_id']))}" target="_blank">一键更新</a>
{/eq}
</li>
<li style="background: #eee;"><span>订单号:</span><span>{$vo.order_sn}</span></li>
<li style="background: #fff;"><span>姓名:</span><span>{$vo.last_name} {$vo.first_name}</span></li>
<li> <span>出生日期:</span><span>{$vo.birth_date_month}/{$vo.birth_date_day}/{$vo.birth_date_year}</span></li>
<li><span>护照号:</span><span>{$vo.passport_number}</span></li>
<li style="background: #eee;"> <span>签证号:</span><span>{$vo.visa_foil_number}</span></li>
<li style="background: #fff;"><span>手机号:</span><span>{$vo.phone}</span></li>
<li><span>下单时间:</span><span>{$vo.reg_time}</span></li>
<li style="background: #eee;"> <span>订单状态:</span><span>{$vo.order_text}</span></li>
{eq name="vo['pay_status']" value="1"}
<li style="background: #eee;" class="last-li">
{eq name="vo['invoice']" value="0"}
<a href="{:url('home/invoice/index',array('order_sn'=>$vo['order_sn']))}">开发票</a>
{/eq}
{eq name="vo['invoice_download']" value="1"}
<a href="{$invoice_url}{$vo['order_sn']}.pdf" target="_blank">下载发票</a>
{/eq}
</li>
{/eq}
</ul>
{/volist}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="djAlert" tabindex="-1" role="dialog"
aria-labelledby="modalTermsAlert">
<div class="modal-dialog modal-txt" role="document" style="height: auto;">
<div class="modal-content" style="height: auto; ">
<div class="modal-header">
<button type="button" class="close" aria-label="关闭"><span
aria-hidden="true">×</span></button>
<h2 class="modal-title" id="myModalLabel" style="font-size: 20px;">登记查询结果</h2>
</div>
<div class="modal-body alert" id="djjg">
<p style="font-size: 22px; line-height: 40px; color: var(--primary-color); font-weight: bold;"></p>
<div class="cont cont5">
<div class="djtable">
<table>
<tr>
<th>姓名</th>
<th>出生日期</th>
<th>登记申请号码</th>
<th>护照号码</th>
<th>B1/B2签证的签证号码</th>
<th>状态</th>
<th>到期</th>
</tr>
<tr>
<td class="tb2_1"></td>
<td class="tb2_2"></td>
<td class="tb2_3"></td>
<td class="tb2_4"></td>
<td class="tb2_5"></td>
<td class="tb2_6"></td>
<td class="tb2_7"></td>
</tr>
</table>
</div>
<div class="djtable2">
<table>
<tr>
<th>姓名</th><td class="tb2_1"></td>
</tr>
<tr>
<th>出生日期</th><td class="tb2_2"></td>
</tr>
<tr>
<th>登记申请号码</th><td class="tb2_3"></td>
</tr>
<tr>
<th>护照号码</th><td class="tb2_4"></td>
</tr>
<tr>
<th>B1/B2签证的签证号码</th><td class="tb2_5"></td>
</tr>
<tr>
<th>状态</th><td class="tb2_6"></td>
</tr>
<tr>
<th>到期</th><td class="tb2_7"></td>
</tr>
</table>
</div>
</div>
<div class="cont cont2" style="margin-top: 20px;">
<div class="container-con">
“已登记”的EVUS状态意味着EVUS的要求得到了满足得以前往美国 1)从登记批准之日起两年内有效期,或 2),直到主要的护照到期(“主要的护照”是用于登记的护照是有效的,并在登记申请时尚未过期)或 3),直到签证过期,以先到者为准。这样并不保证入境美国。美国联邦Customs and Border Protection 的官员在美国的入境口岸将做最终决定。
</div>
<div class="container-con">
要进入您的EVUS登记申请,会要求您提供您的登记申请号码,护照号码,签证号码和出生日期。如果有必要,您可以更新一份成功的登记内以下信息:1)在美地址和 2)电子邮件地址。如果您需要更改或更新表格上的任何其他信息,您必须申请新的旅行授权。
</div>
<div class="container-con">
您已成功提交了以下所列的登记申请。为您的个人记录,请印列此页。
</div>
</div>
<div class="cont cont3" style="margin-top: 20px;">
<div class="container-con">
您的信息正在登记中,请耐心等候!
</div>
</div>
<div class="cont cont4" style="margin-top: 20px;">
<div class="container-con">
您的EVUS登记不成功,并且您目前没有得到授权前往美国。
</div>
<div class="container-con">
EVUS登记申请失败的常见原因包括:您没有完成所有必填的资料; 您没有提供正确的信息; 您没有用有效的护照或美国签证申请登记,或者其他原因。
</div>
<div class="container-con">
如需帮助,请拨打EVUS帮助中心400-0878-958 。帮助中心每天24小時,每周7天提供,以帮助您与您的EVUS招生。
</div>
<div class="container-con">
您已成功提交了以下所列的登记申请。为您的个人记录,请印列此页。
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default">好的</button>
</div>
</div>
</div>
</div>
<script>
function openDjAlert() {
var width = $(window).width() > 700 ? '900px' : '92%';
var contentHtml = $("#djjg").html();
layer.open({
type: 1,
title: $("#djAlert .modal-title").text() || false,
area: width,
content: '<div style="padding:20px 24px;max-height:70vh;overflow-y:auto;box-sizing:border-box;">' + contentHtml + '</div>'
});
}
</script>
{include file="public/footer" /}
<style type="text/css">
@media(max-width:700px) {
body{ padding: 0;}
.user-xx li span{ min-width: 30% !important; width: auto !important;}
.user-tit2{ display: none;}
.user-l{
width: 100%;
min-height:unset;
display: flex;
}
.user-a{
width: 50%;
}
.user-tit{
display: none;
}
.user-xx li{ width: 100%;}
.user-xx li:nth-child(even){
background: #fff !important;
}
.user-xx li:nth-child(odd){
background: #eee !important;
}
.usercon{
flex-direction: column;
}
.container{
box-sizing: border-box;
}
.user-r{
margin-bottom: 10px;
}
}
@media(min-width:700px) {
.user-xx li span{ min-width: 30% !important; width: auto !important;}
.user-xx li{ width: 50%;float: left;}
.user-xx li a{ float: left; margin: 6px 15px 6px 0;}
}
</style>
</body>
</html>

View File

@@ -0,0 +1,217 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4">
<link rel="stylesheet" href="/static/home/css/user.css?v=5">
<body class="home-layout-page user-center-page">
<style>
.add{
float: right;
padding: 0 25px;
line-height: 34px;
margin: 10px 3% 0 0;
display: inline-block;
border-radius: 4px;
background: var(--banner-color);
color: #fff;
text-align: center
}
.cont2,.cont3,.cont4,.cont5{
display: none;
}
/*@media(min-width:992px) {
.djtable{
display: block;
}
.djtable2{
display: none;
}
}
@media(max-width:992px) {
.djtable{
display: none;
}
.djtable2{
display: block;
}
}*/
.djtable{
display: none;
}
.djtable2{
display: block;
}
.container-tit{
width: 100%;
font-size: 20px;
color: var(--banner-color);
line-height: 50px;
}
.container-con{
width: 100%;
line-height: 24px;
margin-bottom: 10px;
font-size: 14px;
}
.djtable{
width: 100%;
}
.djtable table{
width: 100%;
border-collapse: collapse;
border: 2px solid var(--banner-color);
}
.djtable th,.djtable td{
text-align: center;
border: 1px solid var(--banner-color);
height: 40px;
font-size: 14px;
}
.djtable th{
color: #fff;
background: var(--banner-color);
}
.djtable td{
color: #333;
}
.djtable2 table{
width: 100%;
text-align: center;
line-height: 36px;
font-size: 14px;
}
.djtable2 tr{
border-bottom: 1px solid #eee;
}
.djtable2 th{
text-align: center;
}
.djtable2 td{
color: #666;
text-align: center;
}
.formrow{
width: 100%;
overflow: hidden;
}
.m-help ul{
padding: 0 !important;
}
.btn-primary:hover{
background: #337ab7 !important;
}
.modal-open .modal .modal-dialog.modal-txt{
max-height: 550px;
overflow-y: auto;
}
.nodata {
width: 100%;
text-align:center;
padding: 20px 0px;
margin:0 auto;
}
.nodata a {
width: 30%;
height: 40px;
margin: 10px;
line-height: 40px;
display: inline-block;
border-radius: 4px;
background: var(--banner-color);
color: #fff;
text-align: center;
}
.bac-color{
background: #FFFFFF;
}
@media (max-width: 700px) {
.user-l {
width: 100%;
min-height: unset;
display: flex;
}
.user-tit{
display: none;
}
}
</style>
<div class="u-bg-greylight">
<div class="content">
{include file="public/home_menu" /}
<div class="container">
<div class="usercon">
<div class="user-l">
<div class="user-tit">{:lang('menu_user')}</div>
<a href="{:url('user/order')}" class="user-a">evus订单</a>
<a href="{:url('user/orderEsta')}" class="user-a user-on">esta订单</a>
<a href="{:url('user/invoice')}" class="user-a">{:lang('user_invoice')}</a>
<a href="{:url('user/multiple')}" class="user-a">{:lang('user_multiple_invoice')}</a>
<a href="{:url('user/logout')}" class="user-a">{:lang('user_logout')}</a>
</div>
<div class="user-r">
<div class="user-tit user-tit2">esta订单</div>
<div class="user-c">
<div class="dd-type">
<a href="{:url('home/user/orderEsta',array('paystatus'=>'pay'))}">
<span {eq name="paystauts" value="pay"} class="dd-type-on" {/eq}>{:lang('order_paid')}</span>
</a>
<a href="{:url('home/user/orderEsta',array('paystatus'=>'nopay'))}">
<span {eq name="paystauts" value="nopay"} class="dd-type-on" {/eq}>{:lang('order_unpaid')}</span>
</a>
</div>
{empty name="data"}
<div class="nodata">
<a href="{:url('home/esta/index')}">
去登记
</a>
</div>
{/empty}
<div class="xx-con xx-con1">
{volist name="data" id="vo"}
<ul class="user-xx">
<li class="bac-color"><span>订单号:</span><span>{$vo.order_sn}</span></li>
<li class="bac-color"><span>姓名:</span><span>{$vo.last_name} {$vo.first_name}</span></li>
<li class="bac-color"> <span>出生日期:</span><span>{$vo.birth_date}</span></li>
<li class="bac-color"><span>护照号:</span><span>{$vo.passport_number}</span></li>
<li class="bac-color"><span>手机号:</span><span>{$vo.phone}</span></li>
<li class="bac-color"><span>下单时间:</span><span>{$vo.reg_time}</span></li>
<li style="background: #eee;"> <span>状态:</span><span>{$vo.order_text}</span></li>
</ul>
{/volist}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{include file="public/footer" /}
<style type="text/css">
@media(max-width:700px) {
body{ padding: 0;}
.user-xx li span{ min-width: 30% !important; width: auto !important;}
.user-tit2{ display: none;}
.user-xx li{ width: 100%;}
.user-xx li:nth-child(even){
background: #fff !important;
}
.user-xx li:nth-child(odd){
background: #eee !important;
}
.usercon{
flex-direction: column;
}
.container{
box-sizing: border-box;
}
.user-r{
margin-bottom: 10px;
}
}
@media(min-width:700px) {
.user-xx li span{ min-width: 30% !important; width: auto !important;}
.user-xx li{ width: 50%;float: left;}
.user-xx li a{ float: left; margin: 6px 15px 6px 0;}
}
</style>
</body>
</html>

View File

@@ -0,0 +1,275 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>美签代传递信息填报</title>
<script src="/static/home/js/ocr-image-compress.js?v=2"></script>
<script src="/static/js/passport-ocr-sdk.min.js?v=1"></script>
<link rel="stylesheet" href="/static/home/css/usvisa.css?v=6">
</head>
<body>
<main class="usvisa-page">
<section class="hero">
<div class="hero-inner">
<h1 class="hero-title">美签代传递<br>信息填报</h1>
<p class="hero-subtitle">客户资料将按扫码网点归集,便于支行和经办员后续跟进。</p>
</div>
</section>
<section class="branch-strip">
<div class="branch-panel">
<div>
<p class="branch-kicker">当前到访网点</p>
<p class="branch-name" id="branchName">
{if condition="$branch"}
{$branch.name}
{else /}
待选择支行
{/if}
</p>
</div>
<div class="branch-code" id="branchCodeText">已识别</div>
</div>
</section>
<section class="materials-section" aria-labelledby="materialsTitle">
<div class="materials-panel">
<div class="materials-heading">
<p class="materials-kicker">递交前确认</p>
<h2 id="materialsTitle">提交免面谈申请材料说明</h2>
<p>前往中信银行递交材料前,请确认携带以下文件。</p>
</div>
<div class="materials-essential" aria-label="必带材料">
<div class="material-item">
<span>01</span>
<strong>免面谈预约确认信</strong>
</div>
<div class="material-item">
<span>02</span>
<strong>DS-160 确认页</strong>
</div>
<div class="material-item">
<span>03</span>
<strong>旧护照原件</strong>
</div>
<div class="material-item">
<span>04</span>
<strong>新/现用护照</strong>
</div>
<div class="material-item">
<span>05</span>
<strong>符合要求的照片</strong>
</div>
</div>
<div class="materials-alert">
提交额外材料可能延误处理时间,并可能导致必须参加面谈。
</div>
<div class="materials-details">
<details open>
<summary>必带材料</summary>
<ul>
<li>免面谈项目预约确认信,通常为 2-3 页,包含预约详情。</li>
<li>DS-160 申请确认页,页面上需有申请人的电子照片。</li>
<li>旧护照原件,需包含年满 18 岁后签发、且在过期后 12 个月内的 B-1、B-2 或 B-1/B-2 签证,并提交所有符合条件的原件。</li>
<li>如获批准需贴签的新/现用护照。</li>
<li class="photo-requirement-item">
符合要求的照片:
<ul class="photo-requirement-list">
<li>照片拍摄时间须在六个月以内。</li>
<li>显示完整的面部和颈部。</li>
<li>尺寸为 2 英寸 × 2 英寸,即 51 毫米 × 51 毫米。</li>
<li>彩色照片,白色背景,不得佩戴眼镜或有色隐形眼镜。</li>
<li>不得进行任何数码修图或修改。</li>
</ul>
</li>
</ul>
</details>
<details>
<summary>递交与取护照说明</summary>
<ul>
<li>如领事处需要补充信息,将与申请人联系。</li>
<li>如未能在预约日期提交材料,请联系客户服务重新预约。</li>
<li>可以忽略预约确认信上的具体时间段,只需根据预约日期递交材料。</li>
<li>选择中信银行付费网点柜台领取护照或递交文件,费用为人民币 150 元。</li>
<li>选择 EMS 直送到家领取护照或递交文件,费用为人民币 150 元,需在线预付款。如需详细信息,请点击<a class="materials-link" href="/static/home/usvisa/payment-guide.pdf" target="_blank" rel="noopener">缴费指南</a>。</li>
</ul>
</details>
</div>
</div>
</section>
<section class="form-shell">
<div class="form-surface" id="formSurface">
<form id="usvisaForm" autocomplete="on">
<input type="hidden" name="branch_code" id="branchCode" value="{$branch_code|default=''}">
<input type="hidden" name="passport_img" id="passportImg" value="">
<div class="form-section">
<h2 class="section-title">
支行信息
<span class="section-mark"></span>
</h2>
<div class="field">
<label for="branchSelect">支行/网点 <span class="required">*</span></label>
<select class="select-control" id="branchSelect" name="branch_code_select" data-locked="{$branch_locked|default=0}">
<option value="">请选择支行</option>
{volist name="branches" id="branchItem"}
<option value="{$branchItem.code}" {if condition="$branch_code eq $branchItem.code"}selected{/if}>{$branchItem.name}</option>
{/volist}
</select>
</div>
</div>
<div class="form-section">
<h2 class="section-title">
客户信息
<span class="section-mark"></span>
</h2>
<div class="passport-panel is-open" id="passportPanel">
<div class="toggle-copy passport-copy">
<strong>护照拍照识别</strong>
<span>上传护照资料页后可自动填充护照号,识别不准可手动修改。</span>
</div>
<label class="upload-zone" for="passportFile">
<span class="upload-symbol" aria-hidden="true"></span>
<span class="upload-text">
<strong>拍摄或上传护照资料页</strong>
<span id="uploadStatus">JPG/PNG,照片清晰完整</span>
</span>
<input id="passportFile" type="file" accept="image/*" capture="environment">
</label>
<img class="preview" id="passportPreview" alt="护照预览">
<div class="ocr-progress" id="ocrProgress" aria-live="polite" aria-hidden="true">
<span class="ocr-spinner" aria-hidden="true"></span>
<span id="ocrProgressText">正在识别护照信息...</span>
</div>
<p class="status-line" id="ocrStatus"></p>
</div>
<div class="field-grid">
<div class="field">
<label for="passportNumber">护照号 <span class="required">*</span></label>
<input class="control" id="passportNumber" name="passport_number" type="text" maxlength="32" placeholder="请输入护照号" required>
</div>
<div class="field">
<label for="ds160Number">DS160编号 <span class="required">*</span></label>
<div class="scan-control-row">
<input class="control" id="ds160Number" name="ds160_number" type="text" maxlength="64" placeholder="用于查询签证状态" required>
<button class="scan-btn" id="openBarcodeScannerBtn" type="button">扫码</button>
</div>
</div>
<div class="field field-wide">
<label>所属使/领馆 <span class="required">*</span></label>
<div class="consulate-options">
<label class="consulate-option">
<input type="radio" name="consulate" value="北京" required>
<span>北京</span>
</label>
<label class="consulate-option">
<input type="radio" name="consulate" value="上海">
<span>上海</span>
</label>
<label class="consulate-option">
<input type="radio" name="consulate" value="广州">
<span>广州</span>
</label>
<label class="consulate-option">
<input type="radio" name="consulate" value="沈阳">
<span>沈阳</span>
</label>
<label class="consulate-option">
<input type="radio" name="consulate" value="武汉">
<span>武汉</span>
</label>
</div>
</div>
<div class="field">
<label for="customerName">客户姓名 <span class="required">*</span></label>
<input class="control" id="customerName" name="customer_name" type="text" placeholder="请输入客户姓名" maxlength="60" required>
</div>
<div class="field">
<label for="phone">手机号 <span class="required">*</span></label>
<input class="control" id="phone" name="phone" type="tel" inputmode="tel" placeholder="请输入手机号" maxlength="30" required>
</div>
<div class="field">
<label for="submitDate">递交日期 <span class="required">*</span></label>
<input class="control" id="submitDate" name="submit_date" type="date" value="{$submit_date_default|default=''}" required>
</div>
<div class="field">
<label for="uid">UID号 <span class="required">*</span></label>
<div class="scan-control-row">
<input class="control" id="uid" name="uid" type="text" placeholder="请输入或扫码识别客户UID号" maxlength="64" required>
<button class="scan-btn" id="openUidBarcodeScannerBtn" type="button">扫码</button>
</div>
</div>
<div class="field">
<label for="managerName">经办员姓名 <span class="required">*</span></label>
<input class="control" id="managerName" name="manager_name" type="text" placeholder="请输入经办员姓名" maxlength="60" required>
</div>
</div>
</div>
<div class="form-section">
<label class="agreement">
<input id="agreement" type="checkbox" required>
<span>本人确认所提交的信息真实、准确、有效,并同意用于本次美签免面谈材料递交。</span>
</label>
</div>
</form>
<div class="success-panel" id="successPanel">
<div class="success-seal" aria-hidden="true"></div>
<h2>提交成功</h2>
<p id="successText">信息已完成采集。</p>
</div>
</div>
<div class="action-bar" id="actionBar">
<button class="submit-btn" id="submitBtn" type="submit" form="usvisaForm">提交信息</button>
</div>
</section>
</main>
<section id="barcodeScannerLayer" class="barcode-scanner-layer" aria-hidden="true">
<div class="barcode-scanner-panel" role="dialog" aria-modal="true" aria-label="条形码扫描">
<div class="barcode-scanner-header">
<strong id="barcodeScannerTitle">扫描DS160条形码</strong>
<button id="closeBarcodeScannerBtn" class="barcode-close-btn" type="button">关闭</button>
</div>
<div class="barcode-video-wrap">
<video id="barcodePreviewVideo" muted autoplay playsinline webkit-playsinline></video>
<div class="barcode-scan-frame"></div>
<div class="barcode-scan-line"></div>
<div class="barcode-distance-tip" id="barcodeDistanceTip">请将DS160确认页条形码横向完整放入框内,距离保持20-40cm</div>
</div>
<div class="barcode-scanner-tools">
<button id="barcodeTorchBtn" class="barcode-tool-btn" type="button" hidden>打开闪光灯</button>
<label id="barcodeZoomBox" class="barcode-zoom-box" hidden>
<span>变焦</span>
<input id="barcodeZoomRange" type="range" min="1" max="1" step="0.1" value="1">
<span id="barcodeZoomValue">1.0x</span>
</label>
</div>
<div id="barcodeScannerStatus" class="barcode-scanner-status">准备打开摄像头...</div>
</div>
</section>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script>
window.usvisaPageData = {
branches: <?= json_encode($branches, JSON_UNESCAPED_UNICODE) ?>,
ocrConfigRaw: '{$ocr_config|default = ''}'.replace(/&quot;/g, '"')
};
</script>
<script src="/static/js/zxing-browser.min.js?v=1"></script>
<script src="/static/home/js/usvisa.js?v=6"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no" />
<title>美签申请</title>
<link rel="stylesheet" href="/visa/css/layui.css" />
<link rel="stylesheet" href="/visa/css/style.css?v=9" />
<link rel="stylesheet" href="/visa/css/save.css?v={$asset_version}"/>
<style>
.text-center{
text-align: center;
}
.text-visa{
margin-top: 16px;
}
</style>
</head>
<body>
<div class="container visa-ds160-save-and-continue__content">
<form class="ant-form ant-form-vertical">
<div class="visa-global-field">
<p style="text-align: center;font-size: 18px;color: #951e14">资料提交成功</p>
<p style="margin-top: 18px; font-weight: 600;">尊敬的客户,系统已收到您的申请,签证经理将在规定的时间受理您的申请,请您耐心等待。</p>
</div>
<div class="text-center">
<div>
<p class="other" >请扫描二维码添加客服微信以便递交签证申请</p>
<p style="margin-top: 16px"><img src="https://visa.evus.cn/kefu_order.png" width="200px"></p>
</div>
<div class="text-visa">
<p>美签咨询电话:<a href="tel:400-0878-958">400-0878-958</a></p>
<p>流程咨询电话:<a href="tel:0531-61300866">0531-61300866</a></p>
</div>
</div>
</form>
</div>
</body>
</html>

11174
app/home/view/visa/upvisa.html Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,367 @@
{include file="public/head" /}
<link rel="stylesheet" href="/static/home/css/iconfont.css?v=2" />
<link rel="stylesheet" href="/static/home/css/home-menu.css?v=4" />
<link rel="stylesheet" href="/static/home/css/home-index.css?v=8" />
<script src="/static/home/js/layer/layer.js"></script>
<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<!-- uni-app sdk-->
<script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>
<style>
html,
body {
width: 100%;
min-width: 0;
margin: 0;
padding: 0;
overflow-x: hidden;
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
.home-index-page .content_qz {
padding-top: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
overflow-x: hidden;
}
.home-index-page .cont-img {
width: 100% !important;
max-width: none !important;
margin: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
}
.home-index-page .wxmini-three-type {
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 82px;
column-gap: 12px;
height: 82px;
margin-bottom: 0;
}
.home-index-page .wxmini-three-type a {
box-sizing: border-box;
height: 82px;
}
.home-index-page .wxmini-three-type .type-icon {
height: 48px;
}
.home-index-page .wxmini-three-type .type-icon span {
font-size: 30px;
}
.home-index-page .wxmini-three-type .type-text {
height: 22px;
line-height: 22px;
}
@media (max-width: 768px) {
.home-index-page .content_qz {
padding-bottom: 0;
}
.home-index-page .con-btns {
margin-bottom: 0;
}
.home-index-page .wxmini-three-type {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 76px;
gap: 0;
height: 76px;
margin-top: 0;
margin-bottom: 0;
padding-bottom: 0;
overflow: visible;
background: #fff;
}
.home-index-page .wxmini-three-type a {
float: none;
display: block;
width: 100%;
height: 76px;
margin-top: 0;
text-align: center;
}
.home-index-page .wxmini-three-type .type-icon {
height: 44px;
}
.home-index-page .wxmini-three-type .type-icon span {
font-size: 26px;
}
.home-index-page .wxmini-three-type .type-text {
height: 18px;
line-height: 18px;
white-space: nowrap;
}
}
</style>
<body class="home-index-page home-layout-page">
<div class="content_qz">
<div class="cont-img">
<div class="indexswiper">
<div class="swiper-container" data-space-between='10' data-pagination='.swiper-pagination' data-autoplay="1000">
<div class="swiper-wrapper">
<div class="swiper-slide"><img style="width: 100%;" src="/static/home/images/shouye02.jpg" alt=""></div>
</div>
</div>
</div>
<div class="qz_btns">
<div><a class="qz_btns_a1 js-mini-nav" href="javascript:void(0);" data-mini-url="/pages/visa_detail/visa_detail?model=msg" data-fallback="{:url('home/detail/index')}" >eVUS登记</a></div>
<div><a class="qz_btns_a2 js-mini-nav" href="javascript:void(0);" data-mini-url="/pages/evus_search/evus_search" data-fallback="{:url('home/Lookup/index')}">eVUS查询</a></div>
</div>
<div class="con-btns">
<div class="indexcon">
<a class="index-qz">
<h1 class="type-txt">美国签证服务</h1>
<div class="type-cont">
<div class="type-img"><span class="icon iconfont icon-building_line"></span></div>
<div class="type-box">
<div class="type-txt1">7*24小时<span class="type-press"><span class="icon iconfont icon-finger_press_line"></span></span></div>
<div class="type-txt1">400-0878-958</div>
<div class="type-txt1">简单便捷自助办理系统</div>
</div>
</div>
</a>
<div class="index-type wxmini-three-type">
<a class="js-mini-nav" href="javascript:void(0);" data-mini-url="/pages/visa_detail/visa_detail?model=msg" data-fallback="{:url('home/detail/index')}">
<span class="type-icon"><span class="icon iconfont icon-signature_line"></span></span>
<span class="type-text">eVUS登记</span>
</a>
<a class="js-mini-nav" href="javascript:void(0);" data-mini-url="/pages/evus_search/evus_search" data-fallback="{:url('home/Lookup/index')}">
<span class="type-icon"><span class="icon iconfont icon-document_query_line"></span></span>
<span class="type-text">eVUS查询</span>
</a>
<a class="js-mini-nav" href="javascript:void(0);" data-mini-url="/pages/visa_detail/visa_detail?model=esta" data-fallback="{:url('home/esta/index')}">
<span class="type-icon"><span class="icon iconfont icon-edit_line"></span></span>
<span class="type-text">ESTA申请</span>
</a>
</div>
</div>
</div>
</div>
</div>
<div class="boxs" id="boxs">
<div class="contents" id="contents" style="font-weight: bold; width: 100%;">
<!-- 第一个段落 -->
<p style="margin: 10px auto 0; padding: 0; text-align: left; max-width: 800px; width: 90%; font-weight: bold;">
<span style="color: red;font-weight: bold;">请注意:</span>根据美国海关和边境保护局(CBP)规定,自2025年9月30日起,eVUS登记将收取30.75美元官方费用。
</p>
<!-- 第二个段落 -->
<p style="margin: 10px auto; padding: 0; text-align: left; max-width: 800px; width: 90%;font-weight: bold;">
本网站为独立运营的商业服务平台,提供有偿代办服务,收费包含官方费用与服务费,非任何政府机构或附属部门。
</p>
</div>
</div>
<!-- </div> -->
<!-- </div> -->
<div class="process">
<div class="ps-tit">登记流程简述</div>
<div class="ps-tit2" style="text-align: center; width: 100%; padding-bottom: 20px;"><span style="font-size: 14px;">3-15分钟即可反馈信息</span></div>
<div class="pro-con">
<div class="ps-item">
<img src="/static/home/images/icon-infor.png" alt="" />
<div class="ps-text">输入申请人信息</div>
</div>
<div class="ps-item ps-item2">
<img src="/static/home/images/icon-arrow.png" alt="" />
</div>
<div class="ps-item">
<img src="/static/home/images/icon-up2.png" alt="" />
<div class="ps-text">支付并提交申请</div>
</div>
<div class="ps-item ps-item2">
<div style="font-size: 12px; color: var(--primary-color);">3-15分钟收取反馈信息</div>
<img style="margin-top:-107px" src="/static/home/images/icon-arrow.png" alt="" />
</div>
<div class="ps-item">
<img src="/static/home/images/icon-down.png" alt="" />
<div class="ps-text">查询下载登记文件</div>
</div>
</div>
</div>
<div class="einfor" style=" padding-bottom: 0 !important;">
<div class="einfor-con">
<h3>申请登记新的签证更新电子系统(EVUS)</h3>
<h3 style="margin-top: 15px;">本网站使用说明</h3>
<p>欢迎您,使用本网站的服务,方便快捷的完成你的eVUS登记申请。</p>
<p>本网站为你提供下列两种服务:</p>
<ul>
<li>你可以选择自助填写服务 (点击方框 “新登记申请”)。</li>
<li>随时随地自助查询服务(点击右侧“查询已有登记”)。</li>
<li>如果你在机场即将登机,或者有其他需求,我们建议您选择加急服务</li>
</ul>
<h3>查询EVUS状态</h3>
<p>本网可以提供eVUS查询(免费)、eVUS中文代理登记(收费)等服务。</p>
<ul>
<li>查询EVUS登记的状态</li>
<li>检查已完成的登记</li>
<li>更新尚未提交的登记申请</li>
<li>提交尚未提交的登记申请</li>
</ul>
<div>
<p>持有效的 EVUS 更新,将被允许访客前往美国入境口岸申请入境。</p>
</div>
<p style="font-weight: 600;"><span style="color:#FF0000;font-weight: 600;">请注意:</span>美国海关和边境保护局是EVUS的官方机构,该服务将收取30.75美元登记费用,且要求使用英文填写。您也可以选择前往官网登记。官方网址请参考您签证内容!</p>
<div><img src="/static/home/images/cankao.png"></div>
<!--<div class="text2" style="font-size: 14px">-->
</div>
<div class="einfor-con einfor-con2">
<div class="einfor-qrcode einfor-qrcode2" style="float:right; margin-top: 20px;">
<div class="">
<div class="dj-txt" style="font-size: 24px; line-height: 40px; color: var(--primary-color);">EVUS登记服务</div>
<div class="dj-txt2">欢迎使用EVUS中文网登记系统</div>
<a href="javascript:void(0);" class="dj-btn js-mini-nav" data-mini-url="/pages/visa_detail/visa_detail?model=msg" data-fallback="{:url('home/detail/index')}" style="width: 100%;" >新登记申请</a>
<a href="javascript:void(0);" class="dj-btn dj-cx js-mini-nav" data-mini-url="/pages/evus_search/evus_search" data-fallback="{:url('home/Lookup/index')}" style="width: 100%; background: #fff;!important">查询已有登记</a>
</div>
</div>
</div>
</div>
<div class="tt2" style="width: 100%; height: 35px; margin-top: 30px;">
<div style="max-width: 1200px; margin: 0 auto;">
<h3 style="width: auto; float: left; color: #000; padding: 2px 30px; display: block; ">evus常见问题</h3>
</div>
</div>
<div class="context2">
<!-- 一般问题 -->
<div class="general-problems" style="margin-top: 20px;">
<div class="lists">
<div class="litem">
<h3>什么是签证更新电子系统(EVUS)?</h3>
<p>签证更新电子系统是指持有十年有效B1 / B2,B1或B2(访问者)签证的中国公民所使用的个人基本信息在线定期更新系统,以协助其赴美旅行。除了有效签证以外,上述旅客必须完成EVUS登记,以便获得许可进入美国。</p>
</div>
<div class="litem">
<h3>EVUS登记将在哪一天开始强制施行?</h3>
<p>自2016年11月29日起,所有持中华人民共和国护照,同时持有最长有效期(十年)B1 / B2,B1和B2签证的个人必须持有有效的EVUS登记才能赴美旅行。被要求进行EVUS登记的旅客如果没有有效的登记,将不能获得登机牌或者经由陆地入境口入境。</p>
</div>
<div class="litem">
<h3>B1/B2签证有效期问题</h3>
<p>1,绝大多数申请人的B1/B2签证有效期是10年,所有10年B1/B2签证在前往美国前,必须具备生效的美国签证系统EVUS电子签证更新。</p>
<p>2,只有极个别B1/B2签证低于10年,此种情况下常见1年有效期B1/B2签证,这种情况,不需要进行EVUS登记!</p>
</div>
<div class="litem">
<h3>护照有效期问题以及有美国签证的护照换发问题</h3>
<p> 1,16岁以上的护照有效期是10年。</p>
<p> 2,16岁以下护照有效期5年。</p>
<p>3,护照低于6个月有效期的禁止前往美国</p>
<p>因为签证有效期10年,且护照低于6个月有效期的申请人禁止前往美国;因此存在签证有效,但护照过期或者低于6个月而失效的情况,此种情形申请人需要携带旧护照前往申请人中国所在地的出入境管理局换发新护照,请将将旧护照交予出入境管理局,护照首页剪角作废,并保留美国签证。申请人注意,当你在出入境管理局时,所有不携带原始护照或者谎称护照丢失而补发的护照,该护照上面的美国签证全部作废!</p>
</div>
<div class="litem">
<h3>美国B1/B2签证EVUS有效期时长问题</h3>
<p>1,美国B1/B2十年签证有效,且护照有效期大于2年6个月的,EVUS电子签证有效期2年。</p>
<p>2,美国B1/B2十年签证有效,且护照有效期少于2年6个月的,EVUS电子签证有效期:护照实际有效期减去6个月,即为EVUS电子签证有效期(例如:护照剩余有效期是2年3个月,则EVUS有效期为19个月)</p>
<p>3,美国B1/B2十年签证有效,但护照有效期低于6个月的,不准予美国EVUS电子签证登记,请换发新护照。</p>
<p> 4,美国B1/B2十年签证有效,持有刚刚换发的新护照的,所有有效的EVUS会立即失效,需要立即重新更新,并在更新时填写新旧两本护照的相关信息</p>
</div>
<div class="litem">
<h3>美国B1/B2十年签证有效,EVUS失效以及申请人情况有所变更的受否需要登记更新</h3>
<p>1,从美国返回后,美国签证EVUS电子登记过期失效,近期无前往美国的计划,EVUS可以更新吗?</p>
<p>EVUS过期失效不必然导致美国签证失效,您可以在前往美国前进行登记即可。不过,从笔者接触的客户当中,极少量的客户美国签证被取消或者被要求重新面签,且从在重新面签被拒签的情况。而即便没有计划赴美但是及时更新EVUS的客户,笔者没有发现一例失效或者被要求面签的情况。所以,即便无赴美计划,笔者也建议及时更新你的EVUS美国电子更新系统
</p>
<p>2,美国B1/B2十年签证有效,护照有效且无换新护照情况,EVUS电子签证也有效,但是个人信息(住址、工作信息、赴美地址、联系方式等)有变化,需要EVUS电子签证更新吗? </p>
<p>建议更新新的EVUS电子更新,美国EVUS电子更新系统设置的目的就是要掌握并审核申请人的现有情况,并据此来评估是否符合赴美条件。</p>
</div>
</div>
</div>
<div class="register">
<a href="javascript:void(0);" class="btn js-mini-nav" data-mini-url="/pages/visa_detail/visa_detail?model=msg" data-fallback="{:url('home/detail/index')}">在线申请登记</a>
<p>在回答前,请仔细阅读申请表。在填写 EVUS 登记时,尤其在回答所有资格符合问题和安全问题时,尽可能正确作答。</p>
<p>若申请人提供不正确或误导的信息,申请将会遭拒。</p>
</div>
<div class="general-problems" style="margin-top: 10px">
<div class="lists">
<div class="litem">
<h3>在EVUS登记需要准备什么?</h3>
<p>旅客需要准备好其含有最长有效期(10年期)的B1 / B2,B1或B2签证的中华人民共和国护照,并且能够连接互联网。</p>
<p style="color: var(--primary-color)">凡是持十年效期的 B1、B2 或 B1/B2 签证之未成年人,必须持有效的个人护照,在赴美旅游前申请 EVUS。</p>
</div>
<div class="litem">
<h3>EVUS表格上有些什么问题?</h3>
<p>每次在EVUS上登记都要求旅客提供自己的姓名,出生日期,紧急联系人,护照信息,个人和就业信息,旅客还需要回答旅游资格相关的问题。朋友,亲属,专业的旅游从业人员或其他第三方也可以代替旅客提交EVUS的登记。 旅客本人应对代表他/她所提交的信息的真实性和准确性负责。</p>
</div>
<div class="litem">
<h3>进入美国是否需要登记EVUS?</h3>
<p>是的。自2016年11月起即需要登记。美国政府和中国政府就签发十年期旅游签证做出了双边互惠安排。该协议规定旅客须定期完成在线表格填写以更新个人信息。此表格的填写将有助于加快中国旅客入境美国。</p>
</div>
<div class="litem">
<h3>其他国家是否有这项要求?</h3>
<p>这是一项新的规定。美国政府预期在未来可能将此要求适用于其他国家。</p>
</div>
<div class="litem">
<h3>这是否对目前的签证持有人,新申请人或两者都有影响?</h3>
<p>两个都会受到本项新规定的影响。持有2016年11月之前签发的十年有效期B1 / B2,B1或B2签证的申请者,必须在该规定生效后登陆EVUS登记,方可使用签证。自2016年11月起获得十年有效期B1 / B2,B1或B2签证的申请者,必须在首次前往美国旅行前登记。所有申请者的登记维持两年有效,若旅客的签证或护照两者中有任何一者过期,EVUS登记的信息便失效。那么签证持有人必须在前往美国前再次登陆EVUS更新个人信息。</p>
</div>
<div class="litem">
<h3>我在几个月前刚刚收到十年有效期的B1 / B2签证。我是否需要在EVUS登记后申请新签证?</h3>
<p>不需要,您的签证仍然有效。但是,如果您在2016年11月以后前往美国,必须先在EVUS登记.EVUS登记和申请签证是不同的程序。</p>
</div>
</div>
</div>
<div class="register">
<a href="javascript:void(0);" class="btn js-mini-nav" data-mini-url="/pages/visa_detail/visa_detail?model=msg" data-fallback="{:url('home/detail/index')}" style="background: #ff8d0e" >EVUS登记</a>
</div>
</div>
<script>
(function () {
function navigateMini(url, fallback) {
var navigated = false;
function doNavigate() {
if (navigated || !window.uni || typeof window.uni.navigateTo !== 'function') {
return;
}
navigated = true;
window.uni.navigateTo({
url: url
});
}
doNavigate();
if (!navigated) {
document.addEventListener('UniAppJSBridgeReady', doNavigate);
setTimeout(function () {
document.removeEventListener('UniAppJSBridgeReady', doNavigate);
if (!navigated && fallback) {
window.location.href = fallback;
}
}, 800);
}
return false;
}
document.addEventListener('DOMContentLoaded', function () {
var links = document.querySelectorAll('.js-mini-nav');
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click', function (event) {
event.preventDefault();
return navigateMini(this.getAttribute('data-mini-url'), this.getAttribute('data-fallback'));
});
}
});
})();
</script>
</body>
</html>

1058
app/lang/en-us.php Normal file

File diff suppressed because it is too large Load Diff

911
app/lang/zh-cn.php Normal file
View File

@@ -0,0 +1,911 @@
<?php
return [
'site' => [
'title' => 'EVUS中文网_evus美国签证登记_evus登记步骤',
'description' => 'evus,evus登记步骤,evus系统登记入口,evus是什么,evus美国签证登记,evus官网中文',
'keywords' => 'EVUS中文网为您提供申请登记新的签证更新电子系统(EVUS)。提供evus官网查询、更新、evus系统登记入口、evus登记步骤等相关信息。',
'footer_1' => '声明:本网站是经工商注册、工信部备案的专业服务站点,本网站致力于协助个人或者企业获得他们得旅行许可或短时间的入境停留。登记不成功全额退费,登记成功服务费用不退。纠纷解决,适用本网站所属机构注册地仲裁委员会管辖',
'footer_2' => 'ITS INTERNATIONAL TRAVEL SERVICE COMPANY Copyright © 2014-2025 All rights reserved',
],
'menu_home' => '首页',
'menu_apply' => 'EVUS登记',
'menu_search' => '查询EVUS状态',
'menu_us_apply' => '美签申请',
'menu_esta_apply' => 'ESTA申请',
'menu_help' => '使用帮助',
'menu_user' => '个人中心',
'menu_news' => '新闻资讯',
'menu_company' => '关于我们',
'user_my_order' => '我的订单',
'user_invoice' => '自助开票',
'user_multiple_invoice' => '合并开票',
'user_logout' => '退出',
'order_paid' => '已支付',
'order_unpaid' => '未支付',
'index_title' => 'eVUS中文办理登记',
'index_desc' => '点击登记按钮,轻松完成办理',
'index_button' => 'eVUS登记',
'index_step1' => '填写旅行信息',
'index_step2' => '3-5分钟信息录入',
'index_step3' => '支付服务费',
'index_step4' => '3-15分钟内递交',
'index_step5' => '查询登记结果',
'index_attention_tips' => '请注意',
'index_attention_1' => '根据美国海关和边境保护局(CBP)规定,自2025年9月30日起,eVUS登记将收取30.75美元官方费用。',
'index_attention_2' => '本网站为独立运营的商务服务平台,凭借自主研发的智能系统,带来三大核心服务:智能填表系统可高效简化表单填写流程,精准 OCR 识别能快速提取图文信息,智能 AI 翻译则支持多语种精准转换。网站经相关机构注册、登记和备案后上线运营,专注为用户提供专业有偿服务,不隶属于任何政府部门。',
'index_attention_3' => '登记成功,所有费用不予退还;若登记未成功,官方登记费无法退回,但我们承诺全额退还服务费。',
'index_price_1_1' => 'eVUS快速登记',
'index_price_1_2' => '精准OCR识别',
'index_price_1_3' => '智能AI翻译',
'index_price_1_4' => '6小时内递交',
'index_price_1_5' => '包含30.75美金官方收费',
'index_price_1_6' => '6小时内递交',
'index_price_2_1' => 'eVUS专业登记',
'index_price_2_2' => '精准OCR识别',
'index_price_2_3' => '智能AI翻译',
'index_price_2_4' => '15分钟内递交',
'index_service' => '我们的服务',
'index_advantage' => '我们的优势',
'index_advantage_1_title' => '7×24小时急速响应',
'index_advantage_1_content_1' => '提供机场加急服务,专为应对各类临时出行需求而设,为赶时间的旅客开辟高效登记服务',
'index_advantage_1_content_2' => '旅客抵达机场后,无需繁琐排队,仅需 5-7 分钟即可递交',
'index_advantage_1_content_3' => '简化流程,助您快速通关,彻底规避误机风险,让紧急出行也能从容无忧',
'index_advantage_2_title' => '智能填表系统',
'index_advantage_2_content_1' => '我们推出简化中文表单填写服务,全程仅需5分钟,即可完成核心信息录入,大幅降低语言壁垒带来的操作困扰',
'index_advantage_2_content_2' => '专业团队开展二次审核,重点核查信息逻辑、格式规范及关键内容匹配度,从源头减少登记失误,显著降低因信息错漏导致的不成功风险,较用户自行英文操作(30-40分钟)提速8倍',
'evus_pic' => '/new/assets/images/evus.jpg',
'evusearch_pic' => '/new/assets/images/evusearch.jpg',
'esta_pic' => '/new/assets/images/esta.jpg',
'evus' => [
'other_country_acquired_other_required' => '请填写其他',
'other_country_acquired_other_label' => '其他',
'add' => '添加',
'delete' => '删除',
'title' => '旅行证件信息',
'passport_number_label' => '护照号码',
'passport_placeholder' => '输入或拍照上传',
'passport_required' => '请填写护照号码',
'passport_upload_title' => '拍照/上传有效护照照片',
'passport_tooltip' => '护照号码通常为G、E、EA、EB、EC等开头的9位字符,公务护照以及外交护照例外。请仔细区分数字1与字母I,以及数字0与字母O。',
'passport_hint' => '依照您旅游时将使用的护照来输入护照号。',
'passport_country_label' => '护照国家',
'select_country_required' => '请选择一个国家',
'select_country_prompt' => '请选择一个国家',
'china' => '中国',
'country_tooltip' => '', // Can add tooltip text if needed
'country_hint' => '目前只有中华人民共和国的公民国民必须登记 EVUS。',
'pinyin' => '拼音',
'last_name_label' => '姓氏',
'last_name_placeholder' => '请填写拼音姓',
'last_name_required' => '请填写拼音姓',
'last_name_tooltip' => '请勿在此栏输入名字。复姓请按照护照信息为准。若您没有姓氏,请在姓氏栏位填 "UNKNOWN"',
'last_name_hint' => '请参考护照上的信息用英文字母填写您的姓氏',
'first_name_label' => '名字',
'first_name_placeholder' => '请填写拼音名',
'first_name_required' => '请填写拼音名',
'first_name_tooltip' => '请参考护照上的信息填写您的名字,请勿在此栏输入姓氏',
'first_name_hint' => '依照您的护照正确输入您的名字',
'birth_date_label' => '出生日期',
'birth_date_placeholder' => '请选择出生日期',
'birth_date_required' => '请选择出生日期',
'birth_date_tooltip' => '请参考您护照上的信息填写您的出生日期,请确保出生日期正确',
'birth_city_label' => '出生城市',
'birth_city_placeholder' => '请填写出生城市',
'birth_city_required' => '请填写出生城市',
'birth_city_tooltip' => '请参考您护照上的信息填写您的出生地点。',
'birth_country_label' => '出生国家',
'birth_country_tooltip' => '请从下拉式菜单选择您护照上出生地栏位显示的国家名称',
'country_required' => '请选择一个国家',
'gender_label' => '性别',
'male' => '男性',
'female' => '女性',
'passport_issue_date_label' => '护照签发时间',
'passport_issue_placeholder' => '请选择护照签发日期',
'passport_issue_required' => '请选择护照签发日期',
'passport_issue_tooltip' => '请参照护照上的签发日期填写',
'passport_expiry_label' => '护照有效期',
'passport_expiry_placeholder' => '请选择护照有效期',
'passport_expiry_required' => '请选择护照有效期',
'passport_expiry_tooltip' => '请参照护照上的有效期填写',
'ten_year_visa_label' => '您持有十年效期的美国访客签证吗(B1、B2 或 B1/B2 类)?',
'ten_year_visa_hint' => '请确认是否持有美国十年效期商务/旅游(B1、B2、B1/B2)类型签证',
'ten_year_visa_warning' => '要在 EVUS 登记,您必须持有 10 年效期的美国访客签证(B1、 B2 或 B1/B2 类)。若希望到美国旅游,但未持有这类的签证,您必须到美国大使馆申请',
'visa_number_label' => '美国B1/B2签证号码',
'visa_number_placeholder' => '输入或拍照上传',
'visa_number_required' => '请填写签证号码',
'visa_number_tooltip' => '请参考您的美国签证贴纸,输入右下角8位红色字符的签证号码',
'upload_visa_title' => '拍照/上传有效护照照片',
'visa_in_passport_label' => '您旅行时所使用的护照是否含有您的美国签证?',
'visa_in_passport_hint' => '如果你的签证在旧护照上面,请选择"否",并填写旧护照信息',
'yes' => '是',
'no' => '否',
'old_passport_number_label' => '含美国签证的旧护照号码',
'enter_or_upload' => '输入或拍照上传',
'passport_number_required' => '请填写护照号码',
'upload_passport_photo' => '拍照/上传有效护照照片',
'old_passport_tooltip' => '请输入包含美国签证的旧护照号码',
'passport_country_tooltip' => '请选择旧护照的签发国家',
'next_step' => '下一步',
'other_citizenship_title' => '其他公民身份、国籍、护照',
'other_nationality_label' => '您现在是否拥有其他国籍?',
'other_nationality_tooltip' => '请确认是否拥有除中国以外的他国国籍',
'other_citizenship_current_label' => '其他国家公民当前',
'other_citizenship_current_tooltip' => '选择您的其他国籍的国家。如果您以上回答"是",该国家必须完成您的申请',
'how_acquired_citizenship_label' => '你如何从这个国家获得公民/国籍',
'how_acquired_citizenship_tooltip' => '选择你如何获得国籍/从这个国家的国籍',
'past_nationality_label' => '您曾经是否拥有其他国籍?',
'past_nationality_tooltip' => '在此问题上回答"是"代表着现在已无此国籍',
'past_citizenship_label' => '其他国家公民过去',
'past_citizenship_tooltip' => '请从下拉式菜单选择您护照上出生地栏位显示的国家名称',
'other_passport_label' => '您曾经是否拥有其他国家的护照或居民身份证?',
'other_passport_tooltip' => '请确认是否拥有除中国以外的他国护照。若您有此材料但已遗失或不记得号码,可填写"UNKNOWN"',
'issuing_country_label' => '发行国',
'issuing_country_tooltip' => '选择国家的公民身份,因为它出现在您的文档。完成应用程序需签发国的文档。',
'document_type_label' => '文档类型',
'document_type_tooltip' => '请选择另一个国家颁布的旅行文件类型',
'document_number_label' => '文档编号',
'document_number_placeholder' => '字母及数字(如无法提供请填写000000)',
'document_number_tooltip' => '输入您的旅行证件上显示的文件编号。旅行证件可能包含数字和/或字符。请仔细区分数字零和字母O.',
'expiry_year_label' => '到期年份',
'expiry_year_placeholder' => '请选择到期年份',
'expiry_year_tooltip' => '请即使它已过期,说明颁发的另一个国家,你的旅行证件到期年份。',
'social_media_label' => '是否有社交媒体?',
'social_media_tooltip' => '请选择是否有社交媒体',
'facebook_label' => '脸书(facebook)',
'facebook_placeholder' => '请填写脸书用户名',
'facebook_tooltip' => '如有,请填写facebook账号名称。',
'linkedin_label' => '领英链接(linkedin)',
'linkedin_placeholder' => '请填写领英链接',
'linkedin_tooltip' => '如有,请填写linkedin链接。',
'twitter_label' => '推特(Twitter)',
'twitter_placeholder' => '请填写推特用户名',
'twitter_tooltip' => '如有,请填写Twitter账号名称。',
'instagram_label' => '照片墙(Instagram)',
'instagram_placeholder' => '请填写照片墙用户名',
'instagram_tooltip' => '如有,请填写照片墙用户名。',
'platform_label' => '提供者/平台',
'platform_tooltip' => '如有,请请选择提供者/平台。',
'identifier_label' => '社交媒体标识符',
'identifier_placeholder' => '请填写社交媒体标识符',
'identifier_tooltip' => '如有,请填写社交媒体标识符。',
'alias_label' => '是否有曾用名?',
'alias_tooltip' => '是否有曾用名',
'alias_last_name_label' => '曾用 姓氏',
'alias_last_name_placeholder' => '请填写曾用 姓氏',
'alias_last_name_tooltip' => '请填写您曾用名的姓氏',
'alias_last_name_hint' => '请填写您曾用名的姓氏,请勿在此栏输入名字。',
'alias_first_name_label' => '曾用 名字',
'alias_first_name_placeholder' => '请填写曾用 名字',
'alias_first_name_tooltip' => '请填写您曾用名的名字',
'alias_first_name_hint' => '请填写您曾用名的名字,请勿在此栏输入名字。',
'select_option_required' => '请选择',
'select_option_prompt' => '请选择',
'select_document_type_required' => '请选择文档类型',
'select_document_type_prompt' => '请选择文档类型',
'select_platform_required' => '请选择提供者/平台',
'select_platform_prompt' => '请选择提供者/平台',
'by_birth' => '经由出生',
'by_parents' => '通过父母',
'naturalization' => '归化',
'other' => '其他',
'passport_number' => '护照号',
'permanent_residence_id' => '永久居留证件号码(绿卡号)',
'address_contact_title' => '住址及联系方式',
'id_card_instructions' => '输入号码或点击【相机】识别您的有效<span style="color: #7F1313">身份证正面照</span>信息;拍照上传方式,可自动识别导入您的信息。',
'id_number_label' => '身份证号码',
'id_number_required' => '请填写身份证号码',
'upload_photo_title' => '拍照/上传有效照片',
'id_number_tooltip' => '请输入18位的身份证号码。如果没有身份证号码,请填写‘‘UNKNOWN’’。',
'email_label' => '电子邮箱(选填)',
'email_placeholder' => '建议填写,用于收入eVUS批准信',
'email_required' => '请填写电子邮箱',
'email_tooltip' => '您将通过邮件方式收到您的申请确认函。如有任何状态更新也将通过邮件通知您。',
'current_country_label' => '现居住国家',
'current_country_tooltip' => '请选择您当前居住的国家',
'current_province_label' => '现居住省份/州',
'current_province_placeholder' => '填写居住省份/州',
'current_province_required' => '填写居住省份/州',
'current_province_tooltip' => '请填写您当前居住的省份或州',
'current_city_label' => '现居住城市',
'current_city_placeholder' => '填写现居住城市',
'current_city_required' => '填写现居住城市',
'current_city_tooltip' => '请填写您当前居住的城市',
'current_address_label' => '现居住地址',
'current_address_placeholder' => '填写现居住地址',
'current_address_required' => '填写现居住地址',
'current_address_tooltip' => '请填写您当前居住的详细地址',
'phone_label' => '联系电话',
'phone_placeholder' => '请输入手机号码',
'phone_tooltip' => '请填写有效的联系电话号码',
'parents_info_title' => '父母信息',
'father_surname_label' => '父亲的姓氏',
'father_surname_placeholder' => '填写父亲的姓氏',
'father_surname_required' => '填写父亲的姓氏',
'father_surname_tooltip' => '请输入申请人父亲的姓氏',
'father_name_label' => '父亲的名字',
'father_name_placeholder' => '填写父亲的名字',
'father_name_required' => '填写父亲的名字',
'father_name_tooltip' => '请输入申请人父亲的名字',
'mother_surname_label' => '母亲的姓氏',
'mother_surname_placeholder' => '填写母亲的姓氏',
'mother_surname_required' => '填写母亲的姓氏',
'mother_surname_tooltip' => '请输入申请人母亲的姓氏',
'mother_name_label' => '母亲的名字',
'mother_name_placeholder' => '填写母亲的名字',
'mother_name_required' => '填写母亲的名字',
'mother_name_tooltip' => '请输入申请人母亲的名字',
'employment_info_title' => '工作信息',
'has_employer_label' => '您现在或之前是否有过工作单位或雇主',
'has_employer_tooltip' => '如填"是"请填写工作单位信息',
'employer_country_label' => '工作单位所在国家',
'employer_country_tooltip' => '请在列表中选择工作单位所在国家',
'employer_state_label' => '工作单位所在省份/州',
'employer_state_placeholder' => '请填写工作单位所在省份/州',
'employer_state_required' => '请填写工作单位所在省份/州',
'employer_state_tooltip' => '建议使用英文或拼音输入工作单位所在省份。若不清楚可填写"UNKNOWN"',
'employer_city_label' => '工作单位所在城市',
'employer_city_placeholder' => '请填写工作单位所在城市',
'employer_city_required' => '请填写工作单位所在城市,请勿填写省份',
'employer_city_tooltip' => '建议使用英文或拼音输入工作单位所在城市。若不清楚可填写"UNKNOWN"',
'employer_address_label' => '工作单位地址',
'employer_address_placeholder' => '请填写工作单位地址',
'employer_address_required' => '请填写工作单位地址',
'employer_address_tooltip' => '建议使用英文或拼音输入工作单位的地址,不必在此栏填写省份或城市。若不清楚可填写"UNKNOWN"',
'employer_name_label' => '工作单位名称',
'employer_name_placeholder' => '请填写工作单位名称',
'employer_name_required' => '填写工作单位名称限30字',
'employer_name_tooltip' => '请使用英文或拼音输入工作单位的名称。若没有工作单位,您也可以填写自雇、家庭主妇、等信息形容您的工作状况',
'travel_info_title' => '旅游信息',
'transit_purpose_label' => '您到美国的目的,是为了过境到另一国家吗?',
'transit_purpose_tooltip' => '请选择您前往美国是否只是为了过境而不停留。选否可选择填写在美联系人。',
'us_address_section_title' => '在美国的地址(选填)',
'us_contact_name_label' => '将在美国到访的酒店名称 / 商业上往来的友人 / 亲友全名(选填)',
'us_contact_name_placeholder' => '不得含有数字和特殊字符。如无法提供请留空',
'us_contact_name_required' => '不得含有数字和特殊字符。如无法提供请留空',
'us_contact_name_tooltip' => '在美国的联系人可以是友人、亲戚或生意上的伙伴。若您在美国没有联系人,请输入您住宿地点的名称、地址和电话号码(例如酒店名称)。您也可输入"UNKNOWN"。',
'us_state_label' => '所在州(选填)',
'select_state_required' => '请选择所在州',
'select_state_prompt' => '请选择所在州',
'us_state_tooltip' => '请在列表中选择您在美国的联系人所在的州。若不清楚可选择"未知"',
'us_city_label' => '所在城市(选填)',
'us_city_placeholder' => '填写联系人所在城市,不必填写省份',
'us_city_required' => '填写联系人所在城市,不必填写省份',
'us_city_tooltip' => '请输入您在美国的联系人所在城市。若不清楚可填写"UNKNOWN"。',
'us_address_label' => '地址(选填)',
'us_address_placeholder' => '填写联系人的地址街道及号码,不必填写省份或城市',
'us_address_required' => '填写联系人的地址街道及号码,不必填写省份或城市',
'us_address_tooltip' => '请输入您在美国的联系人的地址街道及号码,不必在此栏填写省份或城市。若不清楚可填写"UNKNOWN"。',
'us_phone_label' => '电话号码(选填)',
'select_phone_prefix_prompt' => '请选择手机号前缀',
'us_phone_placeholder' => '请输入手机号码',
'us_phone_tooltip' => '请输入您在美国的联系人的电话号码。若不清楚可填写"0"。',
'emergency_contact_title' => '紧急联系人(选填)',
'emergency_last_name_label' => '姓氏(选填)',
'emergency_last_name_placeholder' => '填写紧急联系人姓氏',
'emergency_last_name_required' => '填写紧急联系人姓氏',
'emergency_last_name_tooltip' => '请输入您的紧急联系人姓氏。紧急联系人可以是您在美国或其他国家的联系人,如家属、好友或商业伙伴。若没有紧急联系人,请留空',
'emergency_first_name_label' => '名字(选填)',
'emergency_first_name_placeholder' => '填写紧急联系人名字',
'emergency_first_name_required' => '填写紧急联系人名字',
'emergency_first_name_tooltip' => '请输入您的紧急联系人名字。紧急联系人名字可以是您在美国或其他国家的联系人,如家属、好友或商业伙伴。若没有紧急联系人,请留空',
'emergency_email_label' => '电子邮箱(选填)',
'emergency_email_placeholder' => '填写紧急联系人电子邮箱',
'emergency_email_required' => '填写紧急联系人电子邮箱',
'emergency_email_tooltip' => '请输入您的紧急联系人的电子邮箱。若没有紧急联系人,请留空',
'emergency_phone_label' => '电话号码(选填)',
'emergency_phone_placeholder' => '填写紧急联系人电话号码',
'emergency_phone_tooltip' => '请输入您的紧急联系人的电话号码。若没有紧急联系人,请输入0',
'eligibility_question' => '资格问题',
'warning_cannot_continue' => '您确定要对此问题回答「是」吗?如果您的答案为「是」,您将不能继续在线申请。',
'q_a' => '您目前是否患有以下任何疾病(《公共健康法》第361条b款所列传染病):霍乱、白喉、肺结核、天花、黄热病、病毒性出血热(包括埃博拉、拉沙热、马尔堡病、克里米亚-刚果出血热)、可传染他人且可能致命的严重急性呼吸道疾病?',
'q_b' => '您是否曾因严重破坏财产或严重伤害他人或政府机关而被逮捕或定罪?',
'q_c' => '您是否曾违反过与非法药物的持有、使用或分发相关的法律?',
'q_d' => '您是否曾经或试图从事恐怖活动、间谍活动、破坏活动或种族灭绝?',
'q_e' => '您是否曾为获取签证或协助他人获取签证、或进入美国而欺诈或伪造自己或他人的信息?',
'q_f' => '您目前是否在美国寻求工作,或是否曾在未获许可的情况下在美国工作?',
'q_g' => '您是否曾被拒签美国签证或被拒绝入境美国,或在入境口岸撤回过申请?',
'q_h' => '您是否曾逾期居留美国或违反过美国签证的规定?',
'q_i' => '自2011年3月1日以来,您是否曾去过或居住在伊朗、伊拉克、利比亚、朝鲜、索马里、苏丹、叙利亚或也门?',
'reject_date' => '拒签日期',
'reject_address' => '拒签地点',
'vist_country' => '访问国家',
'vist_from_date' => '开始日期',
'vist_end_date' => '结束日期',
'vist_country_des' => '访问主要原因',
'IRN' => '伊朗',
'IRQ' => '伊拉克',
'LBY' => '利比亚',
'PRK' => '朝鲜',
'SOM' => '索马里',
'SDN' => '苏丹',
'SYR' => '叙利亚',
'YEM' => '也门',
'reason_1' => '旅游',
'reason_2' => '探亲',
'reason_3' => '工作',
'reason_4' => '商务',
'reason_5' => '学习',
'reason_6' => '新闻报道',
'reason_7' => '会议',
'reason_8' => '文化交流',
'reason_9' => '宗教活动',
'reason_10' => '医疗',
'reason_11' => '过境',
'reason_12' => '外交/公务',
'reason_13' => '其他',
'declaration_title' => '申请人声明',
'declaration_check1' => '本人声明在此申请中提供真实丶完整和正确的信息。',
'declaration_check2' => '我已阅读并理解',
'choose_package' => '选择套餐',
'package_a' => 'A套餐:398元/人民币 Vip快速登记(资料完整15分钟反馈信息)',
'package_b' => 'B套餐:98元/人民币 安逸登记(资料完整6小时内反馈信息)',
'submit_now' => '立即提交',
'termsCheckbox' => '
<div style="padding: 20px;">
<h5>条款与条件</h5>
<p>
签证更新电子系统(EVUS)与执法部门 的数据库进行比对。所有持10年有效期访客签证的旅客(B1, B2 或 B1/B2),
如果需要以短期访客身份入境美国,都必须在赴美前在EVUS上登记。
如果您的EVUS登记获得批准,就意味着您可以前往美国。但这并不意味着您可以入境美国。抵达美国入境口岸时,您将接受United States
Customs and Border Protection官员的检查。 入境口岸的官员会根据美国移民法的规定决定您是否可以入境。
由您或指定的第三方代理人所提供的所有信息,必须是真实和正确的。如果您在填写信息时由您或您的代理人有意提交任何虚假、虚构或伪造的声明或陈述,造成EVUS更新失败或者美国签证被注销,责任由您本人承担。
信息填写完成后,我们根据你所选择的套餐时效反馈信息,提交后信息将不能再更改。
</p>
<p> 请表明您已阅读并了解上述所提供的信息</p>
<h5>隐私政策</h5>
<p>
<p>
本应用尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更有个性化的服务,本应用会按照本隐私权政策的规定使用和披露您的个人信息。但本应用将以高度的勤勉、审慎义务对待这些信息。除本隐私权政策另有规定外,在未征得您事先许可的情况下,本应用不会将这些信息对外披露或向第三方提供。本应用会不时更新本隐私权政策。
您在同意本应用服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私权政策属于本应用服务使用协议不可分割的一部分。
<h5>1. 适用范围</h5>
<p>(a) 在您注册本应用帐号时,您根据本应用要求提供的个人注册信息;
(b)
在您使用本应用网络服务,或访问本应用平台网页时,本应用自动接收并记录的您的浏览器和计算机上的信息,包括但不限于您的IP地址、浏览器的类型、使用的语言、访问日期和时间、软硬件特征信息及您需求的网页记录等数据;
(c) 本应用通过合法途径从商业伙伴处取得的用户个人数据。
您了解并同意,以下信息不适用本隐私权政策:
(a) 您在使用本应用平台提供的搜索服务时输入的关键字信息;
(b) 本应用收集到的您在本应用发布的有关信息数据,包括但不限于参与活动、成交信息及评价详情;
(c) 违反法律规定或违反本应用规则行为及本应用已对您采取的措施。</p>
<h5>2. 信息使用</h5>
<p>
(a)本应用不会向任何无关第三方提供、出售、出租、分享或交易您的个人信息,除非事先得到您的许可,或该第三方和本应用(含本应用关联公司)单独或共同为您提供服务,且在该服务结束后,其将被禁止访问包括其以前能够访问的所有这些资料。
(b)
本应用亦不允许任何第三方以任何手段收集、编辑、出售或者无偿传播您的个人信息。任何本应用平台用户如从事上述活动,一经发现,本应用有权立即终止与该用户的服务协议。
(c)
为服务用户的目的,本应用可能通过使用您的个人信息,向您提供您感兴趣的信息,包括但不限于向您发出产品和服务信息,或者与本应用合作伙伴共享信息以便他们向您发送有关其产品和服务的信息(后者需要您的事先同意)</p>
<h5>3. 信息披露</h5>
<p>在如下情况下,本应用将依据您的个人意愿或法律的规定全部或部分的披露您的个人信息:
(a) 经您事先同意,向第三方披露;
(b)为提供您所要求的产品和服务,而必须和第三方分享您的个人信息;
(c) 根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露;
(d) 如您出现违反中国有关法律、法规或者本应用服务协议或相关规则的情况,需要向第三方披露;
(e) 如您是适格的知识产权投诉人并已提起投诉,应被投诉人要求,向被投诉人披露,以便双方处理可能的权利纠纷;
(f)
在本应用平台上创建的某一交易中,如交易任何一方履行或部分履行了交易义务并提出信息披露请求的,本应用有权决定向该用户提供其交易对方的联络方式等必要信息,以促成交易的完成或纠纷的解决。
(g) 其它本应用根据法律、法规或者网站政策认为合适的披露。</p>
<h5>4. 信息存储和交换</h5>
<p>
本应用收集的有关您的信息和资料将保存在本应用及(或)其关联公司的服务器上,这些信息和资料可能传送至您所在国家、地区或本应用收集信息和资料所在地的境外并在境外被访问、存储和展示。</p>
<h5>5. Cookie的使用</h5>
<p>(a) 在您未拒绝接受cookies的情况下,本应用会在您的计算机上设定或取用cookies
,以便您能登录或使用依赖于cookies的本应用平台服务或功能。本应用使用cookies可为您提供更加周到的个性化服务,包括推广服务。
(b)
您有权选择接受或拒绝接受cookies。您可以通过修改浏览器设置的方式拒绝接受cookies。但如果您选择拒绝接受cookies,则您可能无法登录或使用依赖于cookies的本应用网络服务或功能。
(c) 通过本应用所设cookies所取得的有关信息,将适用本政策。</p>
<h5>6. 信息安全</h5>
<p>(a)
本应用帐号均有安全保护功能,请妥善保管您的用户名及密码信息。本应用将通过对用户密码进行加密等安全措施确保您的信息不丢失,不被滥用和变造。尽管有前述安全措施,但同时也请您注意在信息网络上不存在“完善的安全措施”。
(b) 在使用本应用网络服务进行网上交易时,您不可避免的要向交易对方或潜在的交易对</p>
<h5>7.本隐私政策的更改</h5>
<p>
(a)如果决定更改隐私政策,我们会在本政策中、本公司网站中以及我们认为适当的位置发布这些更改,以便您了解我们如何收集、使用您的个人信息,哪些人可以访问这些信息,以及在什么情况下我们会透露这些信息。
(b)本公司保留随时修改本政策的权利,因此请经常查看。如对本政策作出重大更改,本公司会通过网站通知的形式告知。
方披露自己的个人信息,如联络方式或者邮政地址。请您妥善保护自己的个人信息,仅在必要的情形下向他人提供。如您发现自己的个人信息泄密,尤其是本应用用户名及密码发生泄露,请您立即联络本应用客服,以便本应用采取相应措施。</p>
</div>
',
'terms_privacy_title' => '条款与条件及隐私政策',
'close' => '关闭'
],
'lookup' => [
'hot_price' => '热门套餐',
'status_check_title' => '查询EVUS状态',
'passport_number_label' => '护照号码',
'enter_or_upload' => '输入或拍照上传',
'passport_number_required' => '请填写护照号码',
'upload_passport_photo' => '拍照/上传有效护照照片',
'passport_number_tooltip' => '护照号码通常为G、E、EA、EB、EC等开头的9位字符,公务护照以及外交护照例外。请仔细区分数字1与字母I,以及数字0与字母O。',
'visa_number_label' => '美国B1/B2签证号码',
'visa_number_required' => '请填写签证号码',
'visa_number_tooltip' => '请参考您的美国签证贴纸,输入右下角8位红色字符的签证号码。',
'last_name_label' => '姓氏',
'pinyin' => '拼音',
'last_name_placeholder' => '请填写拼音姓',
'last_name_required' => '请填写拼音姓',
'last_name_tooltip' => '请勿在此栏输入名字。复姓请按照护照信息为准。若您没有姓氏,请在姓氏栏位填 "UNKNOWN"。',
'last_name_hint' => '请参考护照上的信息用英文字母填写您的姓氏',
'first_name_label' => '名字',
'first_name_placeholder' => '请填写拼音名',
'first_name_required' => '请填写拼音名',
'first_name_tooltip' => '请参考护照上的信息填写您的名字,请勿在此栏输入姓氏。',
'first_name_hint' => '依照您的护照正确输入您的名字',
'birth_date_label' => '出生日期',
'birth_date_placeholder' => '请选择出生日期',
'birth_date_required' => '请选择出生日期',
'birth_date_tooltip' => '请参考您护照上的信息填写您的出生日期,请确保出生日期正确',
'citizenship_label' => '公民身份国家',
'select_country_required' => '请选择国家',
'select_country_prompt' => '请选择国家',
'citizenship_tooltip' => '请从下拉式菜单选择您护照上出生地栏位显示的国家名称。',
'terms_acceptance' => '我已阅读并理解条款与条件及隐私政策。',
'check_status_button' => '查询状态',
'status_registered' => '已登记',
'registered_description1' => '“已登记”的EVUS状态意味着EVUS的要求得到了满足得以前往美国 1)从登记批准之日起两年内有效期,或 2),直到主要的护照到期(“主要的护照”是用于登记的护照是有效的,并在登记申请时尚未过期)或 3),直到签证过期,以先到者为准。这样并不保证入境美国。美国联邦Customs and Border Protection 的官员在美国的入境口岸将做最终决定。',
'registered_description2' => '要进入您的EVUS登记申请,会要求您提供您的登记申请号码,护照号码,签证号码和出生日期。如果有必要,您可以更新一份成功的登记内以下信息:1)在美地址和 2)电子邮件地址。如果您需要更改或更新表格上的任何其他信息,您必须申请新的旅行授权。',
'registered_description3' => '您已成功提交了以下所列',
'status_pending' => '审批中',
'pending_description' => '您的信息正在登记中,请耐心等候!',
'status_unsuccessful' => '登记不成功',
'unsuccessful_description1' => '您的EVUS登记不成功,并且您目前没有得到授权前往美国。',
'unsuccessful_description2' => 'EVUS登记申请失败的常见原因包括:您没有完成所有必填的资料; 您没有提供正确的信息; 您没有用有效的护照或美国签证申请登记,或者其他原因。',
'unsuccessful_description3' => '如需帮助,请拨打EVUS帮助中心400-0878-958 。帮助中心每天24小時,每周7天提供,以帮助您与您的EVUS招生。',
'unsuccessful_description4' => '您已成功提交了以下所列的登记申请。为您的个人记录,请印列此页。',
'table_name' => '姓名',
'table_birth_date' => '出生日期',
'table_enrollment_number' => '登记申请号码',
'table_passport_number' => '护照号码',
'table_visa_number' => 'B1/B2签证的签证号码',
'table_status' => '状态',
'table_expiry' => '到期',
'table_view' => '查看',
'visa_services' => '美国签证服务',
'package1_title' => '套餐一',
'package1_price' => '¥198',
'package1_feature1' => 'DS-160 英文翻译填写',
'package2_title' => '套餐二',
'package2_price' => '¥1998',
'package2_feature1' => 'DS-160 英文翻译填写',
'package2_feature2' => '即时预约面签',
'package2_feature3' => '包含签证费用',
'package3_title' => '套餐三(限时特惠)',
'package3_price' => '¥2098<s style="font-size: 14px">¥2250</s>',
'package3_feature1' => 'DS-160 英文翻译填写',
'package3_feature2' => '即时预约',
'package3_feature3' => '面签辅导',
'package3_feature4' => '包含签证费用',
'package4_title' => '套餐四',
'package4_price' => '¥2099',
'package4_feature1' => '免面谈代传递(签证续签)',
'package4_feature2' => 'DS-160 英文翻译填写',
'package4_feature3' => '即时预约代传递',
'package4_feature4' => '包含签证费用',
'package4_feature5' => '(赴美目的说明)',
],
'esta' => [
'notice' => '注意:您正在申请ESTA,如果您拥有中国护照的请点击申请',
'personal_details_title' => '个人详细信息',
'passport_photo_label' => '护照照片',
'upload_instructions' => '点击上传,或将文件拖拽到此处',
'upload_success_alt' => '上传成功后渲染',
'passport_photo_required' => '请上传护照照片',
'passport_example_label' => '护照示例',
'personal_photo_label' => '个人照片',
'personal_photo_required' => '请上传个人照片',
'personal_photo_example_label' => '个人照示例',
'last_name_label' => '姓氏',
'pinyin' => '拼音',
'last_name_placeholder' => '请填写拼音姓',
'last_name_required' => '请填写拼音姓',
'last_name_tooltip' => '请勿在此栏输入名字。复姓请按照护照信息为准。若您没有姓氏,请在姓氏栏位填 "UNKNOWN"。',
'last_name_hint' => '请参考护照上的信息用英文字母填写您的姓氏',
'first_name_label' => '名字',
'first_name_placeholder' => '请填写拼音名',
'first_name_required' => '请填写拼音名',
'first_name_tooltip' => '请参考护照上的信息填写您的名字,请勿在此栏输入姓氏。',
'first_name_hint' => '依照您的护照正确输入您的名字',
'birth_date_label' => '出生日期',
'birth_date_placeholder' => '请选择出生日期',
'birth_date_required' => '请选择出生日期',
'birth_date_tooltip' => '请参考您护照上的信息填写您的出生日期,请确保出生日期正确',
'birth_city_label' => '出生城市',
'birth_city_placeholder' => '请填写出生城市',
'birth_city_required' => '请填写出生城市',
'birth_city_tooltip' => '请参考您护照上的信息填写您的出生地点。',
'birth_country_label' => '出生国家',
'select_country_required' => '请选择一个国家',
'select_country_prompt' => '请选择一个国家',
'birth_country_tooltip' => '请从下拉式菜单选择您护照上出生地栏位显示的国家名称。',
'gender_label' => '性别',
'male' => '男性',
'female' => '女性',
'id_number_label' => 'ID证件号码',
'id_number_placeholder' => '请填写ID证件号码',
'id_number_required' => '请填写ID证件号码',
'id_number_tooltip' => '请输入身份证号码。如果没有身份证号码,请填写"UNKNOWN"',
'former_name_label' => '曾用名(选填)',
'former_name_placeholder' => '请填写曾用名',
'former_name_required' => '请填写曾用名',
'next_step' => '下一步',
'travel_documents_title' => '旅行文件详细信息',
'passport_country_label' => '护照国家',
'passport_number_label' => '护照号码',
'passport_number_placeholder' => '请填写护照号码',
'passport_number_required' => '请填写护照号码',
'passport_number_tooltip' => '护照号码通常为G、E、EA、EB、EC等开头的9位字符,公务护照以及外交护照例外。请仔细区分数字1与字母I,以及数字0与字母O。',
'passport_issue_date_label' => '护照签发时间',
'passport_issue_date_placeholder' => '请选择护照签发日期',
'passport_issue_date_required' => '请选择护照签发日期',
'passport_issue_date_tooltip' => '请参照护照上的签发日期填写',
'passport_expiry_label' => '护照有效期',
'passport_expiry_placeholder' => '请选择护照有效期',
'passport_expiry_required' => '请选择护照有效期',
'passport_expiry_tooltip' => '请参照护照上的有效期填写',
'visa_number_label' => '填写签证号码:(如果有)',
'visa_number_placeholder' => '请填写签证号码',
'visa_number_required' => '请填写签证号码',
'other_citizenship_title' => '其他公民身份、国籍、护照',
'current_other_nationality_label' => '您现在是否拥有其他国籍?',
'current_other_nationality_tooltip' => '请确认是否拥有除中国以外的他国国籍',
'other_citizenship_current_label' => '其他国家公民当前',
'other_citizenship_current_tooltip' => '选择您的其他国籍的国家。如果您以上回答"是",该国家必须完成您的申请',
'how_acquired_citizenship_label' => '你如何从这个国家获得公民/国籍',
'how_acquired_citizenship_tooltip' => '选择你如何获得国籍/从这个国家的国籍',
'past_other_nationality_label' => '您曾经是否拥有其他国籍?',
'past_other_nationality_tooltip' => '在此问题上回答"是"代表着现在已无此国籍',
'past_nationality_start_date_label' => '曾经拥有其他国籍的开始日期',
'past_nationality_end_date_label' => '曾经拥有其他国籍的结束日期',
'past_citizenship_label' => '其他国家公民过去',
'past_citizenship_tooltip' => '请从下拉式菜单选择您护照上出生地栏位显示的国家名称',
'other_passport_label' => '您曾经是否拥有其他国家的护照或居民身份证?',
'other_passport_tooltip' => '请确认是否拥有除中国以外的他国护照。若您有此材料但已遗失或不记得号码,可填写"UNKNOWN"',
'issuing_country_label' => '发行国',
'issuing_country_tooltip' => '选择国家的公民身份,因为它出现在您的文档。完成应用程序需签发国的文档',
'document_type_label' => '文档类型',
'document_type_tooltip' => '请选择另一个国家颁布的旅行文件类型',
'document_number_label' => '文档编号(选填)',
'document_number_placeholder' => '字母及数字(如无法提供请填写000000)',
'document_number_required' => '请填写文档编号',
'document_number_tooltip' => '输入您的旅行证件上显示的文件编号。旅行证件可能包含数字和/或字符。请仔细区分数字零和字母O',
'expiry_year_label' => '到期年份',
'expiry_year_placeholder' => '请选择到期年份',
'expiry_year_required' => '请选择到期年份',
'expiry_year_tooltip' => '请即使它已过期,说明颁发的另一个国家,你的旅行证件到期年份',
'select_option_required' => '请选择',
'select_option_prompt' => '请选择',
'select_document_type_required' => '请选择文档类型',
'select_document_type_prompt' => '请选择文档类型',
'select_date_required' => '请选择日期',
'select_date_prompt' => '请选择日期',
'passport_number' => '护照号',
'national_id' => '身份证号码',
'by_birth' => '经由出生',
'by_parents' => '通过父母',
'naturalization' => '归化',
'other' => '其他',
'yes' => '是',
'no' => '否',
'contact_information_title' => '联系方式',
'email_label' => '电子邮箱(选填)',
'email_placeholder' => '建议填写,用于接收ESTA批准信',
'email_required' => '请填写电子邮箱',
'email_tooltip' => '您将通过邮件方式收到您的申请确认函。如有任何状态更新也将通过邮件通知您。',
'confirm_email_label' => '确认电子邮箱(选填)',
'confirm_email_placeholder' => '建议填写,用于接收ESTA批准信',
'confirm_email_required' => '请填写电子邮箱',
'confirm_email_tooltip' => '您将通过邮件方式收到您的申请确认函。如有任何状态更新也将通过邮件通知您。',
'phone_number_label' => '联系电话',
'phone_number_placeholder' => '请输入手机号码',
'select_phone_prefix_prompt' => '请选择手机号前缀',
'address_details_title' => '详细地址',
'current_country_label' => '现居住国家',
'current_province_label' => '现居住省份/州',
'current_province_placeholder' => '填写居住省份/州',
'current_province_required' => '填写居住省份/州',
'current_city_label' => '现居住城市',
'current_city_placeholder' => '填写现居住城市',
'current_city_required' => '填写现居住城市',
'current_address_label' => '现居住地址',
'current_address_placeholder' => '填写现居住地址',
'current_address_required' => '填写现居住地址',
'parents_info_title' => '父母信息',
'father_surname_label' => '父亲的姓氏',
'father_surname_placeholder' => '填写父亲的姓氏',
'father_surname_required' => '填写父亲的姓氏',
'father_surname_tooltip' => '请输入申请人父亲的姓氏',
'father_name_label' => '父亲的名字',
'father_name_placeholder' => '填写父亲的名字',
'father_name_required' => '填写父亲的名字',
'father_name_tooltip' => '请输入申请人父亲的名字',
'mother_surname_label' => '母亲的姓氏',
'mother_surname_placeholder' => '填写母亲的姓氏',
'mother_surname_required' => '填写母亲的姓氏',
'mother_surname_tooltip' => '请输入申请人母亲的姓氏',
'mother_name_label' => '母亲的名字',
'mother_name_placeholder' => '填写母亲的名字',
'mother_name_required' => '填写母亲的名字',
'mother_name_tooltip' => '请输入申请人母亲的名字',
'employment_info_title' => '工作信息',
'has_employer_label' => '您现在或之前是否有过工作单位或雇主',
'has_employer_tooltip' => '如填"是"请填写工作单位信息',
'employer_country_label' => '工作单位所在国家',
'employer_country_tooltip' => '请在列表中选择工作单位所在国家',
'employer_state_label' => '工作单位所在省份/州',
'employer_state_placeholder' => '填写居住省份/州',
'employer_state_required' => '填写居住省份/州',
'employer_state_tooltip' => '建议使用英文或拼音输入工作单位所在省份。若不清楚可填写"UNKNOWN"',
'employer_city_label' => '工作单位所在城市',
'employer_city_placeholder' => '填写现居住城市',
'employer_city_required' => '填写现居住城市,请勿填写省份',
'employer_city_tooltip' => '建议使用英文或拼音输入工作单位所在城市。若不清楚可填写"UNKNOWN"',
'employer_address_label' => '工作单位地址',
'employer_address_placeholder' => '填写现居住地址',
'employer_address_required' => '填写现居住地址',
'employer_address_tooltip' => '建议使用英文或拼音输入工作单位的地址,不必在此栏填写省份或城市。若不清楚可填写"UNKNOWN"',
'employer_name_label' => '工作单位名称',
'employer_name_placeholder' => '填写工作单位名称',
'employer_name_required' => '填写工作单位名称限30字',
'employer_name_tooltip' => '请使用英文或拼音输入工作单位的名称。若没有工作单位,您也可以填写自雇、家庭主妇、等信息形容您的工作状况',
'travel_info_title' => '旅游信息',
'transit_purpose_label' => '您到美国的目的,是为了过境到另一国家吗?',
'transit_purpose_tooltip' => '请选择您前往美国是否只是为了过境而不停留。选否可选择填写在美联系人',
'us_address_section_title' => '在美国的地址(选填)',
'us_contact_name_label' => '将在美国到访的酒店名称 / 商业上往来的友人 / 亲友全名(选填)',
'us_contact_name_placeholder' => '不得含有数字和特殊字符。如无法提供请留空',
'us_contact_name_required' => '不得含有数字和特殊字符。如无法提供请留空',
'us_contact_name_tooltip' => '在美国的联系人可以是友人、亲戚或生意上的伙伴。若您在美国没有联系人,请输入您住宿地点的名称、地址和电话号码(例如酒店名称)。您也可输入"UNKNOWN"',
'us_state_label' => '所在州(选填)',
'select_state_required' => '请选择所在州',
'select_state_prompt' => '请选择所在州',
'us_state_tooltip' => '请在列表中选择您在美国的联系人所在的州。若不清楚可选择"未知"',
'us_city_label' => '所在城市(选填)',
'us_city_placeholder' => '填写联系人所在城市,不必填写省份',
'us_city_required' => '填写联系人所在城市,不必填写省份',
'us_city_tooltip' => '请输入您在美国的联系人所在城市。若不清楚可填写"UNKNOWN"',
'us_address_label' => '地址(选填)',
'us_address_placeholder' => '填写联系人的地址街道及号码,不必填写省份或城市',
'us_address_required' => '填写联系人的地址街道及号码,不必填写省份或城市',
'us_address_tooltip' => '请输入您在美国的联系人的地址街道及号码,不必在此栏填写省份或城市。若不清楚可填写"UNKNOWN"',
'us_phone_label' => '电话号码(选填)',
'us_phone_placeholder' => '请输入手机号码',
'us_phone_tooltip' => '请输入您在美国的联系人的电话号码。若不清楚可填写"0"',
'emergency_contact_title' => '紧急联系人(选填)',
'emergency_last_name_label' => '姓氏(选填)',
'emergency_last_name_placeholder' => '填写紧急联系人姓氏',
'emergency_last_name_required' => '填写紧急联系人姓氏',
'emergency_last_name_tooltip' => '请输入您的紧急联系人姓氏。紧急联系人可以是您在美国或其他国家的联系人,如家属、好友或商业伙伴。若没有紧急联系人,请留空',
'emergency_first_name_label' => '名字(选填)',
'emergency_first_name_placeholder' => '填写紧急联系人名字',
'emergency_first_name_required' => '填写紧急联系人名字',
'emergency_first_name_tooltip' => '请输入您的紧急联系人名字。紧急联系人名字可以是您在美国或其他国家的联系人,如家属、好友或商业伙伴。若没有紧急联系人,请留空',
'emergency_email_label' => '电子邮箱(选填)',
'emergency_email_placeholder' => '填写紧急联系人电子邮箱',
'emergency_email_required' => '填写紧急联系人电子邮箱',
'emergency_email_tooltip' => '请输入您的紧急联系人的电子邮箱。若没有紧急联系人,请留空',
'emergency_phone_label' => '电话号码(选填)',
'emergency_phone_placeholder' => '填写紧急联系人电话号码',
'emergency_phone_tooltip' => '请输入您的紧急联系人的电话号码。若没有紧急联系人,请输入0',
'applicant_declaration_title' => '申请人声明',
'declaration_statement' => '本人声明在此申请中提供真实、完整和正确的信息。',
'terms_acceptance' => '我已阅读并理解条款与条件及隐私政策。',
'select_package_title' => '选择套餐',
'package_a_option' => 'A套餐:958元/人民币 Vip快速登记(资料完整6小时内通过)',
'package_b_option' => 'B套餐:495元/人民币 安逸登记(资料完整48小时内通过)',
'submit_application_button' => '立即提交',
'eligibility_questions_title' => '资格问题',
'question_a_label' => '您目前是否患有任何下列疾病(《公共健康法案》第 361 号 b 项)?霍乱、白喉、肺结核、结核、天花、黄热病、病毒性出血热,包括埃博拉病毒、拉萨热、马尔堡病、克里米亚-刚果出血热、可传染他人且可能致死的严重急性呼吸道疾病',
'question_b_label' => '您是否曾因严重破坏财产或伤及他人或政府机关,而被逮或被判罪?',
'question_c_label' => '您是否曾违反任何涉及持有、使用或分发非法药物的法律?',
'question_d_label' => '您是否试图或曾经从事恐怖活动、间谍、破坏活动或种族灭绝?',
'question_e_label' => '您是否曾为了取得签证、协助他人取得签证、或入境美国,犯下欺诈或伪造个人或他人的资料?',
'question_f_label' => '您目前是否在美国寻求工作或是您是否曾未经美国政府许可在美国工作?',
'question_g_label' => '您是否曾使用目前或先前的护照申请美国签证被拒?或者您是否曾被拒绝入境美国、或在美国入境口岸时,申请遭到驳回?',
'question_h_label' => '您是否曾在美国停留超过美国政府允许的入境期间?',
'question_i_label' => '您是否曾在 2011 年三月 1 日当日或其后到过伊拉克、叙利亚、伊朗或苏丹',
'eligibility_warning' => '您确定要对此问题回答「是」吗?如果您的答案为「是」,您就不能继续在线申请了。',
],
'pay' => [
'success_message' => '订单提交成功,请尽快付款,订单号',
'payment_amount' => '应付金额',
'order_success_message' => '您的订单已经提交成功,订单号为:',
'notice_1' => '1、您填写的信息必须和您的真实信息一致,如提交的信息与事实不符合,由此造成的后果,本中心概不负责。',
'notice_3' => '2、工作时间:周一至周日09:00 - 22:00 (节假日正常工作),在非工作时间段提交的申请表,系统自动延伸到下一工作日,敬请谅解。',
'notice_4' => '3、提交后,我们会在规定的时间内翻译审核校对资料信息,请注意查收邮件,如收件箱里没有,则很可能被隔离到了垃圾箱里。',
],
'jump' => [
'auto_redirect' => '秒后自动跳转',
'redirect_now' => '立即跳转'
],
'js' => [
'daxie' => '请填写大写字母',
'zhongwen' => '请填写填写中文',
'len40' => '请控制在100字以内',
'required_field' => '此项为必填项',
'min_length' => '至少需要%d个字符',
'max_length' => '最多允许%d个字符',
'ppt_min' => '至少需要9个字符',
'ppt_max' => '最多允许9个字符',
'ppt_format' => '护照格式应为字母开头 + 至少6位数字或字母',
'visa_min' => '至少需要8个字符',
'visa_max' => '最多允许8个字符',
'visa_format' => '签证格式不正确',
'default_reqtext' => '必填项不能为空',
'checkbox_checked' => '必须选择一个选项',
'checkbox_required' => '请勾选声明',
'english_only' => '只能输入英文字母',
'success_message' => '上传成功',
'fail_message' => '上传失败:',
'error_message' => '上传出错',
'upload_image_only' => '文件必须为图片',
'browser_not_supported' => '你的浏览器不支持上传',
'visa_unrecognized' => '无法识别,请手动填写签证号',
'manual_entry_required' => '无法识别,请手动填写',
'upload_retry' => '请重新上传',
'status_enrolled' => '已登记',
'status_pending' => '审批中',
'status_unsuccessful' => '登记不成功',
'status_revoked' => 'DOS已撤销您的签证',
'click_to_view' => '点击查看'
],
'controller' => [
'success' => '操作成功',
'fail' => '操作失败',
'price_error' => '价格错误',
'server_error' => '服务器错误',
'no_registration_info' => '未检索到登记信息',
'registration_expired' => '您正在搜索的登记申请已过期或取消',
'registration_success' => '登记成功',
'registration_failed' => '登记不成功',
'registration_pending' => '登记中',
'visa_revoked' => '已撤销您的签证',
'missing_order_sn' => '缺少订单号,请重新填写',
'order_not_exist' => '订单号不存在,请重新填写',
'payment_success' => '订单已支付成功',
'parameter_error' => '参数错误',
'payment_not_completed' => '订单未支付',
'order_not_exist_retry' => '订单号不存在,请重新支付',
'payment_not_completed_retry' => '您还未支付,请重新支付',
],
'payment' => [
'select_payment_method' => '选择支付方式',
'wechat_pay' => '微信支付',
'alipay' => '支付宝',
'checkout' => 'checkout',
'success' => '支付成功',
'fail' => '支付失败'
],
'foot' => [
'user_agreement' => '条款与条件',
'privacy_policy' => '隐私政策',
'disclaimer' => '免责声明',
'refund_policy' => '退款与支付条款',
'cookie_policy' => 'Cookies 使用声明',
'user_agreement_info' => '<div style="padding: 20px;"> <p>
签证更新电子系统(EVUS)与执法部门 的数据库进行比对。所有持10年有效期访客签证的旅客(B1, B2 或 B1/B2),
如果需要以短期访客身份入境美国,都必须在赴美前在EVUS上登记。
如果您的EVUS登记获得批准,就意味着您可以前往美国。但这并不意味着您可以入境美国。抵达美国入境口岸时,您将接受United States
Customs and Border Protection官员的检查。 入境口岸的官员会根据美国移民法的规定决定您是否可以入境。
由您或指定的第三方代理人所提供的所有信息,必须是真实和正确的。如果您在填写信息时由您或您的代理人有意提交任何虚假、虚构或伪造的声明或陈述,造成EVUS更新失败或者美国签证被注销,责任由您本人承担。
信息填写完成后,我们根据你所选择的套餐时效反馈信息,提交后信息将不能再更改。
</p>
<p> 请表明您已阅读并了解上述所提供的信息</p></div>',
'privacy_policy_info' => ' <div style="padding: 20px;"><p>
本应用尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更有个性化的服务,本应用会按照本隐私权政策的规定使用和披露您的个人信息。但本应用将以高度的勤勉、审慎义务对待这些信息。除本隐私权政策另有规定外,在未征得您事先许可的情况下,本应用不会将这些信息对外披露或向第三方提供。本应用会不时更新本隐私权政策。 您在同意本应用服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私权政策属于本应用服务使用协议不可分割的一部分。注意:为更好的提供您所要求的产品和服务上文所述对“第三方”的限制不包括本公司的关联公司(母公司,子公司,控股、被控股公司等),“第三方”是指本司及本司关联公司之外的主体,即下文:信息披露款项中(b)款之规定。
</p>
<h3>1. 适用范围</h3>
<p>(a) 在您注册本应用帐号时,您根据本应用要求提供的个人注册信息; (b) 在您使用本应用网络服务,或访问本应用平台网页时,本应用自动接收并记录的您的浏览器和计算机上的信息,包括但不限于您的IP地址、浏览器的类型、使用的语言、访问日期和时间、软硬件特征信息及您需求的网页记录等数据; (c) 本应用通过合法途径从商业伙伴处取得的用户个人数据。 您了解并同意,以下信息不适用本隐私权政策: (a) 您在使用本应用平台提供的搜索服务时输入的关键字信息; (b) 本应用收集到的您在本应用发布的有关信息数据,包括但不限于参与活动、成交信息及评价详情; (c) 违反法律规定或违反本应用规则行为及本应用已对您采取的措施。
</p>
<h3>2. 信息使用</h3>
<p>
(a)本应用不会向任何无关第三方提供、出售、出租、分享或交易您的个人信息,除非事先得到您的许可,或该第三方和本应用(含本应用关联公司)单独或共同为您提供服务,且在该服务结束后,其将被禁止访问包括其以前能够访问的所有这些资料。 (b) 本应用亦不允许任何第三方以任何手段收集、编辑、出售或者无偿传播您的个人信息。任何本应用平台用户如从事上述活动,一经发现,本应用有权立即终止与该用户的服务协议。 (c) 为服务用户的目的,本应用可能通过使用您的个人信息,向您提供您感兴趣的信息,包括但不限于向您发出产品和服务信息,或者与本应用合作伙伴共享信息以便他们向您发送有关其产品和服务的信息(后者需要您的事先同意)
</p>
<h3>3. 信息披露</h3>
<p>在如下情况下,本应用将依据您的个人意愿或法律的规定全部或部分的披露您的个人信息: (a) 经您事先同意,向第三方披露; (b)为提供您所要求的产品和服务,而必须和第三方分享您的个人信息; (c) 根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露; (d) 如您出现违反中国有关法律、法规或者本应用服务协议或相关规则的情况,需要向第三方披露; (e) 如您是适格的知识产权投诉人并已提起投诉,应被投诉人要求,向被投诉人披露,以便双方处理可能的权利纠纷; (f) 在本应用平台上创建的某一交易中,如交易任何一方履行或部分履行了交易义务并提出信息披露请求的,本应用有权决定向该用户提供其交易对方的联络方式等必要信息,以促成交易的完成或纠纷的解决。 (g) 其它本应用根据法律、法规或者网站政策认为合适的披露。
</p>
<h3>4. 信息存储和交换</h3>
<p>
本应用收集的有关您的信息和资料将保存在本应用及(或)其关联公司的服务器上,这些信息和资料可能传送至您所在国家、地区或本应用收集信息和资料所在地的境外并在境外被访问、存储和展示。
</p>
<h3>5. Cookie的使用</h3>
<p>(a) 在您未拒绝接受cookies的情况下,本应用会在您的计算机上设定或取用cookies ,以便您能登录或使用依赖于cookies的本应用平台服务或功能。本应用使用cookies可为您提供更加周到的个性化服务,包括推广服务。 (b) 您有权选择接受或拒绝接受cookies。您可以通过修改浏览器设置的方式拒绝接受cookies。但如果您选择拒绝接受cookies,则您可能无法登录或使用依赖于cookies的本应用网络服务或功能。 (c) 通过本应用所设cookies所取得的有关信息,将适用本政策。
</p>
<h3>6. 信息安全</h3>
<p>(a) 本应用帐号均有安全保护功能,请妥善保管您的用户名及密码信息。本应用将通过对用户密码进行加密等安全措施确保您的信息不丢失,不被滥用和变造。尽管有前述安全措施,但同时也请您注意在信息网络上不存在“完善的安全措施”。 (b) 在使用本应用网络服务进行网上交易时,您不可避免的要向交易对方或潜在的交易
</p>
<h3>7.本隐私政策的更改</h3>
<p>
(a)如果决定更改隐私政策,我们会在本政策中、本公司网站中以及我们认为适当的位置发布这些更改,以便您了解我们如何收集、使用您的个人信息,哪些人可以访问这些信息,以及在什么情况下我们会透露这些信息。 (b)本公司保留随时修改本政策的权利,因此请经常查看。如对本政策作出重大更改,本公司会通过网站通知的形式告知。 方披露自己的个人信息,如联络方式或者邮政地址。请您妥善保护自己的个人信息,仅在必要的情形下向他人提供。如您发现自己的个人信息泄密,尤其是本应用用户名及密码发生泄露,请您立即联络本应用客服,以便本应用采取相应措施。
</p>
</div>',
'disclaimer_info' => '<div style="padding: 20px;">
<div class="disclaimer-item">
<h4>1. 非官方性质声明</h4>
<p>本网站<span style="color:#c58d8dbd;">并非美国政府官方网站,也不隶属于美国海关与边境保护局(CBP)</span>。我们是独立的服务提供商,专门协助申请人完成EVUS登记流程。</p>
</div>
<div class="disclaimer-item">
<h4>2. 服务范围说明</h4>
<p>ITS INTERNATIONAL TRAVEL SERVICE COMPANY 仅提供 EVUS 表格填写协助和相关技术支持服务。我们不对最终审批结果作出任何保证或承诺,因为审批权完全在于美国政府相关部门。</p>
</div>
<div class="disclaimer-item">
<h4>3. 审批权限声明</h4>
<p>EVUS申请是否获批完全由美国政府相关部门决定,我们无法影响或加快审批进程。我们的服务仅限于协助您正确填写和提交申请表格。</p>
</div>
<div class="note">
<p>使用本服务即表示您已阅读、理解并同意上述免责声明。</p>
</div>
</div>
</div>',
'refund_policy_info' => '<div style="padding: 20px;"> <h4>1. 支付方式</h4> <p>(a) 本公司接受信用卡、借记卡、PayPal等多种支付方式</p> <p>(b) 所有支付交易均通过安全加密处理,保障您的资金安全</p><h4>2. 退款与支付</h4>
<p>(a) 在提交前,用户可申请退款,退款将在7-14个工作日内处理</p>
<p>(b) 一旦申请提交至EVUS系统,费用不予退还,因服务已实际提供</p>
<p>(c) 如遇重复扣款等系统问题,经核实后将全额退款</p>
<h4>3. 服务失败</h4>
<p>(a) 因用户提供的信息不准确或不完整导致申请失败,本公司不退款</p>
<p>(b) 因美国政府系统问题导致的申请失败,可提供相应证明申请部分退款</p>
<p>(c) 因本公司技术问题导致申请失败,将全额退款或重新提交申请</p></div>
',
'cookie_policy_info' => ' <div style="padding: 20px;">
<div class="cookie-notice">
<h3>Cookie使用说明</h3>
<p>本网站由 ITS INTERNATIONAL TRAVEL SERVICE COMPANY 运营,使用 Cookies 技术以提升用户体验。</p>
<h4>我们使用Cookies的主要目的:</h4>
<ul>
<li>记住您的登录状态和偏好设置</li>
<li>分析网站访问量和用户行为模式</li>
<li>优化网站性能和改进服务质量</li>
<li>提供个性化的内容推荐</li>
</ul>
<h4>Cookie管理:</h4>
<p>您可以通过浏览器设置限制或禁用Cookies。请注意,如果禁用Cookies,部分网站功能可能无法正常使用,包括但不限于:</p>
<ul>
<li>无法保持登录状态,需要每次访问时重新登录</li>
<li>个性化设置无法保存</li>
<li>某些服务可能完全无法使用</li>
</ul>
<p>继续使用本网站即表示您同意我们按照本说明使用Cookies技术。</p>
</div>
</div>'
],
];

125
app/log/driver/Monolog.php Normal file
View File

@@ -0,0 +1,125 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2021 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare (strict_types = 1);
namespace app\log\driver;
use think\App;
use think\contract\LogHandlerInterface;
use think\facade\Config;
/**
* 本地化调试输出到文件
*/
class Monolog implements LogHandlerInterface
{
/**
* 配置参数
* @var array
*/
protected $config = [
'time_format' => 'c',
'json_options' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
];
/**
* 日志写入接口
* @access public
* @param array $log 日志信息
* @return bool
*/
public function save(array $log): bool
{
$info = [];
// 日志信息封装
$time = \DateTime::createFromFormat('0.u00 U', microtime())->setTimezone(new \DateTimeZone(date_default_timezone_get()))->format($this->config['time_format']);
foreach ($log as $type => $val) {
$message = [];
foreach ($val as $msg) {
$message[] = json_encode(['time' => $time, 'type' => $type, 'msg' => $msg], $this->config['json_options']) ;
}
$info[$type] = $message;
}
if ($info) {
return $this->write($info);
}
return true;
}
/**
* 日志写入
* @access protected
* @param array $message 日志信息
* @param string $destination 日志文件
* @return bool
*/
protected function write(array $message): bool
{
$tcp_log_url = env('TCP_LOG_URL');
$tcp_log_port = (int) env('TCP_LOG_PORT');
$project = env('PROJECT_NAME');
// 快速失败:配置缺失
if (!$tcp_log_url || !$tcp_log_port || !$project) {
return true; // 或 error_log("Log config missing");
}
// 1. 安全序列化并限制大小(例如最大 64KB)
$maxSize = 64 * 1024; // 64KB
$json = json_encode([
'message' => $message,
'project' => $project
], $this->config['json_options'] ?? 0);
if ($json === false) {
error_log("Failed to encode log message: " . json_last_error_msg());
return true;
}
// 截断过大的日志(保留结构完整性)
if (strlen($json) > $maxSize) {
// 尝试只截断 message 内容(更智能)
$fallbackMessage = [
'message' => '[TRUNCATED] Log too large (' . strlen($json) . ' bytes)',
'project' => $project,
'original_size_bytes' => strlen($json)
];
$json = json_encode($fallbackMessage, $this->config['json_options'] ?? 0);
}
// 2. 添加换行符(Logstash tcp + json_lines 必需)
$payload = $json . "\n";
// 3. 建立连接(适当延长超时)
$socket = @fsockopen($tcp_log_url, $tcp_log_port, $errno, $errstr, 2); // 2秒超时
if (!$socket) {
error_log("Log socket connect failed to {$tcp_log_url}:{$tcp_log_port} - {$errstr} ({$errno})");
return true; // 不影响主流程
}
// 4. 发送数据(抑制 fwrite 警告,但可选记录)
$bytesWritten = @fwrite($socket, $payload);
$expected = strlen($payload);
if ($bytesWritten === false || $bytesWritten !== $expected) {
error_log("Partial or failed log send to {$tcp_log_url}:{$tcp_log_port} (sent {$bytesWritten}/{$expected} bytes)");
}
// 5. 确保关闭 socket
fclose($socket);
return true;
}
}

11
app/middleware.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
// 全局中间件定义文件
return [
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
\think\middleware\LoadLangPack::class,
// Session初始化
\think\middleware\SessionInit::class,
\app\middleware\LogRecorder::class,
];

View File

@@ -0,0 +1,41 @@
<?php
declare (strict_types = 1);
namespace app\middleware;
use think\facade\Log;
class LogRecorder
{
/**
* 处理请求
*
* @param \think\Request $request
* @param \Closure $next
* @return Response
*/
public function handle($request, \Closure $next)
{
// 记录请求信息
$requestInfo = [
'time' => date('Y-m-d H:i:s'),
'method' => $request->method(),
'uri' => $request->url(),
'params' => $request->param(),
'headers' => $request->header(),
'ip' => $request->ip(),
];
Log::write($requestInfo, 'request');
// 继续处理请求
$response = $next($request);
// 记录响应信息
$responseInfo = [
'status' => $response->getCode(),
'data' => $response->getContent(),
];
Log::write($responseInfo, 'response');
return $response;
}
}

9
app/provider.php Normal file
View File

@@ -0,0 +1,9 @@
<?php
use app\ExceptionHandle;
use app\Request;
// 容器Provider定义文件
return [
'think\Request' => Request::class,
'think\exception\Handle' => ExceptionHandle::class,
];

9
app/service.php Normal file
View File

@@ -0,0 +1,9 @@
<?php
use app\AppService;
// 系统服务定义文件
// 服务在完成全局初始化之后执行
return [
AppService::class,
];

View File

@@ -0,0 +1,126 @@
<?php
namespace app\service;
use Aws\S3\S3Client;
use think\facade\Log;
use think\File;
class AwsUploadService
{
/**
* 处理表单文件上传并转发到目标服务器
*
* @param string $fileField 表单文件字段名
* @param array $extraFields 额外传递的字段
* @return array 包含上传结果的数组
*/
public function uploadAndForward( File $file, string $fileField,array $extraFields = []): array
{
$mimeType = $file->getMime();
$s3config = config('filesystem.disks.s3');
$s3 = new S3Client($s3config);
try {
$config = config('app.upload_conf');
$configs=[];
foreach ($config as $key=>$con){
$configs[] = $key.':'.$con;
}
// 验证文件
$validate = validate([
$fileField =>implode('|',$configs),
]);
if (!$validate->check([$fileField => $file])) {
return $this->createErrorResult($validate->getError());
}
// 根据文件类型设置 Content-Type
if (in_array($mimeType, config('app.imageMimeTypes'))) {
$contentType = $mimeType; // 使用图片的实际 MIME 类型
} else {
$contentType = 'application/octet-stream'; // 非图片文件使用默认类型
}
$checkBucket = $this->checkBucket($s3, $extraFields['Bucket']);
if (!$checkBucket) {
return $this->createErrorResult('Bucket error');
}
$s3->putObject([
'Bucket' => $extraFields['Bucket'],
'Key' => $extraFields['Key'],
'Body' => fopen($file->getRealPath(), 'r'),
'ACL' => 'public-read',
'ContentType' => $contentType, // 设置检测到的 Content-Type
]);
return [
'code' => 1,
'data' =>[
'savename'=>$s3config['endpoint'].'/'.$extraFields['Bucket'].'/'.$extraFields['Key']
] ,
];
} catch (\Exception $e) {
return $this->createErrorResult('上传过程中发生异常: ' . $e->getMessage());
}
}
public function checkBucket($s3, $bucket)
{
try {
$buckets = $s3->listBuckets()->get('Buckets');
$buckets_arr = array_column($buckets, 'Name');
if (!in_array($bucket, $buckets_arr)) {
$s3->createBucket([
'Bucket' => $bucket,
]);
$policy = [
'Version' => '2012-10-17',
'Statement' => [
[
'Effect' => 'Allow',
'Principal' => ['AWS' => ['*']],
'Action' => [
's3:GetBucketLocation',
's3:ListBucket',
's3:ListBucketMultipartUploads',
],
'Resource' => "arn:aws:s3:::$bucket",
],
[
'Effect' => 'Allow',
'Principal' => ['AWS' => ['*']],
'Action' => [
's3:DeleteObject',
's3:GetObject',
's3:ListMultipartUploadParts',
's3:PutObject',
's3:AbortMultipartUpload',
],
'Resource' => "arn:aws:s3:::$bucket/*",
],
],
];
$s3->putBucketPolicy([
'Bucket' => $bucket,
'Policy' => json_encode($policy),
]);
}
return true;
} catch (\Exception $e) {
Log::info('checkBucket error:' . $e->getMessage());
return false;
}
}
/**
* 创建错误结果数组
*
* @param string $message 错误信息
* @return array 错误结果
*/
private function createErrorResult(string $message): array
{
return [
'code' => 0,
'error' => $message
];
}
}

View File

@@ -0,0 +1,122 @@
<?php
namespace app\service;
use Curl\Curl;
class BaiduOcrService
{
private $url = 'https://uniuser.evus.cn/home/upload/';
/**
*
*护照识别
* @param string $fileData 图片的二进制数据
* @return array
*/
function passport($fileData)
{
if ($fileData === false) {
return [
'code' => 0,
'msg' => '无法读取上传的文件',
];
}
$curl = new Curl();
$curl->setOpt(CURLOPT_SSL_VERIFYPEER, false);
$curl->setOpt(CURLOPT_SSL_VERIFYHOST, 0);
$curl->post($this->url.'passport', [
'image' => $fileData,
]);
if ($curl->error) {
return [
'code' => 0,
'msg' => $curl->errorMessage,
];
} else {
if (!$curl->response->code){
return [
'code' => 0,
'msg' => '解析失败',
];
}
return [
'code' => 1,
'data' => $curl->response->data,
];
}
}
/**
*
*身份证识别
* @param string $fileData 图片的二进制数据
* @return array
*/
function identification($fileData)
{
if ($fileData === false) {
return [
'code' => 0,
'msg' => '无法读取上传的文件',
];
}
$curl = new Curl();
$curl->post($this->url.'identification', [
'image' => $fileData,
]);
if ($curl->error) {
return [
'code' => 0,
'msg' => $curl->errorMessage,
];
} else {
if (!$curl->response->code){
return [
'code' => 0,
'msg' => '解析失败',
];
}
return [
'code' => 1,
'data' => $curl->response->data,
];
}
}
/**
*
*护照识别
* @param string $fileData 图片的二进制数据
* @return array 包含压缩后图片信息的数组
*/
function visa($fileData)
{
if ($fileData === false) {
return [
'code' => 0,
'msg' => '无法读取上传的文件',
];
}
$curl = new Curl();
$curl->post($this->url.'visa', [
'image' => $fileData,
]);
if ($curl->error) {
return [
'code' => 0,
'msg' => $curl->errorMessage,
];
} else {
if (!$curl->response->code){
return [
'code' => 0,
'msg' => '解析失败',
];
}
return [
'code' => 1,
'data' => $curl->response->data,
];
}
}
}

View File

@@ -0,0 +1,185 @@
<?php
namespace app\service;
/**
* 压缩二进制流图片
*/
class CompressImgService
{
/**
* 压缩通过表单上传的图片
*
* @param string $fileData 图片的二进制数据
* @param int $quality 压缩质量(0-100,仅适用于JPEG和WebP)
* @param string|null $targetFormat 目标格式('jpeg', 'png', 'webp',默认使用原格式)
* @return array 包含压缩后图片信息的数组
*/
function compress($fileData, $quality = 80, $targetFormat = null)
{
// 读取上传的二进制数据
$imageData = file_get_contents($fileData);
if ($imageData === false) {
return [
'code' => 0,
'message' => '无法读取上传的文件',
];
}
// 获取图片信息
$imageInfo = getimagesizefromstring($imageData);
if (!$imageInfo) {
return [
'code' => 0,
'message' => '无法解析图片信息',
];
}
// 确定原始和目标格式
$originalMimeType = $imageInfo['mime'];
$originalExtension = image_type_to_extension($imageInfo[2], false);
if ($targetFormat === null) {
$targetFormat = $originalExtension;
}
// 创建图片资源
switch (strtolower($originalExtension)) {
case 'jpeg':
case 'jpg':
$image = imagecreatefromstring($imageData);
break;
case 'png':
$image = imagecreatefromstring($imageData);
break;
case 'webp':
$image = imagecreatefromstring($imageData);
break;
default:
return [
'code' => 0,
'message' => '不支持的图片格式',
];
}
if (!$image) {
return [
'code' => 0,
'message' => '无法创建图片资源',
];
}
// 压缩并转换图片
ob_start();
switch (strtolower($targetFormat)) {
case 'jpeg':
case 'jpg':
imagejpeg($image, null, $quality);
$compressedMimeType = 'image/jpeg';
break;
case 'png':
$pngQuality = 9 - floor($quality / 11);
imagepng($image, null, $pngQuality);
$compressedMimeType = 'image/png';
break;
case 'webp':
if (function_exists('imagewebp')) {
imagewebp($image, null, $quality);
$compressedMimeType = 'image/webp';
} else {
imagejpeg($image, null, $quality);
$compressedMimeType = 'image/jpeg';
}
break;
default:
imagedestroy($image);
ob_end_clean();
return [
'code' => 0,
'message' => "不支持的目标格式: {$targetFormat}",
];
}
$compressedData = ob_get_clean();
imagedestroy($image);
// 返回结果
return [
'code' => 1,
'compressed_data' => $compressedData,
'base64' => 'data:' . $compressedMimeType . ';base64,' . base64_encode($compressedData),
];
}
public function compressImage($filePath, $fileSize)
{
// 获取图片信息
$imageInfo = getimagesize($filePath);
if (!$imageInfo) {
return false;
}
$mime = $imageInfo['mime'];
// 根据MIME类型创建图像资源
switch ($mime) {
case 'image/jpeg':
$image = imagecreatefromjpeg($filePath);
break;
case 'image/png':
$image = imagecreatefrompng($filePath);
break;
case 'image/gif':
$image = imagecreatefromgif($filePath);
break;
default:
return false;
}
if (!$image) {
return false;
}
// 计算压缩质量(根据文件大小动态调整)
$originalQuality = 85; // 初始质量
$targetSize = 2.5 * 1024 * 1024; // 目标大小2.5MB
// 如果文件很大,降低初始质量
if ($fileSize > 5 * 1024 * 1024) {
$quality = 75;
} elseif ($fileSize > 10 * 1024 * 1024) {
$quality = 65;
} else {
$quality = $originalQuality;
}
// 创建临时文件
$tempFile = tempnam(sys_get_temp_dir(), 'compressed_');
// 保存压缩后的图片
switch ($mime) {
case 'image/jpeg':
imagejpeg($image, $tempFile, $quality);
break;
case 'image/png':
// PNG使用压缩级别(0-9),需要转换
$pngQuality = 9 - round(($quality / 100) * 9);
imagepng($image, $tempFile, $pngQuality);
break;
case 'image/gif':
imagegif($image, $tempFile);
break;
}
// 释放内存
imagedestroy($image);
// 检查压缩后文件大小,如果仍然大于3MB,继续压缩
$compressedSize = filesize($tempFile);
if ($compressedSize > 3 * 1024 * 1024) {
// 递归压缩直到满足要求
return $this->compressImage($tempFile, $compressedSize);
}
return $tempFile;
}
}

301
app/service/OssService.php Normal file
View File

@@ -0,0 +1,301 @@
<?php
namespace app\service;
use AlibabaCloud\Oss\V2 as Oss;
use Exception;
final class OssService
{
private Oss\Client $client;
private string $bucket;
private string $region;
private ?string $endpoint;
/**
* @param array{
* region: string,
* bucket: string,
* endpoint?: string,
* access_key_id?: string,
* access_key_secret?: string,
* session_token?: string
* } $config
*/
public function __construct(array $config)
{
$this->region = $config['region'] ?? '';
$this->bucket = $config['bucket'] ?? '';
$this->endpoint = $config['endpoint'] ?? null;
if ($this->region === '' || $this->bucket === '') {
throw new Exception('OSS config missing: region/bucket');
}
if (!empty($config['access_key_id']) && !empty($config['access_key_secret'])) {
$credentialsProvider = new FixedCredentialsProvider(
(string)$config['access_key_id'],
(string)$config['access_key_secret'],
$config['session_token'] ?? null
);
} else {
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
}
$cfg = Oss\Config::loadDefault();
$cfg->setCredentialsProvider($credentialsProvider);
$cfg->setRegion($this->region);
if ($this->endpoint) {
$cfg->setEndpoint($this->endpoint);
if ($this->shouldUseCname($this->endpoint)) {
$cfg->setUseCname(true);
}
}
$this->client = new Oss\Client($cfg);
$this->assertCredentialsVisible($config);
}
public function upload(string $source, string $key, ?string $bucket = null, array $options = []): array
{
if ($this->isBase64DataUri($source)) {
return $this->uploadFromBase64($source, $key, $bucket, $options);
}
if ($this->isUrl($source)) {
return $this->uploadFromUrl($source, $key, $bucket, $options);
}
return $this->uploadFromFile($source, $key, $bucket, $options);
}
public function uploadFromBase64(string $base64, string $key, ?string $bucket = null, array $options = []): array
{
$contentType = null;
$payload = $base64;
if (preg_match('/^data:([a-zA-Z0-9.+\\/-]+);base64,(.*)$/s', $base64, $m)) {
$contentType = strtolower((string)$m[1]);
$payload = (string)$m[2];
}
$payload = preg_replace('/\\s+/', '', $payload ?? '');
if ($payload === '') {
throw new Exception('Base64 payload is empty');
}
$binary = base64_decode($payload, true);
if ($binary === false) {
throw new Exception('Invalid base64 payload');
}
if ($contentType && empty($options['contentType'])) {
$options['contentType'] = $contentType;
}
return $this->uploadFromBinary($binary, $key, $bucket, $options);
}
public function uploadFromBinary(string $binary, string $key, ?string $bucket = null, array $options = []): array
{
if ($binary === '') {
throw new Exception('Binary payload is empty');
}
$stream = fopen('php://temp', 'wb+');
if ($stream === false) {
throw new Exception('Unable to create temporary stream for binary upload');
}
fwrite($stream, $binary);
rewind($stream);
return $this->putObjectFromResource($stream, $key, $bucket, $options);
}
public function uploadFromFile(string $filePath, string $key, ?string $bucket = null, array $options = []): array
{
if (!is_file($filePath)) {
throw new Exception("Local file not found: {$filePath}");
}
$fp = fopen($filePath, 'rb');
if ($fp === false) {
throw new Exception("Unable to open local file: {$filePath}");
}
return $this->putObjectFromResource($fp, $key, $bucket, $options);
}
public function uploadFromUrl(string $url, string $key, ?string $bucket = null, array $options = []): array
{
$fp = @fopen($url, 'rb');
if ($fp !== false) {
return $this->putObjectFromResource($fp, $key, $bucket, $options);
}
$tmp = tmpfile();
if ($tmp === false) {
throw new Exception('Unable to create tmpfile() for remote download');
}
$this->downloadToStreamByCurl($url, $tmp);
rewind($tmp);
return $this->putObjectFromResource($tmp, $key, $bucket, $options);
}
public function buildObjectUrl(string $key, ?string $bucket = null, bool $useHttps = true): string
{
$bucket = $bucket ?: $this->bucket;
$key = ltrim($key, '/');
$endpoint = $this->endpoint ?: sprintf('oss-%s.aliyuncs.com', $this->region);
$host = $this->extractEndpointHost($endpoint);
$scheme = $useHttps ? 'https' : 'http';
$encodedKey = implode('/', array_map('rawurlencode', explode('/', $key)));
if ($this->shouldUseCname($endpoint)) {
return sprintf('%s://%s/%s', $scheme, $host, $encodedKey);
}
return sprintf('%s://%s.%s/%s', $scheme, $bucket, $host, $encodedKey);
}
private function putObjectFromResource($resource, string $key, ?string $bucket = null, array $options = []): array
{
$bucket = $bucket ?: $this->bucket;
$key = ltrim($key, '/');
$metadata = $options['metadata'] ?? [];
$contentType = $options['contentType'] ?? null;
$acl = $options['acl'] ?? null;
$body = Oss\Utils::streamFor($resource);
$request = new Oss\Models\PutObjectRequest(
bucket: $bucket,
key: $key,
metadata: $metadata ?: null,
contentType: $contentType,
objectAcl: $acl
);
$request->body = $body;
$result = $this->client->putObject($request);
return [
'statusCode' => $result->statusCode,
'requestId' => $result->requestId,
'etag' => $result->etag,
'bucket' => $bucket,
'key' => $key,
];
}
private function downloadToStreamByCurl(string $url, $destStream): void
{
if (!function_exists('curl_init')) {
throw new Exception('cURL extension is required when allow_url_fopen is disabled.');
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_FILE => $destStream,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 60,
CURLOPT_FAILONERROR => true,
CURLOPT_USERAGENT => 'OssService/1.0',
]);
$ok = curl_exec($ch);
if ($ok !== true) {
$err = curl_error($ch);
$code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
throw new Exception("Failed to download remote file. HTTP={$code}, error={$err}");
}
curl_close($ch);
}
private function isUrl(string $value): bool
{
return (bool)filter_var($value, FILTER_VALIDATE_URL);
}
private function isBase64DataUri(string $value): bool
{
return (bool)preg_match('/^data:[a-zA-Z0-9.+\\/-]+;base64,/i', $value);
}
private function assertCredentialsVisible(array $config): void
{
if (!empty($config['access_key_id']) && !empty($config['access_key_secret'])) {
return;
}
$ak = getenv('OSS_ACCESS_KEY_ID');
$sk = getenv('OSS_ACCESS_KEY_SECRET');
if (empty($ak) || empty($sk)) {
throw new Exception(
"OSS credentials missing in PHP process env. " .
"getenv('OSS_ACCESS_KEY_ID')/getenv('OSS_ACCESS_KEY_SECRET') is empty. " .
"Fix: make sure the PHP runtime process can see env vars, or pass access_key_id/access_key_secret into OssService config."
);
}
}
private function shouldUseCname(string $endpoint): bool
{
$host = strtolower($this->extractEndpointHost($endpoint));
if ($host === '' || str_contains($host, 'aliyuncs.com') || str_contains($host, '.oss-')) {
return false;
}
return true;
}
private function extractEndpointHost(string $endpoint): string
{
$normalized = preg_match('#^https?://#i', $endpoint) ? $endpoint : 'https://' . ltrim($endpoint, '/');
return (string)(parse_url($normalized, PHP_URL_HOST) ?: '');
}
public function presignGetObjectUrl(string $key, ?string $bucket = null, int $expireSeconds = 900): array
{
$bucket = $bucket ?: $this->bucket;
$key = ltrim($key, '/');
$request = new Oss\Models\GetObjectRequest(bucket: $bucket, key: $key);
$result = $this->client->presign($request, [
'expires' => new \DateInterval("PT{$expireSeconds}S"),
]);
return [
'url' => $result->url,
'expire' => $expireSeconds,
'bucket' => $bucket,
'key' => $key,
];
}
}
final class FixedCredentialsProvider implements Oss\Credentials\CredentialsProvider
{
private string $ak;
private string $sk;
private ?string $token;
public function __construct(string $ak, string $sk, ?string $token = null)
{
$this->ak = $ak;
$this->sk = $sk;
$this->token = $token;
}
public function getCredentials(): Oss\Credentials\Credentials
{
return new Oss\Credentials\Credentials($this->ak, $this->sk, $this->token);
}
}

View File

@@ -0,0 +1,203 @@
<?php
namespace app\service;
use Throwable;
class OssUploadService
{
public function uploadBase64(string $fileName, string $base64File, array $extraFields = []): array
{
$fileContent = base64_decode($base64File, true);
if ($fileContent === false || $fileContent === '') {
return $this->createErrorResult('文件解析错误');
}
return $this->uploadBinaryContent($fileName, $fileContent, $extraFields);
}
public function uploadBinary(string $fileName, string $fileContent, array $extraFields = []): array
{
if ($fileContent === '') {
return $this->createErrorResult('Binary payload is empty');
}
return $this->uploadBinaryContent($fileName, $fileContent, $extraFields);
}
private function uploadBinaryContent(string $fileName, string $fileContent, array $extraFields = []): array
{
$uploadConfig = config('filesystem.upload_conf') ?: [];
$maxSize = (int)($uploadConfig['fileSize'] ?? 10 * 1024 * 1024);
if (strlen($fileContent) > $maxSize) {
return $this->createErrorResult('File size exceeds limit');
}
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
$allowedExts = $uploadConfig['fileExt'] ?? [];
if ($ext === '' || (!empty($allowedExts) && !in_array($ext, $allowedExts, true))) {
return $this->createErrorResult('File extension not allowed');
}
$bucket = (string)config('oss.bucket');
$folder = (string)($extraFields['Folder'] ?? ($extraFields['Bucket'] ?? ''));
$key = $extraFields['Key'] ?? basename($fileName);
$objectKey = $this->buildObjectKey($folder, (string)$key);
if ($bucket === '' || $objectKey === '') {
return $this->createErrorResult('Bucket or key missing');
}
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mimeType = (string)$finfo->buffer($fileContent);
try {
$service = new OssService(config('oss'));
$result = $service->uploadFromBinary($fileContent, $objectKey, $bucket, [
'contentType' => $this->resolveContentType($mimeType, $ext),
]);
$result['url'] = $service->buildObjectUrl($objectKey, $bucket);
$result['folder'] = $folder;
return [
'code' => 1,
'msg' => 'upload ok',
'data' => $result,
];
} catch (Throwable $e) {
$fallback = $this->saveToLocalFallback($fileContent, $bucket, $objectKey);
return $this->createErrorResult(
'OSS upload failed: ' . $e->getMessage(),
[
'bucket' => $bucket,
'key' => $objectKey,
'folder' => $folder,
'fallback_saved' => $fallback['saved'],
'fallback_path' => $fallback['path'],
'fallback_error' => $fallback['error'],
]
);
}
}
private function buildObjectKey(string $folder, string $key): string
{
$folder = trim(str_replace('\\', '/', $folder), '/');
$key = trim(str_replace('\\', '/', $key), '/');
if ($folder === '') {
return $key;
}
if ($key === '') {
return $folder;
}
if (str_starts_with($key . '/', $folder . '/')) {
return $key;
}
return $folder . '/' . $key;
}
private function saveToLocalFallback(string $fileContent, string $bucket, string $key): array
{
$baseDir = $this->resolveFallbackBaseDir();
$safeBucket = $this->sanitizePathSegment($bucket);
$safeKey = $this->sanitizeObjectKey($key);
$fullPath = $baseDir . DIRECTORY_SEPARATOR . $safeBucket . DIRECTORY_SEPARATOR . $safeKey;
$directory = dirname($fullPath);
try {
if (!is_dir($directory) && !mkdir($directory, 0777, true) && !is_dir($directory)) {
throw new \RuntimeException('Unable to create fallback directory');
}
if (file_put_contents($fullPath, $fileContent) === false) {
throw new \RuntimeException('Unable to write fallback file');
}
return [
'saved' => true,
'path' => $fullPath,
'error' => null,
];
} catch (Throwable $e) {
return [
'saved' => false,
'path' => $fullPath,
'error' => $e->getMessage(),
];
}
}
private function resolveFallbackBaseDir(): string
{
$uploadConfig = config('filesystem.upload_conf') ?: [];
$configured = (string)($uploadConfig['fallbackDir'] ?? '');
if ($configured !== '') {
return rtrim($configured, "\\/");
}
$localRoot = (string)(config('filesystem.disks.local.root') ?? '');
if ($localRoot !== '') {
return rtrim($localRoot, "\\/") . DIRECTORY_SEPARATOR . 'oss-fallback';
}
return app()->getRuntimePath() . 'storage' . DIRECTORY_SEPARATOR . 'oss-fallback';
}
private function sanitizeObjectKey(string $key): string
{
$normalized = str_replace('\\', '/', $key);
$segments = array_filter(explode('/', $normalized), static function (string $segment): bool {
return $segment !== '' && $segment !== '.' && $segment !== '..';
});
if ($segments === []) {
return 'unnamed-file';
}
$safeSegments = array_map([$this, 'sanitizePathSegment'], $segments);
return implode(DIRECTORY_SEPARATOR, $safeSegments);
}
private function sanitizePathSegment(string $segment): string
{
$cleaned = preg_replace('/[^A-Za-z0-9._-]/', '_', $segment) ?? '';
return $cleaned !== '' ? $cleaned : 'unknown';
}
private function resolveContentType(string $mimeType, string $ext): string
{
if ($mimeType !== '' && $mimeType !== 'application/octet-stream') {
return $mimeType;
}
return match ($ext) {
'jpg', 'jpeg' => 'image/jpeg',
'png' => 'image/png',
'gif' => 'image/gif',
'webp' => 'image/webp',
'bmp' => 'image/bmp',
'svg' => 'image/svg+xml',
'pdf' => 'application/pdf',
'doc' => 'application/msword',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
default => 'application/octet-stream',
};
}
private function createErrorResult(string $message, array $data = []): array
{
$result = [
'code' => 0,
'msg' => $message,
];
if ($data !== []) {
$result['data'] = $data;
}
return $result;
}
}

View File

@@ -0,0 +1,233 @@
<?php
namespace app\service;
use Throwable;
class PassportOcrService
{
private const PASSPORT_ENDPOINT = '/ocr/passport/base64';
private const IDCARD_ENDPOINT = '/ocr/idcard/base64';
private const VISA_ENDPOINT = '/ocr/visa-number/base64';
public function passport($fileData): array
{
return $this->request(self::PASSPORT_ENDPOINT, $fileData);
}
public function identification($fileData): array
{
return $this->request(self::IDCARD_ENDPOINT, $fileData);
}
public function visa($fileData): array
{
return $this->request(self::VISA_ENDPOINT, $fileData);
}
private function request(string $endpoint, $fileData): array
{
if (!is_string($fileData) || $fileData === '') {
return $this->error('Unable to read uploaded file');
}
$config = $this->loadConfig();
if ($config['base_url'] === '' || $config['app_id'] === '' || $config['secret'] === '') {
return $this->error('OCR config missing: app.OCR_BASE_URL, app.OCR_APP_ID and app.OCR_SECRET are required');
}
try {
$payload = $this->buildPayload($fileData, $config);
} catch (Throwable $e) {
return $this->error('Unable to build OCR payload: ' . $e->getMessage());
}
$timestamp = (string) time();
$signature = hash_hmac('sha256', $config['app_id'] . "\n" . $timestamp, $config['secret']);
$headers = [
'Content-Type: application/json',
'Accept: application/json',
'X-App-Id: ' . $config['app_id'],
'X-Timestamp: ' . $timestamp,
'X-Signature: ' . $signature,
];
if ($config['origin'] !== '') {
$headers[] = 'Origin: ' . $config['origin'];
}
$ch = curl_init($config['base_url'] . $endpoint);
if ($ch === false) {
return $this->error('Unable to initialize cURL');
}
try {
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
CURLOPT_TIMEOUT => $config['timeout'],
CURLOPT_CONNECTTIMEOUT => $config['connect_timeout'],
]);
if (!$config['verify_ssl']) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
}
$response = curl_exec($ch);
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($response === false) {
return $this->error('OCR request failed: ' . curl_error($ch));
}
$decoded = json_decode((string) $response, true);
if (!is_array($decoded)) {
return $this->error('OCR response is not valid JSON', [
'http_code' => $httpCode,
'response' => substr((string) $response, 0, 300),
]);
}
return $decoded;
} finally {
curl_close($ch);
}
}
private function buildPayload(string $fileData, array $config): array
{
$mimeType = $this->detectMimeType($fileData);
$extension = $this->extensionForMimeType($mimeType);
return [
'filename' => 'upload.' . $extension,
'content_type' => $mimeType,
'image_base64' => 'data:' . $mimeType . ';base64,' . base64_encode($fileData),
'auto_rotate' => $config['auto_rotate'],
'return_debug' => $config['return_debug'],
];
}
private function loadConfig(): array
{
$config = config('ocr') ?: [];
return [
'base_url' => rtrim((string) (config('app.OCR_BASE_URL') ?? ''), '/'),
'app_id' => (string) (config('app.OCR_APP_ID') ?? ''),
'secret' => (string) (config('app.OCR_SECRET') ?? ''),
'origin' => $this->resolveOrigin((string) (config('app.OCR_ORIGIN') ?? ($config['origin'] ?? ''))),
'timeout' => max(1, (int) ($config['timeout'] ?? 60)),
'connect_timeout' => max(1, (int) ($config['connect_timeout'] ?? 10)),
'auto_rotate' => $this->boolValue($config['auto_rotate'] ?? true),
'return_debug' => $this->boolValue($config['return_debug'] ?? false),
'verify_ssl' => $this->boolValue($config['verify_ssl'] ?? true),
];
}
private function resolveOrigin(string $configuredOrigin): string
{
$configuredOrigin = trim($configuredOrigin);
if ($configuredOrigin !== '') {
return rtrim($configuredOrigin, '/');
}
$requestOrigin = trim((string) ($_SERVER['HTTP_ORIGIN'] ?? ''));
if ($this->isValidOrigin($requestOrigin)) {
return rtrim($requestOrigin, '/');
}
$host = trim((string) ($_SERVER['HTTP_HOST'] ?? ''));
if ($host === '' || !preg_match('/^[A-Za-z0-9.-]+(?::\d+)?$/', $host)) {
return '';
}
return $this->currentScheme() . '://' . $host;
}
private function isValidOrigin(string $origin): bool
{
if ($origin === '') {
return false;
}
$parts = parse_url($origin);
if (!is_array($parts)) {
return false;
}
$scheme = strtolower((string) ($parts['scheme'] ?? ''));
return in_array($scheme, ['http', 'https'], true)
&& !empty($parts['host'])
&& empty($parts['path'])
&& empty($parts['query'])
&& empty($parts['fragment']);
}
private function currentScheme(): string
{
$forwardedProto = trim((string) ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? ''));
if ($forwardedProto !== '') {
$forwardedProto = strtolower(trim(explode(',', $forwardedProto)[0]));
if (in_array($forwardedProto, ['http', 'https'], true)) {
return $forwardedProto;
}
}
$requestScheme = strtolower((string) ($_SERVER['REQUEST_SCHEME'] ?? ''));
if (in_array($requestScheme, ['http', 'https'], true)) {
return $requestScheme;
}
$https = strtolower((string) ($_SERVER['HTTPS'] ?? ''));
return $https !== '' && $https !== 'off' ? 'https' : 'http';
}
private function detectMimeType(string $fileData): string
{
if (!class_exists(\finfo::class)) {
return 'image/jpeg';
}
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->buffer($fileData);
if (is_string($mimeType) && $mimeType !== '' && $mimeType !== 'application/octet-stream') {
return $mimeType;
}
return 'image/jpeg';
}
private function extensionForMimeType(string $mimeType): string
{
return match ($mimeType) {
'image/png' => 'png',
'image/gif' => 'gif',
'image/webp' => 'webp',
'image/bmp', 'image/x-ms-bmp' => 'bmp',
default => 'jpg',
};
}
private function boolValue($value): bool
{
$parsed = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
return $parsed ?? (bool) $value;
}
private function error(string $message, array $data = []): array
{
$result = [
'code' => 0,
'msg' => $message,
];
if ($data !== []) {
$result['data'] = $data;
}
return $result;
}
}

View File

@@ -0,0 +1,173 @@
<?php
declare(strict_types=1);
namespace app\service;
final class SeoMetaService
{
private array $config;
public function __construct(?array $config = null)
{
$this->config = $config ?? (array) config('seo');
}
public function forRoute(
string $app,
string $controller,
string $action,
array $query = [],
array $overrides = []
): array {
$app = strtolower(trim($app));
$controller = strtolower(trim($controller));
$action = strtolower(trim($action));
$routeKey = implode('/', [$app, $controller, $action]);
$page = (array) (($this->config['pages'] ?? [])[$routeKey] ?? []);
$data = array_merge($page, $overrides);
$title = trim((string) ($data['title'] ?? $this->config['default_title'] ?? ''));
$siteName = trim((string) ($this->config['site_name'] ?? ''));
if ($siteName !== '' && $title !== '' && stripos($title, $siteName) === false) {
$title .= ' - ' . $siteName;
}
$robots = (string) ($data['robots'] ?? $this->config['default_robots'] ?? 'noindex,follow');
$noindexControllers = array_map(
'strtolower',
(array) ($this->config['noindex_controllers'] ?? [])
);
if (in_array($controller, $noindexControllers, true)) {
$robots = 'noindex,follow';
}
foreach ((array) ($this->config['sensitive_query_keys'] ?? []) as $key) {
if (isset($query[$key]) && $query[$key] !== '') {
$robots = 'noindex,nofollow';
break;
}
}
$canonical = trim((string) ($data['canonical'] ?? ''));
if ($canonical === '') {
$canonical = $this->canonical(
(string) ($data['canonical_path'] ?? ''),
$query,
(array) ($data['canonical_query_keys'] ?? [])
);
}
return [
'title' => $title,
'description' => trim((string) (
$data['description']
?? $this->config['default_description']
?? ''
)),
'keywords' => trim((string) (
$data['keywords']
?? $this->config['default_keywords']
?? ''
)),
'robots' => $robots,
'canonical' => $canonical,
'lang' => (string) ($data['lang'] ?? $this->config['lang'] ?? 'zh-CN'),
'applicable_device' => (string) (
$data['applicable_device']
?? $this->config['applicable_device']
?? 'pc,mobile'
),
'baidu_site_verification' => trim((string) (
$this->config['baidu_site_verification']
?? ''
)),
];
}
public function canonical(
string $path,
array $query = [],
array $allowedQueryKeys = []
): string {
$baseUrl = $this->normalizedBaseUrl();
if ($baseUrl === '' || $path === '') {
return '';
}
if (str_starts_with($path, '//') || parse_url($path, PHP_URL_HOST) !== null) {
return '';
}
$path = '/' . ltrim($path, '/');
$canonicalQuery = [];
foreach ($allowedQueryKeys as $key) {
if (!array_key_exists($key, $query) || is_array($query[$key])) {
continue;
}
if ($query[$key] === '' || $query[$key] === null) {
continue;
}
$value = (string) $query[$key];
if (in_array($key, ['id', 'page'], true)) {
if (preg_match('/^[1-9]\d*$/', $value) !== 1) {
continue;
}
if ($key === 'page' && $value === '1') {
continue;
}
}
$canonicalQuery[$key] = $value;
}
$url = $baseUrl . ($path === '/' ? '/' : rtrim($path, '/'));
if ($canonicalQuery !== []) {
$url .= '?' . http_build_query($canonicalQuery, '', '&', PHP_QUERY_RFC3986);
}
return $url;
}
public function descriptionFromHtml(string $html, int $maxLength = 100): string
{
$html = (string) preg_replace(
'#<(script|style)\b[^>]*>.*?</\1>#isu',
' ',
$html
);
$text = (string) preg_replace('/<[^>]+>/u', ' ', $html);
$text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
$text = trim((string) preg_replace('/\s+/u', ' ', $text));
if ($maxLength < 1) {
return '';
}
if (function_exists('mb_substr')) {
return mb_substr($text, 0, $maxLength, 'UTF-8');
}
return substr($text, 0, $maxLength);
}
public function baseUrl(): string
{
return $this->normalizedBaseUrl();
}
private function normalizedBaseUrl(): string
{
$baseUrl = rtrim(trim((string) ($this->config['base_url'] ?? '')), '/');
if ($baseUrl === '' || filter_var($baseUrl, FILTER_VALIDATE_URL) === false) {
return '';
}
$scheme = strtolower((string) parse_url($baseUrl, PHP_URL_SCHEME));
if (!in_array($scheme, ['http', 'https'], true)) {
return '';
}
return $baseUrl;
}
}

View File

@@ -0,0 +1,174 @@
<?php
declare(strict_types=1);
namespace app\service;
final class SitemapService
{
private string $baseUrl;
/** @var string[] */
private array $excludedPrefixes;
public function __construct(string $baseUrl, array $excludedPrefixes = [])
{
$this->baseUrl = $this->normalizeBaseUrl($baseUrl);
$this->excludedPrefixes = $excludedPrefixes ?: [
'/home/login',
'/home/user',
'/home/pay',
'/home/payesta',
'/home/invoice',
'/home/miniinvoice',
'/home/multiple',
'/home/update',
'/home/upload',
'/home/panel',
'/home/wxmini',
'/home/wechatpay',
'/home/usvisa',
];
}
public function render(array $entries): string
{
$urls = [];
foreach ($entries as $entry) {
if (!is_array($entry)) {
continue;
}
$path = $this->normalizePath((string) ($entry['path'] ?? ''));
if ($path === '' || !$this->isPublicPath($path)) {
continue;
}
$url = $this->buildUrl($path, (array) ($entry['query'] ?? []));
if ($url === '' || isset($urls[$url])) {
continue;
}
$lastmod = $this->normalizeLastmod((string) ($entry['lastmod'] ?? ''));
$urls[$url] = $lastmod;
}
$xml = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
foreach ($urls as $url => $lastmod) {
$xml .= " <url>\n";
$xml .= ' <loc>' . $this->escapeXml($url) . "</loc>\n";
if ($lastmod !== '') {
$xml .= ' <lastmod>' . $this->escapeXml($lastmod) . "</lastmod>\n";
}
$xml .= " </url>\n";
}
$xml .= "</urlset>\n";
return $xml;
}
public function renderRobots(array $disallowPaths): string
{
$lines = [
'User-agent: *',
'Allow: /',
];
foreach (array_unique($disallowPaths) as $path) {
$path = $this->normalizePath((string) $path);
if ($path !== '') {
$lines[] = 'Disallow: ' . $path;
}
}
if ($this->baseUrl !== '') {
$lines[] = '';
$lines[] = 'Sitemap: ' . $this->baseUrl . '/sitemap.xml';
}
return implode("\n", $lines) . "\n";
}
private function buildUrl(string $path, array $query): string
{
if ($this->baseUrl === '') {
return '';
}
$url = $this->baseUrl . ($path === '/' ? '/' : rtrim($path, '/'));
$query = array_filter(
$query,
static fn ($value): bool => is_scalar($value) && $value !== ''
);
if ($query !== []) {
$url .= '?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986);
}
return $url;
}
private function normalizeBaseUrl(string $baseUrl): string
{
$baseUrl = rtrim(trim($baseUrl), '/');
if ($baseUrl === '' || filter_var($baseUrl, FILTER_VALIDATE_URL) === false) {
return '';
}
$scheme = strtolower((string) parse_url($baseUrl, PHP_URL_SCHEME));
if (!in_array($scheme, ['http', 'https'], true)) {
return '';
}
return $baseUrl;
}
private function normalizePath(string $path): string
{
$path = trim($path);
if ($path === '' || str_starts_with($path, '//')) {
return '';
}
if (parse_url($path, PHP_URL_HOST) !== null) {
return '';
}
$path = (string) parse_url($path, PHP_URL_PATH);
if ($path === '') {
return '';
}
return '/' . ltrim($path, '/');
}
private function isPublicPath(string $path): bool
{
foreach ($this->excludedPrefixes as $prefix) {
$prefix = rtrim('/' . ltrim((string) $prefix, '/'), '/');
if ($path === $prefix || str_starts_with($path, $prefix . '/')) {
return false;
}
}
return true;
}
private function normalizeLastmod(string $lastmod): string
{
$lastmod = trim($lastmod);
if ($lastmod === '') {
return '';
}
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $lastmod) !== 1) {
return '';
}
[$year, $month, $day] = array_map('intval', explode('-', $lastmod));
return checkdate($month, $day, $year) ? $lastmod : '';
}
private function escapeXml(string $value): string
{
return htmlspecialchars($value, ENT_XML1 | ENT_QUOTES, 'UTF-8');
}
}

Some files were not shown because too many files have changed in this diff Show More