后台添加绑定云音响设备

This commit is contained in:
wangxiaowei 2024-12-07 16:31:00 +08:00
parent 569b7eb240
commit 335dbfdb2a
7 changed files with 515 additions and 2 deletions

@ -5,10 +5,12 @@ namespace app\admin\controller\shop;
use app\admin\logic\groupbuy\GroupbuyLogic;
use app\admin\logic\user\UserLogic;
use app\common\basics\AdminBase;
use app\common\server\CloudAudioServer;
use app\common\server\ConfigServer;
use app\common\enum\LocalLifeICBCEnum;
use app\admin\logic\shop\LocalStoreLogic;
use app\common\server\JsonServer;
use app\common\server\storage\engine\Local;
use think\facade\Request;
use app\common\utils\UploadAliOSS;
use app\admin\validate\shop\LocalStoreValidate;
@ -277,4 +279,35 @@ class LocalStore extends AdminBase
{
return view('');
}
public function bind()
{
$id = $this->request->get('lstore_id');
if ($this->request->isAjax()) {
$post = $this->request->post();
$result = LocalStoreLogic::bindCloudAudio($post);
if ($result) {
return JsonServer::success('绑定成功');
}
return JsonServer::error('绑定失败');
}
return view('', [
'lstore_id' => $id,
'detail' => LocalStoreLogic::getBindAudio($id),
'message' => str_replace(',', '', CloudAudioServer::MESSAGE)
]);
}
public function test()
{
$id = $this->request->get('lstore_id');
$result = LocalStoreLogic::testCloudAudio($id);
if ($result) {
return JsonServer::success('操作成功');
}
return JsonServer::error(LocalStoreLogic::getError());
}
}

@ -5,9 +5,11 @@ namespace app\admin\logic\shop;
use app\common\basics\Logic;
use app\common\enum\TreatyEnum;
use app\common\model\LocalStore;
use app\common\model\localstore\LocalStoreCloudAudio;
use app\common\model\LocalStoreOrder;
use app\common\model\LocalStoreOrderRecord;
use app\common\model\Treaty;
use app\common\server\CloudAudioServer;
use app\common\server\ExportExcelServer;
use app\common\server\WeChatServer;
use EasyWeChat\Factory;
@ -460,4 +462,54 @@ class LocalStoreLogic extends Logic
{
return GtMcc::where(['parent_id' => 0, 'state' => 1])->field('mcc_id, mccName')->select();
}
// 国联支付
public static function getBindAudio($lstore_id)
{
return LocalStoreCloudAudio::where('lstore_id', $lstore_id)->find();
}
public static function bindCloudAudio($data)
{
try {
$result = LocalStoreCloudAudio::where('id', $data['id'])->find();
$audio = [
'lstore_id' => $data['lstore_id'],
'sn' => $data['sn'],
'version' => $data['version'] <= 0 ? 1 : $data['version'],
'message' => $data['message'] ?? CloudAudioServer::MESSAGE,
];
if (empty($result)) {
$audio['create_time'] = time();
return LocalStoreCloudAudio::create($audio);
}
$audio['update_time'] = time();
return LocalStoreCloudAudio::where('id', $data['id'])->update($audio);
} catch (\Exception $e) {
self::$error = $e->getMessage();
return false;
}
}
public static function testCloudAudio($lstore_id)
{
$data = LocalStoreCloudAudio::where('lstore_id', $lstore_id)->find();
if (!empty($data)) {
$result = CloudAudioServer::send([
'id' => $data['sn'],
'version' => $data['version'],
'message' => $data['message'],
]);
if ($result['code'] == 1) {
return true;
}
self::$error = $result['msg'];
return false;
}
self::$error = '未配置参数';
return false;
}
}

