Kirin 3 yıl önce
ebeveyn
işleme
08135870ac

+ 505 - 0
app/admin/controller/ump/StoreCard.php

@@ -0,0 +1,505 @@
+<?php
+
+namespace app\admin\controller\ump;
+
+use app\admin\controller\AuthController;
+use app\models\store\Card;
+use app\admin\model\store\{StoreDescription,
+    StoreProductAttr,
+    StoreProductAttrResult,
+    StoreProduct as ProductModel,
+    StoreProductAttrValue
+};
+use crmeb\traits\CurdControllerTrait;
+use think\Exception;
+use think\exception\ErrorException;
+use think\exception\ValidateException;
+use think\facade\Route as Url;
+use app\admin\model\system\{SystemAttachment, SystemGroupData, ShippingTemplates};
+use crmeb\services\{
+    FormBuilder as Form, UtilService as Util, JsonService as Json
+};
+use app\admin\model\store\StoreCategory;
+
+/**
+ * 限时秒杀  控制器
+ * Class StoreSeckill
+ * @package app\admin\controller\store
+ */
+class StoreCard extends AuthController
+{
+
+    use CurdControllerTrait;
+
+    protected $bindModel = Card::class;
+
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        $this->assign('count', Card::count());
+        return $this->fetch();
+    }
+
+    public function save_excel()
+    {
+        $where = Util::getMore([
+            ['status', ''],
+            ['name', '']
+        ]);
+        \app\admin\model\ump\StoreExchange::SaveExcel($where);
+    }
+
+    /**
+     * 异步获取砍价数据
+     */
+    public function get_list()
+    {
+        $where = Util::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['status', ''],
+            ['name', '']
+        ]);
+        $seckillList = \app\admin\model\ump\StoreExchange::systemPage($where);
+        if (is_object($seckillList['list'])) $seckillList['list'] = $seckillList['list']->toArray();
+        $data = $seckillList['list']['data'];
+        return Json::successlayui(['count' => $seckillList['list']['total'], 'data' => $data]);
+    }
+
+    public function get_seckill_id()
+    {
+        return Json::successlayui(\app\admin\model\ump\StoreExchange::getSeckillIdAll());
+    }
+
+    /**
+     * 添加秒杀商品
+     * @return form-builder
+     */
+    public function create()
+    {
+        $f = array();
+        $f[] = Form::frameImageOne('product', '选择商品', Url::buildUrl('productList', array('fodder' => 'product')))->icon('plus')->width('100%')->height('500px');
+        $f[] = Form::hidden('product_id', '');
+        $f[] = Form::hidden('description', '');
+        $f[] = Form::input('title', '商品标题');
+        $f[] = Form::input('info', '活动简介')->type('textarea');
+        $f[] = Form::input('unit_name', '单位')->placeholder('个、位');
+        $f[] = Form::select('temp_id', '运费模板')->setOptions(function () {
+            $list = ShippingTemplates::getList(['page' => 1, 'limit' => 20]);
+            $menus = [];
+            foreach ($list['data'] as $menu) {
+                $menus[] = ['value' => $menu['id'], 'label' => $menu['name']];
+            }
+            return $menus;
+        })->filterable(1)->col(12);
+        $f[] = Form::frameImageOne('image', '商品主图片(305*305px)', Url::buildUrl('admin/widget.images/index', array('fodder' => 'image')))->icon('image')->width('100%')->height('500px');
+        $f[] = Form::frameImages('images', '商品轮播图(640*640px)', Url::buildUrl('admin/widget.images/index', array('fodder' => 'images')))->maxLength(5)->icon('images')->width('100%')->height('500px');
+        $f[] = Form::number('sort', '排序')->col(12);
+        $f[] = Form::number('num', '单次购买商品个数')->precision(0)->col(12);
+        $f[] = Form::number('give_integral', '赠送积分')->min(0)->precision(0)->col(12);
+        $f[] = Form::radio('is_hot', '热门推荐', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]])->col(12);
+        $form = Form::make_post_form('添加用户通知', $f, Url::buildUrl('save'));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存秒杀商品
+     * @param int $id
+     */
+    public function save($id = 0)
+    {
+        $data = Util::postMore([
+            'title',
+            'product_id',
+            'info',
+            'unit_name',
+            ['image', ''],
+            ['images', []],
+            ['price', 0],
+            ['ot_price', 0],
+            ['cost', 0],
+            ['sales', 0],
+            ['stock', 0],
+            ['sort', 0],
+            ['give_integral', 0],
+            ['postage', 0],
+            ['is_postage', 0],
+            ['cost', 0],
+            ['is_hot', 0],
+            ['status', 0],
+            ['num', 0],
+            'temp_id',
+            ['weight', 0],
+            ['volume', 0],
+        ]);
+        $data['description'] = StoreDescription::getDescription($data['product_id']);
+        if (!$data['title']) return Json::fail('请输入商品标题');
+        if (!$data['unit_name']) return Json::fail('请输入商品单位');
+        if (!$data['product_id']) return Json::fail('商品ID不能为空');
+        if (!$data['image']) return Json::fail('请选择推荐图');
+        if (count($data['images']) < 1) return Json::fail('请选择轮播图');
+        $data['images'] = json_encode($data['images']);
+        if ($data['num'] < 1) return Json::fail('请输入单次购买个数');
+        if ($id) {
+            unset($data['description']);
+            $product = \app\admin\model\ump\StoreExchange::get($id);
+            if (!$product) return Json::fail('数据不存在!');
+            \app\admin\model\ump\StoreExchange::edit($data, $id);
+            return Json::successful('编辑成功!');
+        } else {
+            $data['add_time'] = time();
+            $res = \app\admin\model\ump\StoreExchange::create($data);
+            $description['product_id'] = $res['id'];
+            $description['description'] = htmlspecialchars_decode($data['description']);
+            $description['type'] = 5;
+            StoreDescription::create($description);
+            return Json::successful('添加成功!');
+        }
+
+    }
+
+    /**
+     * 显示编辑资源表单页.
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function edit($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $product = \app\admin\model\ump\StoreExchange::get($id);
+//        $time = StoreSeckillTime::getSeckillTime($id);
+        if (!$product) return Json::fail('数据不存在!');
+        $f = array();
+        $f[] = Form::input('product_id', '产品ID', $product->getData('product_id'))->disabled(true);
+        $f[] = Form::input('title', '商品标题', $product->getData('title'));
+        $f[] = Form::input('info', '活动简介', $product->getData('info'))->type('textarea');
+        $f[] = Form::input('unit_name', '单位', $product->getData('unit_name'))->placeholder('个、位');
+        $f[] = Form::select('temp_id', '运费模板', (string)$product->getData('temp_id'))->setOptions(function () {
+            $list = ShippingTemplates::getList(['page' => 1, 'limit' => 20]);
+            $menus = [];
+            foreach ($list['data'] as $menu) {
+                $menus[] = ['value' => $menu['id'], 'label' => $menu['name']];
+            }
+            return $menus;
+        })->filterable(1)->col(12);
+        $f[] = Form::frameImageOne('image', '商品主图片(305*305px)', Url::buildUrl('admin/widget.images/index', array('fodder' => 'image')), $product->getData('image'))->icon('image')->width('100%')->height('500px');
+        $f[] = Form::frameImages('images', '商品轮播图(640*640px)', Url::buildUrl('admin/widget.images/index', array('fodder' => 'images')), json_decode($product->getData('images')))->maxLength(5)->icon('images')->width('100%')->height('500px');
+        $f[] = Form::number('sort', '排序', $product->getData('sort'))->col(12);
+        $f[] = Form::hidden('stock', $product->getData('stock'));
+        $f[] = Form::hidden('price', $product->getData('price'));
+        $f[] = Form::hidden('ot_price', $product->getData('ot_price'));
+        $f[] = Form::hidden('sales', $product->getData('sales'));
+        $f[] = Form::number('num', '单次购买商品个数', $product->getData('num'))->precision(0)->col(12);
+        $f[] = Form::number('give_integral', '赠送积分', $product->getData('give_integral'))->min(0)->precision(0)->col(12);
+        $f[] = Form::radio('is_hot', '热门推荐', $product->getData('is_hot'))->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]])->col(12);
+        $f[] = Form::hidden('status', $product->getData('status'));
+        $form = Form::make_post_form('添加用户通知', $f, Url::buildUrl('save', compact('id')));
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param int $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $product = \app\admin\model\ump\StoreExchange::get($id);
+        if (!$product) return Json::fail('数据不存在!');
+        if ($product['is_del']) return Json::fail('已删除!');
+        $data['is_del'] = 1;
+        if (!\app\admin\model\ump\StoreExchange::edit($data, $id))
+            return Json::fail(\app\admin\model\ump\StoreExchange::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+    public function edit_content($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $seckill = \app\admin\model\ump\StoreExchange::get($id);
+        if (!$seckill) return Json::fail('数据不存在!');
+        $this->assign([
+            'content' => htmlspecialchars_decode(StoreDescription::getDescription($id, 5)),
+            'field' => 'description',
+            'action' => Url::buildUrl('change_field', ['id' => $id, 'field' => 'description'])
+        ]);
+        return $this->fetch('public/edit_content');
+    }
+
+    public function change_field($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $seckill = \app\admin\model\ump\StoreExchange::get($id);
+        if (!$seckill) return Json::fail('数据不存在!');
+        $data['description'] = request()->post('description');
+        StoreDescription::saveDescription($data['description'], $id, 5);
+        $res = \app\admin\model\ump\StoreExchange::edit($data, $id);
+        if ($res)
+            return Json::successful('添加成功');
+        else
+            return Json::fail('添加失败');
+    }
+
+    /**
+     * 属性页面
+     * @param $id
+     * @return mixed|void
+     */
+    public function attr($id)
+    {
+        if (!$id) return $this->failed('数据不存在!');
+        $result = StoreProductAttrResult::getResult($id, 5);
+        $image = \app\admin\model\ump\StoreExchange::where('id', $id)->value('image');
+        $this->assign(compact('id', 'result', 'image'));
+        return $this->fetch();
+    }
+
+    /**
+     * 秒杀属性选择页面
+     * @param $id
+     * @return string|void
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function attr_list($id)
+    {
+        if (!$id) return $this->failed('数据不存在!');
+        $seckillInfo = \app\admin\model\ump\StoreExchange::where('id', $id)->find();
+        $seckillResult = StoreProductAttrResult::where('product_id', $id)->where('type', 5)->value('result');
+        $productResult = StoreProductAttrResult::where('product_id', $seckillInfo['product_id'])->where('type', 0)->value('result');
+        if ($productResult) {
+            $attr = json_decode($productResult, true)['attr'];
+            $productAttr = $this->get_attr($attr, $seckillInfo['product_id'], 0);
+            $seckillAttr = $this->get_attr($attr, $id, 5);
+            foreach ($productAttr as $pk => $pv) {
+                foreach ($seckillAttr as $sv) {
+                    if ($pv['detail'] == $sv['detail']) {
+                        $productAttr[$pk] = $sv;
+                    }
+                }
+            }
+        } else {
+            if ($seckillResult) {
+                $attr = json_decode($seckillResult, true)['attr'];
+                $productAttr = $this->get_attr($attr, $id, 5);
+            } else {
+                $attr[0]['value'] = '默认';
+                $attr[0]['detailValue'] = '';
+                $attr[0]['attrHidden'] = '';
+                $attr[0]['detail'][0] = '默认';
+                $productAttr[0]['value1'] = '默认';
+                $productAttr[0]['detail'] = json_encode(['默认' => '默认']);
+                $productAttr[0]['pic'] = $seckillInfo['image'];
+                $productAttr[0]['price'] = $seckillInfo['price'];
+                $productAttr[0]['cost'] = $seckillInfo['cost'];
+                $productAttr[0]['ot_price'] = $seckillInfo['ot_price'];
+                $productAttr[0]['stock'] = $seckillInfo['stock'];
+                $productAttr[0]['quota'] = 0;
+                $productAttr[0]['bar_code'] = $seckillInfo['bar_code'];
+                $productAttr[0]['weight'] = 0;
+                $productAttr[0]['volume'] = 0;
+                $productAttr[0]['deposit'] = 0;
+                $productAttr[0]['brokerage'] = 0;
+                $productAttr[0]['brokerage_two'] = 0;
+                $productAttr[0]['check'] = 0;
+            }
+        }
+        $attrs['attr'] = $attr;
+        $attrs['value'] = $productAttr;
+        $this->assign('attr', $attrs);
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+    /**
+     * 秒杀属性保存页面
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function save_attr()
+    {
+        $data = Util::postMore([
+            ['attr', []],
+            ['ids', []],
+            ['id', 0],
+        ]);
+        if (!$data['id']) return Json::fail('数据不存在!');
+        if (!$data['ids']) return Json::fail('你没有选择任何规格!');
+        $productId = \app\admin\model\ump\StoreExchange::where('id', $data['id'])->value('product_id');
+        $attr = json_decode(StoreProductAttrResult::where('product_id', $productId)->where('type', 0)->value('result'), true)['attr'];
+        foreach ($data['attr'] as $k => $v) {
+            if (in_array($k, $data['ids'])) {
+                $v['detail'] = json_decode(htmlspecialchars_decode($v['detail']), true);
+                $detail[$k] = $v;
+            }
+        }
+        if (min(array_column($detail, 'quota')) == 0) return Json::fail('限购不能为0');
+        $price = min(array_column($detail, 'price'));
+        $otPrice = min(array_column($detail, 'ot_price'));
+        $quota = array_sum(array_column($detail, 'quota'));
+        $stock = array_sum(array_column($detail, 'stock'));
+        $deposit = min(array_column($detail, 'deposit'));
+        if (!$attr) {
+            $attr[0]['value'] = '默认';
+            $attr[0]['detailValue'] = '';
+            $attr[0]['attrHidden'] = '';
+            $attr[0]['detail'][0] = '默认';
+        }
+        StoreProductAttr::createProductAttr($attr, $detail, $data['id'], 5);
+        \app\admin\model\ump\StoreExchange::where('id', $data['id'])->update(['deposit' => $deposit, 'stock' => $stock, 'quota' => $quota, 'quota_show' => $quota, 'price' => $price, 'ot_price' => $otPrice]);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 生成属性
+     * @param int $id
+     */
+    public function is_format_attr($id = 0)
+    {
+        if (!$id) return Json::fail('商品不存在');
+        list($attr, $detail) = Util::postMore([
+            ['items', []],
+            ['attrs', []]
+        ], $this->request, true);
+        $product = \app\admin\model\ump\StoreExchange::get($id);
+        if (!$product) return Json::fail('商品不存在');
+        $attrFormat = attr_format($attr)[1];
+        if (count($detail)) {
+            foreach ($attrFormat as $k => $v) {
+                foreach ($detail as $kk => $vv) {
+                    if ($v['detail'] == $vv['detail']) {
+                        $attrFormat[$k]['price'] = $vv['price'];
+                        $attrFormat[$k]['sales'] = $vv['sales'];
+                        $attrFormat[$k]['pic'] = $vv['pic'];
+                        $attrFormat[$k]['check'] = false;
+                        break;
+                    } else {
+                        $attrFormat[$k]['price'] = '';
+                        $attrFormat[$k]['sales'] = '';
+                        $attrFormat[$k]['pic'] = $product['image'];
+                        $attrFormat[$k]['check'] = true;
+                    }
+                }
+            }
+        } else {
+            foreach ($attrFormat as $k => $v) {
+                $attrFormat[$k]['price'] = $product['price'];
+                $attrFormat[$k]['sales'] = $product['stock'];
+                $attrFormat[$k]['pic'] = $product['image'];
+                $attrFormat[$k]['check'] = false;
+            }
+        }
+        return Json::successful($attrFormat);
+    }
+
+    /**
+     * 添加 修改属性
+     * @param $id
+     */
+    public function set_attr($id)
+    {
+        if (!$id) return $this->failed('商品不存在!');
+        list($attr, $detail) = Util::postMore([
+            ['items', []],
+            ['attrs', []]
+        ], $this->request, true);
+        $res = StoreProductAttr::createProductAttr($attr, $detail, $id, 5);
+        if ($res)
+            return $this->successful('编辑属性成功!');
+        else
+            return $this->failed(StoreProductAttr::getErrorInfo());
+    }
+
+    /**
+     * 清除属性
+     * @param $id
+     */
+    public function clear_attr($id)
+    {
+        if (!$id) return $this->failed('商品不存在!');
+        if (false !== StoreProductAttr::clearProductAttr($id, 5) && false !== StoreProductAttrResult::clearResult($id))
+            return $this->successful('清空商品属性成功!');
+        else
+            return $this->failed(StoreProductAttr::getErrorInfo('清空商品属性失败!'));
+    }
+
+    /**
+     * 修改秒杀商品状态
+     * @param $status
+     * @param int $id
+     */
+    public function set_seckill_status($status, $id = 0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $res = StoreProductAttrValue::where('product_id', $id)->where('type', 5)->find();
+        if (!$res) return Json::fail('请先配置规格');
+        $res = \app\admin\model\ump\StoreExchange::edit(['status' => $status], $id);
+        if ($res) return Json::successful('修改成功');
+        else return Json::fail('修改失败');
+    }
+
+    /**
+     * 秒杀获取商品列表
+     * @return string
+     * @throws \Exception
+     */
+    public function productList()
+    {
+        $cate = StoreCategory::getTierList(null, 1);
+        $this->assign('cate', $cate);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取秒杀商品规格
+     * @param $attr
+     * @param $id
+     * @param $type
+     * @return array
+     */
+    public function get_attr($attr, $id, $type)
+    {
+        $value = attr_format($attr)[1];
+        $valueNew = [];
+        $count = 0;
+        foreach ($value as $key => $item) {
+            $detail = $item['detail'];
+//            sort($item['detail'], SORT_STRING);
+            $suk = implode(',', $item['detail']);
+            $sukValue = StoreProductAttrValue::where('product_id', $id)->where('type', $type)->where('suk', $suk)->column('bar_code,cost,price,ot_price,stock,image as pic,weight,volume,deposit,brokerage,brokerage_two,quota', 'suk');
+            if (count($sukValue)) {
+                foreach (array_values($detail) as $k => $v) {
+                    $valueNew[$count]['value' . ($k + 1)] = $v;
+                }
+                $valueNew[$count]['detail'] = json_encode($detail);
+                $valueNew[$count]['pic'] = $sukValue[$suk]['pic'] ?? '';
+                $valueNew[$count]['price'] = $sukValue[$suk]['price'] ? floatval($sukValue[$suk]['price']) : 0;
+                $valueNew[$count]['cost'] = $sukValue[$suk]['cost'] ? floatval($sukValue[$suk]['cost']) : 0;
+                $valueNew[$count]['ot_price'] = isset($sukValue[$suk]['ot_price']) ? floatval($sukValue[$suk]['ot_price']) : 0;
+                $valueNew[$count]['stock'] = $sukValue[$suk]['stock'] ? intval($sukValue[$suk]['stock']) : 0;
+                $valueNew[$count]['quota'] = $sukValue[$suk]['quota'] ? intval($sukValue[$suk]['quota']) : 0;
+                $valueNew[$count]['bar_code'] = $sukValue[$suk]['bar_code'] ?? '';
+                $valueNew[$count]['weight'] = $sukValue[$suk]['weight'] ?? 0;
+                $valueNew[$count]['volume'] = $sukValue[$suk]['volume'] ?? 0;
+                $valueNew[$count]['deposit'] = $sukValue[$suk]['deposit'] ?? 0;
+                $valueNew[$count]['brokerage'] = $sukValue[$suk]['brokerage'] ?? 0;
+                $valueNew[$count]['brokerage_two'] = $sukValue[$suk]['brokerage_two'] ?? 0;
+                $valueNew[$count]['check'] = $type != 0 ? 1 : 0;
+                $count++;
+            }
+        }
+        return $valueNew;
+    }
+}

