This commit is contained in:
yyh931018@qq.com
2022-09-08 15:32:32 +08:00
commit 1b0c8f4196
4714 changed files with 974427 additions and 0 deletions

View File

@@ -0,0 +1,453 @@
<?php
namespace app\admin\controller;
use app\common\controller\Backend;
use fast\Http;
use think\addons\AddonException;
use think\addons\Service;
use think\Cache;
use think\Config;
use think\Db;
use think\Exception;
/**
* 插件管理
*
* @icon fa fa-cube
* @remark 可在线安装、卸载、禁用、启用、配置、升级插件,插件升级前请做好备份。
*/
class Addon extends Backend
{
protected $model = null;
protected $noNeedRight = ['get_table_list'];
public function _initialize()
{
parent::_initialize();
if (!$this->auth->isSuperAdmin() && in_array($this->request->action(), ['install', 'uninstall', 'local', 'upgrade', 'authorization', 'testdata'])) {
$this->error(__('Access is allowed only to the super management group'));
}
}
/**
* 插件列表
*/
public function index()
{
$addons = get_addon_list();
foreach ($addons as $k => &$v) {
$config = get_addon_config($v['name']);
$v['config'] = $config ? 1 : 0;
$v['url'] = str_replace($this->request->server('SCRIPT_NAME'), '', $v['url']);
}
$this->assignconfig(['addons' => $addons, 'api_url' => config('fastadmin.api_url'), 'faversion' => config('fastadmin.version'), 'domain' => request()->host(true)]);
return $this->view->fetch();
}
/**
* 配置
*/
public function config($name = null)
{
$name = $name ? $name : $this->request->get("name");
if (!$name) {
$this->error(__('Parameter %s can not be empty', 'name'));
}
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
$this->error(__('Addon name incorrect'));
}
$info = get_addon_info($name);
$config = get_addon_fullconfig($name);
if (!$info) {
$this->error(__('Addon not exists'));
}
if ($this->request->isPost()) {
$params = $this->request->post("row/a", [], 'trim');
if ($params) {
foreach ($config as $k => &$v) {
if (isset($params[$v['name']])) {
if ($v['type'] == 'array') {
$params[$v['name']] = is_array($params[$v['name']]) ? $params[$v['name']] : (array)json_decode($params[$v['name']], true);
$value = $params[$v['name']];
} else {
$value = is_array($params[$v['name']]) ? implode(',', $params[$v['name']]) : $params[$v['name']];
}
$v['value'] = $value;
}
}
try {
$addon = get_addon_instance($name);
//插件自定义配置实现逻辑
if (method_exists($addon, 'config')) {
$addon->config($name, $config);
} else {
//更新配置文件
set_addon_fullconfig($name, $config);
Service::refresh();
}
} catch (Exception $e) {
$this->error(__($e->getMessage()));
}
$this->success();
}
$this->error(__('Parameter %s can not be empty', ''));
}
$tips = [];
$groupList = [];
foreach ($config as $index => &$item) {
//如果有设置分组
if (isset($item['group']) && $item['group']) {
if (!in_array($item['group'], $groupList)) {
$groupList["custom" . (count($groupList) + 1)] = $item['group'];
}
}
if ($item['name'] == '__tips__') {
$tips = $item;
unset($config[$index]);
}
}
$groupList['other'] = '其它';
$this->view->assign("groupList", $groupList);
$this->view->assign("addon", ['info' => $info, 'config' => $config, 'tips' => $tips]);
$configFile = ADDON_PATH . $name . DS . 'config.html';
$viewFile = is_file($configFile) ? $configFile : '';
return $this->view->fetch($viewFile);
}
/**
* 安装
*/
public function install()
{
$name = $this->request->post("name");
$force = (int)$this->request->post("force");
if (!$name) {
$this->error(__('Parameter %s can not be empty', 'name'));
}
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
$this->error(__('Addon name incorrect'));
}
$info = [];
try {
$uid = $this->request->post("uid");
$token = $this->request->post("token");
$version = $this->request->post("version");
$faversion = $this->request->post("faversion");
$extend = [
'uid' => $uid,
'token' => $token,
'version' => $version,
'faversion' => $faversion
];
$info = Service::install($name, $force, $extend);
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) {
$this->error(__($e->getMessage()), $e->getCode());
}
$this->success(__('Install successful'), '', ['addon' => $info]);
}
/**
* 卸载
*/
public function uninstall()
{
$name = $this->request->post("name");
$force = (int)$this->request->post("force");
$droptables = (int)$this->request->post("droptables");
if (!$name) {
$this->error(__('Parameter %s can not be empty', 'name'));
}
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
$this->error(__('Addon name incorrect'));
}
//只有开启调试且为超级管理员才允许删除相关数据库
$tables = [];
if ($droptables && Config::get("app_debug") && $this->auth->isSuperAdmin()) {
$tables = get_addon_tables($name);
}
try {
Service::uninstall($name, $force);
if ($tables) {
$prefix = Config::get('database.prefix');
//删除插件关联表
foreach ($tables as $index => $table) {
//忽略非插件标识的表名
if (!preg_match("/^{$prefix}{$name}/", $table)) {
continue;
}
Db::execute("DROP TABLE IF EXISTS `{$table}`");
}
}
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) {
$this->error(__($e->getMessage()));
}
$this->success(__('Uninstall successful'));
}
/**
* 禁用启用
*/
public function state()
{
$name = $this->request->post("name");
$action = $this->request->post("action");
$force = (int)$this->request->post("force");
if (!$name) {
$this->error(__('Parameter %s can not be empty', 'name'));
}
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
$this->error(__('Addon name incorrect'));
}
try {
$action = $action == 'enable' ? $action : 'disable';
//调用启用、禁用的方法
Service::$action($name, $force);
Cache::rm('__menu__');
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) {
$this->error(__($e->getMessage()));
}
$this->success(__('Operate successful'));
}
/**
* 本地上传
*/
public function local()
{
Config::set('default_return_type', 'json');
$info = [];
$file = $this->request->file('file');
try {
$uid = $this->request->post("uid");
$token = $this->request->post("token");
$faversion = $this->request->post("faversion");
if (!$uid || !$token) {
throw new Exception(__('Please login and try to install'));
}
$extend = [
'uid' => $uid,
'token' => $token,
'faversion' => $faversion
];
$info = Service::local($file, $extend);
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) {
$this->error(__($e->getMessage()));
}
$this->success(__('Offline installed tips'), '', ['addon' => $info]);
}
/**
* 更新插件
*/
public function upgrade()
{
$name = $this->request->post("name");
$addonTmpDir = RUNTIME_PATH . 'addons' . DS;
if (!$name) {
$this->error(__('Parameter %s can not be empty', 'name'));
}
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
$this->error(__('Addon name incorrect'));
}
if (!is_dir($addonTmpDir)) {
@mkdir($addonTmpDir, 0755, true);
}
$info = [];
try {
$uid = $this->request->post("uid");
$token = $this->request->post("token");
$version = $this->request->post("version");
$faversion = $this->request->post("faversion");
$extend = [
'uid' => $uid,
'token' => $token,
'version' => $version,
'faversion' => $faversion
];
//调用更新的方法
$info = Service::upgrade($name, $extend);
Cache::rm('__menu__');
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) {
$this->error(__($e->getMessage()));
}
$this->success(__('Operate successful'), '', ['addon' => $info]);
}
/**
* 测试数据
*/
public function testdata()
{
$name = $this->request->post("name");
if (!$name) {
$this->error(__('Parameter %s can not be empty', 'name'));
}
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
$this->error(__('Addon name incorrect'));
}
try {
Service::importsql($name, 'testdata.sql');
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) {
$this->error(__($e->getMessage()), $e->getCode());
}
$this->success(__('Import successful'), '');
}
/**
* 已装插件
*/
public function downloaded()
{
$offset = (int)$this->request->get("offset");
$limit = (int)$this->request->get("limit");
$filter = $this->request->get("filter");
$search = $this->request->get("search");
$search = htmlspecialchars(strip_tags($search));
$onlineaddons = $this->getAddonList();
$filter = (array)json_decode($filter, true);
$addons = get_addon_list();
$list = [];
foreach ($addons as $k => $v) {
if ($search && stripos($v['name'], $search) === false && stripos($v['title'], $search) === false && stripos($v['intro'], $search) === false) {
continue;
}
if (isset($onlineaddons[$v['name']])) {
$v = array_merge($v, $onlineaddons[$v['name']]);
$v['price'] = '-';
} else {
$v['category_id'] = 0;
$v['flag'] = '';
$v['banner'] = '';
$v['image'] = '';
$v['donateimage'] = '';
$v['demourl'] = '';
$v['price'] = __('None');
$v['screenshots'] = [];
$v['releaselist'] = [];
$v['url'] = addon_url($v['name']);
$v['url'] = str_replace($this->request->server('SCRIPT_NAME'), '', $v['url']);
}
$v['createtime'] = filemtime(ADDON_PATH . $v['name']);
if ($filter && isset($filter['category_id']) && is_numeric($filter['category_id']) && $filter['category_id'] != $v['category_id']) {
continue;
}
$list[] = $v;
}
$total = count($list);
if ($limit) {
$list = array_slice($list, $offset, $limit);
}
$result = array("total" => $total, "rows" => $list);
$callback = $this->request->get('callback') ? "jsonp" : "json";
return $callback($result);
}
/**
* 检测
*/
public function isbuy()
{
$name = $this->request->post("name");
$uid = $this->request->post("uid");
$token = $this->request->post("token");
$version = $this->request->post("version");
$faversion = $this->request->post("faversion");
$extend = [
'uid' => $uid,
'token' => $token,
'version' => $version,
'faversion' => $faversion
];
try {
$result = Service::isBuy($name, $extend);
} catch (Exception $e) {
$this->error(__($e->getMessage()));
}
return json($result);
}
/**
* 刷新授权
*/
public function authorization()
{
$params = [
'uid' => $this->request->post('uid'),
'token' => $this->request->post('token'),
'faversion' => $this->request->post('faversion'),
];
try {
Service::authorization($params);
} catch (Exception $e) {
$this->error(__($e->getMessage()));
}
$this->success(__('Operate successful'));
}
/**
* 获取插件相关表
*/
public function get_table_list()
{
$name = $this->request->post("name");
if (!preg_match("/^[a-zA-Z0-9]+$/", $name)) {
$this->error(__('Addon name incorrect'));
}
$tables = get_addon_tables($name);
$prefix = Config::get('database.prefix');
foreach ($tables as $index => $table) {
//忽略非插件标识的表名
if (!preg_match("/^{$prefix}{$name}/", $table)) {
unset($tables[$index]);
}
}
$tables = array_values($tables);
$this->success('', null, ['tables' => $tables]);
}
protected function getAddonList()
{
$onlineaddons = Cache::get("onlineaddons");
if (!is_array($onlineaddons) && config('fastadmin.api_url')) {
$onlineaddons = [];
$params = [
'uid' => $this->request->post('uid'),
'token' => $this->request->post('token'),
'version' => config('fastadmin.version'),
'faversion' => config('fastadmin.version'),
];
$json = [];
try {
$json = Service::addons($params);
} catch (\Exception $e) {
}
$rows = isset($json['rows']) ? $json['rows'] : [];
foreach ($rows as $index => $row) {
$onlineaddons[$row['name']] = $row;
}
Cache::set("onlineaddons", $onlineaddons, 600);
}
return $onlineaddons;
}
}

View File

@@ -0,0 +1,313 @@
<?php
namespace app\admin\controller;
use app\common\controller\Backend;
use app\common\exception\UploadException;
use app\common\library\Upload;
use fast\Random;
use think\addons\Service;
use think\Cache;
use think\Config;
use think\Db;
use think\Lang;
use think\Response;
use think\Validate;
/**
* Ajax异步请求接口
* @internal
*/
class Ajax extends Backend
{
protected $noNeedLogin = ['lang'];
protected $noNeedRight = ['*'];
protected $layout = '';
public function _initialize()
{
parent::_initialize();
//设置过滤方法
$this->request->filter(['trim', 'strip_tags', 'htmlspecialchars']);
}
/**
* 加载语言包
*/
public function lang()
{
$header = ['Content-Type' => 'application/javascript'];
if (!config('app_debug')) {
$offset = 30 * 60 * 60 * 24; // 缓存一个月
$header['Cache-Control'] = 'public';
$header['Pragma'] = 'cache';
$header['Expires'] = gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
}
$controllername = input("controllername");
//默认只加载了控制器对应的语言名,你还根据控制器名来加载额外的语言包
$this->loadlang($controllername);
return jsonp(Lang::get(), 200, $header, ['json_encode_param' => JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE]);
}
/**
* 上传文件
*/
public function upload()
{
Config::set('default_return_type', 'json');
//必须设定cdnurl为空,否则cdnurl函数计算错误
Config::set('upload.cdnurl', '');
$chunkid = $this->request->post("chunkid");
if ($chunkid) {
if (!Config::get('upload.chunking')) {
$this->error(__('Chunk file disabled'));
}
$action = $this->request->post("action");
$chunkindex = $this->request->post("chunkindex/d");
$chunkcount = $this->request->post("chunkcount/d");
$filename = $this->request->post("filename");
$method = $this->request->method(true);
if ($action == 'merge') {
$attachment = null;
//合并分片文件
try {
$upload = new Upload();
$attachment = $upload->merge($chunkid, $chunkcount, $filename);
} catch (UploadException $e) {
$this->error($e->getMessage());
}
$this->success(__('Uploaded successful'), '', ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
} elseif ($method == 'clean') {
//删除冗余的分片文件
try {
$upload = new Upload();
$upload->clean($chunkid);
} catch (UploadException $e) {
$this->error($e->getMessage());
}
$this->success();
} else {
//上传分片文件
//默认普通上传文件
$file = $this->request->file('file');
try {
$upload = new Upload($file);
$upload->chunk($chunkid, $chunkindex, $chunkcount);
} catch (UploadException $e) {
$this->error($e->getMessage());
}
$this->success();
}
} else {
$attachment = null;
//默认普通上传文件
$file = $this->request->file('file');
try {
$upload = new Upload($file);
$attachment = $upload->upload();
} catch (UploadException $e) {
$this->error($e->getMessage());
}
$this->success(__('Uploaded successful'), '', ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
}
}
/**
* 通用排序
*/
public function weigh()
{
//排序的数组
$ids = $this->request->post("ids");
//拖动的记录ID
$changeid = $this->request->post("changeid");
//操作字段
$field = $this->request->post("field");
//操作的数据表
$table = $this->request->post("table");
if (!Validate::is($table, "alphaDash")) {
$this->error();
}
//主键
$pk = $this->request->post("pk");
//排序的方式
$orderway = strtolower($this->request->post("orderway", ""));
$orderway = $orderway == 'asc' ? 'ASC' : 'DESC';
$sour = $weighdata = [];
$ids = explode(',', $ids);
$prikey = $pk && preg_match("/^[a-z0-9\-_]+$/i", $pk) ? $pk : (Db::name($table)->getPk() ?: 'id');
$pid = $this->request->post("pid", "");
//限制更新的字段
$field = in_array($field, ['weigh']) ? $field : 'weigh';
// 如果设定了pid的值,此时只匹配满足条件的ID,其它忽略
if ($pid !== '') {
$hasids = [];
$list = Db::name($table)->where($prikey, 'in', $ids)->where('pid', 'in', $pid)->field("{$prikey},pid")->select();
foreach ($list as $k => $v) {
$hasids[] = $v[$prikey];
}
$ids = array_values(array_intersect($ids, $hasids));
}
$list = Db::name($table)->field("$prikey,$field")->where($prikey, 'in', $ids)->order($field, $orderway)->select();
foreach ($list as $k => $v) {
$sour[] = $v[$prikey];
$weighdata[$v[$prikey]] = $v[$field];
}
$position = array_search($changeid, $ids);
$desc_id = isset($sour[$position]) ? $sour[$position] : end($sour); //移动到目标的ID值,取出所处改变前位置的值
$sour_id = $changeid;
$weighids = array();
$temp = array_values(array_diff_assoc($ids, $sour));
foreach ($temp as $m => $n) {
if ($n == $sour_id) {
$offset = $desc_id;
} else {
if ($sour_id == $temp[0]) {
$offset = isset($temp[$m + 1]) ? $temp[$m + 1] : $sour_id;
} else {
$offset = isset($temp[$m - 1]) ? $temp[$m - 1] : $sour_id;
}
}
if (!isset($weighdata[$offset])) {
continue;
}
$weighids[$n] = $weighdata[$offset];
Db::name($table)->where($prikey, $n)->update([$field => $weighdata[$offset]]);
}
$this->success();
}
/**
* 清空系统缓存
*/
public function wipecache()
{
try {
$type = $this->request->request("type");
switch ($type) {
case 'all':
// no break
case 'content':
//内容缓存
rmdirs(CACHE_PATH, false);
Cache::clear();
if ($type == 'content') {
break;
}
case 'template':
// 模板缓存
rmdirs(TEMP_PATH, false);
if ($type == 'template') {
break;
}
case 'addons':
// 插件缓存
Service::refresh();
if ($type == 'addons') {
break;
}
case 'browser':
// 浏览器缓存
// 只有生产环境下才修改
if (!config('app_debug')) {
$version = config('site.version');
$newversion = preg_replace_callback("/(.*)\.([0-9]+)\$/", function ($match) {
return $match[1] . '.' . ($match[2] + 1);
}, $version);
if ($newversion && $newversion != $version) {
Db::startTrans();
try {
\app\common\model\Config::where('name', 'version')->update(['value' => $newversion]);
\app\common\model\Config::refreshFile();
Db::commit();
} catch (\Exception $e) {
Db::rollback();
exception($e->getMessage());
}
}
}
if ($type == 'browser') {
break;
}
}
} catch (\Exception $e) {
$this->error($e->getMessage());
}
\think\Hook::listen("wipecache_after");
$this->success();
}
/**
* 读取分类数据,联动列表
*/
public function category()
{
$type = $this->request->get('type', '');
$pid = $this->request->get('pid', '');
$where = ['status' => 'normal'];
$categorylist = null;
if ($pid || $pid === '0') {
$where['pid'] = $pid;
}
if ($type) {
$where['type'] = $type;
}
$categorylist = Db::name('category')->where($where)->field('id as value,name')->order('weigh desc,id desc')->select();
$this->success('', '', $categorylist);
}
/**
* 读取省市区数据,联动列表
*/
public function area()
{
$params = $this->request->get("row/a");
if (!empty($params)) {
$province = isset($params['province']) ? $params['province'] : '';
$city = isset($params['city']) ? $params['city'] : '';
} else {
$province = $this->request->get('province', '');
$city = $this->request->get('city', '');
}
$where = ['pid' => 0, 'level' => 1];
$provincelist = null;
if ($province !== '') {
$where['pid'] = $province;
$where['level'] = 2;
if ($city !== '') {
$where['pid'] = $city;
$where['level'] = 3;
}
}
$provincelist = Db::name('area')->where($where)->field('id as value,name')->select();
$this->success('', '', $provincelist);
}
/**
* 生成后缀图标
*/
public function icon()
{
$suffix = $this->request->request("suffix");
$suffix = $suffix ? $suffix : "FILE";
$data = build_suffix_image($suffix);
$header = ['Content-Type' => 'image/svg+xml'];
$offset = 30 * 60 * 60 * 24; // 缓存一个月
$header['Cache-Control'] = 'public';
$header['Pragma'] = 'cache';
$header['Expires'] = gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
$response = Response::create($data, '', 200, $header);
return $response;
}
}

View File

@@ -0,0 +1,158 @@
<?php
namespace app\admin\controller;
use app\common\controller\Backend;
use app\common\model\Category as CategoryModel;
use fast\Tree;
/**
* 分类管理
*
* @icon fa fa-list
* @remark 用于管理网站的所有分类,分类可进行无限级分类,分类类型请在常规管理->系统配置->字典配置中添加
*/
class Category extends Backend
{
/**
* @var \app\common\model\Category
*/
protected $model = null;
protected $categorylist = [];
protected $noNeedRight = ['selectpage'];
public function _initialize()
{
parent::_initialize();
$this->model = model('app\common\model\Category');
$tree = Tree::instance();
$tree->init(collection($this->model->order('weigh desc,id desc')->select())->toArray(), 'pid');
$this->categorylist = $tree->getTreeList($tree->getTreeArray(0), 'name');
$categorydata = [0 => ['type' => 'all', 'name' => __('None')]];
foreach ($this->categorylist as $k => $v) {
$categorydata[$v['id']] = $v;
}
$typeList = CategoryModel::getTypeList();
$this->view->assign("flagList", $this->model->getFlagList());
$this->view->assign("typeList", $typeList);
$this->view->assign("parentList", $categorydata);
$this->assignconfig('typeList', $typeList);
}
/**
* 查看
*/
public function index()
{
//设置过滤方法
$this->request->filter(['strip_tags']);
if ($this->request->isAjax()) {
$search = $this->request->request("search");
$type = $this->request->request("type");
//构造父类select列表选项数据
$list = [];
foreach ($this->categorylist as $k => $v) {
if ($search) {
if ($v['type'] == $type && stripos($v['name'], $search) !== false || stripos($v['nickname'], $search) !== false) {
if ($type == "all" || $type == null) {
$list = $this->categorylist;
} else {
$list[] = $v;
}
}
} else {
if ($type == "all" || $type == null) {
$list = $this->categorylist;
} elseif ($v['type'] == $type) {
$list[] = $v;
}
}
}
$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();
}
return parent::add();
}
/**
* 编辑
*/
public function edit($ids = null)
{
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) {
if (!in_array($row[$this->dataLimitField], $adminIds)) {
$this->error(__('You have no permission'));
}
}
if ($this->request->isPost()) {
$this->token();
$params = $this->request->post("row/a");
if ($params) {
$params = $this->preExcludeFields($params);
if ($params['pid'] != $row['pid']) {
$childrenIds = Tree::instance()->init(collection(\app\common\model\Category::select())->toArray())->getChildrenIds($row['id'], true);
if (in_array($params['pid'], $childrenIds)) {
$this->error(__('Can not change the parent to child or itself'));
}
}
try {
//是否采用模型验证
if ($this->modelValidate) {
$name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
$validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate;
$row->validate($validate);
}
$result = $row->allowField(true)->save($params);
if ($result !== false) {
$this->success();
} else {
$this->error($row->getError());
}
} catch (\think\exception\PDOException $e) {
$this->error($e->getMessage());
} catch (\think\Exception $e) {
$this->error($e->getMessage());
}
}
$this->error(__('Parameter %s can not be empty', ''));
}
$this->view->assign("row", $row);
return $this->view->fetch();
}
/**
* Selectpage搜索
*
* @internal
*/
public function selectpage()
{
return parent::selectpage();
}
}

View File

@@ -0,0 +1,243 @@
<?php
namespace app\admin\controller;
use app\common\controller\Backend;
use think\Config;
use think\console\Input;
use think\Db;
use think\Exception;
/**
* 在线命令管理
*
* @icon fa fa-circle-o
*/
class Command extends Backend
{
/**
* Command模型对象
*/
protected $model = null;
protected $noNeedRight = ['get_controller_list', 'get_field_list'];
public function _initialize()
{
parent::_initialize();
$this->model = model('Command');
$this->view->assign("statusList", $this->model->getStatusList());
}
/**
* 添加
*/
public function add()
{
$tableList = [];
$list = \think\Db::query("SHOW TABLES");
foreach ($list as $key => $row) {
$tableList[reset($row)] = reset($row);
}
$this->view->assign("tableList", $tableList);
return $this->view->fetch();
}
/**
* 获取字段列表
* @internal
*/
public function get_field_list()
{
$dbname = Config::get('database.database');
$prefix = Config::get('database.prefix');
$table = $this->request->request('table');
//从数据库中获取表字段信息
$sql = "SELECT * FROM `information_schema`.`columns` "
. "WHERE TABLE_SCHEMA = ? AND table_name = ? "
. "ORDER BY ORDINAL_POSITION";
//加载主表的列
$columnList = Db::query($sql, [$dbname, $table]);
$fieldlist = [];
foreach ($columnList as $index => $item) {
$fieldlist[] = $item['COLUMN_NAME'];
}
$this->success("", null, ['fieldlist' => $fieldlist]);
}
/**
* 获取控制器列表
* @internal
*/
public function get_controller_list()
{
//搜索关键词,客户端输入以空格分开,这里接收为数组
$word = (array)$this->request->request("q_word/a");
$word = implode('', $word);
$adminPath = dirname(__DIR__) . DS;
$controllerDir = $adminPath . 'controller' . DS;
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($controllerDir), \RecursiveIteratorIterator::LEAVES_ONLY
);
$list = [];
foreach ($files as $name => $file) {
if (!$file->isDir()) {
$filePath = $file->getRealPath();
$name = str_replace($controllerDir, '', $filePath);
$name = str_replace(DS, "/", $name);
if (!preg_match("/(.*)\.php\$/", $name)) {
continue;
}
if (!$word || stripos($name, $word) !== false) {
$list[] = ['id' => $name, 'name' => $name];
}
}
}
$pageNumber = $this->request->request("pageNumber");
$pageSize = $this->request->request("pageSize");
return json(['list' => array_slice($list, ($pageNumber - 1) * $pageSize, $pageSize), 'total' => count($list)]);
}
/**
* 详情
*/
public function detail($ids)
{
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
$this->view->assign("row", $row);
return $this->view->fetch();
}
/**
* 执行
*/
public function execute($ids)
{
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
$result = $this->doexecute($row['type'], json_decode($row['params'], true));
$this->success("", null, ['result' => $result]);
}
/**
* 执行命令
*/
public function command($action = '')
{
$commandtype = $this->request->request("commandtype");
$params = $this->request->request();
$allowfields = [
'crud' => 'table,controller,model,fields,force,local,delete,menu',
'menu' => 'controller,delete',
'min' => 'module,resource,optimize',
'api' => 'url,module,output,template,force,title,author,class,language,addon',
];
$argv = [];
$allowfields = isset($allowfields[$commandtype]) ? explode(',', $allowfields[$commandtype]) : [];
$allowfields = array_filter(array_intersect_key($params, array_flip($allowfields)));
if (isset($params['local']) && !$params['local']) {
$allowfields['local'] = $params['local'];
} else {
unset($allowfields['local']);
}
foreach ($allowfields as $key => $param) {
$argv[] = "--{$key}=" . (is_array($param) ? implode(',', $param) : $param);
}
if ($commandtype == 'crud') {
$extend = 'setcheckboxsuffix,enumradiosuffix,imagefield,filefield,intdatesuffix,switchsuffix,citysuffix,selectpagesuffix,selectpagessuffix,ignorefields,sortfield,editorsuffix,headingfilterfield,tagsuffix,jsonsuffix,fixedcolumns';
$extendArr = explode(',', $extend);
foreach ($params as $index => $item) {
if (in_array($index, $extendArr)) {
foreach (explode(',', $item) as $key => $value) {
if ($value) {
$argv[] = "--{$index}={$value}";
}
}
}
}
$isrelation = (int)$this->request->request('isrelation');
if ($isrelation && isset($params['relation'])) {
foreach ($params['relation'] as $index => $relation) {
foreach ($relation as $key => $value) {
$argv[] = "--{$key}=" . (is_array($value) ? implode(',', $value) : $value);
}
}
}
} else {
if ($commandtype == 'menu') {
if (isset($params['allcontroller']) && $params['allcontroller']) {
$argv[] = "--controller=all-controller";
} else {
foreach (explode(',', $params['controllerfile']) as $index => $param) {
if ($param) {
$argv[] = "--controller=" . substr($param, 0, -4);
}
}
}
} else {
if ($commandtype == 'min') {
} else {
if ($commandtype == 'api') {
} else {
}
}
}
}
if ($action == 'execute') {
if (stripos(implode(' ', $argv), '--controller=all-controller') !== false) {
$this->error("只允许在命令行执行该命令,执行前请做好菜单规则备份!!!");
}
if (config('app_debug')) {
$result = $this->doexecute($commandtype, $argv);
$this->success("", null, ['result' => $result]);
} else {
$this->error("只允许在开发环境下执行命令");
}
} else {
$this->success("", null, ['command' => "php think {$commandtype} " . implode(' ', $argv)]);
}
return;
}
protected function doexecute($commandtype, $argv)
{
$commandName = "\\app\\admin\\command\\" . ucfirst($commandtype);
$input = new Input($argv);
$output = new \addons\command\library\Output();
$command = new $commandName($commandtype);
$data = [
'type' => $commandtype,
'params' => json_encode($argv),
'command' => "php think {$commandtype} " . implode(' ', $argv),
'executetime' => time(),
];
$this->model->save($data);
try {
$command->run($input, $output);
$result = implode("\n", $output->getMessage());
$this->model->status = 'successed';
} catch (Exception $e) {
$result = implode("\n", $output->getMessage()) . "\n";
$result .= $e->getMessage();
$this->model->status = 'failured';
}
$result = trim($result);
$this->model->content = $result;
$this->model->save();
return $result;
}
}

