分离式后台基类

This commit is contained in:
焦钰锟 2025-04-01 16:31:52 +08:00
parent cf2f68a3e9
commit 856cba0466
66 changed files with 4980 additions and 22 deletions

View File

@ -27,6 +27,7 @@ class Admin extends Backend
protected $selectpageFields = 'id,username,nickname,avatar'; protected $selectpageFields = 'id,username,nickname,avatar';
protected $searchFields = 'id,username,nickname'; protected $searchFields = 'id,username,nickname';
protected $childrenGroupIds = []; protected $childrenGroupIds = [];
protected $childrenApiGroupIds = [];
protected $childrenAdminIds = []; protected $childrenAdminIds = [];
public function _initialize() public function _initialize()
@ -36,6 +37,9 @@ class Admin extends Backend
$this->childrenAdminIds = $this->auth->getChildrenAdminIds($this->auth->isSuperAdmin()); $this->childrenAdminIds = $this->auth->getChildrenAdminIds($this->auth->isSuperAdmin());
$this->childrenGroupIds = $this->auth->getChildrenGroupIds($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(); $groupList = collection(AuthGroup::where('id', 'in', $this->childrenGroupIds)->select())->toArray();
@ -61,6 +65,39 @@ class Admin extends Backend
} }
$this->view->assign('groupdata', $groupdata); $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->assignconfig("admin", ['id' => $this->auth->id]);
$this->getCity(); $this->getCity();
@ -141,6 +178,7 @@ class Admin extends Backend
exception($this->model->getError()); exception($this->model->getError());
} }
$group = $this->request->post("group/a"); $group = $this->request->post("group/a");
$apigroup = $this->request->post("apigroup/a");
//过滤不允许的组别,避免越权 //过滤不允许的组别,避免越权
$group = array_intersect($this->childrenGroupIds, $group); $group = array_intersect($this->childrenGroupIds, $group);
@ -148,11 +186,27 @@ class Admin extends Backend
exception(__('The parent group exceeds permission limit')); exception(__('The parent group exceeds permission limit'));
} }
$apigroup = array_intersect($this->childrenApiGroupIds, $apigroup);
if (!$apigroup) {
exception(__('The parent group exceeds permission limit'));
}
$dataset = []; $dataset = [];
foreach ($group as $value) { foreach ($group as $value) {
$dataset[] = ['uid' => $this->model->id, 'group_id' => $value]; $dataset[] = ['uid' => $this->model->id, 'group_id' => $value];
} }
model('AuthGroupAccess')->saveAll($dataset); 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(); Db::commit();
} catch (\Exception $e) { } catch (\Exception $e) {
Db::rollback(); Db::rollback();
@ -207,8 +261,10 @@ class Admin extends Backend
// 先移除所有权限 // 先移除所有权限
model('AuthGroupAccess')->where('uid', $row->id)->delete(); model('AuthGroupAccess')->where('uid', $row->id)->delete();
\app\admin\model\api\AuthGroupAccess::where('uid', $row->id)->delete();
$group = $this->request->post("group/a"); $group = $this->request->post("group/a");
$apigroup = $this->request->post("apigroup/a");
// 过滤不允许的组别,避免越权 // 过滤不允许的组别,避免越权
$group = array_intersect($this->childrenGroupIds, $group); $group = array_intersect($this->childrenGroupIds, $group);
@ -216,11 +272,25 @@ class Admin extends Backend
exception(__('The parent group exceeds permission limit')); exception(__('The parent group exceeds permission limit'));
} }
$apigroup = array_intersect($this->childrenApiGroupIds, $apigroup);
if (!$apigroup) {
exception(__('The parent group exceeds permission limit'));
}
$dataset = []; $dataset = [];
foreach ($group as $value) { foreach ($group as $value) {
$dataset[] = ['uid' => $row->id, 'group_id' => $value]; $dataset[] = ['uid' => $row->id, 'group_id' => $value];
} }
model('AuthGroupAccess')->saveAll($dataset); 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(); Db::commit();
} catch (\Exception $e) { } catch (\Exception $e) {
Db::rollback(); Db::rollback();
@ -237,6 +307,16 @@ class Admin extends Backend
} }
$this->view->assign("row", $row); $this->view->assign("row", $row);
$this->view->assign("groupids", $groupids); $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(); return $this->view->fetch();
} }

View File

@ -0,0 +1,149 @@
<?php
namespace app\admin\controller\auth\api;
use addons\csmtable\library\xcore\xcore\utils\XcAdminSessionUtils;
use app\admin\model\api\AuthGroup;
use app\common\controller\Backend;
/**
* 管理员日志
*
* @icon fa fa-users
* @remark 管理员可以查看自己所拥有的权限的管理员日志
*/
class Adminlog extends Backend
{
/**
* @var \app\admin\model\api\AdminLog
*/
protected $model = null;
protected $childrenGroupIds = [];
protected $childrenAdminIds = [];
public function _initialize()
{
parent::_initialize();
$this->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();
}
}

View File

@ -0,0 +1,319 @@
<?php
namespace app\admin\controller\auth\api;
use app\admin\model\api\AuthGroup;
use app\admin\model\api\AuthGroupAccess;
use app\admin\model\api\AuthRule;
use app\common\controller\Backend;
use fast\Tree;
use think\Db;
use think\Exception;
/**
* 角色组
*
* @icon fa fa-group
* @remark 角色组可以有多个,角色有上下级层级关系,如果子角色有角色组和管理员的权限则可以派生属于自己组别下级的角色组或管理员
*/
class Group extends Backend
{
/**
* @var \app\admin\model\api\AuthGroup
*/
protected $model = null;
//当前登录管理员所有子组别
protected $childrenGroupIds = [];
//当前组别列表数据
protected $grouplist = [];
protected $groupdata = [];
//无需要权限判断的方法
protected $noNeedRight = ['roletree'];
public function _initialize()
{
parent::_initialize();
$this->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'));
}
}
}

