Ver código fonte

退役军人后台

linwu 9 meses atrás
pai
commit
3c6b42fa47
29 arquivos alterados com 1616 adições e 88 exclusões
  1. 375 0
      app/admin/controller/Soldier.php
  2. 18 0
      app/admin/controller/Upload.php
  3. 2 2
      app/admin/view/company/info.html
  4. 139 0
      app/admin/view/soldier/user.html
  5. 71 0
      app/admin/view/soldier/user_form.html
  6. 164 0
      app/admin/view/soldier/video.html
  7. 191 0
      app/admin/view/soldier/video_form.html
  8. 126 0
      app/admin/view/soldier/video_series.html
  9. 94 0
      app/admin/view/soldier/video_series_form.html
  10. 58 0
      app/admin/view/soldier/video_watch.html
  11. 27 0
      app/common/model/SoldierModel.php
  12. 26 0
      app/common/model/SoldierVideoModel.php
  13. 26 0
      app/common/model/SoldierVideoSeriesModel.php
  14. 34 0
      app/common/model/SoldierVideoWatchModel.php
  15. 20 0
      app/common/validate/SoldierUserValidate.php
  16. 21 0
      app/common/validate/SoldierVideoSeriesValidate.php
  17. 23 0
      app/common/validate/SoldierVideoValidate.php
  18. 14 0
      app/mobile/controller/Soldier.php
  19. 101 0
      app/mobile/view/soldier/login.html
  20. BIN
      public/static/common/exl/soldier_user.xls
  21. BIN
      public/static/mobile/images/bg_login.jpg
  22. 18 18
      vendor/phpoffice/phpexcel/Classes/PHPExcel/Calculation.php
  23. 7 7
      vendor/phpoffice/phpexcel/Classes/PHPExcel/Cell.php
  24. 2 2
      vendor/phpoffice/phpexcel/Classes/PHPExcel/Cell/DefaultValueBinder.php
  25. 48 48
      vendor/phpoffice/phpexcel/Classes/PHPExcel/Reader/Excel5.php
  26. 2 2
      vendor/phpoffice/phpexcel/Classes/PHPExcel/ReferenceHelper.php
  27. 2 2
      vendor/phpoffice/phpexcel/Classes/PHPExcel/Shared/OLE.php
  28. 6 6
      vendor/phpoffice/phpexcel/Classes/PHPExcel/Shared/String.php
  29. 1 1
      vendor/phpoffice/phpexcel/Classes/PHPExcel/Worksheet/AutoFilter.php

+ 375 - 0
app/admin/controller/Soldier.php

@@ -0,0 +1,375 @@
+<?php
+
+namespace app\admin\controller;
+
+use app\admin\AdminBaseController;
+use app\common\model\SoldierModel;
+use app\common\model\SoldierVideoModel;
+use app\common\model\SoldierVideoSeriesModel;
+use app\common\model\SoldierVideoWatchModel;
+use app\common\validate\SoldierUserValidate;
+use app\common\validate\SoldierVideoSeriesValidate;
+use app\common\validate\SoldierVideoValidate;
+use think\exception\ValidateException;
+
+class Soldier extends AdminBaseController
+{
+    /**
+     * 用户列表
+     */
+    public function user()
+    {
+        return view('', [
+            'status_list' => SoldierModel::STATUS,
+        ]);
+    }
+
+    public function listUser()
+    {
+        $map   = $this->dealEqualInput(['status'], $this->dealLikeInput(['keywords' => 'name|mobile']));
+        $list  = SoldierModel::where($map)
+            ->order('id', 'desc')
+            ->limit(input('limit'))
+            ->page(input('page'))
+            ->append(['status_text'])->select();
+        $count = SoldierModel::where($map)->count();
+        if ($count == 0) {
+            ajax_return(1, '未查询到数据');
+        }
+        list_return($list, $count);
+    }
+
+    public function delUser()
+    {
+        $id = input('id/d', 0);
+        if (empty($id)) {
+            ajax_return(1, '未查询到数据');
+        }
+
+        SoldierModel::destroy($id);
+        SoldierVideoWatchModel::destroy(['user_id' => $id]);
+
+        ajax_return();
+    }
+
+    /**
+     * 编辑用户
+     */
+    public function userForm()
+    {
+        $id   = input('id/d', 0);
+        $info = SoldierModel::find($id);
+        return view('', [
+            'info'        => $info,
+            'status_list' => SoldierModel::STATUS,
+        ]);
+    }
+
+    public function editUser()
+    {
+        $data = input('post.');
+        try {
+            validate(SoldierUserValidate::class)->check($data);
+        } catch (ValidateException $e) {
+            ajax_return(1, $e->getError());
+        }
+
+        //手机号
+        $check_mobile_where = [['mobile', '=', $data['mobile']]];
+        if (!empty($data['id'])) {
+            $check_mobile_where[] = ['id', '<>', $data['id']];
+        }
+        $check_mobile = SoldierModel::where($check_mobile_where)->find();
+        if (!empty($check_mobile)) {
+            ajax_return(1, '手机号已存在');
+        }
+
+        //密码
+        if (empty($data['id']) && empty($data['password'])) {
+            ajax_return(1, '请输入一个初始密码');
+        }
+        if (empty($data['password'])) {
+            unset($data['password']);
+        } else {
+            $data['salt']     = rand_str();
+            $data['password'] = md5(md5($data['salt']) . $data['password']);
+        }
+
+        if (empty($data['id'])) {
+            SoldierModel::create($data);
+        } else {
+            SoldierModel::update($data, ['id' => $data['id']]);
+        }
+
+        ajax_return();
+    }
+
+    /**
+     * 用户导入
+     */
+    public function importUser()
+    {
+        return view('public/import', [
+            'url'           => url('soldier/importUserPost'),
+            'last_table'    => 'lay-soldier-user-table',
+            'template_file' => '/static/common/exl/soldier_user.xls',
+        ]);
+    }
+
+    /**
+     * 用户导入提交
+     */
+    public function importUserPost()
+    {
+        $file_url = input('file_url/s', "");
+        if (!file_exists($file_url)) {
+            ajax_return(1, '文件不存在');
+        }
+
+        //初始化数据
+        $data = ['name', 'mobile', 'password'];
+        $list = import_exl($file_url, $data, 1);
+        if (empty($list)) {
+            ajax_return(1, '请上传有数据的文件');
+        }
+        $empty_check = [
+            'name'     => '姓名',
+            'mobile'   => '手机号',
+            'password' => '密码',
+        ];
+
+        //获取手机号
+        $mobile_list       = array_column($list, 'mobile');
+        $mobile_check_list = SoldierModel::where('mobile', 'in', $mobile_list)->column('mobile');
+
+        //错误判断
+        $validate = \think\facade\Validate::rule('mobile', 'mobile');
+        foreach ($list as $k => $v) {
+            foreach ($empty_check as $key => $value) {
+                if (empty($v[$key])) {
+                    return ajax_return(1, '第' . ($k + 2) . '行的' . $value . '不能为空');
+                }
+            }
+            if (!$validate->check($v)) {
+                return ajax_return(1, '第' . ($k + 2) . '行的手机号格式不对');
+            }
+            if (!empty(in_array($v['mobile'], $mobile_check_list))) {
+                return ajax_return(1, '第' . ($k + 2) . '行的手机号已存在');
+            }
+            $list[$k]['salt']     = rand_str();
+            $list[$k]['password'] = md5(md5($list[$k]['salt']) . $v['password']);
+        }
+
+        SoldierModel::insertAll($list);
+        ajax_return(0);
+    }
+
+    /**
+     * 视频系列列表
+     */
+    public function videoSeries()
+    {
+        return view('', [
+            'status_list' => SoldierVideoSeriesModel::STATUS,
+        ]);
+    }
+
+    public function listVideoSeries()
+    {
+        $map   = $this->dealEqualInput(['status'], $this->dealLikeInput(['title']));
+        $list  = SoldierVideoSeriesModel::where($map)
+            ->order('priority desc,id desc')
+            ->limit(input('limit'))
+            ->page(input('page'))
+            ->append(['status_text'])->select();
+        $count = SoldierVideoSeriesModel::where($map)->count();
+        if ($count == 0) {
+            ajax_return(1, '未查询到数据');
+        }
+        list_return($list, $count);
+    }
+
+    public function delVideoSeries()
+    {
+        $id = input('id/d', 0);
+        if (empty($id)) {
+            ajax_return(1, '未查询到数据');
+        }
+
+        $check = SoldierVideoModel::where('series_id', $id)->find();
+        if (!empty($check)) {
+            ajax_return(1, '该系列下有视频,无法删除');
+        }
+
+        SoldierVideoSeriesModel::destroy($id);
+
+        ajax_return();
+    }
+
+    /**
+     * 编辑视频系列
+     */
+    public function videoSeriesForm()
+    {
+        $id   = input('id/d', 0);
+        $info = SoldierVideoSeriesModel::find($id);
+        return view('', [
+            'info'        => $info,
+            'status_list' => SoldierVideoSeriesModel::STATUS,
+        ]);
+    }
+
+    public function editVideoSeries()
+    {
+        $data = input('post.');
+        try {
+            validate(SoldierVideoSeriesValidate::class)->check($data);
+        } catch (ValidateException $e) {
+            ajax_return(1, $e->getError());
+        }
+
+        if (empty($data['id'])) {
+            SoldierVideoSeriesModel::create($data);
+        } else {
+            SoldierVideoSeriesModel::update($data);
+        }
+
+        ajax_return();
+    }
+
+    /**
+     * 视频列表
+     */
+    public function video()
+    {
+        $series_list = SoldierVideoSeriesModel::where('status', SoldierVideoSeriesModel::STATUS_SHOW)->order('priority desc')->select();
+        return view('', [
+            'status_list' => SoldierVideoModel::STATUS,
+            'series_list' => $series_list,
+        ]);
+    }
+
+    public function listVideo()
+    {
+        $map   = $this->dealEqualInput(['status'], $this->dealLikeInput(['title']));
+        $list  = SoldierVideoModel::with(['series'])
+            ->where($map)
+            ->order('priority desc,id desc')
+            ->limit(input('limit'))
+            ->page(input('page'))
+            ->append(['status_text'])->select();
+        $count = SoldierVideoModel::where($map)->count();
+        if ($count == 0) {
+            ajax_return(1, '未查询到数据');
+        }
+        list_return($list, $count);
+    }
+
+    public function delVideo()
+    {
+        $id = input('id/d', 0);
+        if (empty($id)) {
+            ajax_return(1, '未查询到数据');
+        }
+
+        $check = SoldierVideoWatchModel::where('video_id', $id)->find();
+        if (!empty($check)) {
+            ajax_return(1, '该视频下有观看记录,无法删除');
+        }
+
+        SoldierVideoModel::destroy($id);
+
+        ajax_return();
+    }
+
+    /**
+     * 编辑视频
+     */
+    public function videoForm()
+    {
+        $id          = input('id/d', 0);
+        $series_list = SoldierVideoSeriesModel::where('status', SoldierVideoSeriesModel::STATUS_SHOW)->order('priority desc')->select();
+        $info        = SoldierVideoModel::find($id);
+        return view('', [
+            'info'        => $info,
+            'status_list' => SoldierVideoModel::STATUS,
+            'series_list' => $series_list,
+        ]);
+    }
+
+    public function editVideo()
+    {
+        $data = input('post.');
+        try {
+            validate(SoldierVideoValidate::class)->check($data);
+        } catch (ValidateException $e) {
+            ajax_return(1, $e->getError());
+        }
+
+        if (empty($data['id'])) {
+            SoldierVideoModel::create($data);
+        } else {
+            SoldierVideoModel::update($data);
+        }
+
+        ajax_return();
+    }
+
+    /**
+     * 观看记录
+     */
+    public function videoWatch()
+    {
+        $id = input('id/d', 0);
+        if (empty($id)) {
+            return '请选择视频';
+        }
+
+        return view('', [
+            'id' => $id,
+        ]);
+    }
+
+    public function listVideoWatch()
+    {
+        $id = input('id/d', 0);
+        if (empty($id)) {
+            ajax_return(1, '请选择视频');
+        }
+
+        $list = SoldierVideoWatchModel::with(['user'])
+            ->where('video_id', $id)
+            ->limit(input('limit'))
+            ->page(input('page'))
+            ->append(['status_text'])
+            ->select();
+        $count = SoldierVideoWatchModel::where('video_id', $id)->count();
+
+        if ($count == 0) {
+            ajax_return(1, '未查询到数据');
+        }
+        list_return($list, $count);
+    }
+
+    public function exportVideoWatch()
+    {
+        $id = input('id/d', 0);
+        if (empty($id)) {
+            ajax_return(1, '请选择视频');
+        }
+
+        $video = SoldierVideoModel::find($id);
+        $list = SoldierVideoWatchModel::with(['user'])->where('video_id', $id)->append(['status_text'])->select();
+        foreach ($list as $v) {
+            $v['user_name'] = $v['user']['name'];
+        }
+        $xlsCell = [
+            ['id', '表ID'],
+            ['user_name', '姓名'],
+            ['status_text', '状态'],
+            ['create_time', '首次学习时间'],
+            ['update_time', '最后学习时间'],
+        ];
+        export_exl($video['title']."的观看记录", $xlsCell, $list);
+    }
+}

