Commit 417e7a3c authored by 安宁's avatar 安宁

init

parents
[app]
app_name = PearProject
app_version = 2.8.16
app_host = ''
app_debug = false
app_trace = false
[database]
hostname = 127.0.0.1
database = pearproject
username = root
password = root
hostport = 3306
prefix = pear_
debug = true
[config]
notice_push = false
dingtalk_push = false
mail_push = false
[sms]
debug = true
[mail]
open = false
Host = smtp.example.com
SMTPAuth = true
Username = example@example.com
Password = example
SMTPSecure = tls
Port = 25
[cache]
type = redis
path = ./runtime/cache
expire = 0
[redis]
host = 127.0.0.1
port = 6379
password =
*.js linguist-language=php
*.css linguist-language=php
*.html linguist-language=php
!.gitignore
!.gitattributes
*.DS_Store
*.idea
*.svn
*.git
.env
/runtime
/log
/vendor
/data/install.lock
/static/upload
!composer.json
/composer.lock
/config/dingtalk.php
/config/mail.php
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0
</IfModule>
open_basedir="D:/workspace/pearproject/;C:/Windows/Temp/;C:/Temp/;D:/BtSoft/temp/session/"
\ No newline at end of file
This diff is collapsed.
# PearProject
**Pear,梨子项目管理系统**
**相关资料:https://www.yuque.com/bzsxmz**
**安装指南:https://www.yuque.com/bzsxmz/siuq1w/kggzna**
需要配合[前端项目](https://github.com/a54552239/pearProject)使用,链接:https://github.com/a54552239/pearProject
有不明白的地方的可以加群:275264059,或者联系我,QQ:545522390
### 演示地址
> [https://home.vilson.xyz](https://home.vilson.xyz)
### 登录 ###
账号:123456 密码:123456
### 友情链接 ###
**JAVA版本:https://gitee.com/wulon/mk-teamwork-server**
### 界面截图 ###
![1](https://static.vilson.xyz/overview/1.png)
![1](https://static.vilson.xyz/overview/2.png)
![1](https://static.vilson.xyz/overview/3.png)
![1](https://cdn.nlark.com/yuque/0/2019/png/196196/1562568905177-dfaae477-7edd-4862-8b73-04af5aa2c174.png)
![1](https://cdn.nlark.com/yuque/0/2019/png/196196/1562568918658-c51079e5-5995-45ad-a073-b89f6919aee0.png)
![1](https://cdn.nlark.com/yuque/0/2019/png/196196/1562568949579-f01eeaca-2052-44d6-be7d-eb58011732f3.png)
![1](https://cdn.nlark.com/yuque/0/2019/png/196196/1562568992455-a8ccee61-3757-42b4-9ffb-0be73ce94d96.png)
![1](https://static.vilson.xyz/overview/8.png)
![1](https://static.vilson.xyz/overview/9.png)
![1](https://static.vilson.xyz/overview/10.png)
![1](https://static.vilson.xyz/overview/11.png)
![1](https://static.vilson.xyz/overview/12.png)
![1](https://cdn.nlark.com/yuque/0/2019/png/196196/1562569075060-d41ae959-fca4-460e-a123-2ccff6ac6208.png)
### 功能设计 ###
![1](https://cdn.nlark.com/yuque/0/2019/png/196196/1562467192538-6a4a949a-1dad-411e-af9f-ddec3f553276.png)
### 鼓励一下 ###
<img src="https://static.vilson.xyz/pay/wechat.png" alt="Sample" width="150" height="150">
<img src="https://static.vilson.xyz/pay/alipay2.png" alt="Sample" width="150" height="150">
deny from all
\ No newline at end of file
<?php
return [
'projectReport' => 'app\common\command\ProjectReport',
];
This diff is collapsed.
<?php
namespace app\common\Model;
use service\ToolsService;
use think\facade\Cache;
class Areas extends CommonModel
{
protected $append = [];
/**
* 构建AntDesign所需的行政区划数据
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function createJsonForAnt()
{
$list = Cache::store('redis')->get('areadData');
if (!$list) {
$list = self::where('id > 100000')->order('id asc')->select()->toArray();
Cache::store('redis')->set('areadData', $list);
}
if ($list) {
$list = ToolsService::arr2tree($list, 'ID', 'ParentId');
}
return $list;
}
}
<?php
namespace app\common\Model;
/**
* 收藏
* Class TaskStar
* @package app\common\Model
*/
class Collection extends CommonModel
{
protected $append = [];
/**
* @param $code
* @param $memberCode
* @param $star
* @return TaskLike|bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function starTask($code, $memberCode, $star)
{
$stared = self::where(['source_code' => $code, 'type' => 'task', 'member_code' => $memberCode])->find();
if ($star && !$stared) {
$data = [
'create_time' => nowTime(),
'code' => createUniqueCode('collection'),
'create_by' => $memberCode,
'source_code' => $code,
'type' => 'task',
'member_code' => $memberCode,
];
return self::create($data);
}
if (!$star) {
return self::where(['source_code' => $code, 'type' => 'task', 'member_code' => $memberCode])->delete();
}
}
}
<?php
namespace app\common\Model;
use service\FileService;
use service\ToolsService;
use think\Db;
use think\facade\Request;
use think\File;
use think\Model;
class CommonModel extends Model
{
/**
* 返回失败的请求
* @param mixed $msg 消息内容
* @param array $data 返回数据
* @param integer $code 返回代码
*/
protected function error($msg, $data = [], $code = 400)
{
ToolsService::error($msg, $data, $code);
}
public static function limitByQuery($sql, $page = 1, $pageSize = 10)
{
if ($page < 1) {
$page = 1;
}
$offset = ($page - 1) * $pageSize;
$limit = $pageSize;
$total = Db::query($sql);
$total = count($total);
$sql .= " limit {$offset},{$limit}";
$list = Db::query($sql);
return ['total' => $total, 'list' => $list, 'page' => $page];
}
/**
* 分页方法
* @param null $where 可以传入查询对象或模型实例
* @param $order
* @param $field
* @param bool $simple 是否简介模式,简介模式不分页
* @param array $config 分页配置,page: 当前页,rows: 每页数量
* @return array
* @throws \think\exception\DbException
*/
public function _list($where = null, $order = 'id desc', $field = null, $simple = false, $config = [])
{
$rows = intval(Request::param('pageSize', cookie('pageSize')));
if (!$rows) {
$rows = 10;
}
cookie('pageSize', $rows);
$config['query'] = Request::param();
$whereOr = [];
if (isset($where['or']) and $where['or']) {
//todo 怎么or连贯查询
/*
* whereOr查询,形式如:
$where['or'][]= ['name','like',"xxx"];
$where['or'][] = ['id','=',"xxx"];
*/
$whereOr = $where['or'];
unset($where['or']);
}
$page = $this->where($where)->whereOr($whereOr)->order($order)->field($field)->paginate($rows, $simple, $config);
$list = $page->all();
$result = ['total' => $simple ? count($list) : $page->total(), 'page' => $page->currentPage(), 'list' => $list];
return $result;
}
public function _listWithTrashed($where = null, $order = null, $field = null, $simple = false, $config = [])
{
$rows = intval(Request::param('rows', cookie('pageSize')));
if (!$rows) {
$rows = 10;
}
cookie('pageSize', $rows);
$config['query'] = Request::param();
$whereOr = [];
if (isset($where['or']) and $where['or']) {
//todo 怎么or连贯查询
/*
* whereOr查询,形式如:
$where['or'][]= ['name','like',"xxx"];
$where['or'][] = ['id','=',"xxx"];
*/
$whereOr = $where['or'];
unset($where['or']);
}
$class = get_class($this);
$count = $class::withTrashed()->where($where)->whereOr($whereOr)->order($order)->field($field)->count();
$page = $config['query']['page'] ? $config['query']['page'] : 1;
$offset = $rows * ($config['query']['page'] - 1);
$list = $class::withTrashed()->where($where)->whereOr($whereOr)->order($order)->field($field)->limit($offset, $rows)->select();
$result = ['total' => $count, 'page' => $page, 'list' => $list];
return $result;
}
public function _edit($data, $where = [])
{
return $this->isUpdate(true)->save($data, $where);
}
public function _add($data)
{
$obj = $this::create($data);
if ($obj->id) {
return $this::get($obj->id);
}
return false;
}
/**
* @param File $file
* @param $path_name
* @return array|bool
* @throws \OSS\Core\OssException
* @throws \think\Exception
* @throws \think\exception\PDOException
* @throws \Exception
*/
public function _uploadImg(File $file, $path_name = '')
{
if (!$path_name) {
$path_name = config('upload.base_path') . config('default');
}
if (!$file->checkExt(strtolower(sysconf('storage_local_exts')))) {
\exception('文件上传类型受限', 1);
}
$path = $path_name;
$info = $file->move($path);
if ($info) {
$filename = str_replace('\\', '/', $path . '/' . $info->getSaveName());
// $image = \think\Image::open($info->getRealPath());
// $image->thumb($image->width() / 2, $image->height() / 2)->save($filename);//压缩
$site_url = FileService::getFileUrl($filename, 'local');
$fileInfo = FileService::save($filename, file_get_contents($site_url));
if ($fileInfo) {
return ['base_url' => $fileInfo['key'], 'url' => $fileInfo['url'], 'filename' => $file->getInfo('name')];
}
}
return false;
}
}
<?php
namespace app\common\Model;
use service\ToolsService;
use think\Db;
/**
* 部门
* Class Organization
* @package app\common\Model
*/
class Department extends CommonModel
{
protected $append = [];
/**
* @param $name
* @param string $parentDepartmentCode
* @return Department
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function createDepartment($name, $parentDepartmentCode = '')
{
$path = '';
if ($parentDepartmentCode) {
$parentDepartment = self::where(['code' => $parentDepartmentCode])->field('code,path')->find();
$parentDepartment['path'] && $parentDepartment['path'] = ",{$parentDepartment['path']}";
$path = "{$parentDepartment['code']}{$parentDepartment['path']}";
}
$data = [
'organization_code' => getCurrentOrganizationCode(),
'code' => createUniqueCode('department'),
'name' => $name,
'pcode' => $parentDepartmentCode,
'path' => $path,
'create_time' => nowTime(),
];
return self::create($data);
}
public function deleteDepartment($departmentCode)
{
$department = self::where(['code' => $departmentCode])->find();
if (!$department) {
throw new \Exception('该部门不存在', 1);
}
$prefix = config('database.prefix');
$sql = "select code from {$prefix}department where find_in_set('{$departmentCode}',path)";
$departments = Db::name('department')->query($sql);
$codes = [$departmentCode];
if ($departments) {
foreach ($departments as $department) {
$codes[] = $department['code'];
}
}
$result = self::whereIn('code', $codes)->delete();
DepartmentMember::whereIn('department_code', $codes)->delete();
return $result;
}
}
<?php
namespace app\common\Model;
use Exception;
use service\RandomService;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\DbException;
/**
* 部门成员
* Class ProjectMember
* @package app\common\Model
*/
class DepartmentMember extends CommonModel
{
protected $append = [];
/**
* @param $accountCode
* @param string $departmentCode 部门code
* @param int $isOwner 是否拥有者
* @param int $isPrincipal 是否负责人
* @return DepartmentMember|MemberAccount
* @throws DataNotFoundException
* @throws ModelNotFoundException
* @throws DbException
*/
public function inviteMember($accountCode, $departmentCode = '', $isOwner = 0, $isPrincipal = 0)
{
$orgCode = getCurrentOrganizationCode();
if ($departmentCode) {
$department = Department::where(['code' => $departmentCode])->find();
if (!$department) {
throw new Exception('该部门不存在', 1);
}
$hasJoined = self::where(['account_code' => $accountCode, 'department_code' => $departmentCode])->find();
if ($hasJoined) {
throw new Exception('已加入该部门', 2);
}
$data = [
'code' => createUniqueCode('departmentMember'),
'account_code' => $accountCode,
'organization_code' => $orgCode,
'department_code' => $departmentCode,
'is_owner' => $isOwner,
'is_principal' => $isPrincipal,
'join_time' => nowTime()
];
$result = self::create($data);
$department_codes = self::where(['account_code' => $accountCode, 'organization_code' => $orgCode])->column('department_code');
if ($department_codes) {
$department_codes = implode(',', $department_codes);
MemberAccount::update(['department_code' => $department_codes], ['code' => $accountCode]);
}
return $result;
} else {
try {
$result = MemberAccount::inviteMember($accountCode, $orgCode);
} catch (Exception $e) {
throw new Exception($e->getMessage(), 3);
}
return $result;
}
}
/**
* @param $accountCode
* @param $departmentCode
* @return bool
* @throws DataNotFoundException
* @throws ModelNotFoundException
* @throws DbException
*/
public function removeMember($accountCode, $departmentCode)
{
$orgCode = getCurrentOrganizationCode();
$department = Department::where(['code' => $departmentCode])->find();
if (!$department) {
throw new Exception('该部门不存在', 1);
}
$hasJoined = self::where(['account_code' => $accountCode, 'department_code' => $departmentCode])->find();
if (!$hasJoined) {
throw new Exception('尚未加入该部门', 2);
}
$result = $hasJoined->delete();
$department_codes = self::where(['account_code' => $accountCode, 'organization_code' => $orgCode])->column('department_code');
!$department_codes && $department_codes = [];
$department_codes = implode(',', $department_codes);
MemberAccount::update(['department_code' => $department_codes], ['code' => $accountCode]);
return $result;
}
/**
* 导入成员
* @param \think\File $file
* @return bool
* @throws Exception
*/
public function uploadFile(\think\File $file)
{
try {
$data = importExcel($file->getInfo()['tmp_name']);
} catch (Exception $e) {
return error('201', $e->getMessage());
}
$count = 0;
if ($data) {
$organizationCode = getCurrentOrganizationCode();
foreach ($data as $key => $item) {
if ($key > 3) {
$name = trim($item['A']);
$email = trim($item['B']);
$departments = trim($item['C']);
$position = trim($item['D']);
$mobile = trim($item['E']);
$password = trim($item['F']);
$description = trim($item['G']);
if (!$name || !$email) {
continue;
}
$member = Member::where(['email' => $email])->find();
if (!$member) {
//注册新账号
$memberData = [
'email' => $email,
'name' => $name,
'account' => RandomService::alnumLowercase(),
'avatar' => 'https://static.vilson.online/cover.png',
'status' => 1,
'code' => createUniqueCode('member'),
'password' => $password ? md5($password) : '',
// 'mobile' => $mobile,
];
try {
$result = Member::createMember($memberData);
} catch (Exception $e) {
return error(1, $e->getMessage());
}
$member = Member::get($result->id);
$memberAccount = MemberAccount::inviteMember($member['code'], $organizationCode, $position, $mobile, '', $description);
if (!isError($memberAccount)) {
$count++;
}
} else {
$memberAccount = MemberAccount::where(['member_code' => $member['code'], 'organization_code' => $organizationCode])->find();
if (!$memberAccount) {
$memberAccount = MemberAccount::inviteMember($member['code'], $organizationCode, $position, $mobile, '', $description);
if (!isError($memberAccount)) {
$count++;
}
}
}
if ($departments) {
$departmentList = explode(';', $departments);
if ($departmentList) {
foreach ($departmentList as $departmentItems) {
$departmentNames = explode('/', $departmentItems);
if ($departmentNames) {
$department = null;
$pcode = '';
foreach ($departmentNames as $key => $departmentName) {
$department = Department::where(['name' => $departmentNames, 'pcode' => $pcode, 'organization_code' => $organizationCode])->find();
if (!$department) {
break;
}
$pcode = $department['code'];
}
if ($department) {
try {
$this->inviteMember($memberAccount['code'], $department['code']);
} catch (Exception $e) {
return error(2, $e->getMessage());
}
}else{
}
}
}
}
} else {
$this->inviteMember($memberAccount['code'], '');
}
}
}
}
return $count;
}
}
<?php
namespace app\common\Model;
use function GuzzleHttp\Promise\task;
use think\Db;
/**
* 文件
* Class TaskStar
* @package app\common\Model
*/
class File extends CommonModel
{
protected $append = ['fullName'];
/**
* @param $projectCode
* @param string $taskCode
* @param $data
* @return File
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function createFile($projectCode, $data)
{
$project = Project::where(['code' => $projectCode])->find();
if (!$project) {
throw new \Exception('该项目已失效', 1);
}
$memberCode = getCurrentMember()['code'];
$orgCode = getCurrentOrganizationCode();
$fileData = [
'code' => createUniqueCode('file'),
'create_by' => $memberCode,
'project_code' => $projectCode,
'organization_code' => $orgCode,
'path_name' => isset($data['path_name']) ? $data['path_name'] : '',
'title' => isset($data['title']) ? $data['title'] : '',
'extension' => isset($data['extension']) ? $data['extension'] : '',
'size' => isset($data['size']) ? $data['size'] : '',
'object_type' => isset($data['object_type']) ? $data['object_type'] : '',
'extra' => isset($data['extra']) ? $data['extra'] : '',
'file_url' => isset($data['file_url']) ? $data['file_url'] : '',
'file_type' => isset($data['file_type']) ? $data['file_type'] : '',
'create_time' => nowTime(),
];
$result = self::create($fileData);
return $result;
}
/**
* 放入回收站
* @param $code
* @return File
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function recycle($code)
{
$info = self::where(['code' => $code])->find();
if (!$info) {
throw new \Exception('文件不存在', 1);
}
if ($info['deleted']) {
throw new \Exception('文件已在回收站', 2);
}
$result = self::update(['deleted' => 1, 'deleted_time' => nowTime()], ['code' => $code]);
return $result;
}
/**
* 恢复文件
* @param $code
* @return File
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function recovery($code)
{
$info = self::where(['code' => $code])->find();
if (!$info) {
throw new \Exception('文件不存在', 1);
}
if (!$info['deleted']) {
throw new \Exception('文件已恢复', 2);
}
$result = self::update(['deleted' => 0], ['code' => $code]);
return $result;
}
public function deleteFile($code)
{
//todo 权限判断
$info = self::where(['code' => $code])->find();
if (!$info) {
throw new \Exception('文件不存在', 1);
}
Db::startTrans();
try {
self::where(['code' => $code])->delete();
//todo 删除物理文件
Db::commit();
} catch (\Exception $e) {
Db::rollback();
throw new \Exception($e->getMessage());
}
return true;
}
public function getFullNameAttr($value, $data)
{
return "{$data['title']}.{$data['extension']}";
}
}
<?php
namespace app\common\Model;
use service\DateService;
/**
* 邀请链接
* Class TaskStar
* @package app\common\Model
*/
class InviteLink extends CommonModel
{
protected $append = [];
/**
* @param $inviteType
* @param $sourceCode
* @param $linkType
* @param $linkCode
* @param int $sort
* @return InviteLink
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function createInvite($inviteType, $sourceCode)
{
$memberCode = getCurrentMember()['code'];
$inviteLink = self::where(['invite_type' => $inviteType, 'source_code' => $sourceCode, 'create_by' => $memberCode])->find();
if ($inviteLink && nowTime() >= $inviteLink['over_time']) {
$inviteLink->delete();
}
$source = $link = null;
switch ($inviteType) {
case 'project':
$source = Project::where(['code' => $sourceCode])->find();
break;
case 'organization':
$source = Organization::where(['code' => $sourceCode])->find();
}
if (!$source) {
throw new \Exception('该资源不存在', 1);
}
if (!$inviteLink) {
$fileData = [
'code' => createUniqueCode('inviteLink'),
'create_by' => $memberCode,
'invite_type' => $inviteType,
'source_code' => $sourceCode,
'create_time' => nowTime(),
'over_time' => Date('Y-m-d H:i:s', strtotime(nowTime()) + 3600 * 24),
];
$result = self::create($fileData);
}else{
$result = $inviteLink;
}
return $result;
}
public static function getInviteDetail($linkCode)
{
$link = self::where(['code' => $linkCode])->find();
$linkDetail = null;
switch ($link['invite_type']) {
case 'project':
$link['name'] = '';
$linkDetail = Project::where(['code' => $link['source_code']])->field('id', true)->find();
if ($linkDetail) {
$link['name'] = $linkDetail['name'];
}
break;
case 'organization':
$link['name'] = '';
$linkDetail = Organization::where(['code' => $link['source_code']])->field('id', true)->find();
if ($linkDetail) {
$link['name'] = $linkDetail['name'];
}
}
$link['member'] = Member::where(['code' => $link['create_by']])->field('id', true)->find();
$link['sourceDetail'] = $linkDetail;
return $link;
}
}
This diff is collapsed.
<?php
namespace app\common\Model;
use Exception;
use service\NodeService;
use think\Db;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\DbException;
use think\exception\PDOException;
use think\File;
class MemberAccount extends CommonModel
{
protected $append = ['statusText', 'authorizeArr'];
/**
* 获取当前用户菜单
* @throws DataNotFoundException
* @throws ModelNotFoundException
* @throws DbException
*/
public static function getAuthMenuList($isTree = true)
{
NodeService::applyProjectAuthNode();
$menuModel = new ProjectMenu();
return $menuModel->listForUser($isTree);
}
/**
* 邀请成员
* @param $memberCode
* @param $organizationCode
* @param string $position
* @param string $mobile
* @param string $department
* @param string $description
* @return MemberAccount
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function inviteMember($memberCode, $organizationCode, $position = '', $mobile = '', $department = '', $description = '')
{
$hasJoined = MemberAccount::where(['member_code' => $memberCode, 'organization_code' => $organizationCode])->find();
if ($hasJoined) {
return error(3, '已加入该组织');
}
$memberDate = Member::where(['code' => $memberCode])->find();
if (!$memberDate) {
return error(4, '该用户不存在');
}
$auth = ProjectAuth::where(['organization_code' => $organizationCode, 'is_default' => 1])->field('id')->find();
$authId = '';
if ($auth) {
$authId = $auth['id'];//权限id
}
$data = [
'position' => $position,
'department' => $department ?? '某某公司-某某某事业群-某某平台部-某某技术部',
'description' => $description ?? '',
'code' => createUniqueCode('memberAccount'),
'member_code' => $memberCode,
'organization_code' => $organizationCode,
'is_owner' => 0,
'authorize' => $authId,
'status' => 1,
'create_time' => nowTime(),
'name' => $memberDate['name'],
'mobile' => $mobile,
'email' => $memberDate['email'],
];
$result = MemberAccount::create($data);
$cacheKey = 'member:orgList:' . $memberCode;
cache($cacheKey, null);
return $result;
}
/**
* @param File $file
* @return array|bool
* @throws \think\Exception
* @throws PDOException
* @throws Exception
*/
public function uploadImg(File $file)
{
return $this->_uploadImg($file, config('upload.base_path') . config('upload.member_avatar'));
}
public function getAccountByOrganization($account, $organization_code)
{
return $this->where(['account' => $account, 'organization_code' => $organization_code])->find();
}
public function getAuthorizeArrAttr($value, $data)
{
//支持同时设置多个角色,默认关闭
if ($data['authorize']) {
return explode(',', $data['authorize']);
}
return [];
}
public function getStatusTextAttr($value, $data)
{
$status = [0 => '禁用', 1 => '使用中'];
return $status[$data['status']];
}
/**
* @param $accountCode
* @return bool
* @throws Exception
*/
public function del($accountCode)
{
//todo 权限判断
try {
Db::startTrans();
$memberAccount = self::where(['code' => $accountCode])->find()->toArray();
self::destroy(['code' => $accountCode]);
$projects = Project::where(['organization_code' => $memberAccount['organization_code']])->column('code');
if ($projects) {
ProjectMember::whereIn('project_code', $projects)->where(['member_code' => $memberAccount['member_code']])->delete();
$orgCode = getCurrentOrganizationCode();
DepartmentMember::where(['account_code' => $accountCode, 'organization_code' => $orgCode])->delete();
}
$cacheKey = 'member:orgList:' . $memberAccount['member_code'];
cache($cacheKey, null);
Db::commit();
} catch (Exception $e) {
Db::rollback();
throw new Exception($e->getMessage(), 201);
}
return true;
}
}
<?php
namespace app\common\Model;
class Notify extends CommonModel
{
/**
* 按type类型格式化输出列表
* @param $where
* @param bool $size
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function listTypeFormat($where, $size = false)
{
$types = ['notice', 'message', 'task'];
$totalSum = [];
$list = $this->where($where)->order('id desc')->select();
$formatList = [];
$total = $this->where($where)->count('id');
if ($list) {
foreach ($types as $type) {
!isset($formatList[$type]) and $formatList[$type] = [];
!isset($totalSum[$type]) and $totalSum[$type] = 0;
$sum = $this->where($where)->where(['type' => $type])->count('id');
$totalSum[$type] = $sum;
}
foreach ($list as &$item) {
foreach ($types as $type) {
if ($size and count($formatList[$type]) >= $size) {
continue;
}
if ($item['type'] == $type) {
$item['from'] = $this->getReceiverByTerminal($item['terminal'], $item['from']);
$item['to'] = $this->getReceiverByTerminal($item['terminal'], $item['to']);
$formatList[$type][] = $item;
// $total++;
}
}
}
}
return ['list' => $formatList, 'total' => $total, 'totalSum' => $totalSum];
}
public function getReceiverByTerminal($terminal, $to)
{
if (!$to) {
return false;
}
switch ($terminal) {
case 'system':
return [];
}
}
public function getFromByType($fromType, $from)
{
if (!$from) {
return false;
}
switch ($fromType) {
case 'project': //消息
return MemberAccount::find($from);
}
}
public function add($title, $content, $type, $from, $to, $action, $send_data, $terminal, $avatar = '', $fromType = 'system')
{
$data = [
'title' => $title,
'content' => $content,
'type' => $type,
'from' => $from,
'to' => $to,
'action' => $action,
'send_data' => $send_data,
'terminal' => $terminal,
'avatar' => $avatar,
'from_type' => $fromType,
'create_time' => nowTime(),
];
return self::create($data);
}
}
<?php
namespace app\common\Model;
use think\Db;
/**
* 组织
* Class Organization
* @package app\common\Model
*/
class Organization extends CommonModel
{
protected $append = [];
/**
* 创建组织
* @param $memberData
* @param array $data
* @return Organization
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function createOrganization($memberData, $data = [])
{
$defaultAdminAuthId = 3;//默认管理员权限id
$defaultMemberAuthId = 4;//默认成员权限id
if (!isset($data['name'])) {
$data['name'] = $memberData['name'] . '的个人项目';
}
$data['code'] = createUniqueCode('organization');
$data['personal'] = 1;
$data['create_time'] = nowTime();
$data['owner_code'] = $memberData['code'];
$organization = self::create($data);
$defaultAdminAuth = ProjectAuth::get($defaultAdminAuthId)->toArray();
$defaultMemberAuth = ProjectAuth::get($defaultMemberAuthId)->toArray();
unset($defaultAdminAuth['id']);
unset($defaultMemberAuth['id']);
$defaultAdminAuth['organization_code'] = $defaultMemberAuth['organization_code'] = $data['code'];
$defaultAdminAuth = ProjectAuth::create($defaultAdminAuth);
$defaultMemberAuth = ProjectAuth::create($defaultMemberAuth);
$defaultAdminAuthNode = ProjectAuthNode::where(['auth' => $defaultAdminAuthId])->select()->toArray();
$defaultMemberAuthNode = ProjectAuthNode::where(['auth' => $defaultMemberAuthId])->select()->toArray();
foreach ($defaultAdminAuthNode as &$item) {
unset($item['id']);
$item['auth'] = $defaultAdminAuth['id'];
ProjectAuthNode::create($item);
}
foreach ($defaultMemberAuthNode as &$item) {
unset($item['id']);
$item['auth'] = $defaultMemberAuth['id'];
ProjectAuthNode::create($item);
}
$memberAccountData = [
'position' => '资深工程师',
'department' => '某某公司-某某某事业群-某某平台部-某某技术部-BM',
'code' => createUniqueCode('organization'),
'member_code' => $memberData['code'],
'organization_code' => $data['code'],
'is_owner' => 1,
'status' => 1,
'create_time' => nowTime(),
'avatar' => $memberData['avatar'],
'name' => $memberData['name'],
'email' => isset($memberData['email']) ? $memberData['email'] : '',
];
MemberAccount::create($memberAccountData);
return $organization;
}
public function edit($code, $data)
{
if (!$code) {
throw new \Exception('请选择组织', 1);
}
$project = self::where(['code' => $code])->field('id', true)->find();
if (!$project) {
throw new \Exception('该组织不存在', 1);
}
$result = self::update($data, ['code' => $code]);
return $result;
}
public static function quitOrganization($memberCode, $orgCode)
{
if (!$orgCode) {
return error(201, '请选择组织');
}
$org = self::where(['code' => $orgCode])->field('id', true)->find();
if (!$org) {
return error(202, '该组织不存在');
}
$hasJoined = MemberAccount::where(['member_code' => $memberCode, 'organization_code' => $orgCode])->find();
if (!$hasJoined) {
return error(203, '尚未加入该组织');
}
Db::startTrans();
try {
$accountCode = $hasJoined['code'];
$hasJoined->delete();
//退出部门
$list = DepartmentMember::where(['account_code' => $accountCode])->select();
if ($list) {
$departmentMemberModel = new DepartmentMember();
foreach ($list as $item) {
$departmentMemberModel->removeMember($accountCode, $item['department_code']);
}
unset($item);
}
//退出项目
$projectMemberList = ProjectMember::alias('pm')->leftJoin('project p', 'p.code = pm.project_code')->where(['pm.member_code' => $memberCode, 'p.organization_code' => $orgCode])->select();
if ($projectMemberList) {
$projectMemberModel = new ProjectMember();
foreach ($projectMemberList as $item) {
$projectMemberModel->removeMember($memberCode, $item['project_code']);
}
}
} catch (\Exception $exception) {
Db::rollback();
return error($exception->getCode(), $exception->getMessage());
}
Db::commit();
return true;
}
}
<?php
namespace app\common\Model;
use service\FileService;
use think\Db;
use think\facade\Hook;
use think\File as thinkFile;
/**
* 项目
* Class Organization
* @package app\common\Model
*/
class Project extends CommonModel
{
protected $append = [];
protected $defaultStages = [['name' => '待处理'], ['name' => '进行中'], ['name' => '已完成']];
public static function getEffectInfo($id)
{
return self::where(['id' => $id, 'deleted' => 0, 'archive' => 0])->find();
}
public function getMemberProjects($memberCode = '',$organizationCode = '', $deleted = 0, $archive = 0, $collection = -1, $page = 1, $pageSize = 10)
{
if (!$memberCode) {
$memberCode = getCurrentMember()['code'];
}
if (!$organizationCode) {
$organizationCode = getCurrentOrganizationCode();
}
if ($page < 1) {
$page = 1;
}
$offset = ($page - 1) * $pageSize;
$limit = $pageSize;
$prefix = config('database.prefix');
$sql = "select *,p.id as id,p.name as name,p.code as code,p.create_time as create_time from {$prefix}project as p join {$prefix}project_member as pm on p.code = pm.project_code left join {$prefix}project_collection as pc on p.code = pc.project_code where pm.member_code = '{$memberCode}' and p.organization_code = '$organizationCode'";
if ($deleted != -1) {
$sql .= " and p.deleted = {$deleted} ";
}
if ($archive != -1) {
$sql .= " and p.archive = {$archive} ";
}
if ($collection == 1) {
$sql .= " and pc.project_code is not null and pc.member_code = '{$memberCode}'";
}
$sql .= "group by p.id order by pc.id desc, p.id desc";
$total = Db::query($sql);
$total = count($total);
$sql .= " limit {$offset},{$limit}";
$list = Db::query($sql);
return ['list' => $list, 'total' => $total];
}
/**
* 创建项目
* @param $memberCode
* @param $orgCode
* @param $name
* @param string $description
* @param string $templateCode
* @return Project
* @throws \Exception
*/
public function createProject($memberCode, $orgCode, $name, $description = '', $templateCode = '')
{
//d85f1bvwpml2nhxe94zu7tyi
Db::startTrans();
try {
$project = [
'create_time' => nowTime(),
'code' => createUniqueCode('project'),
'name' => $name,
'description' => $description,
'organization_code' => $orgCode,
'task_board_theme' => 'simple',
'cover' => FileService::getFilePrefix() . 'static/image/default/project-cover.png'
];
$result = self::create($project);
$projectMemberModel = new ProjectMember();
$projectMemberModel->inviteMember($memberCode, $project['code'], 1);
if ($templateCode) {
$stages = TaskStagesTemplate::where(['project_template_code' => $templateCode])->order('sort desc,id asc')->select();
} else {
$stages = $this->defaultStages;
}
if ($stages) {
foreach ($stages as $key => $stage) {
$taskStage = [
'project_code' => $project['code'],
'name' => $stage['name'],
'sort' => $key,
'code' => createUniqueCode('taskStages'),
'create_time' => nowTime(),
];
$stagesResult = TaskStages::create($taskStage);
$taskStage['id'] = $stagesResult['id'];
}
}
Db::commit();
} catch (\Exception $e) {
Db::rollback();
throw new \Exception($e->getMessage(), 1);
}
self::projectHook(getCurrentMember()['code'], $project['code'], 'create');
return $result;
}
public function edit($code, $data)
{
if (!$code) {
throw new \Exception('请选择项目', 1);
}
$project = self::where(['code' => $code, 'deleted' => 0])->field('id', true)->find();
if (!$project) {
throw new \Exception('该项目在回收站中无法编辑', 1);
}
$result = self::update($data, ['code' => $code]);
//TODO 项目动态
self::projectHook(getCurrentMember()['code'], $code, 'edit');
return $result;
}
/**
* @param File $file
* @return array|bool
* @throws \think\Exception
* @throws \think\exception\PDOException
* @throws \Exception
*/
public function uploadCover(thinkFile $file)
{
return $this->_uploadImg($file);
}
/**
* 放入回收站
* @param $code
* @return Project
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function recycle($code)
{
$info = self::where(['code' => $code])->find();
if (!$info) {
throw new \Exception('项目不存在', 1);
}
if ($info['deleted']) {
throw new \Exception('项目已在回收站', 2);
}
$result = self::update(['deleted' => 1, 'deleted_time' => nowTime()], ['code' => $code]);
self::projectHook(getCurrentMember()['code'], $code, 'recycle');
return $result;
}
/**
* 恢复项目
* @param $code
* @return Project
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function recovery($code)
{
$info = self::where(['code' => $code])->find();
if (!$info) {
throw new \Exception('项目不存在', 1);
}
if (!$info['deleted']) {
throw new \Exception('项目已恢复', 2);
}
$result = self::update(['deleted' => 0], ['code' => $code]);
self::projectHook(getCurrentMember()['code'], $code, 'recovery');
return $result;
}
/**
* 项目归档
* @param $code
* @return Project
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function archive($code)
{
$info = self::where(['code' => $code])->find();
if (!$info) {
throw new \Exception('项目不存在', 1);
}
if ($info['archive']) {
throw new \Exception('项目已归档', 2);
}
$result = self::update(['archive' => 1, 'archive_time' => nowTime()], ['code' => $code]);
self::projectHook(getCurrentMember()['code'], $code, 'archive');
return $result;
}
/**
* 恢复项目
* @param $code
* @return Project
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function recoveryArchive($code)
{
$info = self::where(['code' => $code])->find();
if (!$info) {
throw new \Exception('项目不存在', 1);
}
if (!$info['archive']) {
throw new \Exception('项目已恢复', 2);
}
$result = self::update(['archive' => 0], ['code' => $code]);
self::projectHook(getCurrentMember()['code'], $code, 'recoveryArchive');
return $result;
}
/**
* 退出项目
* @param $code
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \Exception
*/
public function quit($code)
{
$info = self::where(['code' => $code])->find();
if (!$info) {
throw new \Exception('项目不存在', 1);
}
$where = ['project_code' => $code, 'member_code' => getCurrentMember()['code']];
$projectMember = ProjectMember::where($where)->find();
if (!$projectMember) {
throw new \Exception('你不是该项目成员', 2);
}
if ($projectMember['is_owner']) {
throw new \Exception('创建者不能退出项目', 3);
}
$result = ProjectMember::where($where)->delete();
return $result;
}
/** 项目变动钩子
* @param $memberCode
* @param $sourceCode
* @param string $type
* @param string $toMemberCode
* @param int $isComment
* @param string $remark
* @param string $content
* @param string $fileCode
* @param array $data
* @param string $tag
*/
public static function projectHook($memberCode, $sourceCode, $type = 'create', $toMemberCode = '', $isComment = 0, $remark = '', $content = '', $fileCode = '', $data = [], $tag = 'project')
{
$data = ['memberCode' => $memberCode, 'sourceCode' => $sourceCode, 'remark' => $remark, 'type' => $type, 'content' => $content, 'isComment' => $isComment, 'toMemberCode' => $toMemberCode, 'fileCode' => $fileCode, 'data' => $data, 'tag' => $tag];
Hook::listen($tag, $data);
}
}
<?php
namespace app\common\Model;
class ProjectAuth extends CommonModel
{
protected $pk = 'id';
protected $append = ['canDelete'];
/**
* @param $id
* @return bool|int
* @throws \Exception
*/
public function del($id)
{
//TODO 删除该权限后,拥有这个权限的账户将被在设置默认权限
if ($this::destroy($id)) {
$where = ['auth' => $id];
$result = ProjectAuthNode::where($where)->delete();
if ($result !== false) {
return true;
}
}
return false;
}
public function getIdAttr($value)
{
return strval($value);
}
public function getStatusTextAttr($value, $data)
{
$status = [0 => '禁用', 1 => '使用中'];
return $status[$data['status']];
}
public function getCanDeleteAttr($value, $data)
{
if ($data['type'] == 'admin' || $data['type'] == 'member') {
return 0;
}
return 1;
}
}
<?php
namespace app\common\Model;
class ProjectAuthNode extends CommonModel
{
protected $pk = 'id';
public function getIdAttr($value)
{
return strval($value);
}
}
<?php
namespace app\common\Model;
/**
* 项目收藏
* Class ProjectMember
* @package app\common\Model
*/
class ProjectCollection extends CommonModel
{
protected $append = [];
/**
* @param $memberId
* @param $projectId
* @param string $type
* @return ProjectCollection|bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function collect($memberCode, $projectCode, $type = 'collect')
{
$project = Project::where(['code' => $projectCode, 'deleted' => 0])->find();
if (!$project) {
throw new \Exception('该项目已失效', 1);
}
$hasCollected = self::where(['member_code' => $memberCode, 'project_code' => $projectCode])->find();
if ($type == 'collect') {
if ($hasCollected) {
throw new \Exception('该项目已收藏', 1);
}
$data = [
'member_code' => $memberCode,
'project_code' => $projectCode,
'create_time' => nowTime()
];
return self::create($data);
} else {
if (!$hasCollected) {
throw new \Exception('尚未收藏该项目', 1);
}
return self::where(['member_code' => $memberCode, 'project_code' => $projectCode])->delete();
}
}
}
<?php
namespace app\common\Model;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\exception\DbException;
use think\exception\PDOException;
/**
* 版本库
* Class ProjectFeatures
* @package app\common\Model
*/
class ProjectFeatures extends CommonModel
{
protected $append = [];
/**
* 创建版本库
* @param $name
* @param $description
* @param $projectCode
* @param $organizationCode
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function createData($name, $description, $projectCode, $organizationCode)
{
if (!$name) {
return error(1, '请填写版本库名称');
}
$project = Project::where(['code' => $projectCode, 'deleted' => 0])->field('id')->find();
if (!$project) {
return error(3, '该项目已失效');
}
$features = self::where(['name' => $name, 'project_code' => $projectCode])->find();
if ($features) {
return error(2, '该版本库已名称存在');
}
$data = [
'create_time' => nowTime(),
'code' => createUniqueCode('ProjectFeatures'),
'project_code' => $projectCode,
'description' => $description,
'organization_code' => $organizationCode,
'name' => trim($name),
];
$result = self::create($data)->toArray();
return $result;
}
/**
* 删除版本库
* @param $featuresCode
* @return array|bool
* @throws Exception
* @throws PDOException
*/
public function deleteProjectFeatures($featuresCode)
{
if (!$featuresCode) {
return error(1, '请选择一个版本库');
}
self::where(['code' => $featuresCode])->delete();
Task::update(['features_code' => '', 'version_code' => ''], ['features_code' => $featuresCode]);
return true;
}
}
<?php
namespace app\common\Model;
class ProjectInfo extends CommonModel
{
protected $pk = 'id';
/**
* 创建项目信息
* @param $name
* @param $description
* @param $projectCode
* @param $organizationCode
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function createData($name, $value, $description, $projectCode, $organizationCode, $sort = 0)
{
if (!$name) {
return error(1, '请填写项目信息名称');
}
$project = Project::where(['code' => $projectCode, 'deleted' => 0])->field('id')->find();
if (!$project) {
return error(3, '该项目已失效');
}
$data = [
'create_time' => nowTime(),
'code' => createUniqueCode('ProjectInfo'),
'project_code' => $projectCode,
'description' => $description,
'organization_code' => $organizationCode,
'value' => trim($value),
'sort' => $sort,
'name' => trim($name),
];
$result = self::create($data)->toArray();
return $result;
}
}
<?php
namespace app\common\Model;
class ProjectLog extends CommonModel
{
protected $pk = 'id';
}
<?php
namespace app\common\Model;
/**
* 项目成员
* Class ProjectMember
* @package app\common\Model
*/
class ProjectMember extends CommonModel
{
protected $append = [];
/**
* @param $memberCode
* @param $projectCode
* @param int $isOwner
* @return ProjectMember|bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function inviteMember($memberCode, $projectCode, $isOwner = 0)
{
$project = Project::where(['code' => $projectCode, 'deleted' => 0])->find();
if (!$project) {
throw new \Exception('该项目已失效', 1);
}
$hasJoined = self::where(['member_code' => $memberCode, 'project_code' => $projectCode])->find();
if ($hasJoined) {
// throw new \Exception('该成员已加入项目', 1);
return true;
}
$data = [
'member_code' => $memberCode,
'project_code' => $projectCode,
'is_owner' => $isOwner,
'join_time' => nowTime()
];
$result = self::create($data);
MemberAccount::inviteMember($memberCode, $project['organization_code']);
Project::projectHook(getCurrentMember()['code'], $projectCode, 'inviteMember', $memberCode);
return $result;
}
public function removeMember($memberCode, $projectCode)
{
$project = Project::where(['code' => $projectCode, 'deleted' => 0])->find();
if (!$project) {
throw new \Exception('该项目已失效', 1);
}
$hasJoined = self::where(['member_code' => $memberCode, 'project_code' => $projectCode])->find();
if (!$hasJoined) {
// throw new \Exception('该成员尚未加入项目', 1);
return true;
}
if ($hasJoined['is_owner']) {
throw new \Exception('不能移除创建者', 1);
}
$result = $hasJoined->delete();
Project::projectHook(getCurrentMember()['code'], $projectCode, 'removeMember', $memberCode);
return $result;
}
}
<?php
namespace app\common\Model;
use service\NodeService;
use service\ToolsService;
class ProjectMenu extends CommonModel
{
protected $pk = 'id';
protected $append = ["statusText", "innerText", "fullUrl"];
public function getIdAttr($value)
{
return strval($value);
}
public function getStatusTextAttr($value, $data)
{
$status = [0 => '禁用', 1 => '使用中'];
return $status[$data['status']];
}
public function getInnerTextAttr($value, $data)
{
$status = [0 => '导航', 1 => '内页'];
return $status[$data['is_inner']];
}
public function getFullUrlAttr($value, $data)
{
if (($data['params'] and $data['values'] != null) or $data['values'] != '') {
$fullUrl = $data['url'] . '/' . $data['values'];
return $fullUrl;
}
return $data['url'];
}
public function childrenMenu()
{
return $this->hasMany('menu', 'pid')->selfRelation();
}
/**
* 获取所有菜单列表
* @return array|string|\think\Collection
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function treeList()
{
$list = $this->order('sort asc,id asc')->select();
$list = $list->toArray();
if ($list) {
foreach ($list as &$item) {
$item['is_inner'] = !!$item['is_inner'];
$item['show_slider'] = !!$item['show_slider'];
unset($item);
}
}
$list = ToolsService::arr2tree($list);
return $list;
}
/**
* 获取用户对应的菜单列表
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function listForUser($isTree = true)
{
NodeService::applyProjectAuthNode();
$list = $this->where(['status' => '1'])->order('sort asc,id asc')->select();
$list = $list->toArray();
if ($list) {
foreach ($list as &$item) {
$item['is_inner'] = !!$item['is_inner'];
unset($item);
}
}
//主账号不做过滤
$member = getCurrentMember();
$menus = $member['is_owner'] ? $list : $this->filterMenu($list, $member['nodes']);
$new = [];
$isTree && $menus = ToolsService::arr2tree($menus);
$this->buildFilterMenuData($menus, $new);
$isTree && $menus = ToolsService::arr2tree($new);
return $menus;
}
/**
* 过滤没有节点权限的菜单
* @param $menus array 待过滤菜单
* @param $nodes array 拥有的权限节点
* @return array
*/
private function filterMenu($menus, $nodes)
{
$newMenus = [];
foreach ($menus as $key => $menu) {
if ($menu['node'] == '#') {
$newMenus[] = $menu;
} elseif (preg_match('/^https?\:/i', $menu['url'])) {
$newMenus[] = $menu;
continue;
} elseif ($menu['node'] != '#') {
$node = join('/', array_slice(explode('/', preg_replace('/[\W]/', '/', $menu['node'])), 0, 3));
if ($nodes && in_array($node, $nodes)) {
$newMenus[] = $menu;
}
}
}
return $newMenus;
}
/**
* 后台主菜单权限过滤(过滤没有子节点的菜单)
* @param array $menus 当前树形结构的菜单列表
* @param $new array 过滤后的菜单
* @return void
*/
private function buildFilterMenuData($menus, &$new)
{
foreach ($menus as $key => $menu) {
if (($menu['node'] == '#' && isset($menu['children']) && $menu['children']) || ($menu['node'] != '#' && !isset($menu['children'])) || $menu['url'] == 'home') {
$temp = $menu;
unset($temp['children']);
$new[] = $temp;
}
if (isset($menu['children']) && $menu['children']) {
$this->buildFilterMenuData($menu['children'], $new);
}
}
}
/**
* 后台主菜单权限过滤
* @param array $menus 当前菜单列表
* @param array $nodes 系统权限节点数据
* @param bool $isLogin 是否已经登录
* @return array
*/
private function buildMenuData($menus, $nodes, $isLogin)
{
foreach ($menus as $key => &$menu) {
!empty($menu['children']) && $menu['children'] = $this->buildMenuData($menu['children'], $nodes, $isLogin);
if (!empty($menu['children'])) {
$menu['url'] = '#';
} elseif (preg_match('/^https?\:/i', $menu['url'])) {
continue;
} elseif ($menu['node'] != '#') {
$node = join('/', array_slice(explode('/', preg_replace('/[\W]/', '/', $menu['node'])), 0, 3));
if (!in_array($node, $nodes)) {
array_splice($menus, $key, 1);
continue;
}
if (in_array($node, $nodes) && $nodes[$node]['is_login'] && empty($isLogin)) {
array_splice($menus, $key, 1);
} elseif (in_array($node, $nodes) && $nodes[$node]['is_auth'] && $isLogin && !auth($node)) {
array_splice($menus, $key, 1);
}
} else {
array_splice($menus, $key, 1);
}
}
return $menus;
}
public function del($id)
{
$delArr = [$id];
$list = $this::where(['pid' => $id])->select()->toArray();
if ($list) {
foreach ($list as $item) {
$delArr[] = $item['id'];
$list2 = $this::where(['pid' => $item['id']])->select()->toArray();
if ($list2) {
foreach ($list2 as $item2) {
$delArr[] = $item2['id'];
}
}
}
}
return $this::destroy($delArr);
}
}
<?php
namespace app\common\Model;
class ProjectNode extends CommonModel
{
}
<?php
namespace app\common\Model;
use service\DateService;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\DbException;
/**
* 项目报告
* Class ProjectReport
* @package app\common\Model
*/
class ProjectReport extends CommonModel
{
protected $append = [];
protected $json = ['content'];
/**
* 计算最近n天的数据
* @param string $projectCode 项目code
* @param int $day 近n天
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function getReportByDay($projectCode, $day = 10)
{
$dateList = [];
$taskList = [];
$undoneTaskList = [];
$baseLineList = [];
$max = 0;
for ($i = $day; $i >= 1; $i--) {
$date = date('Y-m-d', mktime(0, 0, 0, date("m"), date("d") - $i, date("Y")));
$dateFormat = date('m-d', strtotime($date));
$dateList[] = $dateFormat;
$report = ProjectReport::where(['project_code' => $projectCode, 'date' => $date])->find();
if ($report) {
$task = get_object_vars($report['content']);
$taskList[] = $task['task'];
$undoneTaskList[] = $task['task:undone'];
if ($task['task:undone'] > $max) {
$max = $task['task:undone'];
}
}else{
$taskList[] = 0;
$undoneTaskList[] = 0;
}
}
if ($max) {
$each = round($max / ($day - 1), 1);
$current = $max;
for ($i = 1; $i <= $day; $i++) {
($current < 0 || $day == $i) && $current = 0;
$baseLineList[] = $current;
$current -= $each;
}
}
return ['date' => $dateList, 'task' => $taskList, 'undoneTask' => $undoneTaskList, 'baseLineList' => $baseLineList];
}
public static function setDayilyProejctReport()
{
$day = date('Y-m-d', time());
$taskList = Task::where(['deleted' => 0])->select()->toArray();
if ($taskList) {
$projectList = [];
foreach ($taskList as $task) {
$item = null;
$projectCode = $task['project_code'];
if (!isset($projectList[$projectCode])) {
$projectList[$projectCode] = [];
}
@$projectList[$projectCode]['task']++;
if (!isset($projectList[$projectCode]['task:undone'])) {
$projectList[$projectCode]['task:undone'] = 0;
}
!$task['done'] && @$projectList[$projectCode]['task:undone']++;
}
if ($projectList) {
foreach ($projectList as $key => $project) {
self::setData($key, $day, 'content', $project, true);
}
}
}
return true;
}
/**
* 插入统计数据
* @param string $projectCode 项目编号
* @param string $date 日期 [2019-07-10]
* @param string $key 键
* @param string|array $values 值,值为null则移除该键值对
* @param bool $isContent 是否存储多个content的键值对
* @param bool $replace 是否覆盖content
* @return bool
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function setData($projectCode, $date, $key, $values, $isContent = false, $replace = false)
{
if (!DateService::checkDateIsValid($date, ['Y-m-d'])) {
return error(1, '日期格式不正确');
}
$projet = Project::where(['code' => $projectCode])->field('id')->find();
if (!$projet) {
return error(2, '项目不存在');
}
$saveData = new \stdClass();
$where = ['project_code' => $projectCode, 'date' => $date];
$report = self::where($where)->find();
if ($report) {
$saveData->content = $report->content;
} else {
$report = new self();
$saveData->project_code = $projectCode;
$saveData->date = $date;
$saveData->create_time = nowTime();
$saveData->content = new \stdClass();
}
$saveData->update_time = nowTime();
//值为null则移除该键值对
if ($values === null) {
unset($saveData->content->$key);
return $report->save($saveData);
}
if ($isContent) {
if ($replace) {
//直接替换content
$saveData->content = $values;
} else {
//遍历键值对,赋值到conetnt
if (!is_array($values)) {
$saveData->content->$key = $values;
} else {
foreach ($values as $keyItme => $value) {
//值为null则移除该键值对
if ($value === null) {
unset($saveData->content->$keyItme);
continue;
}
$saveData->content->$keyItme = $value;
}
}
}
} else {
//单个键值对
$saveData->content->$key = $values;
}
return $report->save($saveData);
}
}
<?php
namespace app\common\Model;
use service\FileService;
use service\RandomService;
use think\File;
/**
* 项目模板
* Class Organization
* @package app\common\Model
*/
class ProjectTemplate extends CommonModel
{
protected $append = [];
/**
* 创建项目模板
* @param $memberCode
* @param $orgCode
* @param $name
* @param string $description
* @param string $cover
* @return ProjectTemplate
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function createProjectTemplate($memberCode, $orgCode, $name, $description = '', $cover = '')
{
$data = [
'create_time' => nowTime(),
'code' => createUniqueCode('projectTemplate'),
'member_code' => $memberCode,
'name' => $name,
'description' => $description,
'organization_code' => $orgCode,
'cover' => $cover ?? FileService::getFilePrefix() . 'static/image/default/cover.png'
];
$result = self::create($data);
if ($result) {
$taskStagesList = TaskStagesTemplate::$defaultTaskStagesNameList;
if ($taskStagesList) {
foreach ($taskStagesList as $name) {
TaskStagesTemplate::createTaskStagesTemplate($data['code'], $name);
}
}
}
return $result;
}
/**
* 删除模板
* @param $code
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function deleteTemplate($code)
{
$template = self::where(['code' => $code])->field('id')->find();
if (!$template) {
throw new \Exception('该模板不存在', 1);
}
$result = self::destroy(['code' => $code]);
if (!$result) {
throw new \Exception('删除失败', 2);
}
return TaskStagesTemplate::destroy(['project_template_code' => $code]);
}
/**
* @param File $file
* @return array|bool
* @throws \think\Exception
* @throws \think\exception\PDOException
* @throws \Exception
*/
public function uploadCover(File $file)
{
return $this->_uploadImg($file);
}
}
<?php
namespace app\common\Model;
use PDOStatement;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\exception\DbException;
use think\exception\PDOException;
use think\facade\Hook;
/**
* 版本
* Class ProjectFeatures
* @package app\common\Model
*/
class ProjectVersion extends CommonModel
{
protected $append = ['statusText'];
/**
* 创建版本
* @param $featuresCode
* @param $name
* @param $description
* @param $projectCode
* @param $organizationCode
* @param $startTime
* @param string $planPublishTime
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function createData($featuresCode, $name, $description, $organizationCode, $startTime, $planPublishTime = '')
{
if (!$name) {
return error(1, '请填写版本名称');
}
$projectFeatures = ProjectFeatures::where(['code' => $featuresCode])->field('id')->find();
if (!$projectFeatures) {
return error(3, '该版本库已失效');
}
$version = self::where(['name' => $name, 'features_code' => $featuresCode])->find();
if ($version) {
return error(2, '该版本已名称存在');
}
$data = [
'create_time' => nowTime(),
'code' => createUniqueCode('ProjectVersion'),
'features_code' => $featuresCode,
'start_time' => $startTime,
'plan_publish_time' => $planPublishTime,
'description' => $description,
'organization_code' => $organizationCode,
'name' => trim($name),
];
$result = self::create($data)->toArray();
return $result;
}
/**
* 删除版本
* @param $featuresCode
* @return array|bool
* @throws Exception
* @throws PDOException
*/
public function deleteProjectVersion($versionCode)
{
if (!$versionCode) {
return error(1, '请选择一个版本');
}
ProjectVersion::versionHook(getCurrentMember()['code'], $versionCode, 'delete');
self::where(['code' => $versionCode])->delete();
Task::update(['features_code' => '', 'version_code' => ''], ['version_code' => $versionCode]);
return true;
}
public function changeStatus($versionCode, $status, $publishTime = '')
{
if (!$versionCode) {
return error(1, '请选择一个版本');
}
$updateData = ['status' => $status];
$logType = 'status';
if ($status == 3) {
$updateData['publish_time'] = $publishTime;
$logType = 'publish';
}
self::update($updateData, ['code' => $versionCode]);
ProjectVersion::versionHook(getCurrentMember()['code'], $versionCode, $logType);
return true;
}
public function addVersionTask($taskCode, $versionCode)
{
$task = Task::where(['code' => $taskCode])->field('id,version_code,name')->find();
if (!$task) {
return error(1, '该任务已被失效');
}
if ($task['version_code']) {
return error(1, '该任务已被关联');
}
$version = ProjectVersion::where(['code' => $versionCode])->find();
if (!$version) {
return error(1, '该版本已被失效');
}
$task->version_code = $versionCode;
$task->features_code = $version['features_code'];
$task->save();
self::updateSchedule($versionCode);
return $task;
}
/**
* 移除发布内容
* @param $taskCode
* @return array|PDOStatement|string|\think\Model|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function removeVersionTask($taskCode)
{
$task = Task::where(['code' => $taskCode])->field('id,version_code,name')->find();
if (!$task) {
return error(1, '该任务已被失效');
}
$versionCode = $task['version_code'];
if ($versionCode) {
$task->version_code = '';
$task->features_code = '';
$task->save();
ProjectVersion::versionHook(getCurrentMember()['code'], $versionCode, 'removeVersionTask', '', '', $task['name']);
self::updateSchedule($versionCode);
}
return $task;
}
public static function updateSchedule($versionCode)
{
$version = ProjectVersion::where(['code' => $versionCode])->find();
$taskList = Task::where(['version_code' => $versionCode, 'deleted' => 0])->field('id', true)->select();
$doneTotal = 0;
if ($taskList) {
foreach ($taskList as $task) {
if ($task['done']) {
$doneTotal++;
}
}
$schedule = intval($doneTotal / count($taskList) * 100);
$version->schedule = $schedule;
$version->save();
}
}
public function getStatusTextAttr($value, $data)
{
//状态。0:未开始,1:进行中,2:延期发布,3:已发布
if (!isset($data['status'])) {
return '-';
}
switch ($data['status']) {
case 0:
return '未开始';
case 1:
return '进行中';
case 2:
return '延期发布';
case 3:
return '已发布';
}
}
/**
* 版本变动钩子
* @param $memberCode
* @param $versionCode
* @param string $type
* @param string $remark
* @param string $content
* @param array $data
* @param string $tag
*/
public static function versionHook($memberCode, $versionCode, $type = 'create', $remark = '', $content = '', $data = [], $tag = 'version')
{
$data = ['memberCode' => $memberCode, 'versionCode' => $versionCode, 'remark' => $remark, 'type' => $type, 'content' => $content, 'data' => $data, 'tag' => $tag];
Hook::listen($tag, $data);
}
}
<?php
namespace app\common\Model;
class ProjectVersionLog extends CommonModel
{
protected $pk = 'id';
}
<?php
namespace app\common\Model;
/**
* 资源关联
* Class TaskStar
* @package app\common\Model
*/
class SourceLink extends CommonModel
{
protected $append = [];
/**
* @param $sourceType
* @param $sourceCode
* @param $linkType
* @param $linkCode
* @param int $sort
* @return SourceLink
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function createSource($sourceType, $sourceCode, $linkType, $linkCode, $sort = 0)
{
$source = $link = null;
switch ($sourceType) {
case 'file':
$source = File::where(['code' => $sourceCode])->find();
}
if (!$source) {
throw new \Exception('该资源不存在', 1);
}
switch ($linkType) {
case 'task':
$link = Task::where(['code' => $linkCode])->find();
}
if (!$link) {
throw new \Exception('关联主体不存在', 2);
}
$memberCode = getCurrentMember()['code'];
$orgCode = getCurrentOrganizationCode();
$fileData = [
'code' => createUniqueCode('sourceLink'),
'create_by' => $memberCode,
'organization_code' => $orgCode,
'source_type' => $sourceType,
'source_code' => $sourceCode,
'link_type' => $linkType,
'link_code' => $linkCode,
'sort' => $sort,
'create_time' => nowTime(),
];
$result = self::create($fileData);
if ($linkType == 'task') {
Task::taskHook(getCurrentMember()['code'], $linkCode, 'linkFile', '', 0, '', '', '', ['title' => $source['fullName'], 'url' => $source['file_url']]);
}
return $result;
}
public static function getSourceDetail($sourceCode)
{
$source = self::where(['code' => $sourceCode])->find();
$sourceDetail = null;
switch ($source['source_type']) {
case 'file':
$source['title'] = '';
$sourceDetail = File::where(['code' => $source['source_code']])->field('id', true)->find();
if ($sourceDetail) {
$source['title'] = $sourceDetail['title'];
$project = Project::where(['code' => $sourceDetail['project_code']])->field('name')->find();
$sourceDetail['projectName'] = $project['name'];
}
}
$source['sourceDetail'] = $sourceDetail;
return $source;
}
public function deleteSource($code)
{
$source = self::where(['code' => $code])->find();
if (!$source) {
throw new \Exception('该资源不存在', 1);
}
$source = self::getSourceDetail($code);
$result = self::where(['code' => $code])->delete();
if ($source['link_type'] == 'task') {
Task::taskHook(getCurrentMember()['code'], $source['link_code'], 'unlinkFile', '', 0, '', '', '', ['title' => $source['title'], 'url' => $source['sourceDetail']['file_url']]);
}
return $result;
}
}
<?php
namespace app\common\Model;
class SystemConfig extends CommonModel
{
protected $pk = 'id';
public function info()
{
$config = $this->select();
$data = [];
foreach ($config as $item) {
$data[$item['name']] = $item['value'];
}
return $data;
}
}
<?php
namespace app\common\Model;
class SystemLog extends CommonModel
{
protected $pk = 'id';
public function actionGroup()
{
return $this->group('action')->column('action');
}
}
This diff is collapsed.
<?php
namespace app\common\Model;
/**
* 任务点赞
* Class TaskLike
* @package app\common\Model
*/
class TaskLike extends CommonModel
{
protected $append = [];
/**
* @param $code
* @param $memberCode
* @param $like
* @return TaskLike|bool
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public static function likeTask($code, $memberCode, $like)
{
$liked = self::where(['task_code' => $code, 'member_code' => $memberCode])->find();
if ($like && !$liked) {
$data = [
'create_time' => nowTime(),
'create_by' => $memberCode,
'task_code' => $code,
'member_code' => $memberCode,
];
return self::create($data);
}
if (!$like) {
return self::where(['task_code' => $code, 'member_code' => $memberCode])->delete();
}
}
}
<?php
namespace app\common\Model;
use think\Db;
/**
* 任务成员
* Class ProjectMember
* @package app\common\Model
*/
class TaskMember extends CommonModel
{
protected $append = [];
/**
* @param $memberCode
* @param $taskCode
* @param int $isExecutor
* @param int $isOwner
* @param bool $fromCreate
* @param bool $isRobot 是否机器人
* @return TaskMember|bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function inviteMember($memberCode, $taskCode, $isExecutor = 0, $isOwner = 0, $fromCreate = false, $isRobot = false)
{
!$memberCode && $memberCode = '';
$task = Task::where(['code' => $taskCode, 'deleted' => 0])->find();
if (!$task) {
throw new \Exception('该任务已失效', 1);
}
$currentMember = getCurrentMember();
$taskExecutor = self::where(['is_executor' => 1, 'task_code' => $taskCode])->find(); //原执行者
if ($taskExecutor['member_code'] == $memberCode) {
//已经是本人
return true;
}
if ($isExecutor) {
self::update(['is_executor' => 0], ['task_code' => $taskCode]);
}
if ($memberCode) {
$hasJoined = self::where(['member_code' => $memberCode, 'task_code' => $taskCode])->find();
if ($hasJoined) {
Task::update(['assign_to' => $memberCode], ['code' => $taskCode]);
self::update(['is_executor' => 1], ['task_code' => $taskCode, 'member_code' => $memberCode]);
$logType = 'assign';
if ($memberCode == $currentMember['code']) {
$logType = 'claim';
}
Task::taskHook($currentMember['code'], $taskCode, $logType, $memberCode, 0, '', '', '', ['is_robot' => $isRobot]);
// throw new \Exception('该成员已参与任务', 2);
return true;
}
}
if (!$memberCode) {
//不指派执行人
Task::update(['assign_to' => $memberCode], ['code' => $taskCode]);
if (!$fromCreate) {
if ($taskExecutor) {
Task::taskHook($currentMember['code'], $taskCode, 'removeExecutor', $taskExecutor['member_code'], 0, '', '', '', ['is_robot' => $isRobot]);
}
}
return true;
}
$data = [
'member_code' => $memberCode,
'task_code' => $taskCode,
'is_executor' => $isExecutor,
'is_owner' => $isOwner,
'join_time' => nowTime()
];
//todo 添加任务动态
$result = self::create($data);
if ($isExecutor) {
Task::update(['assign_to' => $memberCode], ['code' => $taskCode]);
if ($memberCode == $currentMember['code']) {
Task::taskHook($currentMember['code'], $taskCode, 'claim','',0, '', '', '', ['is_robot' => $isRobot]);
} else {
Task::taskHook($currentMember['code'], $taskCode, 'assign', $memberCode,0, '', '', '', ['is_robot' => $isRobot]);
}
}
if ($memberCode) {
$projectModel = new ProjectMember();
$projectModel->inviteMember($memberCode, $task['project_code']);
}
return $result;
}
/**
* 批量邀请成员
* @param $memberCodes
* @param $taskCode
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function inviteMemberBatch($memberCodes, $taskCode)
{
$currentMember = getCurrentMember();
if (!$memberCodes) {
return false;
}
$task = Task::where(['code' => $taskCode, 'deleted' => 0])->find();
if (!$task) {
throw new \Exception('该任务已失效', 1);
}
$isAll = false;
if (in_array('all', $memberCodes)) { //全部项目成员
$memberCodes = ProjectMember::where(['project_code' => $task['project_code']])->column('member_code');
$isAll = true;
}
if ($memberCodes) {
Db::startTrans();
try {
$ownerCode = self::where(['is_owner' => 1, 'task_code' => $taskCode])->column('member_code');
foreach ($memberCodes as $memberCode) {
if ($ownerCode == $memberCode) {
//创建者不能被移除
continue;
}
$hasJoined = self::where(['member_code' => $memberCode, 'task_code' => $taskCode])->find();
if ($hasJoined) {
if (!$isAll) {
if ($hasJoined['is_executor']) {
Task::update(['assign_to' => ''], ['code' => $taskCode]);
Task::taskHook($currentMember['code'], $taskCode, 'removeExecutor', $memberCode);
}
self::where(['task_code' => $taskCode, 'member_code' => $memberCode])->delete();
Task::taskHook($currentMember['code'], $taskCode, 'removeMember', $memberCode);
}
} else {
$data = [
'member_code' => $memberCode,
'task_code' => $taskCode,
'is_executor' => 0,
'join_time' => nowTime()
];
self::create($data);
Task::taskHook($currentMember['code'], $taskCode, 'inviteMember', $memberCode);
}
}
Db::commit();
} catch (\Exception $e) {
Db::rollback();
$this->error($e->getMessage(), $e->getCode());;
}
}
}
}
This diff is collapsed.
<?php
namespace app\common\Model;
use service\FileService;
use service\RandomService;
use think\File;
/**
* 任务列表模板
* Class Organization
* @package app\common\Model
*/
class TaskStagesTemplate extends CommonModel
{
protected $append = [];
public static $defaultTaskStagesNameList = ['待处理', '进行中', '已完成'];
/**
* 创建任务列表模板
* @param $projectTemplateCode
* @param $name
* @return TaskStagesTemplate
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function createTaskStagesTemplate($projectTemplateCode, $name)
{
$data = [
'create_time' => nowTime(),
'code' => createUniqueCode('taskStagesTemplate'),
'project_template_code' => $projectTemplateCode,
'name' => $name,
];
$result = self::create($data);
return $result;
}
/**
* 创建任务列表模板
* @param $code
* @param $name
* @param int $sort
* @return TaskStagesTemplate
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function createTemplate($code, $name, $sort = 0)
{
$data = [
'create_time' => nowTime(),
'code' => createUniqueCode('taskStagesTemplate'),
'project_template_code' => $code,
'sort' => $sort,
'name' => $name,
];
$result = self::create($data);
return $result;
}
/**
* 删除模板
* @param $code
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function deleteTemplate($code)
{
$template = self::where(['code' => $code])->field('id')->find();
if (!$template) {
throw new \Exception('该模板不存在', 1);
}
$result = self::destroy(['code' => $code]);
if (!$result) {
throw new \Exception('删除失败', 2);
}
return $result;
}
}
<?php
namespace app\common\Model;
/**
* 任务标签
* Class TaskTag
* @package app\common\Model
*/
class TaskTag extends CommonModel
{
protected $append = [];
/**
* 创建标签
* @param $name
* @param $color
* @param $projectCode
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function createTag($name, $color, $projectCode)
{
if (!$name) {
return error(1, '请填写标签名称');
}
$project = Project::where(['code' => $projectCode, 'deleted' => 0])->field('id')->find();
if (!$project) {
return error(3, '该项目已失效');
}
$tag = self::where(['name' => $name, 'project_code' => $projectCode])->find();
if ($tag) {
return error(2, '该标签已存在');
}
$data = [
'create_time' => nowTime(),
'code' => createUniqueCode('taskTag'),
'project_code' => $projectCode,
'color' => $color,
'name' => trim($name),
];
$result = self::create($data)->toArray();
return $result;
}
/**
* 删除标签
* @param $tagCode
* @return array|bool
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function deleteTag($tagCode)
{
if (!$tagCode) {
return error(1, '请选择一个标签');
}
self::where(['code' => $tagCode])->delete();
TaskToTag::where(['tag_code' => $tagCode])->delete();
return true;
}
/**
* 设置标签
* @param $tagCode
* @param $taskCode
* @return TaskToTag|bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function setTag($tagCode, $taskCode)
{
$data = ['tag_code' => $tagCode, 'task_code' => $taskCode];
$taskToTag = TaskToTag::where($data)->find();
if ($taskToTag) {
return $taskToTag->delete($data);
} else {
$data['create_time'] = nowTime();
$data['code'] = createUniqueCode('taskToTag');
return TaskToTag::create($data);
}
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment