@@ -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 '';
+ },
+ 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},