View File

@ -0,0 +1,162 @@
<?php
namespace app\admin\controller\auth\api;
use app\admin\model\api\AuthRule;
use app\admin\validate\ApiAuthRule;
use app\common\controller\Backend;
use fast\Tree;
use think\Cache;
/**
* 规则管理
*
* @icon fa fa-list
* @remark 规则通常对应一个控制器的方法,同时左侧的菜单栏数据也从规则中体现,通常建议通过控制台进行生成规则节点
*/
class Rule extends Backend
{
/**
* @var \app\admin\model\api\AuthRule
*/
protected $model = null;
protected $rulelist = [];
protected $multiFields = 'ismenu,status';
public function _initialize()
{
parent::_initialize();
if (!$this->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 = ['&nbsp;&nbsp;&nbsp;&nbsp;', '&nbsp;&nbsp;&nbsp;&nbsp;', '&nbsp;&nbsp;&nbsp;&nbsp;'];
$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();
}
}

View File

@ -62,7 +62,48 @@ class Index extends Backend
protected $error_auth = false; protected $error_auth = false;
protected $qSwitch = true; 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() 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]); Admin::where(array('admin_shop_id'=>$row['shop_id']))->update(['admin_shop_id'=>0]);
Evaluate::where(array('shop_id'=>$row['shop_id']))->delete(); 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){ if(!$result){
exception('商家信息删除失败'); exception('商家信息删除失败');
} }

View File

