From 856cba0466d1f33ab0f8bf1cbb0d013145a04d9e Mon Sep 17 00:00:00 2001 From: 15090180611 <215509543@qq.com> Date: Tue, 1 Apr 2025 16:31:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=86=E7=A6=BB=E5=BC=8F=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E5=9F=BA=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/admin/controller/auth/Admin.php | 80 +++ .../admin/controller/auth/api/Adminlog.php | 149 +++++ .../admin/controller/auth/api/Group.php | 319 +++++++++ .../admin/controller/auth/api/Rule.php | 162 +++++ .../admin/controller/manystore/Index.php | 44 +- .../admin/controller/manystore/ShopApply.php | 73 ++ .../admin/lang/zh-cn/auth/api/group.php | 12 + .../admin/lang/zh-cn/auth/api/rule.php | 29 + .../admin/lang/zh-cn/manystore/shop_apply.php | 20 + application/admin/library/Auth.php | 76 +++ application/admin/model/Admin.php | 19 + application/admin/model/api/AdminLog.php | 119 ++++ application/admin/model/api/AuthGroup.php | 22 + .../admin/model/api/AuthGroupAccess.php | 11 + application/admin/model/api/AuthRule.php | 63 ++ .../admin/model/manystore/ShopApply.php | 83 +++ application/admin/validate/ApiAuthRule.php | 52 ++ .../admin/validate/manystore/ShopApply.php | 27 + application/admin/view/auth/admin/add.html | 9 + application/admin/view/auth/admin/edit.html | 10 + .../admin/view/auth/api/adminlog/detail.html | 27 + .../admin/view/auth/api/adminlog/index.html | 21 + .../admin/view/auth/api/group/add.html | 38 ++ .../admin/view/auth/api/group/edit.html | 38 ++ .../admin/view/auth/api/group/index.html | 21 + application/admin/view/auth/api/rule/add.html | 96 +++ .../admin/view/auth/api/rule/edit.html | 99 +++ .../admin/view/auth/api/rule/index.html | 35 + application/admin/view/auth/api/rule/tpl.html | 43 ++ application/admin/view/command/add.html | 1 + .../admin/view/manystore/index/add.html | 13 +- .../admin/view/manystore/shop_apply/add.html | 75 +++ .../admin/view/manystore/shop_apply/edit.html | 76 +++ .../view/manystore/shop_apply/index.html | 29 + application/adminapi/behavior/AdminLog.php | 14 + application/adminapi/common.php | 1 + application/adminapi/config.php | 6 + application/adminapi/controller/Admin.php | 149 +++++ application/adminapi/controller/Rule.php | 80 +++ application/adminapi/lang/zh-cn.php | 102 +++ application/adminapi/lang/zh-cn/common.php | 3 + .../lang/zh-cn/csmtable/xc_clogin_api.php | 7 + application/adminapi/lang/zh-cn/user.php | 39 ++ .../lang/zh-cn/xilufitness/xilufitess.php | 21 + application/adminapi/library/Auth.php | 622 ++++++++++++++++++ .../adminapi/library/ExceptionHandle.php | 37 ++ application/adminapi/model/Admin.php | 118 ++++ application/adminapi/model/AdminLog.php | 119 ++++ application/adminapi/model/AuthGroup.php | 22 + .../adminapi/model/AuthGroupAccess.php | 11 + application/adminapi/model/AuthRule.php | 210 ++++++ application/adminapi/tags.php | 18 + application/api/controller/school/Shop.php | 52 +- application/common/controller/AdminApi.php | 366 +++++++++++ application/common/controller/Backend.php | 2 +- .../common/controller/ManystoreBase.php | 2 +- application/common/model/BaseModel.php | 223 +++++++ .../common/model/dyqc/ManystoreShop.php | 31 +- .../common/model/manystore/ShopApply.php | 174 +++++ application/database.php | 6 +- public/assets/js/backend/auth/api/adminlog.js | 64 ++ public/assets/js/backend/auth/api/group.js | 160 +++++ public/assets/js/backend/auth/api/rule.js | 221 +++++++ .../assets/js/backend/manystore/shop_apply.js | 127 ++++ .../js/backend/school/classes/classes_lib.js | 2 +- .../manystore/school/classes/classes_lib.js | 2 +- 66 files changed, 4980 insertions(+), 22 deletions(-) create mode 100644 application/admin/controller/auth/api/Adminlog.php create mode 100644 application/admin/controller/auth/api/Group.php create mode 100644 application/admin/controller/auth/api/Rule.php create mode 100644 application/admin/controller/manystore/ShopApply.php create mode 100644 application/admin/lang/zh-cn/auth/api/group.php create mode 100644 application/admin/lang/zh-cn/auth/api/rule.php create mode 100644 application/admin/lang/zh-cn/manystore/shop_apply.php create mode 100644 application/admin/model/api/AdminLog.php create mode 100644 application/admin/model/api/AuthGroup.php create mode 100644 application/admin/model/api/AuthGroupAccess.php create mode 100644 application/admin/model/api/AuthRule.php create mode 100644 application/admin/model/manystore/ShopApply.php create mode 100644 application/admin/validate/ApiAuthRule.php create mode 100644 application/admin/validate/manystore/ShopApply.php create mode 100644 application/admin/view/auth/api/adminlog/detail.html create mode 100644 application/admin/view/auth/api/adminlog/index.html create mode 100644 application/admin/view/auth/api/group/add.html create mode 100644 application/admin/view/auth/api/group/edit.html create mode 100644 application/admin/view/auth/api/group/index.html create mode 100644 application/admin/view/auth/api/rule/add.html create mode 100644 application/admin/view/auth/api/rule/edit.html create mode 100644 application/admin/view/auth/api/rule/index.html create mode 100644 application/admin/view/auth/api/rule/tpl.html create mode 100644 application/admin/view/manystore/shop_apply/add.html create mode 100644 application/admin/view/manystore/shop_apply/edit.html create mode 100644 application/admin/view/manystore/shop_apply/index.html create mode 100644 application/adminapi/behavior/AdminLog.php create mode 100644 application/adminapi/common.php create mode 100644 application/adminapi/config.php create mode 100644 application/adminapi/controller/Admin.php create mode 100644 application/adminapi/controller/Rule.php create mode 100644 application/adminapi/lang/zh-cn.php create mode 100644 application/adminapi/lang/zh-cn/common.php create mode 100644 application/adminapi/lang/zh-cn/csmtable/xc_clogin_api.php create mode 100644 application/adminapi/lang/zh-cn/user.php create mode 100644 application/adminapi/lang/zh-cn/xilufitness/xilufitess.php create mode 100644 application/adminapi/library/Auth.php create mode 100644 application/adminapi/library/ExceptionHandle.php create mode 100644 application/adminapi/model/Admin.php create mode 100644 application/adminapi/model/AdminLog.php create mode 100644 application/adminapi/model/AuthGroup.php create mode 100644 application/adminapi/model/AuthGroupAccess.php create mode 100644 application/adminapi/model/AuthRule.php create mode 100644 application/adminapi/tags.php create mode 100644 application/common/controller/AdminApi.php create mode 100644 application/common/model/manystore/ShopApply.php create mode 100644 public/assets/js/backend/auth/api/adminlog.js create mode 100644 public/assets/js/backend/auth/api/group.js create mode 100644 public/assets/js/backend/auth/api/rule.js create mode 100644 public/assets/js/backend/manystore/shop_apply.js diff --git a/application/admin/controller/auth/Admin.php b/application/admin/controller/auth/Admin.php index 065108e..1d32fba 100644 --- a/application/admin/controller/auth/Admin.php +++ b/application/admin/controller/auth/Admin.php @@ -27,6 +27,7 @@ class Admin extends Backend protected $selectpageFields = 'id,username,nickname,avatar'; protected $searchFields = 'id,username,nickname'; protected $childrenGroupIds = []; + protected $childrenApiGroupIds = []; protected $childrenAdminIds = []; public function _initialize() @@ -36,6 +37,9 @@ class Admin extends Backend $this->childrenAdminIds = $this->auth->getChildrenAdminIds($this->auth->isSuperAdmin()); $this->childrenGroupIds = $this->auth->getChildrenGroupIds($this->auth->isSuperAdmin()); +// var_dump($this->childrenGroupIds); + + $groupList = collection(AuthGroup::where('id', 'in', $this->childrenGroupIds)->select())->toArray(); @@ -61,6 +65,39 @@ class Admin extends Backend } $this->view->assign('groupdata', $groupdata); + + $this->childrenApiGroupIds = $this->auth->getChildrenApiGroupIds($this->auth->isSuperAdmin()); +// var_dump($this->childrenApiGroupIds); + + $groupList = collection(\app\admin\model\api\AuthGroup::where('id', 'in', $this->childrenApiGroupIds)->select())->toArray(); + + Tree::instance()->init($groupList); + $groupdata = []; + if ($this->auth->isSuperAdmin()) { + $result = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0)); + foreach ($result as $k => $v) { + $groupdata[$v['id']] = $v['name']; + } + } else { + $result = []; + $groups = $this->auth->getGroups(); + foreach ($groups as $m => $n) { + $childlist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray($n['id'])); + $temp = []; + foreach ($childlist as $k => $v) { + $temp[$v['id']] = $v['name']; + } + $result[__($n['name'])] = $temp; + } + $groupdata = $result; + } + + $this->view->assign('apigroupdata', $groupdata); + + + + + $this->assignconfig("admin", ['id' => $this->auth->id]); $this->getCity(); @@ -141,6 +178,7 @@ class Admin extends Backend exception($this->model->getError()); } $group = $this->request->post("group/a"); + $apigroup = $this->request->post("apigroup/a"); //过滤不允许的组别,避免越权 $group = array_intersect($this->childrenGroupIds, $group); @@ -148,11 +186,27 @@ class Admin extends Backend exception(__('The parent group exceeds permission limit')); } + + $apigroup = array_intersect($this->childrenApiGroupIds, $apigroup); + if (!$apigroup) { + exception(__('The parent group exceeds permission limit')); + } + + + $dataset = []; foreach ($group as $value) { $dataset[] = ['uid' => $this->model->id, 'group_id' => $value]; } model('AuthGroupAccess')->saveAll($dataset); + + + $dataset = []; + foreach ($apigroup as $value) { + $dataset[] = ['uid' => $this->model->id, 'group_id' => $value]; + } + (new \app\admin\model\api\AuthGroupAccess())->saveAll($dataset); + Db::commit(); } catch (\Exception $e) { Db::rollback(); @@ -207,8 +261,10 @@ class Admin extends Backend // 先移除所有权限 model('AuthGroupAccess')->where('uid', $row->id)->delete(); + \app\admin\model\api\AuthGroupAccess::where('uid', $row->id)->delete(); $group = $this->request->post("group/a"); + $apigroup = $this->request->post("apigroup/a"); // 过滤不允许的组别,避免越权 $group = array_intersect($this->childrenGroupIds, $group); @@ -216,11 +272,25 @@ class Admin extends Backend exception(__('The parent group exceeds permission limit')); } + $apigroup = array_intersect($this->childrenApiGroupIds, $apigroup); + if (!$apigroup) { + exception(__('The parent group exceeds permission limit')); + } + + $dataset = []; foreach ($group as $value) { $dataset[] = ['uid' => $row->id, 'group_id' => $value]; } model('AuthGroupAccess')->saveAll($dataset); + + + $dataset = []; + foreach ($apigroup as $value) { + $dataset[] = ['uid' => $row->id, 'group_id' => $value]; + } + (new \app\admin\model\api\AuthGroupAccess())->saveAll($dataset); + Db::commit(); } catch (\Exception $e) { Db::rollback(); @@ -237,6 +307,16 @@ class Admin extends Backend } $this->view->assign("row", $row); $this->view->assign("groupids", $groupids); + + + $grouplist = $this->auth->getApiGroups($row['id']); + $groupids = []; + foreach ($grouplist as $k => $v) { + $groupids[] = $v['id']; + } +// $this->view->assign("row", $row); + $this->view->assign("apigroupids", $groupids); + return $this->view->fetch(); } diff --git a/application/admin/controller/auth/api/Adminlog.php b/application/admin/controller/auth/api/Adminlog.php new file mode 100644 index 0000000..5f292e0 --- /dev/null +++ b/application/admin/controller/auth/api/Adminlog.php @@ -0,0 +1,149 @@ +model = new \app\admin\model\api\AdminLog; + + $this->childrenAdminIds = $this->auth->getChildrenAdminIds(true); + $this->childrenGroupIds = $this->auth->getChildrenGroupIds(true); + + $groupName = AuthGroup::where('id', 'in', $this->childrenGroupIds) + ->column('id,name'); + + $this->view->assign('groupdata', $groupName); + +// var_dump(XcAdminSessionUtils::getManystoreToken());die; + } + + /** + * 查看 + */ + public function index() + { + //设置过滤方法 + $this->request->filter(['strip_tags', 'trim']); + if ($this->request->isAjax()) { + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); + $isSuperAdmin = $this->auth->isSuperAdmin(); + $childrenAdminIds = $this->childrenAdminIds; + $list = $this->model + ->where($where) + ->where(function ($query) use ($isSuperAdmin, $childrenAdminIds) { + if (!$isSuperAdmin) { + $query->where('admin_id', 'in', $childrenAdminIds); + } + }) + ->field('content,useragent', true) + ->order($sort, $order) + ->paginate($limit); + + $result = array("total" => $list->total(), "rows" => $list->items()); + + return json($result); + } + return $this->view->fetch(); + } + + /** + * 详情 + */ + public function detail($ids) + { + $row = $this->model->get(['id' => $ids]); + if (!$row) { + $this->error(__('No Results were found')); + } + if (!$this->auth->isSuperAdmin()) { + if (!$row['admin_id'] || !in_array($row['admin_id'], $this->childrenAdminIds)) { + $this->error(__('You have no permission')); + } + } + $this->view->assign("row", $row->toArray()); + return $this->view->fetch(); + } + + /** + * 添加 + * @internal + */ + public function add() + { + $this->error(); + } + + /** + * 编辑 + * @internal + */ + public function edit($ids = null) + { + $this->error(); + } + + /** + * 删除 + */ + public function del($ids = "") + { + if (!$this->request->isPost()) { + $this->error(__("Invalid parameters")); + } + $ids = $ids ? $ids : $this->request->post("ids"); + if ($ids) { + $isSuperAdmin = $this->auth->isSuperAdmin(); + $childrenAdminIds = $this->childrenAdminIds; + $adminList = $this->model->where('id', 'in', $ids) + ->where(function ($query) use ($isSuperAdmin, $childrenAdminIds) { + if (!$isSuperAdmin) { + $query->where('admin_id', 'in', $childrenAdminIds); + } + }) + ->select(); + if ($adminList) { + $deleteIds = []; + foreach ($adminList as $k => $v) { + $deleteIds[] = $v->id; + } + if ($deleteIds) { + $this->model->destroy($deleteIds); + $this->success(); + } + } + } + $this->error(); + } + + /** + * 批量更新 + * @internal + */ + public function multi($ids = "") + { + // 管理员禁止批量操作 + $this->error(); + } + +} diff --git a/application/admin/controller/auth/api/Group.php b/application/admin/controller/auth/api/Group.php new file mode 100644 index 0000000..5bedb09 --- /dev/null +++ b/application/admin/controller/auth/api/Group.php @@ -0,0 +1,319 @@ +model = new AuthGroup; + + $this->childrenGroupIds = $this->auth->getChildrenApiGroupIds(true); + + $groupList = collection(AuthGroup::where('id', 'in', $this->childrenGroupIds)->select())->toArray(); + + Tree::instance()->init($groupList); + $groupList = []; + if ($this->auth->isSuperAdmin()) { + $groupList = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0)); + } else { + $groups = $this->auth->getApiGroups(); + $groupIds = []; + foreach ($groups as $m => $n) { + if (in_array($n['id'], $groupIds) || in_array($n['pid'], $groupIds)) { + continue; + } + $groupList = array_merge($groupList, Tree::instance()->getTreeList(Tree::instance()->getTreeArray($n['pid']))); + foreach ($groupList as $index => $item) { + $groupIds[] = $item['id']; + } + } + } + $groupName = []; + foreach ($groupList as $k => $v) { + $groupName[$v['id']] = $v['name']; + } + + $this->grouplist = $groupList; + $this->groupdata = $groupName; + $this->assignconfig("admin", ['id' => $this->auth->id, 'group_ids' => $this->auth->getApiGroupIds()]); + + $this->view->assign('groupdata', $this->groupdata); + } + + /** + * 查看 + */ + public function index() + { + if ($this->request->isAjax()) { + $list = $this->grouplist; + $total = count($list); + $result = array("total" => $total, "rows" => $list); + + return json($result); + } + return $this->view->fetch(); + } + + /** + * 添加 + */ + public function add() + { + if ($this->request->isPost()) { + $this->token(); + $params = $this->request->post("row/a", [], 'strip_tags'); + $params['rules'] = explode(',', $params['rules']); + if (!in_array($params['pid'], $this->childrenGroupIds)) { + $this->error(__('The parent group exceeds permission limit')); + } + $parentmodel = (new AuthGroup)->get($params['pid']); + if (!$parentmodel) { + $this->error(__('The parent group can not found')); + } + // 父级别的规则节点 + $parentrules = explode(',', $parentmodel->rules); + // 当前组别的规则节点 + $currentrules = $this->auth->getRuleIds(); + $rules = $params['rules']; + // 如果父组不是超级管理员则需要过滤规则节点,不能超过父组别的权限 + $rules = in_array('*', $parentrules) ? $rules : array_intersect($parentrules, $rules); + // 如果当前组别不是超级管理员则需要过滤规则节点,不能超当前组别的权限 + $rules = in_array('*', $currentrules) ? $rules : array_intersect($currentrules, $rules); + $params['rules'] = implode(',', $rules); + if ($params) { + $this->model->create($params); + $this->success(); + } + $this->error(); + } + return $this->view->fetch(); + } + + /** + * 编辑 + */ + public function edit($ids = null) + { + if (!in_array($ids, $this->childrenGroupIds)) { + $this->error(__('You have no permission')); + } + $row = $this->model->get(['id' => $ids]); + if (!$row) { + $this->error(__('No Results were found')); + } + if ($this->request->isPost()) { + $this->token(); + $params = $this->request->post("row/a", [], 'strip_tags'); + //父节点不能是非权限内节点 + if (!in_array($params['pid'], $this->childrenGroupIds)) { + $this->error(__('The parent group exceeds permission limit')); + } + // 父节点不能是它自身的子节点或自己本身 + if (in_array($params['pid'], Tree::instance()->getChildrenIds($row->id, true))) { + $this->error(__('The parent group can not be its own child or itself')); + } + $params['rules'] = explode(',', $params['rules']); + + $parentmodel = (new AuthGroup)->get($params['pid']); + if (!$parentmodel) { + $this->error(__('The parent group can not found')); + } + // 父级别的规则节点 + $parentrules = explode(',', $parentmodel->rules); + // 当前组别的规则节点 + $currentrules = $this->auth->getRuleIds(); + $rules = $params['rules']; + // 如果父组不是超级管理员则需要过滤规则节点,不能超过父组别的权限 + $rules = in_array('*', $parentrules) ? $rules : array_intersect($parentrules, $rules); + // 如果当前组别不是超级管理员则需要过滤规则节点,不能超当前组别的权限 + $rules = in_array('*', $currentrules) ? $rules : array_intersect($currentrules, $rules); + $params['rules'] = implode(',', $rules); + if ($params) { + Db::startTrans(); + try { + $row->save($params); + $children_auth_groups = (new AuthGroup)->all(['id' => ['in', implode(',', (Tree::instance()->getChildrenIds($row->id)))]]); + $childparams = []; + foreach ($children_auth_groups as $key => $children_auth_group) { + $childparams[$key]['id'] = $children_auth_group->id; + $childparams[$key]['rules'] = implode(',', array_intersect(explode(',', $children_auth_group->rules), $rules)); + } + (new AuthGroup)->saveAll($childparams); + Db::commit(); + $this->success(); + } catch (Exception $e) { + Db::rollback(); + $this->error($e->getMessage()); + } + } + $this->error(); + return; + } + $this->view->assign("row", $row); + return $this->view->fetch(); + } + + /** + * 删除 + */ + public function del($ids = "") + { + if (!$this->request->isPost()) { + $this->error(__("Invalid parameters")); + } + $ids = $ids ? $ids : $this->request->post("ids"); + if ($ids) { + $ids = explode(',', $ids); + $grouplist = $this->auth->getGroups(); + $group_ids = array_map(function ($group) { + return $group['id']; + }, $grouplist); + // 移除掉当前管理员所在组别 + $ids = array_diff($ids, $group_ids); + + // 循环判断每一个组别是否可删除 + $grouplist = $this->model->where('id', 'in', $ids)->select(); + $groupaccessmodel = new AuthGroupAccess(); + foreach ($grouplist as $k => $v) { + // 当前组别下有管理员 + $groupone = $groupaccessmodel->get(['group_id' => $v['id']]); + if ($groupone) { + $ids = array_diff($ids, [$v['id']]); + continue; + } + // 当前组别下有子组别 + $groupone = $this->model->get(['pid' => $v['id']]); + if ($groupone) { + $ids = array_diff($ids, [$v['id']]); + continue; + } + } + if (!$ids) { + $this->error(__('You can not delete group that contain child group and administrators')); + } + $count = $this->model->where('id', 'in', $ids)->delete(); + if ($count) { + $this->success(); + } + } + $this->error(); + } + + /** + * 批量更新 + * @internal + */ + public function multi($ids = "") + { + // 组别禁止批量操作 + $this->error(); + } + + /** + * 读取角色权限树 + * + * @internal + */ + public function roletree() + { + $this->loadlang('auth/group'); + + $model = (new AuthGroup); + $id = $this->request->post("id"); + $pid = $this->request->post("pid"); + $parentGroupModel = $model->get($pid); + $currentGroupModel = null; + if ($id) { + $currentGroupModel = $model->get($id); + } + if (($pid || $parentGroupModel) && (!$id || $currentGroupModel)) { + $id = $id ? $id : null; + $ruleList = collection((new AuthRule())->order('weigh', 'desc')->order('id', 'asc')->select())->toArray(); + //读取父类角色所有节点列表 + $parentRuleList = []; + if (in_array('*', explode(',', $parentGroupModel->rules))) { + $parentRuleList = $ruleList; + } else { + $parentRuleIds = explode(',', $parentGroupModel->rules); + foreach ($ruleList as $k => $v) { + if (in_array($v['id'], $parentRuleIds)) { + $parentRuleList[] = $v; + } + } + } + + $ruleTree = new Tree(); + $groupTree = new Tree(); + //当前所有正常规则列表 + $ruleTree->init($parentRuleList); + //角色组列表 + $groupTree->init(collection((new AuthGroup)->where('id', 'in', $this->childrenGroupIds)->select())->toArray()); + + //读取当前角色下规则ID集合 + $adminRuleIds = $this->auth->getRuleIds(); + //是否是超级管理员 + $superadmin = $this->auth->isSuperAdmin(); + //当前拥有的规则ID集合 + $currentRuleIds = $id ? explode(',', $currentGroupModel->rules) : []; + + if (!$id || !in_array($pid, $this->childrenGroupIds) || !in_array($pid, $groupTree->getChildrenIds($id, true))) { + $parentRuleList = $ruleTree->getTreeList($ruleTree->getTreeArray(0), 'name'); + $hasChildrens = []; + foreach ($parentRuleList as $k => $v) { + if ($v['haschild']) { + $hasChildrens[] = $v['id']; + } + } + $parentRuleIds = array_map(function ($item) { + return $item['id']; + }, $parentRuleList); + $nodeList = []; + foreach ($parentRuleList as $k => $v) { + if (!$superadmin && !in_array($v['id'], $adminRuleIds)) { + continue; + } + if ($v['pid'] && !in_array($v['pid'], $parentRuleIds)) { + continue; + } + $state = array('selected' => in_array($v['id'], $currentRuleIds) && !in_array($v['id'], $hasChildrens)); + $nodeList[] = array('id' => $v['id'], 'parent' => $v['pid'] ? $v['pid'] : '#', 'text' => __($v['title']), 'type' => 'menu', 'state' => $state); + } + $this->success('', null, $nodeList); + } else { + $this->error(__('Can not change the parent to child')); + } + } else { + $this->error(__('Group not found')); + } + } +} diff --git a/application/admin/controller/auth/api/Rule.php b/application/admin/controller/auth/api/Rule.php new file mode 100644 index 0000000..f0c8cb6 --- /dev/null +++ b/application/admin/controller/auth/api/Rule.php @@ -0,0 +1,162 @@ +auth->isSuperAdmin()) { + $this->error(__('Access is allowed only to the super management group')); + } + $this->model = new AuthRule; + // 必须将结果集转换为数组 + $ruleList = \think\Db::name("api_auth_rule")->field('type,condition,remark,createtime,updatetime', true)->order('weigh DESC,id ASC')->select(); + foreach ($ruleList as $k => &$v) { + $v['title'] = __($v['title']); + } + unset($v); + Tree::instance()->init($ruleList)->icon = ['    ', '    ', '    ']; + $this->rulelist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0), 'title'); + $ruledata = [0 => __('None')]; + foreach ($this->rulelist as $k => &$v) { + if (!$v['ismenu']) { + continue; + } + $ruledata[$v['id']] = $v['title']; + unset($v['spacer']); + } + unset($v); + $this->view->assign('ruledata', $ruledata); + $this->view->assign("menutypeList", $this->model->getMenutypeList()); + } + + /** + * 查看 + */ + public function index() + { + if ($this->request->isAjax()) { + $list = $this->rulelist; + $total = count($this->rulelist); + $result = array("total" => $total, "rows" => $list); + + return json($result); + } + return $this->view->fetch(); + } + + /** + * 添加 + */ + public function add() + { + if ($this->request->isPost()) { + $this->token(); + $params = $this->request->post("row/a", [], 'strip_tags'); + if ($params) { + if (!$params['ismenu'] && !$params['pid']) { + $this->error(__('The non-menu rule must have parent')); + } + $result = $this->model->validate()->save($params); + if ($result === false) { + $this->error($this->model->getError()); + } + Cache::rm('__menu__'); + $this->success(); + } + $this->error(); + } + return $this->view->fetch(); + } + + /** + * 编辑 + */ + public function edit($ids = null) + { + $row = $this->model->get(['id' => $ids]); + if (!$row) { + $this->error(__('No Results were found')); + } + if ($this->request->isPost()) { + $this->token(); + $params = $this->request->post("row/a", [], 'strip_tags'); + if ($params) { + if (!$params['ismenu'] && !$params['pid']) { + $this->error(__('The non-menu rule must have parent')); + } + if ($params['pid'] == $row['id']) { + $this->error(__('Can not change the parent to self')); + } + if ($params['pid'] != $row['pid']) { + $childrenIds = Tree::instance()->init(collection(AuthRule::select())->toArray())->getChildrenIds($row['id']); + if (in_array($params['pid'], $childrenIds)) { + $this->error(__('Can not change the parent to child')); + } + } + //这里需要针对name做唯一验证 +// $ruleValidate = \think\Loader::validate(ApiAuthRule::class); +// $ruleValidate->rule([ +// 'name' => 'require|unique:ApiAuthRule,name,' . $row->id, +// ]); +// $result = $row->validate($ruleValidate)->save($params); + $result = $row->save($params); + + if ($result === false) { + $this->error($row->getError()); + } + Cache::rm('__menu__'); + $this->success(); + } + $this->error(); + } + $this->view->assign("row", $row); + return $this->view->fetch(); + } + + /** + * 删除 + */ + public function del($ids = "") + { + if (!$this->request->isPost()) { + $this->error(__("Invalid parameters")); + } + $ids = $ids ? $ids : $this->request->post("ids"); + if ($ids) { + $delIds = []; + foreach (explode(',', $ids) as $k => $v) { + $delIds = array_merge($delIds, Tree::instance()->getChildrenIds($v, true)); + } + $delIds = array_unique($delIds); + $count = $this->model->where('id', 'in', $delIds)->delete(); + if ($count) { + Cache::rm('__menu__'); + $this->success(); + } + } + $this->error(); + } +} diff --git a/application/admin/controller/manystore/Index.php b/application/admin/controller/manystore/Index.php index d37f8fc..58f3b56 100644 --- a/application/admin/controller/manystore/Index.php +++ b/application/admin/controller/manystore/Index.php @@ -62,7 +62,48 @@ class Index extends Backend protected $error_auth = false; protected $qSwitch = true; - protected $qFields = ["user_id"]; + protected $qFields = ["user_id","name","address_detail","type","tel","legal_entity","shop_apply_id"]; + + + protected function checkAssemblyParameters(){ + if(!$this->qSwitch)return false; + //得到所有get参数 + $get = $this->request->get(); + //得到当前model所有字段 + + + $fields = $this->shopModel->getTableFields(); + +// $commonFields = (new Field())->getCommonFields(); +// var_dump($commonFields); + $fieldLists = $fields; +// foreach ($commonFields as $commonField) { +// if (!in_array($commonField['column_name'], $fields)) { +// $fieldLists[] = $commonField; +// } +// } + $q_fields = []; + + foreach ($get as $kay=>$getField) { + if (in_array($kay, $fieldLists) || in_array($kay, $this->qFields)) { + $q_fields[$kay] = $getField; + } + } + + + //将q_fields塞入模板中 + foreach ($q_fields as $k=>$v) { + //渲染站点配置 + $this->assign('q_'.$k, $v); + } + + foreach ($this->qFields as $k) { + //渲染站点配置 + if(!isset($q_fields[$k]))$this->assign('q_'.$k, ""); + } + + + } public function _initialize() @@ -740,6 +781,7 @@ class Index extends Backend Admin::where(array('admin_shop_id'=>$row['shop_id']))->update(['admin_shop_id'=>0]); Evaluate::where(array('shop_id'=>$row['shop_id']))->delete(); + \app\common\model\manystore\ShopApply::where(array('shop_id'=>$row['shop_id']))->update(['shop_id'=>0,'store_id'=>0]); if(!$result){ exception('商家信息删除失败'); } diff --git a/application/admin/controller/manystore/ShopApply.php b/application/admin/controller/manystore/ShopApply.php new file mode 100644 index 0000000..5eba6db --- /dev/null +++ b/application/admin/controller/manystore/ShopApply.php @@ -0,0 +1,73 @@ +model = new \app\admin\model\manystore\ShopApply; + $this->view->assign("typeList", $this->model->getTypeList()); + + } + + + + /** + * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 + * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 + * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 + */ + + + /** + * 查看 + */ + public function index() + { + //当前是否为关联查询 + $this->relationSearch = true; + //设置过滤方法 + $this->request->filter(['strip_tags', 'trim']); + if ($this->request->isAjax()) { + //如果发送的来源是Selectpage,则转发到Selectpage + if ($this->request->request('keyField')) { + return $this->selectpage(); + } + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); + + $list = $this->model + ->with(['user','shop']) + ->where($where) + ->order($sort, $order) + ->paginate($limit); + + foreach ($list as $row) { + + $row->getRelation('user')->visible(['nickname','mobile','avatar']); + $row->getRelation('shop')->visible(['name','logo']); + } + + $result = array("total" => $list->total(), "rows" => $list->items()); + + return json($result); + } + return $this->view->fetch(); + } + +} diff --git a/application/admin/lang/zh-cn/auth/api/group.php b/application/admin/lang/zh-cn/auth/api/group.php new file mode 100644 index 0000000..9deec57 --- /dev/null +++ b/application/admin/lang/zh-cn/auth/api/group.php @@ -0,0 +1,12 @@ + '父组别不能是自身的子组别', + 'The parent group can not found' => '父组别未找到', + 'Group not found' => '组别未找到', + 'Can not change the parent to child' => '父组别不能是它的子组别', + 'Can not change the parent to self' => '父组别不能是它自己', + 'You can not delete group that contain child group and administrators' => '你不能删除含有子组和管理员的组', + 'The parent group exceeds permission limit' => '父组别超出权限范围', + 'The parent group can not be its own child or itself' => '父组别不能是它的子组别及本身', +]; diff --git a/application/admin/lang/zh-cn/auth/api/rule.php b/application/admin/lang/zh-cn/auth/api/rule.php new file mode 100644 index 0000000..6f8f9da --- /dev/null +++ b/application/admin/lang/zh-cn/auth/api/rule.php @@ -0,0 +1,29 @@ + '显示全部', + 'Condition' => '规则条件', + 'Remark' => '备注', + 'Icon' => '图标', + 'Alert' => '警告', + 'Name' => '规则', + 'Controller/Action' => '控制器名/方法名', + 'Ismenu' => '菜单', + 'Menutype' => '菜单类型', + 'Addtabs' => '选项卡(默认)', + 'Dialog' => '弹窗', + 'Ajax' => 'Ajax请求', + 'Blank' => '链接', + 'Extend' => '扩展属性', + 'Search icon' => '搜索图标', + 'Toggle menu visible' => '点击切换菜单显示', + 'Toggle sub menu' => '点击切换子菜单', + 'Menu tips' => '父级菜单无需匹配控制器和方法,子级菜单请使用控制器名', + 'Node tips' => '控制器/方法名,如果有目录请使用 目录名/控制器名/方法名', + 'Url tips' => '一般情况下留空即可,如果是外部链接或相对链接请输入', + 'The non-menu rule must have parent' => '非菜单规则节点必须有父级', + 'Can not change the parent to child' => '父级不能是它的子级', + 'Can not change the parent to self' => '父级不能是它自己', + 'Name only supports letters, numbers, underscore and slash' => 'URL规则只能是小写字母、数字、下划线和/组成', + 'Rule_name' => '权限标识(菜单需要)', +]; diff --git a/application/admin/lang/zh-cn/manystore/shop_apply.php b/application/admin/lang/zh-cn/manystore/shop_apply.php new file mode 100644 index 0000000..f12fc91 --- /dev/null +++ b/application/admin/lang/zh-cn/manystore/shop_apply.php @@ -0,0 +1,20 @@ + '申请用户', + 'Type' => '类型', + 'Type 1' => '个人', + 'Type 2' => '机构', + 'Name' => '机构名称', + 'Realname' => '联系人姓名', + 'Mobile' => '联系电话', + 'Address' => '机构|授课地址', + 'Shop_id' => '申请的机构id', + 'Create_time' => '创建时间', + 'Update_time' => '修改时间', + 'User.nickname' => '昵称', + 'User.mobile' => '手机号', + 'User.avatar' => '头像', + 'Shop.name' => '店铺名称', + 'Shop.logo' => '品牌LOGO' +]; diff --git a/application/admin/library/Auth.php b/application/admin/library/Auth.php index 6e1c61f..3a01b38 100644 --- a/application/admin/library/Auth.php +++ b/application/admin/library/Auth.php @@ -279,6 +279,13 @@ class Auth extends \fast\Auth return parent::getGroups($uid); } + public function getApiGroups($uid = null) + { + $uid = is_null($uid) ? $this->id : $uid; +// var_dump($uid); + return parent::getApiGroups($uid); + } + public function getRuleList($uid = null) { $uid = is_null($uid) ? $this->id : $uid; @@ -580,4 +587,73 @@ class Auth extends \fast\Auth { return $this->_error ? __($this->_error) : ''; } + + + + + /** + * 取出当前管理员所拥有api权限的分组 + * @param boolean $withself 是否包含当前所在的分组 + * @return array + */ + public function getChildrenApiGroupIds($withself = false) + { + //取出当前管理员所有的分组 + $groups = $this->getApiGroups(); +// var_dump($groups); + + $groupIds = []; + foreach ($groups as $k => $v) { + $groupIds[] = $v['id']; + } + $originGroupIds = $groupIds; + foreach ($groups as $k => $v) { + if (in_array($v['pid'], $originGroupIds)) { + $groupIds = array_diff($groupIds, [$v['id']]); + unset($groups[$k]); + } + } + // 取出所有分组 + $groupList = \app\admin\model\api\AuthGroup::where($this->isSuperAdmin() ? '1=1' : ['status' => 'normal'])->select(); + $objList = []; + foreach ($groups as $k => $v) { + if ($v['rules'] === '*') { + $objList = $groupList; + break; + } + // 取出包含自己的所有子节点 + $childrenList = Tree::instance()->init($groupList, 'pid')->getChildren($v['id'], true); + $obj = Tree::instance()->init($childrenList, 'pid')->getTreeArray($v['pid']); + $objList = array_merge($objList, Tree::instance()->getTreeList($obj)); + } + $childrenGroupIds = []; + foreach ($objList as $k => $v) { + $childrenGroupIds[] = $v['id']; + } + if (!$withself) { + $childrenGroupIds = array_diff($childrenGroupIds, $groupIds); + } + return $childrenGroupIds; + } + + + + /** + * 获取管理员所属于的分组ID + * @param int $uid + * @return array + */ + public function getApiGroupIds($uid = null) + { + $groups = $this->getApiGroups($uid); + $groupIds = []; + foreach ($groups as $K => $v) { + $groupIds[] = (int)$v['group_id']; + } + return $groupIds; + } + + + + } diff --git a/application/admin/model/Admin.php b/application/admin/model/Admin.php index 79975f5..6c778a1 100644 --- a/application/admin/model/Admin.php +++ b/application/admin/model/Admin.php @@ -20,6 +20,25 @@ class Admin extends Model 'salt' ]; + + + /** + * 获取会员的组别 + */ + public function getGroupsAttr($value, $data) + { + $group_ids = \app\admin\model\api\AuthGroupAccess::where("uid", $data['id'])->column("group_id"); + if(!$group_ids)return []; + + $groups = \app\admin\model\api\AuthGroup::where("id","in",$group_ids)->select(); + return $groups; + } + + + + + + public static function init() { self::beforeWrite(function ($row) { diff --git a/application/admin/model/api/AdminLog.php b/application/admin/model/api/AdminLog.php new file mode 100644 index 0000000..3e8df1e --- /dev/null +++ b/application/admin/model/api/AdminLog.php @@ -0,0 +1,119 @@ +isLogin() ? $auth->id : 0; + $username = $auth->isLogin() ? $auth->username : __('Unknown'); + + // 设置过滤函数 + request()->filter('trim,strip_tags,htmlspecialchars'); + + $controllername = Loader::parseName(request()->controller()); + $actionname = strtolower(request()->action()); + $path = str_replace('.', '/', $controllername) . '/' . $actionname; + if (self::$ignoreRegex) { + foreach (self::$ignoreRegex as $index => $item) { + if (preg_match($item, $path)) { + return; + } + } + } + $content = $content ?: self::$content; + if (!$content) { + $content = request()->param('') ?: file_get_contents("php://input"); + $content = self::getPureContent($content); + } + $title = $title ?: self::$title; + if (!$title) { + $title = []; + $breadcrumb = Auth::instance()->getBreadcrumb($path); + foreach ($breadcrumb as $k => $v) { + $title[] = $v['title']; + } + $title = implode(' / ', $title); + } + self::create([ + 'title' => $title, + 'content' => !is_scalar($content) ? json_encode($content, JSON_UNESCAPED_UNICODE) : $content, + 'url' => substr(xss_clean(strip_tags(request()->url())), 0, 1500), + 'admin_id' => $admin_id, + 'username' => $username, + 'useragent' => substr(request()->server('HTTP_USER_AGENT'), 0, 255), + 'ip' => xss_clean(strip_tags(request()->ip())) + ]); + } + + /** + * 获取已屏蔽关键信息的数据 + * @param $content + * @return array + */ + protected static function getPureContent($content) + { + if (!is_array($content)) { + return $content; + } + foreach ($content as $index => &$item) { + if (preg_match("/(password|salt|token)/i", $index)) { + $item = "***"; + } else { + if (is_array($item)) { + $item = self::getPureContent($item); + } + } + } + return $content; + } + + public function admin() + { + return $this->belongsTo('Admin', 'admin_id')->setEagerlyType(0); + } +} diff --git a/application/admin/model/api/AuthGroup.php b/application/admin/model/api/AuthGroup.php new file mode 100644 index 0000000..4a8e396 --- /dev/null +++ b/application/admin/model/api/AuthGroup.php @@ -0,0 +1,22 @@ + __('Addtabs'), 'dialog' => __('Dialog'), 'ajax' => __('Ajax'), 'blank' => __('Blank')]; + } + + public function setPyAttr($value, $data) + { + if (isset($data['title']) && $data['title']) { + return self::$pinyin->abbr(__($data['title'])); + } + return ''; + } + + public function setPinyinAttr($value, $data) + { + if (isset($data['title']) && $data['title']) { + return self::$pinyin->permalink(__($data['title']), ''); + } + return ''; + } +} diff --git a/application/admin/model/manystore/ShopApply.php b/application/admin/model/manystore/ShopApply.php new file mode 100644 index 0000000..e9283cd --- /dev/null +++ b/application/admin/model/manystore/ShopApply.php @@ -0,0 +1,83 @@ + __('Type 1'), '2' => __('Type 2')]; + } + + + public function getTypeTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['type']) ? $data['type'] : ''); + $list = $this->getTypeList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + + public function getCreateTimeTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['create_time']) ? $data['create_time'] : ''); + return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value; + } + + + public function getUpdateTimeTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['update_time']) ? $data['update_time'] : ''); + return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value; + } + + protected function setCreateTimeAttr($value) + { + return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value); + } + + protected function setUpdateTimeAttr($value) + { + return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value); + } + + + public function user() + { + return $this->belongsTo('app\admin\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0); + } + + + public function shop() + { + return $this->belongsTo(Shop::class, 'shop_id', 'id', [], 'LEFT')->setEagerlyType(0); + } +} diff --git a/application/admin/validate/ApiAuthRule.php b/application/admin/validate/ApiAuthRule.php new file mode 100644 index 0000000..b249804 --- /dev/null +++ b/application/admin/validate/ApiAuthRule.php @@ -0,0 +1,52 @@ + '[a-z0-9_\/]+']; + + /** + * 验证规则 + */ + protected $rule = [ + 'name' => 'require|unique:ApiAuthRule', + 'title' => 'require', + ]; + + /** + * 提示消息 + */ + protected $message = [ + 'name.format' => 'URL规则只能是小写字母、数字、下划线和/组成' + ]; + + /** + * 字段描述 + */ + protected $field = [ + ]; + + /** + * 验证场景 + */ + protected $scene = [ + ]; + + public function __construct(array $rules = [], $message = [], $field = []) + { + $this->field = [ + 'name' => __('Name'), + 'title' => __('Title'), + ]; + $this->message['name.format'] = __('Name only supports letters, numbers, underscore and slash'); + parent::__construct($rules, $message, $field); + } + +} diff --git a/application/admin/validate/manystore/ShopApply.php b/application/admin/validate/manystore/ShopApply.php new file mode 100644 index 0000000..b607da9 --- /dev/null +++ b/application/admin/validate/manystore/ShopApply.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/application/admin/view/auth/admin/add.html b/application/admin/view/auth/admin/add.html index 53865f3..c6d24d8 100644 --- a/application/admin/view/auth/admin/add.html +++ b/application/admin/view/auth/admin/add.html @@ -6,6 +6,15 @@ {:build_select('group[]', $groupdata, null, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])} + + +
+ +
+ {:build_select('apigroup[]', $apigroupdata, null, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])} +
+
+
diff --git a/application/admin/view/auth/admin/edit.html b/application/admin/view/auth/admin/edit.html index 7f54dbf..8437717 100644 --- a/application/admin/view/auth/admin/edit.html +++ b/application/admin/view/auth/admin/edit.html @@ -6,6 +6,16 @@ {:build_select('group[]', $groupdata, $groupids, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])}
+ + +
+ +
+ {:build_select('apigroup[]', $apigroupdata, $apigroupids, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])} +
+
+ +
diff --git a/application/admin/view/auth/api/adminlog/detail.html b/application/admin/view/auth/api/adminlog/detail.html new file mode 100644 index 0000000..49722a5 --- /dev/null +++ b/application/admin/view/auth/api/adminlog/detail.html @@ -0,0 +1,27 @@ + + + + + + + + + + {volist name="row" id="vo" } + + + + + {/volist} + +
{:__('Title')}{:__('Content')}
{:__($key)}{if $key=='createtime'}{$vo|datetime}{else/}{$vo|htmlentities}{/if}
+ diff --git a/application/admin/view/auth/api/adminlog/index.html b/application/admin/view/auth/api/adminlog/index.html new file mode 100644 index 0000000..ea09f1d --- /dev/null +++ b/application/admin/view/auth/api/adminlog/index.html @@ -0,0 +1,21 @@ +
+ {:build_heading()} + +
+
+
+
+
+ {:build_toolbar('refresh,delete')} +
+ +
+
+
+ +
+
+
diff --git a/application/admin/view/auth/api/group/add.html b/application/admin/view/auth/api/group/add.html new file mode 100644 index 0000000..3c281ee --- /dev/null +++ b/application/admin/view/auth/api/group/add.html @@ -0,0 +1,38 @@ +
+ {:token()} + +
+ +
+ {:build_select('row[pid]', $groupdata, null, ['class'=>'form-control selectpicker', 'data-rule'=>'required'])} +
+
+
+ +
+ +
+
+
+ +
+ + + +
+
+
+
+ +
+ {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])} +
+
+ +
diff --git a/application/admin/view/auth/api/group/edit.html b/application/admin/view/auth/api/group/edit.html new file mode 100644 index 0000000..a062e43 --- /dev/null +++ b/application/admin/view/auth/api/group/edit.html @@ -0,0 +1,38 @@ +
+ {:token()} + +
+ +
+ {:build_select('row[pid]', $groupdata, $row['pid'], ['class'=>'form-control selectpicker', 'data-rule'=>'required', 'data-id'=>$row['id'], 'data-pid'=>$row['pid']])} +
+
+
+ +
+ +
+
+
+ +
+ + + +
+
+
+
+ +
+ {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])} +
+
+ +
diff --git a/application/admin/view/auth/api/group/index.html b/application/admin/view/auth/api/group/index.html new file mode 100644 index 0000000..1045349 --- /dev/null +++ b/application/admin/view/auth/api/group/index.html @@ -0,0 +1,21 @@ +
+ {:build_heading()} + +
+
+
+
+
+ {:build_toolbar('refresh,add,delete')} +
+ +
+
+
+ +
+
+
diff --git a/application/admin/view/auth/api/rule/add.html b/application/admin/view/auth/api/rule/add.html new file mode 100644 index 0000000..3b904e9 --- /dev/null +++ b/application/admin/view/auth/api/rule/add.html @@ -0,0 +1,96 @@ +
+ {:token()} +
+ +
+ {:build_radios('row[ismenu]', ['1'=>__('Yes'), '0'=>__('No')])} +
+
+
+ +
+ {:build_select('row[pid]', $ruledata, null, ['class'=>'form-control', 'required'=>''])} +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ {:build_radios('row[menutype]', $menutypeList)} +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])} +
+
+ +
+{include file="auth/api/rule/tpl" /} diff --git a/application/admin/view/auth/api/rule/edit.html b/application/admin/view/auth/api/rule/edit.html new file mode 100644 index 0000000..f2947e0 --- /dev/null +++ b/application/admin/view/auth/api/rule/edit.html @@ -0,0 +1,99 @@ +
+ {:token()} +
+ +
+ {:build_radios('row[ismenu]', ['1'=>__('Yes'), '0'=>__('No')], $row['ismenu'])} +
+
+
+ +
+ {:build_select('row[pid]', $ruledata, $row['pid'], ['class'=>'form-control', 'required'=>''])} +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ {:build_radios('row[menutype]', $menutypeList, $row['menutype'])} +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])} +
+
+ +
+{include file="auth/api/rule/tpl" /} diff --git a/application/admin/view/auth/api/rule/index.html b/application/admin/view/auth/api/rule/index.html new file mode 100644 index 0000000..3f27ecb --- /dev/null +++ b/application/admin/view/auth/api/rule/index.html @@ -0,0 +1,35 @@ + + diff --git a/application/admin/view/auth/api/rule/tpl.html b/application/admin/view/auth/api/rule/tpl.html new file mode 100644 index 0000000..9413dde --- /dev/null +++ b/application/admin/view/auth/api/rule/tpl.html @@ -0,0 +1,43 @@ + + \ No newline at end of file diff --git a/application/admin/view/command/add.html b/application/admin/view/command/add.html index 2180096..b2b330f 100644 --- a/application/admin/view/command/add.html +++ b/application/admin/view/command/add.html @@ -353,6 +353,7 @@ + diff --git a/application/admin/view/manystore/index/add.html b/application/admin/view/manystore/index/add.html index d55e71d..1dab7ab 100644 --- a/application/admin/view/manystore/index/add.html +++ b/application/admin/view/manystore/index/add.html @@ -11,6 +11,9 @@
+ + +
@@ -78,7 +81,7 @@ @@ -89,7 +92,7 @@
- +
@@ -162,7 +165,7 @@
- +
@@ -213,7 +216,7 @@
- +
@@ -262,7 +265,7 @@
- +
diff --git a/application/admin/view/manystore/shop_apply/add.html b/application/admin/view/manystore/shop_apply/add.html new file mode 100644 index 0000000..59fc382 --- /dev/null +++ b/application/admin/view/manystore/shop_apply/add.html @@ -0,0 +1,75 @@ +
+ +
+ +
+ + + + + + + +
+
+
+ +
+ + + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + +
diff --git a/application/admin/view/manystore/shop_apply/edit.html b/application/admin/view/manystore/shop_apply/edit.html new file mode 100644 index 0000000..2f0ff6f --- /dev/null +++ b/application/admin/view/manystore/shop_apply/edit.html @@ -0,0 +1,76 @@ +
+ +
+ +
+ + + + + + + + +
+
+
+ +
+ + + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + +
diff --git a/application/admin/view/manystore/shop_apply/index.html b/application/admin/view/manystore/shop_apply/index.html new file mode 100644 index 0000000..6c22245 --- /dev/null +++ b/application/admin/view/manystore/shop_apply/index.html @@ -0,0 +1,29 @@ +
+ {:build_heading()} + +
+
+
+ +
+ +
+
+
diff --git a/application/adminapi/behavior/AdminLog.php b/application/adminapi/behavior/AdminLog.php new file mode 100644 index 0000000..f2563ae --- /dev/null +++ b/application/adminapi/behavior/AdminLog.php @@ -0,0 +1,14 @@ +isPost() && config('fastadmin.auto_record_log')) { + \app\adminapi\model\AdminLog::record(); + } + } +} diff --git a/application/adminapi/common.php b/application/adminapi/common.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/application/adminapi/common.php @@ -0,0 +1 @@ + '\\app\\api\\library\\ExceptionHandle', +]; diff --git a/application/adminapi/controller/Admin.php b/application/adminapi/controller/Admin.php new file mode 100644 index 0000000..e9ae706 --- /dev/null +++ b/application/adminapi/controller/Admin.php @@ -0,0 +1,149 @@ +model = new AdminModel; + parent::_initialize(); + + $auth = $this->auth; + //监听注册登录退出的事件 + Hook::add('admin_login_successed', function ($user) use ($auth) { + $expire = input('post.keeplogin') ? 30 * 86400 : 0; + Cookie::set('adminid', $user->id, $expire); + Cookie::set('admintoken', $auth->getToken(), $expire); + }); + Hook::add('admin_register_successed', function ($user) use ($auth) { + Cookie::set('adminid', $user->id); + Cookie::set('admintoken', $auth->getToken()); + }); + Hook::add('admin_delete_successed', function ($user) use ($auth) { + Cookie::delete('adminid'); + Cookie::delete('admintoken'); + }); + Hook::add('admin_logout_successed', function ($user) use ($auth) { + Cookie::delete('adminid'); + Cookie::delete('admintoken'); + }); + + + } + + + + /** + * 管理员登录 + * + * @ApiMethod (POST) + * @ApiParams (name="account", type="string", required=true, description="账号") + * @ApiParams (name="password", type="string", required=true, description="密码") + */ + public function login() + { + $account = $this->request->post('account'); + $password = $this->request->post('password'); + if (!$account || !$password) { + $this->error(__('Invalid parameters')); + } + $ret = $this->auth->login($account, $password); + if ($ret) { + $data = ['userinfo' => $this->auth->getUserinfo()]; + $this->success(__('Logged in successful'), $data); + } else { + $this->error($this->auth->getError()); + } + } + + + + /** + * 退出登录 + * @ApiMethod (POST) + */ + public function logout() + { +// //设置contenttype不为表单格式防止触发宝塔防火墙 +// header('Content-Type:application/json; charset=utf-8'); + if (!$this->request->isPost()) { + $this->error(__('Invalid parameters')); + } +// $password = $this->request->post('datatime'); + + $this->auth->logout(); + $this->success(__('Logout successful')); + } + + + /** + * 管理员菜单 + * + * @ApiMethod (GET) + * @ApiParams (name="is_tree", type="string", required=true, description="是否是树形结构") + */ + public function menu() + { + $admin_id = $this->auth->id; + $is_tree = $this->request->get('is_tree'); + + $menulist = (new AuthRule)->getMenulist($admin_id,["ismenu"=>1],$is_tree); + + $this->success('查询成功', $menulist); + } + + + /** + * 权限校验(接口校验版-用于前端自行显示隐藏) + * 返回null为无权限 + * @ApiMethod (GET) + * @ApiParams (name="auth_name", type="string", required=true, description="请求路径或权限标识") + */ + public function check_auth() + { + $admin_id = $this->auth->id; + $auth_name = $this->request->get('auth_name',"") ?: "***"; + $check = (new AuthRule)->authCheck($admin_id,$auth_name); + + $this->success('权限校验结果返回', $check); + } + + + + + /** + * 权限校验(直接返回拥有的所有权限,前端自行比对判断) + * + * @ApiMethod (GET) + */ + public function have_auth() + { + $admin_id = $this->auth->id; + $check = (new AuthRule)->getAllRules($admin_id); + + $this->success('权限列表返回', $check); + } + + +} \ No newline at end of file diff --git a/application/adminapi/controller/Rule.php b/application/adminapi/controller/Rule.php new file mode 100644 index 0000000..628663f --- /dev/null +++ b/application/adminapi/controller/Rule.php @@ -0,0 +1,80 @@ +model = new AuthRule; + parent::_initialize(); + } + + + + /** + * 所有权限列表 + * + * @ApiMethod (GET) + * @ApiParams (name="is_tree", type="string", required=true, description="是否是树形结构") + */ + public function rulelist() + { + $admin_id = $this->auth->id; + $is_tree = $this->request->get('is_tree'); + + $menulist = $this->model->getMenulist($admin_id,[],$is_tree,true); + + $this->success('查询成功', $menulist); + } + + + /** + * 添加权限节点(接口或菜单) + * + * @ApiMethod (POST) + * @ApiParams (name="pid", type="int", required=true, description="父ID") + * @ApiParams (name="ismenu", type="int", required=true, description="是否为菜单 0接口 1菜单") + * @ApiParams (name="name", type="string", required=true, description="节点URL(节点URL和外链选填其一)") + * @ApiParams (name="url", type="string", required=true, description="外链(节点URL和外链选填其一)") + * @ApiParams (name="rule_name", type="string", required=true, description="权限标识(菜单才需要)") + * @ApiParams (name="title", type="string", required=true, description="节点中文名") + * @ApiParams (name="icon", type="string", required=true, description="图标(菜单才需要)") + * @ApiParams (name="weigh", type="int", required=true, description="权重") + * @ApiParams (name="menutype", type="string", required=true, description="菜单类型:'addtabs','blank','dialog','ajax'") + * @ApiParams (name="extend", type="string", required=true, description="额外扩展属性(比如加类名做特特殊回调逻辑)") + * @ApiParams (name="status", type="string", required=true, description="状态(normal=正常,hidden=隐藏)") + * + */ + public function add() + { + $admin_id = $this->auth->id; + $params = $this->request->post(); + + $menulist = $this->model->add($params,true); + + $this->success('查询成功', $menulist); + } + + + + +} \ No newline at end of file diff --git a/application/adminapi/lang/zh-cn.php b/application/adminapi/lang/zh-cn.php new file mode 100644 index 0000000..e0531bf --- /dev/null +++ b/application/adminapi/lang/zh-cn.php @@ -0,0 +1,102 @@ + '保持会话', + 'Username' => '用户名', + 'User id' => '会员ID', + 'Nickname' => '昵称', + 'Password' => '密码', + 'Sign up' => '注 册', + 'Sign in' => '登 录', + 'Sign out' => '退 出', + 'Guest' => '游客', + 'Welcome' => '%s,你好!', + 'Add' => '添加', + 'Edit' => '编辑', + 'Delete' => '删除', + 'Move' => '移动', + 'Name' => '名称', + 'Status' => '状态', + 'Weigh' => '权重', + 'Operate' => '操作', + 'Warning' => '温馨提示', + 'Default' => '默认', + 'Article' => '文章', + 'Page' => '单页', + 'OK' => '确定', + 'Cancel' => '取消', + 'Loading' => '加载中', + 'More' => '更多', + 'Normal' => '正常', + 'Hidden' => '隐藏', + 'Submit' => '提交', + 'Reset' => '重置', + 'Execute' => '执行', + 'Close' => '关闭', + 'Search' => '搜索', + 'Refresh' => '刷新', + 'First' => '首页', + 'Previous' => '上一页', + 'Next' => '下一页', + 'Last' => '末页', + 'None' => '无', + 'Home' => '主页', + 'Online' => '在线', + 'Logout' => '退出', + 'Profile' => '个人资料', + 'Index' => '首页', + 'Hot' => '热门', + 'Recommend' => '推荐', + 'Dashboard' => '控制台', + 'Code' => '编号', + 'Message' => '内容', + 'Line' => '行号', + 'File' => '文件', + 'Menu' => '菜单', + 'Type' => '类型', + 'Title' => '标题', + 'Content' => '内容', + 'Append' => '追加', + 'Memo' => '备注', + 'Parent' => '父级', + 'Params' => '参数', + 'Permission' => '权限', + 'Advance search' => '高级搜索', + 'Check all' => '选中全部', + 'Expand all' => '展开全部', + 'Begin time' => '开始时间', + 'End time' => '结束时间', + 'Create time' => '创建时间', + 'Flag' => '标志', + 'Please login first' => '请登录后操作', + 'Uploaded successful' => '上传成功', + 'You can upload up to %d file%s' => '你最多还可以上传%d个文件', + 'You can choose up to %d file%s' => '你最多还可以选择%d个文件', + 'Chunk file write error' => '分片写入失败', + 'Chunk file info error' => '分片文件错误', + 'Chunk file merge error' => '分片合并错误', + 'Chunk file disabled' => '未开启分片上传功能', + 'Cancel upload' => '取消上传', + 'Upload canceled' => '上传已取消', + 'No file upload or server upload limit exceeded' => '未上传文件或超出服务器上传限制', + 'Uploaded file format is limited' => '上传文件格式受限制', + 'Uploaded file is not a valid image' => '上传文件不是有效的图片文件', + 'Are you sure you want to cancel this upload?' => '确定取消上传?', + 'Remove file' => '移除文件', + 'You can only upload a maximum of %s files' => '你最多允许上传 %s 个文件', + 'You can\'t upload files of this type' => '不允许上传的文件类型', + 'Server responded with %s code' => '服务端响应(Code:%s)', + 'File is too big (%sMiB), Max filesize: %sMiB.' => '当前上传(%sM),最大允许上传文件大小:%sM', + 'Redirect now' => '立即跳转', + 'Operation completed' => '操作成功!', + 'Operation failed' => '操作失败!', + 'Unknown data format' => '未知的数据格式!', + 'Network error' => '网络错误!', + 'Advanced search' => '高级搜索', + 'Invalid parameters' => '未知参数', + 'No results were found' => '记录未找到', + 'Parameter %s can not be empty' => '参数%s不能为空', + 'You have no permission' => '你没有权限访问', + 'An unexpected error occurred' => '发生了一个意外错误,程序猿正在紧急处理中', + 'This page will be re-directed in %s seconds' => '页面将在 %s 秒后自动跳转', +]; diff --git a/application/adminapi/lang/zh-cn/common.php b/application/adminapi/lang/zh-cn/common.php new file mode 100644 index 0000000..0b67a5f --- /dev/null +++ b/application/adminapi/lang/zh-cn/common.php @@ -0,0 +1,3 @@ + '验证码不正确', + 'Account is locked' => '账户已经被锁定', + +]; diff --git a/application/adminapi/lang/zh-cn/user.php b/application/adminapi/lang/zh-cn/user.php new file mode 100644 index 0000000..e98e4cd --- /dev/null +++ b/application/adminapi/lang/zh-cn/user.php @@ -0,0 +1,39 @@ + '会员中心', + 'Register' => '注册', + 'Login' => '登录', + 'Sign up successful' => '注册成功', + 'Username can not be empty' => '用户名不能为空', + 'Username must be 3 to 30 characters' => '用户名必须3-30个字符', + 'Username must be 6 to 30 characters' => '用户名必须6-30个字符', + 'Password can not be empty' => '密码不能为空', + 'Password must be 6 to 30 characters' => '密码必须6-30个字符', + 'Mobile is incorrect' => '手机格式不正确', + 'Username already exist' => '用户名已经存在', + 'Nickname already exist' => '昵称已经存在', + 'Email already exist' => '邮箱已经存在', + 'Mobile already exist' => '手机号已经存在', + 'Username is incorrect' => '用户名不正确', + 'Email is incorrect' => '邮箱不正确', + 'Account is locked' => '账户已经被锁定', + 'Password is incorrect' => '密码不正确', + 'Account is incorrect' => '账户不正确', + 'Account not exist' => '账户不存在', + 'Account can not be empty' => '账户不能为空', + 'Username or password is incorrect' => '用户名或密码不正确', + 'You are not logged in' => '你当前还未登录', + 'You\'ve logged in, do not login again' => '你已经存在,请不要重复登录', + 'Profile' => '个人资料', + 'Verify email' => '邮箱验证', + 'Change password' => '修改密码', + 'Captcha is incorrect' => '验证码不正确', + 'Logged in successful' => '登录成功', + 'Logout successful' => '退出成功', + 'Operation failed' => '操作失败', + 'Invalid parameters' => '参数不正确', + 'Change password failure' => '修改密码失败', + 'Change password successful' => '修改密码成功', + 'Reset password successful' => '重置密码成功', +]; diff --git a/application/adminapi/lang/zh-cn/xilufitness/xilufitess.php b/application/adminapi/lang/zh-cn/xilufitness/xilufitess.php new file mode 100644 index 0000000..8320a25 --- /dev/null +++ b/application/adminapi/lang/zh-cn/xilufitness/xilufitess.php @@ -0,0 +1,21 @@ + '参数错误', + 'Registration login failed' => '注册登录失败', + 'Mobile' => '手机号', + 'Openid' => '小程序Openid', + 'Mobile is already exists' => '手机号已存在', + 'Nickname' => '用户昵称', + 'Avatar' => '用户头像', + 'User_id' => '用户Id', + 'Brand_id' => '所属品牌商', + 'Order_no' => '订单号', + 'Recharge_id' => '充值套餐', + 'Pay_amount' => '支付金额', + 'Coach_id' => '教练Id', + 'Start_at' => '开始时间', + 'end_at' => '结束时间', + 'Report_description' => '请假事由', +]; diff --git a/application/adminapi/library/Auth.php b/application/adminapi/library/Auth.php new file mode 100644 index 0000000..eee4fd3 --- /dev/null +++ b/application/adminapi/library/Auth.php @@ -0,0 +1,622 @@ +config = array_merge($this->config, $config); + } + $this->options = array_merge($this->config, $options); + } + + + /** + * + * @param array $options 参数 + * @return \app\common\library\Auth + */ + public static function instance($options = []) + { + if (is_null(self::$instance)) { + self::$instance = new static($options); + } + + return self::$instance; + } + + + /** + * 获取User模型 + * @return User + */ + public function getUser() + { + return $this->_user; + } + + /** + * 兼容调用user模型的属性 + * + * @param string $name + * @return mixed + */ + public function __get($name) + { + return $this->_user ? $this->_user->$name : null; + } + + /** + * 兼容调用user模型的属性 + */ + public function __isset($name) + { + return isset($this->_user) ? isset($this->_user->$name) : false; + } + + + public function isSuperAdmin() + { + return in_array('*', $this->getRuleIds()) ? true : false; + } + + public function getRuleIds($uid=null) + { + $uid = is_null($uid) ? $this->id : $uid; + //读取用户所属用户组 + $groups = $this->getGroups($uid); + $ids = []; //保存用户所属用户组设置的所有权限规则id + foreach ($groups as $g) { + $ids = array_merge($ids, explode(',', trim($g['rules'], ','))); + } + $ids = array_unique($ids); + return $ids; + } + + + public function getGroups($uid=null) + { + $uid = is_null($uid) ? $this->id : $uid; + //读取用户所属用户组 + $group_ids = AuthGroupAccess::where("uid",$uid)->column("group_id"); + $groups = []; + if($group_ids) $groups = AuthGroup::where('id', 'in', $group_ids)->select(); + return $groups; + } + + + /** + * 取出当前管理员所拥有权限的分组 + * @param boolean $withself 是否包含当前所在的分组 + * @return array + */ + public function getChildrenGroupIds($withself = false) + { + //取出当前管理员所有的分组 + $groups = $this->getGroups(); + $groupIds = []; + foreach ($groups as $k => $v) { + $groupIds[] = $v['id']; + } + $originGroupIds = $groupIds; + foreach ($groups as $k => $v) { + if (in_array($v['pid'], $originGroupIds)) { + $groupIds = array_diff($groupIds, [$v['id']]); + unset($groups[$k]); + } + } + // 取出所有分组 + $groupList = \app\adminapi\model\AuthGroup::where($this->isSuperAdmin() ? '1=1' : ['status' => 'normal'])->select(); + $objList = []; + foreach ($groups as $k => $v) { + if ($v['rules'] === '*') { + $objList = $groupList; + break; + } + // 取出包含自己的所有子节点 + $childrenList = Tree::instance()->init($groupList, 'pid')->getChildren($v['id'], true); + $obj = Tree::instance()->init($childrenList, 'pid')->getTreeArray($v['pid']); + $objList = array_merge($objList, Tree::instance()->getTreeList($obj)); + } + $childrenGroupIds = []; + foreach ($objList as $k => $v) { + $childrenGroupIds[] = $v['id']; + } + if (!$withself) { + $childrenGroupIds = array_diff($childrenGroupIds, $groupIds); + } + return $childrenGroupIds; + } + + /** + * 取出当前管理员所拥有权限的管理员 + * @param boolean $withself 是否包含自身 + * @return array + */ + public function getChildrenAdminIds($withself = false) + { + $childrenAdminIds = []; + if (!$this->isSuperAdmin()) { + $groupIds = $this->getChildrenGroupIds(false); + $authGroupList = \app\adminapi\model\AuthGroupAccess::field('uid,group_id') + ->where('group_id', 'in', $groupIds) + ->select(); + foreach ($authGroupList as $k => $v) { + $childrenAdminIds[] = $v['uid']; + } + } else { + //超级管理员拥有所有人的权限 + $childrenAdminIds = Admin::column('id'); + } + if ($withself) { + if (!in_array($this->id, $childrenAdminIds)) { + $childrenAdminIds[] = $this->id; + } + } else { + $childrenAdminIds = array_diff($childrenAdminIds, [$this->id]); + } + return $childrenAdminIds; + } + + + + + + /** + * 根据Token初始化 + * + * @param string $token Token + * @return boolean + */ + public function init($token) + { + if ($this->_logined) { + return true; + } + if ($this->_error) { + return false; + } + $data = Token::get($token); + if (!$data) { + return false; + } + $user_id = intval($data['user_id']); + if ($user_id > 0) { + $user = Admin::get($user_id); + if (!$user) { + $this->setError('Account not exist'); + return false; + } + if ($user['status'] != 'normal') { + $this->setError('Account is locked'); + return false; + } + $this->_user = $user; + $this->_logined = true; + $this->_token = $token; + + //初始化成功的事件 + Hook::listen("admin_init_successed", $this->_user); + + return true; + } else { + $this->setError('You are not logged in'); + return false; + } + } + + + + + /** + * 用户登录 + * + * @param string $account 账号,用户名、邮箱、手机号 + * @param string $password 密码 + * @return boolean + */ + public function login($account, $password, $keeptime = NULL) + { + $field = Validate::is($account, 'email') ? 'email' : (Validate::regex($account, '/^1\d{10}$/') ? 'mobile' : 'username'); + $admin = Admin::get([$field => $account]); + if (!$admin) { + $this->setError('Account is incorrect'); + return false; + } + + if ($admin->status != 'normal') { + $this->setError('Account is locked'); + return false; + } + + if (Config::get('fastadmin.login_failure_retry') && $admin->loginfailure >= 10 && time() - $admin->updatetime < 86400) { + $this->setError('Please try again after 1 day'); + return false; + } + if ($admin->password != $this->getEncryptPassword($password, $admin->salt)) { + $admin->loginfailure++; + $admin->save(); + $this->setError('Password is incorrect'); + return false; + } + $this->keeptime = $keeptime !== NULL ? $keeptime : $this->keeptime; + + //直接登录会员 + return $this->direct($admin->id); + } + + + + /** + * 退出 + * + * @return boolean + */ + public function logout() + { + if (!$this->_logined) { + $this->setError('You are not logged in'); + return false; + } + //设置登录标识 + $this->_logined = false; + //删除Token + Token::delete($this->_token); + //退出成功的事件 + Hook::listen("admin_logout_successed", $this->_user); + return true; + } + + + + /** + * 修改密码 + * @param string $newpassword 新密码 + * @param string $oldpassword 旧密码 + * @param bool $ignoreoldpassword 忽略旧密码 + * @return boolean + */ + public function changepwd($newpassword, $oldpassword = '', $ignoreoldpassword = false) + { + if (!$this->_logined) { + $this->setError('You are not logged in'); + return false; + } + //判断旧密码是否正确 + if ($this->_user->password == $this->getEncryptPassword($oldpassword, $this->_user->salt) || $ignoreoldpassword) { + Db::startTrans(); + try { + $salt = Random::alnum(); + $newpassword = $this->getEncryptPassword($newpassword, $salt); + $this->_user->save(['loginfailure' => 0, 'password' => $newpassword, 'salt' => $salt]); + + Token::delete($this->_token); + //修改密码成功的事件 + Hook::listen("admin_changepwd_successed", $this->_user); + Db::commit(); + } catch (Exception $e) { + Db::rollback(); + $this->setError($e->getMessage()); + return false; + } + return true; + } else { + $this->setError('Password is incorrect'); + return false; + } + } + + + + + /** + * 直接登录账号 + * @param int $user_id + * @return boolean + */ + public function direct($user_id) + { + $admin = Admin::get($user_id); + if ($admin) { + Db::startTrans(); + try { + + + $admin->loginfailure = 0; + $admin->logintime = time(); + $admin->loginip = request()->ip(); + $admin->token = Random::uuid(); + $admin->save(); + + $this->_user = $admin; + + $this->_token = $admin->token; + Token::set($this->_token, $admin->id, $this->keeptime); + + $this->_logined = true; + + //登录成功的事件 + Hook::listen("admin_login_successed", $this->_user); + Db::commit(); + } catch (Exception $e) { + Db::rollback(); + $this->setError($e->getMessage()); + return false; + } + return true; + } else { + return false; + } + } + + + + /** + * 获取密码加密后的字符串 + * @param string $password 密码 + * @param string $salt 密码盐 + * @return string + */ + public function getEncryptPassword($password, $salt = '') + { + return md5(md5($password) . $salt); + } + + + + + /** + * 判断是否登录 + * @return boolean + */ + public function isLogin() + { + if ($this->_logined) { + return true; + } + return false; + } + + /** + * 获取当前Token + * @return string + */ + public function getToken() + { + return $this->_token; + } + + /** + * 获取会员基本信息 + */ + public function getUserinfo() + { + $data = $this->_user->toArray(); + $allowFields = $this->getAllowFields(); + $userinfo = array_intersect_key($data, array_flip($allowFields)); + $userinfo = array_merge($userinfo, Token::get($this->_token)); + return $userinfo; + } + + + /** + * 获取会员组别规则列表 + * @return array|bool|\PDOStatement|string|\think\Collection + */ + public function getRuleList() + { + if ($this->rules) { + return $this->rules; + } + $groups = $this->_user->groups; + if (!$groups) { + return []; + } + $rules = []; + foreach ($groups as $group){ + $rules = array_merge($rules, explode(',', $group->rules)); + } + if(in_array('*',$rules)){ + $this->rules = AuthRule::where('status', 'normal')->field('id,pid,rule_name,name,title,ismenu')->select(); + }else{ + $this->rules = AuthRule::where('status', 'normal')->where('id', 'in', $rules)->field('id,pid,rule_name,name,title,ismenu')->select(); + } + + return $this->rules; + } + + + + /** + * 检测是否是否有对应权限 + * @param string $path 控制器/方法 + * @param string $module 模块 默认为当前模块 + * @return boolean + */ + public function check($path = null, $module = null) + { + + if (!$this->_logined) { + return false; + } + + $ruleList = $this->getRuleList(); + + + $rules = []; + foreach ($ruleList as $k => $v) { + $rules[] = $v['name']; + } +// var_dump($rules); +// $url = ($module ? $module : request()->module()) . '/' . (is_null($path) ? $this->getRequestUri() : $path); + $url = (is_null($path) ? $this->getRequestUri() : $path); + $url = strtolower(str_replace('.', '/', $url)); + return in_array($url, $rules); + } + + + + /** + * 获取当前请求的URI + * @return string + */ + public function getRequestUri() + { + return $this->requestUri; + } + + /** + * 设置当前请求的URI + * @param string $uri + */ + public function setRequestUri($uri) + { + $this->requestUri = $uri; + } + + /** + * 获取允许输出的字段 + * @return array + */ + public function getAllowFields() + { + return $this->allowFields; + } + + /** + * 设置允许输出的字段 + * @param array $fields + */ + public function setAllowFields($fields) + { + $this->allowFields = $fields; + } + + + + /** + * 检测当前控制器和方法是否匹配传递的数组 + * + * @param array $arr 需要验证权限的数组 + * @return boolean + */ + public function match($arr = []) + { + $request = Request::instance(); + $arr = is_array($arr) ? $arr : explode(',', $arr); + if (!$arr) { + return false; + } + $arr = array_map('strtolower', $arr); + // 是否存在 + if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr)) { + return true; + } + + // 没找到匹配 + return false; + } + + + /** + * 设置会话有效时间 + * @param int $keeptime 默认为永久 + */ + public function keeptime($keeptime = 0) + { + $this->keeptime = $keeptime; + } + + /** + * 设置错误信息 + * + * @param string $error 错误信息 + * @return \app\common\library\Auth + */ + public function setError($error) + { + $this->_error = $error; + return $this; + } + + /** + * 获取错误信息 + * @return string + */ + public function getError() + { + return $this->_error ? __($this->_error) : ''; + } + + + + /** + * 获得面包屑导航 + * @param string $path + * @return array + */ + public function getBreadCrumb($path = '') + { + if ($this->breadcrumb || !$path) { + return $this->breadcrumb; + } + $titleArr = []; + $menuArr = []; + $urlArr = explode('/', $path); + foreach ($urlArr as $index => $item) { + $pathArr[implode('/', array_slice($urlArr, 0, $index + 1))] = $index; + } + if (!$this->rules && $this->id) { + $this->getRuleList(); + } + foreach ($this->rules as $rule) { + if (isset($pathArr[$rule['name']])) { + $rule['title'] = __($rule['title']); + $rule['url'] = url($rule['name']); + $titleArr[$pathArr[$rule['name']]] = $rule['title']; + $menuArr[$pathArr[$rule['name']]] = $rule; + } + } + ksort($menuArr); + $this->breadcrumb = $menuArr; + return $this->breadcrumb; + } + +} \ No newline at end of file diff --git a/application/adminapi/library/ExceptionHandle.php b/application/adminapi/library/ExceptionHandle.php new file mode 100644 index 0000000..852f7ef --- /dev/null +++ b/application/adminapi/library/ExceptionHandle.php @@ -0,0 +1,37 @@ +getError(); + } + // Http异常 + if ($e instanceof \think\exception\HttpException) { + $statuscode = $code = $e->getStatusCode(); + } + return json(['code' => $code, 'msg' => $msg, 'time' => time(), 'data' => null], $statuscode); + } + + //其它此交由系统处理 + return parent::render($e); + } + +} diff --git a/application/adminapi/model/Admin.php b/application/adminapi/model/Admin.php new file mode 100644 index 0000000..81f336f --- /dev/null +++ b/application/adminapi/model/Admin.php @@ -0,0 +1,118 @@ +column("group_id"); + if(!$group_ids)return []; + + $groups = \app\admin\model\api\AuthGroup::where("id","in",$group_ids)->select(); + return $groups; + } + + + + + + + public static function init() + { + self::beforeWrite(function ($row) { + $changed = $row->getChangedData(); + //如果修改了用户或或密码则需要重新登录 + if (isset($changed['username']) || isset($changed['password']) || isset($changed['salt'])) { + $row->token = ''; + } + }); + } + + public function getAddressCityList(){ + return SearchCity::column("address_city","id"); + } + + + public static function getHaveShopId($adminId){ + $admin = self::get($adminId); + if(!$admin)throw new \Exception("管理员不存在"); + $area_json = $admin->area_json; + $shop_id = "*"; + if($area_json){ + $shop_id = []; + $searchCity = SearchCity::where("id","in",$area_json)->select(); + foreach ($searchCity as $item){ + $province = $item->province; + $city = $item->city; + $district = $item->district; + //查询在该区域的店铺id + $manystoreShop = new ManystoreShop; + if($province)$manystoreShop = $manystoreShop->where("province",$province); + if($city)$manystoreShop = $manystoreShop->where("city",$city); + if($district)$manystoreShop = $manystoreShop->where("district",$district); + $shop_id = array_merge($shop_id,$manystoreShop->column("id")); + } + } + return $shop_id; + } + + public static function getHaveCity($adminId){ + $provinces = $citys = $districts = $address_citys = []; + $admin = self::get($adminId); + if(!$admin)return compact("provinces","citys","districts","address_citys"); + $area_json = $admin->area_json; + + if($area_json){ + $searchCity = SearchCity::where("id","in",$area_json)->select(); + foreach ($searchCity as $item){ + $address_citys[] = $item->address_city; + $province = $item->province; + if($province)$provinces[] = $province; + $city = $item->city; + if($city)$citys[] = $city; + $district = $item->district; + if($district)$districts[] = $district; + } + } + if(!$provinces)$provinces="*"; + if(!$citys)$citys="*"; + if(!$districts)$districts="*"; + if(!$address_citys)$address_citys="*"; + return compact("provinces","citys","districts","address_citys"); + } + + + + public static function checkAuthMsg($adminId){ + ["provinces" =>$provinces,"citys"=> $citys, "districts"=>$districts,"address_citys"=>$address_citys] = self::getHaveCity($adminId); + if(is_array($address_citys))$address_citys = implode(",",$address_citys); + //必要信息已完善 + return '
+ 您当前的区域管理权限为: '.$address_citys.' (能管理该区域下的机构信息,如果是*则不限制)
'; + + } + + +} diff --git a/application/adminapi/model/AdminLog.php b/application/adminapi/model/AdminLog.php new file mode 100644 index 0000000..37da958 --- /dev/null +++ b/application/adminapi/model/AdminLog.php @@ -0,0 +1,119 @@ +isLogin() ? $auth->id : 0; + $username = $auth->isLogin() ? $auth->username : __('Unknown'); + + // 设置过滤函数 + request()->filter('trim,strip_tags,htmlspecialchars'); + $modulename = request()->module(); + $controllername = Loader::parseName(request()->controller()); + $actionname = strtolower(request()->action()); + $path = $modulename. '/' . str_replace('.', '/', $controllername) . '/' . $actionname; + if (self::$ignoreRegex) { + foreach (self::$ignoreRegex as $index => $item) { + if (preg_match($item, $path)) { + return; + } + } + } + $content = $content ?: self::$content; + if (!$content) { + $content = request()->param('') ?: file_get_contents("php://input"); + $content = self::getPureContent($content); + } + $title = $title ?: self::$title; + if (!$title) { + $title = []; + $breadcrumb = Auth::instance()->getBreadcrumb($path); + foreach ($breadcrumb as $k => $v) { + $title[] = $v['title']; + } + $title = implode(' / ', $title); + } + self::create([ + 'title' => $title, + 'content' => !is_scalar($content) ? json_encode($content, JSON_UNESCAPED_UNICODE) : $content, + 'url' => substr(xss_clean(strip_tags(request()->url())), 0, 1500), + 'admin_id' => $admin_id, + 'username' => $username, + 'useragent' => substr(request()->server('HTTP_USER_AGENT'), 0, 255), + 'ip' => xss_clean(strip_tags(request()->ip())) + ]); + } + + /** + * 获取已屏蔽关键信息的数据 + * @param $content + * @return array + */ + protected static function getPureContent($content) + { + if (!is_array($content)) { + return $content; + } + foreach ($content as $index => &$item) { + if (preg_match("/(password|salt|token)/i", $index)) { + $item = "***"; + } else { + if (is_array($item)) { + $item = self::getPureContent($item); + } + } + } + return $content; + } + + public function admin() + { + return $this->belongsTo('Admin', 'admin_id')->setEagerlyType(0); + } +} diff --git a/application/adminapi/model/AuthGroup.php b/application/adminapi/model/AuthGroup.php new file mode 100644 index 0000000..249d595 --- /dev/null +++ b/application/adminapi/model/AuthGroup.php @@ -0,0 +1,22 @@ + __('Addtabs'), 'dialog' => __('Dialog'), 'ajax' => __('Ajax'), 'blank' => __('Blank')]; + } + + public function setPyAttr($value, $data) + { + if (isset($data['title']) && $data['title']) { + return self::$pinyin->abbr(__($data['title'])); + } + return ''; + } + + public function setPinyinAttr($value, $data) + { + if (isset($data['title']) && $data['title']) { + return self::$pinyin->permalink(__($data['title']), ''); + } + return ''; + } + + + + /** + * 获取会员组别规则列表 + * @return array|bool|\PDOStatement|string|\think\Collection + */ + public function getRuleList($admin_id,$where=[],$full = false) + { + $group_ids = AuthGroupAccess::where("uid",$admin_id)->column("group_id"); + if(!$group_ids && !$full) return []; + $groups = AuthGroup::where('id', 'in', $group_ids)->select(); + if (!$groups && !$full ) { + return []; + } + $rules = []; + foreach ($groups as $group){ + $rules = array_merge($rules, explode(',', $group->rules)); + } + //包含*全查,否则按值查 + if ($full || in_array('*', $rules)) { + return AuthRule::where($where)->where('status', 'normal')->order('weigh desc,id desc')->select(); + } + return AuthRule::where($where)->where('status', 'normal')->where('id', 'in', $rules)->order('weigh desc,id desc')->select(); + } + + + //得到菜单列表 + public function getMenulist($admin_id,$where= ["ismenu"=>1],$is_tree=false,$full = false,$id_name='id',$pid_name='pid',$child_name='children') + { + $menu = $this->getRuleList($admin_id,$where,$full); + if(!$is_tree){ + return $menu; + } + // 生成菜单的树状结构 id pid ,pid=0为顶级菜单 + $menulist = []; + foreach ($menu as $k => $v) { + $v = $v->toArray(); + $v[$id_name] = $v['id']; + $v[$pid_name] = $v['pid']; + $menulist[$v[$id_name]] = $v; + } + $tree = []; + + foreach ($menulist as $k => $v) { + if (isset($menulist[$v[$pid_name]])) { + $menulist[$v[$pid_name]][$child_name][] = &$menulist[$v[$id_name]]; + } else { + $tree[] = &$menulist[$v[$id_name]]; + } + } + return $tree; + + + } + + + public function authCheck($admin_id,$auth_name) + { + $group_ids = AuthGroupAccess::where("uid",$admin_id)->column("group_id"); + if(!$group_ids) return null; + $groups = AuthGroup::where('id', 'in', $group_ids)->select(); + if (!$groups) { + return null; + } + $rules = []; + foreach ($groups as $group){ + $rules = array_merge($rules, explode(',', $group->rules)); + } + //包含*全查,否则按值查 + if (in_array('*', $rules)) { + return AuthRule::where('status', 'normal')->where( 'name|rule_name',$auth_name)->find() ; + } + return AuthRule::where('status', 'normal')->where( 'name|rule_name',$auth_name)->where('id', 'in', $rules)->find(); + + } + + public function getAllRules($admin_id) + { + $group_ids = AuthGroupAccess::where("uid",$admin_id)->column("group_id"); + if(!$group_ids) return null; + $groups = AuthGroup::where('id', 'in', $group_ids)->select(); + if (!$groups) { + return null; + } + $rules = []; + foreach ($groups as $group){ + $rules = array_merge($rules, explode(',', $group->rules)); + } + //包含*全查,否则按值查 + if (in_array('*', $rules)) { + return AuthRule::where('status', 'normal')->field("name,rule_name,ismenu")->select() ; + } + return AuthRule::where('status', 'normal')->where('id', 'in', $rules)->field("name,rule_name,ismenu")->select(); + + + } + + + + /** 通用新增(后台api版本) + * @param $params + * @param $trans + * @return $this + * @throws \Exception + */ + public function add($params,$trans=false){ + + if (empty($params)) { + throw new \Exception(__('Parameter %s can not be empty', '')); + } + + if ($this->dataLimit && $this->dataLimitFieldAutoFill) { + $params[$this->dataLimitField] = $this->auth->id; + } +//判断逻辑 + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + + //是否采用模型验证 + if ($this->modelValidate) { + $name = str_replace("\\model\\", "\\validate\\", get_class($this)); + $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate; + $this->validateFailException()->validate($validate); + } + + + + $result = $this->allowField(true)->save($params); + + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage().$e->getFile().$e->getLine()); + } + return $this; + } + + +} diff --git a/application/adminapi/tags.php b/application/adminapi/tags.php new file mode 100644 index 0000000..882fdfb --- /dev/null +++ b/application/adminapi/tags.php @@ -0,0 +1,18 @@ + +// +---------------------------------------------------------------------- +// 应用行为扩展定义文件 +return [ + // 应用结束 + 'app_end' => [ + 'app\\adminapi\\behavior\\AdminLog', + ], +]; diff --git a/application/api/controller/school/Shop.php b/application/api/controller/school/Shop.php index b1989c6..c15a370 100644 --- a/application/api/controller/school/Shop.php +++ b/application/api/controller/school/Shop.php @@ -3,6 +3,7 @@ namespace app\api\controller\school; use app\common\model\dyqc\ManystoreShop; +use app\common\model\manystore\ShopApply; /** * 机构接口 @@ -61,8 +62,8 @@ class Shop extends Base /** 机构申请 - * @ApiTitle( 机构申请) - * @ApiSummary(机构申请) + * @ApiTitle( 机构申请(废弃)) + * @ApiSummary(机构申请(废弃)) * @ApiRoute(/api/school/shop/shopapply) * @ApiMethod(POST) * @ApiParams(name = "name", type = "string",required=true,description = "机构名称") @@ -161,8 +162,8 @@ class Shop extends Base /** 个人申请 - * @ApiTitle( 个人申请) - * @ApiSummary(个人申请) + * @ApiTitle( 个人申请(废弃)) + * @ApiSummary(个人申请(废弃)) * @ApiRoute(/api/school/shop/userapply) * @ApiMethod(POST) * @ApiParams(name = "name", type = "string",required=true,description = "姓名") @@ -442,4 +443,47 @@ class Shop extends Base } + + + /** 机构申请新版接口 + * @ApiTitle( 机构申请新版接口) + * @ApiSummary(机构申请新版接口) + * @ApiRoute(/api/school/shop/apply) + * @ApiMethod(POST) + * @ApiParams(name = "type", type = "string",required=true,description = "类型:1=个人,2=机构") + * @ApiParams(name = "name", type = "string",required=true,description = "机构名称(机构入驻才需要)") + * @ApiParams(name = "realname", type = "string",required=true,description = "联系人姓名") + * @ApiParams(name = "mobile", type = "string",required=true,description = "联系电话") + * @ApiParams(name = "address", type = "string",required=true,description = "地址") + * @ApiReturn({ + * + *}) + */ + public function apply(){ + $params=[]; + $params["name"] = $this->request->post('name/s',''); + $params["realname"] = $this->request->post('realname/s',''); + $params["mobile"] = $this->request->post('mobile/s',''); + $params["address"] = $this->request->post('address/s',''); + $params["type"] = $this->request->post('type/s',''); + +// if(empty($id)){ +// $this->error(__('缺少必要参数')); +// } + $type = $params["type"]; + $user_id = 0; + $user = $this->auth->getUser();//登录用户 + if($user)$user_id = $user['id']; + $params["user_id"] = $user_id; + try { + $res = (new ShopApply())->apply($type,$user_id,$params,true,true); + } catch (\Exception $e){ +// Log::log($e->getMessage()); + $this->error($e->getMessage(),['errcode'=>$e->getCode()]); + } + $this->success('获取成功', ['detail' => $res]); + } + + + } \ No newline at end of file diff --git a/application/common/controller/AdminApi.php b/application/common/controller/AdminApi.php new file mode 100644 index 0000000..8295574 --- /dev/null +++ b/application/common/controller/AdminApi.php @@ -0,0 +1,366 @@ +request = is_null($request) ? Request::instance() : $request; + + // 控制器初始化 + $this->_initialize(); + + // 前置操作方法 + if ($this->beforeActionList) { + foreach ($this->beforeActionList as $method => $options) { + is_numeric($method) ? + $this->beforeAction($options) : + $this->beforeAction($method, $options); + } + } + } + + + protected $needUrlLock = []; + + protected function setUrlLock($url_key="",$url_suffix="",$model=null){ + if(($this->request->isPost() || (!empty($this->needUrlLock) && in_array($this->request->action(),$this->needUrlLock))) && (!empty($this->model) || $model)){ + $user_id = 0; + $user = $this->auth->getUser();//登录用户 + if($user)$user_id = $user['id']; + + $modulename = $this->request->module(); + $controllername = Loader::parseName($this->request->controller()); + $actionname = strtolower($this->request->action()); + $path = $modulename . '/' . str_replace('.', '/', $controllername) . '/' . $actionname; + if(!$model){ + $this->model::$url_lock_key = $url_key ?: $user_id; + $this->model::$url_lock_suffix = $url_suffix ?: $path."lock-suffix"; + $this->model::$url_lock = true; + }else{ + $model::$url_lock_key = $url_key ?: $user_id; + $model::$url_lock_suffix = $url_suffix ?: $path."lock-suffix"; + $model::$url_lock = true; + } + + } + } + + /** + * 初始化操作 + * @access protected + */ + protected function _initialize() + { + //跨域请求检测 + check_cors_request(); + + // 检测IP是否允许 + check_ip_allowed(); + + //移除HTML标签 + $this->request->filter('trim,strip_tags,htmlspecialchars'); + + + $this->auth = Auth::instance(); + + $modulename = $this->request->module(); + $controllername = Loader::parseName($this->request->controller()); + $actionname = strtolower($this->request->action()); + // token + $token = $this->request->server('HTTP_ADMINTOKEN', $this->request->request('admintoken', \think\Cookie::get('admintoken'))); + + $path = $modulename. '/' .str_replace('.', '/', $controllername) . '/' . $actionname; + // 设置当前请求的URI + $this->auth->setRequestUri($path); + + // 检测是否需要验证登录 + if (!$this->auth->match($this->noNeedLogin)) { + //初始化 + $this->auth->init($token); + //检测是否登录 + if (!$this->auth->isLogin()) { + $this->error(__('Please login first'), ['errcode'=>30002], 401); + } + // 判断是否需要验证权限 + if (!$this->auth->match($this->noNeedRight)) { + // 判断控制器和方法判断是否有对应权限 + if (!$this->auth->check($path)) { + $this->error(__('You have no permission'), null, 403); + } + } + } else { + // 如果有传递token才验证是否登录状态 + if ($token) { + $this->auth->init($token); + } + } + + + $upload = \app\common\model\Config::upload(); + + // 上传信息配置后 + Hook::listen("upload_config_init", $upload); + + Config::set('upload', array_merge(Config::get('upload'), $upload)); + + // 加载当前控制器语言包 + $this->loadlang($controllername); +// Virtual::visitNnmberUpdate(); + } + + + /** + * 加载语言文件 + * @param string $name + */ + protected function loadlang($name) + { + $name = Loader::parseName($name); + $name = preg_match("/^([a-zA-Z0-9_\.\/]+)\$/i", $name) ? $name : 'index'; + $lang = $this->request->langset(); + $lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn'; + Lang::load(APP_PATH . $this->request->module() . '/lang/' . $lang . '/' . str_replace('.', '/', $name) . '.php'); + } + + + /** + * 操作成功返回的数据 + * @param string $msg 提示信息 + * @param mixed $data 要返回的数据 + * @param int $code 错误码,默认为1 + * @param string $type 输出类型 + * @param array $header 发送的 Header 信息 + */ + protected function success($msg = '', $data = null, $code = 1, $type = null, array $header = []) + { + $this->result($msg, $data, $code, $type, $header); + } + + /** + * 操作失败返回的数据 + * @param string $msg 提示信息 + * @param mixed $data 要返回的数据 + * @param int $code 错误码,默认为0 + * @param string $type 输出类型 + * @param array $header 发送的 Header 信息 + */ + protected function error($msg = '', $data = null, $code = 0, $type = null, array $header = []) + { + $this->result($msg, $data, $code, $type, $header); + } + + /** + * 返回封装后的 API 数据到客户端 + * @access protected + * @param mixed $msg 提示信息 + * @param mixed $data 要返回的数据 + * @param int $code 错误码,默认为0 + * @param string $type 输出类型,支持json/xml/jsonp + * @param array $header 发送的 Header 信息 + * @return void + * @throws HttpResponseException + */ + protected function result($msg, $data = null, $code = 0, $type = null, array $header = []) + { + $result = [ + 'code' => $code, + 'msg' => $msg, + 'time' => Request::instance()->server('REQUEST_TIME'), + 'data' => $data, + ]; + // 如果未设置类型则使用默认类型判断 + $type = $type ? : $this->responseType; + + if (isset($header['statuscode'])) { + $code = $header['statuscode']; + unset($header['statuscode']); + } else { + //未设置状态码,根据code值判断 + $code = $code >= 1000 || $code < 200 ? 200 : $code; + } + $response = Response::create($result, $type, $code)->header($header); + throw new HttpResponseException($response); + } + + + /** + * 前置操作 + * @access protected + * @param string $method 前置操作方法名 + * @param array $options 调用参数 ['only'=>[...]] 或者 ['except'=>[...]] + * @return void + */ + protected function beforeAction($method, $options = []) + { + if (isset($options['only'])) { + if (is_string($options['only'])) { + $options['only'] = explode(',', $options['only']); + } + + if (!in_array($this->request->action(), $options['only'])) { + return; + } + } elseif (isset($options['except'])) { + if (is_string($options['except'])) { + $options['except'] = explode(',', $options['except']); + } + + if (in_array($this->request->action(), $options['except'])) { + return; + } + } + + call_user_func([$this, $method]); + } + + /** + * 设置验证失败后是否抛出异常 + * @access protected + * @param bool $fail 是否抛出异常 + * @return $this + */ + protected function validateFailException($fail = true) + { + $this->failException = $fail; + + return $this; + } + + + + /** + * 验证数据 + * @access protected + * @param array $data 数据 + * @param string|array $validate 验证器名或者验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @param mixed $callback 回调方法(闭包) + * @return array|string|true + * @throws ValidateException + */ + protected function validate($data, $validate, $message = [], $batch = false, $callback = null) + { + if (is_array($validate)) { + $v = Loader::validate(); + $v->rule($validate); + } else { + // 支持场景 + if (strpos($validate, '.')) { + list($validate, $scene) = explode('.', $validate); + } + + $v = Loader::validate($validate); + + !empty($scene) && $v->scene($scene); + } + + // 批量验证 + if ($batch || $this->batchValidate) { + $v->batch(true); + } + // 设置错误信息 + if (is_array($message)) { + $v->message($message); + } + // 使用回调验证 + if ($callback && is_callable($callback)) { + call_user_func_array($callback, [$v, &$data]); + } + + if (!$v->check($data)) { + if ($this->failException) { + throw new ValidateException($v->getError()); + } + + return $v->getError(); + } + + return true; + } + + + /** + * 刷新Token + */ + protected function token() + { + $token = $this->request->param('__token__'); + + //验证Token + if (!Validate::make()->check(['__token__' => $token], ['__token__' => 'require|token'])) { + $this->error(__('Token verification error'), ['__token__' => $this->request->token()]); + } + + //刷新Token + $this->request->token(); + } + + + +} \ No newline at end of file diff --git a/application/common/controller/Backend.php b/application/common/controller/Backend.php index f987159..d4a8097 100644 --- a/application/common/controller/Backend.php +++ b/application/common/controller/Backend.php @@ -208,7 +208,7 @@ class Backend extends Controller $q_fields = []; foreach ($get as $kay=>$getField) { - if (in_array($kay, $fieldLists)) { + if (in_array($kay, $fieldLists) || in_array($kay, $this->qFields)) { $q_fields[$kay] = $getField; } } diff --git a/application/common/controller/ManystoreBase.php b/application/common/controller/ManystoreBase.php index 4ed78b0..0e58567 100644 --- a/application/common/controller/ManystoreBase.php +++ b/application/common/controller/ManystoreBase.php @@ -175,7 +175,7 @@ class ManystoreBase extends Controller $q_fields = []; foreach ($get as $kay=>$getField) { - if (in_array($kay, $fieldLists)) { + if (in_array($kay, $fieldLists) || in_array($kay, $this->qFields)) { $q_fields[$kay] = $getField; } } diff --git a/application/common/model/BaseModel.php b/application/common/model/BaseModel.php index 09f1620..b1c7aa4 100644 --- a/application/common/model/BaseModel.php +++ b/application/common/model/BaseModel.php @@ -32,6 +32,62 @@ class BaseModel extends Model + /** + * 是否开启Validate验证 + */ + protected $modelValidate = false; + + /** + * 是否开启模型场景验证 + */ + protected $modelSceneValidate = false; + + + + /** + * 是否开启数据限制 + * 支持auth/personal + * 表示按权限判断/仅限个人 + * 默认为禁用,若启用请务必保证表中存在admin_id字段 + */ + protected $dataLimit = false; + + + /** + * 数据限制字段 + */ + protected $dataLimitField = 'admin_id'; + + /** + * 数据限制开启时自动填充限制字段值 + */ + protected $dataLimitFieldAutoFill = true; + + + + + + /** + * 获取数据限制的管理员ID(后台api版本) + * 禁用数据限制时返回的是null + * @return mixed + */ + protected function getDataLimitAdminIds() + { + if (!$this->dataLimit) { + return null; + } + $auth = \app\adminapi\library\Auth::instance(); + if ($auth->isSuperAdmin()) { + return null; + } + $adminIds = []; + if (in_array($this->dataLimit, ['auth', 'personal'])) { + $adminIds = $this->dataLimit == 'auth' ? $auth->getChildrenAdminIds(true) : [$auth->id]; + } + return $adminIds; + } + public function checkAssemblyParameters($get=[],$exclude = []){ //得到所有get参数 @@ -288,4 +344,171 @@ class BaseModel extends Model } + /** 通用新增(后台api版本) + * @param $params + * @param $trans + * @return $this + * @throws \Exception + */ + public function add($params,$trans=false){ + + if (empty($params)) { + throw new \Exception(__('Parameter %s can not be empty', '')); + } + + if ($this->dataLimit && $this->dataLimitFieldAutoFill) { + $params[$this->dataLimitField] = $this->auth->id; + } +//判断逻辑 + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + + //是否采用模型验证 + if ($this->modelValidate) { + $name = str_replace("\\model\\", "\\validate\\", get_class($this)); + $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate; + $this->validateFailException()->validate($validate); + } + + $result = $this->allowField(true)->save($params); + + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage().$e->getFile().$e->getLine()); + } + return $this; + } + + + /** 通用编辑(后台api版本) + * @param $params + * @param $trans + * @return $this + * @throws \Exception + */ + public function edit($id,$params,$trans=false){ + + $row = $this->get($id); + if (!$row) { + throw new \Exception(__('No Results were found')); + } + + $adminIds = $this->getDataLimitAdminIds(); + if (is_array($adminIds) && !in_array($row[$this->dataLimitField], $adminIds)) { + throw new \Exception(__('You have no permission')); + } + + if (empty($params)) { + throw new \Exception(__('Parameter %s can not be empty', '')); + } +//判断逻辑 + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + + //是否采用模型验证 + if ($this->modelValidate) { + $name = str_replace("\\model\\", "\\validate\\", get_class($this)); + $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate; + $row->validateFailException()->validate($validate); + } + $result = $row->allowField(true)->save($params); + + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage().$e->getFile().$e->getLine()); + } + return $row; + } + + + /** 通用详情(后台api版本) + * @param $params + * @param $trans + * @return $this + * @throws \Exception + */ + public function detail($id,$show_field=[],$except_field=[]){ + $row = $this->get($id); + if (!$row) { + throw new \Exception(__('No Results were found')); + } + if($show_field){ + $row->visible($show_field); + } + if($except_field){ + $row->hidden($except_field); + } + return $row; + } + +// public function index($page,$limit,$where=[]) +// { +// $adminIds = $this->getDataLimitAdminIds(); +// $aliasName = "" ; +// if (is_array($adminIds)) { +// $where[] = [$aliasName . $this->dataLimitField, 'in', $adminIds]; +// } +// +// } + + + /** 通用删除(后台api版本) + * @param $params + * @param $trans + * @return $this + * @throws \Exception + */ + public function del($ids = null,$trans=false){ + if (empty($ids)) { + throw new \Exception(__('Parameter %s can not be empty', 'ids')); + } +//判断逻辑 + + $pk = $this->getPk(); + $adminIds = $this->getDataLimitAdminIds(); + if (is_array($adminIds)) { + $this->where($this->dataLimitField, 'in', $adminIds); + } + $list = $this->where($pk, 'in', $ids)->select(); + $count = 0; + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + + foreach ($list as $item) { + $count += $item->delete(); + } + + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage().$e->getFile().$e->getLine()); + } + return $count; + } + + + } diff --git a/application/common/model/dyqc/ManystoreShop.php b/application/common/model/dyqc/ManystoreShop.php index 08ccf77..c687ce4 100644 --- a/application/common/model/dyqc/ManystoreShop.php +++ b/application/common/model/dyqc/ManystoreShop.php @@ -5,6 +5,7 @@ namespace app\common\model\dyqc; use app\admin\model\Admin; use app\common\library\Virtual; use app\common\model\BaseModel; +use app\common\model\manystore\ShopApply; use app\common\model\school\Area; use app\common\model\school\classes\activity\Activity; use app\common\model\school\classes\ClassesLib; @@ -894,7 +895,7 @@ public static function getAuthInfo($user_id){ $verification = true; //核销权限 $verification_shop_id = 0; //可核销机构 - + $join_number = self::getJoinNumber(); try{ $verification_shop_id = ClassesLib::checkOptionAuth(0,$user_id,"user"); }catch (\Exception $e){ @@ -907,7 +908,7 @@ public static function getAuthInfo($user_id){ if(!$verification_classes_lib_ids && !$verification_shop_id && !$verification_classes_activity_ids){ $verification = false; } - $verification_auth = compact("verification","verification_shop_id","verification_classes_lib_ids","verification_classes_activity_ids"); + $verification_auth = compact("join_number","verification","verification_shop_id","verification_classes_lib_ids","verification_classes_activity_ids"); @@ -926,14 +927,14 @@ public static function getAuthInfo($user_id){ "logo" ]; $apply_info = null; - if(!$user_id)return compact("verification_auth","check_full_msg","check_full","check_field",'auth_status','shop_id','reason','apply_info',"type"); + if(!$user_id)return compact("join_number","verification_auth","check_full_msg","check_full","check_field",'auth_status','shop_id','reason','apply_info',"type"); //得到申请单 $apply_info = self::where("user_id",$user_id)->where("status","1")->find(); if(!$apply_info)$apply_info = self::where("user_id",$user_id)->find(); //不存在说明未申请,直接返回 if(!$apply_info){ - return compact("verification_auth","check_full_msg","check_full","check_field",'auth_status','shop_id','reason','apply_info',"type"); + return compact("join_number","verification_auth","check_full_msg","check_full","check_field",'auth_status','shop_id','reason','apply_info',"type"); } $type = $apply_info['type']; //从申请单取到申请状态 @@ -952,7 +953,17 @@ public static function getAuthInfo($user_id){ $check_full_msg = $self->checkFullMsg($shop_id); $check_full = $self->checkFull($shop_id); - return compact("verification_auth","check_full_msg","check_full","check_field",'auth_status','shop_id','reason','apply_info',"type"); + + return compact("join_number","verification_auth","check_full_msg","check_full","check_field",'auth_status','shop_id','reason','apply_info',"type"); +} + + + +public static function getJoinNumber($real=false) +{ + $number =self::count(); + if($real) return $number; + return $number + (int) config('site.shop_base_apply_num'); } @@ -1085,6 +1096,16 @@ public static function getAuthInfo($user_id){ $manystore = Manystore::where("shop_id" ,$shop_id)->find(); if($user && $manystore){ + //更新申请表单状态 + $shopApply = ShopApply::where("id",$manystore["shop_apply_id"])->find(); + if($shopApply){ + $shopApply->shop_id = $shop_id; + $shopApply->store_id = $manystore["id"]; + $shopApply->save(); + } + + + //授权认证成功 $result = \app\common\model\manystore\UserAuth::auth(0,$shop["id"],$shop["user_id"],"1",'admin',0); //删除用户所有老师和核销员 diff --git a/application/common/model/manystore/ShopApply.php b/application/common/model/manystore/ShopApply.php new file mode 100644 index 0000000..9cbd4b8 --- /dev/null +++ b/application/common/model/manystore/ShopApply.php @@ -0,0 +1,174 @@ + __('Type 1'), '2' => __('Type 2')]; + } + + + public function getTypeTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['type']) ? $data['type'] : ''); + $list = $this->getTypeList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + + public function getCreateTimeTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['create_time']) ? $data['create_time'] : ''); + return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value; + } + + + public function getUpdateTimeTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['update_time']) ? $data['update_time'] : ''); + return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value; + } + + protected function setCreateTimeAttr($value) + { + return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value); + } + + protected function setUpdateTimeAttr($value) + { + return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value); + } + + + public function user() + { + return $this->belongsTo('app\common\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0); + } + + + public function shop() + { + return $this->belongsTo(Shop::class, 'shop_id', 'id', [], 'LEFT')->setEagerlyType(0); + } + + + public function apply($type,$user_id=0,$params,$check=false,$trans=false){ + + if(!in_array($type,['1','2'])) throw new \Exception('类型参数错误'); + + if($check){ + $user = User::get($user_id ?: ($params["user_id"] ?? 0)); + if(!$user)throw new \Exception("用户不存在"); + //已经是机构 + $shop = ManystoreShop::where( 'user_id',$user_id)->find(); + if($shop){ + throw new \Exception("已是机构,请勿重复申请"); + }else{ + //申请认证的时候不能是老师或其他机构的核销员 + $teacher = Teacher::where("user_id" ,$user_id)->find(); + if($teacher) throw new \Exception("您已经是老师,不能申请认证!"); + + $verification = Verification::where("user_id" ,$user_id)->find(); + if($verification) throw new \Exception("您已经是机构核销员,不能申请认证!"); + } + + } + + + switch ($type) { + case '1': //个人 + $rule = [ + 'realname' => 'require', + 'user_id' => 'require', + 'mobile' => 'require', + 'address' => 'require', + ]; + $rule_msg = [ + 'user_id.require' => '请指定提交用户', +// 'name.require' => '机构名称必须填写', + 'realname.require' => '联系人必须填写', + 'mobile.require' => '联系人电话必须是数字', + 'address.require' => '联系地址必须填写', + ]; + break; + case '2': //机构 + + $rule = [ + 'name' => 'require', + 'realname' => 'require', + 'mobile' => 'require', + 'address' => 'require', + 'user_id' => 'require', + ]; + + $rule_msg = [ + 'user_id.require' => '请指定提交用户', + 'name.require' => '机构名称必须填写', + 'realname.require' => '联系人必须填写', + 'mobile.require' => '联系人电话必须是数字', + 'address.require' => '联系地址必须填写', + ]; + + break; + } + self::check($params,$rule,$rule_msg); + + + + +//判断逻辑 + if($trans){ + self::beginTrans(); + } +// $res = false; + try{ + $res = self::create($params); + + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage().$e->getFile().$e->getLine()); + } + return $res; + } +} diff --git a/application/database.php b/application/database.php index bb8fc99..f7b0d00 100644 --- a/application/database.php +++ b/application/database.php @@ -18,11 +18,11 @@ return [ // 服务器地址 'hostname' => Env::get('database.hostname', '127.0.0.1'), // 数据库名 - 'database' => Env::get('database.database', 'duoyangqingchunyexiao'), + 'database' => Env::get('database.database', 'duoyangnew'), // 用户名 - 'username' => Env::get('database.username', 'duoyangqingchun'), + 'username' => Env::get('database.username', 'duoyangnew'), // 密码 - 'password' => Env::get('database.password', 'C8YrFHBDwjaxjYbF'), + 'password' => Env::get('database.password', 'hXJ4FfJhXYsBcXte'), // 端口 'hostport' => Env::get('database.hostport', ''), // 连接dsn diff --git a/public/assets/js/backend/auth/api/adminlog.js b/public/assets/js/backend/auth/api/adminlog.js new file mode 100644 index 0000000..bb2fcf4 --- /dev/null +++ b/public/assets/js/backend/auth/api/adminlog.js @@ -0,0 +1,64 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'auth/api/adminlog/index', + add_url: '', + edit_url: '', + del_url: 'auth/api/adminlog/del', + multi_url: 'auth/api/adminlog/multi', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + fixedColumns: true, + fixedRightNumber: 1, + columns: [ + [ + {field: 'state', checkbox: true,}, + {field: 'id', title: 'ID', operate: false}, + {field: 'admin_id', title: __('Admin_id'), formatter: Table.api.formatter.search, visible: false}, + {field: 'username', title: __('Username'), formatter: Table.api.formatter.search}, + {field: 'title', title: __('Title'), operate: 'LIKE %...%', placeholder: '模糊搜索'}, + {field: 'url', title: __('Url'), formatter: Table.api.formatter.url}, + {field: 'ip', title: __('IP'), events: Table.api.events.ip, formatter: Table.api.formatter.search}, + {field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true}, + { + field: 'operate', title: __('Operate'), table: table, + events: Table.api.events.operate, + buttons: [{ + name: 'detail', + text: __('Detail'), + icon: 'fa fa-list', + classname: 'btn btn-info btn-xs btn-detail btn-dialog', + url: 'auth/api/adminlog/detail' + }], + formatter: Table.api.formatter.operate + } + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + api: { + bindevent: function () { + Form.api.bindevent($("form[role=form]")); + }, + formatter: { + browser: function (value, row, index) { + return '' + row.useragent.split(" ")[0] + ''; + }, + }, + } + }; + return Controller; +}); diff --git a/public/assets/js/backend/auth/api/group.js b/public/assets/js/backend/auth/api/group.js new file mode 100644 index 0000000..fd42d90 --- /dev/null +++ b/public/assets/js/backend/auth/api/group.js @@ -0,0 +1,160 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'jstree'], function ($, undefined, Backend, Table, Form, undefined) { + //读取选中的条目 + $.jstree.core.prototype.get_all_checked = function (full) { + var obj = this.get_selected(), i, j; + for (i = 0, j = obj.length; i < j; i++) { + obj = obj.concat(this.get_node(obj[i]).parents); + } + obj = $.grep(obj, function (v, i, a) { + return v != '#'; + }); + obj = obj.filter(function (itm, i, a) { + return i == a.indexOf(itm); + }); + return full ? $.map(obj, $.proxy(function (i) { + return this.get_node(i); + }, this)) : obj; + }; + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + "index_url": "auth/api/group/index", + "add_url": "auth/api/group/add", + "edit_url": "auth/api/group/edit", + "del_url": "auth/api/group/del", + "multi_url": "auth/api/group/multi", + } + }); + + var table = $("#table"); + + //在表格内容渲染完成后回调的事件 + table.on('post-body.bs.table', function (e, json) { + $("tbody tr[data-index]", this).each(function () { + if (Config.admin.group_ids.indexOf(parseInt(parseInt($("td:eq(1)", this).text()))) > -1) { + $("input[type=checkbox]", this).prop("disabled", true); + } + }); + }); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + columns: [ + [ + {field: 'state', checkbox: true,}, + {field: 'id', title: 'ID'}, + {field: 'pid', title: __('Parent')}, + {field: 'name', title: __('Name'), align: 'left', formatter:function (value, row, index) { + return value.toString().replace(/(&|&)nbsp;/g, ' '); + } + }, + {field: 'status', title: __('Status'), formatter: Table.api.formatter.status}, + { + field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: function (value, row, index) { + if (Config.admin.group_ids.indexOf(parseInt(row.id)) > -1) { + return ''; + } + return Table.api.formatter.operate.call(this, value, row, index); + } + } + ] + ], + pagination: false, + search: false, + commonSearch: false, + }); + + // 为表格绑定事件 + Table.api.bindevent(table);//当内容渲染完成后 + + }, + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + bindevent: function () { + Form.api.bindevent($("form[role=form]"), null, null, function () { + if ($("#treeview").length > 0) { + var r = $("#treeview").jstree("get_all_checked"); + $("input[name='row[rules]']").val(r.join(',')); + } + return true; + }); + //渲染权限节点树 + //变更级别后需要重建节点树 + $(document).on("change", "select[name='row[pid]']", function () { + var pid = $(this).data("pid"); + var id = $(this).data("id"); + if ($(this).val() == id) { + $("option[value='" + pid + "']", this).prop("selected", true).change(); + Backend.api.toastr.error(__('Can not change the parent to self')); + return false; + } + $.ajax({ + url: "auth/api/group/roletree", + type: 'post', + dataType: 'json', + data: {id: id, pid: $(this).val()}, + success: function (ret) { + if (ret.hasOwnProperty("code")) { + var data = ret.hasOwnProperty("data") && ret.data != "" ? ret.data : ""; + if (ret.code === 1) { + //销毁已有的节点树 + $("#treeview").jstree("destroy"); + Controller.api.rendertree(data); + } else { + Backend.api.toastr.error(ret.msg); + } + } + }, error: function (e) { + Backend.api.toastr.error(e.message); + } + }); + }); + //全选和展开 + $(document).on("click", "#checkall", function () { + $("#treeview").jstree($(this).prop("checked") ? "check_all" : "uncheck_all"); + }); + $(document).on("click", "#expandall", function () { + $("#treeview").jstree($(this).prop("checked") ? "open_all" : "close_all"); + }); + $("select[name='row[pid]']").trigger("change"); + }, + rendertree: function (content) { + $("#treeview") + .on('redraw.jstree', function (e) { + $(".layer-footer").attr("domrefresh", Math.random()); + }) + .jstree({ + "themes": {"stripes": true}, + "checkbox": { + "keep_selected_style": false, + }, + "types": { + "root": { + "icon": "fa fa-folder-open", + }, + "menu": { + "icon": "fa fa-folder-open", + }, + "file": { + "icon": "fa fa-file-o", + } + }, + "plugins": ["checkbox", "types"], + "core": { + 'check_callback': true, + "data": content + } + }); + } + } + }; + return Controller; +}); diff --git a/public/assets/js/backend/auth/api/rule.js b/public/assets/js/backend/auth/api/rule.js new file mode 100644 index 0000000..3bd498b --- /dev/null +++ b/public/assets/js/backend/auth/api/rule.js @@ -0,0 +1,221 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function ($, undefined, Backend, Table, Form, Template) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + "index_url": "auth/api/rule/index", + "add_url": "auth/api/rule/add", + "edit_url": "auth/api/rule/edit", + "del_url": "auth/api/rule/del", + "multi_url": "auth/api/rule/multi", + "table": "auth_rule" + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + sortName: '', + escape: false, + columns: [ + [ + {field: 'state', checkbox: true,}, + {field: 'id', title: 'ID'}, + {field: 'title', title: __('Title'), align: 'left', formatter: Controller.api.formatter.title, clickToSelect: !false}, + {field: 'icon', title: __('Icon'), formatter: Controller.api.formatter.icon}, + {field: 'name', title: __('Name'), align: 'left', formatter: Controller.api.formatter.name}, + {field: 'weigh', title: __('Weigh')}, + {field: 'status', title: __('Status'), formatter: Table.api.formatter.status}, + { + field: 'ismenu', + title: __('Ismenu'), + align: 'center', + table: table, + formatter: Table.api.formatter.toggle + }, + { + field: 'operate', + title: __('Operate'), + table: table, + events: Table.api.events.operate, + formatter: Table.api.formatter.operate + } + ] + ], + pagination: false, + search: false, + commonSearch: false, + rowAttributes: function (row, index) { + return row.pid == 0 ? {} : {style: "display:none"}; + } + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + + var btnSuccessEvent = function (data, ret) { + if ($(this).hasClass("btn-change")) { + var index = $(this).data("index"); + var row = Table.api.getrowbyindex(table, index); + row.ismenu = $("i.fa.text-gray", this).length > 0 ? 1 : 0; + table.bootstrapTable("updateRow", {index: index, row: row}); + } else if ($(this).hasClass("btn-delone")) { + if ($(this).closest("tr[data-index]").find("a.btn-node-sub.disabled").length > 0) { + $(this).closest("tr[data-index]").remove(); + } else { + table.bootstrapTable('refresh'); + } + } else if ($(this).hasClass("btn-dragsort")) { + table.bootstrapTable('refresh'); + } + Fast.api.refreshmenu(); + return false; + }; + + //表格内容渲染前 + table.on('pre-body.bs.table', function (e, data) { + var options = table.bootstrapTable("getOptions"); + options.escape = true; + }); + + //当内容渲染完成后 + table.on('post-body.bs.table', function (e, data) { + var options = table.bootstrapTable("getOptions"); + options.escape = false; + + //点击切换/排序/删除操作后刷新左侧菜单 + $(".btn-change[data-id],.btn-delone,.btn-dragsort").data("success", btnSuccessEvent); + + }); + + table.on('post-body.bs.table', function (e, settings, json, xhr) { + //显示隐藏子节点 + $(">tbody>tr[data-index] > td", this).on('click', "a.btn-node-sub", function () { + var status = $(this).data("shown") ? true : false; + $("a[data-pid='" + $(this).data("id") + "']").each(function () { + $(this).closest("tr").toggle(!status); + }); + if (status) { + $("a[data-pid='" + $(this).data("id") + "']").trigger("collapse"); + } + $(this).data("shown", !status); + $("i", this).toggleClass("fa-caret-down").toggleClass("fa-caret-right"); + return false; + }); + }); + + //隐藏子节点 + $(document).on("collapse", ".btn-node-sub", function () { + if ($("i", this).length > 0) { + $("a[data-pid='" + $(this).data("id") + "']").trigger("collapse"); + } + $("i", this).removeClass("fa-caret-down").addClass("fa-caret-right"); + $(this).data("shown", false); + $(this).closest("tr").toggle(false); + }); + + //批量删除后的回调 + $(".toolbar > .btn-del,.toolbar .btn-more~ul>li>a").data("success", function (e) { + Fast.api.refreshmenu(); + }); + + //展开隐藏一级 + $(document.body).on("click", ".btn-toggle", function (e) { + $("a[data-id][data-pid][data-pid!=0].disabled").closest("tr").hide(); + var that = this; + var show = $("i", that).hasClass("fa-chevron-down"); + $("i", that).toggleClass("fa-chevron-down", !show).toggleClass("fa-chevron-up", show); + $("a[data-id][data-pid][data-pid!=0]").not('.disabled').closest("tr").toggle(show); + $(".btn-node-sub[data-pid=0]").data("shown", show); + }); + + //展开隐藏全部 + $(document.body).on("click", ".btn-toggle-all", function (e) { + var that = this; + var show = $("i", that).hasClass("fa-plus"); + $("i", that).toggleClass("fa-plus", !show).toggleClass("fa-minus", show); + $(".btn-node-sub:not([data-pid=0])").closest("tr").toggle(show); + $(".btn-node-sub").data("shown", show); + $(".btn-node-sub > i").toggleClass("fa-caret-down", show).toggleClass("fa-caret-right", !show); + }); + }, + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + formatter: { + title: function (value, row, index) { + value = value.toString().replace(/(&|&)nbsp;/g, ' '); + var caret = row.haschild == 1 || row.ismenu == 1 ? '' : ''; + value = value.indexOf(" ") > -1 ? value.replace(/(.*) /, "$1" + caret) : caret + value; + + value = !row.ismenu || row.status == 'hidden' ? "" + value + "" : value; + return '' + value + ''; + }, + name: function (value, row, index) { + return !row.ismenu || row.status == 'hidden' ? "" + value + "" : value; + }, + icon: function (value, row, index) { + return ''; + } + }, + bindevent: function () { + $(document).on('click', "input[name='row[ismenu]']", function () { + var name = $("input[name='row[name]']"); + var ismenu = $(this).val() == 1; + name.prop("placeholder", ismenu ? name.data("placeholder-menu") : name.data("placeholder-node")); + $('div[data-type="menu"]').toggleClass("hidden", !ismenu); + }); + $("input[name='row[ismenu]']:checked").trigger("click"); + + var iconlist = []; + var iconfunc = function () { + Layer.open({ + type: 1, + area: ['99%', '98%'], //宽高 + content: Template('chooseicontpl', {iconlist: iconlist}) + }); + }; + Form.api.bindevent($("form[role=form]"), function (data) { + Fast.api.refreshmenu(); + }); + $(document).on('change keyup', "#icon", function () { + $(this).prev().find("i").prop("class", $(this).val()); + }); + $(document).on('click', ".btn-search-icon", function () { + if (iconlist.length == 0) { + $.get(Config.site.cdnurl + "/assets/libs/font-awesome/less/variables.less", function (ret) { + var exp = /fa-var-(.*):/ig; + var result; + while ((result = exp.exec(ret)) != null) { + iconlist.push(result[1]); + } + iconfunc(); + }); + } else { + iconfunc(); + } + }); + $(document).on('click', '#chooseicon ul li', function () { + $("input[name='row[icon]']").val('fa fa-' + $(this).data("font")).trigger("change"); + Layer.closeAll(); + }); + $(document).on('keyup', 'input.js-icon-search', function () { + $("#chooseicon ul li").show(); + if ($(this).val() != '') { + $("#chooseicon ul li:not([data-font*='" + $(this).val() + "'])").hide(); + } + }); + } + } + }; + return Controller; +}); diff --git a/public/assets/js/backend/manystore/shop_apply.js b/public/assets/js/backend/manystore/shop_apply.js new file mode 100644 index 0000000..63427ec --- /dev/null +++ b/public/assets/js/backend/manystore/shop_apply.js @@ -0,0 +1,127 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'manystore/shop_apply/index' + location.search, + add_url: 'manystore/shop_apply/add', + edit_url: 'manystore/shop_apply/edit', + del_url: 'manystore/shop_apply/del', + multi_url: 'manystore/shop_apply/multi', + generate_url: 'manystore/shop_apply/generate',//生成机构 + import_url: 'manystore/shop_apply/import', + table: 'manystore_shop_apply', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'id', + fixedColumns: true, + fixedRightNumber: 1, + columns: [ + [ + {checkbox: true}, + {field: 'id', title: __('Id')}, + {field: 'user_id', title: __('User_id')}, + {field: 'type', title: __('Type'), searchList: {"1":__('Type 1'),"2":__('Type 2')}, formatter: Table.api.formatter.normal}, + {field: 'name', title: __('Name'), operate: 'LIKE'}, + {field: 'realname', title: __('Realname'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'mobile', title: __('Mobile'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'address', title: __('Address'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'shop_id', title: __('Shop_id')}, + {field: 'create_time', title: __('Create_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, + {field: 'update_time', title: __('Update_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, + {field: 'user.nickname', title: __('User.nickname'), operate: 'LIKE'}, + {field: 'user.mobile', title: __('User.mobile'), operate: 'LIKE'}, + {field: 'user.avatar', title: __('User.avatar'), operate: 'LIKE', events: Table.api.events.image, formatter: Table.api.formatter.image}, + {field: 'shop.name', title: __('Shop.name'), operate: 'LIKE'}, + {field: 'shop.logo', title: __('Shop.logo'), operate: 'LIKE'}, + // {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + + {field: 'operate', title: __('Operate'), table: table , buttons: [ + { + name: 'edit', + text: __('生成机构'), + title: __('生成机构'), + auth:"edit", + classname: 'btn btn-xs btn-danger btn-magic btn-dialog', + icon: 'fa fa-cube', + // dropdown : '更多', + url: generate_url, + callback: function (data) { + + }, + visible: function (row) { + return !row.shop_id; + } + }, + + + + { + name: 'generate', + text: __('查看机构'), + title: __('查看机构'), + auth:"generate", + classname: 'btn btn-xs btn-danger btn-magic btn-dialog', + icon: 'fa fa-cubes', + // dropdown : '更多', + url: list_url, + callback: function (data) { + + }, + visible: function (row) { + return row.shop_id; + } + }, + + ], events: Table.api.events.operate, formatter: Table.api.formatter.operate}, + + + + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + bindevent: function () { + Form.api.bindevent($("form[role=form]")); + } + } + }; + + + + var generate_url = function (row,dom) { + + return 'manystore/index/add?user_id='+row.user_id + + '&type='+row.type + + '&name=' + (row.name || row.realname) + + '&tel='+row.mobile + + '&shop_apply_id='+row.id + + '&address_detail='+row.address + '&legal_entity='+row.realname; + + }; + + var list_url = function (row,dom) { + return 'manystore/index/index?id='+row.store_id; + }; + + return Controller; +}); diff --git a/public/assets/js/backend/school/classes/classes_lib.js b/public/assets/js/backend/school/classes/classes_lib.js index 850586a..f8df6b9 100644 --- a/public/assets/js/backend/school/classes/classes_lib.js +++ b/public/assets/js/backend/school/classes/classes_lib.js @@ -37,7 +37,7 @@ define(['jquery', 'bootstrap', 'backend', 'csmtable', 'form'], function ($, unde {checkbox: true}, - {field: 'id', title: __('Id')}, + {field: 'id', title: __('Id') ,sortable:true}, {field: 'title', title: __('Title'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, {field: 'headimage', title: __('Headimage'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.image}, {field: 'has_expire', title: __('Has_expire'), searchList: {"1":__('Has_expire 1'),"2":__('Has_expire 2')}, formatter: Table.api.formatter.normal}, diff --git a/public/assets/js/manystore/school/classes/classes_lib.js b/public/assets/js/manystore/school/classes/classes_lib.js index 8da0adc..9c58878 100644 --- a/public/assets/js/manystore/school/classes/classes_lib.js +++ b/public/assets/js/manystore/school/classes/classes_lib.js @@ -36,7 +36,7 @@ define(['jquery', 'bootstrap', 'backend', 'csmtable', 'form'], function ($, unde [ {checkbox: true}, - {field: 'id', title: __('Id')}, + {field: 'id', title: __('Id') ,sortable:true}, {field: 'title', title: __('Title'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, {field: 'headimage', title: __('Headimage'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.image},