+ 18 - 0
app/admin/controller/Upload.php

@@ -43,4 +43,22 @@ class Upload extends AdminBaseController
             ajax_return(1, '上传失败,请稍后重试');
         }
     }
+
+    /**
+     * 视频上传
+     */
+    public function video()
+    {
+        $file     = request()->file("file");
+        $savename = \think\facade\Filesystem::disk('public')->putFile('video', $file);
+        if ($file) {
+            $filename = str_replace(strrchr($_FILES['file']['name'], "."), "", $_FILES['file']['name']);
+            ajax_return(0, '', [
+                'src'   => request()->domain() . "/storage/" . str_replace("\\", "/", $savename),
+                'title' => $filename,
+            ]);
+        } else {
+            ajax_return(1, '上传失败,请稍后重试');
+        }
+    }
 }

+ 2 - 2
app/admin/view/company/info.html

@@ -205,12 +205,12 @@
                                 <tr>
                                     <td colspan="2" onclick="copyMobileUrl('https://110.88.129.62:8443');">IP:https://110.88.129.62:8443</td>
                                     <td onclick="copyMobileUrl('jjrencai');">用户名:jjrencai</td>
-                                    <td onclick="copyMobileUrl('Mq5qdWPBg5SS#!Tk');">密码:Mq5qdWPBg5SS#!Tk</td>
+                                    <td onclick="copyMobileUrl('MGK@c#svu6G2');">密码:MGK@c#svu6G2</td>
                                 </tr>
                                 <tr>
                                     <td onclick="copyMobileUrl('https://172.21.134.92');">网址:https://172.21.134.92</td>
                                     <td onclick="copyMobileUrl('jjrencai');">用户名:jjrencai</td>
-                                    <td onclick="copyMobileUrl('DvNCeXtxMI!9Enib');">密码:DvNCeXtxMI!9Enib</td>
+                                    <td onclick="copyMobileUrl('fGfCjb^jCH!J');">密码:fGfCjb^jCH!J</td>
                                     <td onclick="copyMobileUrl('D:\\install\\Navicat Premium 15\\navicat.exe');">navicate:D:\install\Navicat Premium 15\navicat.exe</td>
                                 </tr>
                             </tbody>

+ 139 - 0
app/admin/view/soldier/user.html

@@ -0,0 +1,139 @@
+<style>
+
+</style>
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-form layui-form-pane  layui-card-header layuiadmin-card-header-auto">
+            <div class="layui-form-item">
+                <div class="layui-inline">
+                    <label class="layui-form-label">关键字</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="keywords" placeholder="请输入姓名/手机号" autocomplete="off" class="layui-input">
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <label class="layui-form-label">状态</label>
+                    <div class="layui-input-block">
+                        <select name="status">
+                            <option value="">全部状态</option>
+                            {volist name="status_list" id="v"}
+                            <option value="{$key}">{$v}</option>
+                            {/volist}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <button class="layui-btn" lay-submit lay-filter="{$lay_btn}">
+                        <i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
+                    </button>
+                </div>
+            </div>
+        </div>
+        <div class="layui-form layui-card-header layuiadmin-card-header-auto">
+            <button class="layui-btn layuiadmin-btn" data-type="add">添加新用户</button>
+            <button class="layui-btn layuiadmin-btn" data-type="import">批量导入</button>
+        </div>
+
+        <div class="layui-card-body">
+            <table id="{$lay_table}" lay-filter="{$lay_table}"></table>
+            <script type="text/html" id="setTpl">
+                <a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
+                <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
+            </script>
+        </div>
+    </div>
+</div>
+
+<script>
+    layui.use(['index', 'admin', 'form', 'table'], function () {
+        const $ = layui.$;
+        const admin = layui.admin;
+        const form = layui.form;
+        const table = layui.table;
+        form.render();
+
+        table.render({
+            elem: '#{$lay_table}',
+            url: "{:url('soldier/listUser')}",
+            cols: [
+                [
+                    {field: 'id', title: 'ID' ,width: 100},
+                    {field: 'name', title: '姓名' ,width: 200},
+                    {field: 'mobile', title: '手机号', width: 200},
+                    {field: 'status_text', title: '状态', width: 200, align: 'center'},
+                    {title: '操作', align: 'center', fixed: 'right', toolbar: '#setTpl'}
+                ]
+            ],
+            page: true,
+            limit: 50,
+            cellMinWidth: 150,
+            text: '对不起,加载出现异常!'
+        });
+
+        form.on('submit({$lay_btn})', function (data) {
+            table.reload('{$lay_table}', {
+                where: data.field,
+                page: {
+                    curr: 1
+                }
+            });
+        });
+
+        //事件
+        const active = {
+            add: function () {
+                const index = layer.open({
+                    type: 2,
+                    title: '添加用户',
+                    content: "{:url('soldier/userForm')}",
+                    maxmin: true,
+                    area: ['550px', '550px']
+                });
+                layer.full(index);
+            },
+            import: function() {
+                layer.open({
+                    type: 2,
+                    title: '批量导入',
+                    content: "{:url('soldier/importUser')}",
+                    maxmin: true,
+                    area: ['750px', '300px']
+                });
+            },
+        };
+
+        //监听工具条
+        table.on('tool({$lay_table})', function (obj) {
+            const data = obj.data;
+            if (obj.event === 'del') {
+                layer.confirm('删除用户的同时会删除用户观看记录,确定删除此用户吗?', function (index) {
+                    admin.req({
+                        url: "{:url('soldier/delUser')}",
+                        data: {
+                            id: data.id
+                        },
+                        done: function (res) {
+                            obj.del();
+                            layer.msg('已删除');
+                        }
+                    });
+                    layer.close(index);
+                });
+            } else if (obj.event === 'edit') {
+                const index = layer.open({
+                    type: 2,
+                    title: '编辑用户',
+                    content: "{:url('soldier/userForm')}?id=" + data.id,
+                    maxmin: true,
+                    area: ['550px', '550px']
+                });
+                layer.full(index);
+            }
+        });
+
+        $('.layui-btn.layuiadmin-btn').on('click', function () {
+            const type = $(this).data('type');
+            active[type] ? active[type].call(this) : '';
+        });
+    });
+</script>

+ 71 - 0
app/admin/view/soldier/user_form.html

@@ -0,0 +1,71 @@
+<div class="layui-fluid">
+    <div class="layui-row layui-col-space15">
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">用户信息</div>
+                <div class="layui-card-body" pad15>
+                    <div class="layui-form layui-form-pane" lay-filter="{$lay_table}">
+                        <input type="hidden" name="id" value="{:array_get($info,'id')}" />
+                        <div class="layui-form-item">
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>用户名</label>
+                            <div class="layui-input-block">
+                                <input type="text" name="name" value="{:array_get($info,'name')}" lay-verify="required" placeholder="请输入用户名"
+                                       autocomplete="off" class="layui-input">
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>手机号</label>
+                            <div class="layui-input-block">
+                                <input type="text" name="mobile" value="{:array_get($info,'mobile')}" lay-verify="required|phone" placeholder="请输入手机号"
+                                       autocomplete="off" class="layui-input">
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label">密码</label>
+                            <div class="layui-input-block">
+                                <input type="text" name="password" placeholder="请输入登录密码,不修改留空" autocomplete="off" class="layui-input">
+                            </div>
+                        </div>
+                        <div class="layui-form-item" pane>
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>状态</label>
+                            <div class="layui-input-block">
+                                {volist name="status_list" id="v"}
+                                <input type="radio" name="status" lay-filter="type" value="{$key}" title="{$v}" {eq name=":array_get($info,'status',1)" value="$key" }checked{/eq}>
+                                {/volist}
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <div class="layui-input-block">
+                                <input type="button" lay-submit lay-filter="{$lay_btn}" value="确认提交" class="layui-btn">
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+
+<script>
+    layui.use(['index', 'form', 'upload', 'laydate'], function () {
+        const admin = layui.admin;
+        const form = layui.form;
+        form.render();
+
+        form.on('submit({$lay_btn})', function (obj) {
+            const index = parent.layer.getFrameIndex(window.name);
+            admin.req({
+                url: "{:url('soldier/editUser')}",
+                type: 'post',
+                data: obj.field,
+                done: function (res) {
+                    layer.msg("提交成功", {
+                        icon: 1
+                    });
+                    parent.layui.table.reload('lay-soldier-user-table'); //重载表格
+                    parent.layer.close(index);
+                }
+            });
+        });
+    });
+</script>

+ 164 - 0
app/admin/view/soldier/video.html