View File

@@ -0,0 +1,84 @@
<?php
namespace app\admin\controller;
use app\admin\model\Admin;
use app\admin\model\User;
use app\common\controller\Backend;
use app\common\model\Attachment;
use fast\Date;
use think\Db;
/**
* 控制台
*
* @icon fa fa-dashboard
* @remark 用于展示当前系统中的统计数据、统计报表及重要实时数据
*/
class Dashboard extends Backend
{
/**
* 查看
*/
public function index()
{
try {
\think\Db::execute("SET @@sql_mode='';");
} catch (\Exception $e) {
}
$column = [];
$starttime = Date::unixtime('day', -6);
$endtime = Date::unixtime('day', 0, 'end');
$joinlist = Db("user")->where('jointime', 'between time', [$starttime, $endtime])
->field('jointime, status, COUNT(*) AS nums, DATE_FORMAT(FROM_UNIXTIME(jointime), "%Y-%m-%d") AS join_date')
->group('join_date')
->select();
for ($time = $starttime; $time <= $endtime;) {
$column[] = date("Y-m-d", $time);
$time += 86400;
}
$userlist = array_fill_keys($column, 0);
foreach ($joinlist as $k => $v) {
$userlist[$v['join_date']] = $v['nums'];
}
$dbTableList = Db::query("SHOW TABLE STATUS");
$addonList = get_addon_list();
$totalworkingaddon = 0;
$totaladdon = count($addonList);
foreach ($addonList as $index => $item) {
if ($item['state']) {
$totalworkingaddon += 1;
}
}
$this->view->assign([
'totaluser' => User::count(),
'totaladdon' => $totaladdon,
'totaladmin' => Admin::count(),
'totalcategory' => \app\common\model\Category::count(),
'todayusersignup' => User::whereTime('jointime', 'today')->count(),
'todayuserlogin' => User::whereTime('logintime', 'today')->count(),
'sevendau' => User::whereTime('jointime|logintime|prevtime', '-7 days')->count(),
'thirtydau' => User::whereTime('jointime|logintime|prevtime', '-30 days')->count(),
'threednu' => User::whereTime('jointime', '-3 days')->count(),
'sevendnu' => User::whereTime('jointime', '-7 days')->count(),
'dbtablenums' => count($dbTableList),
'dbsize' => array_sum(array_map(function ($item) {
return $item['Data_length'] + $item['Index_length'];
}, $dbTableList)),
'totalworkingaddon' => $totalworkingaddon,
'attachmentnums' => Attachment::count(),
'attachmentsize' => Attachment::sum('filesize'),
'picturenums' => Attachment::where('mimetype', 'like', 'image/%')->count(),
'picturesize' => Attachment::where('mimetype', 'like', 'image/%')->sum('filesize'),
]);
$this->assignconfig('column', array_keys($userlist));
$this->assignconfig('userdata', array_values($userlist));
return $this->view->fetch();
}
}

View File

