no message

This commit is contained in:
kuaifan 2021-06-02 16:30:40 +08:00
parent 9d24f51845
commit a6bdf9e7ad
25 changed files with 1116 additions and 116 deletions

View File

@ -0,0 +1,144 @@
<?php
namespace App\Http\Controllers\Api;
use App\Models\AbstractModel;
use App\Models\Project;
use App\Models\ProjectColumn;
use App\Models\ProjectLog;
use App\Models\ProjectUser;
use App\Models\User;
use App\Module\Base;
use Request;
/**
* @apiDefine project
*
* 项目
*/
class ProjectController extends AbstractController
{
/**
* 项目列表
*
* @apiParam {Number} [page] 当前页,默认:1
* @apiParam {Number} [pagesize] 每页显示数量,默认:100,最大:200
*/
public function lists()
{
$user = User::authE();
if (Base::isError($user)) {
return $user;
} else {
$user = User::IDE($user['data']);
}
//
$list = Project::join('project_users', 'projects.id', '=', 'project_users.project_id')
->where('project_users.userid', $user->userid)
->orderByDesc('projects.id')
->paginate(Base::getPaginate(200, 100));
//
return Base::retSuccess('success', $list);
}
/**
* 项目详情
*
* @apiParam {Number} project_id 项目ID
*/
public function detail()
{
$user = User::authE();
if (Base::isError($user)) {
return $user;
} else {
$user = User::IDE($user['data']);
}
//
$project_id = intval(Request::input('project_id'));
//
$project = Project::with(['projectColumn' => function($query) {
$query->with(['projectTask' => function($taskQuery) {
$taskQuery->where('parent_id', 0);
}]);
}, 'projectUser'])
->join('project_users', 'projects.id', '=', 'project_users.project_id')
->where('projects.id', $project_id)
->where('project_users.userid', $user->userid)
->first();
//
return Base::retSuccess('success', $project);
}
/**
* 添加项目
*
* @apiParam {String} name 项目名称
* @apiParam {String} [desc] 项目描述
* @apiParam {Array} [columns] 流程,格式[流程1, 流程2]
*/
public function add()
{
$user = User::authE();
if (Base::isError($user)) {
return $user;
} else {
$user = User::IDE($user['data']);
}
//项目名称
$name = trim(Request::input('name', ''));
$desc = trim(Request::input('desc', ''));
if (mb_strlen($name) < 2) {
return Base::retError('项目名称不可以少于2个字');
} elseif (mb_strlen($name) > 32) {
return Base::retError('项目名称最多只能设置32个字');
}
//流程
$columns = Request::input('columns');
if (!is_array($columns)) $columns = [];
$insertColumns = [];
$inorder = 0;
foreach ($columns AS $column) {
$column = trim($column);
if ($column) {
$insertColumns[] = [
'name' => $column,
'inorder' => $inorder++,
];
}
}
if (empty($insertColumns)) {
$insertColumns[] = [
'name' => 'Default',
'inorder' => 0,
];
}
if (count($insertColumns) > 30) {
return Base::retError('项目流程最多不能超过30个');
}
//开始创建
$project = Project::createInstance([
'name' => $name,
'desc' => $desc,
'userid' => $user->userid,
]);
return AbstractModel::transaction(function() use ($user, $insertColumns, $project) {
$project->save();
ProjectUser::createInstance([
'project_id' => $project->id,
'userid' => $user->userid,
'owner' => 1,
])->save();
ProjectLog::createInstance([
'project_id' => $project->id,
'userid' => $user->userid,
'detail' => '创建项目',
])->save();
foreach ($insertColumns AS $column) {
$column['project_id'] = $project->id;
ProjectColumn::createInstance($column)->save();
}
return Base::retSuccess('添加成功!');
});
}
}

View File