@@ -0,0 +1,164 @@
+<style>
+    .layui-table-cell {height:45px;line-height:unset;}
+    .user-box {display:flex;}
+    .user-box .avatar{width:45px;height:45px;}
+    .user-box .content {margin-left:10px;}
+    .user-box .content .account {font-size:18px;color:#000;}
+    .user-box .content .sex {font-size:14px;color:red;}
+    .user-box .content .info {font-size:14px;margin-top:5px;}
+</style>
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-form layui-form-pane  layui-card-header layuiadmin-card-header-auto">
+            <div class="layui-form-item">
+                <div class="layui-inline">
+                    <label class="layui-form-label">关键字</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="title" placeholder="请输入标题" autocomplete="off" class="layui-input">
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <label class="layui-form-label">系列</label>
+                    <div class="layui-input-block">
+                        <select name="status">
+                            <option value="">全部系列</option>
+                            {volist name="series_list" id="v"}
+                            <option value="{$v.id}">{$v.title}</option>
+                            {/volist}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <label class="layui-form-label">状态</label>
+                    <div class="layui-input-block">
+                        <select name="status">
+                            <option value="">全部状态</option>
+                            {volist name="status_list" id="v"}
+                            <option value="{$key}">{$v}</option>
+                            {/volist}
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <button class="layui-btn" lay-submit lay-filter="{$lay_btn}">
+                        <i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
+                    </button>
+                </div>
+            </div>
+        </div>
+        <div class="layui-form layui-card-header layuiadmin-card-header-auto">
+            <button class="layui-btn layuiadmin-btn" data-type="add">添加</button>
+        </div>
+
+        <div class="layui-card-body">
+            <table id="{$lay_table}" lay-filter="{$lay_table}"></table>
+            <script type="text/html" id="seriesTpl">
+                {{d.series.title}}
+            </script>
+            <script type="text/html" id="userTpl">
+                <div class="user-box">
+                    <img src="{{d.main_image}}" class="avatar">
+                </div>
+            </script>
+            <script type="text/html" id="setTpl">
+                <a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
+                <a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="watch"><i class="layui-icon layui-icon-engine"></i>观看记录</a>
+                <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
+            </script>
+        </div>
+    </div>
+</div>
+
+<script>
+    layui.use(['index', 'admin', 'form', 'table'], function () {
+        const $ = layui.$;
+        const admin = layui.admin;
+        const form = layui.form;
+        const table = layui.table;
+        form.render();
+
+        table.render({
+            elem: '#{$lay_table}',
+            url: "{:url('soldier/listVideo')}",
+            cols: [
+                [
+                    {field: 'series', title: '系列', width: 200, templet: '#seriesTpl'},
+                    {field: 'title', title: '标题'},
+                    {field: 'main_image', title: '主图' ,width: 160, templet: '#userTpl'},
+                    {field: 'status_text', title: '状态', width: 80, align: 'center'},
+                    {title: '操作', width: 240, align: 'center', fixed: 'right', toolbar: '#setTpl'}
+                ]
+            ],
+            page: true,
+            limit: 50,
+            cellMinWidth: 150,
+            text: '对不起,加载出现异常!'
+        });
+
+        form.on('submit({$lay_btn})', function (data) {
+            table.reload('{$lay_table}', {
+                where: data.field,
+                page: {
+                    curr: 1
+                }
+            });
+        });
+
+        //事件
+        const active = {
+            add: function () {
+                const index = layer.open({
+                    type: 2,
+                    title: '添加视频',
+                    content: "{:url('soldier/videoForm')}",
+                    maxmin: true,
+                    area: ['550px', '550px']
+                });
+                layer.full(index);
+            },
+        };
+
+        //监听工具条
+        table.on('tool({$lay_table})', function (obj) {
+            const data = obj.data;
+            if (obj.event === 'del') {
+                layer.confirm('确定删除此视频吗?', function (index) {
+                    admin.req({
+                        url: "{:url('soldier/delVideo')}",
+                        data: {
+                            id: [data.id]
+                        },
+                        done: function (res) {
+                            obj.del();
+                            layer.msg('已删除');
+                        }
+                    });
+                    layer.close(index);
+                });
+            } else if (obj.event === 'edit') {
+                const index = layer.open({
+                    type: 2,
+                    title: '编辑视频',
+                    content: "{:url('soldier/videoForm')}?id=" + data.id,
+                    maxmin: true,
+                    area: ['550px', '550px']
+                });
+                layer.full(index);
+            } else if (obj.event === 'watch') {
+                const index = layer.open({
+                    type: 2,
+                    title: obj.data.title + '的观看记录',
+                    content: "{:url('soldier/videoWatch')}?id=" + data.id,
+                    maxmin: true,
+                    area: ['550px', '550px']
+                });
+                layer.full(index);
+            }
+        });
+
+        $('.layui-btn.layuiadmin-btn').on('click', function () {
+            const type = $(this).data('type');
+            active[type] ? active[type].call(this) : '';
+        });
+    });
+</script>

+ 191 - 0
app/admin/view/soldier/video_form.html

@@ -0,0 +1,191 @@
+<div class="layui-fluid">
+    <div class="layui-row layui-col-space15">
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">视频信息</div>
+                <div class="layui-card-body" pad15>
+                    <div class="layui-form layui-form-pane" lay-filter="{$lay_table}">
+                        <input type="hidden" name="id" value="{:array_get($info,'id')}" />
+                        <div class="layui-form-item" pane>
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>系列</label>
+                            <div class="layui-input-block">
+                                <select name="series_id" lay-verify="required">
+                                    {volist name="series_list" id="v"}
+                                    <option value="{$v.id}" {eq name=":array_get($info,'series_id')" value="$v['id']" }selected{/eq}>{$v.title}</option>
+                                    {/volist}
+                                </select>
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>标题</label>
+                            <div class="layui-input-block">
+                                <input type="text" name="title" value="{:array_get($info,'title')}" lay-verify="required" placeholder="请输入标题"
+                                       autocomplete="off" class="layui-input">
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>主图</label>
+                            <div class="layui-input-block">
+                                <div class="layui-upload">
+                                    <button type="button" class="layui-btn attachment-upload-images" data-input="main_image" data-amount="1">上传图片</button>
+                                    <div class="layui-inline layui-word-aux"> 最佳尺寸:320px*320px </div>
+                                    <div class="layui-upload-list echo-attachment-image-list" id="main_image">
+                                        {notempty name="info.main_image"}
+                                        <div>
+                                            <input type="hidden" name="main_image" value="{:array_get($info,'main_image')}">
+                                            <img src="{:array_get($info,'main_image')}">
+                                        </div>
+                                        {/notempty}
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>视频</label>
+                            <div class="layui-input-block">
+                                <div class="layui-upload">
+                                    <button type="button" class="layui-btn attachment-upload-video" data-input="video" data-amount="1">上传视频</button>
+                                    <div class="layui-inline layui-word-aux"> 请上传MP4格式的视频文件 </div>
+                                    <div class="layui-upload-list echo-attachment-video" id="video">
+                                        {notempty name="info.main_image"}
+                                        <div>
+                                            <input type="hidden" name="video" value="{:array_get($info,'video')}">
+                                            <video src="{:array_get($info,'video')}" controls></video>
+                                        </div>
+                                        {/notempty}
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>排序</label>
+                            <div class="layui-input-block">
+                                <input type="text" name="priority" value="{:array_get($info,'priority',255)}"
+                                       lay-verify="required" placeholder="请输入排序值(倒序,值越大越靠前)"
+                                       autocomplete="off" class="layui-input">
+                                <div class="layui-form-mid layui-word-aux">倒序,值越大越靠前</div>
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>状态</label>
+                            <div class="layui-input-block">
+                                {volist name="status_list" id="v"}
+                                <input type="radio" name="status" value="{$key}" title="{$v}" {eq name=":array_get($info,'status',1)" value="$key" }checked{/eq}>
+                                {/volist}
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <div class="layui-input-block">
+                                <input type="button" lay-submit lay-filter="{$lay_btn}" value="确认提交" class="layui-btn">
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+
+<script>
+    layui.use(['index', 'form', 'upload', 'laydate'], function () {
+        const $ = layui.$;
+        const admin = layui.admin;
+        const form = layui.form;
+        const upload = layui.upload;
+        const laydate = layui.laydate;
+        form.render();
+
+        laydate.render({
+            elem: '#birthday',
+            type: 'date'
+        });
+
+        form.on('submit({$lay_btn})', function (obj) {
+            const index = parent.layer.getFrameIndex(window.name);
+            admin.req({
+                url: "{:url('soldier/editVideo')}",
+                type: 'post',
+                data: obj.field,
+                done: function (res) {
+                    layer.msg("提交成功", {
+                        icon: 1
+                    });
+                    parent.layui.table.reload('lay-soldier-video-table'); //重载表格
+                    parent.layer.close(index);
+                }
+            });
+        });
+
+        let upload_input = '';
+        let upload_amount = '';
+        upload.render({
+            elem: '.attachment-upload-images',
+            url: "{:url('upload/image')}",
+            accept: 'images',
+            exits: 'jpg|png|jpeg',
+            acceptMime: 'image/*',
+            size: 2048,
+            number: 1,
+            method: 'post',
+            before: function(obj) {
+                var item = this.item;
+                upload_input = $(item).data('input');
+                upload_amount = $(item).data('amount');
+                layer.load();
+            },
+            done: function(res, index, upload) {
+                layer.closeAll('loading');
+                let html = "";
+                if (upload_amount == 1) {
+                    html += '<div> <input type="hidden" name="' + upload_input + '" value="' + res.data.src + '"> ';
+                    html += '<img src="' + res.data.src + '"></div>';
+                    $("#" + upload_input).html(html);
+                } else {
+                    html += '<div> <input type="hidden" name="' + upload_input + '[]" value="' + res.data.src + '"> ';
+                    html += '<img src="' + res.data.src +
+                        '"> <button type="button" class="attachment-del layui-btn layui-btn-primary layui-btn-xs layui-btn-fluid">删除</button></div>';
+                    $("#" + upload_input).append(html);
+                }
+            },
+            error: function(index, upload) {
+                layer.closeAll('loading');
+            }
+        });
+
+        let video_upload_input = '';
+        let video_upload_amount = '';
+        upload.render({
+            elem: '.attachment-upload-video',
+            url: "{:url('upload/video')}",
+            accept: 'video',
+            exits: 'mp4',
+            acceptMime: 'video/*',
+            size: 0,
+            number: 1,
+            method: 'post',
+            before: function(obj) {
+                var item = this.item;
+                video_upload_input = $(item).data('input');
+                video_upload_amount = $(item).data('amount');
+                layer.load();
+            },
+            done: function(res, index, upload) {
+                layer.closeAll('loading');
+                let html = "";
+                if (video_upload_amount == 1) {
+                    html += '<div> <input type="hidden" name="' + video_upload_input + '" value="' + res.data.src + '"> ';
+                    html += '<video src="' + res.data.src + '" controls></video></div>';
+                    $("#" + video_upload_input).html(html);
+                } else {
+                    html += '<div> <input type="hidden" name="' + video_upload_input + '[]" value="' + res.data.src + '"> ';
+                    html += '<video src="' + res.data.src +
+                        '"></video><button type="button" class="attachment-del layui-btn layui-btn-primary layui-btn-xs layui-btn-fluid">删除</button></div>';
+                    $("#" + video_upload_input).append(html);
+                }
+            },
+            error: function(index, upload) {
+                layer.closeAll('loading');
+            }
+        });
+    });
+</script>

+ 126 - 0
app/admin/view/soldier/video_series.html

@@ -0,0 +1,126 @@
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-form layui-form-pane layui-card-header layuiadmin-card-header-auto">
+            <div class="layui-inline">
+                <label class="layui-form-label">标题</label>
+                <div class="layui-input-block">
+                    <input type="text" name="title" placeholder="请输入标题" autocomplete="off" class="layui-input">
+                </div>
+            </div>
+            <div class="layui-inline">
+                <label class="layui-form-label">状态</label>
+                <div class="layui-input-block">
+                    <select name="status">
+                        <option value="">全部状态</option>
+                        {volist name="status_list" id="v"}
+                        <option value="{$key}">{$v}</option>
+                        {/volist}
+                    </select>
+                </div>
+            </div>
+            <div class="layui-inline">
+                <button class="layui-btn" lay-submit lay-filter="{$lay_btn}">
+                    <i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
+                </button>
+            </div>
+        </div>
+        <div class="layui-form layui-card-header layuiadmin-card-header-auto">
+            <button class="layui-btn layuiadmin-btn" data-type="add">添加</button>
+        </div>
+
+        <div class="layui-card-body">
+            <table id="{$lay_table}" lay-filter="{$lay_table}"></table>
+            <script type="text/html" id="setTpl">
+                <a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i
+                        class="layui-icon layui-icon-edit"></i>编辑</a>
+                <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i
+                        class="layui-icon layui-icon-delete"></i>删除</a>
+            </script>
+        </div>
+    </div>
+</div>
+
+<script>
+    layui.use(['index', 'form', 'set', 'table'], function () {
+        const $ = layui.$;
+        const admin = layui.admin;
+        const form = layui.form;
+        const table = layui.table;
+        form.render();
+
+        table.render({
+            elem: '#{$lay_table}',
+            url: "{:url('soldier/listVideoSeries')}",
+            cols: [
+                [
+                    {field: 'id', width: 80,title: '分类ID'},
+                    {field: 'title', title: '名称', edit: 'text'},
+                    {field: 'status_text', title: '状态', minWidth: 100, align: 'center'},
+                    {field: 'priority', width: 100, title: '排序', sort: true},
+                    {title: '操作', width: 150, align: 'center', fixed: 'right', toolbar: '#setTpl'}
+                ]
+            ],
+            page: true,
+            limit: 50,
+            cellMinWidth: 150,
+            text: '对不起,加载出现异常!'
+        });
+
+        form.on('submit({$lay_btn})', function (data) {
+            table.reload('{$lay_table}', {
+                where: data.field,
+                page: {
+                    curr: 1
+                }
+            });
+        });
+
+        //事件
+        const active = {
+            add: function () {
+                const index = layer.open({
+                    type: 2,
+                    title: '添加系列',
+                    content: "{:url('soldier/videoSeriesForm')}",
+                    maxmin: true,
+                    area: ['550px', '550px']
+                });
+                layer.full(index);
+            },
+        };
+
+        //监听工具条
+        table.on('tool({$lay_table})', function (obj) {
+            const data = obj.data;
+            if (obj.event === 'del') {
+                layer.confirm('确定删除此系列吗?', function (index) {
+                    admin.req({
+                        url: "{:url('soldier/delVideoSeries')}",
+                        data: {
+                            id: data.id
+                        },
+                        done: function (res) {
+                            obj.del();
+                            layer.msg('已删除');
+                        }
+                    });
+                    layer.close(index);
+                });
+            } else if (obj.event === 'edit') {
+                const index = layer.open({
+                    type: 2,
+                    title: '编辑系列',
+                    content: "{:url('soldier/videoSeriesForm')}?id=" + data.id,
+                    maxmin: true,
+                    area: ['550px', '550px']
+                });
+                layer.full(index);
+            }
+        });
+
+        $('.layui-btn.layuiadmin-btn').on('click', function () {
+            const type = $(this).data('type');
+            active[type] ? active[type].call(this) : '';
+        });
+    });
+</script>

+ 94 - 0
app/admin/view/soldier/video_series_form.html

@@ -0,0 +1,94 @@
+<div class="layui-fluid">
+    <div class="layui-row layui-col-space15">
+        <div class="layui-col-md12">
+            <div class="layui-card">
+                <div class="layui-card-header">系列信息</div>
+                <div class="layui-card-body" pad15>
+                    <div class="layui-form layui-form-pane" lay-filter="{$lay_table}">
+                        <input type="hidden" name="id" value="{:array_get($info,'id')}">
+                        <div class="layui-form-item">
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>标题</label>
+                            <div class="layui-input-block">
+                                <input type="text" name="title" value="{:array_get($info,'title')}" lay-verify="required"
+                                       placeholder="请输入分类名称" autocomplete="off"
+                                       class="layui-input">
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>开始时间</label>
+                            <div class="layui-input-block">
+                                <input type="text" name="start_time" id="start_time" value="{:array_get($info,'start_time')}" lay-verify="required"
+                                       placeholder="请选择..." autocomplete="off" class="layui-input">
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>结束时间</label>
+                            <div class="layui-input-block">
+                                <input type="text" name="end_time" id="end_time" value="{:array_get($info,'end_time')}" lay-verify="required"
+                                       placeholder="请选择..." autocomplete="off" class="layui-input">
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>排序</label>
+                            <div class="layui-input-block">
+                                <input type="text" name="priority" value="{:array_get($info,'priority',255)}"
+                                       lay-verify="required" placeholder="请输入排序值(倒序,值越大越靠前)"
+                                       autocomplete="off" class="layui-input">
+                                <div class="layui-form-mid layui-word-aux">倒序,值越大越靠前</div>
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <label class="layui-form-label"><span style="color:#f90c05;">*</span>状态</label>
+                            <div class="layui-input-block">
+                                {volist name="status_list" id="v"}
+                                <input type="radio" name="status" value="{$key}" title="{$v}" {eq name=":array_get($info,'status',1)" value="$key" }checked{/eq}>
+                                {/volist}
+                            </div>
+                        </div>
+                        <div class="layui-form-item">
+                            <div class="layui-input-block">
+                                <input type="button" lay-submit lay-filter="{$lay_btn}" value="确认提交" class="layui-btn">
+                            </div>
+                        </div>
+                    </div>
+
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+
+<script>
+    layui.use(['index', 'form', 'laydate'], function () {
+        const admin = layui.admin;
+        const form = layui.form;
+        const laydate = layui.laydate;
+        form.render();
+
+        laydate.render({
+            elem: '#start_time',
+            type: 'datetime'
+        });
+
+        laydate.render({
+            elem: '#end_time',
+            type: 'datetime'
+        });
+
+        form.on('submit({$lay_btn})', function (obj) {
+            const index = parent.layer.getFrameIndex(window.name);
+            admin.req({
+                url: "{:url('soldier/editVideoSeries')}",
+                type: 'post',
+                data: obj.field,
+                done: function (res) {
+                    layer.msg("提交成功", {
+                        icon: 1
+                    });
+                    parent.layui.table.reload('lay-soldier-videoSeries-table'); //重载表格
+                    parent.layer.close(index);
+                }
+            });
+        });
+    });
+</script>

+ 58 - 0
app/admin/view/soldier/video_watch.html

@@ -0,0 +1,58 @@
+<style>
+
+</style>
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-form layui-card-header layuiadmin-card-header-auto">
+            <button class="layui-btn layuiadmin-btn" data-type="export">导出</button>
+        </div>
+
+        <div class="layui-card-body">
+            <table id="{$lay_table}" lay-filter="{$lay_table}"></table>
+            <script type="text/html" id="userTpl">
+                {{d.user.name}}
+            </script>
+        </div>
+    </div>
+</div>
+
+<script>
+    layui.use(['index', 'admin', 'form', 'table'], function () {
+        const $ = layui.$;
+        const admin = layui.admin;
+        const form = layui.form;
+        const table = layui.table;
+        form.render();
+
+        table.render({
+            elem: '#{$lay_table}',
+            url: "{:url('soldier/listVideoWatch')}?id={$id}",
+            cols: [
+                [
+                    {field: 'id', title: 'ID' ,width: 100},
+                    {field: 'name', title: '姓名' ,width: 200, templet: '#userTpl'},
+                    {field: 'status_text', title: '状态', width: 200, align: 'center'},
+                    {field: 'create_time', title: '首次学习时间', width: 200},
+                    {field: 'update_time', title: '最后学习时间'},
+                ]
+            ],
+            page: true,
+            limit: 50,
+            cellMinWidth: 150,
+            text: '对不起,加载出现异常!'
+        });
+
+        //事件
+        const active = {
+            export: function() {
+                const url = "{:url('soldier/exportVideoWatch')}";
+                window.open(url + '?id={$id}');
+            },
+        };
+
+        $('.layui-btn.layuiadmin-btn').on('click', function () {
+            const type = $(this).data('type');
+            active[type] ? active[type].call(this) : '';
+        });
+    });
+</script>

+ 27 - 0
app/common/model/SoldierModel.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace app\common\model;
+
+use think\model\concern\SoftDelete;
+
+class SoldierModel extends BaseModel
+{
+    // 设置表名
+    protected $name = 'soldier';
+
+    // 软删除
+    use SoftDelete;
+    protected $deleteTime = 'delete_time';
+    protected $defaultSoftDelete = 0;
+
+    // 常量
+    const STATUS = [1 => '正常', 2 => '禁用'];
+
+    const STATUS_NORMAL  = 1;
+    const STATUS_DISABLE = 2;
+
+    public function getStatusTextAttr($value, $data)
+    {
+        return self::STATUS[$data['status']];
+    }
+}

+ 26 - 0
app/common/model/SoldierVideoModel.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace app\common\model;
+
+
+class SoldierVideoModel extends BaseModel
+{
+    // 设置表名
+    protected $name = 'soldier_video';
+
+    // 常量
+    const STATUS = [1 => '显示', 2 => '隐藏'];
+
+    const STATUS_SHOW = 1;
+    const STATUS_HIDE = 2;
+
+    public function getStatusTextAttr($value, $data)
+    {
+        return self::STATUS[$data['status']];
+    }
+
+    public function series()
+    {
+        return $this->hasOne(SoldierVideoSeriesModel::class, 'id', 'series_id');
+    }
+}

+ 26 - 0
app/common/model/SoldierVideoSeriesModel.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace app\common\model;
+
+
+class SoldierVideoSeriesModel extends BaseModel
+{
+    // 设置表名
+    protected $name = 'soldier_video_series';
+
+    protected $type = [
+        'start_time' => 'timestamp:Y-m-d H:i:s',
+        'end_time'   => 'timestamp:Y-m-d H:i:s',
+    ];
+
+    // 常量
+    const STATUS = [1 => '显示', 2 => '隐藏'];
+
+    const STATUS_SHOW = 1;
+    const STATUS_HIDE = 2;
+
+    public function getStatusTextAttr($value, $data)
+    {
+        return self::STATUS[$data['status']];
+    }
+}

+ 34 - 0
app/common/model/SoldierVideoWatchModel.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace app\common\model;
+
+
+class SoldierVideoWatchModel extends BaseModel
+{
+    // 设置表名
+    protected $name = 'soldier_video_watch';
+
+    protected $autoWriteTimestamp = true;
+
+    // 常量
+    const STATUS = [1 => '未开始', 2 => '未看完', 3 => '已完成'];
+
+    const STATUS_NO_STARTED  = 1;
+    const STATUS_NO_FINISHED = 2;
+    const STATUS_FINISH      = 3;
+
+    public function getStatusTextAttr($value, $data)
+    {
+        return self::STATUS[$data['status']];
+    }
+
+    public function user()
+    {
+        return $this->hasOne(SoldierModel::class, 'id', 'user_id');
+    }
+
+    public function video()
+    {
+        return $this->hasOne(SoldierVideoModel::class, 'id', 'video_id');
+    }
+}

+ 20 - 0
app/common/validate/SoldierUserValidate.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace app\common\validate;
+
+use think\Validate;
+
+class SoldierUserValidate extends Validate
+{
+    protected $rule = [
+        'name'   => 'require',
+        'mobile' => 'require|mobile',
+    ];
+
+    protected $message = [
+        'name'           => '姓名不能为空',
+        'mobile.require' => '手机号不能为空',
+        'mobile.mobile'  => '手机号格式不正确',
+    ];
+
+}

+ 21 - 0
app/common/validate/SoldierVideoSeriesValidate.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace app\common\validate;
+
+use think\Validate;
+
+class SoldierVideoSeriesValidate extends Validate
+{
+    protected $rule = [
+        'title'      => 'require',
+        'start_time' => 'require',
+        'end_time'   => 'require',
+    ];
+
+    protected $message = [
+        'title'      => '标题不能为空',
+        'start_time' => '开始时间不能为空',
+        'end_time'   => '结束时间不能为空',
+    ];
+
+}

+ 23 - 0
app/common/validate/SoldierVideoValidate.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace app\common\validate;
+
+use think\Validate;
+
+class SoldierVideoValidate extends Validate
+{
+    protected $rule = [
+        'series_id'  => 'require',
+        'title'      => 'require',
+        'main_image' => 'require',
+        'video'      => 'require',
+    ];
+
+    protected $message = [
+        'series_id'  => '请选择系列',
+        'title'      => '标题不能为空',
+        'main_image' => '主图不能为空',
+        'video'      => '视频不能为空',
+    ];
+
+}

+ 14 - 0
app/mobile/controller/Soldier.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace app\mobile\controller;
+
+use app\mobile\MobileBaseController;
+
+class Soldier extends MobileBaseController
+{
+    public function login()
+    {
+        return view();
+    }
+
+}

+ 101 - 0
app/mobile/view/soldier/login.html

@@ -0,0 +1,101 @@
+{extend name="public/base"/}
+{block name="css"}
+<style>
+    .content {
+        height: 100vh;
+        background-color: aquamarine;
+        background: url("__MIMAGES__/bg_login.jpg") no-repeat;
+        background-size: cover;
+    }
+
+    .topBox {
+        font-size: 17px;
+        color: #fff;
+        padding: 10px 25px;
+    }
+
+    h3 {
+        margin-bottom: 5px;
+    }
+
+    .inputBox {
+        position: fixed;
+        bottom: 0;
+        left: 0;
+        width: 100%;
+        height: 85vh;
+        background-color: #fff;
+        border-top-left-radius: 20px;
+        border-top-right-radius: 20px;
+        padding: 30px;
+        box-sizing: border-box;
+    }
+
+    .ipt {
+        margin-bottom: 25px;
+    }
+
+    .ipt h4 {
+        margin-bottom: 10px;
+        font-size: 18px;
+        color: #333;
+    }
+
+    .ipt input {
+        border:none;
+        border-bottom:1px solid #dedede;
+        width:100%;
+        padding-bottom: 10px;
+        font-size: 14px;
+    }
+
+    .loginBtn {
+        line-height: 43px;
+        text-align: center;
+        background: linear-gradient(to right, rgb(86, 104, 214), rgb(86, 104, 214));
+        border-radius: 20px;
+        color: #fff;
+        margin-top: 25px;
+        width:100%;
+        border:none;
+        display:block;
+    }
+
+</style>
+{/block}
+{block name="body"}
+<div class="content">
+    <div class="topBox">
+        <h3>WELCOME</h3>
+        <h3>欢迎使用</h3>
+    </div>
+    <div class="inputBox">
+        <div class="ipt">
+            <h4>手机号</h4>
+            <input type="mobile" v-model="form.mobile" placeholder="请输入手机号码" />
+        </div>
+        <div class="ipt">
+            <h4>密码</h4>
+            <input type="password" v-model="form.password" placeholder="请输入密码" />
+        </div>
+        <button class="loginBtn" @click="onLogin">登录</button>
+    </div>
+</div>
+{/block}
+{block name="script"}
+<script>
+    function v_setup() {
+        let base = {};
+
+        base.form = Vue.reactive({});
+
+        base.onLogin = () => {
+            postJson('/soldier/doLogin', base.form).then(({data, code}) => {
+                location.href = "{:url('soldier/index')}";
+            })
+        };
+
+        return base;
+    }
+</script>
+{/block}

BIN
public/static/common/exl/soldier_user.xls


BIN
public/static/mobile/images/bg_login.jpg


+ 18 - 18
vendor/phpoffice/phpexcel/Classes/PHPExcel/Calculation.php

@@ -2548,7 +2548,7 @@ class PHPExcel_Calculation
     public static function unwrapResult($value)
     {
         if (is_string($value)) {
-            if ((isset($value{0})) && ($value{0} == '"') && (substr($value, -1) == '"')) {
+            if ((isset($value[0])) && ($value[0] == '"') && (substr($value, -1) == '"')) {
                 return substr($value, 1, -1);
             }
         //    Convert numeric errors to NaN error
@@ -2669,11 +2669,11 @@ class PHPExcel_Calculation
         //    Basic validation that this is indeed a formula
         //    We return an empty array if not
         $formula = trim($formula);
-        if ((!isset($formula{0})) || ($formula{0} != '=')) {
+        if ((!isset($formula[0])) || ($formula[0] != '=')) {
             return array();
         }
         $formula = ltrim(substr($formula, 1));
-        if (!isset($formula{0})) {
+        if (!isset($formula[0])) {
             return array();
         }
 
@@ -2761,11 +2761,11 @@ class PHPExcel_Calculation
         //    Basic validation that this is indeed a formula
         //    We simply return the cell value if not
         $formula = trim($formula);
-        if ($formula{0} != '=') {
+        if ($formula[0] != '=') {
             return self::wrapResult($formula);
         }
         $formula = ltrim(substr($formula, 1));
-        if (!isset($formula{0})) {
+        if (!isset($formula[0])) {
             return self::wrapResult($formula);
         }
 
@@ -2777,7 +2777,7 @@ class PHPExcel_Calculation
             return $cellValue;
         }
 
-        if (($wsTitle{0} !== "\x00") && ($this->cyclicReferenceStack->onStack($wsCellReference))) {
+        if (($wsTitle[0] !== "\x00") && ($this->cyclicReferenceStack->onStack($wsCellReference))) {
             if ($this->cyclicFormulaCount <= 0) {
                 $this->cyclicFormulaCell = '';
                 return $this->raiseFormulaError('Cyclic Reference in Formula');
@@ -3031,7 +3031,7 @@ class PHPExcel_Calculation
             } else {
                 if ($value == '') {
                     return 'an empty string';
-                } elseif ($value{0} == '#') {
+                } elseif ($value[0] == '#') {
                     return 'a '.$value.' error';
                 } else {
                     $typeString = 'a string';
@@ -3163,10 +3163,10 @@ class PHPExcel_Calculation
         //    Loop through the formula extracting each operator and operand in turn
         while (true) {
 //echo 'Assessing Expression '.substr($formula, $index), PHP_EOL;
-            $opCharacter = $formula{$index};    //    Get the first character of the value at the current index position
+            $opCharacter = $formula[$index];    //    Get the first character of the value at the current index position
 //echo 'Initial character of expression block is '.$opCharacter, PHP_EOL;
-            if ((isset(self::$comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset(self::$comparisonOperators[$formula{$index+1}]))) {
-                $opCharacter .= $formula{++$index};
+            if ((isset(self::$comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset(self::$comparisonOperators[$formula[$index+1]]))) {
+                $opCharacter .= $formula[++$index];
 //echo 'Initial character of expression block is comparison operator '.$opCharacter.PHP_EOL;
             }
 
@@ -3454,11 +3454,11 @@ class PHPExcel_Calculation
                 }
             }
             //    Ignore white space
-            while (($formula{$index} == "\n") || ($formula{$index} == "\r")) {
+            while (($formula[$index] == "\n") || ($formula[$index] == "\r")) {
                 ++$index;
             }
-            if ($formula{$index} == ' ') {
-                while ($formula{$index} == ' ') {
+            if ($formula[$index] == ' ') {
+                while ($formula[$index] == ' ') {
                     ++$index;
                 }
                 //    If we're expecting an operator, but only have a space between the previous and next operands (and both are
@@ -3888,7 +3888,7 @@ class PHPExcel_Calculation
 //                    echo 'Token is a PHPExcel constant: '.$excelConstant.'<br />';
                     $stack->push('Constant Value', self::$excelConstants[$excelConstant]);
                     $this->_debugLog->writeDebugLog('Evaluating Constant ', $excelConstant, ' as ', $this->showTypeDetails(self::$excelConstants[$excelConstant]));
-                } elseif ((is_numeric($token)) || ($token === null) || (is_bool($token)) || ($token == '') || ($token{0} == '"') || ($token{0} == '#')) {
+                } elseif ((is_numeric($token)) || ($token === null) || (is_bool($token)) || ($token == '') || ($token[0] == '"') || ($token[0] == '#')) {
 //                    echo 'Token is a number, boolean, string, null or an Excel error<br />';
                     $stack->push('Value', $token);
                 // if the token is a named range, push the named range name onto the stack
@@ -3933,13 +3933,13 @@ class PHPExcel_Calculation
         if (is_string($operand)) {
             //    We only need special validations for the operand if it is a string
             //    Start by stripping off the quotation marks we use to identify true excel string values internally
-            if ($operand > '' && $operand{0} == '"') {
+            if ($operand > '' && $operand[0] == '"') {
                 $operand = self::unwrapResult($operand);
             }
             //    If the string is a numeric value, we treat it as a numeric, so no further testing
             if (!is_numeric($operand)) {
                 //    If not a numeric, test to see if the value is an Excel error, and so can't be used in normal binary operations
-                if ($operand > '' && $operand{0} == '#') {
+                if ($operand > '' && $operand[0] == '#') {
                     $stack->push('Value', $operand);
                     $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($operand));
                     return false;
@@ -3995,10 +3995,10 @@ class PHPExcel_Calculation
         }
 
         //    Simple validate the two operands if they are string values
-        if (is_string($operand1) && $operand1 > '' && $operand1{0} == '"') {
+        if (is_string($operand1) && $operand1 > '' && $operand1[0] == '"') {
             $operand1 = self::unwrapResult($operand1);
         }
-        if (is_string($operand2) && $operand2 > '' && $operand2{0} == '"') {
+        if (is_string($operand2) && $operand2 > '' && $operand2[0] == '"') {
             $operand2 = self::unwrapResult($operand2);
         }
 

+ 7 - 7
vendor/phpoffice/phpexcel/Classes/PHPExcel/Cell.php

@@ -809,19 +809,19 @@ class PHPExcel_Cell
 
         //    We also use the language construct isset() rather than the more costly strlen() function to match the length of $pString
         //        for improved performance
-        if (isset($pString{0})) {
-            if (!isset($pString{1})) {
+        if (isset($pString[0])) {
+            if (!isset($pString[1])) {
                 $_indexCache[$pString] = $_columnLookup[$pString];
                 return $_indexCache[$pString];
-            } elseif (!isset($pString{2})) {
-                $_indexCache[$pString] = $_columnLookup[$pString{0}] * 26 + $_columnLookup[$pString{1}];
+            } elseif (!isset($pString[2])) {
+                $_indexCache[$pString] = $_columnLookup[$pString[0]] * 26 + $_columnLookup[$pString[1]];
                 return $_indexCache[$pString];
-            } elseif (!isset($pString{3})) {
-                $_indexCache[$pString] = $_columnLookup[$pString{0}] * 676 + $_columnLookup[$pString{1}] * 26 + $_columnLookup[$pString{2}];
+            } elseif (!isset($pString[3])) {
+                $_indexCache[$pString] = $_columnLookup[$pString[0]] * 676 + $_columnLookup[$pString[1]] * 26 + $_columnLookup[$pString[2]];
                 return $_indexCache[$pString];
             }
         }
-        throw new PHPExcel_Exception("Column string index can not be " . ((isset($pString{0})) ? "longer than 3 characters" : "empty"));
+        throw new PHPExcel_Exception("Column string index can not be " . ((isset($pString[0])) ? "longer than 3 characters" : "empty"));
     }
 
     /**

+ 2 - 2
vendor/phpoffice/phpexcel/Classes/PHPExcel/Cell/DefaultValueBinder.php

@@ -79,7 +79,7 @@ class PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
             return PHPExcel_Cell_DataType::TYPE_STRING;
         } elseif ($pValue instanceof PHPExcel_RichText) {
             return PHPExcel_Cell_DataType::TYPE_INLINE;
-        } elseif ($pValue{0} === '=' && strlen($pValue) > 1) {
+        } elseif ($pValue[0] === '=' && strlen($pValue) > 1) {
             return PHPExcel_Cell_DataType::TYPE_FORMULA;
         } elseif (is_bool($pValue)) {
             return PHPExcel_Cell_DataType::TYPE_BOOL;
@@ -87,7 +87,7 @@ class PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
             return PHPExcel_Cell_DataType::TYPE_NUMERIC;
         } elseif (preg_match('/^[\+\-]?([0-9]+\\.?[0-9]*|[0-9]*\\.?[0-9]+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $pValue)) {
             $tValue = ltrim($pValue, '+-');
-            if (is_string($pValue) && $tValue{0} === '0' && strlen($tValue) > 1 && $tValue{1} !== '.') {
+            if (is_string($pValue) && $tValue[0] === '0' && strlen($tValue) > 1 && $tValue[1] !== '.') {
                 return PHPExcel_Cell_DataType::TYPE_STRING;
             } elseif ((strpos($pValue, '.') === false) && ($pValue > PHP_INT_MAX)) {
                 return PHPExcel_Cell_DataType::TYPE_STRING;

+ 48 - 48
vendor/phpoffice/phpexcel/Classes/PHPExcel/Reader/Excel5.php

@@ -1925,7 +1925,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
 
         // offset: 0; size: 2; 0 = base 1900, 1 = base 1904
         PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900);
-        if (ord($recordData{0}) == 1) {
+        if (ord($recordData[0]) == 1) {
             PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_MAC_1904);
         }
     }
@@ -1988,7 +1988,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
             }
 
             // offset: 10; size: 1; underline type
-            $underlineType = ord($recordData{10});
+            $underlineType = ord($recordData[10]);
             switch ($underlineType) {
                 case 0x00:
                     break; // no underline
@@ -2125,7 +2125,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
 
             // offset:  6; size: 1; Alignment and text break
             // bit 2-0, mask 0x07; horizontal alignment
-            $horAlign = (0x07 & ord($recordData{6})) >> 0;
+            $horAlign = (0x07 & ord($recordData[6])) >> 0;
             switch ($horAlign) {
                 case 0:
                     $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_GENERAL);
@@ -2150,7 +2150,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                     break;
             }
             // bit 3, mask 0x08; wrap text
-            $wrapText = (0x08 & ord($recordData{6})) >> 3;
+            $wrapText = (0x08 & ord($recordData[6])) >> 3;
             switch ($wrapText) {
                 case 0:
                     $objStyle->getAlignment()->setWrapText(false);
@@ -2160,7 +2160,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                     break;
             }
             // bit 6-4, mask 0x70; vertical alignment
-            $vertAlign = (0x70 & ord($recordData{6})) >> 4;
+            $vertAlign = (0x70 & ord($recordData[6])) >> 4;
             switch ($vertAlign) {
                 case 0:
                     $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_TOP);
@@ -2178,7 +2178,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
 
             if ($this->version == self::XLS_BIFF8) {
                 // offset:  7; size: 1; XF_ROTATION: Text rotation angle
-                $angle = ord($recordData{7});
+                $angle = ord($recordData[7]);
                 $rotation = 0;
                 if ($angle <= 90) {
                     $rotation = $angle;
@@ -2191,11 +2191,11 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
 
                 // offset:  8; size: 1; Indentation, shrink to cell size, and text direction
                 // bit: 3-0; mask: 0x0F; indent level
-                $indent = (0x0F & ord($recordData{8})) >> 0;
+                $indent = (0x0F & ord($recordData[8])) >> 0;
                 $objStyle->getAlignment()->setIndent($indent);
 
                 // bit: 4; mask: 0x10; 1 = shrink content to fit into cell
-                $shrinkToFit = (0x10 & ord($recordData{8})) >> 4;
+                $shrinkToFit = (0x10 & ord($recordData[8])) >> 4;
                 switch ($shrinkToFit) {
                     case 0:
                         $objStyle->getAlignment()->setShrinkToFit(false);
@@ -2275,7 +2275,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                 // BIFF5
 
                 // offset: 7; size: 1; Text orientation and flags
-                $orientationAndFlags = ord($recordData{7});
+                $orientationAndFlags = ord($recordData[7]);
 
                 // bit: 1-0; mask: 0x03; XF_ORIENTATION: Text orientation
                 $xfOrientation = (0x03 & $orientationAndFlags) >> 0;
@@ -2399,7 +2399,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                         $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
 
                         if ($xclfType == 2) {
-                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue[0]), ord($xclrValue[1]), ord($xclrValue[2]));
 
                             // modify the relevant style property
                             if (isset($this->mapCellXfIndex[$ixfe])) {
@@ -2414,7 +2414,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                         $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
 
                         if ($xclfType == 2) {
-                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue[0]), ord($xclrValue[1]), ord($xclrValue[2]));
 
                             // modify the relevant style property
                             if (isset($this->mapCellXfIndex[$ixfe])) {
@@ -2429,7 +2429,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                         $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
 
                         if ($xclfType == 2) {
-                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue[0]), ord($xclrValue[1]), ord($xclrValue[2]));
 
                             // modify the relevant style property
                             if (isset($this->mapCellXfIndex[$ixfe])) {
@@ -2444,7 +2444,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                         $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
 
                         if ($xclfType == 2) {
-                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue[0]), ord($xclrValue[1]), ord($xclrValue[2]));
 
                             // modify the relevant style property
                             if (isset($this->mapCellXfIndex[$ixfe])) {
@@ -2459,7 +2459,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                         $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
 
                         if ($xclfType == 2) {
-                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue[0]), ord($xclrValue[1]), ord($xclrValue[2]));
 
                             // modify the relevant style property
                             if (isset($this->mapCellXfIndex[$ixfe])) {
@@ -2474,7 +2474,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                         $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
 
                         if ($xclfType == 2) {
-                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue[0]), ord($xclrValue[1]), ord($xclrValue[2]));
 
                             // modify the relevant style property
                             if (isset($this->mapCellXfIndex[$ixfe])) {
@@ -2489,7 +2489,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                         $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
 
                         if ($xclfType == 2) {
-                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue[0]), ord($xclrValue[1]), ord($xclrValue[2]));
 
                             // modify the relevant style property
                             if (isset($this->mapCellXfIndex[$ixfe])) {
@@ -2504,7 +2504,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                         $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
 
                         if ($xclfType == 2) {
-                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+                            $rgb = sprintf('%02X%02X%02X', ord($xclrValue[0]), ord($xclrValue[1]), ord($xclrValue[2]));
 
                             // modify the relevant style property
                             if (isset($this->mapCellXfIndex[$ixfe])) {
@@ -2546,7 +2546,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
 
             if ($isBuiltIn) {
                 // offset: 2; size: 1; identifier for built-in style
-                $builtInId = ord($recordData{2});
+                $builtInId = ord($recordData[2]);
 
                 switch ($builtInId) {
                     case 0x00:
@@ -2611,7 +2611,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
         $this->pos += 4 + $length;
 
         // offset: 4; size: 1; sheet state
-        switch (ord($recordData{4})) {
+        switch (ord($recordData[4])) {
             case 0x00:
                 $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE;
                 break;
@@ -2627,7 +2627,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
         }
 
         // offset: 5; size: 1; sheet type
-        $sheetType = ord($recordData{5});
+        $sheetType = ord($recordData[5]);
 
         // offset: 6; size: var; sheet name
         if ($this->version == self::XLS_BIFF8) {
@@ -2805,7 +2805,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
             // offset: 2; size: 1; keyboard shortcut
 
             // offset: 3; size: 1; length of the name (character count)
-            $nlen = ord($recordData{3});
+            $nlen = ord($recordData[3]);
 
             // offset: 4; size: 2; size of the formula data (it can happen that this is zero)
             // note: there can also be additional data, this is not included in $flen
@@ -2888,7 +2888,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
             $pos += 2;
 
             // option flags
-            $optionFlags = ord($recordData{$pos});
+            $optionFlags = ord($recordData[$pos]);
             ++$pos;
 
             // bit: 0; mask: 0x01; 0 = compressed; 1 = uncompressed
@@ -2955,7 +2955,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
 
                     // repeated option flags
                     // OpenOffice.org documentation 5.21
-                    $option = ord($recordData{$pos});
+                    $option = ord($recordData[$pos]);
                     ++$pos;
 
                     if ($isCompressed && ($option == 0)) {
@@ -2977,7 +2977,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                         // this fragment compressed
                         $len = min($charsLeft, $limitpos - $pos);
                         for ($j = 0; $j < $len; ++$j) {
-                            $retstr .= $recordData{$pos + $j} . chr(0);
+                            $retstr .= $recordData[$pos + $j] . chr(0);
                         }
                         $charsLeft -= $len;
                         $isCompressed = false;
@@ -3883,7 +3883,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
         // We can apparently not rely on $isPartOfSharedFormula. Even when $isPartOfSharedFormula = true
         // the formula data may be ordinary formula data, therefore we need to check
         // explicitly for the tExp token (0x01)
-        $isPartOfSharedFormula = $isPartOfSharedFormula && ord($formulaStructure{2}) == 0x01;
+        $isPartOfSharedFormula = $isPartOfSharedFormula && ord($formulaStructure[2]) == 0x01;
 
         if ($isPartOfSharedFormula) {
             // part of shared formula which means there will be a formula with a tExp token and nothing else
@@ -3906,7 +3906,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
             $xfIndex = self::getInt2d($recordData, 4);
 
             // offset: 6; size: 8; result of the formula
-            if ((ord($recordData{6}) == 0) && (ord($recordData{12}) == 255) && (ord($recordData{13}) == 255)) {
+            if ((ord($recordData[6]) == 0) && (ord($recordData[12]) == 255) && (ord($recordData[13]) == 255)) {
                 // String formula. Result follows in appended STRING record
                 $dataType = PHPExcel_Cell_DataType::TYPE_STRING;
 
@@ -3918,21 +3918,21 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
 
                 // read STRING record
                 $value = $this->readString();
-            } elseif ((ord($recordData{6}) == 1)
-                && (ord($recordData{12}) == 255)
-                && (ord($recordData{13}) == 255)) {
+            } elseif ((ord($recordData[6]) == 1)
+                && (ord($recordData[12]) == 255)
+                && (ord($recordData[13]) == 255)) {
                 // Boolean formula. Result is in +2; 0=false, 1=true
                 $dataType = PHPExcel_Cell_DataType::TYPE_BOOL;
-                $value = (bool) ord($recordData{8});
-            } elseif ((ord($recordData{6}) == 2)
-                && (ord($recordData{12}) == 255)
-                && (ord($recordData{13}) == 255)) {
+                $value = (bool) ord($recordData[8]);
+            } elseif ((ord($recordData[6]) == 2)
+                && (ord($recordData[12]) == 255)
+                && (ord($recordData[13]) == 255)) {
                 // Error formula. Error code is in +2
                 $dataType = PHPExcel_Cell_DataType::TYPE_ERROR;
-                $value = PHPExcel_Reader_Excel5_ErrorCode::lookup(ord($recordData{8}));
-            } elseif ((ord($recordData{6}) == 3)
-                && (ord($recordData{12}) == 255)
-                && (ord($recordData{13}) == 255)) {
+                $value = PHPExcel_Reader_Excel5_ErrorCode::lookup(ord($recordData[8]));
+            } elseif ((ord($recordData[6]) == 3)
+                && (ord($recordData[12]) == 255)
+                && (ord($recordData[13]) == 255)) {
                 // Formula result is a null string
                 $dataType = PHPExcel_Cell_DataType::TYPE_NULL;
                 $value = '';
@@ -3996,7 +3996,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
         // offset: 6, size: 1; not used
 
         // offset: 7, size: 1; number of existing FORMULA records for this shared formula
-        $no = ord($recordData{7});
+        $no = ord($recordData[7]);
 
         // offset: 8, size: var; Binary token array of the shared formula
         $formula = substr($recordData, 8);
@@ -4062,10 +4062,10 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
             $xfIndex = self::getInt2d($recordData, 4);
 
             // offset: 6; size: 1; the boolean value or error value
-            $boolErr = ord($recordData{6});
+            $boolErr = ord($recordData[6]);
 
             // offset: 7; size: 1; 0=boolean; 1=error
-            $isError = ord($recordData{7});
+            $isError = ord($recordData[7]);
 
             $cell = $this->phpSheet->getCell($columnString . ($row + 1));
             switch ($isError) {
@@ -4447,7 +4447,7 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
 
         if (!$this->readDataOnly) {
             // offset: 0; size: 1; pane identifier
-            $paneId = ord($recordData{0});
+            $paneId = ord($recordData[0]);
 
             // offset: 1; size: 2; index to row of the active cell
             $r = self::getInt2d($recordData, 1);
@@ -4598,9 +4598,9 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
                 $hyperlinkType = 'UNC';
             } elseif (!$isFileLinkOrUrl) {
                 $hyperlinkType = 'workbook';
-            } elseif (ord($recordData{$offset}) == 0x03) {
+            } elseif (ord($recordData[$offset]) == 0x03) {
                 $hyperlinkType = 'local';
-            } elseif (ord($recordData{$offset}) == 0xE0) {
+            } elseif (ord($recordData[$offset]) == 0xE0) {
                 $hyperlinkType = 'URL';
             }
 
@@ -6886,10 +6886,10 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
         $lr = self::getInt2d($subData, 2) + 1;
 
         // offset: 4; size: 1; index to first column
-        $fc = ord($subData{4});
+        $fc = ord($subData[4]);
 
         // offset: 5; size: 1; index to last column
-        $lc = ord($subData{5});
+        $lc = ord($subData[5]);
 
         // check values
         if ($fr > $lr || $fc > $lc) {
@@ -7294,13 +7294,13 @@ class PHPExcel_Reader_Excel5 extends PHPExcel_Reader_Abstract implements PHPExce
     private static function readRGB($rgb)
     {
         // offset: 0; size 1; Red component
-        $r = ord($rgb{0});
+        $r = ord($rgb[0]);
 
         // offset: 1; size: 1; Green component
-        $g = ord($rgb{1});
+        $g = ord($rgb[1]);
 
         // offset: 2; size: 1; Blue component
-        $b = ord($rgb{2});
+        $b = ord($rgb[2]);
 
         // HEX notation, e.g. 'FF00FC'
         $rgb = sprintf('%02X%02X%02X', $r, $g, $b);

+ 2 - 2
vendor/phpoffice/phpexcel/Classes/PHPExcel/ReferenceHelper.php

@@ -881,8 +881,8 @@ class PHPExcel_ReferenceHelper
             list($newColumn, $newRow) = PHPExcel_Cell::coordinateFromString($pCellReference);
 
             // Verify which parts should be updated
-            $updateColumn = (($newColumn{0} != '$') && ($beforeColumn{0} != '$') && (PHPExcel_Cell::columnIndexFromString($newColumn) >= PHPExcel_Cell::columnIndexFromString($beforeColumn)));
-            $updateRow = (($newRow{0} != '$') && ($beforeRow{0} != '$') && $newRow >= $beforeRow);
+            $updateColumn = (($newColumn[0] != '$') && ($beforeColumn[0] != '$') && (PHPExcel_Cell::columnIndexFromString($newColumn) >= PHPExcel_Cell::columnIndexFromString($beforeColumn)));
+            $updateRow = (($newRow[0] != '$') && ($beforeRow[0] != '$') && $newRow >= $beforeRow);
 
             // Create new column reference
             if ($updateColumn) {

+ 2 - 2
vendor/phpoffice/phpexcel/Classes/PHPExcel/Shared/OLE.php

@@ -285,7 +285,7 @@ class PHPExcel_Shared_OLE
                     $pps = new PHPExcel_Shared_OLE_PPS_File($name);
                     break;
                 default:
-                    continue;
+                    continue 2;
             }
             fseek($fh, 1, SEEK_CUR);
             $pps->Type    = $type;
@@ -443,7 +443,7 @@ class PHPExcel_Shared_OLE
     {
         $rawname = '';
         for ($i = 0; $i < strlen($ascii); ++$i) {
-            $rawname .= $ascii{$i} . "\x00";
+            $rawname .= $ascii[$i] . "\x00";
         }
         return $rawname;
     }

+ 6 - 6
vendor/phpoffice/phpexcel/Classes/PHPExcel/Shared/String.php

@@ -523,8 +523,8 @@ class PHPExcel_Shared_String
         if (strlen($str) < 2) {
             return $str;
         }
-        $c0 = ord($str{0});
-        $c1 = ord($str{1});
+        $c0 = ord($str[0]);
+        $c1 = ord($str[1]);
         if ($c0 == 0xfe && $c1 == 0xff) {
             $str = substr($str, 2);
         } elseif ($c0 == 0xff && $c1 == 0xfe) {
@@ -535,11 +535,11 @@ class PHPExcel_Shared_String
         $newstr = '';
         for ($i=0; $i<$len; $i+=2) {
             if ($bom_be) {
-                $val = ord($str{$i})   << 4;
-                $val += ord($str{$i+1});
+                $val = ord($str[$i])   << 4;
+                $val += ord($str[$i+1]);
             } else {
-                $val = ord($str{$i+1}) << 4;
-                $val += ord($str{$i});
+                $val = ord($str[$i+1]) << 4;
+                $val += ord($str[$i]);
             }
             $newstr .= ($val == 0x228) ? "\n" : chr($val);
         }

+ 1 - 1
vendor/phpoffice/phpexcel/Classes/PHPExcel/Worksheet/AutoFilter.php

@@ -717,7 +717,7 @@ class PHPExcel_Worksheet_AutoFilter
                             );
                         } else {
                             //    Date based
-                            if ($dynamicRuleType{0} == 'M' || $dynamicRuleType{0} == 'Q') {
+                            if ($dynamicRuleType[0] == 'M' || $dynamicRuleType[0] == 'Q') {
                                 //    Month or Quarter
                                 sscanf($dynamicRuleType, '%[A-Z]%d', $periodType, $period);
                                 if ($periodType == 'M') {