@@ -0,0 +1,238 @@
<?php
namespace app\admin\controller;
use app\admin\model\Admin;
use app\admin\model\AdminLog;
use app\common\controller\Backend;
use app\common\library\Sms;
use app\common\library\Sms as Smslib;
use think\Config;
use think\Hook;
use think\Session;
use think\Validate;
/**
* 后台首页
* @internal
*/
class Index extends Backend
{
protected $noNeedLogin = ['login','forgot_password','send'];
protected $noNeedRight = ['index', 'logout','forgot_password','send'];
protected $layout = '';
public function _initialize()
{
parent::_initialize();
//移除HTML标签
$this->request->filter('trim,strip_tags,htmlspecialchars');
}
/**
* 后台首页
*/
public function index()
{
$cookieArr = ['adminskin' => "/^skin\-([a-z\-]+)\$/i", 'multiplenav' => "/^(0|1)\$/", 'multipletab' => "/^(0|1)\$/", 'show_submenu' => "/^(0|1)\$/"];
foreach ($cookieArr as $key => $regex) {
$cookieValue = $this->request->cookie($key);
if (!is_null($cookieValue) && preg_match($regex, $cookieValue)) {
config('fastadmin.' . $key, $cookieValue);
}
}
//左侧菜单
list($menulist, $navlist, $fixedmenu, $referermenu) = $this->auth->getSidebar([
'dashboard' => 'hot',
'addon' => ['new', 'red', 'badge'],
'auth/rule' => __('Menu'),
'general' => ['new', 'purple'],
], $this->view->site['fixedpage']);
$action = $this->request->request('action');
if ($this->request->isPost()) {
if ($action == 'refreshmenu') {
$this->success('', null, ['menulist' => $menulist, 'navlist' => $navlist]);
}
}
$this->assignconfig('cookie', ['prefix' => config('cookie.prefix')]);
$this->view->assign('menulist', $menulist);
$this->view->assign('navlist', $navlist);
$this->view->assign('fixedmenu', $fixedmenu);
$this->view->assign('referermenu', $referermenu);
$this->view->assign('title', __('Home'));
return $this->view->fetch();
}
/**
* 管理员登录
*/
public function login()
{
$url = $this->request->get('url', 'index/index');
if ($this->auth->isLogin()) {
$this->success(__("You've logged in, do not login again"), $url);
}
if ($this->request->isPost()) {
$mobile = $this->request->post('mobile');
$password = $this->request->post('password');
$keeplogin = $this->request->post('keeplogin',1);
$token = $this->request->post('__token__');
$rule = [
'mobile' => 'require|length:11',
'password' => 'require|length:3,30',
'__token__' => 'require|token',
];
$data = [
'mobile' => $mobile,
'password' => $password,
'__token__' => $token,
];
/*if (Config::get('fastadmin.login_captcha')) {
$rule['captcha'] = 'require|captcha';
$data['captcha'] = $this->request->post('captcha');
}*/
//$validate = new Validate($rule, [], ['username' => __('Username'), 'password' => __('Password'), 'captcha' => __('Captcha')]);
$validate = new Validate($rule, [], ['mobile' => __('Mobile'), 'password' => __('Password')]);
$result = $validate->check($data);
if (!$result) {
$this->error($validate->getError(), $url, ['token' => $this->request->token()]);
}
AdminLog::setTitle(__('Login'));
$result = $this->auth->login($mobile, $password, $keeplogin ? 86400 : 0);
if ($result === true) {
Hook::listen("admin_login_after", $this->request);
$this->success(__('Login successful'), $url, ['url' => $url, 'id' => $this->auth->id, 'username' => $mobile, 'avatar' => $this->auth->avatar]);
} else {
$msg = $this->auth->getError();
$msg = $msg ? $msg : __('Username or password is incorrect');
$this->error($msg, $url, ['token' => $this->request->token()]);
}
}
// 根据客户端的cookie,判断是否可以自动登录
if ($this->auth->autologin()) {
Session::delete("referer");
$this->redirect($url);
}
$background = Config::get('fastadmin.login_background');
$background = $background ? (stripos($background, 'http') === 0 ? $background : config('site.cdnurl') . $background) : '';
$this->view->assign('background', $background);
$this->view->assign('title', __('Login'));
Hook::listen("admin_login_init", $this->request);
return $this->view->fetch();
}
/**
* 退出登录
*/
public function logout()
{
if ($this->request->isPost()) {
$this->auth->logout();
Hook::listen("admin_logout_after", $this->request);
$this->success(__('Logout successful'), 'index/login');
}
$html = "<form id='logout_submit' name='logout_submit' action='' method='post'>" . token() . "<input type='submit' value='ok' style='display:none;'></form>";
$html .= "<script>document.forms['logout_submit'].submit();</script>";
return $html;
}
/**
* 忘记密码
*/
public function forgot_password()
{
$url = $this->request->get('url', 'index/index');
$login_url = $this->request->get('url', 'index/login');
if ($this->auth->isLogin()) {
$this->success(__("You've logged in, do not login again"), $url);
}
if ($this->request->isPost()) {
$mobile = $this->request->post('mobile');
$password = $this->request->post('password');
$code = $this->request->post('code');
$token = $this->request->post('__token__');
$rule = [
'mobile' => 'require|length:11',
'password' => 'require|length:3,30',
'__token__' => 'require|token',
];
$data = [
'mobile' => $mobile,
'password' => $password,
'__token__' => $token,
];
/*if (Config::get('fastadmin.login_captcha')) {
$rule['captcha'] = 'require|captcha';
$data['captcha'] = $this->request->post('captcha');
}*/
if (!Sms::check($mobile, $code, 'forgot_password')) {
$this->error(__('验证码错误'));
}
//$validate = new Validate($rule, [], ['username' => __('Username'), 'password' => __('Password'), 'captcha' => __('Captcha')]);
$validate = new Validate($rule, [], ['mobile' => __('Mobile'), 'password' => __('Password')]);
$result = $validate->check($data);
if (!$result) {
$this->error($validate->getError(), $url, ['token' => $this->request->token()]);
}
AdminLog::setTitle(__('Forgot Password'));
$result = $this->auth->reset_password($mobile, $password);
if ($result === true) {
//Hook::listen("admin_login_after", $this->request);
$this->success('重置成功', $login_url, ['url' => $login_url, 'id' => $this->auth->id, 'username' => $mobile, 'avatar' => $this->auth->avatar]);
} else {
$msg = $this->auth->getError();
$msg = $msg ? $msg : __('Username or password is incorrect');
$this->error($msg, $url, ['token' => $this->request->token()]);
}
}
$background = Config::get('fastadmin.login_background');
$background = $background ? (stripos($background, 'http') === 0 ? $background : config('site.cdnurl') . $background) : '';
$this->view->assign('background', $background);
$this->view->assign('title', __('Forgot Password'));
//Hook::listen("admin_login_init", $this->request);
return $this->view->fetch();
}
/**
* 发送验证码
*
* @ApiMethod (POST)
* @param string $mobile 手机号
* @param string $event 事件名称
*/
public function send()
{
$mobile = $this->request->post("mobile");
$event = $this->request->post("event");
$event = $event ? $event : 'adminlogin';
if (!$mobile || !\think\Validate::regex($mobile, "^1\d{10}$")) {
$this->error(__('手机号不正确'));
}
$admin = Admin::get(['username' => $mobile]);
if (!$admin) {
$this->error(__('Username is incorrect'));
}
if ($admin['status'] == 'hidden') {
$this->error(__('Admin is forbidden'));
}
$last = Smslib::get($mobile, $event);
if ($last && time() - $last['createtime'] < 60) {
$this->error(__('发送频繁'));
}
if (!Hook::get('sms_send')) {
$this->error(__('请在后台插件管理安装短信验证插件'));
}
$ret = Smslib::send($mobile, null, $event);
if ($ret) {
$this->success(__('发送成功'));
} else {
$this->error(__('发送失败,请检查短信配置是否正确'));
}
}
}

View File

@@ -0,0 +1,311 @@
<?php
namespace app\admin\controller\auth;
use app\admin\model\AuthGroup;
use app\admin\model\AuthGroupAccess;
use app\common\controller\Backend;
use fast\Random;
use fast\Tree;
use think\Db;
use think\Validate;
/**
* 管理员管理
*
* @icon fa fa-users
* @remark 一个管理员可以有多个角色组,左侧的菜单根据管理员所拥有的权限进行生成
*/
class Admin extends Backend
{
/**
* @var \app\admin\model\Admin
*/
protected $model = null;
protected $selectpageFields = 'id,username,nickname,avatar';
protected $searchFields = 'id,username,nickname';
protected $childrenGroupIds = [];
protected $childrenAdminIds = [];
public function _initialize()
{
parent::_initialize();
$this->model = model('Admin');
$this->childrenAdminIds = $this->auth->getChildrenAdminIds($this->auth->isSuperAdmin(), $this->auth->isSuperAdmin() ? -1 : 1);
$this->childrenGroupIds = $this->auth->getChildrenGroupIds($this->auth->isSuperAdmin(), $this->auth->isSuperAdmin() ? -1 : 1);
$level = $this->request->param('level');
if(!empty($level)){
$groupList = collection(AuthGroup::where('level', $level)->where('id', 'in', $this->childrenGroupIds)->select())->toArray();
$groupdata = array_column($groupList,'name','id');
foreach ($groupList as $k => $v) {
$groupdata[$v['id']] = $v['name'];
}
$this->childrenGroupIds = array_keys($groupdata);
}else{
$groupList = collection(AuthGroup::where('id', 'in', $this->childrenGroupIds)->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('groupdata', $groupdata);
$this->assignconfig("admin", ['id' => $this->auth->id]);
$this->assignconfig("level", $level?:0);
}
/**
* 查看
*/
public function index()
{
//设置过滤方法
$this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) {
//如果发送的来源是Selectpage则转发到Selectpage
if ($this->request->request('keyField')) {
return $this->selectpage();
}
$childrenGroupIds = $this->childrenGroupIds;
$groupName = AuthGroup::where('id', 'in', $childrenGroupIds)
->column('id,name');
$authGroupList = AuthGroupAccess::where('group_id', 'in', $childrenGroupIds)
->field('uid,group_id')
->select();
$this->childrenAdminIds = array_column(collection($authGroupList)->toArray(),'uid');
$adminGroupName = [];
foreach ($authGroupList as $k => $v) {
if (isset($groupName[$v['group_id']])) {
$adminGroupName[$v['uid']][$v['group_id']] = $groupName[$v['group_id']];
}
}
$groups = $this->auth->getGroups();
foreach ($groups as $m => $n) {
$adminGroupName[$this->auth->id][$n['id']] = $n['name'];
}
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$list = $this->model
->where($where)
->where('id', 'in', $this->childrenAdminIds)
->field(['password', 'salt', 'token'], true)
->order($sort, $order)
->paginate($limit);
foreach ($list as $k => &$v) {
$groups = isset($adminGroupName[$v['id']]) ? $adminGroupName[$v['id']] : [];
$v['groups'] = implode(',', array_keys($groups));
$v['groups_text'] = implode(',', array_values($groups));
}
unset($v);
$result = array("total" => $list->total(), "rows" => $list->items());
return json($result);
}
return $this->view->fetch();
}
/**
* 添加
*/
public function add()
{
if ($this->request->isPost()) {
$this->token();
$params = $this->request->post("row/a");
if ($params) {
Db::startTrans();
try {
if (!Validate::is($params['password'], '\S{6,30}')) {
exception(__("Please input correct password"));
}
$params['salt'] = Random::alnum();
$params['password'] = md5(md5($params['password']) . $params['salt']);
$params['avatar'] = '/assets/img/avatar.png'; //设置新管理员默认头像。
$params['mobile'] = $params['username'];
$result = $this->model->validate('Admin.add')->save($params);
if ($result === false) {
exception($this->model->getError());
}
$group = $this->request->post("group/a");
//过滤不允许的组别,避免越权
$group = array_intersect($this->childrenGroupIds, $group);
if (!$group) {
exception(__('The parent group exceeds permission limit'));
}
$dataset = [];
foreach ($group as $value) {
$dataset[] = ['uid' => $this->model->id, 'group_id' => $value];
}
model('AuthGroupAccess')->saveAll($dataset);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
$this->success();
}
$this->error(__('Parameter %s can not be empty', ''));
}
return $this->view->fetch();
}
/**
* 编辑
*/
public function edit($ids = null)
{
$row = $this->model->get(['id' => $ids]);
if (!$row) {
$this->error(__('No Results were found'));
}
if (!in_array($row->id, $this->childrenAdminIds)) {
$this->error(__('You have no permission'));
}
if ($this->request->isPost()) {
$this->token();
$params = $this->request->post("row/a");
if ($params) {
Db::startTrans();
try {
if ($params['password']) {
if (!Validate::is($params['password'], '\S{6,30}')) {
exception(__("Please input correct password"));
}
$params['salt'] = Random::alnum();
$params['password'] = md5(md5($params['password']) . $params['salt']);
} else {
unset($params['password'], $params['salt']);
}
$params['mobile'] = $params['username'];
//这里需要针对username和email做唯一验证
$adminValidate = \think\Loader::validate('Admin');
$adminValidate->rule([
'username' => 'require|regex:1[3-9]\d{9}|unique:admin,username,' . $row->id,
//'email' => 'require|email|unique:admin,email,' . $row->id,
'mobile' => 'regex:1[3-9]\d{9}|unique:admin,mobile,' . $row->id,
'password' => 'regex:\S{32}',
]);
$result = $row->validate('Admin.edit')->save($params);
if ($result === false) {
exception($row->getError());
}
// 先移除所有权限
model('AuthGroupAccess')->where('uid', $row->id)->delete();
$group = $this->request->post("group/a");
// 过滤不允许的组别,避免越权
$group = array_intersect($this->childrenGroupIds, $group);
if (!$group) {
exception(__('The parent group exceeds permission limit'));
}
$dataset = [];
foreach ($group as $value) {
$dataset[] = ['uid' => $row->id, 'group_id' => $value];
}
model('AuthGroupAccess')->saveAll($dataset);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
$this->success();
}
$this->error(__('Parameter %s can not be empty', ''));
}
$grouplist = $this->auth->getGroups($row['id']);
$groupids = [];
foreach ($grouplist as $k => $v) {
$groupids[] = $v['id'];
}
$this->view->assign("row", $row);
$this->view->assign("groupids", $groupids);
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 = array_intersect($this->childrenAdminIds, array_filter(explode(',', $ids)));
// 避免越权删除管理员
$childrenGroupIds = $this->childrenGroupIds;
$adminList = $this->model->where('id', 'in', $ids)->where('id', 'in', function ($query) use ($childrenGroupIds) {
$query->name('auth_group_access')->where('group_id', 'in', $childrenGroupIds)->field('uid');
})->select();
if ($adminList) {
$deleteIds = [];
foreach ($adminList as $k => $v) {
$deleteIds[] = $v->id;
}
$deleteIds = array_values(array_diff($deleteIds, [$this->auth->id]));
if ($deleteIds) {
Db::startTrans();
try {
$this->model->destroy($deleteIds);
model('AuthGroupAccess')->where('uid', 'in', $deleteIds)->delete();
Db::commit();
} catch (\Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
$this->success();
}
$this->error(__('No rows were deleted'));
}
}
$this->error(__('You have no permission'));
}
/**
* 批量更新
* @internal
*/
public function multi($ids = "")
{
// 管理员禁止批量操作
$this->error();
}
/**
* 下拉搜索
*/
public function selectpage()
{
$this->dataLimit = 'auth';
$this->dataLimitField = 'id';
return parent::selectpage();
}
}

View File

@@ -0,0 +1,133 @@
<?php
namespace app\admin\controller\auth;
use app\admin\model\AuthGroup;
use app\common\controller\Backend;
/**
* 管理员日志
*
* @icon fa fa-users
* @remark 管理员可以查看自己所拥有的权限的管理员日志
*/
class Adminlog extends Backend
{
/**
* @var \app\admin\model\AdminLog
*/
protected $model = null;
protected $childrenGroupIds = [];
protected $childrenAdminIds = [];
public function _initialize()
{
parent::_initialize();
$this->model = model('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);
}
/**
* 查看
*/
public function index()
{
//设置过滤方法
$this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) {
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$list = $this->model
->where($where)
->where('admin_id', 'in', $this->childrenAdminIds)
->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 (!$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) {
$adminList = $this->model->where('id', 'in', $ids)->where('admin_id', 'in', $this->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();
}
public function selectpage()
{
return parent::selectpage();
}
}

View File

@@ -0,0 +1,392 @@
<?php
namespace app\admin\controller\auth;
use app\admin\model\AuthGroup;
use app\admin\model\Grade;
use app\admin\model\Shiyou;
use app\admin\model\Student;
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\AuthGroup
*/
protected $model = null;
//当前登录管理员所有子组别
protected $childrenGroupIds = [];
//当前组别列表数据
protected $grouplist = [];
protected $groupdata = [];
//无需要权限判断的方法
protected $noNeedRight = ['roletree','selectpage'];
//各级别对应的权限
protected $rules = [
1 => '*',
2 => '8,29,30,31,32,33,34,40,41,42,43,47,48,49,50,113,114,2',
3 => '8,29,30,31,32,33,34,40,41,42,43,47,48,49,50,98,99,100,101,102,103,110,115,116,2',
4 => '8,29,30,31,32,33,34,93,104,105,106,107,108,109,117,118,119,120,121,122,2,92',
];
public function _initialize()
{
parent::_initialize();
$this->model = model('AuthGroup');
$this->childrenGroupIds = $this->auth->getChildrenGroupIds(true, $this->auth->isSuperAdmin() ? -1 : 1);
$level = $this->request->param('level');
if(!empty($level)){
$action = $this->request->action();
if(in_array($action, ['index','selectpage'])){
$where = ['level'=>$level];
}else{
if ($this->auth->isSuperAdmin()) {
$where = ['level'=>$level-1];
}else{
$groupIds = $this->auth->getGroupIds();
$where = ['id'=>['in',$groupIds]];
}
}
$groupList = collection(AuthGroup::where($where)->where('id', 'in', $this->childrenGroupIds)->select())->toArray();
}else{
$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->getGroups();
$groupIds = [];
$action = $this->request->action();
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) {
//index:查看自己及直属下级other:查看自己
if($action != 'index' && $item['id'] != $n['id']){
unset($groupList[$index]);
continue;
}
$groupIds[] = $item['id'];
}
}
//重置数组索引
$groupList = array_slice($groupList,0);
}
}
$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->getGroupIds()]);
$this->assignconfig("level", $level?:0);
$this->view->assign('groupdata', $this->groupdata);
$this->view->assign('cityList', $this->model->getCityList());
$this->view->assign("level", $level?:0);
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax()) {
$list = $this->grouplist;
$level = $this->request->param('level');
$groupList = array_column(collection(AuthGroup::where([])->select())->toArray(), 'name', 'id');
foreach ($list as &$row) {
$row['pname'] = isset($groupList[$row['pid']]) ? $groupList[$row['pid']] : $row['pid'];
$row['child'] = AuthGroup::where('pid', $row['id'])->count();
$row['shiyou'] = $row['class'] = $row['student'] = 0;
switch ($level){
case 3: // 服务队
//狮友
$row['shiyou'] = Shiyou::where('group_id', $row['id'])->count();
$row['student'] = Student::where('group_id','IN',function($query)use($row){
$query->table('fa_auth_group')->where('pid',$row['id'])->field('id');
})->count();
break;
case 4: // 学校
//班级、学生
$row['class'] = Grade::where('group_id', $row['id'])->count();
$row['student'] = Student::where('group_id', $row['id'])->count();
break;
}
}
$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 = model("AuthGroup")->get($params['pid']);
if (!$parentmodel) {
$this->error(__('The parent group can not found'));
}
if($parentmodel['level']==4){
$this->error(__('The parent group exceeds permission limit'));
}
$params['level'] = $parentmodel['level'] + 1;
// 父级别的规则节点
$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);
//根据等级直接分配权限
$params['rules'] = $this->rules[$params['level']];
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 = model("AuthGroup")->get($params['pid']);
if (!$parentmodel) {
$this->error(__('The parent group can not found'));
}
if($parentmodel['level']==4){
$this->error(__('The parent group exceeds permission limit'));
}
$params['level'] = $parentmodel['level'] + 1;
// 父级别的规则节点
$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);
//根据等级直接分配权限
$params['rules'] = $this->rules[$params['level']];
if ($params) {
Db::startTrans();
try {
$row->save($params);
/*$children_auth_groups = model("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));
}
model("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 = model('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 = model('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(model('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(model('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'));
}
}
public function selectpage(){
return parent::selectpage();
}
}

View File

@@ -0,0 +1,159 @@
<?php
namespace app\admin\controller\auth;
use app\admin\model\AuthRule;
use app\common\controller\Backend;
use fast\Tree;
use think\Cache;
/**
* 规则管理
*
* @icon fa fa-list
* @remark 规则通常对应一个控制器的方法,同时左侧的菜单栏数据也从规则中体现,通常建议通过控制台进行生成规则节点
*/
class Rule extends Backend
{
/**
* @var \app\admin\model\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 = model('AuthRule');
// 必须将结果集转换为数组
$ruleList = \think\Db::name("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);
$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('AuthRule');
$ruleValidate->rule([
'name' => 'require|unique:AuthRule,name,' . $row->id,
]);
$result = $row->validate()->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

@@ -0,0 +1,71 @@
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
/**
* 地区管理
*
* @icon fa fa-circle-o
*/
class Area extends Backend
{
/**
* Area模型对象
* @var \app\common\model\Area
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = new \app\common\model\Area;
}
/**
* 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
* 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
* 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
*/
/**
* 查看
*/
public function index()
{
//当前是否为关联查询
$this->relationSearch = false;
//设置过滤方法
$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
->where(['pid'=>655])
->where($where)
->order($sort, $order)
->paginate($limit);
foreach ($list as $row) {
$row->visible(['id','name','encoded']);
}
$result = array("total" => $list->total(), "rows" => $list->items());
return json($result);
}
return $this->view->fetch();
}
}

View File

@@ -0,0 +1,160 @@
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
/**
* 附件管理
*
* @icon fa fa-circle-o
* @remark 主要用于管理上传到服务器或第三方存储的数据
*/
class Attachment extends Backend
{
/**
* @var \app\common\model\Attachment
*/
protected $model = null;
protected $searchFields = 'id,filename,url';
protected $noNeedRight = ['classify'];
public function _initialize()
{
parent::_initialize();
$this->model = model('Attachment');
$this->view->assign("mimetypeList", \app\common\model\Attachment::getMimetypeList());
$this->view->assign("categoryList", \app\common\model\Attachment::getCategoryList());
$this->assignconfig("categoryList", \app\common\model\Attachment::getCategoryList());
}
/**
* 查看
*/
public function index()
{
//设置过滤方法
$this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) {
$mimetypeQuery = [];
$filter = $this->request->request('filter');
$filterArr = (array)json_decode($filter, true);
if (isset($filterArr['category']) && $filterArr['category'] == 'unclassed') {
$filterArr['category'] = ',unclassed';
$this->request->get(['filter' => json_encode(array_diff_key($filterArr, ['category' => '']))]);
}
if (isset($filterArr['mimetype']) && preg_match("/(\/|\,|\*)/", $filterArr['mimetype'])) {
$mimetype = $filterArr['mimetype'];
$filterArr = array_diff_key($filterArr, ['mimetype' => '']);
$mimetypeQuery = function ($query) use ($mimetype) {
$mimetypeArr = array_filter(explode(',', $mimetype));
foreach ($mimetypeArr as $index => $item) {
$query->whereOr('mimetype', 'like', '%' . str_replace("/*", "/", $item) . '%');
}
};
}
$this->request->get(['filter' => json_encode($filterArr)]);
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$list = $this->model
->where($mimetypeQuery)
->where($where)
->order($sort, $order)
->paginate($limit);
$cdnurl = preg_replace("/\/(\w+)\.php$/i", '', $this->request->root());
foreach ($list as $k => &$v) {
$v['fullurl'] = ($v['storage'] == 'local' ? $cdnurl : $this->view->config['upload']['cdnurl']) . $v['url'];
}
unset($v);
$result = array("total" => $list->total(), "rows" => $list->items());
return json($result);
}
return $this->view->fetch();
}
/**
* 选择附件
*/
public function select()
{
if ($this->request->isAjax()) {
return $this->index();
}
$mimetype = $this->request->get('mimetype', '');
$mimetype = substr($mimetype, -1) === '/' ? $mimetype . '*' : $mimetype;
$this->view->assign('mimetype', $mimetype);
return $this->view->fetch();
}
/**
* 添加
*/
public function add()
{
if ($this->request->isAjax()) {
$this->error();
}
return $this->view->fetch();
}
/**
* 删除附件
* @param array $ids
*/
public function del($ids = "")
{
if (!$this->request->isPost()) {
$this->error(__("Invalid parameters"));
}
$ids = $ids ? $ids : $this->request->post("ids");
if ($ids) {
\think\Hook::add('upload_delete', function ($params) {
if ($params['storage'] == 'local') {
$attachmentFile = ROOT_PATH . '/public' . $params['url'];
if (is_file($attachmentFile)) {
@unlink($attachmentFile);
}
}
});
$attachmentlist = $this->model->where('id', 'in', $ids)->select();
foreach ($attachmentlist as $attachment) {
\think\Hook::listen("upload_delete", $attachment);
$attachment->delete();
}
$this->success();
}
$this->error(__('Parameter %s can not be empty', 'ids'));
}
/**
* 归类
*/
public function classify()
{
if (!$this->auth->check('general/attachment/edit')) {
\think\Hook::listen('admin_nopermission', $this);
$this->error(__('You have no permission'), '');
}
if (!$this->request->isPost()) {
$this->error(__("Invalid parameters"));
}
$category = $this->request->post('category', '');
$ids = $this->request->post('ids');
if (!$ids) {
$this->error(__('Parameter %s can not be empty', 'ids'));
}
$categoryList = \app\common\model\Attachment::getCategoryList();
if ($category && !isset($categoryList[$category])) {
$this->error(__('Category not found'));
}
$category = $category == 'unclassed' ? '' : $category;
\app\common\model\Attachment::where('id', 'in', $ids)->update(['category' => $category]);
$this->success();
}
}

View File

@@ -0,0 +1,343 @@
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
use app\common\library\Email;
use app\common\model\Config as ConfigModel;
use think\Cache;
use think\Db;
use think\Exception;
use think\Validate;
/**
* 系统配置
*
* @icon fa fa-cogs
* @remark 可以在此增改系统的变量和分组,也可以自定义分组和变量,如果需要删除请从数据库中删除
*/
class Config extends Backend
{
/**
* @var \app\common\model\Config
*/
protected $model = null;
protected $noNeedRight = ['check', 'rulelist', 'selectpage', 'get_fields_list'];
public function _initialize()
{
parent::_initialize();
// $this->model = model('Config');
$this->model = new ConfigModel;
ConfigModel::event('before_write', function ($row) {
if (isset($row['name']) && $row['name'] == 'name' && preg_match("/fast" . "admin/i", $row['value'])) {
throw new Exception(__("Site name incorrect"));
}
});
}
/**
* 查看
*/
public function index()
{
$siteList = [];
$groupList = ConfigModel::getGroupList();
foreach ($groupList as $k => $v) {
$siteList[$k]['name'] = $k;
$siteList[$k]['title'] = $v;
$siteList[$k]['list'] = [];
}
foreach ($this->model->all() as $k => $v) {
if (!isset($siteList[$v['group']])) {
continue;
}
$value = $v->toArray();
$value['title'] = __($value['title']);
if (in_array($value['type'], ['select', 'selects', 'checkbox', 'radio'])) {
$value['value'] = explode(',', $value['value']);
}
$value['content'] = json_decode($value['content'], true);
if (in_array($value['name'], ['categorytype', 'configgroup', 'attachmentcategory'])) {
$dictValue = (array)json_decode($value['value'], true);
foreach ($dictValue as $index => &$item) {
$item = __($item);
}
unset($item);
$value['value'] = json_encode($dictValue, JSON_UNESCAPED_UNICODE);
}
$value['tip'] = htmlspecialchars($value['tip']);
if ($value['name'] == 'cdnurl') {
//cdnurl不支持在线修改
continue;
}
$siteList[$v['group']]['list'][] = $value;
}
$index = 0;
foreach ($siteList as $k => &$v) {
$v['active'] = !$index ? true : false;
$index++;
}
$this->view->assign('siteList', $siteList);
$this->view->assign('typeList', ConfigModel::getTypeList());
$this->view->assign('ruleList', ConfigModel::getRegexList());
$this->view->assign('groupList', ConfigModel::getGroupList());
return $this->view->fetch();
}
/**
* 添加
*/
public function add()
{
if (!config('app_debug')) {
$this->error(__('Only work at development environment'));
}
if ($this->request->isPost()) {
$this->token();
$params = $this->request->post("row/a", [], 'trim');
if ($params) {
foreach ($params as $k => &$v) {
$v = is_array($v) && $k !== 'setting' ? implode(',', $v) : $v;
}
if (in_array($params['type'], ['select', 'selects', 'checkbox', 'radio', 'array'])) {
$params['content'] = json_encode(ConfigModel::decode($params['content']), JSON_UNESCAPED_UNICODE);
} else {
$params['content'] = '';
}
try {
$result = $this->model->create($params);
} catch (Exception $e) {
$this->error($e->getMessage());
}
if ($result !== false) {
try {
ConfigModel::refreshFile();
} catch (Exception $e) {
$this->error($e->getMessage());
}
$this->success();
} else {
$this->error($this->model->getError());
}
}
$this->error(__('Parameter %s can not be empty', ''));
}
return $this->view->fetch();
}
/**
* 编辑
* @param null $ids
*/
public function edit($ids = null)
{
if ($this->request->isPost()) {
$this->token();
$row = $this->request->post("row/a", [], 'trim');
if ($row) {
$configList = [];
foreach ($this->model->all() as $v) {
if (isset($row[$v['name']])) {
$value = $row[$v['name']];
if (is_array($value) && isset($value['field'])) {
$value = json_encode(ConfigModel::getArrayData($value), JSON_UNESCAPED_UNICODE);
} else {
$value = is_array($value) ? implode(',', $value) : $value;
}
$v['value'] = $value;
$configList[] = $v->toArray();
}
}
// //清除数据
// $stu = $configList[7]['value'];
// $stu_back = db('config')->where('id',19)->find();
// if($stu == 1 && $stu_back['value'] == 0){
// //执行删除
// db('student')->delete();
// }
// $tea = $configList[8]['value'];
// $tea_back = db('config')->where('id',20)->find();
// if($stu == 1 && $tea_back['value'] == 0){
// //执行删除
// db('student')->delete();
// }
// $stu = $configList[7]['value'];
// $stu_back = db('config')->where('id',19)->find();
// if($stu == 1 && $stu_back['value'] == 0){
// //执行删除
// db('student')->delete();
// }
// $stu = $configList[7]['value'];
// $stu_back = db('config')->where('id',19)->find();
// if($stu == 1 && $stu_back['value'] == 0){
// //执行删除
// db('student')->delete();
// }
try {
$this->model->allowField(true)->saveAll($configList);
} catch (Exception $e) {
$this->error($e->getMessage());
}
try {
ConfigModel::refreshFile();
} catch (Exception $e) {
$this->error($e->getMessage());
}
$this->success();
}
$this->error(__('Parameter %s can not be empty', ''));
}
}
/**
* 删除
* @param string $ids
*/
public function del($ids = "")
{
if (!config('app_debug')) {
$this->error(__('Only work at development environment'));
}
$name = $this->request->post('name');
$config = ConfigModel::getByName($name);
if ($name && $config) {
try {
$config->delete();
ConfigModel::refreshFile();
} catch (Exception $e) {
$this->error($e->getMessage());
}
$this->success();
} else {
$this->error(__('Invalid parameters'));
}
}
/**
* 检测配置项是否存在
* @internal
*/
public function check()
{
$params = $this->request->post("row/a");
if ($params) {
$config = $this->model->get($params);
if (!$config) {
$this->success();
} else {
$this->error(__('Name already exist'));
}
} else {
$this->error(__('Invalid parameters'));
}
}
/**
* 规则列表
* @internal
*/
public function rulelist()
{
//主键
$primarykey = $this->request->request("keyField");
//主键值
$keyValue = $this->request->request("keyValue", "");
$keyValueArr = array_filter(explode(',', $keyValue));
$regexList = \app\common\model\Config::getRegexList();
$list = [];
foreach ($regexList as $k => $v) {
if ($keyValueArr) {
if (in_array($k, $keyValueArr)) {
$list[] = ['id' => $k, 'name' => $v];
}
} else {
$list[] = ['id' => $k, 'name' => $v];
}
}
return json(['list' => $list]);
}
/**
* 发送测试邮件
* @internal
*/
public function emailtest()
{
$row = $this->request->post('row/a');
$receiver = $this->request->post("receiver");
if ($receiver) {
if (!Validate::is($receiver, "email")) {
$this->error(__('Please input correct email'));
}
\think\Config::set('site', array_merge(\think\Config::get('site'), $row));
$email = new Email;
$result = $email
->to($receiver)
->subject(__("This is a test mail", config('site.name')))
->message('<div style="min-height:550px; padding: 100px 55px 200px;">' . __('This is a test mail content', config('site.name')) . '</div>')
->send();
if ($result) {
$this->success();
} else {
$this->error($email->getError());
}
} else {
$this->error(__('Invalid parameters'));
}
}
public function selectpage()
{
$id = $this->request->get("id/d");
$config = \app\common\model\Config::get($id);
if (!$config) {
$this->error(__('Invalid parameters'));
}
$setting = $config['setting'];
//自定义条件
$custom = isset($setting['conditions']) ? (array)json_decode($setting['conditions'], true) : [];
$custom = array_filter($custom);
$this->request->request(['showField' => $setting['field'], 'keyField' => $setting['primarykey'], 'custom' => $custom, 'searchField' => [$setting['field'], $setting['primarykey']]]);
$this->model = \think\Db::connect()->setTable($setting['table']);
return parent::selectpage();
}
/**
* 获取表列表
* @internal
*/
public function get_table_list()
{
$tableList = [];
$dbname = \think\Config::get('database.database');
$tableList = \think\Db::query("SELECT `TABLE_NAME` AS `name`,`TABLE_COMMENT` AS `title` FROM `information_schema`.`TABLES` where `TABLE_SCHEMA` = '{$dbname}';");
$this->success('', null, ['tableList' => $tableList]);
}
/**
* 获取表字段列表
* @internal
*/
public function get_fields_list()
{
$table = $this->request->request('table');
$dbname = \think\Config::get('database.database');
//从数据库中获取表字段信息
$sql = "SELECT `COLUMN_NAME` AS `name`,`COLUMN_COMMENT` AS `title`,`DATA_TYPE` AS `type` FROM `information_schema`.`columns` WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION";
//加载主表的列
$fieldList = Db::query($sql, [$dbname, $table]);
$this->success("", null, ['fieldList' => $fieldList]);
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
use think\Db;
/**
* 班级管理
*
* @icon fa fa-circle-o
*/
class Grade extends Backend
{
/**
* Grade模型对象
* @var \app\admin\model\Grade
*/
protected $model = null;
protected $selectpageFields = 'id,grade,class,name';
//无需要权限判断的方法
protected $noNeedRight = ['selectpage'];
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\Grade;
$this->view->assign("statusList", $this->model->getStatusList());
$this->view->assign("isSuperAdmin", $this->auth->isSuperAdmin());
$this->view->assign("group_id", $this->auth->getGroupIds()[0]);
}
/**
* 默认生成的控制器所继承的父类中有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();
$wheres = [];
if(!$this->auth->isSuperAdmin()){
$groupIds = $this->auth->getGroupIds();
$wheres = ['group_id'=>['in',$groupIds]];
}
$list = $this->model
->with(['groups'])
->where($where)
->where($wheres)
->order($sort, $order)
->paginate($limit);
foreach ($list as $row) {
$row->getRelation('groups')->visible(['name']);
}
$result = array("total" => $list->total(), "rows" => $list->items());
return json($result);
}
$this->assignconfig("isSuperAdmin", $this->auth->isSuperAdmin());
return $this->view->fetch();
}
public function selectpage(){
return parent::selectpage();
}
}

View File

@@ -0,0 +1,220 @@
<?php
namespace app\admin\controller\general;
use app\admin\model\AuthGroup;
use app\admin\model\Student;
use app\common\controller\Backend;
use app\common\model\Area;
use think\Db;
/**
* 编号管理
*
* @icon fa fa-circle-o
*/
class Identifier extends Backend
{
/**
* Identifier模型对象
* @var \app\admin\model\Identifier
*/
protected $model = null;
//无需要权限判断的方法
protected $noNeedRight = ['create_id'];
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\Identifier;
$this->view->assign("statusList", $this->model->getStatusList());
}
/**
* 默认生成的控制器所继承的父类中有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();
$wheres = [];
if(!$this->auth->isSuperAdmin()){
$groupIds = $this->auth->getGroupIds();
$wheres = ['group_id'=>['in',$groupIds]];
}
$list = $this->model
->with(['groups'])
->where($where)
->where($wheres)
->order($sort, $order)
->paginate($limit);
foreach ($list as $row) {
$row->getRelation('groups')->visible(['name']);
}
$result = array("total" => $list->total(), "rows" => $list->items());
return json($result);
}
$this->assignconfig("isSuperAdmin", $this->auth->isSuperAdmin());
return $this->view->fetch();
}
/**
* 添加
*
* @return string
* @throws \think\Exception
*/
public function add()
{
if (false === $this->request->isPost()) {
return $this->view->fetch();
}
$params = $this->request->post('row/a');
if (empty($params)) {
$this->error(__('Parameter %s can not be empty', ''));
}
$params = $this->preExcludeFields($params);
if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
$params[$this->dataLimitField] = $this->auth->id;
}
//生成编号
//判断长度和数量
$length = $params['length'] - strlen($params['prefix']);
if(10**$length < $params['number'] + $params['first']){
$this->error('编号长度不足');
}
$data = [];
$suffix = sprintf("%'0{$params['length']}s",$params['first']);
for($i=0;$i<$params['number'];$i++){
$identifier = strtoupper($params['prefix']).$suffix;
//查询是否存在
$exist = $this->model->where('identifier', $identifier)->find();
if($exist){
$this->error("编号 $identifier 重复");
}
$data[] = [
'group_id' => $params['group_id'],
'identifier' => $identifier,
];
$suffix = sprintf("%'0{$params['length']}s",++$suffix);
}
$result = false;
Db::startTrans();
try {
//是否采用模型验证
if ($this->modelValidate) {
$name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
$validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
$this->model->validateFailException()->validate($validate);
}
$result = $this->model->allowField(true)->saveAll($data);
Db::commit();
} catch (ValidateException|PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($result === false) {
$this->error(__('No rows were inserted'));
}
$this->success();
}
/**
* 编辑
*
* @param $ids
* @return string
* @throws DbException
* @throws \think\Exception
*/
public function edit($ids = null)
{
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds) && !in_array($row[$this->dataLimitField], $adminIds)) {
$this->error(__('You have no permission'));
}
if (false === $this->request->isPost()) {
$this->view->assign('row', $row);
return $this->view->fetch();
}
$params = $this->request->post('row/a');
if (empty($params)) {
$this->error(__('Parameter %s can not be empty', ''));
}
$params = $this->preExcludeFields($params);
//查询是否存在
$exist = $this->model->where('identifier', $params['identifier'])->find();
if($exist && $exist['id'] != $params['id']){
$this->error("编号 {$params['identifier']} 重复");
}
$result = false;
Db::startTrans();
try {
//是否采用模型验证
if ($this->modelValidate) {
$name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
$validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate;
$row->validateFailException()->validate($validate);
}
$result = $row->allowField(true)->save($params);
Db::commit();
} catch (ValidateException|PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if (false === $result) {
$this->error(__('No rows were updated'));
}
$this->success();
}
/**
* 根据学校ID生成学生编号
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function create_id(){
$group_id = $this->request->post("group_id");
$info = AuthGroup::where('id', $group_id)->find();
while ($info['level'] > 2){
$info = AuthGroup::where('id', $info['pid'])->find();
}
//地区编号
$area_encoded = Area::where('id', $info['city'])->value('encoded');
//当前学校学生最大编号
$student_number = Student::where('group_id', $group_id)->value('CONVERT(MAX(RIGHT(`identifier`,4)),UNSIGNED)');
$student_code = $area_encoded.sprintf("%'04s", $group_id).sprintf("%'04s", $student_number+1);
$this->success('', '', $student_code);
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace app\admin\controller\general;
use app\admin\model\Admin;
use app\common\controller\Backend;
use fast\Random;
use think\Session;
use think\Validate;
/**
* 个人配置
*
* @icon fa fa-user
*/
class Profile extends Backend
{
protected $searchFields = 'id,title';
/**
* 查看
*/
public function index()
{
//设置过滤方法
$this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) {
$this->model = model('AdminLog');
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$list = $this->model
->where($where)
->where('admin_id', $this->auth->id)
->order($sort, $order)
->paginate($limit);
$result = array("total" => $list->total(), "rows" => $list->items());
return json($result);
}
return $this->view->fetch();
}
/**
* 更新个人信息
*/
public function update()
{
if ($this->request->isPost()) {
$this->token();
$params = $this->request->post("row/a");
$params = array_filter(array_intersect_key(
$params,
array_flip(array('email', 'nickname', 'password', 'avatar'))
));
unset($v);
/*if (!Validate::is($params['email'], "email")) {
$this->error(__("Please input correct email"));
}*/
if (isset($params['password'])) {
if (!Validate::is($params['password'], "/^[\S]{6,30}$/")) {
$this->error(__("Please input correct password"));
}
$params['salt'] = Random::alnum();
$params['password'] = md5(md5($params['password']) . $params['salt']);
}
/*$exist = Admin::where('email', $params['email'])->where('id', '<>', $this->auth->id)->find();
if ($exist) {
$this->error(__("Email already exists"));
}*/
if ($params) {
$admin = Admin::get($this->auth->id);
$admin->save($params);
//因为个人资料面板读取的Session显示修改自己资料后同时更新Session
Session::set("admin", $admin->toArray());
$this->success();
}
$this->error();
}
return;
}
}

View File

@@ -0,0 +1,341 @@
<?php
namespace app\admin\controller\general;
use app\admin\library\Auth;
use app\common\controller\Backend;
use Exception;
use fast\Random;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xls;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use think\Db;
use think\exception\PDOException;
use think\exception\ValidateException;
/**
* 狮友管理
*
* @icon fa fa-circle-o
*/
class Shiyou extends Backend
{
/**
* Shiyou模型对象
* @var \app\admin\model\Shiyou
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\Shiyou;
$this->view->assign("genderList", $this->model->getGenderList());
$this->view->assign("statusList", $this->model->getStatusList());
$this->view->assign("isSuperAdmin", $this->auth->isSuperAdmin());
$this->view->assign("group_id", $this->auth->getGroupIds()[0]);
}
/**
* 默认生成的控制器所继承的父类中有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();
$wheres = [];
if(!$this->auth->isSuperAdmin()){
$groupIds = $this->auth->getGroupIds();
$wheres = ['group_id'=>['in',$groupIds]];
}
$list = $this->model
->with(['groups'])
->where($where)
->where($wheres)
->order($sort, $order)
->paginate($limit);
foreach ($list as $row) {
/*$row->visible(['id','nickname','mobile','gender','createtime','status']);
$row->visible(['groups']);*/
$row->getRelation('groups')->visible(['name']);
}
$result = array("total" => $list->total(), "rows" => $list->items());
return json($result);
}
$this->assignconfig("isSuperAdmin", $this->auth->isSuperAdmin());
return $this->view->fetch();
}
/**
* 添加
*
* @return string
* @throws \think\Exception
*/
public function add()
{
if (false === $this->request->isPost()) {
return $this->view->fetch();
}
$params = $this->request->post('row/a');
if (empty($params)) {
$this->error(__('Parameter %s can not be empty', ''));
}
$params = $this->preExcludeFields($params);
if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
$params[$this->dataLimitField] = $this->auth->id;
}
$result = false;
Db::startTrans();
try {
$params['salt'] = Random::alnum();
$params['password'] = md5(md5($params['password']) . $params['salt']);
$result = $this->model->validateFailException()->validate('Shiyou.add')->allowField(true)->save($params);
Db::commit();
} catch (ValidateException|PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($result === false) {
$this->error(__('No rows were inserted'));
}
$this->success();
}
/**
* 编辑
*
* @param $ids
* @return string
* @throws DbException
* @throws \think\Exception
*/
public function edit($ids = null)
{
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds) && !in_array($row[$this->dataLimitField], $adminIds)) {
$this->error(__('You have no permission'));
}
if (false === $this->request->isPost()) {
$this->view->assign('row', $row);
return $this->view->fetch();
}
$params = $this->request->post('row/a');
if (empty($params)) {
$this->error(__('Parameter %s can not be empty', ''));
}
$params = $this->preExcludeFields($params);
$result = false;
Db::startTrans();
try {
if ($params['password']) {
$params['salt'] = Random::alnum();
$params['password'] = md5(md5($params['password']) . $params['salt']);
} else {
unset($params['password'], $params['salt']);
}
//这里需要针对mobile做唯一验证
$adminValidate = \think\Loader::validate('Shiyou');
$adminValidate->rule([
'mobile' => 'regex:1[3-9]\d{9}|unique:shiyou,mobile,' . $row->id,
]);
$result = $row->validateFailException()->validate('Shiyou.edit')->allowField(true)->save($params);
Db::commit();
} catch (ValidateException|PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if (false === $result) {
$this->error(__('No rows were updated'));
}
$this->success();
}
/**
* 导入
*
* @return void
* @throws PDOException
* @throws BindParamException
*/
public function import()
{
$file = $this->request->request('file');
if (!$file) {
$this->error(__('Parameter %s can not be empty', 'file'));
}
$filePath = ROOT_PATH . DS . 'public' . DS . $file;
if (!is_file($filePath)) {
$this->error(__('No results were found'));
}
//实例化reader
$ext = pathinfo($filePath, PATHINFO_EXTENSION);
if (!in_array($ext, ['csv', 'xls', 'xlsx'])) {
$this->error(__('Unknown data format'));
}
if ($ext === 'csv') {
$file = fopen($filePath, 'r');
$filePath = tempnam(sys_get_temp_dir(), 'import_csv');
$fp = fopen($filePath, 'w');
$n = 0;
while ($line = fgets($file)) {
$line = rtrim($line, "\n\r\0");
$encoding = mb_detect_encoding($line, ['utf-8', 'gbk', 'latin1', 'big5']);
if ($encoding !== 'utf-8') {
$line = mb_convert_encoding($line, 'utf-8', $encoding);
}
if ($n == 0 || preg_match('/^".*"$/', $line)) {
fwrite($fp, $line . "\n");
} else {
fwrite($fp, '"' . str_replace(['"', ','], ['""', '","'], $line) . "\"\n");
}
$n++;
}
fclose($file) || fclose($fp);
$reader = new Csv();
} elseif ($ext === 'xls') {
$reader = new Xls();
} else {
$reader = new Xlsx();
}
//导入文件首行类型,默认是注释,如果需要使用字段名称请使用name
$importHeadType = isset($this->importHeadType) ? $this->importHeadType : 'comment';
$table = $this->model->getQuery()->getTable();
$database = \think\Config::get('database.database');
$fieldArr = [];
$list = db()->query("SELECT COLUMN_NAME,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ?", [$table, $database]);
foreach ($list as $k => $v) {
if ($importHeadType == 'comment') {
$fieldArr[$v['COLUMN_COMMENT']] = $v['COLUMN_NAME'];
} else {
$fieldArr[$v['COLUMN_NAME']] = $v['COLUMN_NAME'];
}
}
//加载文件
$insert = [];
try {
if (!$PHPExcel = $reader->load($filePath)) {
$this->error(__('Unknown data format'));
}
$currentSheet = $PHPExcel->getSheet(0); //读取文件中的第一个工作表
$allColumn = $currentSheet->getHighestDataColumn(); //取得最大的列号
$allRow = $currentSheet->getHighestRow(); //取得一共有多少行
$maxColumnNumber = Coordinate::columnIndexFromString($allColumn);
$fields = [];
for ($currentRow = 1; $currentRow <= 1; $currentRow++) {
for ($currentColumn = 1; $currentColumn <= $maxColumnNumber; $currentColumn++) {
$val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();
$fields[] = $val;
}
}
$extend = [];
if(!in_array('服务队ID',$fields) && !in_array('group_id',$fields)){
//从服务队导入
$group_id = $this->request->param('ids');
//从狮友导入
if(empty($group_id)){
$groupInfo = $this->auth->getGroups()[0];
if($groupInfo['level'] != 3){
throw new \think\Exception('上传文件缺失参数 服务队ID');
}
$group_id = $groupInfo['group_id'];
}
$extend['group_id'] = $group_id;
}
for ($currentRow = 2; $currentRow <= $allRow; $currentRow++) {
$values = [];
for ($currentColumn = 1; $currentColumn <= $maxColumnNumber; $currentColumn++) {
$val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();
$values[] = is_null($val) ? '' : $val;
}
$row = [];
$temp = array_combine($fields, $values);
foreach ($temp as $k => $v) {
if (isset($fieldArr[$k]) && $k !== '') {
if(empty($v)){
$row = []; break;
}
$row[$fieldArr[$k]] = $v;
}
}
if ($row) {
if(!empty($extend)) $row = array_merge($row, $extend);
$row['salt'] = Random::alnum();
$row['password'] = empty($row['password']) ? '123456' : $row['password'];
$row['password'] = md5(md5($row['password']) . $row['salt']);
$insert[] = $row;
}
}
} catch (Exception $exception) {
$this->error($exception->getMessage());
}
if (!$insert) {
$this->error(__('No rows were updated'));
}
try {
//是否包含admin_id字段
$has_admin_id = false;
foreach ($fieldArr as $name => $key) {
if ($key == 'admin_id') {
$has_admin_id = true;
break;
}
}
if ($has_admin_id) {
$auth = Auth::instance();
foreach ($insert as &$val) {
if (!isset($val['admin_id']) || empty($val['admin_id'])) {
$val['admin_id'] = $auth->isLogin() ? $auth->id : 0;
}
}
}
$this->model->saveAll($insert);
} catch (PDOException $exception) {
$msg = $exception->getMessage();
if (preg_match("/.+Integrity constraint violation: 1062 Duplicate entry '(.+)' for key '(.+)'/is", $msg, $matches)) {
$msg = "导入失败,包含【{$matches[1]}】的记录已存在";
};
$this->error($msg);
} catch (Exception $e) {
$this->error($e->getMessage());
}
$this->success();
}
}