@ -0,0 +1,73 @@
<?php
namespace app\admin\controller\manystore;
use app\common\controller\Backend;
/**
* 机构申请
*
* @icon fa fa-circle-o
*/
class ShopApply extends Backend
{
/**
* ShopApply模型对象
* @var \app\admin\model\manystore\ShopApply
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->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();
}
}

View File

@ -0,0 +1,12 @@
<?php
return [
'The parent group can not be its own child' => '父组别不能是自身的子组别',
'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' => '父组别不能是它的子组别及本身',
];

View File

@ -0,0 +1,29 @@
<?php
return [
'Toggle all' => '显示全部',
'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' => '权限标识(菜单需要)',
];

View File

@ -0,0 +1,20 @@
<?php
return [
'User_id' => '申请用户',
'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'
];

View File

@ -279,6 +279,13 @@ class Auth extends \fast\Auth
return parent::getGroups($uid); 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) public function getRuleList($uid = null)
{ {
$uid = is_null($uid) ? $this->id : $uid; $uid = is_null($uid) ? $this->id : $uid;
@ -580,4 +587,73 @@ class Auth extends \fast\Auth
{ {
return $this->_error ? __($this->_error) : ''; 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;
}
} }

View File

@ -20,6 +20,25 @@ class Admin extends Model
'salt' '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() public static function init()
{ {
self::beforeWrite(function ($row) { self::beforeWrite(function ($row) {

View File

@ -0,0 +1,119 @@
<?php
namespace app\admin\model\api;
use app\admin\library\Auth;
use think\Model;
use think\Loader;
class AdminLog extends Model
{
protected $name = 'admin_api_log';
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = '';
//自定义日志标题
protected static $title = '';
//自定义日志内容
protected static $content = '';
//忽略的链接正则列表
protected static $ignoreRegex = [
'/^(.*)\/(selectpage|index)$/i',
];
public static function setTitle($title)
{
self::$title = $title;
}
public static function setContent($content)
{
self::$content = $content;
}
public static function setIgnoreRegex($regex = [])
{
$regex = is_array($regex) ? $regex : [$regex];
self::$ignoreRegex = array_merge(self::$ignoreRegex, $regex);
}
/**
* 记录日志
* @param string $title 日志标题
* @param string $content 日志内容
*/
public static function record($title = '', $content = '')
{
$auth = Auth::instance();
$admin_id = $auth->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);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace app\admin\model\api;
use think\Model;
class AuthGroup extends Model
{
protected $name = 'api_auth_group';
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
public function getNameAttr($value, $data)
{
return __($value);
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace app\admin\model\api;
use think\Model;
class AuthGroupAccess extends Model
{
//
protected $name = 'api_auth_group_access';
}

View File

@ -0,0 +1,63 @@
<?php
namespace app\admin\model\api;
use think\Cache;
use think\Model;
class AuthRule extends Model
{
protected $name = 'api_auth_rule';
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
// 数据自动完成字段
protected $insert = ['py', 'pinyin'];
protected $update = ['py', 'pinyin'];
// 拼音对象
protected static $pinyin = null;
protected static function init()
{
self::$pinyin = new \Overtrue\Pinyin\Pinyin('Overtrue\Pinyin\MemoryFileDictLoader');
self::beforeWrite(function ($row) {
if (isset($_POST['row']) && is_array($_POST['row']) && isset($_POST['row']['condition'])) {
$originRow = $_POST['row'];
$row['condition'] = $originRow['condition'] ?? '';
}
});
self::afterWrite(function ($row) {
Cache::rm('__menu__');
});
}
public function getTitleAttr($value, $data)
{
return __($value);
}
public function getMenutypeList()
{
return ['addtabs' => __('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 '';
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace app\admin\model\manystore;
use think\Model;
class ShopApply extends Model
{
// 表名
protected $name = 'manystore_shop_apply';
// 自动写入时间戳字段
protected $autoWriteTimestamp = false;
// 定义时间戳字段名
protected $createTime = "create_time";
protected $updateTime = "update_time";
protected $deleteTime = false;
// 追加属性
protected $append = [
'type_text',
'create_time_text',
'update_time_text'
];
public function getTypeList()
{
return ['1' => __('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);
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace app\admin\validate;
use think\Validate;
class ApiAuthRule extends Validate
{
/**
* 正则
*/
protected $regex = ['format' => '[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);
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace app\admin\validate\manystore;
use think\Validate;
class ShopApply extends Validate
{
/**
* 验证规则
*/
protected $rule = [
];
/**
* 提示消息
*/
protected $message = [
];
/**
* 验证场景
*/
protected $scene = [
'add' => [],
'edit' => [],
];
}

View File

@ -6,6 +6,15 @@
{:build_select('group[]', $groupdata, null, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])} {:build_select('group[]', $groupdata, null, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])}
</div> </div>
</div> </div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('API权限组')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('apigroup[]', $apigroupdata, null, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])}
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="username" class="control-label col-xs-12 col-sm-2">{:__('Username')}:</label> <label for="username" class="control-label col-xs-12 col-sm-2">{:__('Username')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">

View File

@ -6,6 +6,16 @@
{:build_select('group[]', $groupdata, $groupids, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])} {:build_select('group[]', $groupdata, $groupids, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])}
</div> </div>
</div> </div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('API权限组')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('apigroup[]', $apigroupdata, $apigroupids, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])}
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="username" class="control-label col-xs-12 col-sm-2">{:__('Username')}:</label> <label for="username" class="control-label col-xs-12 col-sm-2">{:__('Username')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">

View File

@ -0,0 +1,27 @@
<style>
.table-adminlog tr td {
word-break: break-all;
}
</style>
<table class="table table-striped table-adminlog">
<thead>
<tr>
<th width="100">{:__('Title')}</th>
<th>{:__('Content')}</th>
</tr>
</thead>
<tbody>
{volist name="row" id="vo" }
<tr>
<td>{:__($key)}</td>
<td>{if $key=='createtime'}{$vo|datetime}{else/}{$vo|htmlentities}{/if}</td>
</tr>
{/volist}
</tbody>
</table>
<div class="hide layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="reset" class="btn btn-primary btn-embossed btn-close" onclick="Layer.closeAll();">{:__('Close')}</button>
</div>
</div>

View File

@ -0,0 +1,21 @@
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar('refresh,delete')}
</div>
<table id="table" class="table table-striped table-bordered table-hover table-nowrap"
data-operate-detail="{:$auth->check('auth/api/adminlog/index')}"
data-operate-del="{:$auth->check('auth/api/adminlog/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,38 @@
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
{:token()}
<input type="hidden" name="row[rules]" value="" />
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $groupdata, null, ['class'=>'form-control selectpicker', 'data-rule'=>'required'])}
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="name" name="row[name]" value="" data-rule="required" />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label>
<div class="col-xs-12 col-sm-8">
<span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><span>{:__('Check all')}</span></label></span>
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><span>{:__('Expand all')}</span></label></span>
<div id="treeview"></div>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
</div>
<div class="form-group hidden layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>

View File

@ -0,0 +1,38 @@
<form id="edit-form" class="form-horizontal form-ajax" role="form" method="POST" action="">
{:token()}
<input type="hidden" name="row[rules]" value="" />
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $groupdata, $row['pid'], ['class'=>'form-control selectpicker', 'data-rule'=>'required', 'data-id'=>$row['id'], 'data-pid'=>$row['pid']])}
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="name" name="row[name]" value="{$row.name|htmlentities}" data-rule="required" />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label>
<div class="col-xs-12 col-sm-8">
<span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><span>{:__('Check all')}</span></label></span>
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><span>{:__('Expand all')}</span></label></span>
<div id="treeview"></div>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
</div>
<div class="form-group hidden layer-footer">
<label class="control-label col-xs-12 col-sm-2 col-xs-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>

View File

@ -0,0 +1,21 @@
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar('refresh,add,delete')}
</div>
<table id="table" class="table table-striped table-bordered table-hover table-nowrap"
data-operate-edit="{:$auth->check('auth/api/group/edit')}"
data-operate-del="{:$auth->check('auth/api/group/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,96 @@
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
{:token()}
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Ismenu')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[ismenu]', ['1'=>__('Yes'), '0'=>__('No')])}
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $ruledata, null, ['class'=>'form-control', 'required'=>''])}
</div>
</div>
<div class="form-group">
<label for="name" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="name" name="row[name]" data-placeholder-node="{:__('Node tips')}" data-placeholder-menu="{:__('Menu tips')}" value="" data-rule="required" />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="title" name="row[title]" value="" data-rule="required" />
</div>
</div>
<div class="form-group" data-type="menu">
<label class="control-label col-xs-12 col-sm-2">{:__('Url')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="url" name="row[url]" value="" data-rule="" placeholder="{:__('Url tips')}" />
</div>
</div>
<div class="form-group" data-type="menu">
<label class="control-label col-xs-12 col-sm-2">{:__('Rule_name')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="rule_name" name="row[rule_name]" value="" data-rule="" placeholder="输入的权限标识(菜单需要)" />
</div>
</div>
<div class="form-group">
<label for="icon" class="control-label col-xs-12 col-sm-2">{:__('Icon')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="input-group input-groupp-md">
<span class="input-group-addon"><i class="fa fa-circle-o" id="icon-style"></i></span>
<input type="text" class="form-control" id="icon" name="row[icon]" value="fa fa-circle-o" />
<a href="javascript:;" class="btn-search-icon input-group-addon">{:__('Search icon')}</a>
</div>
</div>
</div>
<div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Condition')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="condition" name="row[condition]"></textarea>
</div>
</div>
<div class="form-group" data-type="menu">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Menutype')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[menutype]', $menutypeList)}
</div>
</div>
<div class="form-group" data-type="menu">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Extend')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="extend" name="row[extend]"></textarea>
</div>
</div>
<div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Remark')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="remark" name="row[remark]"></textarea>
</div>
</div>
<div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="weigh" name="row[weigh]" value="0" data-rule="required" />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
</div>
<div class="form-group hidden layer-footer">
<div class="col-xs-2"></div>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
{include file="auth/api/rule/tpl" /}

View File

@ -0,0 +1,99 @@
<form id="edit-form" class="form-horizontal form-ajax" role="form" method="POST" action="">
{:token()}
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Ismenu')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[ismenu]', ['1'=>__('Yes'), '0'=>__('No')], $row['ismenu'])}
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $ruledata, $row['pid'], ['class'=>'form-control', 'required'=>''])}
</div>
</div>
<div class="form-group">
<label for="name" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="name" name="row[name]" data-placeholder-node="{:__('Node tips')}" data-placeholder-menu="{:__('Menu tips')}" value="{$row.name|htmlentities}" data-rule="required" />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="title" name="row[title]" value="{$row.title|htmlentities}" data-rule="required" />
</div>
</div>
<div class="form-group" data-type="menu">
<label class="control-label col-xs-12 col-sm-2">{:__('Url')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="url" name="row[url]" value="{$row.url|htmlentities}" data-rule="" placeholder="{:__('Url tips')}" />
</div>
</div>
<div class="form-group" data-type="menu">
<label class="control-label col-xs-12 col-sm-2">{:__('Rule_name')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="rule_name" name="row[rule_name]" value="{$row.rule_name|htmlentities}" data-rule="" placeholder="输入的权限标识(菜单需要)" />
</div>
</div>
<div class="form-group">
<label for="icon" class="control-label col-xs-12 col-sm-2">{:__('Icon')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="input-group input-groupp-md">
<span class="input-group-addon"><i class="{$row.icon|htmlentities}" id="icon-style"></i></span>
<input type="text" class="form-control" id="icon" name="row[icon]" value="{$row.icon|htmlentities}" />
<a href="javascript:;" class="btn-search-icon input-group-addon">{:__('Search icon')}</a>
</div>
</div>
</div>
<div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Condition')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="condition" name="row[condition]">{$row.condition|htmlentities}</textarea>
</div>
</div>
<div class="form-group" data-type="menu">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Menutype')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[menutype]', $menutypeList, $row['menutype'])}
</div>
</div>
<div class="form-group" data-type="menu">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Extend')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="extend" name="row[extend]">{$row.extend|htmlentities}</textarea>
</div>
</div>
<div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Remark')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="remark" name="row[remark]">{$row.remark|__|htmlentities}</textarea>
</div>
</div>
<div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="weigh" name="row[weigh]" value="{$row.weigh|htmlentities}" data-rule="required" />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
</div>
<div class="form-group hidden layer-footer">
<div class="col-xs-2"></div>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
{include file="auth/api/rule/tpl" /}

View File

@ -0,0 +1,35 @@
<style>
.bootstrap-table tr td .text-muted {color:#888;}
</style>
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
<a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" data-force-refresh="false"><i class="fa fa-refresh"></i> </a>
<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('auth/api/rule/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>
<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('auth/api/rule/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
<a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('auth/api/rule/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>
<div class="dropdown btn-group {:$auth->check('auth/api/rule/multi')?'':'hide'}">
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
<ul class="dropdown-menu text-left" role="menu">
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li>
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li>
</ul>
</div>
<a href="javascript:;" class="btn btn-danger btn-toggle-all"><i class="fa fa-plus"></i> {:__('Toggle all')}</a>
</div>
<table id="table" class="table table-bordered table-hover"
data-operate-edit="{:$auth->check('auth/api/rule/edit')}"
data-operate-del="{:$auth->check('auth/api/rule/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,43 @@
<style>
#chooseicon {
margin:10px;
}
#chooseicon ul {
margin:5px 0 0 0;
}
#chooseicon ul li{
width:41px;height:42px;
line-height:42px;
border:1px solid #efefef;
padding:1px;
margin:1px;
text-align: center;
font-size:18px;
}
#chooseicon ul li:hover{
border:1px solid #2c3e50;
cursor:pointer;
}
</style>
<script id="chooseicontpl" type="text/html">
<div id="chooseicon">
<div>
<form onsubmit="return false;">
<div class="input-group input-groupp-md">
<div class="input-group-addon">{:__('Search icon')}</div>
<input class="js-icon-search form-control" type="text" placeholder="">
</div>
</form>
</div>
<div>
<ul class="list-inline">
<% for(var i=0; i<iconlist.length; i++){ %>
<li data-font="<%=iconlist[i]%>" data-toggle="tooltip" title="<%=iconlist[i]%>">
<i class="fa fa-<%=iconlist[i]%>"></i>
</li>
<% } %>
</ul>
</div>
</div>
</script>

View File

@ -353,6 +353,7 @@
<option value="" selected>请选择模块</option> <option value="" selected>请选择模块</option>
<option value="api">API</option> <option value="api">API</option>
<option value="backend">后台</option> <option value="backend">后台</option>
<option value="adminapi">总后台API</option>
<option value="manystoreapi">机构后台API</option> <option value="manystoreapi">机构后台API</option>
<option value="frontend">前台</option> <option value="frontend">前台</option>
</select> </select>

View File

@ -11,6 +11,9 @@
<div class="panel-body"> <div class="panel-body">
<div id="myTabContent" class="tab-content"> <div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="basic"> <div class="tab-pane fade active in" id="basic">
<input type="hidden" name="row[shop_apply_id]" value="{$q_shop_apply_id}" />
<div class="form-group"> <div class="form-group">
<label for="username" class="control-label col-xs-12 col-sm-2">{:__('Username')}:</label> <label for="username" class="control-label col-xs-12 col-sm-2">{:__('Username')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
@ -78,7 +81,7 @@
<select id="c-type" data-rule="required" class="form-control selectpicker" name="shop[type]"> <select id="c-type" data-rule="required" class="form-control selectpicker" name="shop[type]">
{foreach name="typeList" item="vo"} {foreach name="typeList" item="vo"}
<option value="{$key}" {in name="key" value="2"}selected{/in}>{$vo}</option> <option value="{$key}" {in name="key" value="$q_type"}selected{/in}>{$vo}</option>
{/foreach} {/foreach}
</select> </select>
@ -89,7 +92,7 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input id="c-name" data-rule="required" class="form-control" name="shop[name]" type="text" value="" placeholder="请输入{:__('Name')}" > <input id="c-name" data-rule="required" class="form-control" name="shop[name]" type="text" value="{$q_name}" placeholder="请输入{:__('Name')}" >
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -162,7 +165,7 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Address_detail')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Address_detail')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input id="c-address_detail" data-rule="required" class="form-control" name="shop[address_detail]" type="text" value="" placeholder="请输入{:__('Address_detail')}"> <input id="c-address_detail" data-rule="required" class="form-control" name="shop[address_detail]" type="text" value="{$q_address_detail}" placeholder="请输入{:__('Address_detail')}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -213,7 +216,7 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Tel')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Tel')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input id="c-tel" class="form-control" data-rule="required" name="shop[tel]" type="text" value="" placeholder="请输入{:__('Tel')}"> <input id="c-tel" class="form-control" data-rule="required" name="shop[tel]" type="text" value="{$q_tel}" placeholder="请输入{:__('Tel')}">
</div> </div>
</div> </div>
@ -262,7 +265,7 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Legal_entity')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Legal_entity')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input id="c-legal_entity" class="form-control" name="shop[legal_entity]" type="text" value=""> <input id="c-legal_entity" class="form-control" name="shop[legal_entity]" type="text" value="{$q_legal_entity}">
</div> </div>
</div> </div>