@ -0,0 +1,212 @@
{layout name="layout2" /}
<style>
.layui-form {padding: 20px 30px;background-color: #ffffff;}
.layui-form-item .layui-form-label { width: 95px; }
.layui-form-item .layui-input-inline { width: 240px; }
.layui-form-item
</style>
<div class="layui-card layui-form">
<div class="layui-card-body">
<input type="hidden" name="lstore_id" value="{$lstore_id}">
<input type="hidden" name="id" value="{$detail->id ?? 0}">
<div class="layui-form-item">
<label class="layui-form-label">SN/ID(机器背面)</label>
<div class="layui-input-inline">
<input type="text" name="sn" autocomplete="off" class="layui-input" lay-verify="required" placeholder="请输入SN/ID(机器背面)" lay-vertype="tips" value="{$detail->sn ?? ''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">设备版本号</label>
<div class="layui-input-inline">
<input type="text" style="width: 300px;" name="version" autocomplete="off" class="layui-input" placeholder="请输入设备版本号(机器背面), 默认为1"value="{$detail->version ?? ''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">消息提示内容</label>
<div class="layui-input-inline">
<input type="text" style="width: 340px;" name="message" autocomplete="off" class="layui-input" placeholder="消息提示内容前缀 如:支付宝倒账,默认为{$message}" value="{$detail->message ?? ''}">
</div>
</div>
<!-- 确认按钮 -->
<div class="layui-form-item layui-hide">
<input type="button" lay-submit lay-filter="addSubmit" id="addSubmit" value="确认">
</div>
</div>
</div>
<script>
layui.config({
base: "/static/lib/"
}).extend({
likeedit: "likeedit/likeedit",
likeArea: "likeArea/likeArea",
txMap: "likeMap/txMap"
}).use(["form", "laydate", "likeArea", "txMap", 'likeedit', 'upload', 'element'], function(){
var $ = layui.$;
var form = layui.form;
var laydate = layui.laydate;
var likeedit = layui.likeedit;
var likeupload = layui.upload;
//------------------------------------------富文本编辑器 begin --------------------------------
var content = likeedit.build("content", {
uploadImage: {
url: '{:url("file/lists")}?type=10'
}
});
form.verify({
content: function() {
likeedit.sync(content)
}
});
//------------------------------------------富文本编辑器 end --------------------------------
form.on('radio(type)', function(data){
var val = $('input[name="mall_type"]:checked').val()
if(data.value == 0){
if (val == 1) {
$("#mall-image").hide()
} else {
$("#mall-image").show()
}
$("#mall_type").show()
$("#mall-video").hide()
} else {
$("#mall-image").hide()
$("#mall_type").hide()
$("#one-shop").show()
$("#mall-video").show()
}
});
form.on('radio(mall_type)', function(data){
if(data.value == 0){
$("#mall-image").show()
$("#mall-video").hide()
$("#article-content").show()
} else {
console.log(456)
$("#mall-image").hide()
$("#mall-video").hide()
$("#article-content").hide()
}
});
laydate.render({type:"datetime", elem:"#expire_time", trigger:"click",min:0});
// 视频上传
likeupload
var uploadInst = likeupload.render({
elem: '.add-upload-video' //绑定元素
,url: "{:url('MallNews/uploadVideo')}" //上传接口
,accept: 'video'
,exts: "mp4"
,before: function(obj){ //obj参数包含的信息,跟 choose回调完全一致,可参见上文。
console.log(222)
layer.load(); //上传loading
}
,done: function(res, index, upload){
if (res.code === 1) {
$("#upload-video-block").hide()
$("#video-block").show()
$("#mallVideo").attr('src', res.data.file)
$("#mall_news_images").val(res.data.file)
$("input[name='video_file']").val(res.data.file)
} else {
layer.msg('上传错误');
return false;
}
layer.closeAll('loading'); //关闭loading
}
,error: function(index, upload){
layer.closeAll('loading'); //关闭loading
}
});
// 删除视频
$(document).on("click", ".del-video-btn", function (e) {
layer.confirm("是否删除该视频?", function(index) {
const videoFile = $("#mallVideo").attr('src')
like.ajax({
url: '{:url("mallNews/delVideo")}',
data: {videoFile},
type: "post",
success: function (res) {}
});
$("#upload-video-block").show()
$("#video-block").hide()
$("#mallVideo").attr('src', '')
layer.close(index);
})
});
// 选择商品
$(document).on('click','.select-goods',function () {
var val = $('input[name="mall_type"]:checked').val()
if (val == 0) {
layer.open({
type: 2
,title: '选择商品'
,content: '{:url("mallNews/goods")}'
,area: ['90%', '90%']
,btn: ['确认', '取消']
,yes: function(index, layero){
var data = window["layui-layer-iframe" + index].callbackdata();
$('#shop_name').html(data[0].name)
$('#shop_id').val(data[0].id)
}
})
} else if (val == 1) {
layer.open({
type: 2
,title: '选择商品'
,content: '{:url("mallNews/mall_news_goods")}'
,area: ['90%', '90%']
,btn: ['确认', '取消']
,yes: function(index, layero){
var data = window["layui-layer-iframe" + index].callbackdata();
var html = $('#shop_name').html()
html += '<br/> ' + data[0].name
$('#shop_name').html(html)
var val = $('#shop_id').val()
val += ',' + data[0].id
$('#shop_id').val(val)
}
})
}
})
form.verify({
title: function (value, item) {
if (!value) {
switchTab($(item).attr("switch-tab"));
return "请填写标题";
}
},
desc: function (value, item) {
if (!value) {
switchTab($(item).attr("switch-tab"));
return "请填写文章概述";
}
},
});
function switchTab(number) {
$('.layui-tab-card .layui-tab-title li').removeClass('layui-this');
$('.layui-tab-content .layui-tab-item').removeClass('layui-show');
$('.layui-tab-card .layui-tab-title li').eq(number).addClass('layui-this');
$('.layui-tab-content .layui-tab-item').eq(number).addClass('layui-show');
}
})
</script>

@ -66,17 +66,21 @@
</script>
<script type="text/html" id="localstore-operation">
<div>
<div style="display: flex;justify-content: flex-start;">
<a class="layui-btn layui-btn-info layui-btn-sm" lay-event="glzf">国联支付</a>
<a class="layui-btn layui-btn-normal layui-btn-sm" lay-event="hfzf">汇付支付</a>
<a class="layui-btn layui-btn-danger layui-btn-sm" lay-event="ghzf">工行支付</a>
</div>
<div style="margin-top: 20px;">
<div style="display: flex;justify-content: flex-start;margin-top: 20px;">
<a class="layui-btn layui-btn-info layui-btn-sm" lay-event="download">下载二维码</a>
<a class="layui-btn layui-btn-normal layui-btn-sm" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-sm" lay-event="del">删除</a>
<a class="layui-btn layui-btn-normal layui-btn-sm" lay-event="verify">添加核销</a>
</div>
<div style="display: flex;justify-content: flex-start;margin-top: 20px;">
<a class="layui-btn layui-btn-info layui-btn-sm" lay-event="bind">绑定设备</a>
<a class="layui-btn layui-btn-danger layui-btn-sm" lay-event="test">测试设备</a>
</div>
</script>
</div>
</div>
@ -324,6 +328,52 @@
submit.trigger("click");
}
});
},
bind(obj) {
// 绑定设备
layer.open({
type: 2
, title: "绑定设备"
, content: "{:url('shop.LocalStore/bind')}?lstore_id=" + obj.data.lstore_id
, area: ['90%', '90%']
, btn: ["确定", "取消"]
, yes: function (index, layero) {
var iframeWindow = window["layui-layer-iframe" + index];
var submit = layero.find("iframe").contents().find("#addSubmit");
iframeWindow.layui.form.on("submit(addSubmit)", function (data) {
like.ajax({
url: "{:url('shop.LocalStore/bind')}",
data: data.field,
type: "POST",
success: function (res) {
if (res.code === 1) {
layui.layer.msg(res.msg);
layer.close(index);
table.reload("like-table-lists", {
where: {},
page: {cur: 1}
});
}
}
});
});
submit.trigger("click");
}
});
},
test(obj) {
// 测试设备
like.ajax({
url: "{:url('shop.LocalStore/test')}?lstore_id=" + obj.data.lstore_id,
type: "POST",
success: function (res) {
if (res.code === 1) {
layui.layer.msg(res.msg);
}
}
});
return false
}
};
like.eventClick(active);

@ -0,0 +1,10 @@
<?php
namespace app\common\model\localstore;
use app\common\basics\Models;
class LocalStoreCloudAudio extends Models
{
}

@ -0,0 +1,81 @@
<?php
namespace app\common\server;
class CloudAudioServer
{
const URI = 'https://speaker.17laimai.cn';
const TOKEN = 'HK1733377641';
const MESSAGE = '商家收款,';
public static function send($data)
{
try {
$api = '/notify.php';
if (empty($data)) {
throw new \Exception('请填写参数');
}
if (!isset($data['id'])) {
// 指该云音箱标签上的的 SN/ID
throw new \Exception('请输入设备上的SN码');
}
if (!isset($data['version']) && $data['version'] <= 0) {
// 接口版本 按音箱标签上标注的VERSION版本,由用户配置时选择,预留1-9供选择
throw new \Exception('设备版本号输入错误: 1-9');
}
if (empty($data['message'])) {
$data['message'] = self::MESSAGE;
}
$result = self::curlPost($api, $data);
if ($result['errcode'] == 0 && $result['errmsg'] == 'ok') {
return [
'code' => 1,
];
}
return [
'code' => 0,
'msg' => $result['errmsg']
];
} catch (\Exception $e) {
return [
'code' => 0,
'msg' => $e->getMessage()
];
}
}
private static function curlPost($api, $postData)
{
$postData['token'] = self::TOKEN;
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => self::URI . $api,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => http_build_query($postData),
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
if ($err) {
return "CURL Error #:" . $err;
}
return json_decode($response,true);
}
}

@ -0,0 +1,75 @@
<?php
use think\migration\Migrator;
use think\migration\db\Column;
class CreateLocalStoreCloudAudioTable extends Migrator
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
// 创建表
$table = $this->table('local_store_cloud_audio', ['comment' => '本地生活商家绑定的音响设备']);
// 创建字段
$table->addColumn('lstore_id', 'integer', [
'limit' => 10,
'default' => 0,
'null' => false,
'comment' => '本地生活商家ID',
])
->addColumn('sn', 'string', [
'limit' => 64,
'default' => '',
'null' => false,
'comment' => '设备SN/ID号',
])
->addColumn('version', 'integer', [
'limit' => 1,
'default' => 1,
'null' => false,
'comment' => '设备版本号',
])
->addColumn('message', 'string', [
'limit' => 32,
'default' => '',
'null' => false,
'comment' => '设备消息提示',
])
->addColumn('create_time', 'integer', [
'limit' => 10,
'default' => 0,
'null' => false,
'comment' => '创建时间',
])
->addColumn('update_time', 'integer', [
'limit' => 10,
'default' => 0,
'null' => false,
'comment' => '更新时间',
])
->addIndex(['lstore_id'], ['unique' => true, 'name' => 'idx_lstore_id'])
->addIndex(['sn'], ['unique' => true, 'name' => 'idx_sn'])
->create();
}
}