View File

@@ -0,0 +1,248 @@
<?php
namespace app\admin\controller\general;
use app\common\controller\Backend;
use Exception;
use fast\Random;
use think\Db;
use think\exception\PDOException;
use think\exception\ValidateException;
use app\common\model\Area;
/**
* 学生管理
*
* @icon fa fa-circle-o
*/
class Student extends Backend
{
private $IdentifierModel;
/**
* Student模型对象
* @var \app\admin\model\Student
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\Student;
$this->IdentifierModel = new \app\admin\model\Identifier;
$this->view->assign("genderList", $this->model->getGenderList());
$this->view->assign("typeList", $this->model->getTypeList());
$this->view->assign("statusList", $this->model->getStatusList());
$this->view->assign("isSuperAdmin", $this->auth->isSuperAdmin());
$this->view->assign("group_id", $this->auth->getGroupIds()[0]);
}
/**
* 默认生成的控制器所继承的父类中有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();
$wheres = [];
if(!$this->auth->isSuperAdmin()){
$groupIds = $this->auth->getGroupIds();
$wheres = ['student.group_id'=>['in',$groupIds]];
}
$list = $this->model
->with(['groups','grade'])
->where($where)
->where($wheres)
->order($sort, $order)
->paginate($limit);
foreach ($list as $row) {
$row->getRelation('groups')->visible(['name']);
$row->getRelation('grade')->visible(['grade','class']);
}
$result = array("total" => $list->total(), "rows" => $list->items());
return json($result);
}
$this->assignconfig("isSuperAdmin", $this->auth->isSuperAdmin());
return $this->view->fetch();
}
/**
* 添加
*
* @return string
* @throws \think\Exception
*/
public function add()
{
if (false === $this->request->isPost()) {
return $this->view->fetch();
}
$params = $this->request->post('row/a');
if (empty($params)) {
$this->error(__('Parameter %s can not be empty', ''));
}
$params = $this->preExcludeFields($params);
if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
$params[$this->dataLimitField] = $this->auth->id;
}
$result = false;
Db::startTrans();
try {
//编号状态
/*$identifier = $this->IdentifierModel->where('identifier', $params['identifier'])->find();
if(empty($identifier)){
$this->error("编号不存在");
}
if($identifier['status'] != 'normal'){
$this->error("编号已分配");
}
//修改编号状态
$this->IdentifierModel->where('identifier', $params['identifier'])->update(['status'=>'hidden']);*/
$params['salt'] = Random::alnum();
$params['password'] = md5(md5($params['password']) . $params['salt']);
$school = db('auth_group')->where('id',$params['group_id'])->find();
$params['school'] = $school['name'];
$info = db('auth_group')->where('id', $params['group_id'])->find();
while ($info['level'] > 2){
$info = db('auth_group')->where('id', $info['pid'])->find();
}
//地区编号
$area_encoded = db('area')->where('id', $info['city'])->find();
$params['city'] = $area_encoded['name'];
$result = $this->model->validateFailException()->validate('Student.add')->allowField(true)->save($params);
Db::commit();
} catch (ValidateException|PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($result === false) {
$this->error(__('No rows were inserted'));
}
$this->success();
}
/**
* 编辑
*
* @param $ids
* @return string
* @throws DbException
* @throws \think\Exception
*/
public function edit($ids = null)
{
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds) && !in_array($row[$this->dataLimitField], $adminIds)) {
$this->error(__('You have no permission'));
}
if (false === $this->request->isPost()) {
$this->view->assign('row', $row);
return $this->view->fetch();
}
$params = $this->request->post('row/a');
if (empty($params)) {
$this->error(__('Parameter %s can not be empty', ''));
}
$params = $this->preExcludeFields($params);
$result = false;
Db::startTrans();
try {
if ($params['password']) {
$params['salt'] = Random::alnum();
$params['password'] = md5(md5($params['password']) . $params['salt']);
} else {
unset($params['password'], $params['salt']);
}
//这里需要针对mobile做唯一验证
$adminValidate = \think\Loader::validate('Student');
$adminValidate->rule([
'mobile' => 'regex:1[3-9]\d{9}|unique:student,mobile,' . $row->id,
]);
$result = $row->validateFailException()->validate('Student.edit')->allowField(true)->save($params);
Db::commit();
} catch (ValidateException|PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if (false === $result) {
$this->error(__('No rows were updated'));
}
$this->success();
}
/**
* 删除
*
* @param $ids
* @return void
* @throws DbException
* @throws DataNotFoundException
* @throws ModelNotFoundException
*/
/*public function del($ids = null)
{
if (false === $this->request->isPost()) {
$this->error(__("Invalid parameters"));
}
$ids = $ids ?: $this->request->post("ids");
if (empty($ids)) {
$this->error(__('Parameter %s can not be empty', 'ids'));
}
$pk = $this->model->getPk();
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
$list = $this->model->where($pk, 'in', $ids)->select();
$count = 0;
Db::startTrans();
try {
//释放编号
$identifiers = array_column($list, 'identifier');
$this->IdentifierModel->where('identifier', 'in', $identifiers)->update(['status'=>'normal']);
foreach ($list as $item) {
$count += $item->delete();
}
Db::commit();
} catch (PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($count) {
$this->success();
}
$this->error(__('No rows were deleted'));
}*/
}