+ 218 - 0
app/admin/view/ump/store_card/index.php

@@ -0,0 +1,218 @@
+{extend name="public/container"}
+{block name="head_top"}
+<script type="text/javascript" src="{__PLUG_PATH}jquery.downCount.js"></script>
+{/block}
+{block name="content"}
+<div class="layui-fluid">
+    <div class="layui-row layui-col-space15"  id="app">
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">兑换券商品搜索</div>
+                <div class="layui-card-body">
+                    <div class="alert alert-success alert-dismissable">
+                        <button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
+                        目前拥有{$countSeckill}个兑换券商品
+                    </div>
+                    <form class="layui-form">
+                        <div class="layui-form-item">
+                            <div class="layui-inline">
+                                <label class="layui-form-label">搜  索:</label>
+                                <div class="layui-input-inline">
+                                    <input type="text" name="store_name" lay-verify="store_name" style="width: 100%" autocomplete="off" placeholder="请输入商品名称,关键字,编号" class="layui-input">
+                                </div>
+                            </div>
+                            <div class="layui-inline">
+                                <label class="layui-form-label">兑换券状态:</label>
+                                <div class="layui-input-inline">
+                                    <select name="status" lay-verify="status">
+                                        <option value="">全部</option>
+                                        <option value="1">开启</option>
+                                        <option value="0">关闭</option>
+                                    </select>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label">
+                                <button class="layui-btn layui-btn-sm" lay-submit="" lay-filter="search" style="font-size:14px;line-height: 9px;">
+                                    <i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>搜索</button>
+                                <button lay-submit="export" lay-filter="export" class="layui-btn layui-btn-primary layui-btn-sm">
+                                    <i class="layui-icon layui-icon-delete layuiadmin-button-btn" ></i> Excel导出</button>
+                            </label>
+                        </div>
+                    </form>
+                </div>
+            </div>
+        </div>
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">兑换券商品列表</div>
+                <div class="layui-card-body">
+                    <div class="layui-btn-container">
+                        <a class="layui-btn layui-btn-sm" onclick="$eb.createModalFrame(this.innerText,'{:Url('create')}',{h:700,w:1100});">添加兑换券商品</a>
+                    </div>
+                    <table class="layui-hide" id="seckillList" lay-filter="seckillList"></table>
+                    <script type="text/html" id="status">
+                        <input type='checkbox' name='status' lay-skin='switch' value="{{d.id}}" lay-filter='status' lay-text='开启|关闭'  {{ d.status == 1 ? 'checked' : '' }}>
+                    </script>
+                    <script type="text/html" id="statusCn">
+                        {{ d.status == 1 ? d.start_name : '关闭' }}
+                    </script>
+                    <script type="text/html" id="barDemo">
+                        <button type="button" class="layui-btn layui-btn-xs" onclick="$eb.createModalFrame('{{d.title}}-设置规格','{:Url('attr_list')}?id={{d.id}}',{h:1000,w:1400});"><i class="layui-icon layui-icon-util"></i>规格</button>
+
+                        <button type="button" class="layui-btn layui-btn-xs" onclick="dropdown(this)">操作<span class="caret"></span></button>
+                        <ul class="layui-nav-child layui-anim layui-anim-upbit">
+                            <li>
+                                <a href="javascript:void(0);" onclick="$eb.createModalFrame('{{d.title}}-编辑','{:Url('edit')}?id={{d.id}}')"><i class="layui-icon layui-icon-edit"></i> 编辑活动</a>
+                            </li>
+                            <li>
+                                <a href="javascript:void(0);" onclick="$eb.createModalFrame('{{d.title}}-编辑内容','{:Url('edit_content')}?id={{d.id}}')"><i class="layui-icon layui-icon-edit"></i> 编辑内容</a>
+                            </li>
+                            <li>
+                                <a href="javascript:void(0);" class="delstor" lay-event='delstor'><i class="layui-icon layui-icon-delete"></i> 删除</a>
+                            </li>
+                        </ul>
+                    </script>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+{/block}
+{block name="script"}
+<script src="{__ADMIN_PATH}js/layuiList.js"></script>
+<script src="{__FRAME_PATH}js/content.min.js?v=1.0.0"></script>
+<script>
+    layList.form.render();
+    layList.tableList('seckillList',"{:Url('get_seckill_list')}",function () {
+        return [
+            {field: 'id', title: 'ID', sort: true,width:'6%',event:'id'},
+            {field: 'image', title: '商品图片', width: '10%',templet: '<p><img src="{{d.image}}" alt="{{d.title}}" class="open_image" data-image="{{d.image}}"></p>'},
+            {field: 'title', title: '活动标题'},
+            {field: 'info', title: '活动简介',width:'20%'},
+            {field: 'ot_price', title: '原价',width:'6%'},
+            {field: 'price', title: '兑换券价格',width:'6%'},
+            {field: 'quota_show', title: '限量',width:'6%'},
+            {field: 'quota', title: '限量剩余',width:'6%'},
+            // {field: 'start_name', title: '状态',width:'6%',toolbar:"#statusCn"},
+            {field: 'status', title: '状态',width:'6%',toolbar:"#status"},
+            {field: 'right', title: '操作',width:'10%', align: 'center', toolbar: '#barDemo'}
+        ]
+    });
+    layList.tool(function (event,data,obj) {
+        switch (event) {
+            case 'delstor':
+                var url=layList.U({c:'ump.store_exchange',a:'delete',q:{id:data.id}});
+                $eb.$swal('delete',function(){
+                    $eb.axios.get(url).then(function(res){
+                        if(res.status == 200 && res.data.code == 200) {
+                            $eb.$swal('success',res.data.msg);
+                            obj.del();
+                        }else
+                            return Promise.reject(res.data.msg || '删除失败')
+                    }).catch(function(err){
+                        $eb.$swal('error',err);
+                    });
+                })
+                break;
+        }
+    })
+    $(document).click(function (e) {
+        $('.layui-nav-child').hide();
+    })
+    function dropdown(that){
+        var oEvent = arguments.callee.caller.arguments[0] || event;
+        oEvent.stopPropagation();
+        var offset = $(that).offset();
+        var top=offset.top-$(window).scrollTop();
+        var index = $(that).parents('tr').data('index');
+        $('.layui-nav-child').each(function (key) {
+            if (key != index) {
+                $(this).hide();
+            }
+        })
+        if($(document).height() < top+$(that).next('ul').height()){
+            $(that).next('ul').css({
+                'padding': 10,
+                'top': - ($(that).parent('td').height() / 2 + $(that).height() + $(that).next('ul').height()/2),
+                'min-width': 'inherit',
+                'position': 'absolute'
+            }).toggle();
+        }else{
+            $(that).next('ul').css({
+                'padding': 10,
+                'top':$(that).parent('td').height() / 2 + $(that).height(),
+                'min-width': 'inherit',
+                'position': 'absolute'
+            }).toggle();
+        }
+    }
+    layList.search('search',function(where){
+        layList.reload(where);
+        setTime();
+    });
+    layList.search('export',function(where){
+        location.href=layList.U({c:'ump.store_exchange',a:'save_excel',q:{status:where.status,store_name:where.store_name}});
+    })
+    layList.switch('status',function (odj,value,name) {
+        if (odj.elem.checked == true) {
+            layList.baseGet(layList.Url({
+                c: 'ump.store_exchange',
+                a: 'set_seckill_status',
+                p: {status: 1, id: value}
+            }), function (res) {
+                layList.msg(res.msg);
+            }, function () {
+                odj.elem.checked = false;
+                layui.form.render();
+                layer.open({
+                    type: 1
+                    ,offset: 'auto'
+                    ,id: 'layerDemoauto' //防止重复弹出
+                    ,content: '<div style="padding: 20px 100px;">请先配置规格</div>'
+                    ,btn: '设置规格'
+                    ,btnAlign: 'c' //按钮居中
+                    ,shade: 0 //不显示遮罩
+                    ,yes: function(){
+                        layer.closeAll();
+                        $eb.createModalFrame('设置规格','{:Url('attr_list')}?id='+value+'',{h:1000,w:1400});
+                    }
+                });
+            });
+        } else {
+            layList.baseGet(layList.Url({
+                c: 'ump.store_exchange',
+                a: 'set_seckill_status',
+                p: {status: 0, id: value}
+            }), function (res) {
+                layList.msg(res.msg);
+            });
+        }
+    })
+    $('.js-group-btn').on('click',function(){
+        $('.js-group-btn').css({zIndex:1});
+        $(this).css({zIndex:2});
+    });
+    $('#delstor').on('click',function(){
+        window.t = $(this);
+        var _this = $(this),url =_this.data('url');
+        $eb.$swal('delete',function(){
+            $eb.axios.get(url).then(function(res){
+                console.log(res);
+                if(res.status == 200 && res.data.code == 200) {
+                    $eb.$swal('success',res.data.msg);
+                    _this.parents('tr').remove();
+                }else
+                    return Promise.reject(res.data.msg || '删除失败')
+            }).catch(function(err){
+                $eb.$swal('error',err);
+            });
+        })
+    });
+    $(document).on('click',".open_image",function (e) {
+        var image = $(this).data('image');
+        $eb.openImage(image);
+    });
+</script>
+{/block}

