This commit is contained in:
2025-06-21 16:39:10 +08:00
commit 7ff2185f8e
17 changed files with 1058 additions and 0 deletions

39
composer.json Normal file
View File

@ -0,0 +1,39 @@
{
"name": "q792602257/think-plugs-staff",
"description": "ThinkAdmin Plugin: Staff with Dept Support",
"version": "dev-master",
"minimum-stability": "dev",
"license": "WTFPL",
"authors": [
{
"name": "Jerry Yan",
"email": "792602257@qq.com"
}
],
"extra": {
"config": {
"type": "module",
"name": "员工及组织架构模块",
"platforms": ["h5web"],
"description": "员工及组织架构模块"
},
"plugin": {
"copy": {
"stc/database": "database/migrations"
}
},
"think": {
"services": [
"jerryyan\\staff\\Service"
]
}
},
"autoload": {
"psr-4": {
"jerryyan\\staff\\": "src"
}
},
"require": {
}
}

24
src/Service.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace jerryyan\staff;
use think\admin\Plugin;
class Service extends Plugin
{
protected $appCode = 'staff';
protected $appName = '部门员工';
public static function menu(): array
{
return [
[
'name' => '组织架构',
'subs' => [
['name' => '员工管理', 'icon' => 'layui-icon layui-icon-group', 'url' => 'staff/user/index'],
['name' => '部门管理', 'icon' => 'layui-icon layui-icon-cols', 'url' => 'staff/dept/index'],
// ['name' => '角色管理', 'icon' => 'layui-icon layui-icon-auz', 'url' => 'staff/role/index'],
]
]
];
}
}

120
src/controller/Dept.php Normal file
View File