View File

@@ -0,0 +1,52 @@
<?php
namespace app\admin\controller\user;
use app\common\controller\Backend;
/**
* 会员组管理
*
* @icon fa fa-users
*/
class Group extends Backend
{
/**
* @var \app\admin\model\UserGroup
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('UserGroup');
$this->view->assign("statusList", $this->model->getStatusList());
}
public function add()
{
if ($this->request->isPost()) {
$this->token();
}
$nodeList = \app\admin\model\UserRule::getTreeList();
$this->assign("nodeList", $nodeList);
return parent::add();
}
public function edit($ids = null)
{
if ($this->request->isPost()) {
$this->token();
}
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
$rules = explode(',', $row['rules']);
$nodeList = \app\admin\model\UserRule::getTreeList($rules);
$this->assign("nodeList", $nodeList);
return parent::edit($ids);
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace app\admin\controller\user;
use app\common\controller\Backend;
use fast\Tree;
/**
* 会员规则管理
*
* @icon fa fa-circle-o
*/
class Rule extends Backend
{
/**
* @var \app\admin\model\UserRule
*/
protected $model = null;
protected $rulelist = [];
protected $multiFields = 'ismenu,status';
public function _initialize()
{
parent::_initialize();
$this->model = model('UserRule');
$this->view->assign("statusList", $this->model->getStatusList());
// 必须将结果集转换为数组
$ruleList = collection($this->model->order('weigh', 'desc')->select())->toArray();
foreach ($ruleList as $k => &$v) {
$v['title'] = __($v['title']);
$v['remark'] = __($v['remark']);
}
unset($v);
Tree::instance()->init($ruleList);
$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'];
}
$this->view->assign('ruledata', $ruledata);
}
/**
* 查看
*/
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();
}
return parent::add();
}
/**
* 编辑
*/
public function edit($ids = null)
{
if ($this->request->isPost()) {
$this->token();
}
return parent::edit($ids);
}
/**
* 删除
*/
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) {
$this->success();
}
}
$this->error();
}
}

