新增视频扫码

feat/task1-c-wallet
gongfuxiang 2023-03-03 18:07:09 +08:00
parent 31fb13222e
commit 0ff79d66dc
16 changed files with 342 additions and 61 deletions

View File

@ -325,6 +325,9 @@ class Common extends BaseController
// 默认不加载打印组件
$assign['is_load_hiprint'] = 0;
// 默认不加载视频扫码组件
$assign['is_load_video_scan'] = 0;
// 默认不加载echarts图表组件
$assign['is_load_echarts'] = 0;

View File

@ -38,7 +38,9 @@ class Order extends Base
// 模板数据
$assign = [
// 快递公司
'express_list' => ExpressService::ExpressList(),
'express_list' => ExpressService::ExpressList(),
// 默认不加载视频扫码组件
'is_load_video_scan' => 1,
];
// 发起支付 - 支付方式

View File

@ -4,8 +4,8 @@
<!-- 扩展 -->
{{block name="form_extend"}}
<!-- 取货弹窗 -->
<div class="am-modal am-radius am-nbfc" tabindex="-1" id="order-take-modal">
<div class="am-modal-dialog">
<div class="am-modal" tabindex="-1" id="order-take-modal">
<div class="am-modal-dialog am-radius am-nbfc">
<div class="am-modal-hd">
<a href="javascript: void(0)" class="am-close" data-am-modal-close>&times;</a>
</div>
@ -13,7 +13,10 @@
<form class="am-form form-validation-take" method="post" action="{{:MyUrl('admin/order/delivery')}}" request-type="ajax-reload">
<div class="am-form-group am-form-group-refreshing am-margin-bottom-0">
<label>{{:MyLang('order.form_item_take')}}</label>
<input type="text" autocomplete="off" name="extraction_code" placeholder="{{:MyLang('order.form_item_take_message')}}" minlength="4" maxlength="4" data-validation-message="{{:MyLang('order.form_item_take_message')}}" class="am-radius" required />
<div class="am-form-icon am-nbfc">
<i class="am-icon-camera common-scan-submit" data-back-fun="OrderTakeScanBackHandle"></i>
<input type="text" autocomplete="off" name="extraction_code" placeholder="{{:MyLang('order.form_item_take_message')}}" minlength="4" maxlength="4" data-validation-message="{{:MyLang('order.form_item_take_message')}}" class="am-radius am-form-field" required />
</div>
</div>
<div class="am-form-group am-form-group-refreshing">
<input type="hidden" name="id" value="0" />
@ -21,6 +24,14 @@
<button type="submit" class="am-btn am-btn-primary am-radius btn-loading-example am-btn-sm am-btn-block" data-am-loading="{loadingText:'{{:MyLang('processing_tips')}}'}">{{:MyLang('confirm_title')}}</button>
</div>
</form>
<script type="text/javascript">
// 扫码回调
function OrderTakeScanBackHandle(value)
{
$('form.form-validation-take input[name="extraction_code"]').val(value);
$('form.form-validation-take').find('button[type="submit"]').trigger('click');
}
</script>
</div>
</div>
</div>

View File