View File

@ -0,0 +1,75 @@
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('User_id')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-user_id" data-rule="required" data-source="user/user/index" data-field="mobile" data-format-item="{id} - {nickname} - {mobile}" class="form-control selectpage" name="row[user_id]" type="text" value="0">
<!-- <span style="color: red">-->
<!-- (没找到用户则点击按钮创建用户后重新下拉框选用户)-->
<!-- <a data-url="user/user/changeuser" href="javascript:;" class="btn btn-success btn-changeuser {:$auth->check('user/user/changeuser')?'':'hide'}" title="根据手机号生成用户" ><i class="fa fa-plus"></i> 根据手机号生成用户</a>-->
<!-- </span>-->
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label>
<div class="col-xs-12 col-sm-8">
<select id="c-type" data-rule="required" class="form-control selectpicker" name="row[type]">
{foreach name="typeList" item="vo"}
<option value="{$key}" {in name="key" value="2"}selected{/in}>{$vo}</option>
{/foreach}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-name" data-rule="required" class="form-control" name="row[name]" type="text">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Realname')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-realname" data-rule="required" class="form-control" name="row[realname]" type="text">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Mobile')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-mobile" data-rule="required" class="form-control" name="row[mobile]" type="text">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Address')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-address" class="form-control" name="row[address]" type="text">
</div>
</div>
<!-- <div class="form-group">-->
<!-- <label class="control-label col-xs-12 col-sm-2">{:__('Shop_id')}:</label>-->
<!-- <div class="col-xs-12 col-sm-8">-->
<!-- <input id="c-shop_id" data-rule="required" data-source="manystore/shop/index" class="form-control selectpage" name="row[shop_id]" type="text" value="">-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="form-group">-->
<!-- <label class="control-label col-xs-12 col-sm-2">{:__('Create_time')}:</label>-->
<!-- <div class="col-xs-12 col-sm-8">-->
<!-- <input id="c-create_time" data-rule="required" min="0" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[create_time]" type="text" value="{:date('Y-m-d H:i:s')}">-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="form-group">-->
<!-- <label class="control-label col-xs-12 col-sm-2">{:__('Update_time')}:</label>-->
<!-- <div class="col-xs-12 col-sm-8">-->
<!-- <input id="c-update_time" data-rule="required" min="0" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[update_time]" type="text" value="{:date('Y-m-d H:i:s')}">-->
<!-- </div>-->
<!-- </div>-->
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
</div>
</div>
</form>