+ 108 - 0
app/api/controller/user/MobileRechargeController.php

@@ -0,0 +1,108 @@
+<?php
+
+namespace app\api\controller\user;
+
+use app\models\system\SystemGroupData;
+use app\models\user\UserMobileRecharge;
+use app\Request;
+use crmeb\services\UtilService;
+use think\facade\Log;
+
+/**
+ * 充值类
+ * Class UserRechargeController
+ * @package app\api\controller\user
+ */
+class MobileRechargeController
+{
+
+    /**
+     * 小程序充值
+     *
+     * @param Request $request
+     * @return mixed
+     */
+    public function routine(Request $request)
+    {
+        list($recharId, $mobile) = UtilService::postMore([['rechar_id', 0], ['mobile', '']], $request, true);
+        if (!$recharId) return app('json')->fail('请选择充值金额!');
+        if (!not_empty_check($mobile) || !mobile_check($mobile)) return app('json')->fail('请输入正确的手机号码!');
+        if ($recharId) {
+            $data = SystemGroupData::getDateValue($recharId);
+            if ($data === false) {
+                return app('json')->fail('您选择的充值方式已下架!');
+            } else {
+                $get_money = $data['get_money'] ?? 0;
+            }
+        }
+        $price = $data['price'];
+        $rechargeOrder = UserMobileRecharge::addRecharge($request->uid(), $mobile, $price, 'weixin', $get_money);
+        if (!$rechargeOrder) return app('json')->fail('充值订单生成失败!');
+        try {
+            return app('json')->successful(UserMobileRecharge::jsPay($rechargeOrder));
+        } catch (\Exception $e) {
+            return app('json')->fail($e->getMessage());
+        }
+    }
+
+    /**
+     * 公众号充值
+     *
+     * @param Request $request
+     * @return mixed
+     */
+    public function wechat(Request $request)
+    {
+        list($recharId, $mobile, $from) = UtilService::postMore([['rechar_id', 0], ['mobile', ''], ['from', 'weixin']], $request, true);
+        if (!$recharId) return app('json')->fail('请选择充值金额!');
+        if (!not_empty_check($mobile) || !mobile_check($mobile)) return app('json')->fail('请输入正确的手机号码!');
+        if ($recharId) {
+            $data = SystemGroupData::getDateValue($recharId);
+            if ($data === false) {
+                return app('json')->fail('您选择的充值方式已下架!');
+            } else {
+                $get_money = $data['get_money'] ?? 0;
+            }
+        }
+        $price = $data['price'];
+        $rechargeOrder = UserMobileRecharge::addRecharge($request->uid(), $mobile, $price, 'weixin', $get_money);
+        if (!$rechargeOrder) return app('json')->fail('充值订单生成失败!');
+        try {
+            if ($from == 'weixinh5') {
+                $recharge = UserMobileRecharge::wxH5Pay($rechargeOrder);
+            } else {
+                $recharge = UserMobileRecharge::wxPay($rechargeOrder);
+            }
+        } catch (\Exception $e) {
+            return app('json')->fail($e->getMessage());
+        }
+        return app('json')->successful(['type' => $from, 'data' => $recharge]);
+    }
+
+    /**
+     * 充值额度选择
+     * @return mixed
+     */
+    public function index()
+    {
+        $rechargeQuota = sys_data('user_mobile_recharge_quota') ?? [];
+        $data['recharge_quota'] = $rechargeQuota;
+        $recharge_attention = sys_config('mobile_recharge_attention');
+        $recharge_attention = explode("\n", $recharge_attention);
+        $data['recharge_attention'] = $recharge_attention;
+        return app('json')->successful($data);
+    }
+
+    public function notify(Request $request)
+    {
+        $date = $request->post();
+        if ($date['status'] == 'SUCCESS') {
+            UserMobileRecharge::where('order_id', $date['orderId'])->update(['status', 1]);
+            return 'SUCCESS';
+        } else {
+            UserMobileRecharge::where('order_id', $date['orderId'])->update(['status', 2]);
+            Log::error($date['orderId'] . '充值失败');
+            return 'SUCCESS';
+        }
+    }
+}