@ -50,9 +50,28 @@
</div>
</div>
<!-- commom html -->
<!-- 公共上传组件初始化 -->
<textarea id="upload-editor-view" data-url="{{if isset($is_load_upload_editor) and $is_load_upload_editor eq 1}}{{:MyUrl('admin/ueditor/index', ['path_type'=>empty($editor_path_type) ? 'common' : $editor_path_type])}}{{/if}}" style="display: none;"></textarea>
<!-- 公共视频扫码组件初始化 -->
<div class="am-popup am-radius popup-iframe popup-not-title" id="common-video-scan-popup">
<div class="am-popup-inner am-radius">
<span data-am-modal-close class="am-close am-close-alt am-icon-times"></span>
<div class="scanner">
<div class="scan-area">
<div class="mark top-left"></div>
<div class="mark top-right"></div>
<div class="mark bottom-left"></div>
<div class="mark bottom-right"></div>
</div>
<video id="video"></video>
<i class="am-icon-refresh am-icon-md video-scan-switch-camera-submit"></i>
<button type="button" class="am-btn am-btn-primary am-radius am-btn-xs video-scan-continue-submit am-hide">{{:MyLang('continue_scan_title')}}</button>
<div class="video-scan-audio-container"></div>
</div>
</div>
</div>
<!-- 公共底部钩子 -->
{{if !empty($plugins_admin_view_common_bottom_data) and is_array($plugins_admin_view_common_bottom_data)}}
{{foreach $plugins_admin_view_common_bottom_data as $hook}}
@ -160,6 +179,11 @@
<script type="text/javascript" src="{{$public_host}}static/common/lib/hiprint/hiprint.config.js"></script>
{{/if}}
<!-- 调用摄像头扫码js -->
{{if isset($is_load_video_scan) and $is_load_video_scan eq 1}}
<script type="text/javascript" src="{{$public_host}}static/common/lib/ZXing/ZXing.min.js"></script>
{{/if}}
<!-- 隐藏编辑器初始化 -->
<script type="text/javascript">
var upload_editor = UE.getEditor("upload-editor-view", {

View File

@ -422,6 +422,9 @@ class Common extends BaseController
// 默认不加载打印组件
$assign['is_load_hiprint'] = 0;
// 默认不加载视频扫码组件
$assign['is_load_video_scan'] = 0;
// 默认不加载echarts图表组件
$assign['is_load_echarts'] = 0;

View File

@ -19,7 +19,7 @@
<!-- content -->
<div class="am-container">
{{if !empty($data)}}
<article class="am-article am-margin-top-lg xo-padding-horizontal-md-xs">
<article class="am-article am-margin-top-lg">
<div class="am-article-hd am-text-center">
<h1 class="am-article-title am-text-default">{{$data.name}}</h1>
<p class="am-article-meta am-margin-top-xs">{{$data.upd_time_time}}</p>

View File

@ -1,6 +1,25 @@
<!-- commom html -->
<!-- 公共上传组件初始化 -->
<textarea id="upload-editor-view" data-url="{{if isset($is_load_upload_editor) and $is_load_upload_editor eq 1}}{{:MyUrl('index/ueditor/index', ['path_type'=>empty($editor_path_type) ? 'common' : $editor_path_type])}}{{/if}}" style="display: none;"></textarea>
<!-- 公共视频扫码组件初始化 -->
<div class="am-popup am-radius popup-iframe popup-not-title" id="common-video-scan-popup">
<div class="am-popup-inner am-radius">
<span data-am-modal-close class="am-close am-close-alt am-icon-times"></span>
<div class="scanner">
<div class="scan-area">
<div class="mark top-left"></div>
<div class="mark top-right"></div>
<div class="mark bottom-left"></div>
<div class="mark bottom-right"></div>
</div>
<video id="video"></video>
<i class="am-icon-refresh am-icon-md video-scan-switch-camera-submit"></i>
<button type="button" class="am-btn am-btn-primary am-radius am-btn-xs video-scan-continue-submit am-hide">{{:MyLang('continue_scan_title')}}</button>
<div class="video-scan-audio-container"></div>
</div>
</div>
</div>
<!-- footer start -->
{{if (!isset($page_pure) or $page_pure neq 1) and (!isset($is_footer) or $is_footer eq 1)}}
{{include file="public/footer_nav" /}}
@ -142,6 +161,11 @@
<script type="text/javascript" src="{{$public_host}}static/common/lib/hiprint/hiprint.config.js"></script>
{{/if}}
<!-- 调用摄像头扫码js -->
{{if isset($is_load_video_scan) and $is_load_video_scan eq 1}}
<script type="text/javascript" src="{{$public_host}}static/common/lib/ZXing/ZXing.min.js"></script>
{{/if}}
<!-- 隐藏编辑器初始化 -->
<script type="text/javascript">
var upload_editor = UE.getEditor("upload-editor-view", {

View File

@ -16,7 +16,6 @@
<meta name="apple-mobile-web-app-title" content="{{:MyC('home_site_name')}}">
<link rel="apple-touch-icon" href="{{:AttachmentPathViewHandle(MyC('home_site_logo_square'))}}">
<link rel="apple-touch-icon-precomposed" href="{{:AttachmentPathViewHandle(MyC('home_site_logo_square'))}}">
<link rel="stylesheet" type="text/css" href="{{$public_host}}static/common/lib/assets/css/amazeui.css?v={{:MyC('home_static_cache_version')}}" />
<link rel="stylesheet" type="text/css" href="{{$public_host}}static/common/lib/amazeui-switch/amazeui.switch.css?v={{:MyC('home_static_cache_version')}}" />
<link rel="stylesheet" type="text/css" href="{{$public_host}}static/common/lib/amazeui-chosen/amazeui.chosen.css?v={{:MyC('home_static_cache_version')}}" />

View File

@ -436,6 +436,7 @@ return [
'lan_title' => 'Longitude',
'lat_title' => 'Latitude',
'lang_title' => 'Language',
'continue_scan_title' => 'ContinueScan',
// 商品基础相关
'goods_name' => 'Goods Name',
'goods_stop_sale_title' => 'Stop Sale',

View File

@ -83,7 +83,7 @@ return [
'address_data_empty_tips' => '地址为空',
'assembly_not_init_tips' => '组件未初始化',
'not_specified_container_tips' => '未指定容器',
'not_specified_assembly_tips' => '未指定加载组',
'not_specified_assembly_tips' => '未指定加载组',
'not_specified_form_name_tips' => '未指定表单name名称',
'not_load_lib_hiprint_error' => '请先引入hiprint组件库',
],
@ -437,6 +437,7 @@ return [
'lan_title' => '经度',
'lat_title' => '纬度',
'lang_title' => '语言',
'continue_scan_title' => '继续扫码',
// 商品基础相关
'goods_name' => '商品名称',
'goods_stop_sale_title' => '暂停销售',

35
public/static/admin/default/css/order.css Executable file → Normal file
View File

@ -1,28 +1,37 @@
/**
* -
*/
* -
*/
.fictitious-container {
margin-top: 0 !important;
margin-top: 0 !important;
}
.fictitious-container li .am-u-sm-2 {
width: 60px;
padding: 0;
width: 60px;
padding: 0;
}
.fictitious-container li .am-u-sm-10 {
width: calc(100% - 60px);
padding: 0;
width: calc(100% - 60px);
padding: 0;
}
.fictitious-container li img {
max-width: 40px;
max-width: 40px;
}
.fictitious-container li {
border-color: #eee;
border-color: #eee;
}
.fictitious-container li:first-child {
border-top: 0;
padding-top: 0;
border-top: 0;
padding-top: 0;
}
.fictitious-container li:last-child {
border-bottom: 0;
padding-bottom: 0;
border-bottom: 0;
padding-bottom: 0;
}
/**
*
*/
.form-validation-take .common-scan-submit {
padding: 16px 5px;
left: 0 !important;
top: 0 !important;
}

View File

@ -892,45 +892,6 @@ button.colorpicker-submit img {
.form-search .so-list select, .form-search .so-list .chosen-container, .form-search .input input { width: calc(100% - 44px) !important; display: -webkit-inline-box; }
}
/**
*
*/
.xo-cursor-pr {
cursor: pointer;
}
@media only screen and (max-width: 641px) {
/* 水平方向内边距 */
.xo-padding-horizontal-md-xs {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.xo-padding-horizontal-md-sm {
padding-left: 1rem;
padding-right: 1rem;
}
}
@media only screen and (min-width: 640px) {
/* 水平方向内边距 */
.xo-padding-horizontal-md-xs {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.xo-padding-horizontal-md-sm {
padding-left: 1rem;
padding-right: 1rem;
}
}
@media only screen and (min-width: 1025px) {
/* 水平方向内边距 */
.xo-padding-horizontal-md-xs,
.xo-padding-horizontal-md-sm {
padding-left: 0;
padding-right: 0;
}
}
/**
*
*/
@ -1841,6 +1802,102 @@ a.input-clearout-submit:focus > i {
}
}
/**
*
*/
.common-scan-submit {
cursor: pointer;
}
#common-video-scan-popup .scanner {
position: relative;
overflow: hidden;
width: 100%;
height: 100%;
z-index: 0;
}
#common-video-scan-popup .scan-area {
position: absolute;
z-index: 10;
width: 300px;
height: 300px;
left: calc(50% - 150px);
top: calc(50% - 150px);
border: 1px solid white;
box-sizing: border-box;
box-shadow: 0 0 100px 1920px rgb(0 0 0 / 70%);
z-index: 1;
}
#common-video-scan-popup .scan-area .mark {
position: absolute;
width: 20px;
height: 20px;
border: 3px solid #3cb067;
background: transparent;
}
#common-video-scan-popup .mark {
padding: 0.2em;
background-color: #fcf8e3;
}
#common-video-scan-popup .scan-area .top-left {
top: -1px;
left: -1px;
border-color: #3cb067 transparent transparent #3cb067;
}
#common-video-scan-popup .scan-area .top-right {
top: -1px;
right: -1px;
border-color: #3cb067 #3cb067 transparent transparent;
}
#common-video-scan-popup .scan-area .bottom-left {
bottom: -1px;
left: -1px;
border-color: transparent transparent #3cb067 #3cb067;
}
#common-video-scan-popup .scan-area .bottom-right {
bottom: -1px;
right: -1px;
border-color: transparent #3cb067 #3cb067 transparent;
}
#common-video-scan-popup .scan-area::after {
content: ' ';
width: 100%;
display: block;
height: 4px;
position: absolute;
animation: move 3s linear infinite;
background: -moz-linear-gradient(left, rgba(76,175,80,0.25) 0%, rgba(76,175,80,0.25) 10%, rgba(76,175,80,1) 50%, rgba(76,175,80,0.25) 90%, rgba(76,175,80,0.25) 100%);
background: -webkit-linear-gradient(left, rgba(76,175,80,0.25) 0%,rgba(76,175,80,0.25) 10%,rgba(76,175,80,1) 50%,rgba(76,175,80,0.25) 90%,rgba(76,175,80,0.25) 100%);
background: linear-gradient(to right, rgba(76,175,80,0.25) 0%,rgba(76,175,80,0.25) 10%,rgba(76,175,80,1) 50%,rgba(76,175,80,0.25) 90%,rgba(76,175,80,0.25) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#404caf50', endColorstr='#404caf50',GradientType=1 );
}
@keyframes move {
0% {
top: 0;
}
100% {
top: 100%;
}
}
#common-video-scan-popup .scanner video {
transform: rotateY(180deg);
width: 100%;
height: 100%;
}
#common-video-scan-popup .video-scan-switch-camera-submit {
position: absolute;
left: calc(50% - 12px);
bottom: calc(50% - 200px);
z-index: 2;
cursor: pointer;
color: #fff;
}
#common-video-scan-popup .video-scan-continue-submit {
position: absolute;
left: calc(50% - 35px);
bottom: 20px;
z-index: 2;
}
/**
*

View File

@ -4684,4 +4684,118 @@ $(function()
{
Prompt(window['lang_copy_fail'] || '复制失败');
});
// 调起视频扫码、持续扫码
var $video_scan_popup = $('#common-video-scan-popup');
var $continue_submit = $video_scan_popup.find('.video-scan-continue-submit');
var $switch_submit = $video_scan_popup.find('.video-scan-switch-camera-submit');
var video_scan_code_reader = null;
var video_scan_selected_deviceid = null;
var video_scan_source_select = [];
var video_scan_back_function = null;
$(document).on('click', '.common-scan-submit,.video-scan-continue-submit', function()
{
// 关闭摄像头
if(video_scan_code_reader != null)
{
video_scan_code_reader.reset();
}
// 关闭继续按钮
$continue_submit.addClass('am-hide');
// 回调方法、组建去的持续操作则不读取回调方法
var is_close_popup = 1;
if(!$(this).hasClass('video-scan-continue-submit'))
{
video_scan_back_function = $(this).data('back-fun');
is_close_popup = ($(this).data('auto-close-popup') == undefined) ? 1 : parseInt($(this).data('auto-close-popup') || 0);
} else {
is_close_popup = 0;
}
// 开启弹窗
$video_scan_popup.modal('open');
// 初始化组建
video_scan_code_reader = new ZXing.BrowserMultiFormatReader()
// 摄像头列表
video_scan_code_reader.listVideoInputDevices().then((videoInputDevices) => {
// 是否可以切换摄像头
video_scan_source_select = [];
video_scan_selected_deviceid = videoInputDevices[0].deviceId
if(videoInputDevices.length > 1)
{
// 摄像头加到容器
videoInputDevices.forEach((element) => {
video_scan_source_select.push(element.deviceId);
});
// 切换摄像头
$switch_submit.on('click', function()
{
var index = parseInt($(this).attr('data-index') || 0);
var length = video_scan_source_select.length;
var index_new = (index > length) ? 0 : index+1;
if(video_scan_source_select.indexOf(index_new) == -1)
{
index_new = 0;
}
video_scan_selected_deviceid = video_scan_source_select[index_new];
$switch_submit.attr('data-index', index_new);
});
// 展示切换摄像头按钮
$switch_submit.removeClass('am-hide');
} else {
$switch_submit.addClass('am-hide');
}
// 调起摄像头
video_scan_code_reader.decodeFromVideoDevice(video_scan_selected_deviceid, 'video', (res, err) => {
// 识别成功
if(res)
{
// 语音提示
$('.video-scan-audio-container').html('<audio src="'+__my_public_url__+'/static/common/media/scan-success.mp3" controls autoplay style="height:0;"></audio>');
// 调用回调方法
if(IsExitsFunction(video_scan_back_function))
{
window[video_scan_back_function](res.text);
} else {
Prompt((window['lang_config_fun_not_exist_tips'] || '配置方法未定义')+'['+video_scan_back_function+']');
}
// 关闭摄像头
video_scan_code_reader.reset();
// 打开继续按钮
$continue_submit.removeClass('am-hide');
// 是否需要关闭弹窗
if(is_close_popup == 1)
{
$video_scan_popup.modal('close');
}
}
// 调起失败
if(err && !(err instanceof ZXing.NotFoundException))
{
Prompt(err);
// 打开继续按钮
$continue_submit.removeClass('am-hide');
}
});
}).catch((err) => {
Prompt(err);
});
});
// 弹窗关闭则关闭摄像头
$video_scan_popup.on('close.modal.amui', function()
{
// 关闭摄像头组建
video_scan_code_reader.reset();
// 打开继续按钮
$continue_submit.removeClass('am-hide');
});
});

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -0,0 +1,18 @@
@media only screen and (max-width: 641px) {
.am-article {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
}
@media only screen and (min-width: 640px) {
.am-article {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
}
@media only screen and (min-width: 1025px) {
.am-article {
padding-left: 0;
padding-right: 0;
}
}