@ -311,7 +311,7 @@ class UsersController extends AbstractController
}
/**
* @api {get} api/users/searchinfo 08. 搜索会员列表
* @api {get} api/users/search 08. 搜索会员列表
*
* @apiDescription 搜索会员列表
* @apiVersion 1.0.0
@ -319,65 +319,29 @@ class UsersController extends AbstractController
* @apiName searchinfo
*
* @apiParam {Object} where 搜索条件
* - where.email
* - where.noemail
* - where.username
* - where.nousername
* - where.usernameequal
* - where.noidentity
* - where.identity
* - where.key 昵称、邮箱、用户名
* @apiParam {Number} [take] 获取数量10-100
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function searchinfo()
public function search()
{
$builder = User::select(['userid', 'email', 'username', 'nickname', 'userimg']);
//
$keys = Request::input('where');
$whereArr = [];
$whereRaw = null;
if ($keys['email']) $whereArr[] = ['email', '=', $keys['email']];
if ($keys['usernameequal']) $whereArr[] = ['username', '=', $keys['usernameequal']];
if ($keys['identity']) $whereArr[] = ['identity', 'like', '%,' . $keys['identity'] . ',%'];
if ($keys['noidentity']) $whereArr[] = ['identity', 'not like', '%,' . $keys['noidentity'] . ',%'];
if ($keys['username']) {
$whereRaw.= $whereRaw ? ' AND ' : '';
$whereRaw.= "(`username` LIKE '%" . $keys['username'] . "%' OR `nickname` LIKE '%" . $keys['username'] . "%')";
}
if ($keys['nousername']) {
$nousername = [];
foreach (explode(",", $keys['nousername']) AS $name) {
$name = trim($name);
if ($name && !in_array($name, $nousername)) {
$nousername[] = $name;
}
}
if ($nousername) {
$whereRaw.= $whereRaw ? ' AND ' : '';
$whereRaw.= "(`username` NOT IN ('" . implode("','", $nousername) . "'))";
}
}
if ($keys['noemail']) {
$noemail = [];
foreach (explode(",", $keys['noemail']) AS $email) {
$email = trim($email);
if ($email && !in_array($email, $noemail)) {
$noemail[] = $email;
}
}
if ($noemail) {
$whereRaw.= $whereRaw ? ' AND ' : '';
$whereRaw.= "(`email` NOT IN ('" . implode("','", $noemail) . "'))";
if (is_array($keys)) {
if ($keys['key']) {
$builder->where(function($query) use ($keys) {
$query->where('email', 'like', '%,' . $keys['key'] . ',%')
->orWhere('username', 'like', '%,' . $keys['key'] . ',%')
->orWhere('nickname', 'like', '%,' . $keys['key'] . ',%');
});
}
}
//
$list = User::select(['userid', 'email', 'username', 'nickname', 'userimg'])
->where($whereArr)
->whereRaw($whereRaw)
->orderBy('userid')
->take(Base::getPaginate(100, 10, 'take'))
->get();
$list = $builder->orderBy('userid')->take(Base::getPaginate(100, 10, 'take'))->get();
return Base::retSuccess('success', $list);
}
@ -389,7 +353,7 @@ class UsersController extends AbstractController
* @apiGroup users
* @apiName basic
*
* @apiParam {String} email 会员用户名(多个格式jsonArray一次最多30个)
* @apiParam {Number} userid 会员ID(多个格式jsonArray一次最多30个)
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
@ -397,17 +361,17 @@ class UsersController extends AbstractController
*/
public function basic()
{
$email = trim(Request::input('email'));
$array = Base::json2array($email);
$userid = Request::input('userid');
$array = Base::json2array($userid);
if (empty($array)) {
$array[] = $email;
$array[] = $userid;
}
if (count($array) > 50) {
return Base::retError(['一次最多只能获取%条数据!', 50]);
}
$retArray = [];
foreach ($array AS $name) {
$basic = User::email2basic($name);
foreach ($array AS $id) {
$basic = User::userid2basic($id);
if ($basic) {
$retArray[] = $basic;
}

66
app/Models/Project.php Normal file
View File

@ -0,0 +1,66 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class Project
*
* @package App\Models
* @property int $id
* @property string|null $name 名称
* @property string|null $desc 描述、备注
* @property int|null $userid 创建人
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property \Illuminate\Support\Carbon|null $deleted_at
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectColumn[] $projectColumn
* @property-read int|null $project_column_count
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectLog[] $projectLog
* @property-read int|null $project_log_count
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectUser[] $projectUser
* @property-read int|null $project_user_count
* @method static \Illuminate\Database\Eloquent\Builder|Project newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Project newQuery()
* @method static \Illuminate\Database\Query\Builder|Project onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|Project query()
* @method static \Illuminate\Database\Eloquent\Builder|Project whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Project whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Project whereDesc($value)
* @method static \Illuminate\Database\Eloquent\Builder|Project whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Project whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|Project whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Project whereUserid($value)
* @method static \Illuminate\Database\Query\Builder|Project withTrashed()
* @method static \Illuminate\Database\Query\Builder|Project withoutTrashed()
* @mixin \Eloquent
*/
class Project extends AbstractModel
{
use SoftDeletes;
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function projectColumn(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(projectColumn::class, 'project_id', 'id')->orderByDesc('id');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function projectLog(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(projectLog::class, 'project_id', 'id')->orderByDesc('id');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function projectUser(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(projectUser::class, 'project_id', 'id')->orderByDesc('id');
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace App\Models;
/**
* Class ProjectColumn
*
* @package App\Models
* @property int $id
* @property int|null $project_id 项目ID
* @property string|null $name 列表名称
* @property int|null $inorder 排序(ASC)
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectTask[] $projectTask
* @property-read int|null $project_task_count
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn query()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn whereInorder($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn whereProjectId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn whereUpdatedAt($value)
* @mixin \Eloquent
*/
class ProjectColumn extends AbstractModel
{
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function projectTask(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(projectTask::class, 'column_id', 'id')->orderByDesc('id');
}
}

31
app/Models/ProjectLog.php Normal file
View File

@ -0,0 +1,31 @@
<?php
namespace App\Models;
/**
* Class ProjectLog
*
* @package App\Models
* @property int $id
* @property int|null $project_id 项目ID
* @property int|null $task_id 项目ID
* @property int|null $userid 会员ID
* @property string|null $detail 详细信息
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog query()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereDetail($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereProjectId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereTaskId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereUserid($value)
* @mixin \Eloquent
*/
class ProjectLog extends AbstractModel
{
}

View File

@ -0,0 +1,45 @@
<?php
namespace App\Models;
/**
* Class ProjectTask
*
* @package App\Models
* @property int $id
* @property int|null $parent_id 父级任务ID
* @property int|null $project_id 项目ID
* @property int|null $column_id 列表ID
* @property string|null $name 标题
* @property string|null $desc 描述
* @property string|null $start_at 计划开始时间
* @property string|null $end_at 计划结束时间
* @property string|null $archived_at 归档时间
* @property string|null $complete_at 完成时间
* @property int|null $userid 创建人
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property \Illuminate\Support\Carbon|null $deleted_at
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask query()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereArchivedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereColumnId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereCompleteAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereDesc($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereEndAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereParentId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereProjectId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereStartAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereUserid($value)
* @mixin \Eloquent
*/
class ProjectTask extends AbstractModel
{
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Models;
/**
* Class ProjectTaskContent
*
* @package App\Models
* @property int $id
* @property int|null $project_id 项目ID
* @property int|null $task_id 任务ID
* @property string|null $content 内容
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent query()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent whereContent($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent whereProjectId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent whereTaskId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent whereUpdatedAt($value)
* @mixin \Eloquent
*/
class ProjectTaskContent extends AbstractModel
{
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Models;
/**
* Class ProjectTaskUser
*
* @package App\Models
* @property int $id
* @property int|null $project_id 项目ID
* @property int|null $task_id 任务ID
* @property int|null $userid 成员ID
* @property int|null $owner 是否任务负责人
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser query()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereOwner($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereProjectId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereTaskId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereUserid($value)
* @mixin \Eloquent
*/
class ProjectTaskUser extends AbstractModel
{
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Models;
/**
* Class ProjectUser
*
* @package App\Models
* @property int $id
* @property int|null $project_id 项目ID
* @property int|null $userid 成员ID
* @property int|null $owner 是否负责人
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser query()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereOwner($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereProjectId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereUserid($value)
* @mixin \Eloquent
*/
class ProjectUser extends AbstractModel
{
}

View File

@ -7,7 +7,7 @@ namespace App\Models;
*
* @package App\Models
* @property int $id
* @property string|null $title
* @property string|null $name
* @property string|null $desc 参数描述、备注
* @property string|null $setting
* @property \Illuminate\Support\Carbon|null $created_at
@ -18,8 +18,8 @@ namespace App\Models;
* @method static \Illuminate\Database\Eloquent\Builder|Setting whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Setting whereDesc($value)
* @method static \Illuminate\Database\Eloquent\Builder|Setting whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Setting whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|Setting whereSetting($value)
* @method static \Illuminate\Database\Eloquent\Builder|Setting whereTitle($value)
* @method static \Illuminate\Database\Eloquent\Builder|Setting whereUpdatedAt($value)
* @mixin \Eloquent
*/

View File

@ -7,7 +7,7 @@ namespace App\Models;
*
* @package App\Models
* @property int $id
* @property string|null $title
* @property string|null $name
* @property string|null $value
* @property string|null $content
* @property \Illuminate\Support\Carbon|null $created_at
@ -18,7 +18,7 @@ namespace App\Models;
* @method static \Illuminate\Database\Eloquent\Builder|Tmp whereContent($value)
* @method static \Illuminate\Database\Eloquent\Builder|Tmp whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Tmp whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Tmp whereTitle($value)
* @method static \Illuminate\Database\Eloquent\Builder|Tmp whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|Tmp whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Tmp whereValue($value)
* @mixin \Eloquent

View File

@ -65,16 +65,6 @@ class User extends AbstractModel
'updated_at',
];
/**
* 用户名
* @param $value
* @return string
*/
public function getUsernameAttribute($value)
{
return $value ?: $this->email;
}
/**
* 昵称
* @param $value
@ -88,7 +78,7 @@ class User extends AbstractModel
if ($this->username) {
return $this->username;
}
return Base::getMiddle($this->email, null, "@");
return Base::cardFormat($this->email);
}
/**
@ -367,12 +357,13 @@ class User extends AbstractModel
* @param int $userid 会员ID
* @return self
*/
public static function userid2basic(int $userid)
public static function userid2basic($userid)
{
global $_A;
if (empty($userid)) {
return null;
}
$userid = intval($userid);
if (isset($_A["__static_userid2basic_" . $userid])) {
return $_A["__static_userid2basic_" . $userid];
}

View File

@ -53,7 +53,7 @@ class Base
$log = self::array2json($log, JSON_UNESCAPED_UNICODE);
}
Tmp::createInstance([
'title' => 'log_' . ($title ?: date("Y-m-d H:i:s", time())),
'name' => 'log_' . ($title ?: date("Y-m-d H:i:s", time())),
'value' => date("Y-m-d H:i:s", time()),
'content' => $log,
])->save();
@ -1139,11 +1139,11 @@ class Base
return $_A["__static_setting_" . $setname];
}
$setting = [];
$row = Setting::whereTitle($setname)->first();
$row = Setting::whereName($setname)->first();
if (!empty($row)) {
$setting = Base::string2array($row->setting);
} else {
$row = Setting::createInstance(['title' => $setname]);
$row = Setting::createInstance(['name' => $setname]);
$row->save();
}
if ($array !== false) {
@ -2629,19 +2629,19 @@ class Base
/**
* 缓存数据
* @param $title
* @param $name
* @param null $value
* @return mixed|null
*/
public static function cacheData($title, $value = null)
public static function cacheData($name, $value = null)
{
$title = "cacheData::" . $title;
$tmp = Tmp::where('title', $title)->select('value')->first();
$name = "cacheData::" . $name;
$tmp = Tmp::whereName($name)->select('value')->first();
if ($value !== null) {
if (empty($tmp)) {
Tmp::insert(['title' => $title, 'value' => $value]);
Tmp::createInstance(['name' => $name, 'value' => $value])->save();
} else {
Tmp::where('title', $title)->update(['value' => $value]);
Tmp::whereName($name)->update(['value' => $value]);
}
return $value;
} else {

View File

@ -34,7 +34,7 @@
"dependencies": {
"echarts": "^5.1.1",
"tinymce": "^5.8.1",
"view-design-hi": "^4.5.0-4",
"view-design-hi": "^4.5.0-10",
"vue-clipboard2": "^0.3.1",
"vue-emoji-picker": "^1.0.1",
"vue-kityminder-gg": "^1.3.6",

View File

@ -191,7 +191,13 @@
type: String,
default: ' undo redo | styleselect | uploadImages | uploadFiles | bold italic underline forecolor backcolor | alignleft aligncenter alignright | bullist numlist outdent indent | link image emoticons media codesample | preview screenload',
},
other_options: {
options: {
type: Object,
default: () => {
return {};
}
},
optionFull: {
type: Object,
default: () => {
return {};
@ -262,23 +268,31 @@
methods: {
init() {
this.$nextTick(() => {
tinymce.init(this.concatAssciativeArrays(this.options(false), this.other_options));
tinymce.init(this.concatAssciativeArrays(this.option(false), this.options));
});
},
initTransfer() {
this.$nextTick(() => {
tinymce.init(this.concatAssciativeArrays(this.options(true), this.other_options));
tinymce.init(this.concatAssciativeArrays(this.option(true), this.optionFull));
});
},
options(isFull) {
plugin(isFull) {
if (isFull) {
return this.plugins.filter((val) => val != 'autoresize');
} else {
return this.plugins;
}
},
option(isFull) {
return {
selector: (isFull ? '#T_' : '#') + this.id,
base_url: $A.serverUrl('js/build'),
base_url: $A.serverUrl('js/tinymce'),
language: "zh_CN",
toolbar: this.toolbar,
plugins: this.plugins,
plugins: this.plugin(isFull),
save_onsavecallback: (e) => {
this.$emit('editorSave', e);
},

View File

@ -0,0 +1,138 @@
<template>
<div v-if="ready" class="common-user">
<Select
v-model="values"
:transfer="transfer"
:remote-method="searchUser"
:placeholder="placeholder"
:loading="loading"
:loading-text="$L('加载中...')"
:default-label="value"
:default-event-object="true"
:multipleMax="multipleMax"
multiple
filterable
transfer-class-name="common-user-transfer"
@on-set-default-options="setDefaultOptions">
<div v-if="multipleMax" slot="drop-prepend" class="user-drop-prepend">{{$L('最多只能选择' + multipleMax + '')}}</div>
<Option v-for="(item, key) in lists" :value="item.userid" :key="key" :label="item.nickname" :avatar="item.userimg">
<div class="user-input-option">
<div class="user-input-avatar"><Avatar :src="item.userimg"/></div>
<div class="user-input-nickname">{{ item.nickname }}</div>
<div class="user-input-userid">ID: {{ item.userid }}</div>
</div>
</Option>
</Select>
<div v-if="!initialized" class="common-user-loading"><Loading/></div>
</div>
</template>
<script>
export default {
name: 'UserInput',
props: {
value: {
type: [String, Number, Array],
default: ''
},
placeholder: {
default: ''
},
transfer: {
type: Boolean,
default () {
return true;
}
},
multipleMax: {
type: Number,
}
},
data() {
return {
ready: false,
initialized: false,
loading: false,
values: [],
lists: []
}
},
mounted() {
if (!$A.isArray(this.value)) {
this.$emit('input', [this.value]);
} else {
this.values = $A.cloneJSON(this.value);
}
this.$nextTick(() => {
this.ready = true;
});
},
watch: {
value(val) {
this.values = val;
},
values(val) {
this.$emit('input', val);
}
},
methods: {
setDefaultOptions(options) {
const userids = [];
options.forEach(({value, label}) => {
this.lists.push({
userid: value,
nickname: label,
});
userids.push(value);
});
//
this.$store.commit('getUserBasic', {
userid: userids,
complete: () => {
this.initialized = true;
},
success: (user) => {
let option = options.find(({value}) => value == user.userid);
if (option) {
this.$set(option, 'label', user.nickname)
this.$set(option, 'avatar', user.userimg)
}
this.lists.some((item, index) => {
if (item.userid == user.userid) {
this.$set(this.lists, index, Object.assign(item, user));
}
});
}
});
},
searchUser(query) {
if (query !== '') {
this.loading = true;
$A.apiAjax({
url: 'users/search',
data: {
keys: {
key: query
},
take: 30
},
complete: () => {
this.loading = false;
},
success: ({ret, data, msg}) => {
if (ret === 1) {
this.lists = data;
} else {
this.lists = [];
$A.messageWarning(msg);
}
}
});
} else {
this.lists = [];
}
}
}
};
</script>

View File

@ -21,17 +21,13 @@
<li class="menu-project">
<ul>
<li v-for="(item, key) in projectLists" :key="key" @click="toggleRoute('project/' + item.id)" :class="classNameRoute('project/' + item.id)">{{item.name}}</li>
<li @click="toggleRoute('project/1')" :class="classNameRoute('project/1')"> Daily Task</li>
<li @click="toggleRoute('project/2')" :class="classNameRoute('project/2')"> Meetings Summary</li>
<li @click="toggleRoute('project/3')" :class="classNameRoute('project/3')">🛰 Resources</li>
<li @click="toggleRoute('project/4')" :class="classNameRoute('project/4')">💺 Availibity</li>
<li @click="toggleRoute('project/5')" :class="classNameRoute('project/5')">🍒 Brainstroaming</li>
</ul>
<Loading v-if="projectLoad > 0"/>
</li>
</ul>
<Button class="manage-box-new" type="primary" icon="md-add" @click="addShow=true">New Project</Button>
</div>
<div class="manage-box-main">
<div class="manage-box-body">
<div class="manage-box-body-content">
@ -46,12 +42,11 @@
<Modal
v-model="addShow"
:title="$L('新建项目')"
:closable="false"
:mask-closable="false"
class-name="simple-modal">
<Form ref="addProject" :model="addData" :rules="addRule" label-width="auto" @submit.native.prevent>
<FormItem prop="title" :label="$L('项目名称')">
<Input type="text" v-model="addData.title"></Input>
<FormItem prop="name" :label="$L('项目名称')">
<Input type="text" v-model="addData.name"></Input>
</FormItem>
<FormItem prop="columns" :label="$L('项目模板')">
<Select v-model="addData.template" @on-change="(res) => {$set(addData, 'columns', columns[res].value)}" :placeholder="$L('请选择模板')">
@ -78,7 +73,6 @@
</div>
</template>
<style lang="scss" scoped>
:global {
.manage-box {
@ -244,7 +238,7 @@ export default {
addShow: false,
addData: {
title: '',
name: '',
columns: [],
template: 0,
},
@ -267,8 +261,8 @@ export default {
...mapState(['userId']),
},
watch: {
'$route' (To) {
this.curPath = To.path;
'$route' (route) {
this.curPath = route.path;
},
userId(userid) {
if (userid > 0) {
@ -289,7 +283,7 @@ export default {
value: [this.$L('产品计划'), this.$L('正在设计'), this.$L('正在研发'), this.$L('测试'), this.$L('准备发布'), this.$L('发布成功')],
}];
this.addRule = {
title: [
name: [
{ required: true, message: this.$L('请填写项目名称!'), trigger: 'change' },
{ type: 'string', min: 2, message: this.$L('项目名称至少2个字'), trigger: 'change' }
]

View File

@ -7,23 +7,26 @@
</div>
<div class="project-icobox">
<ul class="project-icons">
<li class="project-icon">
<Icon type="ios-add" />
<li class="project-avatar online">
<Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" />
</li>
<li class="project-icon" @click="addShow=true">
<Icon type="md-add" />
</li>
<li class="project-icon">
<Tooltip theme="light" :always="searchText!=''" transfer>
<Icon type="ios-search-outline" />
<Icon type="ios-search" />
<div slot="content">
<Input v-model="searchText" placeholder="Search task..." clearable autofocus/>
</div>
</Tooltip>
</li>
<li class="project-icon" :class="{'active':$store.state.projectChatShow}" @click="$store.commit('toggleProjectChatShow')">
<Icon type="ios-chatbubbles-outline" />
<Icon type="ios-chatbubbles" />
<Badge :count="999"></Badge>
</li>
<li class="project-avatar online">
<Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" />
<li class="project-icon">
<Icon type="ios-more" />
</li>
</ul>
<div class="project-switch">
@ -595,6 +598,23 @@
</Row>
</div>
</div>
<!--新建项目-->
<Modal
v-model="addShow"
:title="$L('添加任务')"
:styles="{
width: '90%',
maxWidth: '640px'
}"
:mask-closable="false"
class-name="simple-modal">
<TaskAdd v-model="addData"/>
<div slot="footer">
<Button type="default" @click="addShow=false">{{$L('取消')}}</Button>
<Button type="primary" :loading="taskLoad > 0" @click="">{{$L('添加')}}</Button>
</div>
</Modal>
</div>
</template>
@ -639,8 +659,14 @@
justify-content: center;
width: 36px;
height: 36px;
border-radius: 50%;
position: relative;
margin-left: 16px;
cursor: pointer;
transition: all 0.3s;
&:hover {
box-shadow: 0 0 6px #cccccc;
}
&.project-icon {
border-radius: 50%;
background-color: #F2F3F5;
@ -945,7 +971,7 @@
}
.item-icon {
font-size: 12px;
margin-right: 6px;
margin-right: 8px;
color: #777777;
.ivu-icon,
.iconfont {
@ -988,12 +1014,22 @@
<script>
import TaskPriority from "./task-priority";
import TaskAdd from "./task-add";
export default {
name: "ProjectList",
components: {TaskPriority},
components: {TaskAdd, TaskPriority},
data() {
return {
searchText: '',
addShow: false,
addData: {
type: 'task',
owner: 1,
column_id: 5,
times: [],
},
taskLoad: false,
}
},
mounted() {

View File

@ -0,0 +1,181 @@
<template>
<div class="task-add">
<Form class="task-add-form" label-position="top" @submit.native.prevent>
<FormItem :label="$L('任务名称')">
<Input type="text" v-model="value.name"></Input>
</FormItem>
<FormItem :label="$L('任务详情')">
<TEditor v-model="value.content" :plugins="taskPlugins" :options="taskOptions" :option-full="taskOptionFull"></TEditor>
</FormItem>
<Button class="advanced-option" :class="{advanced: advanced}" @click="advanced=!advanced">{{$L('高级选项')}}</Button>
</Form>
<Form v-if="advanced" class="task-add-advanced" label-width="auto" @submit.native.prevent>
<FormItem :label="$L('任务列表')">
<Select
v-model="value.column_id"
:placeholder="$L('选择任务列表')"
:multipleMax="1"
multiple
filterable
transfer
allowCreate
transfer-class-name="task-add-advanced-transfer"
@on-create="columnCreate">
<div slot="drop-prepend" class="task-drop-prepend">{{$L('最多只能选择1项')}}</div>
<Option v-for="(item, key) in columns" :value="item.id" :key="key">{{ item.name }}</Option>
</Select>
</FormItem>
<FormItem :label="$L('计划时间')">
<DatePicker
v-model="value.times"
:options="timeOptions"
:editable="false"
:placeholder="$L('选择计划范围')"
format="yyyy-MM-dd HH:mm"
type="datetimerange"
@on-change="taskTimeChange"/>
</FormItem>
<FormItem :label="$L('项目负责人')">
<UserInput v-model="value.owner" :multiple-max="1" :placeholder="$L('选择项目负责人')"/>
</FormItem>
<div class="subtasks">
<Input type="text" :placeholder="$L('+ 输入子任务,回车添加子任务')"></Input>
</div>
</Form>
</div>
</template>
<script>
import TEditor from "../../../components/TEditor";
import {mapState} from "vuex";
import UserInput from "../../../components/UserInput";
export default {
name: "TaskAdd",
components: {UserInput, TEditor},
props: {
value: {
type: Object,
default: () => {
return {};
}
},
},
data() {
return {
advanced: false,
columns: [],
taskPlugins: [
'advlist autolink lists link image charmap print preview hr anchor pagebreak imagetools',
'searchreplace visualblocks visualchars code',
'insertdatetime media nonbreaking save table contextmenu directionality',
'emoticons paste textcolor colorpicker imagetools codesample',
'autoresize'
],
taskOptions: {
statusbar: false,
menubar: false,
forced_root_block : false,
remove_trailing_brs: false,
autoresize_bottom_margin: 2,
min_height: 200,
max_height: 380,
valid_elements : 'a[href|target=_blank],em,strong/b,div[align],span[style],a,br,img,pre[class],code',
toolbar: 'uploadImages | uploadFiles | bold italic underline forecolor backcolor | codesample | preview screenload'
},
taskOptionFull: {
menubar: 'file edit view',
forced_root_block : false,
remove_trailing_brs: false,
valid_elements : 'a[href|target=_blank],em,strong/b,div[align],span[style],a,br,img,pre[class],code',
toolbar: 'uploadImages | uploadFiles | bold italic underline forecolor backcolor | codesample | preview screenload'
},
timeOptions: {
shortcuts: []
},
}
},
mounted() {
},
computed: {
...mapState(['projectDetail']),
},
watch: {
projectDetail(detail) {
this.columns = detail.project_column;
}
},
methods: {
initLanguage() {
const lastSecond = (e) => {
return new Date($A.formatDate("Y-m-d 23:59:29", Math.round(e / 1000)))
};
this.timeOptions = {
shortcuts: [{
text: this.$L('今天'),
value() {
return [new Date(), lastSecond(new Date().getTime())];
}
}, {
text: this.$L('明天'),
value() {
let e = new Date();
e.setDate(e.getDate() + 1);
return [new Date(), lastSecond(e.getTime())];
}
}, {
text: this.$L('本周'),
value() {
return [$A.getData('今天', true), lastSecond($A.getData('本周结束2', true))];
}
}, {
text: this.$L('本月'),
value() {
return [$A.getData('今天', true), lastSecond($A.getData('本月结束', true))];
}
}, {
text: this.$L('3天'),
value() {
let e = new Date();
e.setDate(e.getDate() + 3);
return [new Date(), lastSecond(e.getTime())];
}
}, {
text: this.$L('5天'),
value() {
let e = new Date();
e.setDate(e.getDate() + 5);
return [new Date(), lastSecond(e.getTime())];
}
}, {
text: this.$L('7天'),
value() {
let e = new Date();
e.setDate(e.getDate() + 7);
return [new Date(), lastSecond(e.getTime())];
}
}]
};
},
columnCreate(val) {
if (!this.columns.find(({id}) => id == val)) {
this.columns.push({
id: val,
name: val
});
}
},
taskTimeChange() {
let tempc = $A.date2string(this.value.times, "Y-m-d H:i");
if (tempc[0] && tempc[1]) {
if ($A.rightExists(tempc[0], '00:00') && $A.rightExists(tempc[1], '00:00')) {
this.$set(this.value.times, 1, tempc[1].replace("00:00", "23:59"));
}
}
},
}
}
</script>

View File

@ -44,11 +44,19 @@ export default {
components: {ProjectMessage, ProjectList},
data() {
return {
project_id: 0,
}
},
mounted() {
this.project_id = this.$route.params.id;
},
watch: {
'$route' (route) {
this.project_id = route.params.id;
},
project_id(id) {
this.$store.commit('getProjectDetail', id);
}
},
}
</script>

View File

@ -1,14 +1,27 @@
export default {
/**
* 切换项目聊天显隐
* @param state
*/
toggleProjectChatShow(state) {
state.projectChatShow = !state.projectChatShow
state.setStorage('projectChatShow', state.projectChatShow);
},
/**
* 切换项目面板显示类型
* @param state
*/
toggleProjectListPanel(state) {
state.projectListPanel = !state.projectListPanel
state.setStorage('projectListPanel', state.projectListPanel);
},
/**
* 更新会员信息
* @param state
* @param info
*/
setUserInfo(state, info) {
const userInfo = state._cloneJSON(info);
userInfo.userid = state._runNum(userInfo.userid);
@ -17,5 +30,73 @@ export default {
state.userId = userInfo.userid;
state.userToken = userInfo.token;
state.setStorage('userInfo', state.userInfo);
},
/**
* 获取项目信息
* @param state
* @param project_id
*/
getProjectDetail(state, project_id) {
if (state._isJson(state.cacheProject[project_id])) {
state.projectDetail = state.cacheProject[project_id];
}
state.projectLoad++;
$A.apiAjax({
url: 'project/detail',
data: {
project_id: project_id,
},
complete: () => {
state.projectLoad--;
},
success: ({ret, data, msg}) => {
if (ret === 1) {
state.projectDetail = state.cacheProject[project_id] = data;
} else {
$A.modalError(msg);
}
}
});
},
/**
* 获取用户基本信息
* @param state
* @param params {userid, success, complete}
*/
getUserBasic(state, params) {
if (!state._isJson(params)) {
return;
}
const {userid, success, complete} = params;
if (typeof success === "function") {
if (state._isArray(userid)) {
userid.forEach((uid) => {
state.cacheUserBasic[uid] && success(state.cacheUserBasic[uid], false)
});
} else {
state.cacheUserBasic[userid] && success(state.cacheUserBasic[userid], false)
}
}
$A.apiAjax({
url: 'users/basic',
data: {
userid: userid
},
complete: () => {
typeof complete === "function" && complete()
},
success: ({ret, data, msg}) => {
if (ret === 1) {
data.forEach((item) => {
state.cacheUserBasic[item.userid] = item;
typeof success === "function" && success(item, true)
});
} else {
$A.modalError(msg);
}
}
});
}
}

View File

@ -172,4 +172,10 @@ export default Object.assign(stateCommon, {
userId,
userInfo,
userToken,
projectLoad: 0,
projectDetail: {},
cacheProject: {},
cacheUserBasic: {},
})

View File

@ -24,10 +24,47 @@
top: 35px;
padding-bottom: 35px;
}
}
.ivu-modal-header,
.ivu-modal-footer {
border-color: transparent;
&.ivu-modal-fullscreen {
top: 0;
}
.ivu-modal-header,
.ivu-modal-footer {
border-color: transparent;
}
.ivu-modal-header {
padding: 22px 24px 20px;
.ivu-modal-header-inner {
font-size: 18px;
}
}
.ivu-modal-body {
padding: 16px 32px 2px;
}
.ivu-modal-footer {
padding: 20px 30px 22px;
.ivu-btn {
height: 34px;
line-height: 32px;
padding: 0 32px;
}
}
.ivu-modal-content {
border-radius: 18px;
.ivu-modal-close {
.ivu-icon-ios-close {
font-size: 38px;
top: 3px;
right: 2px;
transition: all 0.2s;
}
&:hover {
.ivu-icon-ios-close {
transform: rotate(-90deg);
}
}
}
}
}
.form-network-add-tabs {
@ -283,3 +320,138 @@
}
}
}
.task-add {
.task-add-form,
.task-add-advanced {
margin: 0 0 -18px;
.ivu-form-item-label {
font-weight: 600;
}
.ivu-input,
.ivu-select-selection {
border-color: #e8e8e8;
}
.teditor-box {
.tox-tinymce {
border-color: #e8e8e8;
}
.tox .tox-statusbar,
.tox .tox-menubar+.tox-toolbar,
.tox .tox-menubar+.tox-toolbar-overlord .tox-toolbar__primary,
.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type) {
border-color: #e8e8e8;
}
.tox .tox-toolbar,
.tox .tox-toolbar__overflow,
.tox .tox-toolbar__primary {
background-image: none;
border-bottom: 1px solid #e8e8e8;
}
}
.advanced-option {
margin-top: -6px;
transition: margin 0.2s;
z-index: 1;
&.advanced {
margin-left: 22px;
}
&:focus {
box-shadow: none;
}
}
}
.task-add-advanced {
margin: 0;
padding: 34px 32px 6px;
border-radius: 8px;
border: 1px solid #e8e8e8;
.subtasks {
margin-bottom: 24px;
padding: 12px 16px;
border-radius: 6px;
background-color: #f8f8f8;
.ivu-input {
background: transparent;
border-color: transparent;
&:hover,
&:focus {
box-shadow: none;
}
}
}
.ivu-date-picker {
width: 100%;
}
}
}
.task-add-advanced-transfer {
.task-drop-prepend {
text-align: center;
color: #c5c8ce;
line-height: 20px;
padding-bottom: 5px;
font-size: 12px;
border-bottom: 1px solid #f1f1f1;
margin-bottom: 5px;
}
}
.common-user {
position: relative;
.common-user-loading {
position: absolute;
top: 2px;
bottom: 0;
right: 10px;
display: flex;
align-items: center;
.common-loading {
width: 14px;
height: 14px;
}
}
}
.common-user-transfer {
.user-input-option {
display: flex;
align-items: center;
.user-input-avatar {
.ivu-avatar {
width: 26px;
height: 26px;
}
}
.user-input-nickname {
margin-left: 10px;
flex: 1;
}
.user-input-userid {
margin-left: 10px;
font-size: 12px;
color: #cccccc;
transition: margin 0.1s;
}
}
.ivu-select-item {
&.ivu-select-item-selected {
&:after {
top: 8px;
}
.user-input-option {
.user-input-userid {
margin-right: 16px;
}
}
}
}
.user-drop-prepend {
text-align: center;
color: #c5c8ce;
line-height: 20px;
padding-bottom: 5px;
font-size: 12px;
border-bottom: 1px solid #f1f1f1;
margin-bottom: 5px;
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,6 @@
<?php
use App\Http\Controllers\Api\ProjectController;
use App\Http\Controllers\Api\UsersController;
use App\Http\Controllers\IndexController;
use Illuminate\Support\Facades\Route;
@ -16,7 +17,6 @@ use Illuminate\Support\Facades\Route;
*/
/**
* 接口
*/
@ -24,6 +24,9 @@ Route::prefix('api')->middleware(['webapi'])->group(function () {
// 会员
Route::any('users/{method}', UsersController::class);
Route::any('users/{method}/{action}', UsersController::class);
//项目
Route::any('project/{method}', ProjectController::class);
Route::any('project/{method}/{action}', ProjectController::class);
});
/**