+ 32 - 0
app/models/store/Card.php

@@ -0,0 +1,32 @@
+<?php
+/**
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2017/11/11
+ */
+
+namespace app\models\store;
+
+use crmeb\traits\ModelTrait;
+use crmeb\basic\BaseModel;
+
+/**
+ * 商品浏览分析
+ * Class StoreVisit
+ * @package app\admin\model\store
+ */
+class Card extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'card';
+
+    use ModelTrait;
+}

+ 130 - 0
app/models/user/UserMobileRecharge.php

@@ -0,0 +1,130 @@
+<?php
+/**
+ *
+ * @author: xaboy<365615158@qq.com>
+ * @day: 2018/01/05
+ */
+
+namespace app\models\user;
+
+use crmeb\basic\BaseModel;
+use crmeb\services\AlipayService;
+use crmeb\services\MiniProgramService;
+use crmeb\services\MobileRechargeService;
+use crmeb\services\SystemConfigService;
+use crmeb\services\WechatService;
+use crmeb\traits\ModelTrait;
+use think\facade\Log;
+
+/**
+ * TODO 用户充值
+ * Class UserRecharge
+ * @package app\models\user
+ */
+class UserMobileRecharge extends BaseModel
+{
+    /**
+     * 数据表主键
+     * @var string
+     */
+    protected $pk = 'id';
+
+    /**
+     * 模型名称
+     * @var string
+     */
+    protected $name = 'user_mobile_recharge';
+
+    use ModelTrait;
+
+    protected $insert = ['add_time'];
+
+    protected function setAddTimeAttr()
+    {
+        return time();
+    }
+
+    /**
+     * 创建充值订单
+     * @param $uid
+     * @param $price
+     * @param string $recharge_type
+     * @param int $paid
+     * @return UserRecharge|bool|\think\Model
+     */
+    public static function addRecharge($uid, $mobile, $price, $recharge_type = 'weixin', $get_money = 0, $paid = 0)
+    {
+        $order_id = self::getNewOrderId($uid);
+        if (!$order_id) return self::setErrorInfo('订单生成失败!');
+        $add_time = time();
+        return self::create(compact('order_id', 'get_money', 'uid', 'mobile', 'price', 'recharge_type', 'paid', 'add_time'));
+    }
+
+    /**
+     * 生成充值订单号
+     * @param int $uid
+     * @return bool|string
+     */
+    public static function getNewOrderId($uid = 0)
+    {
+        if (!$uid) return false;
+        $count = (int)self::where('uid', $uid)->where('add_time', '>=', strtotime(date("Y-m-d")))->where('add_time', '<', strtotime(date("Y-m-d", strtotime('+1 day'))))->count();
+        return 'mr' . date('YmdHis', time()) . (10000 + $count + $uid);
+    }
+
+    /**
+     * 充值js支付
+     * @param $orderInfo
+     * @return array|string
+     * @throws \Exception
+     */
+    public static function jsPay($orderInfo)
+    {
+        return MiniProgramService::jsPay(WechatUser::uidToOpenid($orderInfo['uid']), $orderInfo['order_id'], $orderInfo['price'], 'mobile_recharge', '用户充值话费');
+    }
+
+
+    /**
+     * 微信H5支付
+     * @param $orderInfo
+     * @return mixed
+     */
+    public static function wxH5Pay($orderInfo)
+    {
+        return WechatService::paymentPrepare(null, $orderInfo['order_id'], $orderInfo['price'], 'mobile_recharge', '用户充值话费', '', 'MWEB');
+    }
+
+    /**
+     * 公众号支付
+     * @param $orderInfo
+     * @return array|string
+     * @throws \Exception
+     */
+    public static function wxPay($orderInfo)
+    {
+        return WechatService::jsPay(WechatUser::uidToOpenid($orderInfo['uid'], 'openid'), $orderInfo['order_id'], $orderInfo['price'], 'mobile_recharge', '用户充值话费');
+    }
+
+    /**
+     * //TODO用户充值成功后
+     * @param $orderId
+     */
+    public static function rechargeSuccess($orderId)
+    {
+        $order = self::where('order_id', $orderId)->where('paid', 0)->find();
+        if (!$order) return false;
+        self::beginTrans();
+        $res1 = self::where('order_id', $order['order_id'])->update(['paid' => 1, 'pay_time' => time()]);
+        $res = MobileRechargeService::fastRecharge($order['mobile'], $orderId, $order['get_money']);
+        if ($res['return_code'] != 200 || $res['result_code'] != 'SUCCESS') {
+            Log::error($res['return_msg']);
+            $res = MobileRechargeService::slowRecharge($order['mobile'], $orderId, $order['get_money']);
+            if ($res['return_code'] != 200 || $res['result_code'] != 'SUCCESS') {
+                Log::error($res['return_msg']);
+            }
+        }
+        //充值
+        self::checkTrans($res1);
+        return $res1;
+    }
+}