@ -0,0 +1,120 @@
<?php
namespace jerryyan\staff\controller;
use jerryyan\staff\model\StaffDept;
use jerryyan\staff\model\StaffUser;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
class Dept extends Controller
{
/**
* 员工部门管理
* @menu true
* @auth true
* @return null
*/
public function index()
{
return StaffDept::mQuery()->layTable(function () {
$this->title = '员工部门';
}, static function (QueryHelper $query) {
$query->with('parent.parent')->append(['headman_name']);
$query->equal('status')->like('name');
});
}
/**
* 添加部门
* @auth true
* @menu true
* @return void
*/
public function add()
{
StaffDept::mForm('form');
}
/**
* 编辑部门
* @auth true
* @return void
*/
public function edit()
{
StaffDept::mForm('form');
}
protected function _form_filter(array &$data)
{
if ($this->request->isPost()) {
$this->_vali([
'name.require' => '部门名称不能为空!',
]);
} else {
$this->depts = StaffDept::topItems();
}
}
/**
* 部门排序
* @auth true
* @return void
*/
public function sort()
{
StaffDept::mSave($this->_vali([
'sort.require' => '排序参数不能为空!',
'sort.number' => '排序参数格式错误!',
]));
}
/**
* 设置部门领导人
* @auth true
* @return void
*/
public function headman()
{
$data = $this->_vali([
'id.require' => '部门不能为空!',
]);
if ($this->request->isGet()) {
$this->title = '设置部门负责人';
$this->dept = StaffDept::mk()->where(['id' => $data['id']])->findOrEmpty();
if ($this->dept->isEmpty()) $this->error('部门不存在!');
$this->users = StaffUser::mk()->where(['status' => 1, 'dept_id' => $this->dept['id']])->select();
$this->fetch();
} else {
StaffDept::mSave($this->_vali([
'headman_id.require' => '部门领导人不能为空!',
'headman_id.number' => '部门领导人格式错误!',
]));
}
}
/**
* 启用禁用部门
* @auth true
* @return void
*/
public function state()
{
StaffDept::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除部门
* @auth true
* @return void
*/
public function del()
{
StaffDept::mDelete();
}
}

151
src/controller/User.php Normal file
View File

@ -0,0 +1,151 @@
<?php
namespace jerryyan\staff\controller;
use jerryyan\staff\model\StaffDept;
use jerryyan\staff\model\StaffUser;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemAuth;
use think\admin\model\SystemUser;
/**
* 部门员工管理
*/
class User extends Controller
{
/**
* 部门员工管理
* @menu true
* @auth true
* @return null
*/
public function index()
{
return StaffUser::mQuery()->layTable(function () {
$this->title = '部门员工';
$this->dept = StaffDept::tree();
}, static function (QueryHelper $query) {
$query->equal('dept_id,status')->like('name');
$query->with('dept')->append(['dept_name']);
});
}
/**
* 添加员工
* @auth true
* @menu true
* @return void
*/
public function add()
{
StaffUser::mForm('form');
}
/**
* 编辑员工
* @auth true
* @return void
*/
public function edit()
{
StaffUser::mForm('form');
}
protected function _form_filter(array &$data)
{
if ($this->request->isPost()) {
// 检查资料是否完整
$this->_vali([
'name.require' => '用户名称不能为空!',
'phone.require' => '手机号码不能为空!',
'phone.mobile' => '手机号码格式错误!',
'email.email' => '邮箱地址格式错误!',
'dept_id.require' => '部门名称不能为空!',
'authorize.require' => '未配置权限!'
]);
if (!empty($data['password'])) {
if (strlen($data['password']) < 6) {
$this->error('密码长度不能少于6位!');
};
}
} else {
if (!empty($data['id'])) {
$user = SystemUser::mk()->find($data['id']);
$data['authorize'] = str2arr($user['authorize'] ?? '');;
} else {
$data['authorize'] = [];
}
$data['dept_id'] = $data['dept_id'] ?? '';
$this->auths = SystemAuth::items();
$this->depts = StaffDept::items();
}
}
protected function _form_result(bool $state, $data)
{
if ($state) {
$user = [];
// 检查账号是否重复
$map = ['username' => $data['phone'], 'is_deleted' => 0];
$systemUser = SystemUser::mk()->where($map)->findOrEmpty();
if ($systemUser->isExists() && $systemUser->id != $data['id']) {
$this->error("账号已经存在,请使用其它账号!");
}
$user['id'] = $data['id'];
$user['username'] = $data['phone'];
if (!empty($data['password'])) {
$user['password'] = md5($data['password']);
}
$user['nickname'] = $data['name'];
$user['contact_mail'] = $data['email'];
// 处理上传的权限格式
$user['authorize'] = arr2str($data['authorize'] ?? []);
SystemUser::mk()->save($user);
}
}
/**
* 启用禁用员工
* @return void
*/
public function state()
{
StaffUser::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
protected function _state_save_result(bool $state, $data)
{
if ($state) {
$systemUser = SystemUser::mk()->findOrEmpty($this->request->post('id'));
if ($systemUser->isExists()) {
$systemUser->status = $this->request->post('status');
$systemUser->save();
}
}
}
/**
* 删除员工
* @auth true
* @return void
*/
public function del()
{
StaffUser::mDelete();
}
protected function _del_delete_result(bool $state)
{
if ($state) {
$systemUser = SystemUser::mk()->findOrEmpty($this->request->post('id'));
if ($systemUser->isExists()) {
$systemUser->is_deleted = 1;
$systemUser->save();
}
}
}
}

77
src/model/StaffDept.php Normal file
View File

@ -0,0 +1,77 @@
<?php
namespace jerryyan\staff\model;
use think\admin\Model;
use think\db\Query;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
class StaffDept extends Model
{
protected $createTime = 'create_at';
protected $updateTime = false;
protected $oplogName = '部门';
protected $oplogType = '部门管理';
protected $globalScope = ['notDeleted'];
public static function topItems()
{
return self::where(['pid' => 0])->field("id, name")->select()->unshift([
'id' => 0,
'name' => '顶级部门',
]);
}
public function scopeDeleted(Query $query): void
{
$query->where(['is_deleted' => 1]);
}
public function scopeNotDeleted(Query $query): void
{
$query->where(['is_deleted' => 0]);
}
public static function items()
{
return self::mk()->where(['status' => 1])->select();
}
public function staffs(): HasMany
{
return $this->hasMany(StaffUser::class, 'dept_id', 'id')->where([
'status' => 1, 'is_deleted' => 0,
]);
}
public function headman(): HasOne
{
return $this->hasOne(StaffUser::class, 'id', 'headman_id')->where([
'status' => 1, 'is_deleted' => 0,
]);
}
public function children(): HasMany
{
return $this->hasMany(StaffDept::class, 'pid', 'id');
}
public function parent(): HasOne
{
return $this->hasOne(StaffDept::class, 'id', 'pid');
}
public static function tree()
{
return static::mk()->where(['is_deleted' => 0, 'pid' => 0])->with('children.children')->select();
}
public function getHeadmanNameAttr()
{
if (!$this->headman_id) {
return '无';
}
return $this->headman ? $this->headman['name'] : '无';
}
}

38
src/model/StaffUser.php Normal file
View File

@ -0,0 +1,38 @@
<?php
namespace jerryyan\staff\model;
use think\admin\Model;
use think\db\Query;
use think\model\relation\HasOne;
class StaffUser extends Model
{
protected $createTime = 'create_at';
protected $updateTime = false;
protected $oplogName = '部门员工';
protected $oplogType = '部门员工管理';
protected $globalScope = ['notDeleted'];
public function scopeDeleted(Query $query): void
{
$query->where('is_deleted', '=', 1);
}
public function scopeNotDeleted(Query $query): void
{
$query->where('is_deleted', '=', 0);
}
public function dept(): HasOne
{
return $this->hasOne(StaffDept::class, 'id', 'dept_id')->where([
'status' => 1, 'is_deleted' => 0,
]);
}
public function getDeptNameAttr($value, $data)
{
return $this->dept ? $this->dept['name'] : '';
}
}

29
src/view/dept/form.html Normal file
View File

@ -0,0 +1,29 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card" data-table-id="DeptTable">
<div class="layui-card-body padding-left-40">
<fieldset class="layui-bg-gray">
<legend><b class="layui-badge think-bg-violet">基础信息</b></legend>
<label class="layui-form-item relative block">
<span class="help-label"><b>名称</b></span>
<input maxlength="100" class="layui-input" name="name" value='{$vo.name|default=""}' required vali-name="名称" placeholder="请输入名称">
</label>
<label class="layui-form-item relative block">
<span class="help-label"><b>上级部门</b></span>
<select name="pid" lay-search class="layui-select">
{foreach $depts as $dept}{if isset($vo.pid) and $dept.id eq $vo.pid}
<option selected value="{$dept.id}">{$dept.name}</option>
{else}
<option value="{$dept.id}">{$dept.name}</option>
{/if}{/foreach}
</select>
</label>
</fieldset>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>{:lang('保存数据')}</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="{:lang('确定要取消编辑吗?')}" data-close>{:lang('取消编辑')}</button>
</div>
</form>

View File

@ -0,0 +1,26 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card" data-table-id="DeptTable">
<div class="layui-card-body padding-left-40">
<fieldset class="layui-bg-gray">
<legend><b class="layui-badge think-bg-violet">部门:{$dept.name}</b></legend>
<label class="layui-form-item relative block">
<span class="help-label"><b>新的部门主管</b></span>
<select required name="headman_id" lay-search class="layui-select">
<option value="">请选择部门主管</option>
{foreach $users as $user}{if isset($dept.headman_id) and $dept.headman_id eq $user.id}
<option selected value="{$user.id}">{$user.name}</option>
{else}
<option value="{$user.id}">{$user.name}</option>
{/if}{/foreach}
</select>
</label>
</fieldset>
</div>
<div class="hr-line-dashed"></div>
{notempty name='get.id'}<input type='hidden' value='{$get.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>{:lang('保存数据')}</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="{:lang('确定要取消编辑吗?')}" data-close>{:lang('取消编辑')}</button>
</div>
</form>

89
src/view/dept/index.html Normal file
View File

@ -0,0 +1,89 @@
{extend name='table'}
{block name="button"}
<!--{if auth("add")}-->
<button data-modal='{:url("add")}' data-title="{:lang('添加部门')}" class='layui-btn layui-btn-sm layui-btn-primary'>{:lang('添加部门')}</button>
<!--{/if}-->
{/block}
{block name="content"}
<div class="think-box-shadow">
{include file="dept/index_search"}
<table class="layui-hide" id="DeptTable" data-url="{:request()->url()}" data-target-search="form.form-search" lay-filter="DeptTable"></table>
</div>
<script type="text/html" id="StatusSwitchTpl">
<!--{if auth("state")}-->
<input type="checkbox" value="{{d.id}}" lay-skin="switch" lay-text="{:lang('已激活')}|{:lang('已禁用')}" lay-filter="StatusSwitch" {{-d.status>0?'checked':''}}>
<!--{else}-->
{{-d.status ? '<b class="color-green">{:lang("已激活")}</b>' : '<b class="color-red">{:lang("已禁用")}</b>'}}
<!--{/if}-->
</script>
<script type="text/html" id="SortInputTpl">
<input type="number" min="0" data-blur-number="0" data-action-blur="{:sysuri()}" data-value="id#{{d.id}};action#sort;sort#{value}" data-loading="false" value="{{d.sort}}" class="layui-input text-center">
</script>
<script type="text/html" id="HeadmanTpl">
{{d.headman_name}}
<!--{if auth("headman")}-->
{{# if(d.headman_id) { }}
<a class="layui-btn layui-btn-xs" data-modal="{:url('headman')}?id={{d.id}}" data-title="修改部门负责人">{:lang('修改')}</a>
{{# } else { }}
<a class="layui-btn layui-btn-xs" data-modal="{:url('headman')}?id={{d.id}}" data-title="设置部门负责人">{:lang('设置')}</a>
{{# } }}
<!--{/if}-->
</script>
<script type="text/html" id="ToolbarTpl">
<div class="layui-btn-container">
<!--{if auth("edit")}-->
<a class="layui-btn layui-btn-warm layui-btn-xs" data-modal="{:url('edit')}?id={{d.id}}" data-title="{:lang('编辑员工')}">编辑</a>
<!--{/if}-->
<!--{if auth("del")}-->
<a class="layui-btn layui-btn-danger layui-btn-xs" data-confirm="{:lang('确定要永久删除吗?')}" data-action="{:url('del')}" data-value="id#{{d.id}}">{:lang('删 除')}</a>
<!--{/if}-->
</div>
</script>
<script>
$(function () {
$('#DeptTable').layTable({
elem: '',
height: 'full',
sort: {field: 'sort', type: 'desc'},
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'sort', title: '排序', width: 100, sort: true, templet: '#SortInputTpl' },
{ field: 'name', title: '部门名', templet: function (d) {
if (d.parent) {
if (d.parent.parent) {
return '<span class="layui-badge layui-bg-gray">' + d.parent.parent.name + '&nbsp;/&nbsp;' + d.parent.name + '&nbsp;</span>' + d.name;
}
return '<span class="layui-badge layui-bg-gray">' + d.parent.name + '&nbsp;/&nbsp;</span>' + d.name;
}
return d.name;
} },
{ field: 'headman_name', title: '部门负责人', templet: '#HeadmanTpl'},
{ field: 'status', title: '状态', align: 'center', minWidth: 110, templet: '#StatusSwitchTpl' },
{ fixed: "right", title: "操作", width: 200, align: "center", toolbar: "#ToolbarTpl"}
]],
page: true
})
layui.use(['form', 'table'], function () {
const Table = layui.table;
const Form = layui.form;
Table.on('tool(DeptTable)', function (obj) {
console.log(obj);
})
Form.on('switch(StatusSwitch)', function (obj) {
var data = {id: obj.value, status: obj.elem.checked > 0 ? 1 : 0};
$.form.load("{:url('state')}", data, 'post', function (ret) {
if (ret.code < 1) $.msg.error(ret.info, 3, function () {
$('#DeptTable').trigger('reload');
}); else {
$('#DeptTable').trigger('reload')
}
return false;
}, false);
});
});
})
</script>
{/block}

View File

@ -0,0 +1,27 @@
<fieldset>
<legend>{:lang('条件搜索')}</legend>
<form class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="post" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">{:lang('部门名')}</label>
<label class="layui-input-inline">
<input name="name" value="{$get.name|default=''}" placeholder="{:lang('请输入部门名')}" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">{:lang('启用状态')}</label>
<label class="layui-input-inline">
<select name="status">
<option value="">{:lang('请选择启用状态')}</option>
<option value="1">{:lang('已启用')}</option>
<option value="0">{:lang('已禁用')}</option>
</select>
</label>
</div>
<div class="layui-form-item layui-inline">
<input type="hidden" name="dept_id" value="{$get.dept_id|default=''}">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> {:lang('搜 索')}</button>
</div>
</form>
</fieldset>

23
src/view/main.html Normal file
View File

@ -0,0 +1,23 @@
<div class="layui-card">
{block name='style'}{/block}
{block name='header'}
{notempty name='title'}
<div class="layui-card-header">
<span class="layui-icon font-s10 color-desc margin-right-5">&#xe65b;</span>{$title|lang}
<div class="pull-right">{block name='button'}{/block}</div>
</div>
{/notempty}
{/block}
<div class="layui-card-line"></div>
<div class="layui-card-body">
<div class="layui-card-html">
{notempty name='showErrorMessage'}
<div class="think-box-notify" type="error">
<b>{:lang('系统提示:')}</b><span>{$showErrorMessage|raw}</span>
</div>
{/notempty}
{block name='content'}{/block}
</div>
</div>
{block name='script'}{/block}
</div>

23
src/view/table.html Normal file
View File

@ -0,0 +1,23 @@
<div class="layui-card">
{block name='style'}{/block}
{block name='header'}
{notempty name='title'}
<div class="layui-card-header">
<span class="layui-icon font-s10 color-desc margin-right-5">&#xe65b;</span>{$title|lang}
<div class="pull-right">{block name='button'}{/block}</div>
</div>
{/notempty}
{/block}
<div class="layui-card-line"></div>
<div class="layui-card-body">
<div class="layui-card-table">
{notempty name='showErrorMessage'}
<div class="think-box-notify" type="error">
<b>{:lang('系统提示:')}</b><span>{$showErrorMessage|raw}</span>
</div>
{/notempty}
{block name='content'}{/block}
</div>
</div>
{block name='script'}{/block}
</div>

91
src/view/user/form.html Normal file
View File

@ -0,0 +1,91 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card" data-table-id="UserTable">
<div class="layui-card-body padding-left-40">
<fieldset class="layui-bg-gray">
<legend><b class="layui-badge think-bg-violet">基础信息</b></legend>
<label class="layui-form-item relative block">
<span class="help-label"><b>名称</b></span>
<input maxlength="100" class="layui-input" name="name" value='{$vo.name|default=""}' required vali-name="名称" placeholder="请输入名称">
</label>
<label class="layui-form-item relative block">
<span class="help-label"><b>性别</b></span>
<label class="think-radio">
{if (0==$vo.gender)}
<input type="radio" name="gender" value="0" checked lay-ignore>
{else}
<input type="radio" name="gender" value="0" lay-ignore>
{/if}
</label>
<label class="think-radio">
{if (1==$vo.gender)}
<input type="radio" name="gender" value="1" checked lay-ignore>
{else}
<input type="radio" name="gender" value="1" lay-ignore>
{/if}
</label>
</label>
<label class="layui-form-item relative block">
<span class="help-label"><b>手机号</b>(登录名)</span>
<input maxlength="100" class="layui-input" name="phone" value='{$vo.phone|default=""}' required vali-name="手机号" placeholder="请输入手机号">
</label>
<label class="layui-form-item relative block">
<span class="help-label"><b>登录密码</b></span>
{notempty name='vo.id'}
<input maxlength="100" class="layui-input" name="password" placeholder="不填写则不修改">
{else}
<input maxlength="100" class="layui-input" name="password" required vali-name="登录密码" placeholder="请输入登录密码">
{/notempty}
</label>
<label class="layui-form-item relative block">
<span class="help-label"><b>邮箱</b></span>
<input maxlength="100" class="layui-input" name="email" value='{$vo.email|default=""}' placeholder="请输入邮箱">
</label>
</fieldset>
<fieldset class="layui-bg-gray">
<legend><b class="layui-badge think-bg-violet">部门权限</b></legend>
{if !empty($depts)}
<div class="layui-form-item">
<div class="help-label"><b>部门</b></div>
<div class="layui-textarea help-checks">
{foreach $depts as $dept}
<label class="think-radio">
{if ($dept.id==$vo.dept_id)}
<input type="radio" name="dept_id" value="{$dept.id}" checked lay-ignore>
{else}
<input type="radio" name="dept_id" value="{$dept.id}" lay-ignore>
{/if}
{$dept.name}
</label>
{/foreach}
</div>
</div>
{/if}
{if !empty($auths)}
<div class="layui-form-item">
<div class="help-label"><b>访问权限</b></div>
<div class="layui-textarea help-checks">
{foreach $auths as $authorize}
<label class="think-checkbox">
{if in_array($authorize.id, $vo.authorize)}
<input type="checkbox" checked name="authorize[]" value="{$authorize.id}" lay-ignore>{$authorize.title}
{else}
<input type="checkbox" name="authorize[]" value="{$authorize.id}" lay-ignore>{$authorize.title}
{/if}
</label>
{/foreach}
</div>
</div>
{/if}
</fieldset>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>{:lang('保存数据')}</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="{:lang('确定要取消编辑吗?')}" data-close>{:lang('取消编辑')}</button>
</div>
</form>

131
src/view/user/index.html Normal file
View File

@ -0,0 +1,131 @@
{extend name='table'}
{block name="button"}
<!--{if auth("admin/user/index")}-->
<button data-open='{:url("admin/user/index")}' class='layui-btn layui-btn-sm layui-btn-danger'>{:lang('可登录用户管理')}</button>
<!--{/if}-->
<!--{if auth("add")}-->
<button data-modal='{:url("add")}' data-title="{:lang('添加员工')}" class='layui-btn layui-btn-sm layui-btn-primary'>{:lang('添加员工')}</button>
<!--{/if}-->
{/block}
{block name="content"}
<div style="display: flex; flex-direction: row; background: white; gap: 20px">
<div class="think-box-shadow" style="flex: 1">
<!-- 部门管理 -->
<table class="layui-hide" id="DeptTreeTable" lay-filter="DeptTreeTable"></table>
</div>
<div class="think-box-shadow" style="flex: 4">
{include file="user/index_search"}
<table class="layui-hide" id="UserTable" data-url="{:request()->url()}" data-target-search="form.form-search" lay-filter="UserTable"></table>
</div>
</div>
<script type="text/html" id="StatusSwitchTpl">
<!--{if auth("state")}-->
<input type="checkbox" value="{{d.id}}" lay-skin="switch" lay-text="{:lang('已激活')}|{:lang('已禁用')}" lay-filter="StatusSwitch" {{-d.status>0?'checked':''}}>
<!--{else}-->
{{-d.status ? '<b class="color-green">{:lang("已激活")}</b>' : '<b class="color-red">{:lang("已禁用")}</b>'}}
<!--{/if}-->
</script>
<script type="text/html" id="ToolbarTpl">
<div class="layui-btn-container">
<!--{if auth("edit")}-->
<a class="layui-btn layui-btn-warm layui-btn-xs" data-modal="{:url('edit')}?id={{d.id}}" data-title="{:lang('编辑员工')}">编辑</a>
<!--{/if}-->
<!--{if auth("del")}-->
<a class="layui-btn layui-btn-danger layui-btn-xs" data-confirm="{:lang('确定要永久删除吗?')}" data-action="{:url('del')}" data-value="id#{{d.id}}">{:lang('删 除')}</a>
<!--{/if}-->
</div>
</script>
<script>
const deptJson = JSON.parse('{:json_encode($dept)}');
</script>
<script>
$(function () {
$('#UserTable').layTable({
elem: '',
height: 'full',
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'dept_name', title: '所属部门' },
{ field: 'name', title: '用户名' },
{ field: 'gender', title: '性别', templet: function (d) {
return d.gender === 0 ? '男' : d.gender === 1 ? '女' : '';
} },
{ field: 'phone', title: '手机号' },
{ field: 'email', title: '邮箱' },
{ field: '', title: '部门负责人', templet: function (d) {
if (d.dept) {
if (d.dept.headman_id === d.id) {
return '是'
}
}
return '否';
} },
{field: 'status', title: '状态', align: 'center', minWidth: 110, templet: '#StatusSwitchTpl'},
{ fixed: "right", title: "操作", width: 200, align: "center", toolbar: "#ToolbarTpl"}
]],
page: true
})
layui.use(['treeTable', 'form', 'table'], function () {
const TreeTable = layui.treeTable;
const Table = layui.table;
const Form = layui.form;
TreeTable.render({
elem: '#DeptTreeTable',
height: 'full',
data: deptJson,
tree: {
customName: {},
data: {
isSimpleData: false,
},
view: {
iconClose: 'layui-icon layui-icon-folder',
iconOpen: 'layui-icon layui-icon-folder-open',
iconLeaf: 'layui-icon layui-icon-file',
dblClickExpand: false,
}
},
cols: [[
{ field: 'name', title: '部门名称' },
]],
page: false,
})
TreeTable.on('rowDouble(DeptTreeTable)', function (obj) {
console.log(obj)
const data = obj.data;
$('input[name="dept_id"]').val(data.id)
$('form.form-search').trigger('submit');
const nodes = TreeTable.getNodesByFilter('DeptTreeTable', function (item) {
return item.LAY_CHECKED === true
})
nodes.forEach(node => {
TreeTable.updateNode('DeptTreeTable', node.dataIndex, {
LAY_CHECKED: false
})
})
console.log(nodes)
TreeTable.updateNode('DeptTreeTable', obj.dataIndex, {
LAY_CHECKED: true
})
})
Table.on('tool(UserTable)', function (obj) {
console.log(obj);
})
Form.on('switch(StatusSwitch)', function (obj) {
var data = {id: obj.value, status: obj.elem.checked > 0 ? 1 : 0};
$.form.load("{:url('state')}", data, 'post', function (ret) {
if (ret.code < 1) $.msg.error(ret.info, 3, function () {
$('#UserTable').trigger('reload');
}); else {
$('#UserTable').trigger('reload')
}
return false;
}, false);
});
});
})
</script>
{/block}

View File

@ -0,0 +1,27 @@
<fieldset>
<legend>{:lang('条件搜索')}</legend>
<form class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="post" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">{:lang('用户名')}</label>
<label class="layui-input-inline">
<input name="name" value="{$get.name|default=''}" placeholder="{:lang('请输入用户名')}" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">{:lang('启用状态')}</label>
<label class="layui-input-inline">
<select name="status">
<option value="">{:lang('请选择启用状态')}</option>
<option value="1">{:lang('已启用')}</option>
<option value="0">{:lang('已禁用')}</option>
</select>
</label>
</div>
<div class="layui-form-item layui-inline">
<input type="hidden" name="dept_id" value="{$get.dept_id|default=''}">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> {:lang('搜 索')}</button>
</div>
</form>
</fieldset>

View File

@ -0,0 +1,89 @@
<?php
use jerryyan\staff\Service;
use think\admin\extend\PhinxExtend;
use think\migration\Migrator;
@set_time_limit(0);
@ini_set('memory_limit', -1);
/**
* 系统模块数据
*/
class InstallStaffDb extends Migrator
{
/**
* 获取脚本名称
* @return string
*/
public function getName(): string
{
return 'StaffPlugin';
}
/**
* 创建数据库
*/
public function change()
{
$this->_create_staff_dept();
$this->_create_staff_user();
}
/**
* 创建数据对象
* @class StaffDept
* @table staff_dept
* @return void
*/
private function _create_staff_dept()
{
// 创建数据表对象
$table = $this->table('staff_dept', [
'engine' => 'InnoDB', 'collation' => 'utf8mb4_general_ci', 'comment' => '部门员工',
]);
// 创建或更新数据表
PhinxExtend::upgrade($table, [
['name', 'string', ['limit' => 255, 'default' => NULL, 'null' => false, 'comment' => '部门名称']],
['pid', 'integer', ['limit' => 11, 'default' => 0, 'null' => false, 'comment' => '上级部门ID']],
['headman_id', 'integer', ['default' => NULL, 'null' => true, 'comment' => '领导人ID']],
['sort', 'integer', ['limit' => 9, 'default' => 100, 'null' => false, 'comment' => '排序权重']],
['status', 'integer', ['limit' => 11, 'default' => 1, 'null' => false, 'comment' => '状态(0禁用,1启用)']],
['is_deleted', 'integer', ['limit' => 11, 'default' => 0, 'null' => false, 'comment' => '删除(1删除,0未删)']],
['create_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP', 'null' => true, 'comment' => '创建时间']],
], [
], false);
}
/**
* 创建数据对象
* @class StaffUser
* @table staff_user
* @return void
*/
private function _create_staff_user()
{
// 创建数据表对象
$table = $this->table('staff_user', [
'engine' => 'InnoDB', 'collation' => 'utf8mb4_general_ci', 'comment' => '部门员工',
]);
// 创建或更新数据表
PhinxExtend::upgrade($table, [
['name', 'string', ['limit' => 255, 'default' => NULL, 'null' => false, 'comment' => '员工名称']],
['gender', 'tinyinteger', ['limit' => 4, 'default' => 0, 'null' => true, 'comment' => '性别(0男,1女)']],
['phone', 'string', ['limit' => 255, 'default' => NULL, 'null' => false, 'comment' => '手机号']],
['email', 'string', ['limit' => 255, 'default' => NULL, 'null' => true, 'comment' => '电子邮箱']],
['dept_id', 'integer', ['limit' => 11, 'default' => 0, 'null' => true, 'comment' => '所属部门']],
['status', 'integer', ['default' => '1', 'null' => false, 'comment' => '状态(0禁用,1启用)']],
['is_deleted', 'integer', ['default' => '0', 'null' => false, 'comment' => '删除(1删除,0未删)']],
['create_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP', 'null' => true, 'comment' => '创建时间']],
], [
], false);
}
}

View File

@ -0,0 +1,54 @@
<?php
use jerryyan\staff\Service;
use think\admin\extend\PhinxExtend;
use think\migration\Migrator;
@set_time_limit(0);
@ini_set('memory_limit', -1);
/**
* 系统模块数据
*/
class InstallStaffMenu extends Migrator
{
/**
* 获取脚本名称
* @return string
*/
public function getName(): string
{
return 'StaffPlugin';
}
/**
* 创建数据库
*/
public function change()
{
$this->insertMenu();
}
/**
* 初始化系统菜单
* @return void
* @throws \Exception
*/
private function insertMenu()
{
// 初始化菜单数据
PhinxExtend::write2menu([
[
'name' => '组织架构',
'sort' => '101',
'subs' => Service::menu(),
],
], [
'url|node' => 'staff/user/index'
]);
}
}