View File

@ -0,0 +1,76 @@
<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('User_id')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-user_id" data-rule="required" data-source="user/user/index" data-field="mobile" data-format-item="{id} - {nickname} - {mobile}" class="form-control selectpage" name="row[user_id]" type="text" value="{$row.user_id|htmlentities}">
<!-- <span style="color: red">-->
<!-- (没找到用户则点击按钮创建用户后重新下拉框选用户)-->
<!-- <a data-url="user/user/changeuser" href="javascript:;" class="btn btn-success btn-changeuser {:$auth->check('user/user/changeuser')?'':'hide'}" title="根据手机号生成用户" ><i class="fa fa-plus"></i> 根据手机号生成用户</a>-->
<!-- </span>-->
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Type')}:</label>
<div class="col-xs-12 col-sm-8">
<select id="c-type" data-rule="required" class="form-control selectpicker" name="row[type]">
{foreach name="typeList" item="vo"}
<option value="{$key}" {in name="key" value="$row.type"}selected{/in}>{$vo}</option>
{/foreach}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-name" data-rule="required" class="form-control" name="row[name]" type="text" value="{$row.name|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Realname')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-realname" data-rule="required" class="form-control" name="row[realname]" type="text" value="{$row.realname|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Mobile')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-mobile" data-rule="required" class="form-control" name="row[mobile]" type="text" value="{$row.mobile|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Address')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-address" class="form-control" name="row[address]" type="text" value="{$row.address|htmlentities}">
</div>
</div>
<!-- <div class="form-group">-->
<!-- <label class="control-label col-xs-12 col-sm-2">{:__('Shop_id')}:</label>-->
<!-- <div class="col-xs-12 col-sm-8">-->
<!-- <input id="c-shop_id" data-rule="required" data-source="manystore/shop/index" class="form-control selectpage" name="row[shop_id]" type="text" value="{$row.shop_id|htmlentities}">-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="form-group">-->
<!-- <label class="control-label col-xs-12 col-sm-2">{:__('Create_time')}:</label>-->
<!-- <div class="col-xs-12 col-sm-8">-->
<!-- <input id="c-create_time" data-rule="required" min="0" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[create_time]" type="text" value="{:$row.create_time?datetime($row.create_time):''}">-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="form-group">-->
<!-- <label class="control-label col-xs-12 col-sm-2">{:__('Update_time')}:</label>-->
<!-- <div class="col-xs-12 col-sm-8">-->
<!-- <input id="c-update_time" data-rule="required" min="0" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[update_time]" type="text" value="{:$row.update_time?datetime($row.update_time):''}">-->
<!-- </div>-->
<!-- </div>-->
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
</div>
</div>
</form>

View File

@ -0,0 +1,29 @@
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
<a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a>
<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('manystore/shop_apply/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>
<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('manystore/shop_apply/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
<a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('manystore/shop_apply/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>
</div>
<table id="table" class="table table-striped table-bordered table-hover table-nowrap"
data-operate-edit="{:$auth->check('manystore/shop_apply/edit')}"
data-operate-del="{:$auth->check('manystore/shop_apply/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,14 @@
<?php
namespace app\adminapi\behavior;
class AdminLog
{
public function run(&$response)
{
//只记录POST请求的日志
if (request()->isPost() && config('fastadmin.auto_record_log')) {
\app\adminapi\model\AdminLog::record();
}
}
}

View File

@ -0,0 +1 @@
<?php

View File

@ -0,0 +1,6 @@
<?php
//配置文件
return [
'exception_handle' => '\\app\\api\\library\\ExceptionHandle',
];

View File

@ -0,0 +1,149 @@
<?php
namespace app\adminapi\controller;
use app\adminapi\model\Admin as AdminModel;
use app\adminapi\model\AuthRule;
use app\common\controller\AdminApi;
use think\Cookie;
use think\Hook;
class Admin extends AdminApi
{
protected $model = null;
protected $noNeedLogin = ['login'];
protected $noNeedRight = '*';
/**
* 初始化操作
* @access protected
*/
public function _initialize()
{
$this->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);
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace app\adminapi\controller;
use app\adminapi\model\AuthRule;
use app\common\controller\AdminApi;
use think\Cookie;
use think\Hook;
/**
* api权限菜单管理
*
*
*/
class Rule extends AdminApi
{
protected $model = null;
/**
* 初始化操作
* @access protected
*/
public function _initialize()
{
$this->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);
}
}

View File

@ -0,0 +1,102 @@
<?php
return [
'Keep login' => '保持会话',
'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 秒后自动跳转',
];

View File

@ -0,0 +1,3 @@
<?php
return [];

View File

@ -0,0 +1,7 @@
<?php
return [
'Captcha is incorrect' => '验证码不正确',
'Account is locked' => '账户已经被锁定',
];

View File

@ -0,0 +1,39 @@
<?php
return [
'User center' => '会员中心',
'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' => '重置密码成功',
];

View File

@ -0,0 +1,21 @@
<?php
return [
'Params error' => '参数错误',
'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' => '请假事由',
];

View File

@ -0,0 +1,622 @@
<?php
namespace app\adminapi\library;
use app\admin\model\Admin;
use app\admin\model\api\AuthRule;
use app\adminapi\model\AuthGroup;
use app\adminapi\model\AuthGroupAccess;
use app\common\library\Token;
use app\common\model\User;
use fast\Random;
use fast\Tree;
use think\Config;
use think\Cookie;
use think\Hook;
use think\Request;
use think\Session;
use think\Db;
use think\Exception;
use think\Validate;
class Auth
{
protected static $instance = null;
protected $_error = '';
protected $_logined = false;
protected $_user = null;
protected $_token = '';
//Token默认有效时长
protected $keeptime = 2592000;
protected $requestUri = '';
protected $rules = [];
//默认配置
protected $config = [];
protected $options = [];
protected $breadcrumb = [];
protected $allowFields = ['id', 'username', 'nickname', 'mobile', 'avatar', 'email'];
public function __construct($options = [])
{
if ($config = Config::get('user')) {
$this->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;
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace app\api\library;
use Exception;
use think\exception\Handle;
/**
* 自定义API模块的错误显示
*/
class ExceptionHandle extends Handle
{
public function render(Exception $e)
{
// 在生产环境下返回code信息
if (!\think\Config::get('app_debug')) {
$statuscode = $code = 500;
$msg = 'An error occurred';
// 验证异常
if ($e instanceof \think\exception\ValidateException) {
$code = 0;
$statuscode = 200;
$msg = $e->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);
}
}

View File

@ -0,0 +1,118 @@
<?php
namespace app\adminapi\model;
use app\admin\model\school\SearchCity;
use app\common\model\dyqc\ManystoreShop;
use think\Model;
use think\Session;
class Admin extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $hidden = [
'password',
'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) {
$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 '<div class="alert alert-success-light">
<b >您当前的区域管理权限为:<span style="color: red"> '.$address_citys.' </span>(能管理该区域下的机构信息,如果是*则不限制)</b></div>';
}
}

View File

@ -0,0 +1,119 @@
<?php
namespace app\adminapi\model;
use app\adminapi\library\Auth;
use think\Model;
use think\Loader;
class AdminLog extends Model
{
protected $name = 'admin_api_log';
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = '';
//自定义日志标题
protected static $title = '';
//自定义日志内容
protected static $content = '';
//忽略的链接正则列表
protected static $ignoreRegex = [
'/^(.*)\/(selectpage|index)$/i',
];
public static function setTitle($title)
{
self::$title = $title;
}
public static function setContent($content)
{
self::$content = $content;
}
public static function setIgnoreRegex($regex = [])
{
$regex = is_array($regex) ? $regex : [$regex];
self::$ignoreRegex = array_merge(self::$ignoreRegex, $regex);
}
/**
* 记录日志
* @param string $title 日志标题
* @param string $content 日志内容
*/
public static function record($title = '', $content = '')
{
$auth = Auth::instance();
$admin_id = $auth->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);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace app\adminapi\model;
use think\Model;
class AuthGroup extends Model
{
protected $name = 'api_auth_group';
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
public function getNameAttr($value, $data)
{
return __($value);
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace app\adminapi\model;
use think\Model;
class AuthGroupAccess extends Model
{
//
protected $name = 'api_auth_group_access';
}

View File

@ -0,0 +1,210 @@
<?php
namespace app\adminapi\model;
use app\common\model\BaseModel;
use think\Cache;
use think\Model;
class AuthRule extends BaseModel
{
protected $name = 'api_auth_rule';
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
// 数据自动完成字段
protected $insert = ['py', 'pinyin'];
protected $update = ['py', 'pinyin'];
// 拼音对象
protected static $pinyin = null;
protected static function init()
{
self::$pinyin = new \Overtrue\Pinyin\Pinyin('Overtrue\Pinyin\MemoryFileDictLoader');
self::beforeWrite(function ($row) {
if (isset($_POST['row']) && is_array($_POST['row']) && isset($_POST['row']['condition'])) {
$originRow = $_POST['row'];
$row['condition'] = $originRow['condition'] ?? '';
}
});
self::afterWrite(function ($row) {
Cache::rm('__menu__');
});
}
public function getTitleAttr($value, $data)
{
return __($value);
}
public function getMenutypeList()
{
return ['addtabs' => __('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;
}
}

View File

@ -0,0 +1,18 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// 应用行为扩展定义文件
return [
// 应用结束
'app_end' => [
'app\\adminapi\\behavior\\AdminLog',
],
];

View File

@ -3,6 +3,7 @@
namespace app\api\controller\school; namespace app\api\controller\school;
use app\common\model\dyqc\ManystoreShop; use app\common\model\dyqc\ManystoreShop;
use app\common\model\manystore\ShopApply;
/** /**
* 机构接口 * 机构接口
@ -61,8 +62,8 @@ class Shop extends Base
/** 机构申请 /** 机构申请
* @ApiTitle( 机构申请) * @ApiTitle( 机构申请(废弃))
* @ApiSummary(机构申请) * @ApiSummary(机构申请(废弃))
* @ApiRoute(/api/school/shop/shopapply) * @ApiRoute(/api/school/shop/shopapply)
* @ApiMethod(POST) * @ApiMethod(POST)
* @ApiParams(name = "name", type = "string",required=true,description = "机构名称") * @ApiParams(name = "name", type = "string",required=true,description = "机构名称")
@ -161,8 +162,8 @@ class Shop extends Base
/** 个人申请 /** 个人申请
* @ApiTitle( 个人申请) * @ApiTitle( 个人申请(废弃))
* @ApiSummary(个人申请) * @ApiSummary(个人申请(废弃))
* @ApiRoute(/api/school/shop/userapply) * @ApiRoute(/api/school/shop/userapply)
* @ApiMethod(POST) * @ApiMethod(POST)
* @ApiParams(name = "name", type = "string",required=true,description = "姓名") * @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]);
}
} }

View File

@ -0,0 +1,366 @@
<?php
namespace app\common\controller;
use app\adminapi\library\Auth;
use app\common\library\Virtual;
use think\Config;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Hook;
use think\Lang;
use think\Loader;
use think\Request;
use think\Response;
use think\Route;
use think\Validate;
class AdminApi
{
/**
* @var Request Request 实例
*/
protected $request;
/**
* @var bool 验证失败是否抛出异常
*/
protected $failException = false;
/**
* @var bool 是否批量验证
*/
protected $batchValidate = false;
/**
* @var array 前置操作方法列表
*/
protected $beforeActionList = [];
/**
* 无需登录的方法,同时也就不需要鉴权了
* @var array
*/
protected $noNeedLogin = [];
/**
* 无需鉴权的方法,但需要登录
* @var array
*/
protected $noNeedRight = [];
/**
* 权限Auth
* @var Auth
*/
protected $auth = null;
/**
* 默认响应输出类型,支持json/xml
* @var string
*/
protected $responseType = 'json';
/**
* 构造方法
* @access public
* @param Request $request Request 对象
*/
public function __construct(Request $request = null)
{
$this->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();
}
}

View File

@ -208,7 +208,7 @@ class Backend extends Controller
$q_fields = []; $q_fields = [];
foreach ($get as $kay=>$getField) { foreach ($get as $kay=>$getField) {
if (in_array($kay, $fieldLists)) { if (in_array($kay, $fieldLists) || in_array($kay, $this->qFields)) {
$q_fields[$kay] = $getField; $q_fields[$kay] = $getField;
} }
} }

View File

@ -175,7 +175,7 @@ class ManystoreBase extends Controller
$q_fields = []; $q_fields = [];
foreach ($get as $kay=>$getField) { foreach ($get as $kay=>$getField) {
if (in_array($kay, $fieldLists)) { if (in_array($kay, $fieldLists) || in_array($kay, $this->qFields)) {
$q_fields[$kay] = $getField; $q_fields[$kay] = $getField;
} }
} }

View File

@ -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 = []){ public function checkAssemblyParameters($get=[],$exclude = []){
//得到所有get参数 //得到所有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;
}
} }

View File

@ -5,6 +5,7 @@ namespace app\common\model\dyqc;
use app\admin\model\Admin; use app\admin\model\Admin;
use app\common\library\Virtual; use app\common\library\Virtual;
use app\common\model\BaseModel; use app\common\model\BaseModel;
use app\common\model\manystore\ShopApply;
use app\common\model\school\Area; use app\common\model\school\Area;
use app\common\model\school\classes\activity\Activity; use app\common\model\school\classes\activity\Activity;
use app\common\model\school\classes\ClassesLib; use app\common\model\school\classes\ClassesLib;
@ -894,7 +895,7 @@ public static function getAuthInfo($user_id){
$verification = true; //核销权限 $verification = true; //核销权限
$verification_shop_id = 0; //可核销机构 $verification_shop_id = 0; //可核销机构
$join_number = self::getJoinNumber();
try{ try{
$verification_shop_id = ClassesLib::checkOptionAuth(0,$user_id,"user"); $verification_shop_id = ClassesLib::checkOptionAuth(0,$user_id,"user");
}catch (\Exception $e){ }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){ if(!$verification_classes_lib_ids && !$verification_shop_id && !$verification_classes_activity_ids){
$verification = false; $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" "logo"
]; ];
$apply_info = null; $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(); $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)$apply_info = self::where("user_id",$user_id)->find();
//不存在说明未申请,直接返回 //不存在说明未申请,直接返回
if(!$apply_info){ 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']; $type = $apply_info['type'];
//从申请单取到申请状态 //从申请单取到申请状态
@ -952,7 +953,17 @@ public static function getAuthInfo($user_id){
$check_full_msg = $self->checkFullMsg($shop_id); $check_full_msg = $self->checkFullMsg($shop_id);
$check_full = $self->checkFull($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(); $manystore = Manystore::where("shop_id" ,$shop_id)->find();
if($user && $manystore){ 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); $result = \app\common\model\manystore\UserAuth::auth(0,$shop["id"],$shop["user_id"],"1",'admin',0);
//删除用户所有老师和核销员 //删除用户所有老师和核销员

View File

@ -0,0 +1,174 @@
<?php
namespace app\common\model\manystore;
use app\common\model\BaseModel;
use app\common\model\dyqc\ManystoreShop;
use app\common\model\school\classes\Teacher;
use app\common\model\school\classes\Verification;
use app\common\model\User;
use think\Model;
class ShopApply extends BaseModel
{
// 表名
protected $name = 'manystore_shop_apply';
// 自动写入时间戳字段
protected $autoWriteTimestamp = false;
// 定义时间戳字段名
protected $createTime = "create_time";
protected $updateTime = "update_time";
protected $deleteTime = false;
// 追加属性
protected $append = [
'type_text',
'create_time_text',
'update_time_text'
];
public function getTypeList()
{
return ['1' => __('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;
}
}

View File

@ -18,11 +18,11 @@ return [
// 服务器地址 // 服务器地址
'hostname' => Env::get('database.hostname', '127.0.0.1'), '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', ''), 'hostport' => Env::get('database.hostport', ''),
// 连接dsn // 连接dsn

View File

@ -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 '<a class="btn btn-xs btn-browser">' + row.useragent.split(" ")[0] + '</a>';
},
},
}
};
return Controller;
});

View File

@ -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(/(&|&amp;)nbsp;/g, '&nbsp;');
}
},
{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;
});

View File

@ -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(/(&|&amp;)nbsp;/g, '&nbsp;');
var caret = row.haschild == 1 || row.ismenu == 1 ? '<i class="fa fa-caret-right"></i>' : '';
value = value.indexOf("&nbsp;") > -1 ? value.replace(/(.*)&nbsp;/, "$1" + caret) : caret + value;
value = !row.ismenu || row.status == 'hidden' ? "<span class='text-muted'>" + value + "</span>" : value;
return '<a href="javascript:;" data-id="' + row.id + '" data-pid="' + row.pid + '" class="'
+ (row.haschild == 1 || row.ismenu == 1 ? 'text-primary' : 'disabled') + ' btn-node-sub">' + value + '</a>';
},
name: function (value, row, index) {
return !row.ismenu || row.status == 'hidden' ? "<span class='text-muted'>" + value + "</span>" : value;
},
icon: function (value, row, index) {
return '<span class="' + (!row.ismenu || row.status == 'hidden' ? 'text-muted' : '') + '"><i class="' + value + '"></i></span>';
}
},
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;
});

View File

@ -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;
});

View File

@ -37,7 +37,7 @@ define(['jquery', 'bootstrap', 'backend', 'csmtable', 'form'], function ($, unde
{checkbox: true}, {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: '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: '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}, {field: 'has_expire', title: __('Has_expire'), searchList: {"1":__('Has_expire 1'),"2":__('Has_expire 2')}, formatter: Table.api.formatter.normal},

View File

@ -36,7 +36,7 @@ define(['jquery', 'bootstrap', 'backend', 'csmtable', 'form'], function ($, unde
[ [
{checkbox: true}, {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: '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: 'headimage', title: __('Headimage'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.image},