+ 16 - 0
crmeb/repositories/PaymentRepositories.php

@@ -3,6 +3,7 @@
 namespace crmeb\repositories;
 
 use app\models\store\StoreOrder;
+use app\models\user\UserMobileRecharge;
 use app\models\user\UserRecharge;
 
 /**
@@ -58,6 +59,21 @@ class PaymentRepositories
         }
     }
 
+    /**
+     * 订单支付成功之后
+     * @param string|null $order_id 订单id
+     * @return bool
+     */
+    public static function wechatMobileRecharge(string $order_id = null)
+    {
+        try {
+            if (UserMobileRecharge::be(['order_id' => $order_id, 'paid' => 1])) return true;
+            return UserMobileRecharge::rechargeSuccess($order_id);
+        } catch (\Exception $e) {
+            return false;
+        }
+    }
+
     /**
      * 充值成功后
      * @param string|null $order_id 订单id

+ 97 - 0
crmeb/services/MobileRechargeService.php

@@ -0,0 +1,97 @@
+<?php
+
+
+namespace crmeb\services;
+
+
+use app\models\user\UserMobileRecharge;
+
+class MobileRechargeService
+{
+    private static $domain = 'https://api.nyyun.cn';
+
+    private static $app_id = 'nyeu184mkg';
+
+    private static $app_secret = '7e226a8469b045d493c378e21c20b68d';
+
+    /**
+     * @param $params
+     * @return string
+     */
+    private static function getSign($params): string
+    {
+        $key = self::$app_secret;
+        ksort($params);
+        $sign = '';
+        foreach ($params as $ke => $value) {
+            if ($value !== '') $sign .= sprintf('%s=%s&', $ke, $value);
+        }
+        return strtoupper(md5($sign . 'key=' . $key));
+    }
+
+    /**
+     * @param $mobile
+     * @param $order_id
+     * @param $money
+     * @return mixed
+     */
+    public static function fastRecharge($mobile, $order_id, $money)
+    {
+        $url = "/api/recharge/server";
+
+        $domain = sys_config('site_url', '');
+        if (strstr($domain, 'http://')) {
+            $domain = substr($domain, 7);
+        } else {
+            $domain = substr($domain, 8);
+        }
+
+        $time = time();
+
+        $data = [
+            'appId' => self::$app_id,
+            'mobile' => $mobile,
+            'orderId' => $order_id,
+            'amount' => $money,
+            'notifyUrl' => sys_config('site_url', '') . '/api/mobile/notify',
+            'timestamp' => $time,
+            'urlHost' => $domain];
+        $data['sign'] = self::getSign($data);
+
+        $res = do_request(self::$domain . $url, $data);
+        return json_decode($res, true);
+    }
+
+    /**
+     * @param $mobile
+     * @param $order_id
+     * @param $money
+     * @return mixed
+     */
+    public static function slowRecharge($mobile, $order_id, $money)
+    {
+        $url = "/api/rechargeslow/server";
+
+        $domain = sys_config('site_url', '');
+        if (strstr($domain, 'http://')) {
+            $domain = substr($domain, 7);
+        } else {
+            $domain = substr($domain, 8);
+        }
+
+        $time = time();
+
+        $data = [
+            'appId' => self::$app_id,
+            'mobile' => $mobile,
+            'orderId' => $order_id,
+            'amount' => $money,
+            'notifyUrl' => sys_config('site_url', '') . '/api/mobile/notify',
+            'timestamp' => $time,
+            'urlHost' => $domain];
+        $data['sign'] = self::getSign($data);
+
+        $res = do_request(self::$domain . $url, $data);
+        return json_decode($res, true);
+    }
+}

+ 6 - 0
route/api/route.php

@@ -180,6 +180,12 @@ Route::group(function () {
     Route::post('recharge/routine', 'user.UserRechargeController/routine')->name('rechargeRoutine');//小程序充值
     Route::post('recharge/wechat', 'user.UserRechargeController/wechat')->name('rechargeWechat');//公众号充值
     Route::get('recharge/index', 'user.UserRechargeController/index')->name('rechargeQuota');//充值余额选择
+
+
+    Route::post('mobile_recharge/routine', 'user.MobileRechargeController/routine')->name('MobileRechargeRoutine');//公众号充值
+    Route::post('mobile_recharge/wechat', 'user.MobileRechargeController/wechat')->name('MobileRechargeWechat');//公众号充值
+    Route::get('mobile_recharge/index', 'user.MobileRechargeController/index')->name('MobileRechargeQuota');//充值余额选择
+
     //会员等级类
     Route::get('menu/user', 'PublicController/menu_user')->name('menuUser');//个人中心菜单
     Route::get('user/level/detection', 'user.UserLevelController/detection')->name('userLevelDetection');//检测用户是否可以成为会员