View File

@@ -0,0 +1,105 @@
<?php
namespace app\admin\controller\user;
use app\common\controller\Backend;
use app\common\library\Auth;
/**
* 会员管理
*
* @icon fa fa-user
*/
class User extends Backend
{
protected $relationSearch = true;
protected $searchFields = 'id,username,nickname';
/**
* @var \app\admin\model\User
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('User');
}
/**
* 查看
*/
public function index()
{
//设置过滤方法
$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('group')
->where($where)
->order($sort, $order)
->paginate($limit);
foreach ($list as $k => $v) {
$v->avatar = $v->avatar ? cdnurl($v->avatar, true) : letter_avatar($v->nickname);
$v->hidden(['password', 'salt']);
}
$result = array("total" => $list->total(), "rows" => $list->items());
return json($result);
}
return $this->view->fetch();
}
/**
* 添加
*/
public function add()
{
if ($this->request->isPost()) {
$this->token();
}
return parent::add();
}
/**
* 编辑
*/
public function edit($ids = null)
{
if ($this->request->isPost()) {
$this->token();
}
$row = $this->model->get($ids);
$this->modelValidate = true;
if (!$row) {
$this->error(__('No Results were found'));
}
$this->view->assign('groupList', build_select('row[group_id]', \app\admin\model\UserGroup::column('id,name'), $row['group_id'], ['class' => 'form-control selectpicker']));
return parent::edit($ids);
}
/**
* 删除
*/
public function del($ids = "")
{
if (!$this->request->isPost()) {
$this->error(__("Invalid parameters"));
}
$ids = $ids ? $ids : $this->request->post("ids");
$row = $this->model->get($ids);
$this->modelValidate = true;
if (!$row) {
$this->error(__('No Results were found'));
}
Auth::instance()->delete($row['id']);
$this->success();
}
}