Compare commits

..

No commits in common. "master" and "v0.6.26" have entirely different histories.

2117 changed files with 363770 additions and 50733 deletions

View File

@ -19,7 +19,7 @@ jobs:
uses: loopwerk/tag-changelog@v1 uses: loopwerk/tag-changelog@v1
with: with:
token: ${{ secrets.GH_PAT }} token: ${{ secrets.GH_PAT }}
exclude_types: other,chore,build exclude_types: other,chore
- name: Create release - name: Create release
uses: actions/create-release@latest uses: actions/create-release@latest

1
.gitignore vendored
View File

@ -19,6 +19,7 @@ Homestead.yaml
npm-debug.log npm-debug.log
yarn-error.log yarn-error.log
test.* test.*
composer.lock
package-lock.json package-lock.json
laravels-timer-process.pid laravels-timer-process.pid
.DS_Store .DS_Store

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "resources/drawio"]
path = resources/drawio
url = https://github.com/jgraph/drawio.git

View File

@ -5,15 +5,10 @@ English | **[中文文档](./README_CN.md)**
- [Screenshot Preview](README_PREVIEW.md) - [Screenshot Preview](README_PREVIEW.md)
- [Demo site](http://www.dootask.com/) - [Demo site](http://www.dootask.com/)
**QQ Group**
Group No.: `546574618`
## Setup ## Setup
- `Docker` & `Docker Compose v2.0+` must be installed > `Docker` & `Docker Compose v2.0+` must be installed
- System: `Centos/Debian/Ubuntu/macOS`
- Hardware suggestion: 2 cores and above 2G memory
### Deployment project ### Deployment project
@ -21,9 +16,9 @@ Group No.: `546574618`
# 1、Clone the repository # 1、Clone the repository
# Clone projects on github # Clone projects on github
git clone --depth=1 https://github.com/kuaifan/dootask.git git clone https://github.com/kuaifan/dootask.git
# Or you can use gitee # Or you can use gitee
git clone --depth=1 https://gitee.com/aipaw/dootask.git git clone https://gitee.com/aipaw/dootask.git
# 2、Enter directory # 2、Enter directory
cd dootask cd dootask
@ -54,28 +49,18 @@ cd dootask
./cmd start ./cmd start
``` ```
### Development compilation
```bash
# Development mode, Mac OS only
./cmd dev
# Production projects, macOS only
./cmd prod
```
### Shortcuts for running command ### Shortcuts for running command
```bash ```bash
# You can do this using the following command # You can do this using the following command
./cmd artisan "your command" # To run a artisan command ./cmd artisan "your command" // To run a artisan command
./cmd php "your command" # To run a php command ./cmd php "your command" // To run a php command
./cmd nginx "your command" # To run a nginx command ./cmd nginx "your command" // To run a nginx command
./cmd redis "your command" # To run a redis command ./cmd redis "your command" // To run a redis command
./cmd composer "your command" # To run a composer command ./cmd composer "your command" // To run a composer command
./cmd supervisorctl "your command" # To run a supervisorctl command ./cmd supervisorctl "your command" // To run a supervisorctl command
./cmd test "your command" # To run a phpunit command ./cmd test "your command" // To run a phpunit command
./cmd mysql "your command" # To run a mysql command (backup: Backup database, recovery: Restore database) ./cmd mysql "your command" // To run a mysql command (backup: Backup database, recovery: Restore database)
``` ```
### NGINX PROXY SSL ### NGINX PROXY SSL
@ -113,3 +98,7 @@ git pull
# Enter directory and run command # Enter directory and run command
./cmd uninstall ./cmd uninstall
``` ```
## Contact us
QQ Group: 546574618

View File

@ -5,15 +5,10 @@
- [截图预览](README_PREVIEW.md) - [截图预览](README_PREVIEW.md)
- [演示站点](http://www.dootask.com/) - [演示站点](http://www.dootask.com/)
**QQ交流群**
- QQ群号: `546574618`
## 安装程序 ## 安装程序
- 必须安装:`Docker``Docker Compose v2.0+` > 必须安装 `Docker``Docker Compose v2.0+`
- 支持环境:`Centos/Debian/Ubuntu/macOS`
- 硬件建议2核2G以上
### 部署项目 ### 部署项目
@ -21,9 +16,9 @@
# 1、克隆项目到您的本地或服务器 # 1、克隆项目到您的本地或服务器
# 通过github克隆项目 # 通过github克隆项目
git clone --depth=1 https://github.com/kuaifan/dootask.git git clone https://github.com/kuaifan/dootask.git
# 或者你也可以使用gitee # 或者你也可以使用gitee
git clone --depth=1 https://gitee.com/aipaw/dootask.git git clone https://gitee.com/aipaw/dootask.git
# 2、进入目录 # 2、进入目录
cd dootask cd dootask
@ -54,29 +49,18 @@ cd dootask
./cmd start ./cmd start
``` ```
### 开发编译
```bash
# 开发模式仅限macOS
./cmd dev
# 编译项目仅限macOS
./cmd prod
```
### 运行命令的快捷方式 ### 运行命令的快捷方式
```bash ```bash
# 你可以使用以下命令来执行 # 你可以使用以下命令来执行
./cmd artisan "your command" # 运行 artisan 命令 ./cmd artisan "your command" // 运行 artisan 命令
./cmd php "your command" # 运行 php 命令 ./cmd php "your command" // 运行 php 命令
./cmd nginx "your command" # 运行 nginx 命令 ./cmd nginx "your command" // 运行 nginx 命令
./cmd redis "your command" # 运行 redis 命令 ./cmd redis "your command" // 运行 redis 命令
./cmd composer "your command" # 运行 composer 命令 ./cmd composer "your command" // 运行 composer 命令
./cmd supervisorctl "your command" # 运行 supervisorctl 命令 ./cmd supervisorctl "your command" // 运行 supervisorctl 命令
./cmd test "your command" # 运行 phpunit 命令 ./cmd test "your command" // 运行 phpunit 命令
./cmd mysql "your command" # 运行 mysql 命令 (backup: 备份数据库recovery: 还原数据库) ./cmd mysql "your command" // 运行 mysql 命令 (backup: 备份数据库recovery: 还原数据库)
``` ```
### NGINX 代理 SSL ### NGINX 代理 SSL
@ -114,3 +98,7 @@ git pull
# 进入项目所在目录,运行以下命令 # 进入项目所在目录,运行以下命令
./cmd uninstall ./cmd uninstall
``` ```
## 联系我们
QQ群号: 546574618

View File

@ -2,7 +2,6 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Models\File;
use App\Models\ProjectTask; use App\Models\ProjectTask;
use App\Models\ProjectTaskFile; use App\Models\ProjectTaskFile;
use App\Models\User; use App\Models\User;
@ -11,9 +10,7 @@ use App\Models\WebSocketDialogMsg;
use App\Models\WebSocketDialogMsgRead; use App\Models\WebSocketDialogMsgRead;
use App\Models\WebSocketDialogUser; use App\Models\WebSocketDialogUser;
use App\Module\Base; use App\Module\Base;
use Carbon\Carbon;
use Request; use Request;
use Response;
/** /**
* @apiDefine dialog * @apiDefine dialog
@ -41,10 +38,9 @@ class DialogController extends AbstractController
{ {
$user = User::auth(); $user = User::auth();
// //
$list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at']) $list = WebSocketDialog::select(['web_socket_dialogs.*'])
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id') ->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
->where('u.userid', $user->userid) ->where('u.userid', $user->userid)
->orderByDesc('u.top_at')
->orderByDesc('web_socket_dialogs.last_at') ->orderByDesc('web_socket_dialogs.last_at')
->paginate(Base::getPaginate(200, 100)); ->paginate(Base::getPaginate(200, 100));
$list->transform(function (WebSocketDialog $item) use ($user) { $list->transform(function (WebSocketDialog $item) use ($user) {
@ -164,35 +160,23 @@ class DialogController extends AbstractController
} }
/** /**
* @api {get} api/dialog/msg/unread 05. 获取未读消息数量 * @api {get} api/dialog/msg/sendtext 05. 未读消息
* *
* @apiDescription 需要token身份 * @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup dialog * @apiGroup dialog
* @apiName msg__unread * @apiName msg__sendtext
*
* @apiParam {Number} [dialog_id] 对话ID留空获取总未读消息数量
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/ */
public function msg__unread() public function msg__unread()
{ {
$dialog_id = intval(Request::input('dialog_id')); $unread = WebSocketDialogMsgRead::whereUserid(User::userid())->whereReadAt(null)->count();
//
$builder = WebSocketDialogMsgRead::whereUserid(User::userid())->whereReadAt(null);
if ($dialog_id > 0) {
$builder->whereDialogId($dialog_id);
}
$unread = $builder->count();
return Base::retSuccess('success', [ return Base::retSuccess('success', [
'unread' => $unread, 'unread' => $unread,
]); ]);
} }
/** /**
* @api {post} api/dialog/msg/sendtext 06. 发送消息 * @api {get} api/dialog/msg/sendtext 06. 发送消息
* *
* @apiDescription 需要token身份 * @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -208,7 +192,6 @@ class DialogController extends AbstractController
*/ */
public function msg__sendtext() public function msg__sendtext()
{ {
Base::checkClientVersion('0.8.1');
$user = User::auth(); $user = User::auth();
// //
$chat_nickname = Base::settingFind('system', 'chat_nickname'); $chat_nickname = Base::settingFind('system', 'chat_nickname');
@ -219,8 +202,8 @@ class DialogController extends AbstractController
} }
} }
// //
$dialog_id = Base::getPostInt('dialog_id'); $dialog_id = intval(Request::input('dialog_id'));
$text = trim(Base::getPostValue('text')); $text = trim(Request::input('text'));
// //
if (mb_strlen($text) < 1) { if (mb_strlen($text) < 1) {
return Base::retError('消息内容不能为空'); return Base::retError('消息内容不能为空');
@ -230,21 +213,11 @@ class DialogController extends AbstractController
// //
WebSocketDialog::checkDialog($dialog_id); WebSocketDialog::checkDialog($dialog_id);
// //
if (mb_strlen($text) > 2000) { $msg = [
$array = mb_str_split($text, 2000); 'text' => $text
} else { ];
$array = [$text];
}
// //
$list = []; return WebSocketDialogMsg::sendMsg($dialog_id, 'text', $msg, $user->userid);
foreach ($array as $item) {
$res = WebSocketDialogMsg::sendMsg($dialog_id, 'text', ['text' => $item], $user->userid);
if (Base::isSuccess($res)) {
$list[] = $res['data'];
}
}
//
return Base::retSuccess('发送成功', $list);
} }
/** /**
@ -272,7 +245,7 @@ class DialogController extends AbstractController
// //
$dialog = WebSocketDialog::checkDialog($dialog_id); $dialog = WebSocketDialog::checkDialog($dialog_id);
// //
$path = "uploads/chat/" . date("Ym") . "/" . $dialog_id . "/"; $path = "uploads/chat/" . $user->userid . "/";
$image64 = Base::getPostValue('image64'); $image64 = Base::getPostValue('image64');
$fileName = Base::getPostValue('filename'); $fileName = Base::getPostValue('filename');
if ($image64) { if ($image64) {
@ -284,7 +257,7 @@ class DialogController extends AbstractController
} else { } else {
$data = Base::upload([ $data = Base::upload([
"file" => Request::file('files'), "file" => Request::file('files'),
"type" => 'more', "type" => 'file',
"path" => $path, "path" => $path,
"fileName" => $fileName, "fileName" => $fileName,
]); ]);
@ -354,137 +327,4 @@ class DialogController extends AbstractController
$read = WebSocketDialogMsgRead::whereMsgId($msg_id)->get(); $read = WebSocketDialogMsgRead::whereMsgId($msg_id)->get();
return Base::retSuccess('success', $read ?: []); return Base::retSuccess('success', $read ?: []);
} }
/**
* @api {get} api/dialog/msg/detail 09. 消息详情
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup dialog
* @apiName msg__detail
*
* @apiParam {Number} msg_id 消息ID
* @apiParam {String} only_update_at 仅获取update_at字段
* - no (默认)
* - yes
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function msg__detail()
{
User::auth();
//
$msg_id = intval(Request::input('msg_id'));
$only_update_at = Request::input('only_update_at', 'no');
//
$dialogMsg = WebSocketDialogMsg::whereId($msg_id)->first();
if (empty($dialogMsg)) {
return Base::retError("文件不存在");
}
//
if ($only_update_at == 'yes') {
return Base::retSuccess('success', [
'id' => $dialogMsg->id,
'update_at' => Carbon::parse($dialogMsg->updated_at)->toDateTimeString()
]);
}
//
$data = $dialogMsg->toArray();
//
if ($data['type'] == 'file') {
$msg = Base::json2array($dialogMsg->getRawOriginal('msg'));
$msg = File::formatFileData($msg);
$data['content'] = $msg['content'];
$data['file_mode'] = $msg['file_mode'];
}
//
return Base::retSuccess('success', $data);
}
/**
* @api {get} api/dialog/msg/download 10. 文件下载
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup dialog
* @apiName msg__download
*
* @apiParam {Number} msg_id 消息ID
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function msg__download()
{
User::auth();
//
$msg_id = intval(Request::input('msg_id'));
//
$msg = WebSocketDialogMsg::whereId($msg_id)->first();
if (empty($msg)) {
abort(403, "This file not exist.");
}
if ($msg->type != 'file') {
abort(403, "This file not support download.");
}
$array = Base::json2array($msg->getRawOriginal('msg'));
//
return Response::download(public_path($array['path']), $array['name']);
}
/**
* @api {get} api/dialog/msg/withdraw 11. 聊天消息撤回
*
* @apiDescription 消息撤回限制24小时内需要token身份
* @apiVersion 1.0.0
* @apiGroup dialog
* @apiName msg__withdraw
*
* @apiParam {Number} msg_id 消息ID
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function msg__withdraw()
{
$user = User::auth();
$msg_id = intval(Request::input("msg_id"));
$msg = WebSocketDialogMsg::whereId($msg_id)->whereUserid($user->userid)->first();
if (empty($msg)) {
return Base::retError("消息不存在或已被删除");
}
$msg->deleteMsg();
return Base::retSuccess("success");
}
/**
* @api {get} api/dialog/top 12. 会话置顶
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup dialog
* @apiName top
*
* @apiParam {Number} dialog_id 会话ID
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function top()
{
$user = User::auth();
$dialogId = intval(Request::input('dialog_id'));
$dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
if (!$dialogUser) {
return Base::retError("会话不存在");
}
$dialogUser->top_at = $dialogUser->top_at ? null : Carbon::now();
$dialogUser->save();
return Base::retSuccess("success", $dialogId);
}
} }

View File

@ -2,7 +2,7 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Exceptions\ApiException;
use App\Models\AbstractModel; use App\Models\AbstractModel;
use App\Models\File; use App\Models\File;
use App\Models\FileContent; use App\Models\FileContent;
@ -11,7 +11,6 @@ use App\Models\FileUser;
use App\Models\User; use App\Models\User;
use App\Module\Base; use App\Module\Base;
use App\Module\Ihttp; use App\Module\Ihttp;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Request; use Request;
@ -206,30 +205,22 @@ class FileController extends AbstractController
'folder', 'folder',
'document', 'document',
'mind', 'mind',
'drawio', 'sheet',
'flow',
'word', 'word',
'excel', 'excel',
'ppt', 'ppt',
])) { ])) {
return Base::retError('类型错误'); return Base::retError('类型错误');
} }
$ext = str_replace([ $ext = '';
'folder', if (in_array($type, [
'document',
'mind',
'drawio',
'word', 'word',
'excel', 'excel',
'ppt', 'ppt',
], [ ])) {
'', $ext = str_replace(['word', 'excel', 'ppt'], ['docx', 'xlsx', 'pptx'], $type);
'md', }
'mind',
'drawio',
'docx',
'xlsx',
'pptx',
], $type);
// //
$userid = $user->userid; $userid = $user->userid;
if ($pid > 0) { if ($pid > 0) {
@ -302,19 +293,9 @@ class FileController extends AbstractController
'userid' => $userid, 'userid' => $userid,
'created_id' => $user->userid, 'created_id' => $user->userid,
]); ]);
$data = AbstractModel::transaction(function() use ($file) { $file->save();
$content = FileContent::select(['content', 'text', 'size'])->whereFid($file->cid)->orderByDesc('id')->first();
$file->size = $content?->size ?: 0;
$file->save();
if ($content) {
$content = $content->toArray();
$content['fid'] = $file->id;
$content['userid'] = $file->userid;
FileContent::createInstance($content)->save();
}
return File::find($file->id);
});
// //
$data = File::find($file->id);
$data->pushMsg('add', $data); $data->pushMsg('add', $data);
return Base::retSuccess('复制成功', $data); return Base::retSuccess('复制成功', $data);
} }
@ -327,7 +308,7 @@ class FileController extends AbstractController
* @apiGroup file * @apiGroup file
* @apiName move * @apiName move
* *
* @apiParam {Numbers} ids 文件ID(格式:[id1, id2] * @apiParam {Number} id 文件ID
* @apiParam {Number} pid 移动到的文件夹ID * @apiParam {Number} pid 移动到的文件夹ID
* *
* @apiSuccess {Number} ret 返回状态码1正确、0错误 * @apiSuccess {Number} ret 返回状态码1正确、0错误
@ -338,45 +319,30 @@ class FileController extends AbstractController
{ {
$user = User::auth(); $user = User::auth();
// //
$ids = Request::input('ids'); $id = intval(Request::input('id'));
$pid = intval(Request::input('pid')); $pid = intval(Request::input('pid'));
// //
if (!is_array($ids) || empty($ids)) { $file = File::permissionFind($id, 1000);
return Base::retError('请选择移动的文件或文件夹'); //
}
if (count($ids) > 100) {
return Base::retError('一次最多只能移动100个文件或文件夹');
}
if ($pid > 0) { if ($pid > 0) {
File::permissionFind($pid, 1); if (!File::whereUserid($user->userid)->whereId($pid)->exists()) {
return Base::retError('参数错误');
}
$arr = [];
$tid = $pid;
while ($tid > 0) {
$arr[] = $tid;
$tid = intval(File::whereId($tid)->value('pid'));
}
if (in_array($id, $arr)) {
return Base::retError('位置错误');
}
} }
// //
$files = []; $file->pid = $pid;
AbstractModel::transaction(function() use ($pid, $ids, &$files) { $file->save();
foreach ($ids as $id) { $file->pushMsg('update', $file);
$file = File::permissionFind($id, 1000); return Base::retSuccess('操作成功', $file);
//
if ($pid > 0) {
$arr = [];
$tid = $pid;
while ($tid > 0) {
$arr[] = $tid;
$tid = intval(File::whereId($tid)->value('pid'));
}
if (in_array($id, $arr)) {
throw new ApiException('移动位置错误');
}
}
//
$file->pid = $pid;
$file->save();
$files[] = $file;
}
});
foreach ($files as $file) {
$file->pushMsg('update', $file);
}
return Base::retSuccess('操作成功', $files);
} }
/** /**
@ -387,7 +353,7 @@ class FileController extends AbstractController
* @apiGroup file * @apiGroup file
* @apiName remove * @apiName remove
* *
* @apiParam {Numbers} ids 文件ID(格式:[id1, id2] * @apiParam {Number} id 文件ID
* *
* @apiSuccess {Number} ret 返回状态码1正确、0错误 * @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述) * @apiSuccess {String} msg 返回信息(错误描述)
@ -397,25 +363,12 @@ class FileController extends AbstractController
{ {
User::auth(); User::auth();
// //
$ids = Request::input('ids'); $id = intval(Request::input('id'));
// //
if (!is_array($ids) || empty($ids)) { $file = File::permissionFind($id, 1000);
return Base::retError('请选择删除的文件或文件夹');
}
if (count($ids) > 100) {
return Base::retError('一次最多只能删除100个文件或文件夹');
}
// //
$files = []; $file->deleteFile();
AbstractModel::transaction(function() use ($ids, &$files) { return Base::retSuccess('删除成功', $file);
foreach ($ids as $id) {
$file = File::permissionFind($id, 1000);
$file->deleteFile();
$files[] = $file;
}
});
//
return Base::retSuccess('删除成功', $files);
} }
/** /**
@ -427,14 +380,8 @@ class FileController extends AbstractController
* @apiName content * @apiName content
* *
* @apiParam {Number|String} id * @apiParam {Number|String} id
* - Number: 文件ID需要登录 * - Number 文件ID需要登录
* - String: 链接码(不需要登录,用于预览) * - String 链接码(不需要登录,用于预览)
* @apiParam {String} only_update_at 仅获取update_at字段
* - no (默认)
* - yes
* @apiParam {String} down 直接下载
* - no: 浏览(默认)
* - yes: 下载office文件直接下载
* *
* @apiSuccess {Number} ret 返回状态码1正确、0错误 * @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述) * @apiSuccess {String} msg 返回信息(错误描述)
@ -443,8 +390,6 @@ class FileController extends AbstractController
public function content() public function content()
{ {
$id = Request::input('id'); $id = Request::input('id');
$down = Request::input('down', 'no');
$only_update_at = Request::input('only_update_at', 'no');
// //
if (Base::isNumber($id)) { if (Base::isNumber($id)) {
User::auth(); User::auth();
@ -459,15 +404,8 @@ class FileController extends AbstractController
return Base::retError('参数错误'); return Base::retError('参数错误');
} }
// //
if ($only_update_at == 'yes') {
return Base::retSuccess('success', [
'id' => $file->id,
'update_at' => Carbon::parse($file->updated_at)->toDateTimeString()
]);
}
//
$content = FileContent::whereFid($file->id)->orderByDesc('id')->first(); $content = FileContent::whereFid($file->id)->orderByDesc('id')->first();
return FileContent::formatContent($file, $content?->content, $down == 'yes'); return FileContent::formatContent($file->type, $content ? $content->content : []);
} }
/** /**
@ -478,7 +416,7 @@ class FileController extends AbstractController
* @apiGroup file * @apiGroup file
* @apiName content__save * @apiName content__save
* *
* @apiParam {Number} id 文件ID * @apiParam {Number} id 文件ID
* @apiParam {Object} [D] Request Payload 提交 * @apiParam {Object} [D] Request Payload 提交
* - content: 内容 * - content: 内容
* *
@ -488,7 +426,6 @@ class FileController extends AbstractController
*/ */
public function content__save() public function content__save()
{ {
Base::checkClientVersion('0.9.13');
$user = User::auth(); $user = User::auth();
// //
$id = Base::getPostInt('id'); $id = Base::getPostInt('id');
@ -502,11 +439,12 @@ class FileController extends AbstractController
$isRep = false; $isRep = false;
preg_match_all("/<img\s*src=\"data:image\/(png|jpg|jpeg);base64,(.*?)\"/s", $data['content'], $matchs); preg_match_all("/<img\s*src=\"data:image\/(png|jpg|jpeg);base64,(.*?)\"/s", $data['content'], $matchs);
foreach ($matchs[2] as $key => $text) { foreach ($matchs[2] as $key => $text) {
$tmpPath = "uploads/file/document/" . date("Ym") . "/" . $id . "/attached/"; $p = "uploads/files/document/" . $id . "/";
Base::makeDir(public_path($tmpPath)); Base::makeDir(public_path($p));
$tmpPath .= md5($text) . "." . $matchs[1][$key]; $p.= md5($text) . "." . $matchs[1][$key];
if (file_put_contents(public_path($tmpPath), base64_decode($text))) { $r = file_put_contents(public_path($p), base64_decode($text));
$data['content'] = str_replace($matchs[0][$key], '<img src="' . Base::fillUrl($tmpPath) . '"', $data['content']); if ($r) {
$data['content'] = str_replace($matchs[0][$key], '<img src="' . Base::fillUrl($p) . '"', $data['content']);
$isRep = true; $isRep = true;
} }
} }
@ -516,41 +454,11 @@ class FileController extends AbstractController
} }
} }
// //
switch ($file->type) {
case 'document':
$contentArray = Base::json2array($content);
$contentString = $contentArray['content'];
$file->ext = $contentArray['type'] == 'md' ? 'md' : 'text';
break;
case 'drawio':
$contentArray = Base::json2array($content);
$contentString = $contentArray['xml'];
$file->ext = 'drawio';
break;
case 'mind':
$contentString = $content;
$file->ext = 'mind';
break;
case 'code':
case 'txt':
$contentString = $content;
break;
default:
return Base::retError('参数错误');
}
$path = "uploads/file/" . $file->type . "/" . date("Ym") . "/" . $id . "/" . md5($contentString);
$save = public_path($path);
Base::makeDir(dirname($save));
file_put_contents($save, $contentString);
//
$content = FileContent::createInstance([ $content = FileContent::createInstance([
'fid' => $file->id, 'fid' => $file->id,
'content' => [ 'content' => $content,
'type' => $file->ext,
'url' => $path
],
'text' => $text, 'text' => $text,
'size' => filesize($save), 'size' => strlen($content),
'userid' => $user->userid, 'userid' => $user->userid,
]); ]);
$content->save(); $content->save();
@ -590,7 +498,7 @@ class FileController extends AbstractController
if ($status === 2) { if ($status === 2) {
$parse = parse_url($url); $parse = parse_url($url);
$from = 'http://' . env('APP_IPPR') . '.3' . $parse['path'] . '?' . $parse['query']; $from = 'http://' . env('APP_IPPR') . '.3' . $parse['path'] . '?' . $parse['query'];
$path = 'uploads/file/' . $file->type . '/' . date("Ym") . '/' . $file->id . '/' . $key; $path = 'uploads/office/' . date("Ym") . '/' . $file->id . '/' . $user->userid . '-' . $key;
$save = public_path($path); $save = public_path($path);
Base::makeDir(dirname($save)); Base::makeDir(dirname($save));
$res = Ihttp::download($from, $save); $res = Ihttp::download($from, $save);
@ -608,7 +516,6 @@ class FileController extends AbstractController
$content->save(); $content->save();
// //
$file->size = $content->size; $file->size = $content->size;
$file->updated_at = Carbon::now();
$file->save(); $file->save();
$file->pushMsg('update', $file); $file->pushMsg('update', $file);
} }
@ -636,7 +543,6 @@ class FileController extends AbstractController
$user = User::auth(); $user = User::auth();
// //
$pid = intval(Request::input('pid')); $pid = intval(Request::input('pid'));
$webkitRelativePath = Request::input('webkitRelativePath');
// //
$userid = $user->userid; $userid = $user->userid;
if ($pid > 0) { if ($pid > 0) {
@ -651,37 +557,7 @@ class FileController extends AbstractController
} }
} }
// //
$dirs = explode("/", $webkitRelativePath); $path = 'uploads/office/' . date("Ym") . '/u' . $user->userid . '/';
while (count($dirs) > 1) {
$dirName = array_shift($dirs);
if ($dirName) {
$pushMsg = [];
AbstractModel::transaction(function () use ($dirName, $user, $userid, &$pid, &$pushMsg) {
$dirRow = File::wherePid($pid)->whereType('folder')->whereName($dirName)->lockForUpdate()->first();
if (empty($dirRow)) {
$dirRow = File::createInstance([
'pid' => $pid,
'type' => 'folder',
'name' => $dirName,
'userid' => $userid,
'created_id' => $user->userid,
]);
if ($dirRow->save()) {
$pushMsg[] = File::find($dirRow->id);
}
}
if (empty($dirRow)) {
throw new ApiException('创建文件夹失败');
}
$pid = $dirRow->id;
});
foreach ($pushMsg as $tmpRow) {
$tmpRow->pushMsg('add', $tmpRow);
}
}
}
//
$path = 'uploads/tmp/' . date("Ym") . '/';
$data = Base::upload([ $data = Base::upload([
"file" => Request::file('files'), "file" => Request::file('files'),
"type" => 'more', "type" => 'more',
@ -694,9 +570,6 @@ class FileController extends AbstractController
$data = $data['data']; $data = $data['data'];
// //
$type = match ($data['ext']) { $type = match ($data['ext']) {
'text', 'md', 'markdown' => 'document',
'drawio' => 'drawio',
'mind' => 'mind',
'doc', 'docx' => "word", 'doc', 'docx' => "word",
'xls', 'xlsx' => "excel", 'xls', 'xlsx' => "excel",
'ppt', 'pptx' => "ppt", 'ppt', 'pptx' => "ppt",
@ -708,22 +581,12 @@ class FileController extends AbstractController
'ofd' => "ofd", 'ofd' => "ofd",
'pdf' => "pdf", 'pdf' => "pdf",
'txt' => "txt", 'txt' => "txt",
'htaccess', 'htgroups', 'htpasswd', 'conf', 'bat', 'cmd', 'cpp', 'c', 'cc', 'cxx', 'h', 'hh', 'hpp', 'ino', 'cs', 'css', 'html', 'htm', 'asp', 'jsp', 'xml', 'json', 'properties', 'md', 'gitignore', 'log', 'java', 'py', 'c', 'cpp', 'sql', 'sh', 'bat', 'm', 'bas', 'prg', 'cmd',
'dockerfile', 'go', 'html', 'htm', 'xhtml', 'vue', 'we', 'wpy', 'java', 'js', 'jsm', 'jsx', 'json', 'jsp', 'less', 'lua', 'makefile', 'gnumakefile', 'php', 'go', 'python', 'js', 'ftl', 'css', 'lua', 'rb', 'yaml', 'yml', 'h', 'cs', 'aspx' => "code",
'ocamlmakefile', 'make', 'mysql', 'nginx', 'ini', 'cfg', 'prefs', 'm', 'mm', 'pl', 'pm', 'p6', 'pl6', 'pm6', 'pgsql', 'php',
'inc', 'phtml', 'shtml', 'php3', 'php4', 'php5', 'phps', 'phpt', 'aw', 'ctp', 'module', 'ps1', 'py', 'r', 'rb', 'ru', 'gemspec', 'rake', 'guardfile', 'rakefile',
'gemfile', 'rs', 'sass', 'scss', 'sh', 'bash', 'bashrc', 'sql', 'sqlserver', 'swift', 'ts', 'typescript', 'str', 'vbs', 'vb', 'v', 'vh', 'sv', 'svh', 'xml',
'rdf', 'rss', 'wsdl', 'xslt', 'atom', 'mathml', 'mml', 'xul', 'xbl', 'xaml', 'yaml', 'yml',
'asp', 'properties', 'gitignore', 'log', 'bas', 'prg', 'python', 'ftl', 'aspx' => "code",
'mp3', 'wav', 'mp4', 'flv', 'mp3', 'wav', 'mp4', 'flv',
'avi', 'mov', 'wmv', 'mkv', '3gp', 'rm' => "media", 'avi', 'mov', 'wmv', 'mkv', '3gp', 'rm' => "media",
'xmind' => "xmind",
'rp' => "axure",
default => "", default => "",
}; };
if ($data['ext'] == 'markdown') {
$data['ext'] = 'md';
}
$file = File::createInstance([ $file = File::createInstance([
'pid' => $pid, 'pid' => $pid,
'name' => Base::rightDelete($data['name'], '.' . $data['ext']), 'name' => Base::rightDelete($data['name'], '.' . $data['ext']),
@ -733,11 +596,9 @@ class FileController extends AbstractController
'created_id' => $user->userid, 'created_id' => $user->userid,
]); ]);
// 开始创建 // 开始创建
return AbstractModel::transaction(function () use ($webkitRelativePath, $type, $user, $data, $file) { return AbstractModel::transaction(function () use ($type, $user, $data, $file) {
$file->size = $data['size'] * 1024;
$file->save(); $file->save();
// //
$data = Base::uploadMove($data, "uploads/file/" . $file->type . "/" . date("Ym") . "/" . $file->id . "/");
$content = FileContent::createInstance([ $content = FileContent::createInstance([
'fid' => $file->id, 'fid' => $file->id,
'content' => [ 'content' => [
@ -747,16 +608,16 @@ class FileController extends AbstractController
'url' => $data['path'] 'url' => $data['path']
], ],
'text' => '', 'text' => '',
'size' => $file->size, 'size' => $data['size'] * 1024,
'userid' => $user->userid, 'userid' => $user->userid,
]); ]);
$content->save(); $content->save();
// //
$tmpRow = File::find($file->id); $file->size = $content->size;
$tmpRow->pushMsg('add', $tmpRow); $file->save();
// //
$data = $tmpRow->toArray(); $data = File::find($file->id);
$data['full_name'] = $webkitRelativePath ?: $data['name']; $data->pushMsg('add', $data);
return Base::retSuccess($data['name'] . ' 上传成功', $data); return Base::retSuccess($data['name'] . ' 上传成功', $data);
}); });
} }

View File

@ -4,7 +4,6 @@ namespace App\Http\Controllers\Api;
use App\Exceptions\ApiException; use App\Exceptions\ApiException;
use App\Models\AbstractModel; use App\Models\AbstractModel;
use App\Models\File;
use App\Models\Project; use App\Models\Project;
use App\Models\ProjectColumn; use App\Models\ProjectColumn;
use App\Models\ProjectFlow; use App\Models\ProjectFlow;
@ -17,13 +16,9 @@ use App\Models\ProjectUser;
use App\Models\User; use App\Models\User;
use App\Models\WebSocketDialog; use App\Models\WebSocketDialog;
use App\Module\Base; use App\Module\Base;
use App\Module\BillExport;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Madzipper;
use Request; use Request;
use Response;
use Session;
/** /**
* @apiDefine project * @apiDefine project
@ -208,9 +203,6 @@ class ProjectController extends AbstractController
* @apiParam {String} name 项目名称 * @apiParam {String} name 项目名称
* @apiParam {String} [desc] 项目介绍 * @apiParam {String} [desc] 项目介绍
* @apiParam {String} [columns] 列表格式列表名称1,列表名称2 * @apiParam {String} [columns] 列表格式列表名称1,列表名称2
* @apiParam {String} [flow] 开启流程
* - open: 开启
* - close: 关闭(默认)
* *
* @apiSuccess {Number} ret 返回状态码1正确、0错误 * @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述) * @apiSuccess {String} msg 返回信息(错误描述)
@ -222,7 +214,6 @@ class ProjectController extends AbstractController
// 项目名称 // 项目名称
$name = trim(Request::input('name', '')); $name = trim(Request::input('name', ''));
$desc = trim(Request::input('desc', '')); $desc = trim(Request::input('desc', ''));
$flow = trim(Request::input('flow', 'close'));
if (mb_strlen($name) < 2) { if (mb_strlen($name) < 2) {
return Base::retError('项目名称不可以少于2个字'); return Base::retError('项目名称不可以少于2个字');
} elseif (mb_strlen($name) > 32) { } elseif (mb_strlen($name) > 32) {
@ -259,7 +250,7 @@ class ProjectController extends AbstractController
'desc' => $desc, 'desc' => $desc,
'userid' => $user->userid, 'userid' => $user->userid,
]); ]);
AbstractModel::transaction(function() use ($flow, $insertColumns, $project) { AbstractModel::transaction(function() use ($insertColumns, $project) {
$project->save(); $project->save();
ProjectUser::createInstance([ ProjectUser::createInstance([
'project_id' => $project->id, 'project_id' => $project->id,
@ -276,10 +267,6 @@ class ProjectController extends AbstractController
} }
$project->dialog_id = $dialog->id; $project->dialog_id = $dialog->id;
$project->save(); $project->save();
//
if ($flow == 'open') {
$project->addFlow(Base::json2array('[{"id":"-10","name":"\u5f85\u5904\u7406","status":"start","turns":["-10","-11","-12","-13"],"usertype":"add","userlimit":"0","sort":"0"},{"id":"-11","name":"\u8fdb\u884c\u4e2d","status":"progress","turns":["-10","-11","-12","-13"],"usertype":"add","userlimit":"0","sort":"1"},{"id":"-12","name":"\u5df2\u5b8c\u6210","status":"end","turns":["-10","-11","-12","-13"],"usertype":"add","userlimit":"0","sort":"2"},{"id":"-13","name":"\u5df2\u53d6\u6d88","status":"end","turns":["-10","-11","-12","-13"],"usertype":"add","userlimit":"0","sort":"3"}]'));
}
}); });
// //
$data = Project::find($project->id); $data = Project::find($project->id);
@ -607,14 +594,13 @@ class ProjectController extends AbstractController
if (!is_array($item['task'])) continue; if (!is_array($item['task'])) continue;
$index = 0; $index = 0;
foreach ($item['task'] as $task_id) { foreach ($item['task'] as $task_id) {
if (ProjectTask::whereId($task_id)->whereProjectId($project->id)->whereCompleteAt(null)->update([ ProjectTask::whereId($task_id)->whereProjectId($project->id)->update([
'column_id' => $item['id'], 'column_id' => $item['id'],
'sort' => $index 'sort' => $index
])) { ]);
ProjectTask::whereParentId($task_id)->whereProjectId($project->id)->update([ ProjectTask::whereParentId($task_id)->whereProjectId($project->id)->update([
'column_id' => $item['id'], 'column_id' => $item['id'],
]); ]);
}
$index++; $index++;
} }
} }
@ -890,7 +876,6 @@ class ProjectController extends AbstractController
* - yes已完成 * - yes已完成
* - no未完成 * - no未完成
* @apiParam {String} [archived] 归档状态 * @apiParam {String} [archived] 归档状态
* - all所有
* - yes已归档 * - yes已归档
* - no未归档默认 * - no未归档默认
* @apiParam {Object} sorts 排序方式 * @apiParam {Object} sorts 排序方式
@ -926,7 +911,7 @@ class ProjectController extends AbstractController
// //
$scopeAll = false; $scopeAll = false;
if ($parent_id > 0) { if ($parent_id > 0) {
ProjectTask::userTask($parent_id, str_replace(['all', 'yes', 'no'], [null, false, true], $archived)); ProjectTask::userTask($parent_id);
$scopeAll = true; $scopeAll = true;
$builder->where('project_tasks.parent_id', $parent_id); $builder->where('project_tasks.parent_id', $parent_id);
} elseif ($parent_id === -1) { } elseif ($parent_id === -1) {
@ -980,154 +965,6 @@ class ProjectController extends AbstractController
return Base::retSuccess('success', $list); return Base::retSuccess('success', $list);
} }
/**
* @api {get} api/project/task/export 18. 导出任务(限管理员)
*
* @apiDescription 导出指定范围任务已完成、未完成、已归档返回下载地址需要token身份
* @apiVersion 1.0.0
* @apiGroup project
* @apiName task__export
*
* @apiParam {Array} [userid] 指定会员,如:[1, 2]
* @apiParam {Array} [time] 指定时间范围,如:['2020-12-12', '2020-12-30']
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function task__export()
{
$user = User::auth('admin');
//
$userid = Base::arrayRetainInt(Request::input('userid'), true);
$time = Request::input('time');
if (empty($userid) || empty($time)) {
return Base::retError('参数错误');
}
if (count($userid) > 20) {
return Base::retError('导出会员限制最多20个');
}
if (!(is_array($time) && Base::isDateOrTime($time[0]) && Base::isDateOrTime($time[1]))) {
return Base::retError('时间选择错误');
}
if (Carbon::parse($time[1])->timestamp - Carbon::parse($time[0])->timestamp > 90 * 86400) {
return Base::retError('时间范围限制最大90天');
}
//
$headings = [];
$headings[] = '任务ID';
$headings[] = '任务标题';
$headings[] = '负责人';
$headings[] = '创建人';
$headings[] = '是否完成';
$headings[] = '完成时间';
$headings[] = '是否归档';
$headings[] = '归档时间';
$headings[] = '任务开始时间';
$headings[] = '任务结束时间';
$headings[] = '结束剩余';
$headings[] = '所属项目';
$headings[] = '父级任务ID';
$datas = [];
//
$builder = ProjectTask::select(['project_tasks.*', 'project_task_users.userid as ownerid'])
->join('project_task_users', 'project_tasks.id', '=', 'project_task_users.task_id')
->where('project_task_users.owner', 1)
->whereIn('project_task_users.userid', $userid)
->betweenTime(Carbon::parse($time[0])->startOfDay(), Carbon::parse($time[1])->endOfDay());
$builder->orderByDesc('project_tasks.id')->chunk(100, function($tasks) use (&$datas) {
/** @var ProjectTask $task */
foreach ($tasks as $task) {
if ($task->complete_at) {
$a = Carbon::parse($task->complete_at)->timestamp;
$b = Carbon::parse($task->end_at)->timestamp;
if ($b > $a) {
$endSurplus = Base::timeDiff($a, $b);
} else {
$endSurplus = "-" . Base::timeDiff($b, $a);
}
} else {
$endSurplus = '-';
}
$datas[] = [
$task->id,
Base::filterEmoji($task->name),
Base::filterEmoji(User::userid2nickname($task->ownerid)) . " (ID: {$task->ownerid})",
Base::filterEmoji(User::userid2nickname($task->userid)) . " (ID: {$task->userid})",
$task->complete_at ? '已完成' : '-',
$task->complete_at ?: '-',
$task->archived_at ? '已归档' : '-',
$task->archived_at ?: '-',
$task->start_at ?: '-',
$task->end_at ?: '-',
$endSurplus,
Base::filterEmoji($task->project?->name) ?: '-',
$task->parent_id ?: '-',
];
}
});
//
$fileName = User::userid2nickname($userid[0]) ?: $userid[0];
if (count($userid) > 1) {
$fileName .= "" . count($userid) . "位成员";
}
$fileName .= '任务统计_' . Base::time() . '.xls';
$filePath = "temp/task/export/" . date("Ym", Base::time());
$res = BillExport::create()->setHeadings($headings)->setData($datas)->store($filePath . "/" . $fileName);
if ($res != 1) {
return Base::retError('导出失败,' . $fileName . '');
}
$xlsPath = storage_path("app/" . $filePath . "/" . $fileName);
$zipFile = "app/" . $filePath . "/" . Base::rightDelete($fileName, '.xls'). ".zip";
$zipPath = storage_path($zipFile);
if (file_exists($zipPath)) {
Base::deleteDirAndFile($zipPath, true);
}
try {
Madzipper::make($zipPath)->add($xlsPath)->close();
} catch (\Exception) { }
//
if (file_exists($zipPath)) {
$base64 = base64_encode(Base::array2string([
'file' => $zipFile,
]));
Session::put('task::export:userid', $user->userid);
return Base::retSuccess('success', [
'size' => Base::twoFloat(filesize($zipPath) / 1024, true),
'url' => Base::fillUrl('api/project/task/down?key=' . urlencode($base64)),
]);
} else {
return Base::retError('打包失败,请稍后再试...');
}
}
/**
* @api {get} api/project/task/down 18. 导出任务(限管理员)
*
* @apiDescription 导出指定范围任务已完成、未完成、已归档返回下载地址需要token身份
* @apiVersion 1.0.0
* @apiGroup project
* @apiName task__down
*
* @apiParam {String} key 通过export接口得到的下载钥匙
*
* @apiSuccess {File} 文件下载
*/
public function task__down()
{
$userid = Session::get('task::export:userid');
if (empty($userid)) {
return Base::ajaxError("请求已过期,请重新导出!", [], 0, 502);
}
//
$array = Base::string2array(base64_decode(urldecode(Request::input('key'))));
$file = $array['file'];
if (empty($file) || !file_exists(storage_path($file))) {
return Base::ajaxError("文件不存在!", [], 0, 502);
}
return response()->download(storage_path($file));
}
/** /**
* @api {get} api/project/task/one 19. 获取单个任务信息 * @api {get} api/project/task/one 19. 获取单个任务信息
* *
@ -1137,10 +974,6 @@ class ProjectController extends AbstractController
* @apiName task__one * @apiName task__one
* *
* @apiParam {Number} task_id 任务ID * @apiParam {Number} task_id 任务ID
* @apiParam {String} [archived] 归档状态
* - all所有
* - yes已归档
* - no未归档默认
* *
* @apiSuccess {Number} ret 返回状态码1正确、0错误 * @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述) * @apiSuccess {String} msg 返回信息(错误描述)
@ -1151,9 +984,8 @@ class ProjectController extends AbstractController
User::auth(); User::auth();
// //
$task_id = intval(Request::input('task_id')); $task_id = intval(Request::input('task_id'));
$archived = Request::input('archived', 'no');
// //
$task = ProjectTask::userTask($task_id, str_replace(['all', 'yes', 'no'], [null, false, true], $archived), false, ['taskUser', 'taskTag']); $task = ProjectTask::userTask($task_id, true, false, ['taskUser', 'taskTag']);
// //
$data = $task->toArray(); $data = $task->toArray();
$data['project_name'] = $task->project?->name; $data['project_name'] = $task->project?->name;
@ -1181,7 +1013,7 @@ class ProjectController extends AbstractController
// //
$task_id = intval(Request::input('task_id')); $task_id = intval(Request::input('task_id'));
// //
$task = ProjectTask::userTask($task_id, null); $task = ProjectTask::userTask($task_id);
// //
return Base::retSuccess('success', $task->content ?: json_decode('{}')); return Base::retSuccess('success', $task->content ?: json_decode('{}'));
} }
@ -1206,7 +1038,7 @@ class ProjectController extends AbstractController
// //
$task_id = intval(Request::input('task_id')); $task_id = intval(Request::input('task_id'));
// //
$task = ProjectTask::userTask($task_id, null); $task = ProjectTask::userTask($task_id);
// //
return Base::retSuccess('success', $task->taskFile); return Base::retSuccess('success', $task->taskFile);
} }
@ -1245,85 +1077,7 @@ class ProjectController extends AbstractController
} }
/** /**
* @api {get} api/project/task/filedetail 23. 获取任务文件详情 * @api {post} api/project/task/add 23. 添加任务
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup project
* @apiName task__filedetail
*
* @apiParam {Number} file_id 文件ID
* @apiParam {String} only_update_at 仅获取update_at字段
* - no (默认)
* - yes
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function task__filedetail()
{
User::auth();
//
$file_id = intval(Request::input('file_id'));
$only_update_at = Request::input('only_update_at', 'no');
//
$file = ProjectTaskFile::find($file_id);
if (empty($file)) {
return Base::retError("文件不存在");
}
//
if ($only_update_at == 'yes') {
return Base::retSuccess('success', [
'id' => $file->id,
'update_at' => Carbon::parse($file->updated_at)->toDateTimeString()
]);
}
//
$data = $file->toArray();
$data['path'] = $file->getRawOriginal('path');
//
ProjectTask::userTask($file->task_id, null);
//
return Base::retSuccess('success', File::formatFileData($data));
}
/**
* @api {get} api/project/task/filedown 24. 下载任务文件
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup project
* @apiName task__filedown
*
* @apiParam {Number} file_id 文件ID
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function task__filedown()
{
User::auth();
//
$file_id = intval(Request::input('file_id'));
//
$file = ProjectTaskFile::find($file_id);
if (empty($file)) {
abort(403, "This file not exist.");
}
//
try {
ProjectTask::userTask($file->task_id, null);
} catch (\Exception $e) {
abort(403, $e->getMessage() ?: "This file not support download.");
}
//
return Response::download(public_path($file->getRawOriginal('path')), $file->name);
}
/**
* @api {post} api/project/task/add 25. 添加任务
* *
* @apiDescription 需要token身份 * @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -1394,7 +1148,7 @@ class ProjectController extends AbstractController
} }
/** /**
* @api {get} api/project/task/addsub 26. 添加子任务 * @api {get} api/project/task/addsub 24. 添加子任务
* *
* @apiDescription 需要token身份项目、任务负责人 * @apiDescription 需要token身份项目、任务负责人
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -1434,7 +1188,7 @@ class ProjectController extends AbstractController
} }
/** /**
* @api {post} api/project/task/update 27. 修改任务、子任务 * @api {post} api/project/task/update 25. 修改任务、子任务
* *
* @apiDescription 需要token身份项目、任务负责人 * @apiDescription 需要token身份项目、任务负责人
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -1480,7 +1234,73 @@ class ProjectController extends AbstractController
} }
/** /**
* @api {get} api/project/task/dialog 28. 创建/获取聊天室 * @api {post} api/project/task/upload 26. 上传文件
*
* @apiDescription 需要token身份项目、任务负责人
* @apiVersion 1.0.0
* @apiGroup project
* @apiName task__upload
*
* @apiParam {Number} task_id 任务ID
* @apiParam {String} [filename] post-文件名称
* @apiParam {String} [image64] post-base64图片二选一
* @apiParam {File} [files] post-文件对象(二选一)
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function task__upload()
{
$user = User::auth();
//
$task_id = Base::getPostInt('task_id');
//
$task = ProjectTask::userTask($task_id, true, true);
//
$path = "uploads/task/" . $task->id . "/";
$image64 = Base::getPostValue('image64');
$fileName = Base::getPostValue('filename');
if ($image64) {
$data = Base::image64save([
"image64" => $image64,
"path" => $path,
"fileName" => $fileName,
]);
} else {
$data = Base::upload([
"file" => Request::file('files'),
"type" => 'file',
"path" => $path,
"fileName" => $fileName,
]);
}
//
if (Base::isError($data)) {
return Base::retError($data['msg']);
} else {
$fileData = $data['data'];
$file = ProjectTaskFile::createInstance([
'project_id' => $task->project_id,
'task_id' => $task->id,
'name' => $fileData['name'],
'size' => $fileData['size'] * 1024,
'ext' => $fileData['ext'],
'path' => $fileData['path'],
'thumb' => Base::unFillUrl($fileData['thumb']),
'userid' => $user->userid,
]);
$file->save();
//
$file = ProjectTaskFile::find($file->id);
$task->addLog("上传文件:" . $file->name);
$task->pushMsg('upload', $file);
return Base::retSuccess("上传成功", $file);
}
}
/**
* @api {get} api/project/task/dialog 27. 创建/获取聊天室
* *
* @apiDescription 需要token身份 * @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -1527,7 +1347,7 @@ class ProjectController extends AbstractController
} }
/** /**
* @api {get} api/project/task/archived 29. 归档任务 * @api {get} api/project/task/archived 28. 归档任务
* *
* @apiDescription 需要token身份项目、任务负责人 * @apiDescription 需要token身份项目、任务负责人
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -1561,15 +1381,11 @@ class ProjectController extends AbstractController
} elseif ($type == 'add') { } elseif ($type == 'add') {
$task->archivedTask(Carbon::now()); $task->archivedTask(Carbon::now());
} }
return Base::retSuccess('操作成功', [ return Base::retSuccess('操作成功', ['id' => $task->id]);
'id' => $task->id,
'archived_at' => $task->archived_at,
'archived_userid' => $task->archived_userid,
]);
} }
/** /**
* @api {get} api/project/task/remove 30. 删除任务 * @api {get} api/project/task/remove 29. 删除任务
* *
* @apiDescription 需要token身份项目、任务负责人 * @apiDescription 需要token身份项目、任务负责人
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -1595,7 +1411,7 @@ class ProjectController extends AbstractController
} }
/** /**
* @api {get} api/project/task/resetfromlog 31. 根据日志重置任务 * @api {get} api/project/task/resetfromlog 29. 根据日志重置任务
* *
* @apiDescription 需要token身份项目、任务负责人 * @apiDescription 需要token身份项目、任务负责人
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -1619,7 +1435,7 @@ class ProjectController extends AbstractController
return Base::retError('记录不存在'); return Base::retError('记录不存在');
} }
// //
$task = ProjectTask::userTask($projectLog->task_id, true, true); $task = ProjectTask::userTask($projectLog->task_id, null, true);
// //
$record = $projectLog->record; $record = $projectLog->record;
if ($record['flow'] && is_array($record['flow'])) { if ($record['flow'] && is_array($record['flow'])) {
@ -1642,7 +1458,6 @@ class ProjectController extends AbstractController
$task->updateTask($data, $updateMarking); $task->updateTask($data, $updateMarking);
// //
$data = ProjectTask::oneTask($task->id)->toArray(); $data = ProjectTask::oneTask($task->id)->toArray();
$data["flow_item_name"] = $newFlowItem->status . "|" . $newFlowItem->name;
$data['update_marking'] = $updateMarking ?: json_decode('{}'); $data['update_marking'] = $updateMarking ?: json_decode('{}');
$task->pushMsg('update', $data); $task->pushMsg('update', $data);
// //
@ -1654,7 +1469,7 @@ class ProjectController extends AbstractController
} }
/** /**
* @api {get} api/project/task/flow 32. 任务工作流信息 * @api {get} api/project/task/flow 29. 任务工作流信息
* *
* @apiDescription 需要token身份 * @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -1736,9 +1551,9 @@ class ProjectController extends AbstractController
} }
/** /**
* @api {get} api/project/flow/list 33. 工作流列表 * @api {get} api/project/flow/list 29. 工作流列表
* *
* @apiDescription 需要token身份 * @apiDescription 需要token身份(限:项目负责人)
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup project * @apiGroup project
* @apiName flow__list * @apiName flow__list
@ -1755,14 +1570,14 @@ class ProjectController extends AbstractController
// //
$project_id = intval(Request::input('project_id')); $project_id = intval(Request::input('project_id'));
// //
$project = Project::userProject($project_id, true); $project = Project::userProject($project_id, true, true);
// //
$list = ProjectFlow::with(['ProjectFlowItem'])->whereProjectId($project->id)->get(); $list = ProjectFlow::with(['ProjectFlowItem'])->whereProjectId($project->id)->get();
return Base::retSuccess('success', $list); return Base::retSuccess('success', $list);
} }
/** /**
* @api {post} api/project/flow/save 34. 保存工作流 * @api {post} api/project/flow/save 29. 保存工作流
* *
* @apiDescription 需要token身份项目负责人 * @apiDescription 需要token身份项目负责人
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -1792,11 +1607,96 @@ class ProjectController extends AbstractController
// //
$project = Project::userProject($project_id, true, true); $project = Project::userProject($project_id, true, true);
// //
return Base::retSuccess('保存成功', $project->addFlow($flows)); return AbstractModel::transaction(function() use ($project, $flows) {
$projectFlow = ProjectFlow::whereProjectId($project->id)->first();
if (empty($projectFlow)) {
$projectFlow = ProjectFlow::createInstance([
'project_id' => $project->id,
'name' => 'Default'
]);
if (!$projectFlow->save()) {
throw new ApiException('工作流创建失败');
}
}
//
$ids = [];
$idc = [];
$hasStart = false;
$hasEnd = false;
foreach ($flows as $item) {
$id = intval($item['id']);
$turns = Base::arrayRetainInt($item['turns'] ?: [], true);
$userids = Base::arrayRetainInt($item['userids'] ?: [], true);
$usertype = trim($item['usertype']);
$userlimit = intval($item['userlimit']);
if ($usertype == 'replace' && empty($userids)) {
throw new ApiException("状态[{$item['name']}]设置错误,设置流转模式时必须填写状态负责人");
}
if ($userlimit && empty($userids)) {
throw new ApiException("状态[{$item['name']}]设置错误,设置限制负责人时必须填写状态负责人");
}
$flow = ProjectFlowItem::updateInsert([
'id' => $id,
'project_id' => $project->id,
'flow_id' => $projectFlow->id,
], [
'name' => trim($item['name']),
'status' => trim($item['status']),
'sort' => intval($item['sort']),
'turns' => $turns,
'userids' => $userids,
'usertype' => trim($item['usertype']),
'userlimit' => $userlimit,
]);
if ($flow) {
$ids[] = $flow->id;
if ($flow->id != $id) {
$idc[$id] = $flow->id;
}
if ($flow->status == 'start') {
$hasStart = true;
}
if ($flow->status == 'end') {
$hasEnd = true;
}
}
}
if (!$hasStart) {
throw new ApiException('至少需要1个开始状态');
}
if (!$hasEnd) {
throw new ApiException('至少需要1个结束状态');
}
ProjectFlowItem::whereFlowId($projectFlow->id)->whereNotIn('id', $ids)->chunk(100, function($list) {
foreach ($list as $item) {
$item->deleteFlowItem();
}
});
//
$projectFlow = ProjectFlow::with(['projectFlowItem'])->whereProjectId($project->id)->find($projectFlow->id);
$itemIds = $projectFlow->projectFlowItem->pluck('id')->toArray();
foreach ($projectFlow->projectFlowItem as $item) {
$turns = $item->turns;
foreach ($idc as $oid => $nid) {
if (in_array($oid, $turns)) {
$turns = array_diff($turns, [$oid]);
$turns[] = $nid;
}
}
if (!in_array($item->id, $turns)) {
$turns[] = $item->id;
}
$turns = array_values(array_filter(array_unique(array_intersect($turns, $itemIds))));
sort($turns);
$item->turns = $turns;
ProjectFlowItem::whereId($item->id)->update([ 'turns' => Base::array2json($turns) ]);
}
return Base::retSuccess('保存成功', $projectFlow);
});
} }
/** /**
* @api {get} api/project/flow/delete 35. 删除工作流 * @api {get} api/project/flow/delete 29. 删除工作流
* *
* @apiDescription 需要token身份项目负责人 * @apiDescription 需要token身份项目负责人
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -1828,7 +1728,7 @@ class ProjectController extends AbstractController
} }
/** /**
* @api {get} api/project/log/lists 36. 获取项目、任务日志 * @api {get} api/project/log/lists 30. 获取项目、任务日志
* *
* @apiDescription 需要token身份 * @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -1854,7 +1754,7 @@ class ProjectController extends AbstractController
// //
$builder = ProjectLog::select(["*"]); $builder = ProjectLog::select(["*"]);
if ($task_id > 0) { if ($task_id > 0) {
$task = ProjectTask::userTask($task_id, null); $task = ProjectTask::userTask($task_id);
$builder->whereTaskId($task->id); $builder->whereTaskId($task->id);
} else { } else {
$project = Project::userProject($project_id); $project = Project::userProject($project_id);
@ -1878,31 +1778,4 @@ class ProjectController extends AbstractController
// //
return Base::retSuccess('success', $list); return Base::retSuccess('success', $list);
} }
/**
* @api {get} api/project/top 37. 项目置顶
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup project
* @apiName top
*
* @apiParam {Number} project_id 项目ID
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function top()
{
$user = User::auth();
$projectId = intval(Request::input('project_id'));
$projectUser = ProjectUser::whereUserid($user->userid)->whereProjectId($projectId)->first();
if (!$projectUser) {
return Base::retError("项目不存在");
}
$projectUser->top_at = $projectUser->top_at ? null : Carbon::now();
$projectUser->save();
return Base::retSuccess("success", $projectId);
}
} }

View File

@ -1,466 +0,0 @@
<?php
namespace App\Http\Controllers\Api;
use App\Exceptions\ApiException;
use App\Models\ProjectTask;
use App\Models\Report;
use App\Models\ReportReceive;
use App\Models\User;
use App\Module\Base;
use App\Tasks\PushTask;
use Carbon\Carbon;
use Hhxsv5\LaravelS\Swoole\Task\Task;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Validation\Rule;
use Request;
use Illuminate\Support\Facades\Validator;
/**
* @apiDefine report
*
* 汇报
*/
class ReportController extends AbstractController
{
/**
* @api {get} api/report/my 01. 我发送的汇报
*
* @apiVersion 1.0.0
* @apiGroup report
* @apiName my
*
* @apiParam {String} [type] 汇报类型weekly:周报daily:日报
* @apiParam {Array} [created_at] 汇报时间
* @apiParam {Number} [page] 当前页,默认:1
* @apiParam {Number} [pagesize] 每页显示数量,默认:20,最大:50
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function my(): array
{
$user = User::auth();
// 搜索当前用户
$builder = Report::with(['receivesUser'])->whereUserid($user->userid);
$type = trim(Request::input('type'));
$createAt = Request::input('created_at');
in_array($type, [Report::WEEKLY, Report::DAILY]) && $builder->whereType($type);
$whereArray = [];
if (is_array($createAt)) {
if ($createAt[0] > 0) $whereArray[] = ['created_at', '>=', date('Y-m-d H:i:s', Base::dayTimeF($createAt[0]))];
if ($createAt[1] > 0) $whereArray[] = ['created_at', '<=', date('Y-m-d H:i:s', Base::dayTimeE($createAt[1]))];
}
$list = $builder->where($whereArray)->orderByDesc('created_at')->paginate(Base::getPaginate(50, 20));
return Base::retSuccess('success', $list);
}
/**
* @api {get} api/report/receive 02. 我接收的汇报
*
* @apiVersion 1.0.0
* @apiGroup report
* @apiName receive
*
* @apiParam {String} [username] 会员名
* @apiParam {String} [type] 汇报类型weekly:周报daily:日报
* @apiParam {Array} [created_at] 汇报时间
* @apiParam {Number} [page] 当前页,默认:1
* @apiParam {Number} [pagesize] 每页显示数量,默认:20,最大:50
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function receive(): array
{
$user = User::auth();
$builder = Report::with(['receivesUser']);
$builder->whereHas("receivesUser", function ($query) use ($user) {
$query->where("report_receives.userid", $user->userid);
});
$type = trim(Request::input('type'));
$createAt = Request::input('created_at');
$username = trim(Request::input('username', ''));
$builder->whereHas('sendUser', function ($query) use ($username) {
if (!empty($username)) {
$query->where('users.email', 'LIKE', '%' . $username . '%');
}
});
in_array($type, [Report::WEEKLY, Report::DAILY]) && $builder->whereType($type);
$whereArray = [];
if (is_array($createAt)) {
if ($createAt[0] > 0) $whereArray[] = ['created_at', '>=', date('Y-m-d H:i:s', Base::dayTimeF($createAt[0]))];
if ($createAt[1] > 0) $whereArray[] = ['created_at', '<=', date('Y-m-d H:i:s', Base::dayTimeE($createAt[1]))];
}
$list = $builder->where($whereArray)->orderByDesc('created_at')->paginate(Base::getPaginate(50, 20));
if ($list->items()) {
foreach ($list->items() as $item) {
$item->receive_time = ReportReceive::query()->whereRid($item["id"])->whereUserid($user->userid)->value("receive_time");
}
}
return Base::retSuccess('success', $list);
}
/**
* @api {get} api/report/store 03. 保存并发送工作汇报
*
* @apiVersion 1.0.0
* @apiGroup report
* @apiName store
*
* @apiParam {Number} [id] 汇报ID
* @apiParam {String} [title] 汇报标题
* @apiParam {Array} [type] 汇报类型weekly:周报daily:日报
* @apiParam {Number} [content] 内容
* @apiParam {Number} [receive] 汇报对象
* @apiParam {Number} [offset] 偏移量
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function store(): array
{
$input = [
"id" => Base::getPostValue("id", 0),
"title" => Base::getPostValue("title"),
"type" => Base::getPostValue("type"),
"content" => Base::getPostValue("content"),
"receive" => Base::getPostValue("receive"),
// 以当前日期为基础的周期偏移量。例如选择了上一周那么就是 -1上一天同理。
"offset" => Base::getPostValue("offset", 0),
];
$validator = Validator::make($input, [
'id' => 'numeric',
'title' => 'required',
'type' => ['required', Rule::in([Report::WEEKLY, Report::DAILY])],
'content' => 'required',
'receive' => 'required',
'offset' => ['numeric', 'max:0'],
], [
'id.numeric' => 'ID只能是数字',
'title.required' => '请填写标题',
'type.required' => '请选择汇报类型',
'type.in' => '汇报类型错误',
'content.required' => '请填写汇报内容',
'receive.required' => '请选择接收人',
'offset.numeric' => '工作汇报周期格式错误,只能是数字',
'offset.max' => '只能提交当天/本周或者之前的的工作汇报',
]);
if ($validator->fails())
return Base::retError($validator->errors()->first());
$user = User::auth();
// 接收人
if (is_array($input["receive"])) {
// 删除当前登录人
$input["receive"] = array_diff($input["receive"], [$user->userid]);
// 查询用户是否存在
if (count($input["receive"]) !== User::whereIn("userid", $input["receive"])->count())
return Base::retError("用户不存在");
foreach ($input["receive"] as $userid) {
$input["receive_content"][] = [
"receive_time" => Carbon::now()->toDateTimeString(),
"userid" => $userid,
"read" => 0,
];
}
}
// 在事务中运行
Report::transaction(function () use ($input, $user) {
$id = $input["id"];
if ($id) {
// 编辑
$report = Report::getOne($id);
$report->updateInstance([
"title" => $input["title"],
"type" => $input["type"],
"content" => htmlspecialchars($input["content"]),
]);
} else {
// 生成唯一标识
$sign = Report::generateSign($input["type"], $input["offset"]);
// 检查唯一标识是否存在
if (empty($input["id"])) {
if (Report::query()->whereSign($sign)->whereType($input["type"])->count() > 0)
throw new ApiException("请勿重复提交工作汇报");
}
$report = Report::createInstance([
"title" => $input["title"],
"type" => $input["type"],
"content" => htmlspecialchars($input["content"]),
"userid" => $user->userid,
"sign" => $sign,
]);
}
$report->save();
if (!empty($input["receive_content"])) {
// 删除关联
$report->Receives()->delete();
// 保存接收人
$report->Receives()->createMany($input["receive_content"]);
}
// 推送消息
$userids = [];
foreach ($input["receive_content"] as $item) {
$userids[] = $item['userid'];
}
if ($userids) {
$params = [
'ignoreFd' => Request::header('fd'),
'userid' => $userids,
'msg' => [
'type' => 'report',
'action' => 'unreadUpdate',
]
];
Task::deliver(new PushTask($params, false));
}
});
return Base::retSuccess('保存成功');
}
/**
* @api {get} api/report/template 04. 生成汇报模板
*
* @apiVersion 1.0.0
* @apiGroup report
* @apiName template
*
* @apiParam {Array} [type] 汇报类型weekly:周报daily:日报
* @apiParam {Number} [offset] 偏移量
* @apiParam {String} [date] 时间
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function template(): array
{
$user = User::auth();
$type = trim(Request::input("type"));
$offset = abs(intval(Request::input("offset", 0)));
$id = intval(Request::input("offset", 0));
$now_dt = trim(Request::input("date")) ? Carbon::parse(Request::input("date")) : Carbon::now();
// 获取开始时间
if ($type === Report::DAILY) {
$start_time = Carbon::today();
if ($offset > 0) {
// 将当前时间调整为偏移量当天结束
$now_dt->subDays($offset)->endOfDay();
// 开始时间偏移量计算
$start_time->subDays($offset);
}
$end_time = Carbon::instance($start_time)->endOfDay();
} else {
$start_time = Carbon::now();
if ($offset > 0) {
// 将当前时间调整为偏移量当周结束
$now_dt->subWeeks($offset)->endOfDay();
// 开始时间偏移量计算
$start_time->subWeeks($offset);
}
$start_time->startOfWeek();
$end_time = Carbon::instance($start_time)->endOfWeek();
}
// 生成唯一标识
$sign = Report::generateSign($type, 0, Carbon::instance($start_time));
$one = Report::query()->whereSign($sign)->whereType($type)->first();
// 如果已经提交了相关汇报
if ($one && $id > 0) {
return Base::retSuccess('success', [
"content" => $one->content,
"title" => $one->title,
"id" => $one->id,
]);
}
// 已完成的任务
$completeContent = "";
$complete_task = ProjectTask::query()
->whereNotNull("complete_at")
->whereBetween("complete_at", [$start_time->toDateTimeString(), $end_time->toDateTimeString()])
->whereHas("taskUser", function ($query) use ($user) {
$query->where("userid", $user->userid);
})
->orderByDesc("id")
->get();
if ($complete_task->isNotEmpty()) {
foreach ($complete_task as $task) {
$complete_at = Carbon::parse($task->complete_at);
$pre = $type == Report::WEEKLY ? ('<span>[' . Base::Lang('周' . ['日', '一', '二', '三', '四', '五', '六'][$complete_at->dayOfWeek]) . ']</span>&nbsp;') : '';
$completeContent .= '<li>' . $pre . $task->name . '</li>';
}
} else {
$completeContent = '<li>&nbsp;</li>';
}
// 未完成的任务
$unfinishedContent = "";
$unfinished_task = ProjectTask::query()
->whereNull("complete_at")
->whereNotNull("start_at")
->where("end_at", "<", $end_time->toDateTimeString())
->whereHas("taskUser", function ($query) use ($user) {
$query->where("userid", $user->userid);
})
->orderByDesc("id")
->get();
if ($unfinished_task->isNotEmpty()) {
foreach ($unfinished_task as $task) {
empty($task->end_at) || $end_at = Carbon::parse($task->end_at);
$pre = (!empty($end_at) && $end_at->lt($now_dt)) ? '<span style="color:#ff0000;">[' . Base::Lang('超期') . ']</span>&nbsp;' : '';
$unfinishedContent .= '<li>' . $pre . $task->name . '</li>';
}
} else {
$unfinishedContent = '<li>&nbsp;</li>';
}
// 生成标题
if ($type === Report::WEEKLY) {
$title = $user->nickname . "的周报[" . $start_time->format("m/d") . "-" . $end_time->format("m/d") . "]";
$title .= "[" . $start_time->month . "月第" . $start_time->weekOfMonth . "周]";
} else {
$title = $user->nickname . "的日报[" . $start_time->format("Y/m/d") . "]";
}
$data = [
"time" => $start_time->toDateTimeString(),
"complete_task" => $complete_task,
"unfinished_task" => $unfinished_task,
"content" => '<h2>' . Base::Lang('已完成工作') . '</h2><ol>' .
$completeContent . '</ol><h2>' .
Base::Lang('未完成的工作') . '</h2><ol>' .
$unfinishedContent . '</ol>',
"title" => $title,
];
if ($one) {
$data['id'] = $one->id;
}
return Base::retSuccess('success', $data);
}
/**
* @api {get} api/report/detail 05. 报告详情
*
* @apiVersion 1.0.0
* @apiGroup report
* @apiName detail
*
* @apiParam {Number} [id] 报告id
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function detail(): array
{
$id = intval(trim(Request::input("id")));
if (empty($id))
return Base::retError("缺少ID参数");
$one = Report::getOne($id);
$one->type_val = $one->getRawOriginal("type");
$user = User::auth();
// 标记为已读
if (!empty($one->receivesUser)) {
foreach ($one->receivesUser as $item) {
if ($item->userid === $user->userid && $item->pivot->read === 0) {
$one->receivesUser()->updateExistingPivot($user->userid, [
"read" => 1,
]);
}
}
}
return Base::retSuccess("success", $one);
}
/**
* @api {get} api/report/last_submitter 06. 获取最后一次提交的接收人
*
* @apiVersion 1.0.0
* @apiGroup report
* @apiName last_submitter
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function last_submitter(): array
{
$one = Report::getLastOne();
return Base::retSuccess("success", empty($one["receives"]) ? [] : $one["receives"]);
}
/**
* @api {get} api/report/unread 07. 获取未读
*
* @apiVersion 1.0.0
* @apiGroup report
* @apiName unread
*
* @apiParam {Number} [userid] 用户id
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function unread(): array
{
$userid = intval(trim(Request::input("userid")));
$user = empty($userid) ? User::auth() : User::find($userid);
$data = Report::whereHas("Receives", function (Builder $query) use ($user) {
$query->where("userid", $user->userid)->where("read", 0);
})->orderByDesc('created_at')->paginate(Base::getPaginate(50, 20));
return Base::retSuccess("success", $data);
}
/**
* @api {get} api/report/read 08. 标记汇报已读,可批量
*
* @apiVersion 1.0.0
* @apiGroup report
* @apiName read
*
* @apiParam {String} [ids] 报告id
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function read(): array
{
$user = User::auth();
$ids = Request::input("ids");
if (!is_array($ids) && !is_string($ids)) {
return Base::retError("请传入正确的工作汇报Id");
}
if (is_string($ids)) {
$ids = explode(",", $ids);
}
$data = Report::with(["receivesUser" => function (BelongsToMany $query) use ($user) {
$query->where("report_receives.userid", $user->userid)->where("read", 0);
}])->whereIn("id", $ids)->get();
if ($data->isNotEmpty()) {
foreach ($data as $item) {
(!empty($item->receivesUser) && $item->receivesUser->isNotEmpty()) && $item->receivesUser()->updateExistingPivot($user->userid, [
"read" => 1,
]);
}
}
return Base::retSuccess("success", $data);
}
}

View File

@ -101,16 +101,12 @@ class SystemController extends AbstractController
} }
/** /**
* @api {post} api/system/priority 03. 任务优先级 * @api {post} api/system/priority 03. 获取优先级、保存优先级
* *
* @apiDescription 获取任务优先级、保存任务优先级
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup system * @apiGroup system
* @apiName priority * @apiName priority
* *
* @apiParam {String} type
* - get: 获取(默认)
* - save: 保存(限管理员)
* @apiParam {Array} list 优先级数据,格式:[{name,color,days,priority}] * @apiParam {Array} list 优先级数据,格式:[{name,color,days,priority}]
* *
* @apiSuccess {Number} ret 返回状态码1正确、0错误 * @apiSuccess {Number} ret 返回状态码1正确、0错误
@ -150,54 +146,7 @@ class SystemController extends AbstractController
} }
/** /**
* @api {post} api/system/column/template 04. 创建项目模板 * @api {get} api/system/get/info 04. 获取终端详细信息
*
* @apiDescription 获取创建项目模板、保存创建项目模板
* @apiVersion 1.0.0
* @apiGroup system
* @apiName column__template
*
* @apiParam {String} type
* - get: 获取(默认)
* - save: 保存(限管理员)
* @apiParam {Array} list 优先级数据,格式:[{name,columns}]
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function column__template()
{
$type = trim(Request::input('type'));
if ($type == 'save') {
User::auth('admin');
$list = Base::getPostValue('list');
$array = [];
if (empty($list) || !is_array($list)) {
return Base::retError('参数错误');
}
foreach ($list AS $item) {
if (empty($item['name']) || empty($item['columns'])) {
continue;
}
$array[] = [
'name' => $item['name'],
'columns' => array_values(array_filter(array_unique(explode(",", $item['columns']))))
];
}
if (empty($array)) {
return Base::retError('参数为空');
}
$setting = Base::setting('columnTemplate', $array);
} else {
$setting = Base::setting('columnTemplate');
}
//
return Base::retSuccess('success', $setting);
}
/**
* @api {get} api/system/get/info 05. 获取终端详细信息
* *
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup system * @apiGroup system
@ -226,7 +175,7 @@ class SystemController extends AbstractController
} }
/** /**
* @api {get} api/system/get/ip 06. 获取IP地址 * @api {get} api/system/get/ip 05. 获取IP地址
* *
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup system * @apiGroup system
@ -241,7 +190,7 @@ class SystemController extends AbstractController
} }
/** /**
* @api {get} api/system/get/cnip 07. 是否中国IP地址 * @api {get} api/system/get/cnip 06. 是否中国IP地址
* *
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup system * @apiGroup system
@ -258,7 +207,7 @@ class SystemController extends AbstractController
} }
/** /**
* @api {get} api/system/get/ipgcj02 08. 获取IP地址经纬度 * @api {get} api/system/get/ipgcj02 07. 获取IP地址经纬度
* *
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup system * @apiGroup system
@ -275,7 +224,7 @@ class SystemController extends AbstractController
} }
/** /**
* @api {get} api/system/get/ipinfo 09. 获取IP地址详细信息 * @api {get} api/system/get/ipinfo 08. 获取IP地址详细信息
* *
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup system * @apiGroup system
@ -292,7 +241,7 @@ class SystemController extends AbstractController
} }
/** /**
* @api {post} api/system/imgupload 10. 上传图片 * @api {post} api/system/imgupload 09. 上传图片
* *
* @apiDescription 需要token身份 * @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -315,7 +264,7 @@ class SystemController extends AbstractController
if (!$scale[0] && !$scale[1]) { if (!$scale[0] && !$scale[1]) {
$scale = [2160, 4160, -1]; $scale = [2160, 4160, -1];
} }
$path = "uploads/user/picture/" . User::userid() . "/" . date("Ym") . "/"; $path = "uploads/picture/" . User::userid() . "/" . date("Ym") . "/";
$image64 = trim(Base::getPostValue('image64')); $image64 = trim(Base::getPostValue('image64'));
$fileName = trim(Base::getPostValue('filename')); $fileName = trim(Base::getPostValue('filename'));
if ($image64) { if ($image64) {
@ -342,7 +291,7 @@ class SystemController extends AbstractController
} }
/** /**
* @api {get} api/system/get/imgview 11. 浏览图片空间 * @api {get} api/system/get/imgview 10. 浏览图片空间
* *
* @apiDescription 需要token身份 * @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -360,7 +309,7 @@ class SystemController extends AbstractController
if (User::userid() === 0) { if (User::userid() === 0) {
return Base::retError('身份失效,等重新登录'); return Base::retError('身份失效,等重新登录');
} }
$publicPath = "uploads/user/picture/" . User::userid() . "/"; $publicPath = "uploads/picture/" . User::userid() . "/";
$dirPath = public_path($publicPath); $dirPath = public_path($publicPath);
$dirs = $files = []; $dirs = $files = [];
// //
@ -438,7 +387,7 @@ class SystemController extends AbstractController
} }
/** /**
* @api {post} api/system/fileupload 12. 上传文件 * @api {post} api/system/fileupload 11. 上传文件
* *
* @apiDescription 需要token身份 * @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -458,7 +407,7 @@ class SystemController extends AbstractController
if (User::userid() === 0) { if (User::userid() === 0) {
return Base::retError('身份失效,等重新登录'); return Base::retError('身份失效,等重新登录');
} }
$path = "uploads/user/file/" . User::userid() . "/" . date("Ym") . "/"; $path = "uploads/files/" . User::userid() . "/" . date("Ym") . "/";
$image64 = trim(Base::getPostValue('image64')); $image64 = trim(Base::getPostValue('image64'));
$fileName = trim(Base::getPostValue('filename')); $fileName = trim(Base::getPostValue('filename'));
if ($image64) { if ($image64) {

View File

@ -21,9 +21,6 @@ class VerifyCsrfToken extends Middleware
// 保存任务优先级 // 保存任务优先级
'api/system/priority/', 'api/system/priority/',
// 保存创建项目列表模板
'api/system/column/template/',
// 添加任务 // 添加任务
'api/project/task/add/', 'api/project/task/add/',
@ -33,8 +30,8 @@ class VerifyCsrfToken extends Middleware
// 修改任务 // 修改任务
'api/project/task/update/', 'api/project/task/update/',
// 聊天发文本 // 上传任务问题
'api/dialog/msg/sendtext/', 'api/project/task/upload/',
// 聊天发文件 // 聊天发文件
'api/dialog/msg/sendfile/', 'api/dialog/msg/sendfile/',
@ -47,8 +44,5 @@ class VerifyCsrfToken extends Middleware
// 保存文件内容(上传) // 保存文件内容(上传)
'api/file/content/upload/', 'api/file/content/upload/',
// 保存汇报
'api/report/store/',
]; ];
} }

View File

@ -18,7 +18,6 @@ use Illuminate\Support\Facades\DB;
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore() * @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue() * @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
* @method static \Illuminate\Database\Eloquent\Model|object|static|null cancelAppend() * @method static \Illuminate\Database\Eloquent\Model|object|static|null cancelAppend()
* @method static \Illuminate\Database\Eloquent\Model|object|static|null cancelHidden()
* @method static \Illuminate\Database\Eloquent\Builder|static with($relations) * @method static \Illuminate\Database\Eloquent\Builder|static with($relations)
* @method static \Illuminate\Database\Query\Builder|static select($columns = []) * @method static \Illuminate\Database\Query\Builder|static select($columns = [])
* @method static \Illuminate\Database\Query\Builder|static whereNotIn($column, $values, $boolean = 'and') * @method static \Illuminate\Database\Query\Builder|static whereNotIn($column, $values, $boolean = 'and')
@ -73,15 +72,6 @@ class AbstractModel extends Model
return $this->setAppends([]); return $this->setAppends([]);
} }
/**
* 取消隐藏值
* @return static
*/
protected function scopeCancelHidden()
{
return $this->setHidden([]);
}
/** /**
* 为数组 / JSON 序列化准备日期。 * 为数组 / JSON 序列化准备日期。
* @param DateTimeInterface $date * @param DateTimeInterface $date
@ -153,10 +143,9 @@ class AbstractModel extends Model
* @param $where * @param $where
* @param array $update 存在时更新的内容 * @param array $update 存在时更新的内容
* @param array $insert 不存在时插入的内容,如果没有则插入更新内容 * @param array $insert 不存在时插入的内容,如果没有则插入更新内容
* @param bool $isInsert 是否是插入数据
* @return AbstractModel|\Illuminate\Database\Eloquent\Builder|Model|object|static|null * @return AbstractModel|\Illuminate\Database\Eloquent\Builder|Model|object|static|null
*/ */
public static function updateInsert($where, $update = [], $insert = [], &$isInsert = true) public static function updateInsert($where, $update = [], $insert = [])
{ {
$row = static::where($where)->first(); $row = static::where($where)->first();
if (empty($row)) { if (empty($row)) {
@ -166,10 +155,8 @@ class AbstractModel extends Model
unset($array[$row->primaryKey]); unset($array[$row->primaryKey]);
} }
$row->updateInstance($array); $row->updateInstance($array);
$isInsert = true;
} elseif ($update) { } elseif ($update) {
$row->updateInstance($update); $row->updateInstance($update);
$isInsert = false;
} }
if (!$row->save()) { if (!$row->save()) {
return null; return null;

View File

@ -50,48 +50,15 @@ class File extends AbstractModel
{ {
use SoftDeletes; use SoftDeletes;
/**
* 文件文件
*/
const codeExt = [
'txt',
'htaccess', 'htgroups', 'htpasswd', 'conf', 'bat', 'cmd', 'cpp', 'c', 'cc', 'cxx', 'h', 'hh', 'hpp', 'ino', 'cs', 'css',
'dockerfile', 'go', 'html', 'htm', 'xhtml', 'vue', 'we', 'wpy', 'java', 'js', 'jsm', 'jsx', 'json', 'jsp', 'less', 'lua', 'makefile', 'gnumakefile',
'ocamlmakefile', 'make', 'mysql', 'nginx', 'ini', 'cfg', 'prefs', 'm', 'mm', 'pl', 'pm', 'p6', 'pl6', 'pm6', 'pgsql', 'php',
'inc', 'phtml', 'shtml', 'php3', 'php4', 'php5', 'phps', 'phpt', 'aw', 'ctp', 'module', 'ps1', 'py', 'r', 'rb', 'ru', 'gemspec', 'rake', 'guardfile', 'rakefile',
'gemfile', 'rs', 'sass', 'scss', 'sh', 'bash', 'bashrc', 'sql', 'sqlserver', 'swift', 'ts', 'typescript', 'str', 'vbs', 'vb', 'v', 'vh', 'sv', 'svh', 'xml',
'rdf', 'rss', 'wsdl', 'xslt', 'atom', 'mathml', 'mml', 'xul', 'xbl', 'xaml', 'yaml', 'yml',
'asp', 'properties', 'gitignore', 'log', 'bas', 'prg', 'python', 'ftl', 'aspx'
];
/**
* office文件
*/
const officeExt = [
'doc', 'docx',
'xls', 'xlsx',
'ppt', 'pptx',
];
/**
* 本地媒体文件
*/
const localExt = [
'jpg', 'jpeg', 'png', 'gif', 'bmp', 'ico', 'raw',
'tif', 'tiff',
'mp3', 'wav', 'mp4', 'flv',
'avi', 'mov', 'wmv', 'mkv', '3gp', 'rm',
];
/** /**
* 是否有访问权限 * 是否有访问权限
* @param $userid * @param $userid
* @return int -1:没有权限0:访问权限1:读写权限1000:所有者或创建者 * @return int -1:没有权限0:访问权限1:读写权限1000:所有者
*/ */
public function getPermission($userid) public function getPermission($userid)
{ {
if ($userid == $this->userid || $userid == $this->created_id) { if ($userid == $this->userid) {
// ① 自己的文件夹 或 自己创建的文件夹 // ① 自己的文件夹
return 1000; return 1000;
} }
$row = $this->getShareInfo(); $row = $this->getShareInfo();
@ -250,7 +217,7 @@ class File extends AbstractModel
/** /**
* 获取文件并检测权限 * 获取文件并检测权限
* @param $id * @param $id
* @param int $limit 要求权限: 0-访问权限、1-读写权限、1000-所有者或创建者 * @param int $limit 要求权限: 0-访问权限、1-读写权限、1000-所有者
* @param $permission * @param $permission
* @return File * @return File
*/ */
@ -264,7 +231,7 @@ class File extends AbstractModel
$permission = $file->getPermission(User::userid()); $permission = $file->getPermission(User::userid());
if ($permission < $limit) { if ($permission < $limit) {
$msg = match ($limit) { $msg = match ($limit) {
1000 => '仅限所有者或创建者操作', 1000 => '仅限所有者操作',
1 => '没有读写权限', 1 => '没有读写权限',
default => '没有访问权限', default => '没有访问权限',
}; };
@ -272,77 +239,4 @@ class File extends AbstractModel
} }
return $file; return $file;
} }
/**
* 格式化内容数据
* @param array $data [path, size, ext, name]
* @return array
*/
public static function formatFileData(array $data)
{
$filePath = $data['path'];
$fileSize = $data['size'];
$fileExt = $data['ext'];
$fileDotExt = '.' . $fileExt;
$fileName = Base::rightDelete($data['name'], $fileDotExt) . $fileDotExt;
$publicPath = public_path($filePath);
//
switch ($fileExt) {
case 'md':
case 'text':
// 文本
$data['content'] = [
'type' => $fileExt,
'content' => file_get_contents($publicPath),
];
$data['file_mode'] = $fileExt;
break;
case 'drawio':
// 图表
$data['content'] = [
'xml' => file_get_contents($publicPath)
];
$data['file_mode'] = $fileExt;
break;
case 'mind':
// 思维导图
$data['content'] = Base::json2array(file_get_contents($publicPath));
$data['file_mode'] = $fileExt;
break;
default:
if (in_array($fileExt, self::codeExt) && $fileSize < 2 * 1024 * 1024)
{
// 文本预览限制2M内的文件
$data['content'] = file_get_contents($publicPath);
$data['file_mode'] = 'code';
}
elseif (in_array($fileExt, File::officeExt))
{
// office预览
$data['content'] = '';
$data['file_mode'] = 'office';
}
else
{
// 其他预览
if (in_array($fileExt, File::localExt)) {
$url = Base::fillUrl($filePath);
} else {
$url = 'http://' . env('APP_IPPR') . '.3/' . $filePath;
}
$data['content'] = [
'preview' => true,
'url' => base64_encode(Base::urlAddparameter($url, [
'fullfilename' => $fileName
])),
];
$data['file_mode'] = 'preview';
}
break;
}
return $data;
}
} }

View File

@ -41,53 +41,43 @@ class FileContent extends AbstractModel
use SoftDeletes; use SoftDeletes;
/** /**
* 获取格式内容(或下载) * 获取格式内容
* @param File $file * @param $type
* @param $content * @param $content
* @param $download
* @return array|\Symfony\Component\HttpFoundation\BinaryFileResponse * @return array|\Symfony\Component\HttpFoundation\BinaryFileResponse
*/ */
public static function formatContent($file, $content, $download = false) public static function formatContent($type, $content)
{ {
$name = $file->ext ? "{$file->name}.{$file->ext}" : null; $content = Base::json2array($content);
$content = Base::json2array($content ?: []); if (in_array($type, ['word', 'excel', 'ppt'])) {
if (in_array($file->type, ['word', 'excel', 'ppt'])) {
if (empty($content)) { if (empty($content)) {
return Response::download(resource_path('assets/statics/office/empty.' . str_replace(['word', 'excel', 'ppt'], ['docx', 'xlsx', 'pptx'], $file->type)), $name); return Response::download(resource_path('assets/statics/office/empty.' . str_replace(['word', 'excel', 'ppt'], ['docx', 'xlsx', 'pptx'], $type)));
} }
return Response::download(public_path($content['url']), $name); return Response::download(public_path($content['url']));
} }
if (empty($content)) { if (empty($content)) {
$content = match ($file->type) { $content = match ($type) {
'document' => [ 'document' => [
"type" => $file->ext, "type" => "md",
"content" => "", "content" => "",
], ],
'sheet' => [
[
"name" => "Sheet1",
"config" => json_decode('{}'),
]
],
default => json_decode('{}'), default => json_decode('{}'),
}; };
if ($download) {
abort(403, "This file is empty.");
}
} else { } else {
$path = $content['url']; $content['preview'] = false;
if ($file->ext) { if ($content['ext'] && !in_array($content['ext'], ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'])) {
$res = File::formatFileData([ $url = 'http://' . env('APP_IPPR') . '.3/' . $content['url'];
'path' => $path, if (in_array($type, ['picture', 'image', 'tif', 'media'])) {
'ext' => $file->ext, $url = Base::fillUrl($content['url']);
'size' => $file->size,
'name' => $file->name,
]);
$content = $res['content'];
} else {
$content['preview'] = false;
}
if ($download) {
$filePath = public_path($path);
if (isset($filePath)) {
return Response::download($filePath, $name);
} else {
abort(403, "This file not support download.");
} }
$content['url'] = base64_encode($url);
$content['preview'] = true;
} }
} }
return Base::retSuccess('success', [ 'content' => $content ]); return Base::retSuccess('success', [ 'content' => $content ]);

View File

@ -3,7 +3,6 @@
namespace App\Models; namespace App\Models;
use App\Exceptions\ApiException; use App\Exceptions\ApiException;
use App\Module\Base;
use App\Tasks\PushTask; use App\Tasks\PushTask;
use Carbon\Carbon; use Carbon\Carbon;
use DB; use DB;
@ -113,7 +112,6 @@ class Project extends AbstractModel
->select([ ->select([
'projects.*', 'projects.*',
'project_users.owner', 'project_users.owner',
'project_users.top_at',
]) ])
->leftJoin('project_users', function ($leftJoin) use ($userid) { ->leftJoin('project_users', function ($leftJoin) use ($userid) {
$leftJoin $leftJoin
@ -137,7 +135,6 @@ class Project extends AbstractModel
->select([ ->select([
'projects.*', 'projects.*',
'project_users.owner', 'project_users.owner',
'project_users.top_at',
]) ])
->join('project_users', 'projects.id', '=', 'project_users.project_id') ->join('project_users', 'projects.id', '=', 'project_users.project_id')
->where('project_users.userid', $userid); ->where('project_users.userid', $userid);
@ -214,7 +211,7 @@ class Project extends AbstractModel
*/ */
public function relationUserids() public function relationUserids()
{ {
return ProjectUser::whereProjectId($this->id)->orderBy('id')->pluck('userid')->toArray(); return $this->projectUser->pluck('userid')->toArray();
} }
/** /**
@ -353,114 +350,6 @@ class Project extends AbstractModel
} }
} }
/**
* 添加工作流
* @param $flows
* @return mixed
*/
public function addFlow($flows)
{
return AbstractModel::transaction(function() use ($flows) {
$projectFlow = ProjectFlow::whereProjectId($this->id)->first();
if (empty($projectFlow)) {
$projectFlow = ProjectFlow::createInstance([
'project_id' => $this->id,
'name' => 'Default'
]);
if (!$projectFlow->save()) {
throw new ApiException('工作流创建失败');
}
}
//
$ids = [];
$idc = [];
$hasStart = false;
$hasEnd = false;
$upTaskList = [];
foreach ($flows as $item) {
$id = intval($item['id']);
$turns = Base::arrayRetainInt($item['turns'] ?: [], true);
$userids = Base::arrayRetainInt($item['userids'] ?: [], true);
$usertype = trim($item['usertype']);
$userlimit = intval($item['userlimit']);
if ($usertype == 'replace' && empty($userids)) {
throw new ApiException("状态[{$item['name']}]设置错误,设置流转模式时必须填写状态负责人");
}
if ($usertype == 'merge' && empty($userids)) {
throw new ApiException("状态[{$item['name']}]设置错误,设置剔除模式时必须填写状态负责人");
}
if ($userlimit && empty($userids)) {
throw new ApiException("状态[{$item['name']}]设置错误,设置限制负责人时必须填写状态负责人");
}
$flow = ProjectFlowItem::updateInsert([
'id' => $id,
'project_id' => $this->id,
'flow_id' => $projectFlow->id,
], [
'name' => trim($item['name']),
'status' => trim($item['status']),
'sort' => intval($item['sort']),
'turns' => $turns,
'userids' => $userids,
'usertype' => trim($item['usertype']),
'userlimit' => $userlimit,
], [], $isInsert);
if ($flow) {
$ids[] = $flow->id;
if ($flow->id != $id) {
$idc[$id] = $flow->id;
}
if ($flow->status == 'start') {
$hasStart = true;
}
if ($flow->status == 'end') {
$hasEnd = true;
}
if (!$isInsert) {
$upTaskList[$flow->id] = $flow->status . "|" . $flow->name;
}
}
}
if (!$hasStart) {
throw new ApiException('至少需要1个开始状态');
}
if (!$hasEnd) {
throw new ApiException('至少需要1个结束状态');
}
ProjectFlowItem::whereFlowId($projectFlow->id)->whereNotIn('id', $ids)->chunk(100, function($list) {
foreach ($list as $item) {
$item->deleteFlowItem();
}
});
//
foreach ($upTaskList as $id => $value) {
ProjectTask::whereFlowItemId($id)->update([
'flow_item_name' => $value
]);
}
//
$projectFlow = ProjectFlow::with(['projectFlowItem'])->whereProjectId($this->id)->find($projectFlow->id);
$itemIds = $projectFlow->projectFlowItem->pluck('id')->toArray();
foreach ($projectFlow->projectFlowItem as $item) {
$turns = $item->turns;
foreach ($idc as $oid => $nid) {
if (in_array($oid, $turns)) {
$turns = array_diff($turns, [$oid]);
$turns[] = $nid;
}
}
if (!in_array($item->id, $turns)) {
$turns[] = $item->id;
}
$turns = array_values(array_filter(array_unique(array_intersect($turns, $itemIds))));
sort($turns);
$item->turns = $turns;
ProjectFlowItem::whereId($item->id)->update([ 'turns' => Base::array2json($turns) ]);
}
return $projectFlow;
});
}
/** /**
* 获取项目信息(用于判断会员是否存在项目内) * 获取项目信息(用于判断会员是否存在项目内)
* @param int $project_id * @param int $project_id

View File

@ -342,13 +342,11 @@ class ProjectTask extends AbstractModel
$content = $data['content']; $content = $data['content'];
$times = $data['times']; $times = $data['times'];
$owner = $data['owner']; $owner = $data['owner'];
$add_assist = intval($data['add_assist']);
$subtasks = $data['subtasks']; $subtasks = $data['subtasks'];
$p_level = intval($data['p_level']); $p_level = intval($data['p_level']);
$p_name = $data['p_name']; $p_name = $data['p_name'];
$p_color = $data['p_color']; $p_color = $data['p_color'];
$top = intval($data['top']); $top = intval($data['top']);
$userid = User::userid();
// //
if (ProjectTask::whereProjectId($project_id) if (ProjectTask::whereProjectId($project_id)
->whereNull('project_tasks.complete_at') ->whereNull('project_tasks.complete_at')
@ -413,13 +411,8 @@ class ProjectTask extends AbstractModel
$tmpArray[] = $uid; $tmpArray[] = $uid;
} }
$owner = $tmpArray; $owner = $tmpArray;
// 协助人员
$assist = [];
if (!in_array($userid, $owner) && $add_assist) {
$assist = [$userid];
}
// 创建人 // 创建人
$task->userid = $userid; $task->userid = User::userid();
// 排序位置 // 排序位置
if ($top) { if ($top) {
$task->sort = intval(self::whereColumnId($task->column_id)->orderBy('sort')->value('sort')) - 1; $task->sort = intval(self::whereColumnId($task->column_id)->orderBy('sort')->value('sort')) - 1;
@ -441,7 +434,7 @@ class ProjectTask extends AbstractModel
} }
} }
// //
return AbstractModel::transaction(function() use ($assist, $times, $subtasks, $content, $owner, $task) { return AbstractModel::transaction(function() use ($times, $subtasks, $content, $owner, $task) {
$task->save(); $task->save();
$owner = array_values(array_unique($owner)); $owner = array_values(array_unique($owner));
foreach ($owner as $uid) { foreach ($owner as $uid) {
@ -453,16 +446,6 @@ class ProjectTask extends AbstractModel
'owner' => 1, 'owner' => 1,
])->save(); ])->save();
} }
$assist = array_values(array_unique(array_diff($assist, $owner)));
foreach ($assist as $uid) {
ProjectTaskUser::createInstance([
'project_id' => $task->project_id,
'task_id' => $task->id,
'task_pid' => $task->parent_id ?: $task->id,
'userid' => $uid,
'owner' => 0,
])->save();
}
if ($content) { if ($content) {
ProjectTaskContent::createInstance([ ProjectTaskContent::createInstance([
'project_id' => $task->project_id, 'project_id' => $task->project_id,
@ -508,15 +491,13 @@ class ProjectTask extends AbstractModel
{ {
AbstractModel::transaction(function () use ($data, &$updateMarking) { AbstractModel::transaction(function () use ($data, &$updateMarking) {
// 判断版本 // 判断版本
Base::checkClientVersion('0.6.0'); if (version_compare(Base::getClientVersion(), '0.6.0', '<')) {
throw new ApiException('当前版本过低');
}
// 主任务 // 主任务
$mainTask = $this->parent_id > 0 ? self::find($this->parent_id) : null; $mainTask = $this->parent_id > 0 ? self::find($this->parent_id) : null;
// 工作流 // 工作流
if (Arr::exists($data, 'flow_item_id')) { if (Arr::exists($data, 'flow_item_id')) {
$isProjectOwner = $this->useridInTheProject(User::userid()) === 2;
if (!$isProjectOwner && !$this->isOwner()) {
throw new ApiException('仅限项目或任务负责人修改任务状态');
}
if ($this->flow_item_id == $data['flow_item_id']) { if ($this->flow_item_id == $data['flow_item_id']) {
throw new ApiException('任务状态未发生改变'); throw new ApiException('任务状态未发生改变');
} }
@ -537,7 +518,8 @@ class ProjectTask extends AbstractModel
throw new ApiException("当前状态[{$currentFlowItem->name}]不可流转到[{$newFlowItem->name}]"); throw new ApiException("当前状态[{$currentFlowItem->name}]不可流转到[{$newFlowItem->name}]");
} }
if ($currentFlowItem->userlimit) { if ($currentFlowItem->userlimit) {
if (!$isProjectOwner && !in_array(User::userid(), $currentFlowItem->userids)) { if (!in_array(User::userid(), $currentFlowItem->userids)
&& !ProjectUser::whereProjectId($this->project_id)->whereOwner(1)->exists()) {
throw new ApiException("当前状态[{$currentFlowItem->name}]仅限状态负责人或项目负责人修改"); throw new ApiException("当前状态[{$currentFlowItem->name}]仅限状态负责人或项目负责人修改");
} }
} }
@ -559,17 +541,13 @@ class ProjectTask extends AbstractModel
if ($newFlowItem->userids) { if ($newFlowItem->userids) {
// 判断自动添加负责人 // 判断自动添加负责人
$flowData['owner'] = $data['owner'] = $this->taskUser->where('owner', 1)->pluck('userid')->toArray(); $flowData['owner'] = $data['owner'] = $this->taskUser->where('owner', 1)->pluck('userid')->toArray();
if (in_array($newFlowItem->usertype, ["replace", "merge"])) { if ($newFlowItem->usertype == "replace") {
// 流转模式、剔除模式 // 流转模式
if ($this->parent_id === 0) { if ($this->parent_id === 0) {
$flowData['assist'] = $data['assist'] = $this->taskUser->where('owner', 0)->pluck('userid')->toArray(); $flowData['assist'] = $data['assist'] = $this->taskUser->where('owner', 0)->pluck('userid')->toArray();
$data['assist'] = array_merge($data['assist'], $data['owner']); $data['assist'] = array_merge($data['assist'], $data['owner']);
} }
$data['owner'] = $newFlowItem->userids; $data['owner'] = $newFlowItem->userids;
// 判断剔除模式:保留操作状态的人员
if ($newFlowItem->usertype == "merge") {
$data['owner'][] = User::userid();
}
} else { } else {
// 添加模式 // 添加模式
$data['owner'] = array_merge($data['owner'], $newFlowItem->userids); $data['owner'] = array_merge($data['owner'], $newFlowItem->userids);
@ -585,14 +563,6 @@ class ProjectTask extends AbstractModel
'flow' => $flowData, 'flow' => $flowData,
'change' => [$currentFlowItem?->name, $newFlowItem->name] 'change' => [$currentFlowItem?->name, $newFlowItem->name]
]); ]);
ProjectTaskFlowChange::createInstance([
'task_id' => $this->id,
'userid' => User::userid(),
'before_flow_item_id' => $flowData['flow_item_id'],
'before_flow_item_name' => $flowData['flow_item_name'],
'after_flow_item_id' => $this->flow_item_id,
'after_flow_item_name' => $this->flow_item_name,
])->save();
} }
// 状态 // 状态
if (Arr::exists($data, 'complete_at')) { if (Arr::exists($data, 'complete_at')) {
@ -614,6 +584,7 @@ class ProjectTask extends AbstractModel
$this->completeTask(null); $this->completeTask(null);
} }
$updateMarking['is_update_project'] = true; $updateMarking['is_update_project'] = true;
return;
} }
// 标题 // 标题
if (Arr::exists($data, 'name') && $this->name != $data['name']) { if (Arr::exists($data, 'name') && $this->name != $data['name']) {
@ -672,7 +643,6 @@ class ProjectTask extends AbstractModel
// 计划时间(原则:子任务时间在主任务时间内) // 计划时间(原则:子任务时间在主任务时间内)
if (Arr::exists($data, 'times')) { if (Arr::exists($data, 'times')) {
$oldAt = [Carbon::parse($this->start_at), Carbon::parse($this->end_at)]; $oldAt = [Carbon::parse($this->start_at), Carbon::parse($this->end_at)];
$oldStringAt = $this->start_at ? ($oldAt[0]->toDateTimeString() . '~' . $oldAt[1]->toDateTimeString()) : '';
$this->start_at = null; $this->start_at = null;
$this->end_at = null; $this->end_at = null;
$times = $data['times']; $times = $data['times'];
@ -716,18 +686,14 @@ class ProjectTask extends AbstractModel
$start_at = Carbon::parse($subTask->start_at); $start_at = Carbon::parse($subTask->start_at);
$end_at = Carbon::parse($subTask->end_at); $end_at = Carbon::parse($subTask->end_at);
$isUp = false; $isUp = false;
if (empty($subTask->start_at) || $start_at->eq($oldAt[0]) || $start_at->lt(Carbon::parse($this->start_at))) { if ($start_at->eq($oldAt[0]) || $start_at->lt(Carbon::parse($this->start_at))) {
$subTask->start_at = $this->start_at; $subTask->start_at = $this->start_at;
$isUp = true; $isUp = true;
} }
if (empty($subTask->end_at) || $end_at->eq($oldAt[1]) || $end_at->gt(Carbon::parse($this->end_at))) { if ($end_at->eq($oldAt[1]) || $end_at->gt(Carbon::parse($this->end_at))) {
$subTask->end_at = $this->end_at; $subTask->end_at = $this->end_at;
$isUp = true; $isUp = true;
} }
if ($subTask->start_at && Carbon::parse($subTask->start_at)->gt($subTask->end_at)) {
$subTask->start_at = $this->start_at;
$isUp = true;
}
if ($isUp) { if ($isUp) {
$updateMarking['is_update_subtask'] = true; $updateMarking['is_update_subtask'] = true;
$subTask->addLog("同步修改{任务}时间"); $subTask->addLog("同步修改{任务}时间");
@ -736,10 +702,7 @@ class ProjectTask extends AbstractModel
} }
}); });
} }
$newStringAt = $this->start_at ? ($this->start_at->toDateTimeString() . '~' . $this->end_at->toDateTimeString()) : ''; $this->addLog("修改{任务}时间");
$this->addLog("修改{任务}时间", [
'change' => [$oldStringAt, $newStringAt]
]);
} }
// 以下紧顶级任务可修改 // 以下紧顶级任务可修改
if ($this->parent_id === 0) { if ($this->parent_id === 0) {
@ -809,7 +772,6 @@ class ProjectTask extends AbstractModel
} }
// 优先级 // 优先级
$p = false; $p = false;
$oldPName = $this->p_name;
if (Arr::exists($data, 'p_level') && $this->p_level != $data['p_level']) { if (Arr::exists($data, 'p_level') && $this->p_level != $data['p_level']) {
$this->p_level = intval($data['p_level']); $this->p_level = intval($data['p_level']);
$p = true; $p = true;
@ -823,9 +785,7 @@ class ProjectTask extends AbstractModel
$p = true; $p = true;
} }
if ($p) { if ($p) {
$this->addLog("修改{任务}优先级", [ $this->addLog("修改{任务}优先级");
'change' => [$oldPName, $this->p_name]
]);
} }
} }
$this->save(); $this->save();
@ -866,7 +826,7 @@ class ProjectTask extends AbstractModel
*/ */
public function relationUserids() public function relationUserids()
{ {
$userids = ProjectTaskUser::whereTaskId($this->id)->orderByDesc('owner')->orderByDesc('id')->pluck('userid')->toArray(); $userids = $this->taskUser->pluck('userid')->toArray();
$items = ProjectTask::with(['taskUser'])->where('parent_id', $this->id)->whereNull('archived_at')->get(); $items = ProjectTask::with(['taskUser'])->where('parent_id', $this->id)->whereNull('archived_at')->get();
foreach ($items as $item) { foreach ($items as $item) {
$userids = array_merge($userids, $item->taskUser->pluck('userid')->toArray()); $userids = array_merge($userids, $item->taskUser->pluck('userid')->toArray());
@ -902,62 +862,6 @@ class ProjectTask extends AbstractModel
return $user->owner ? 2 : 1; return $user->owner ? 2 : 1;
} }
/**
* 权限版本
* @param int $level 1-负责人2-协助人/负责人3-创建人/协助人/负责人
* @return bool
*/
public function permission($level = 1)
{
if ($level >= 3 && $this->isCreater()) {
return true;
}
if ($level >= 2 && $this->isAssister()) {
return true;
}
return $this->isOwner();
}
/**
* 判断是否创建者
* @return bool
*/
public function isCreater()
{
return $this->userid == User::userid();
}
/**
* 判断是否协助人员
* @return bool
*/
public function isAssister()
{
$row = $this;
while ($row->parent_id > 0) {
$row = self::find($row->parent_id);
}
return ProjectTaskUser::whereTaskId($row->id)->whereUserid(User::userid())->whereOwner(0)->exists();
}
/**
* 判断是否负责人(或者是主任务的负责人)
* @return bool
*/
public function isOwner()
{
if ($this->owner) {
return true;
}
if ($this->parent_id > 0) {
$mainTask = self::allData()->find($this->parent_id);
if ($mainTask->owner) {
return true;
}
}
return false;
}
/** /**
* 是否有负责人 * 是否有负责人
* @return bool * @return bool
@ -1007,16 +911,6 @@ class ProjectTask extends AbstractModel
*/ */
public function archivedTask($archived_at, $isAuto = false) public function archivedTask($archived_at, $isAuto = false)
{ {
if (!$this->complete_at) {
$flowItems = ProjectFlowItem::whereProjectId($this->project_id)->whereStatus('end')->pluck('name');
if ($flowItems) {
$flowItems = implode(",", array_values(array_unique($flowItems->toArray())));
}
if (empty($flowItems)) {
$flowItems = "已完成";
}
throw new ApiException('仅限【' . $flowItems . '】状态的任务归档');
}
AbstractModel::transaction(function () use ($isAuto, $archived_at) { AbstractModel::transaction(function () use ($isAuto, $archived_at) {
if ($archived_at === null) { if ($archived_at === null) {
// 取消归档 // 取消归档
@ -1024,6 +918,7 @@ class ProjectTask extends AbstractModel
$this->archived_userid = User::userid(); $this->archived_userid = User::userid();
$this->archived_follow = 0; $this->archived_follow = 0;
$this->addLog("任务取消归档"); $this->addLog("任务取消归档");
$this->pushMsg('add', ProjectTask::oneTask($this->id));
} else { } else {
// 归档任务 // 归档任务
if ($isAuto === true) { if ($isAuto === true) {
@ -1037,12 +932,8 @@ class ProjectTask extends AbstractModel
$this->archived_userid = $userid; $this->archived_userid = $userid;
$this->archived_follow = 0; $this->archived_follow = 0;
$this->addLog($logText, [], $userid); $this->addLog($logText, [], $userid);
$this->pushMsg('archived');
} }
$this->pushMsg('update', [
'id' => $this->id,
'archived_at' => $this->archived_at,
'archived_userid' => $this->archived_userid,
]);
self::whereParentId($this->id)->update([ self::whereParentId($this->id)->update([
'archived_at' => $this->archived_at, 'archived_at' => $this->archived_at,
'archived_userid' => $this->archived_userid, 'archived_userid' => $this->archived_userid,
@ -1168,12 +1059,12 @@ class ProjectTask extends AbstractModel
/** /**
* 获取任务(会员有任务权限 会员存在项目内) * 获取任务(会员有任务权限 会员存在项目内)
* @param int $task_id * @param int $task_id
* @param bool $archived true:仅限未归档, false:仅限已归档, null:不限制 * @param bool $archived true:仅限未归档, false:不限制, null:不限制
* @param int|bool $permission 0|false:不限制, 1|true:限制项目负责人、任务负责人、协助人员及任务创建者, 2:已有负责人才限制true (子任务时如果是主任务负责人也可以) * @param int|bool $mustOwner 0|false:不限制, 1|true:限制任务或项目负责人, 2:已有负责人才限制任务或项目负责人
* @param array $with * @param array $with
* @return self * @return self
*/ */
public static function userTask($task_id, $archived = true, $permission = 0, $with = []) public static function userTask($task_id, $archived = true, $mustOwner = 0, $with = [])
{ {
$task = self::with($with)->allData()->where("project_tasks.id", intval($task_id))->first(); $task = self::with($with)->allData()->where("project_tasks.id", intval($task_id))->first();
// //
@ -1181,14 +1072,14 @@ class ProjectTask extends AbstractModel
throw new ApiException('任务不存在', [ 'task_id' => $task_id ], -4002); throw new ApiException('任务不存在', [ 'task_id' => $task_id ], -4002);
} }
if ($archived === true && $task->archived_at != null) { if ($archived === true && $task->archived_at != null) {
throw new ApiException('任务已归档', [ 'task_id' => $task_id ]); throw new ApiException('任务已归档', [ 'task_id' => $task_id ], -4002);
} }
if ($archived === false && $task->archived_at == null) { if ($archived === false && $task->archived_at == null) {
throw new ApiException('任务未归档', [ 'task_id' => $task_id ]); throw new ApiException('任务未归档', [ 'task_id' => $task_id ]);
} }
// //
try { try {
$project = Project::userProject($task->project_id); $project = Project::userProject($task->project_id, $archived);
} catch (Exception $e) { } catch (Exception $e) {
if ($task->owner === null) { if ($task->owner === null) {
throw new ApiException($e->getMessage(), [ 'task_id' => $task_id ], -4002); throw new ApiException($e->getMessage(), [ 'task_id' => $task_id ], -4002);
@ -1199,11 +1090,11 @@ class ProjectTask extends AbstractModel
} }
} }
// //
if ($permission === 2) { if ($mustOwner === 2) {
$permission = $task->hasOwner() ? 1 : 0; $mustOwner = $task->hasOwner() ? 1 : 0;
} }
if (($permission === 1 || $permission === true) && !$project->owner && !$task->permission(3)) { if (($mustOwner === 1 || $mustOwner === true) && !$task->owner && !$project->owner) {
throw new ApiException('仅限项目负责人、任务负责人、协助人员或任务创建者操作'); throw new ApiException('仅限项目或任务负责人操作');
} }
// //
return $task; return $task;

View File

@ -1,34 +0,0 @@
<?php
namespace App\Models;
/**
* App\Models\ProjectTaskFlowChange
*
* @property int $id
* @property int|null $task_id 任务ID
* @property int|null $userid 会员ID
* @property int|null $before_flow_item_id 变化前工作流状态ID
* @property string|null $before_flow_item_name (变化前)工作流状态名称
* @property int|null $after_flow_item_id 变化后工作流状态ID
* @property string|null $after_flow_item_name (变化后)工作流状态名称
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange query()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereAfterFlowItemId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereAfterFlowItemName($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereBeforeFlowItemId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereBeforeFlowItemName($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereTaskId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereUserid($value)
* @mixin \Eloquent
*/
class ProjectTaskFlowChange extends AbstractModel
{
}

View File

@ -11,7 +11,6 @@ use App\Module\Base;
* @property int|null $project_id 项目ID * @property int|null $project_id 项目ID
* @property int|null $userid 成员ID * @property int|null $userid 成员ID
* @property int|null $owner 是否负责人 * @property int|null $owner 是否负责人
* @property string|null $top_at 置顶时间
* @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \App\Models\Project|null $project * @property-read \App\Models\Project|null $project
@ -22,7 +21,6 @@ use App\Module\Base;
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereId($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 whereOwner($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereProjectId($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereProjectId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereTopAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereUpdatedAt($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereUserid($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereUserid($value)
* @mixin \Eloquent * @mixin \Eloquent

View File

@ -1,158 +0,0 @@
<?php
namespace App\Models;
use App\Exceptions\ApiException;
use Carbon\Carbon;
use Carbon\Traits\Creator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use JetBrains\PhpStorm\Pure;
/**
* App\Models\Report
*
* @property int $id
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property string $title 标题
* @property string $type 汇报类型
* @property int $userid
* @property string $content
* @property string $sign 汇报唯一标识
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ReportReceive[] $Receives
* @property-read int|null $receives_count
* @property-read mixed $receives
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\User[] $receivesUser
* @property-read int|null $receives_user_count
* @property-read \App\Models\User|null $sendUser
* @method static Builder|Report newModelQuery()
* @method static Builder|Report newQuery()
* @method static Builder|Report query()
* @method static Builder|Report whereContent($value)
* @method static Builder|Report whereCreatedAt($value)
* @method static Builder|Report whereId($value)
* @method static Builder|Report whereSign($value)
* @method static Builder|Report whereTitle($value)
* @method static Builder|Report whereType($value)
* @method static Builder|Report whereUpdatedAt($value)
* @method static Builder|Report whereUserid($value)
* @mixin \Eloquent
*/
class Report extends AbstractModel
{
use HasFactory;
const WEEKLY = "weekly";
const DAILY = "daily";
protected $fillable = [
"title",
"type",
"userid",
"content",
];
protected $appends = [
'receives',
];
public function Receives(): HasMany
{
return $this->hasMany(ReportReceive::class, "rid");
}
public function receivesUser(): BelongsToMany
{
return $this->belongsToMany(User::class, ReportReceive::class, "rid", "userid")
->withPivot("receive_time", "read");
}
public function sendUser()
{
return $this->hasOne(User::class, "userid", "userid");
}
public function getTypeAttribute($value): string
{
return match ($value) {
Report::WEEKLY => "周报",
Report::DAILY => "日报",
default => "",
};
}
public function getContentAttribute($value): string
{
return htmlspecialchars_decode($value);
}
public function getReceivesAttribute()
{
if (!isset($this->appendattrs['receives'])) {
$this->appendattrs['receives'] = empty( $this->receivesUser ) ? [] : array_column($this->receivesUser->toArray(), "userid");
}
return $this->appendattrs['receives'];
}
/**
* 获取单条记录
* @param $id
* @param User|null $user
* @return Report|Builder|Model|object|null
* @throw ApiException
*/
public static function getOne($id, User $user = null)
{
$user === null && $user = User::auth();
$one = self::whereUserid($user->userid)->whereId($id)->first();
if ( empty($one) )
throw new ApiException("记录不存在");
return $one;
}
/**
* 获取最后一条提交记录
* @param User|null $user
* @return Builder|Model|\Illuminate\Database\Query\Builder|object
*/
public static function getLastOne(User $user = null)
{
$user === null && $user = User::auth();
$one = self::whereUserid($user->userid)->orderByDesc("created_at")->first();
if ( empty($one) )
throw new ApiException("记录不存在");
return $one;
}
/**
* 生成唯一标识
* @param $type
* @param $offset
* @param Carbon|null $time
* @return string
*/
public static function generateSign($type, $offset, Carbon $time = null): string
{
$user = User::auth();
$now_dt = $time === null ? Carbon::now() : $time;
$time_s = match ($type) {
Report::WEEKLY => function() use ($now_dt, $offset) {
// 如果设置了周期偏移量
empty( $offset ) || $now_dt->subWeeks( abs( $offset ) );
$now_dt->startOfWeek(); // 设置为当周第一天
return $now_dt->year . $now_dt->weekOfYear;
},
Report::DAILY => function() use ($now_dt, $offset) {
// 如果设置了周期偏移量
empty( $offset ) || $now_dt->subDays( abs( $offset ) );
return $now_dt->format("Ymd");
},
default => "",
};
return $user->userid . ( is_callable($time_s) ? $time_s() : "" );
}
}

View File

@ -1,39 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
/**
* App\Models\ReportReceive
*
* @property int $id
* @property int $rid
* @property string|null $receive_time 接收时间
* @property int $userid 接收人
* @property int $read 是否已读
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive query()
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereRead($value)
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereReceiveTime($value)
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereRid($value)
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereUserid($value)
* @mixin \Eloquent
*/
class ReportReceive extends AbstractModel
{
use HasFactory;
// 关闭时间戳自动写入
public $timestamps = false;
protected $fillable = [
"rid",
"receive_time",
"userid",
"read",
];
}

View File

@ -181,7 +181,7 @@ class User extends AbstractModel
public static function reg($email, $password, $other = []) public static function reg($email, $password, $other = [])
{ {
//邮箱 //邮箱
if (!Base::isEmail($email)) { if (!Base::isMail($email)) {
throw new ApiException('请输入正确的邮箱地址'); throw new ApiException('请输入正确的邮箱地址');
} }
if (User::email2userid($email) > 0) { if (User::email2userid($email) > 0) {

View File

@ -120,10 +120,10 @@ class WebSocketDialog extends AbstractModel
break; break;
case "group": case "group":
if ($dialog->group_type === 'project') { if ($dialog->group_type === 'project') {
$dialog->group_info = Project::withTrashed()->select(['id', 'name', 'archived_at', 'deleted_at'])->whereDialogId($dialog->id)->first()?->cancelAppend()->cancelHidden(); $dialog->group_info = Project::withTrashed()->select(['id', 'name'])->whereDialogId($dialog->id)->first();
$dialog->name = $dialog->group_info ? $dialog->group_info->name : ''; $dialog->name = $dialog->group_info ? $dialog->group_info->name : '';
} elseif ($dialog->group_type === 'task') { } elseif ($dialog->group_type === 'task') {
$dialog->group_info = ProjectTask::withTrashed()->select(['id', 'name', 'complete_at', 'archived_at', 'deleted_at'])->whereDialogId($dialog->id)->first()?->cancelAppend()->cancelHidden(); $dialog->group_info = ProjectTask::withTrashed()->select(['id', 'name'])->whereDialogId($dialog->id)->first();
$dialog->name = $dialog->group_info ? $dialog->group_info->name : ''; $dialog->name = $dialog->group_info ? $dialog->group_info->name : '';
} }
break; break;

View File

@ -8,7 +8,6 @@ use App\Tasks\PushTask;
use App\Tasks\WebSocketDialogMsgTask; use App\Tasks\WebSocketDialogMsgTask;
use Carbon\Carbon; use Carbon\Carbon;
use Hhxsv5\LaravelS\Swoole\Task\Task; use Hhxsv5\LaravelS\Swoole\Task\Task;
use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
* App\Models\WebSocketDialogMsg * App\Models\WebSocketDialogMsg
@ -22,15 +21,11 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property int|null $send 发送数量 * @property int|null $send 发送数量
* @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $updated_at
* @property \Illuminate\Support\Carbon|null $deleted_at
* @property-read int|mixed $percentage * @property-read int|mixed $percentage
* @property-read \App\Models\WebSocketDialog|null $webSocketDialog
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newQuery() * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newQuery()
* @method static \Illuminate\Database\Query\Builder|WebSocketDialogMsg onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg query() * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg query()
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereCreatedAt($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereDialogId($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereDialogId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereId($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereMsg($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereMsg($value)
@ -39,14 +34,10 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereType($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereType($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUpdatedAt($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUserid($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUserid($value)
* @method static \Illuminate\Database\Query\Builder|WebSocketDialogMsg withTrashed()
* @method static \Illuminate\Database\Query\Builder|WebSocketDialogMsg withoutTrashed()
* @mixin \Eloquent * @mixin \Eloquent
*/ */
class WebSocketDialogMsg extends AbstractModel class WebSocketDialogMsg extends AbstractModel
{ {
use SoftDeletes;
protected $appends = [ protected $appends = [
'percentage', 'percentage',
]; ];
@ -55,14 +46,6 @@ class WebSocketDialogMsg extends AbstractModel
'updated_at', 'updated_at',
]; ];
/**
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function webSocketDialog(): \Illuminate\Database\Eloquent\Relations\HasOne
{
return $this->hasOne(WebSocketDialog::class, 'id', 'dialog_id');
}
/** /**
* 阅读占比 * 阅读占比
* @return int|mixed * @return int|mixed
@ -70,7 +53,11 @@ class WebSocketDialogMsg extends AbstractModel
public function getPercentageAttribute() public function getPercentageAttribute()
{ {
if (!isset($this->appendattrs['percentage'])) { if (!isset($this->appendattrs['percentage'])) {
$this->generatePercentage(); if ($this->read > $this->send || empty($this->send)) {
$this->appendattrs['percentage'] = 100;
} else {
$this->appendattrs['percentage'] = intval($this->read / $this->send * 100);
}
} }
return $this->appendattrs['percentage']; return $this->appendattrs['percentage'];
} }
@ -94,22 +81,6 @@ class WebSocketDialogMsg extends AbstractModel
return $value; return $value;
} }
/**
* 获取占比
* @param bool $increment 是否新增阅读数
* @return int
*/
public function generatePercentage($increment = false) {
if ($increment) {
$this->increment('read');
}
if ($this->read > $this->send || empty($this->send)) {
return $this->appendattrs['percentage'] = 100;
} else {
return $this->appendattrs['percentage'] = intval($this->read / $this->send * 100);
}
}
/** /**
* 标记已送达 同时 告诉发送人已送达 * 标记已送达 同时 告诉发送人已送达
* @param $userid * @param $userid
@ -139,17 +110,13 @@ class WebSocketDialogMsg extends AbstractModel
if (!$msgRead->read_at) { if (!$msgRead->read_at) {
$msgRead->read_at = Carbon::now(); $msgRead->read_at = Carbon::now();
$msgRead->save(); $msgRead->save();
$this->generatePercentage(true); $this->increment('read');
PushTask::push([ PushTask::push([
'userid' => $this->userid, 'userid' => $this->userid,
'msg' => [ 'msg' => [
'type' => 'dialog', 'type' => 'dialog',
'mode' => 'readed', 'mode' => 'update',
'data' => [ 'data' => $this->toArray(),
'id' => $this->id,
'read' => $this->read,
'percentage' => $this->percentage,
],
] ]
]); ]);
} }
@ -157,47 +124,6 @@ class WebSocketDialogMsg extends AbstractModel
return true; return true;
} }
/**
* 删除消息
* @return void
*/
public function deleteMsg()
{
$send_dt = Carbon::parse($this->created_at)->addDay();
if ($send_dt->lt(Carbon::now())) {
throw new ApiException('已超过24小时此消息不能撤回');
}
AbstractModel::transaction(function() {
$deleteRead = WebSocketDialogMsgRead::whereMsgId($this->id)->whereNull('read_at')->delete(); // 未阅读记录不需要软删除,直接删除即可
$this->delete();
//
$last_msg = null;
if ($this->webSocketDialog) {
$last_msg = WebSocketDialogMsg::whereDialogId($this->dialog_id)->orderByDesc('id')->first();
$this->webSocketDialog->last_at = $last_msg->created_at;
$this->webSocketDialog->save();
}
//
$dialog = WebSocketDialog::find($this->dialog_id);
if ($dialog) {
$userids = $dialog->dialogUser->pluck('userid')->toArray();
PushTask::push([
'userid' => $userids,
'msg' => [
'type' => 'dialog',
'mode' => 'delete',
'data' => [
'id' => $this->id,
'dialog_id' => $this->dialog_id,
'last_msg' => $last_msg,
'update_read' => $deleteRead ? 1 : 0
],
]
]);
}
});
}
/** /**
* 发送消息 * 发送消息
* @param int $dialog_id 会话ID 聊天室ID * @param int $dialog_id 会话ID 聊天室ID

View File

@ -8,7 +8,6 @@ namespace App\Models;
* @property int $id * @property int $id
* @property int|null $dialog_id 对话ID * @property int|null $dialog_id 对话ID
* @property int|null $userid 会员ID * @property int|null $userid 会员ID
* @property string|null $top_at 置顶时间
* @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser newModelQuery()
@ -17,7 +16,6 @@ namespace App\Models;
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereCreatedAt($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereDialogId($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereDialogId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereId($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereTopAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereUpdatedAt($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereUserid($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereUserid($value)
* @mixin \Eloquent * @mixin \Eloquent

View File

@ -2,7 +2,6 @@
namespace App\Module; namespace App\Module;
use App\Exceptions\ApiException;
use App\Models\Setting; use App\Models\Setting;
use App\Models\Tmp; use App\Models\Tmp;
use Cache; use Cache;
@ -88,18 +87,6 @@ class Base
return $_A["__static_client_version"]; return $_A["__static_client_version"];
} }
/**
* 检查客户端版本
* @param string $min 最小版本
* @return void
*/
public static function checkClientVersion($min)
{
if (version_compare(Base::getClientVersion(), $min, '<')) {
throw new ApiException('当前版本 (v' . Base::getClientVersion() . ') 过低');
}
}
/** /**
* 判断是否域名格式 * 判断是否域名格式
* @param $domain * @param $domain
@ -342,15 +329,19 @@ class Base
{ {
if (strtolower($charset) == 'utf-8') { if (strtolower($charset) == 'utf-8') {
if (Base::getStrlen($string) <= $length) return $string; if (Base::getStrlen($string) <= $length) return $string;
$strcut = Base::utf8Substr($string, $length, $start); $strcut = str_replace(array('&amp;', '&quot;', '&lt;', '&gt;'), array('&', '"', '<', '>'), $string);
$strcut = Base::utf8Substr($strcut, $length, $start);
$strcut = str_replace(array('&', '"', '<', '>'), array('&amp;', '&quot;', '&lt;', '&gt;'), $strcut);
return $strcut . $dot; return $strcut . $dot;
} else { } else {
$length = $length * 2; $length = $length * 2;
if (strlen($string) <= $length) return $string; if (strlen($string) <= $length) return $string;
$string = str_replace(array('&amp;', '&quot;', '&lt;', '&gt;'), array('&', '"', '<', '>'), $string);
$strcut = ''; $strcut = '';
for ($i = 0; $i < $length; $i++) { for ($i = 0; $i < $length; $i++) {
$strcut .= ord($string[$i]) > 127 ? $string[$i] . $string[++$i] : $string[$i]; $strcut .= ord($string[$i]) > 127 ? $string[$i] . $string[++$i] : $string[$i];
} }
$strcut = str_replace(array('&', '"', '<', '>'), array('&amp;', '&quot;', '&lt;', '&gt;'), $strcut);
} }
return $strcut . $dot; return $strcut . $dot;
} }
@ -734,7 +725,7 @@ class Base
public static function getHost($var = '') public static function getHost($var = '')
{ {
if (empty($var)) { if (empty($var)) {
$var = url("/"); $var = self::url();
} }
$arr = parse_url($var); $arr = parse_url($var);
return $arr['host']; return $arr['host'];
@ -747,7 +738,6 @@ class Base
*/ */
public static function fillUrl($str = '') public static function fillUrl($str = '')
{ {
global $_A;
if (is_array($str)) { if (is_array($str)) {
foreach ($str as $key => $item) { foreach ($str as $key => $item) {
$str[$key] = Base::fillUrl($item); $str[$key] = Base::fillUrl($item);
@ -766,14 +756,7 @@ class Base
) { ) {
return $str; return $str;
} else { } else {
if ($_A['__fill_url_remote_url'] === true) { return self::url($str);
return "{{RemoteURL}}" . $str;
}
try {
return url($str);
} catch (\Throwable) {
return self::getSchemeAndHost() . "/" . $str;
}
} }
} }
@ -790,12 +773,25 @@ class Base
} }
return $str; return $str;
} }
return Base::leftDelete($str, self::url() . '/');
}
/**
* 获取url
* @param $path
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\UrlGenerator|string
*/
public static function url($path = '')
{
try { try {
$find = url(''); $url = url($path);
if (str_starts_with($url, "http://localhost/")) {
$url = "http://localhost:" . env("APP_PORT", "80") . "/" . substr($url, 17);
}
} catch (\Throwable) { } catch (\Throwable) {
$find = self::getSchemeAndHost(); $url = self::getSchemeAndHost() . "/" . $path;
} }
return Base::leftDelete($str, $find . '/'); return $url;
} }
/** /**
@ -808,31 +804,6 @@ class Base
return $scheme.($_SERVER['HTTP_HOST'] ?? ''); return $scheme.($_SERVER['HTTP_HOST'] ?? '');
} }
/**
* 地址后拼接参数
* @param $url
* @param $parames
* @return mixed|string
*/
public static function urlAddparameter($url, $parames)
{
if ($parames && is_array($parames)) {
$array = [];
foreach ($parames as $key => $val) {
$array[] = $key . "=" . $val;
}
if ($array) {
$query = implode("&", $array);
if (str_contains($url, "?")) {
$url .= "&" . $query;
} else {
$url .= "?" . $query;
}
}
}
return $url;
}
/** /**
* 格式化内容图片地址 * 格式化内容图片地址
* @param $content * @param $content
@ -988,7 +959,7 @@ class Base
* @param string $str 需要检测的字符串 * @param string $str 需要检测的字符串
* @return int * @return int
*/ */
public static function isEmail($str) public static function isMail($str)
{ {
$RegExp = '/^[a-z0-9][a-z\.0-9-_]+@[a-z0-9_-]+(?:\.[a-z]{0,3}\.[a-z]{0,2}|\.[a-z]{0,3}|\.[a-z]{0,2})$/i'; $RegExp = '/^[a-z0-9][a-z\.0-9-_]+@[a-z0-9_-]+(?:\.[a-z]{0,3}\.[a-z]{0,2}|\.[a-z]{0,3}|\.[a-z]{0,2})$/i';
return preg_match($RegExp, $str); return preg_match($RegExp, $str);
@ -2270,7 +2241,7 @@ class Base
$type = ['zip']; $type = ['zip'];
break; break;
case 'file': case 'file':
$type = ['jpg', 'jpeg', 'png', 'gif', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'esp', 'pdf', 'rar', 'zip', 'gz', 'ai', 'avi', 'bmp', 'cdr', 'eps', 'mov', 'mp3', 'mp4', 'pr', 'psd', 'svg', 'tif']; $type = ['jpg', 'jpeg', 'png', 'gif', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'esp', 'pdf', 'rar', 'zip', 'gz'];
break; break;
case 'firmware': case 'firmware':
$type = ['img', 'tar', 'bin']; $type = ['img', 'tar', 'bin'];
@ -2280,9 +2251,6 @@ class Base
break; break;
case 'more': case 'more':
$type = [ $type = [
'text', 'md', 'markdown',
'drawio',
'mind',
'docx', 'wps', 'doc', 'xls', 'xlsx', 'ppt', 'pptx', 'docx', 'wps', 'doc', 'xls', 'xlsx', 'ppt', 'pptx',
'jpg', 'jpeg', 'png', 'gif', 'bmp', 'ico', 'raw', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'ico', 'raw',
'rar', 'zip', 'jar', '7-zip', 'tar', 'gzip', '7z', 'rar', 'zip', 'jar', '7-zip', 'tar', 'gzip', '7z',
@ -2291,17 +2259,10 @@ class Base
'ofd', 'ofd',
'pdf', 'pdf',
'txt', 'txt',
'htaccess', 'htgroups', 'htpasswd', 'conf', 'bat', 'cmd', 'cpp', 'c', 'cc', 'cxx', 'h', 'hh', 'hpp', 'ino', 'cs', 'css', 'html', 'htm', 'asp', 'jsp', 'xml', 'json', 'properties', 'md', 'gitignore', 'log', 'java', 'py', 'c', 'cpp', 'sql', 'sh', 'bat', 'm', 'bas', 'prg', 'cmd',
'dockerfile', 'go', 'html', 'htm', 'xhtml', 'vue', 'we', 'wpy', 'java', 'js', 'jsm', 'jsx', 'json', 'jsp', 'less', 'lua', 'makefile', 'gnumakefile', 'php', 'go', 'python', 'js', 'ftl', 'css', 'lua', 'rb', 'yaml', 'yml', 'h', 'cs', 'aspx',
'ocamlmakefile', 'make', 'mysql', 'nginx', 'ini', 'cfg', 'prefs', 'm', 'mm', 'pl', 'pm', 'p6', 'pl6', 'pm6', 'pgsql', 'php',
'inc', 'phtml', 'shtml', 'php3', 'php4', 'php5', 'phps', 'phpt', 'aw', 'ctp', 'module', 'ps1', 'py', 'r', 'rb', 'ru', 'gemspec', 'rake', 'guardfile', 'rakefile',
'gemfile', 'rs', 'sass', 'scss', 'sh', 'bash', 'bashrc', 'sql', 'sqlserver', 'swift', 'ts', 'typescript', 'str', 'vbs', 'vb', 'v', 'vh', 'sv', 'svh', 'xml',
'rdf', 'rss', 'wsdl', 'xslt', 'atom', 'mathml', 'mml', 'xul', 'xbl', 'xaml', 'yaml', 'yml',
'asp', 'properties', 'gitignore', 'log', 'bas', 'prg', 'python', 'ftl', 'aspx',
'mp3', 'wav', 'mp4', 'flv', 'mp3', 'wav', 'mp4', 'flv',
'avi', 'mov', 'wmv', 'mkv', '3gp', 'rm', 'avi', 'mov', 'wmv', 'mkv', '3gp', 'rm',
'xmind',
'rp',
]; ];
break; break;
default: default:
@ -2423,37 +2384,6 @@ class Base
} }
} }
/**
* 上传文件移动
* @param array $uploadResult
* @param string $newPath "/" 结尾
* @return array
*/
public static function uploadMove($uploadResult, $newPath)
{
if (str_ends_with($newPath, "/") && file_exists($uploadResult['file'])) {
Base::makeDir(public_path($newPath));
$oldPath = dirname($uploadResult['path']) . "/";
$newFile = str_replace($oldPath, $newPath, $uploadResult['file']);
if (rename($uploadResult['file'], $newFile)) {
$oldUrl = $uploadResult['url'];
$uploadResult['file'] = $newFile;
$uploadResult['path'] = str_replace($oldPath, $newPath, $uploadResult['path']);
$uploadResult['url'] = str_replace($oldPath, $newPath, $uploadResult['url']);
if ($uploadResult['thumb'] == $oldUrl) {
$uploadResult['thumb'] = $uploadResult['url'];
} elseif ($uploadResult['thumb']) {
$oldThumb = substr($uploadResult['thumb'], strpos($uploadResult['thumb'], $newPath));
$newThumb = str_replace($oldPath, $newPath, $oldThumb);
if (file_exists(public_path($oldThumb)) && rename(public_path($oldThumb), public_path($newThumb))) {
$uploadResult['thumb'] = str_replace($oldPath, $newPath, $uploadResult['thumb']);
}
}
}
}
return $uploadResult;
}
/** /**
* 生成缩略图 * 生成缩略图
* @param string $src_img 源图绝对完整地址{带文件名及后缀名} * @param string $src_img 源图绝对完整地址{带文件名及后缀名}
@ -2963,19 +2893,4 @@ class Base
$matrix = array_unique($matrix, SORT_REGULAR); $matrix = array_unique($matrix, SORT_REGULAR);
return array_merge($matrix); return array_merge($matrix);
} }
/**
* 去除emoji表情
* @param $str
* @return string|string[]|null
*/
public static function filterEmoji($str)
{
return preg_replace_callback(
'/./u',
function (array $match) {
return strlen($match[0]) >= 4 ? '' : $match[0];
},
$str);
}
} }

View File

@ -1,144 +0,0 @@
<?php
namespace App\Module;
use Excel;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;
use Maatwebsite\Excel\Concerns\WithTitle;
use Maatwebsite\Excel\Events\AfterSheet;
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
use PhpOffice\PhpSpreadsheet\Writer\Exception;
class BillExport implements WithHeadings, WithEvents, FromCollection, WithTitle, WithStrictNullComparison
{
public $title;
public $headings = [];
public $data = [];
public $typeLists = [];
public $typeNumber = 0;
public function __construct($title, array $data)
{
$this->title = $title;
$this->data = $data;
}
public static function create($data = [], $title = "Sheet1") {
if (is_string($data)) {
list($title, $data) = [$data, $title];
}
if (!is_array($data)) {
$data = [];
}
return new BillExport($title, $data);
}
public function setTitle($title) {
$this->title = $title;
return $this;
}
public function setHeadings(array $headings) {
$this->headings = $headings;
return $this;
}
public function setData(array $data) {
$this->data = $data;
return $this;
}
public function setTypeList(array $typeList, $number = 0) {
$this->typeLists = $typeList;
$this->typeNumber = $number;
return $this;
}
public function store($fileName = '') {
if (empty($fileName)) {
$fileName = date("YmdHis") . '.xls';
}
try {
return Excel::store($this, $fileName);
} catch (Exception $e) {
return "导出错误:" . $e->getMessage();
} catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
return "导出错误:" . $e->getMessage();
}
}
public function download($fileName = '') {
if (empty($fileName)) {
$fileName = date("YmdHis") . '.xls';
}
try {
return Excel::download($this, $fileName);
} catch (Exception $e) {
return "导出错误:" . $e->getMessage();
} catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
return "导出错误:" . $e->getMessage();
}
}
/**
* 导出的文件标题
* @return string
*/
public function title(): string
{
return $this->title;
}
/**
* 标题行
* @return array
*/
public function headings(): array
{
return $this->headings;
}
/**
* 导出的内容
* @return \Illuminate\Support\Collection
*/
public function collection()
{
return collect($this->data);
}
/**
* 设置单元格事件
* @return array
*/
public function registerEvents(): array
{
return [
AfterSheet::Class => function (AfterSheet $event) {
$count = count($this->data);
foreach ($this->typeLists AS $cell => $typeList) {
if ($cell && $typeList) {
$p = $this->headings ? 1 : 0;
for ($i = 1 + $p; $i <= max($count, $this->typeNumber) + $p; $i++) {
$validation = $event->sheet->getDelegate()->getCell($cell . $i)->getDataValidation();
$validation->setType(DataValidation::TYPE_LIST);
$validation->setErrorStyle(DataValidation::STYLE_WARNING);
$validation->setAllowBlank(false);
$validation->setShowDropDown(true);
$validation->setShowInputMessage(true);
$validation->setShowErrorMessage(true);
$validation->setErrorTitle('输入的值不合法');
$validation->setError('选择的值不在列表中,请选择列表中的值');
$validation->setPromptTitle('从列表中选择');
$validation->setPrompt('请选择下拉列表中的值');
$validation->setFormula1('"' . implode(',', $typeList) . '"');
}
}
}
}
];
}
}

View File

@ -1,16 +0,0 @@
<?php
namespace App\Module;
use Maatwebsite\Excel\Concerns\ToArray;
class BillImport implements ToArray
{
public function Array(Array $tables)
{
return $tables;
}
}

View File

@ -127,11 +127,9 @@ class WebSocketService implements WebSocketHandlerInterface
case 'readMsg': case 'readMsg':
$ids = is_array($data['id']) ? $data['id'] : [$data['id']]; $ids = is_array($data['id']) ? $data['id'] : [$data['id']];
$userid = $this->getUserid($frame->fd); $userid = $this->getUserid($frame->fd);
WebSocketDialogMsg::whereIn('id', $ids)->chunkById(20, function($list) use ($userid) { $list = WebSocketDialogMsg::whereIn('id', $ids)->get();
/** @var WebSocketDialogMsg $item */ $list->transform(function(WebSocketDialogMsg $item) use ($userid) {
foreach ($list as $item) { $item->readSuccess($userid);
$item->readSuccess($userid);
}
}); });
return; return;
@ -206,19 +204,7 @@ class WebSocketService implements WebSocketHandlerInterface
*/ */
private function deleteUser($fd) private function deleteUser($fd)
{ {
$array = []; WebSocket::whereFd($fd)->delete();
WebSocket::whereFd($fd)->chunk(10, function($list) use (&$array) {
/** @var WebSocket $item */
foreach ($list as $item) {
$item->delete();
if ($item->path && str_starts_with($item->path, "file/content/")) {
$array[$item->path] = $item->path;
}
}
});
foreach ($array as $path) {
$this->pushPath($path);
}
} }
/** /**

View File

@ -33,11 +33,6 @@ class WebSocketDialogMsgTask extends AbstractTask
public function start() public function start()
{ {
global $_A;
$_A = [
'__fill_url_remote_url' => true,
];
//
$msg = WebSocketDialogMsg::find($this->id); $msg = WebSocketDialogMsg::find($this->id);
if (empty($msg)) { if (empty($msg)) {
return; return;

102
cmd
View File

@ -13,7 +13,6 @@ Error="${Red}[错误]${Font}"
cur_path="$(pwd)" cur_path="$(pwd)"
cur_arg=$@ cur_arg=$@
COMPOSE="docker-compose"
judge() { judge() {
if [[ 0 -eq $? ]]; then if [[ 0 -eq $? ]]; then
@ -32,15 +31,6 @@ rand() {
echo $(($num%$max+$min)) echo $(($num%$max+$min))
} }
rand_string() {
local lan=$1
if [[ `uname` == 'Linux' ]]; then
echo "$(date +%s%N | md5sum | cut -c 1-${lan})"
else
echo "$(docker run -it --rm alpine sh -c "date +%s%N | md5sum | cut -c 1-${lan}")"
fi
}
supervisorctl_restart() { supervisorctl_restart() {
local RES=`run_exec php "supervisorctl update $1"` local RES=`run_exec php "supervisorctl update $1"`
if [ -z "$RES" ]; then if [ -z "$RES" ]; then
@ -56,24 +46,15 @@ check_docker() {
echo -e "${Error} ${RedBG} 未安装 Docker${Font}" echo -e "${Error} ${RedBG} 未安装 Docker${Font}"
exit 1 exit 1
fi fi
docker-compose version &> /dev/null docker-compose --version &> /dev/null
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
docker compose version &> /dev/null echo -e "${Error} ${RedBG} 未安装 Docker-compose${Font}"
if [ $? -ne 0 ]; then
echo -e "${Error} ${RedBG} 未安装 Docker-compose${Font}"
exit 1
fi
COMPOSE="docker compose"
fi
if [[ -n `$COMPOSE version | grep -E "\sv*1"` ]]; then
$COMPOSE version
echo -e "${Error} ${RedBG} Docker-compose 版本过低请升级至v2+${Font}"
exit 1 exit 1
fi fi
} }
check_node() { check_node() {
npm --version &> /dev/null npm --version > /dev/null
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo -e "${Error} ${RedBG} 未安装nodejs${Font}" echo -e "${Error} ${RedBG} 未安装nodejs${Font}"
exit 1 exit 1
@ -81,7 +62,7 @@ check_node() {
} }
docker_name() { docker_name() {
echo `$COMPOSE ps | awk '{print $1}' | grep "\-$1\-"` echo `docker-compose ps | awk '{print $1}' | grep "\-$1\-"`
} }
run_compile() { run_compile() {
@ -136,7 +117,11 @@ run_exec() {
echo -e "${Error} ${RedBG} 没有找到 $container 容器! ${Font}" echo -e "${Error} ${RedBG} 没有找到 $container 容器! ${Font}"
exit 1 exit 1
fi fi
docker exec -it "$name" /bin/sh -c "$cmd" if [ "$container" = "mariadb" ] || [ "$container" = "nginx" ] || [ "$container" = "redis" ]; then
docker exec -it "$name" /bin/sh -c "$cmd"
else
docker exec -it "$name" /bin/bash -c "$cmd"
fi
} }
run_mysql() { run_mysql() {
@ -193,11 +178,8 @@ env_set() {
if [ -z "$exist" ]; then if [ -z "$exist" ]; then
echo "$key=$val" >> $cur_path/.env echo "$key=$val" >> $cur_path/.env
else else
if [[ `uname` == 'Linux' ]]; then command="sed -i '/^$key=/c\\$key=$val' /www/.env"
sed -i "/^${key}=/c\\${key}=${val}" ${cur_path}/.env docker run -it --rm -v ${cur_path}:/www alpine sh -c "$command"
else
docker run -it --rm -v ${cur_path}:/www alpine sh -c "sed -i "/^${key}=/c\\${key}=${val}" /www/.env"
fi
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo -e "${Error} ${RedBG} 设置env参数失败${Font}" echo -e "${Error} ${RedBG} 设置env参数失败${Font}"
exit 1 exit 1
@ -210,10 +192,10 @@ env_init() {
cp .env.docker .env cp .env.docker .env
fi fi
if [ -z "$(env_get DB_ROOT_PASSWORD)" ]; then if [ -z "$(env_get DB_ROOT_PASSWORD)" ]; then
env_set DB_ROOT_PASSWORD "$(rand_string 16)" env_set DB_ROOT_PASSWORD "$(docker run -it --rm alpine sh -c "date +%s%N | md5sum | cut -c 1-16")"
fi fi
if [ -z "$(env_get APP_ID)" ]; then if [ -z "$(env_get APP_ID)" ]; then
env_set APP_ID "$(rand_string 6)" env_set APP_ID "$(docker run -it --rm alpine sh -c "date +%s%N | md5sum | cut -c 1-6")"
fi fi
if [ -z "$(env_get APP_IPPR)" ]; then if [ -z "$(env_get APP_IPPR)" ]; then
env_set APP_IPPR "10.$(rand 50 100).$(rand 100 200)" env_set APP_IPPR "10.$(rand 50 100).$(rand 100 200)"
@ -225,28 +207,16 @@ arg_get() {
local value="" local value=""
for var in $cur_arg; do for var in $cur_arg; do
if [[ "$find" == "y" ]]; then if [[ "$find" == "y" ]]; then
if [[ ! $var =~ "--" ]]; then value=$var
value=$var
fi
break break
fi fi
if [[ "--$1" == "$var" ]] || [[ "-$1" == "$var" ]]; then if [[ "--$1" == "$var" ]] || [[ "-$1" == "$var" ]]; then
find="y" find="y"
value="yes"
fi fi
done done
echo $value echo $value
} }
is_arm() {
local get_arch=`arch`
if [[ $get_arch =~ "aarch" ]] || [[ $get_arch =~ "arm" ]]; then
echo "yes"
else
echo "no"
fi
}
#################################################################################### ####################################################################################
#################################################################################### ####################################################################################
#################################################################################### ####################################################################################
@ -259,25 +229,17 @@ fi
if [ $# -gt 0 ]; then if [ $# -gt 0 ]; then
if [[ "$1" == "init" ]] || [[ "$1" == "install" ]]; then if [[ "$1" == "init" ]] || [[ "$1" == "install" ]]; then
shift 1 shift 1
# 判断架构
if [[ "$(is_arm)" == "yes" ]] && [[ -z "$(arg_get force)" ]]; then
echo -e "${Error} ${RedBG}暂不支持arm架构强制安装请使用./cmd install --force${Font}"
exit 1
fi
# 初始化文件 # 初始化文件
if [[ -n "$(arg_get relock)" ]]; then rm -rf composer.lock
rm -rf node_modules rm -rf package-lock.json
rm -rf package-lock.json
rm -rf vendor
rm -rf composer.lock
fi
mkdir -p "${cur_path}/docker/log/supervisor" mkdir -p "${cur_path}/docker/log/supervisor"
mkdir -p "${cur_path}/docker/mysql/data" mkdir -p "${cur_path}/docker/mysql/data"
chmod -R 775 "${cur_path}/docker/log/supervisor" chmod -R 775 "${cur_path}/docker/log/supervisor"
chmod -R 775 "${cur_path}/docker/mysql/data" chmod -R 775 "${cur_path}/docker/mysql/data"
# 启动容器 # 启动容器
[[ "$(arg_get port)" -gt 0 ]] && env_set APP_PORT "$(arg_get port)" [[ "$(arg_get port)" -gt 0 ]] && env_set APP_PORT "$(arg_get port)"
$COMPOSE up php -d docker-compose up -d
docker-compose restart php
# 安装composer依赖 # 安装composer依赖
run_exec php "composer install" run_exec php "composer install"
if [ ! -f "${cur_path}/vendor/autoload.php" ]; then if [ ! -f "${cur_path}/vendor/autoload.php" ]; then
@ -305,8 +267,8 @@ if [ $# -gt 0 ]; then
run_exec php "php artisan migrate --seed" run_exec php "php artisan migrate --seed"
# 设置初始化密码 # 设置初始化密码
res=`run_exec mariadb "sh /etc/mysql/repassword.sh"` res=`run_exec mariadb "sh /etc/mysql/repassword.sh"`
$COMPOSE up -d docker-compose stop
supervisorctl_restart php docker-compose start
echo -e "${OK} ${GreenBG} 安装完成 ${Font}" echo -e "${OK} ${GreenBG} 安装完成 ${Font}"
echo -e "地址: http://${GreenBG}127.0.0.1:$(env_get APP_PORT)${Font}" echo -e "地址: http://${GreenBG}127.0.0.1:$(env_get APP_PORT)${Font}"
echo -e "$res" echo -e "$res"
@ -319,7 +281,7 @@ if [ $# -gt 0 ]; then
run_exec php "composer update" run_exec php "composer update"
run_exec php "php artisan migrate" run_exec php "php artisan migrate"
supervisorctl_restart php supervisorctl_restart php
$COMPOSE up -d docker-compose up -d
elif [[ "$1" == "uninstall" ]]; then elif [[ "$1" == "uninstall" ]]; then
shift 1 shift 1
read -rp "确定要卸载(含:删除容器、数据库、日志)吗?(y/n): " uninstall read -rp "确定要卸载(含:删除容器、数据库、日志)吗?(y/n): " uninstall
@ -333,20 +295,20 @@ if [ $# -gt 0 ]; then
exit 2 exit 2
;; ;;
esac esac
$COMPOSE down docker-compose down
rm -rf "./docker/mysql/data" rm -rf "./docker/mysql/data"
rm -rf "./docker/log/supervisor" rm -rf "./docker/log/supervisor"
find "./storage/logs" -name "*.log" | xargs rm -rf find "./storage/logs" -name "*.log" | xargs rm -rf
echo -e "${OK} ${GreenBG} 卸载完成 ${Font}" echo -e "${OK} ${GreenBG} 卸载完成 ${Font}"
elif [[ "$1" == "reinstall" ]]; then elif [[ "$1" == "reinstall" ]]; then
shift 1 shift 1
./cmd uninstall $@ ./cmd uninstall
sleep 3 sleep 3
./cmd install $@ ./cmd install
elif [[ "$1" == "port" ]]; then elif [[ "$1" == "port" ]]; then
shift 1 shift 1
env_set APP_PORT "$1" env_set APP_PORT "$1"
$COMPOSE up -d docker-compose up -d
echo -e "${OK} ${GreenBG} 修改成功 ${Font}" echo -e "${OK} ${GreenBG} 修改成功 ${Font}"
echo -e "地址: http://${GreenBG}127.0.0.1:$(env_get APP_PORT)${Font}" echo -e "地址: http://${GreenBG}127.0.0.1:$(env_get APP_PORT)${Font}"
elif [[ "$1" == "repassword" ]]; then elif [[ "$1" == "repassword" ]]; then
@ -405,10 +367,10 @@ if [ $# -gt 0 ]; then
elif [[ "$1" == "composer" ]]; then elif [[ "$1" == "composer" ]]; then
shift 1 shift 1
e="composer $@" && run_exec php "$e" e="composer $@" && run_exec php "$e"
elif [[ "$1" == "service" ]]; then elif [[ "$1" == "super" ]]; then
shift 1 shift 1
e="service $@" && run_exec php "$e" supervisorctl_restart "$@"
elif [[ "$1" == "super" ]] || [[ "$1" == "supervisorctl" ]]; then elif [[ "$1" == "supervisorctl" ]]; then
shift 1 shift 1
e="supervisorctl $@" && run_exec php "$e" e="supervisorctl $@" && run_exec php "$e"
elif [[ "$1" == "models" ]]; then elif [[ "$1" == "models" ]]; then
@ -419,11 +381,11 @@ if [ $# -gt 0 ]; then
e="./vendor/bin/phpunit $@" && run_exec php "$e" e="./vendor/bin/phpunit $@" && run_exec php "$e"
elif [[ "$1" == "restart" ]]; then elif [[ "$1" == "restart" ]]; then
shift 1 shift 1
$COMPOSE stop "$@" docker-compose stop "$@"
$COMPOSE start "$@" docker-compose start "$@"
else else
$COMPOSE "$@" docker-compose "$@"
fi fi
else else
$COMPOSE ps docker-compose ps
fi fi

9554
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,7 @@ class CreateProjectLogsTable extends Migration
$table->bigIncrements('id'); $table->bigIncrements('id');
$table->bigInteger('project_id')->nullable()->default(0)->comment('项目ID'); $table->bigInteger('project_id')->nullable()->default(0)->comment('项目ID');
$table->bigInteger('column_id')->nullable()->default(0)->comment('列表ID'); $table->bigInteger('column_id')->nullable()->default(0)->comment('列表ID');
$table->bigInteger('task_id')->nullable()->default(0)->comment('任务ID'); $table->bigInteger('task_id')->nullable()->default(0)->comment('项目ID');
$table->bigInteger('userid')->nullable()->default(0)->comment('会员ID'); $table->bigInteger('userid')->nullable()->default(0)->comment('会员ID');
$table->string('detail', 500)->nullable()->default('')->comment('详细信息'); $table->string('detail', 500)->nullable()->default('')->comment('详细信息');
$table->timestamps(); $table->timestamps();

View File

@ -1,39 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateReportsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if ( Schema::hasTable('reports') )
return;
Schema::create('reports', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string("title")->default("")->comment("标题");
$table->enum("type", ["weekly", "daily"])->default("daily")->comment("汇报类型");
$table->unsignedBigInteger("userid")->default(0);
$table->longText("content")->nullable();
$table->index(["userid", "created_at"], "default");
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('reports');
}
}

View File

@ -1,38 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateReportReceivesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if ( Schema::hasTable('report_receives') )
return;
Schema::create('report_receives', function (Blueprint $table) {
$table->bigIncrements("id");
$table->unsignedInteger("rid")->default(0);
$table->timestamp("receive_time")->nullable()->comment("接收时间");
$table->unsignedBigInteger("userid")->default(0)->comment("接收人");
$table->unsignedTinyInteger("read")->default(0)->comment("是否已读");
$table->index(["userid", "receive_time"], "default");
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('report_receives');
}
}

View File

@ -1,32 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddReportSign extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('reports', function (Blueprint $table) {
$table->string("sign")->default("")->comment("汇报唯一标识");
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('reports', function (Blueprint $table) {
$table->dropColumn("sign");
});
}
}

View File

@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class WebSocketDialogMsgsAddDeletes extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
if (!Schema::hasColumn('web_socket_dialog_msgs', 'deleted_at')) {
$table->softDeletes();
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
$table->dropSoftDeletes();
});
}
}

View File

@ -1,40 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class InsertSettingColumnTemplate extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$array = \App\Module\Base::setting('columnTemplate');
if (empty($array)) {
\App\Module\Base::setting('columnTemplate', [
[
'name' => '软件开发',
'columns' => ['产品规划', '前端开发', '后端开发', '测试', '发布', '其他'],
],
[
'name' => '产品开发',
'columns' => ['产品计划', '正在设计', '正在研发', '测试', '准备发布', '发布成功'],
],
]);
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
}
}

View File

@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class WebSocketDialogUsersAddTopAt extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
if (!Schema::hasColumn('web_socket_dialog_users', 'top_at')) {
$table->timestamp('top_at')->nullable()->after('userid')->comment('置顶时间');
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
$table->dropColumn("top_at");
});
}
}

View File

@ -1,30 +0,0 @@
<?php
use App\Models\File;
use Illuminate\Database\Migrations\Migration;
class FilesUpdateType extends Migration
{
/**
* 更改流程图文件类型
* @return void
*/
public function up()
{
File::whereType('flow')->update([
'type' => 'drawio'
]);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
File::whereType('drawio')->update([
'type' => 'flow'
]);
}
}

View File

@ -1,75 +0,0 @@
<?php
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
use App\Models\File;
use App\Models\FileContent;
use App\Module\Base;
use Carbon\Carbon;
use Illuminate\Database\Migrations\Migration;
class FilesUpdateExt extends Migration
{
/**
* 更新后缀
* @return void
*/
public function up()
{
File::whereIn('type', ['mind', 'drawio', 'document'])->where('ext', '')->orderBy('id')->chunk(100, function($files) {
/** @var File $file */
foreach ($files as $file) {
$fileContent = FileContent::whereFid($file->id)->orderByDesc('id')->first();
$contentArray = Base::json2array($fileContent?->content);
$contentString = '';
//
switch ($file->type) {
case 'document':
$file->ext = $contentArray['type'] ?: 'md';
$contentString = $contentArray['content'];
break;
case 'drawio':
$file->ext = 'drawio';
$contentString = $contentArray['xml'];
break;
case 'mind':
$file->ext = 'mind';
$contentString = $fileContent?->content;
break;
}
$file->save();
//
$path = 'uploads/file/' . $file->type . '/' . date("Ym", Carbon::parse($file->created_at)->timestamp) . '/' . $file->id . '/' . md5($contentString);
$save = public_path($path);
Base::makeDir(dirname($save));
file_put_contents($save, $contentString);
$content = [
'type' => $file->ext,
'url' => $path
];
//
$content = FileContent::createInstance([
'fid' => $file->id,
'content' => $content,
'text' => $fileContent?->text,
'size' => $file->size,
'userid' => $file->userid,
]);
$content->save();
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
File::whereIn('ext', ['mind', 'drawio', 'md'])->update([
'ext' => ''
]);
// ... 退回去意义不大,文件内容不做回滚操作
}
}

View File

@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ProjectUsersAddTopAt extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('project_users', function (Blueprint $table) {
if (!Schema::hasColumn('project_users', 'top_at')) {
$table->timestamp('top_at')->nullable()->after('owner')->comment('置顶时间');
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('project_users', function (Blueprint $table) {
$table->dropColumn("top_at");
});
}
}

View File

@ -1,37 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProjectTaskFlowChangesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('project_task_flow_changes', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('task_id')->nullable()->default(0)->comment('任务ID');
$table->bigInteger('userid')->nullable()->default(0)->comment('会员ID');
$table->bigInteger('before_item_id')->nullable()->default(0)->comment('变化前工作流状态ID');
$table->string('before_item_name', 50)->nullable()->default('')->comment('(变化前)工作流状态名称');
$table->bigInteger('after_item_id')->nullable()->default(0)->comment('变化后工作流状态ID');
$table->string('after_item_name', 50)->nullable()->default('')->comment('(变化后)工作流状态名称');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('project_task_flow_changes');
}
}

View File

@ -1,37 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class RenamePreProjectTaskFlowChangesItem extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('project_task_flow_changes', function (Blueprint $table) {
if (Schema::hasColumn('project_task_flow_changes', 'before_item_id')) {
$table->renameColumn('before_item_id', 'before_flow_item_id');
$table->renameColumn('before_item_name', 'before_flow_item_name');
$table->renameColumn('after_item_id', 'after_flow_item_id');
$table->renameColumn('after_item_name', 'after_flow_item_name');
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('project_task_flow_changes', function (Blueprint $table) {
//
});
}
}

View File

@ -18,8 +18,6 @@ class DatabaseSeeder extends Seeder
$this->call(FilesTableSeeder::class); $this->call(FilesTableSeeder::class);
$this->call(FileUsersTableSeeder::class); $this->call(FileUsersTableSeeder::class);
$this->call(ProjectColumnsTableSeeder::class); $this->call(ProjectColumnsTableSeeder::class);
$this->call(ProjectFlowItemsTableSeeder::class);
$this->call(ProjectFlowsTableSeeder::class);
$this->call(ProjectLogsTableSeeder::class); $this->call(ProjectLogsTableSeeder::class);
$this->call(ProjectTaskContentsTableSeeder::class); $this->call(ProjectTaskContentsTableSeeder::class);
$this->call(ProjectTaskUsersTableSeeder::class); $this->call(ProjectTaskUsersTableSeeder::class);

View File

@ -599,5 +599,7 @@ curl -O https://task.hitosea.com/uploads/files/3/202105/ba786dfc2f4c2fe916880474
'deleted_at' => NULL, 'deleted_at' => NULL,
), ),
)); ));
} }
} }

View File

@ -2,10 +2,6 @@
namespace Database\Seeders; namespace Database\Seeders;
use App\Models\File;
use App\Models\FileContent;
use App\Module\Base;
use Carbon\Carbon;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
class FilesTableSeeder extends Seeder class FilesTableSeeder extends Seeder
@ -207,7 +203,7 @@ class FilesTableSeeder extends Seeder
'pid' => 0, 'pid' => 0,
'cid' => 0, 'cid' => 0,
'name' => '流程图', 'name' => '流程图',
'type' => 'drawio', 'type' => 'flow',
'ext' => '', 'ext' => '',
'size' => 5418, 'size' => 5418,
'userid' => 1, 'userid' => 1,
@ -284,47 +280,5 @@ class FilesTableSeeder extends Seeder
)); ));
File::whereIn('type', ['mind', 'drawio', 'document'])->where('ext', '')->orderBy('id')->chunk(100, function($files) {
/** @var File $file */
foreach ($files as $file) {
$fileContent = FileContent::whereFid($file->id)->orderByDesc('id')->first();
$contentArray = Base::json2array($fileContent?->content);
$contentString = '';
//
switch ($file->type) {
case 'document':
$file->ext = $contentArray['type'] ?: 'md';
$contentString = $contentArray['content'];
break;
case 'drawio':
$file->ext = 'drawio';
$contentString = $contentArray['xml'];
break;
case 'mind':
$file->ext = 'mind';
$contentString = $fileContent?->content;
break;
}
$file->save();
//
$path = 'uploads/file/' . $file->type . '/' . date("Ym", Carbon::parse($file->created_at)->timestamp) . '/' . $file->id . '/' . md5($contentString);
$save = public_path($path);
Base::makeDir(dirname($save));
file_put_contents($save, $contentString);
$content = [
'type' => $file->ext,
'url' => $path
];
//
$content = FileContent::createInstance([
'fid' => $file->id,
'content' => $content,
'text' => $fileContent?->text,
'size' => $file->size,
'userid' => $file->userid,
]);
$content->save();
}
});
} }
} }

View File

@ -1,388 +0,0 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class ProjectFlowItemsTableSeeder extends Seeder
{
/**
* Auto generated seed file
*
* @return void
*/
public function run()
{
if (\DB::table('project_flow_items')->count() > 0) {
return;
}
\DB::table('project_flow_items')->insert(array (
0 =>
array (
'id' => 1,
'project_id' => 2,
'flow_id' => 1,
'name' => '待处理',
'status' => 'start',
'turns' => '[1,2,3,4]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 0,
'created_at' => '2022-01-15 23:43:15',
'updated_at' => '2022-01-15 23:43:15',
),
1 =>
array (
'id' => 2,
'project_id' => 2,
'flow_id' => 1,
'name' => '进行中',
'status' => 'progress',
'turns' => '[1,2,3,4]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 1,
'created_at' => '2022-01-15 23:43:15',
'updated_at' => '2022-01-15 23:43:15',
),
2 =>
array (
'id' => 3,
'project_id' => 2,
'flow_id' => 1,
'name' => '已完成',
'status' => 'end',
'turns' => '[1,2,3,4]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 2,
'created_at' => '2022-01-15 23:43:15',
'updated_at' => '2022-01-15 23:43:15',
),
3 =>
array (
'id' => 4,
'project_id' => 2,
'flow_id' => 1,
'name' => '已取消',
'status' => 'end',
'turns' => '[1,2,3,4]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 3,
'created_at' => '2022-01-15 23:43:15',
'updated_at' => '2022-01-15 23:43:15',
),
4 =>
array (
'id' => 5,
'project_id' => 3,
'flow_id' => 2,
'name' => '待处理',
'status' => 'start',
'turns' => '[5,6,7,8]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 0,
'created_at' => '2022-01-15 23:43:23',
'updated_at' => '2022-01-15 23:43:23',
),
5 =>
array (
'id' => 6,
'project_id' => 3,
'flow_id' => 2,
'name' => '进行中',
'status' => 'progress',
'turns' => '[5,6,7,8]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 1,
'created_at' => '2022-01-15 23:43:23',
'updated_at' => '2022-01-15 23:43:23',
),
6 =>
array (
'id' => 7,
'project_id' => 3,
'flow_id' => 2,
'name' => '已完成',
'status' => 'end',
'turns' => '[5,6,7,8]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 2,
'created_at' => '2022-01-15 23:43:23',
'updated_at' => '2022-01-15 23:43:23',
),
7 =>
array (
'id' => 8,
'project_id' => 3,
'flow_id' => 2,
'name' => '已取消',
'status' => 'end',
'turns' => '[5,6,7,8]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 3,
'created_at' => '2022-01-15 23:43:23',
'updated_at' => '2022-01-15 23:43:23',
),
8 =>
array (
'id' => 9,
'project_id' => 4,
'flow_id' => 3,
'name' => '待处理',
'status' => 'start',
'turns' => '[9,10,11,12]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 0,
'created_at' => '2022-01-15 23:43:28',
'updated_at' => '2022-01-15 23:43:28',
),
9 =>
array (
'id' => 10,
'project_id' => 4,
'flow_id' => 3,
'name' => '进行中',
'status' => 'progress',
'turns' => '[9,10,11,12]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 1,
'created_at' => '2022-01-15 23:43:28',
'updated_at' => '2022-01-15 23:43:28',
),
10 =>
array (
'id' => 11,
'project_id' => 4,
'flow_id' => 3,
'name' => '已完成',
'status' => 'end',
'turns' => '[9,10,11,12]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 2,
'created_at' => '2022-01-15 23:43:28',
'updated_at' => '2022-01-15 23:43:28',
),
11 =>
array (
'id' => 12,
'project_id' => 4,
'flow_id' => 3,
'name' => '已取消',
'status' => 'end',
'turns' => '[9,10,11,12]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 3,
'created_at' => '2022-01-15 23:43:28',
'updated_at' => '2022-01-15 23:43:28',
),
12 =>
array (
'id' => 13,
'project_id' => 5,
'flow_id' => 4,
'name' => '待处理',
'status' => 'start',
'turns' => '[13,14,15,16]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 0,
'created_at' => '2022-01-15 23:43:34',
'updated_at' => '2022-01-15 23:43:34',
),
13 =>
array (
'id' => 14,
'project_id' => 5,
'flow_id' => 4,
'name' => '进行中',
'status' => 'progress',
'turns' => '[13,14,15,16]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 1,
'created_at' => '2022-01-15 23:43:34',
'updated_at' => '2022-01-15 23:43:34',
),
14 =>
array (
'id' => 15,
'project_id' => 5,
'flow_id' => 4,
'name' => '已完成',
'status' => 'end',
'turns' => '[13,14,15,16]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 2,
'created_at' => '2022-01-15 23:43:34',
'updated_at' => '2022-01-15 23:43:34',
),
15 =>
array (
'id' => 16,
'project_id' => 5,
'flow_id' => 4,
'name' => '已取消',
'status' => 'end',
'turns' => '[13,14,15,16]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 3,
'created_at' => '2022-01-15 23:43:34',
'updated_at' => '2022-01-15 23:43:34',
),
16 =>
array (
'id' => 17,
'project_id' => 6,
'flow_id' => 5,
'name' => '待处理',
'status' => 'start',
'turns' => '[17,18,19,20]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 0,
'created_at' => '2022-01-15 23:43:40',
'updated_at' => '2022-01-15 23:43:40',
),
17 =>
array (
'id' => 18,
'project_id' => 6,
'flow_id' => 5,
'name' => '进行中',
'status' => 'progress',
'turns' => '[17,18,19,20]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 1,
'created_at' => '2022-01-15 23:43:40',
'updated_at' => '2022-01-15 23:43:40',
),
18 =>
array (
'id' => 19,
'project_id' => 6,
'flow_id' => 5,
'name' => '已完成',
'status' => 'end',
'turns' => '[17,18,19,20]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 2,
'created_at' => '2022-01-15 23:43:40',
'updated_at' => '2022-01-15 23:43:40',
),
19 =>
array (
'id' => 20,
'project_id' => 6,
'flow_id' => 5,
'name' => '已取消',
'status' => 'end',
'turns' => '[17,18,19,20]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 3,
'created_at' => '2022-01-15 23:43:40',
'updated_at' => '2022-01-15 23:43:40',
),
20 =>
array (
'id' => 21,
'project_id' => 7,
'flow_id' => 6,
'name' => '待处理',
'status' => 'start',
'turns' => '[21,22,23,24]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 0,
'created_at' => '2022-01-15 23:43:45',
'updated_at' => '2022-01-15 23:43:45',
),
21 =>
array (
'id' => 22,
'project_id' => 7,
'flow_id' => 6,
'name' => '进行中',
'status' => 'progress',
'turns' => '[21,22,23,24]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 1,
'created_at' => '2022-01-15 23:43:45',
'updated_at' => '2022-01-15 23:43:45',
),
22 =>
array (
'id' => 23,
'project_id' => 7,
'flow_id' => 6,
'name' => '已完成',
'status' => 'end',
'turns' => '[21,22,23,24]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 2,
'created_at' => '2022-01-15 23:43:45',
'updated_at' => '2022-01-15 23:43:45',
),
23 =>
array (
'id' => 24,
'project_id' => 7,
'flow_id' => 6,
'name' => '已取消',
'status' => 'end',
'turns' => '[21,22,23,24]',
'userids' => '[]',
'usertype' => 'add',
'userlimit' => 0,
'sort' => 3,
'created_at' => '2022-01-15 23:43:45',
'updated_at' => '2022-01-15 23:43:45',
),
));
}
}

View File

@ -1,76 +0,0 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class ProjectFlowsTableSeeder extends Seeder
{
/**
* Auto generated seed file
*
* @return void
*/
public function run()
{
if (\DB::table('project_flows')->count() > 0) {
return;
}
\DB::table('project_flows')->insert(array (
0 =>
array (
'id' => 1,
'project_id' => 2,
'name' => 'Default',
'created_at' => '2022-01-15 23:43:15',
'updated_at' => '2022-01-15 23:43:15',
),
1 =>
array (
'id' => 2,
'project_id' => 3,
'name' => 'Default',
'created_at' => '2022-01-15 23:43:23',
'updated_at' => '2022-01-15 23:43:23',
),
2 =>
array (
'id' => 3,
'project_id' => 4,
'name' => 'Default',
'created_at' => '2022-01-15 23:43:28',
'updated_at' => '2022-01-15 23:43:28',
),
3 =>
array (
'id' => 4,
'project_id' => 5,
'name' => 'Default',
'created_at' => '2022-01-15 23:43:34',
'updated_at' => '2022-01-15 23:43:34',
),
4 =>
array (
'id' => 5,
'project_id' => 6,
'name' => 'Default',
'created_at' => '2022-01-15 23:43:40',
'updated_at' => '2022-01-15 23:43:40',
),
5 =>
array (
'id' => 6,
'project_id' => 7,
'name' => 'Default',
'created_at' => '2022-01-15 23:43:45',
'updated_at' => '2022-01-15 23:43:45',
),
));
}
}

View File

@ -28,8 +28,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 2, 'project_id' => 2,
'column_id' => 2, 'column_id' => 2,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 1,
'flow_item_name' => 'start|待处理',
'name' => '说明:将进度分成多级 'name' => '说明:将进度分成多级
每张卡片为一个项目任务,标签表示任务状况 每张卡片为一个项目任务,标签表示任务状况
通过将卡片拖至不同的进度列表下,来表示各项目进度', 通过将卡片拖至不同的进度列表下,来表示各项目进度',
@ -56,8 +54,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 2, 'project_id' => 2,
'column_id' => 2, 'column_id' => 2,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 1,
'flow_item_name' => 'start|待处理',
'name' => '官网项目', 'name' => '官网项目',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -82,8 +78,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 2, 'project_id' => 2,
'column_id' => 2, 'column_id' => 2,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 1,
'flow_item_name' => 'start|待处理',
'name' => '新增职位需求', 'name' => '新增职位需求',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -108,8 +102,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 2, 'project_id' => 2,
'column_id' => 2, 'column_id' => 2,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 1,
'flow_item_name' => 'start|待处理',
'name' => '更新公司简介', 'name' => '更新公司简介',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -134,8 +126,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 2, 'project_id' => 2,
'column_id' => 3, 'column_id' => 3,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 1,
'flow_item_name' => 'start|待处理',
'name' => '官网项目四期', 'name' => '官网项目四期',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -160,8 +150,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 2, 'project_id' => 2,
'column_id' => 4, 'column_id' => 4,
'dialog_id' => 16, 'dialog_id' => 16,
'flow_item_id' => 1,
'flow_item_name' => 'start|待处理',
'name' => '官网项目三期', 'name' => '官网项目三期',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -186,8 +174,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 2, 'project_id' => 2,
'column_id' => 5, 'column_id' => 5,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 1,
'flow_item_name' => 'start|待处理',
'name' => '官网项目二期', 'name' => '官网项目二期',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -212,8 +198,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 2, 'project_id' => 2,
'column_id' => 6, 'column_id' => 6,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 3,
'flow_item_name' => 'end|已完成',
'name' => '官网项目一期', 'name' => '官网项目一期',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -238,8 +222,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 7, 'column_id' => 7,
'dialog_id' => 18, 'dialog_id' => 18,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => '免费高品质的Sketch资源', 'name' => '免费高品质的Sketch资源',
'color' => '', 'color' => '',
'desc' => 'https://sketchrepo.com/', 'desc' => 'https://sketchrepo.com/',
@ -264,8 +246,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 7, 'column_id' => 7,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => '免费高品质的PSD资源', 'name' => '免费高品质的PSD资源',
'color' => '', 'color' => '',
'desc' => 'https://psdrepo.com/', 'desc' => 'https://psdrepo.com/',
@ -290,8 +270,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 7, 'column_id' => 7,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => '免费高清灵感图片网(偏文艺)', 'name' => '免费高清灵感图片网(偏文艺)',
'color' => '', 'color' => '',
'desc' => 'https://magdeleine.co/', 'desc' => 'https://magdeleine.co/',
@ -316,8 +294,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 7, 'column_id' => 7,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => '每天发现充满灵感且美丽的图片', 'name' => '每天发现充满灵感且美丽的图片',
'color' => '', 'color' => '',
'desc' => 'https://weheartit.com/', 'desc' => 'https://weheartit.com/',
@ -342,8 +318,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 8, 'column_id' => 8,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => '花瓣网:设计师寻找灵感的天堂', 'name' => '花瓣网:设计师寻找灵感的天堂',
'color' => '', 'color' => '',
'desc' => 'https://huaban.com/', 'desc' => 'https://huaban.com/',
@ -368,8 +342,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 8, 'column_id' => 8,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'WallHaven高清壁纸图片搜索引擎', 'name' => 'WallHaven高清壁纸图片搜索引擎',
'color' => '', 'color' => '',
'desc' => 'https://wallhaven.typepad.com/', 'desc' => 'https://wallhaven.typepad.com/',
@ -394,8 +366,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 8, 'column_id' => 8,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'Pexels免费高品质图片 可商用', 'name' => 'Pexels免费高品质图片 可商用',
'color' => '', 'color' => '',
'desc' => 'https://www.pexels.com/', 'desc' => 'https://www.pexels.com/',
@ -420,8 +390,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 9, 'column_id' => 9,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'RetinizeiOS切图神器', 'name' => 'RetinizeiOS切图神器',
'color' => '', 'color' => '',
'desc' => 'http://retinize.it/', 'desc' => 'http://retinize.it/',
@ -446,8 +414,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 9, 'column_id' => 9,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'GuideGuide一款PS参考线插件', 'name' => 'GuideGuide一款PS参考线插件',
'color' => '', 'color' => '',
'desc' => 'https://guideguide.me/photoshop/', 'desc' => 'https://guideguide.me/photoshop/',
@ -472,8 +438,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 9, 'column_id' => 9,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'Assistor PS一个功能强大的PS辅助工具', 'name' => 'Assistor PS一个功能强大的PS辅助工具',
'color' => '', 'color' => '',
'desc' => 'http://wit-web.azurewebsites.net/assistor/download', 'desc' => 'http://wit-web.azurewebsites.net/assistor/download',
@ -498,8 +462,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 10, 'column_id' => 10,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'Fontello图标字体生成器', 'name' => 'Fontello图标字体生成器',
'color' => '', 'color' => '',
'desc' => 'http://fontello.com/', 'desc' => 'http://fontello.com/',
@ -524,8 +486,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 10, 'column_id' => 10,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'inconfont: 免费提供高度可辨识符号图标', 'name' => 'inconfont: 免费提供高度可辨识符号图标',
'color' => '', 'color' => '',
'desc' => 'https://www.iconfont.cn/', 'desc' => 'https://www.iconfont.cn/',
@ -550,8 +510,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 10, 'column_id' => 10,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'The Noun Project免费提供高度可辨识符号图标', 'name' => 'The Noun Project免费提供高度可辨识符号图标',
'color' => '', 'color' => '',
'desc' => 'https://thenounproject.com/', 'desc' => 'https://thenounproject.com/',
@ -576,8 +534,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 10, 'column_id' => 10,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'EasyIcon免费图标搜索和下载平台', 'name' => 'EasyIcon免费图标搜索和下载平台',
'color' => '', 'color' => '',
'desc' => 'https://www.easyicon.net/', 'desc' => 'https://www.easyicon.net/',
@ -602,8 +558,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 10, 'column_id' => 10,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'Icon Deposit一个奇妙的图标下载站', 'name' => 'Icon Deposit一个奇妙的图标下载站',
'color' => '', 'color' => '',
'desc' => 'https://www.icondeposit.com/', 'desc' => 'https://www.icondeposit.com/',
@ -628,8 +582,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 10, 'column_id' => 10,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'iConifyMac平台的苹果应用图标自动化生成工具', 'name' => 'iConifyMac平台的苹果应用图标自动化生成工具',
'color' => '', 'color' => '',
'desc' => 'https://iconify.net/', 'desc' => 'https://iconify.net/',
@ -654,8 +606,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 11, 'column_id' => 11,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'Logaster教你在线几分钟内搞定专业的LOGO', 'name' => 'Logaster教你在线几分钟内搞定专业的LOGO',
'color' => '', 'color' => '',
'desc' => '设计https://www.logaster.cn/', 'desc' => '设计https://www.logaster.cn/',
@ -680,8 +630,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 11, 'column_id' => 11,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'LogoLounge国际知名的LOGO设计权威网站', 'name' => 'LogoLounge国际知名的LOGO设计权威网站',
'color' => '', 'color' => '',
'desc' => 'https://www.logolounge.com/', 'desc' => 'https://www.logolounge.com/',
@ -706,8 +654,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 11, 'column_id' => 11,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'LogoMoose一个优秀的logo素材站点', 'name' => 'LogoMoose一个优秀的logo素材站点',
'color' => '', 'color' => '',
'desc' => 'https://www.logomoose.com/', 'desc' => 'https://www.logomoose.com/',
@ -732,8 +678,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 11, 'column_id' => 11,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'LOGOED一个展示Logo设计的博客', 'name' => 'LOGOED一个展示Logo设计的博客',
'color' => '', 'color' => '',
'desc' => 'http://www.logoed.co.uk/page/2/', 'desc' => 'http://www.logoed.co.uk/page/2/',
@ -758,8 +702,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 11, 'column_id' => 11,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'Logo of the Day汇集世界各地优秀LOGO作品的站点', 'name' => 'Logo of the Day汇集世界各地优秀LOGO作品的站点',
'color' => '', 'color' => '',
'desc' => 'https://logooftheday.com/', 'desc' => 'https://logooftheday.com/',
@ -784,8 +726,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 2, 'project_id' => 2,
'column_id' => 5, 'column_id' => 5,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 1,
'flow_item_name' => 'start|待处理',
'name' => 'asdasdad1111', 'name' => 'asdasdad1111',
'color' => '', 'color' => '',
'desc' => '7777777', 'desc' => '7777777',
@ -810,8 +750,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 2, 'project_id' => 2,
'column_id' => 5, 'column_id' => 5,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 1,
'flow_item_name' => 'start|待处理',
'name' => 'hjhjhjjh', 'name' => 'hjhjhjjh',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -836,8 +774,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 11, 'column_id' => 11,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'Logo of the Day汇集世界各地优秀LOGO作品的站点', 'name' => 'Logo of the Day汇集世界各地优秀LOGO作品的站点',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -862,8 +798,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 11, 'column_id' => 11,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'LogoDesignLoveLogo设计技巧分享网', 'name' => 'LogoDesignLoveLogo设计技巧分享网',
'color' => '', 'color' => '',
'desc' => 'LogoDesignLoveLogo设计技巧分享网', 'desc' => 'LogoDesignLoveLogo设计技巧分享网',
@ -888,8 +822,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 11, 'column_id' => 11,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'LogoDesignLoveLogo设计技巧分享网', 'name' => 'LogoDesignLoveLogo设计技巧分享网',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -914,8 +846,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 12, 'column_id' => 12,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'Coolors自动生成配色色板的小工具', 'name' => 'Coolors自动生成配色色板的小工具',
'color' => '', 'color' => '',
'desc' => 'https://coolors.co/', 'desc' => 'https://coolors.co/',
@ -940,8 +870,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 12, 'column_id' => 12,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'Material PaletteMaterial Design专用在线配色工具', 'name' => 'Material PaletteMaterial Design专用在线配色工具',
'color' => '', 'color' => '',
'desc' => 'https://www.materialpalette.com/', 'desc' => 'https://www.materialpalette.com/',
@ -966,8 +894,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 12, 'column_id' => 12,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'Web安全色WEB设计、开发中常用的安全颜色', 'name' => 'Web安全色WEB设计、开发中常用的安全颜色',
'color' => '', 'color' => '',
'desc' => 'https://www.bootcss.com/p/websafecolors/', 'desc' => 'https://www.bootcss.com/p/websafecolors/',
@ -992,8 +918,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 12, 'column_id' => 12,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'ColorZilla火狐浏览器网页取色器插件', 'name' => 'ColorZilla火狐浏览器网页取色器插件',
'color' => '', 'color' => '',
'desc' => 'https://www.colorzilla.com/', 'desc' => 'https://www.colorzilla.com/',
@ -1018,8 +942,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 12, 'column_id' => 12,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'Color Palette Generator图片配色工具', 'name' => 'Color Palette Generator图片配色工具',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1044,8 +966,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 12, 'column_id' => 12,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'inconfont: 免费提供高度可辨识符号图标', 'name' => 'inconfont: 免费提供高度可辨识符号图标',
'color' => '', 'color' => '',
'desc' => 'https://www.iconfont.cn/', 'desc' => 'https://www.iconfont.cn/',
@ -1070,8 +990,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 12, 'column_id' => 12,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'inconfont: 免费提供高度可辨识符号图标https://www.iconfont.cn/', 'name' => 'inconfont: 免费提供高度可辨识符号图标https://www.iconfont.cn/',
'color' => '', 'color' => '',
'desc' => 'https://www.iconfont.cn/', 'desc' => 'https://www.iconfont.cn/',
@ -1096,8 +1014,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 3, 'project_id' => 3,
'column_id' => 12, 'column_id' => 12,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 5,
'flow_item_name' => 'start|待处理',
'name' => 'https://www.iconfont.cn/', 'name' => 'https://www.iconfont.cn/',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1122,8 +1038,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 13, 'column_id' => 13,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '将收集箱的事务进行判断。要立即执行进入Q2列表。非立即执行判断——1.不做删掉、2.稍晚再做进入「稍后做」、3.可做可不做的任务或可能有用的资源进入「Mark」列表', 'name' => '将收集箱的事务进行判断。要立即执行进入Q2列表。非立即执行判断——1.不做删掉、2.稍晚再做进入「稍后做」、3.可做可不做的任务或可能有用的资源进入「Mark」列表',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1148,8 +1062,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 13, 'column_id' => 13,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '2分钟内能做完贴上2分钟标签进入「2分钟速战」列表。2分钟以上做完的事务进入Q3', 'name' => '2分钟内能做完贴上2分钟标签进入「2分钟速战」列表。2分钟以上做完的事务进入Q3',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1174,8 +1086,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 13, 'column_id' => 13,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '判断能否一步做完能进入Q4不能打上多步标签进入「项目清单」或将多步骤任务分解成多个一步做完任务进入Q4。', 'name' => '判断能否一步做完能进入Q4不能打上多步标签进入「项目清单」或将多步骤任务分解成多个一步做完任务进入Q4。',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1200,8 +1110,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 13, 'column_id' => 13,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '如果自己做,打上自己做标签(进入「执行清单」);如果别人做,打上别人做标签(进入「等待清单」)。', 'name' => '如果自己做,打上自己做标签(进入「执行清单」);如果别人做,打上别人做标签(进入「等待清单」)。',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1226,8 +1134,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 2, 'project_id' => 2,
'column_id' => 2, 'column_id' => 2,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 1,
'flow_item_name' => 'start|待处理',
'name' => '❓❗ 说明:将进度分成多级 'name' => '❓❗ 说明:将进度分成多级
每张卡片为一个项目任务,标签表示任务状况 每张卡片为一个项目任务,标签表示任务状况
@ -1256,8 +1162,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 13, 'column_id' => 13,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '每天晚上复查整套流程', 'name' => '每天晚上复查整套流程',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1282,8 +1186,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 13, 'column_id' => 13,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '1.检查「收集箱」是否清空。', 'name' => '1.检查「收集箱」是否清空。',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1308,8 +1210,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 13, 'column_id' => 13,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '2.检查「Mark」是否有条目需要执行转化成行动或项目。', 'name' => '2.检查「Mark」是否有条目需要执行转化成行动或项目。',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1334,8 +1234,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 13, 'column_id' => 13,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '3.检查「项目清单」了解项目进度。', 'name' => '3.检查「项目清单」了解项目进度。',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1360,8 +1258,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 13, 'column_id' => 13,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '4.检查「等待清单」是否有条目需要转化成行动,也就是催促。', 'name' => '4.检查「等待清单」是否有条目需要转化成行动,也就是催促。',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1386,8 +1282,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 13, 'column_id' => 13,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '5.检查各清单是否有已完成,完成的、已作废的卡片,立刻删除。', 'name' => '5.检查各清单是否有已完成,完成的、已作废的卡片,立刻删除。',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1412,8 +1306,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 14, 'column_id' => 14,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '任何事务或信息,先以最简单的方式记录到“收集箱”。然后判断,贴上标签后,拖动到相应列表里', 'name' => '任何事务或信息,先以最简单的方式记录到“收集箱”。然后判断,贴上标签后,拖动到相应列表里',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1438,8 +1330,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 15, 'column_id' => 15,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '优先级1立即去做的事', 'name' => '优先级1立即去做的事',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1464,8 +1354,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 14, 'column_id' => 14,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '任何事务或信息,先以最简单的方式记录到“收集箱”。然后判断,贴上标签后,拖动到相应列表里', 'name' => '任何事务或信息,先以最简单的方式记录到“收集箱”。然后判断,贴上标签后,拖动到相应列表里',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1490,8 +1378,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 16, 'column_id' => 16,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '优先级2主要的执行清单', 'name' => '优先级2主要的执行清单',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1516,8 +1402,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 17, 'column_id' => 17,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '优先级3存放需要多步骤做的事持续追踪', 'name' => '优先级3存放需要多步骤做的事持续追踪',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1542,8 +1426,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 17, 'column_id' => 17,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '可以为这个多步骤项目单独建一个项目,并把项目的链接放到卡片的详情页里,点击就能跳转进去。', 'name' => '可以为这个多步骤项目单独建一个项目,并把项目的链接放到卡片的详情页里,点击就能跳转进去。',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1568,8 +1450,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 17, 'column_id' => 17,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '活动策划', 'name' => '活动策划',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1594,8 +1474,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 16, 'column_id' => 16,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '填问卷', 'name' => '填问卷',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1620,8 +1498,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 18, 'column_id' => 18,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '存放等待协同的事', 'name' => '存放等待协同的事',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1646,8 +1522,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 18, 'column_id' => 18,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '设计稿反馈', 'name' => '设计稿反馈',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1672,8 +1546,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 18, 'column_id' => 18,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '存放等待协同的事', 'name' => '存放等待协同的事',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1698,8 +1570,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 19, 'column_id' => 19,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '存放稍后做的任务', 'name' => '存放稍后做的任务',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1724,8 +1594,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 19, 'column_id' => 19,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '阅实习生简历', 'name' => '阅实习生简历',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1750,8 +1618,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 20, 'column_id' => 20,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '存放可做可不做的任务,以及各种可能用到的资源', 'name' => '存放可做可不做的任务,以及各种可能用到的资源',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1776,8 +1642,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 4, 'project_id' => 4,
'column_id' => 20, 'column_id' => 20,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 9,
'flow_item_name' => 'start|待处理',
'name' => '团建KTV', 'name' => '团建KTV',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1802,8 +1666,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 5, 'project_id' => 5,
'column_id' => 21, 'column_id' => 21,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 13,
'flow_item_name' => 'start|待处理',
'name' => '产品新需求', 'name' => '产品新需求',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1828,8 +1690,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 5, 'project_id' => 5,
'column_id' => 22, 'column_id' => 22,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 13,
'flow_item_name' => 'start|待处理',
'name' => '需要调研的需求', 'name' => '需要调研的需求',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1854,8 +1714,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 5, 'project_id' => 5,
'column_id' => 23, 'column_id' => 23,
'dialog_id' => 17, 'dialog_id' => 17,
'flow_item_id' => 13,
'flow_item_name' => 'start|待处理',
'name' => '进入交互设计的需求', 'name' => '进入交互设计的需求',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1880,8 +1738,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 5, 'project_id' => 5,
'column_id' => 25, 'column_id' => 25,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 13,
'flow_item_name' => 'start|待处理',
'name' => '设计稿(放入设计稿)', 'name' => '设计稿(放入设计稿)',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1906,8 +1762,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 5, 'project_id' => 5,
'column_id' => 25, 'column_id' => 25,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 13,
'flow_item_name' => 'start|待处理',
'name' => '提测(放入提测时间规划表)', 'name' => '提测(放入提测时间规划表)',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1932,8 +1786,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 5, 'project_id' => 5,
'column_id' => 25, 'column_id' => 25,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 13,
'flow_item_name' => 'start|待处理',
'name' => '发布流程(放入发布流程,应用文案等)', 'name' => '发布流程(放入发布流程,应用文案等)',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1958,8 +1810,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 5, 'project_id' => 5,
'column_id' => 25, 'column_id' => 25,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 13,
'flow_item_name' => 'start|待处理',
'name' => '-----上线需求-----(将左边列表中的需求拖动至下方,表示本版本上线需求)', 'name' => '-----上线需求-----(将左边列表中的需求拖动至下方,表示本版本上线需求)',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -1984,8 +1834,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 6, 'project_id' => 6,
'column_id' => 26, 'column_id' => 26,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 17,
'flow_item_name' => 'start|待处理',
'name' => '将小组一年工作目标拆解,设置出里程碑时间节点。并指派相关责任人。用标签来展示进行状况', 'name' => '将小组一年工作目标拆解,设置出里程碑时间节点。并指派相关责任人。用标签来展示进行状况',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2010,8 +1858,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 6, 'project_id' => 6,
'column_id' => 27, 'column_id' => 27,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 19,
'flow_item_name' => 'end|已完成',
'name' => '🚴 里程碑 1 需求评审完成,资源准备到位', 'name' => '🚴 里程碑 1 需求评审完成,资源准备到位',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2036,8 +1882,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 6, 'project_id' => 6,
'column_id' => 27, 'column_id' => 27,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 17,
'flow_item_name' => 'start|待处理',
'name' => '🚴 里程碑 2 设计完成,进行评审', 'name' => '🚴 里程碑 2 设计完成,进行评审',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2062,8 +1906,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 6, 'project_id' => 6,
'column_id' => 28, 'column_id' => 28,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 17,
'flow_item_name' => 'start|待处理',
'name' => '🚴 里程碑 3 产品开发完成,开始提测', 'name' => '🚴 里程碑 3 产品开发完成,开始提测',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2088,8 +1930,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 6, 'project_id' => 6,
'column_id' => 28, 'column_id' => 28,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 17,
'flow_item_name' => 'start|待处理',
'name' => '🚴 里程碑 4 测试完成准备线上发布', 'name' => '🚴 里程碑 4 测试完成准备线上发布',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2114,8 +1954,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 6, 'project_id' => 6,
'column_id' => 28, 'column_id' => 28,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 17,
'flow_item_name' => 'start|待处理',
'name' => '测试1', 'name' => '测试1',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2140,8 +1978,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 6, 'project_id' => 6,
'column_id' => 28, 'column_id' => 28,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 17,
'flow_item_name' => 'start|待处理',
'name' => '测试2', 'name' => '测试2',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2166,8 +2002,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 6, 'project_id' => 6,
'column_id' => 28, 'column_id' => 28,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 17,
'flow_item_name' => 'start|待处理',
'name' => '测试3', 'name' => '测试3',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2192,8 +2026,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 6, 'project_id' => 6,
'column_id' => 29, 'column_id' => 29,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 17,
'flow_item_name' => 'start|待处理',
'name' => '🚴 里程碑 5 市场发布', 'name' => '🚴 里程碑 5 市场发布',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2218,8 +2050,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 7, 'project_id' => 7,
'column_id' => 32, 'column_id' => 32,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 21,
'flow_item_name' => 'start|待处理',
'name' => '产品官网设计', 'name' => '产品官网设计',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2244,8 +2074,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 7, 'project_id' => 7,
'column_id' => 32, 'column_id' => 32,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 23,
'flow_item_name' => 'end|已完成',
'name' => '首页', 'name' => '首页',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2270,8 +2098,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 7, 'project_id' => 7,
'column_id' => 32, 'column_id' => 32,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 23,
'flow_item_name' => 'end|已完成',
'name' => '公司介绍', 'name' => '公司介绍',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2296,8 +2122,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 7, 'project_id' => 7,
'column_id' => 32, 'column_id' => 32,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 23,
'flow_item_name' => 'end|已完成',
'name' => '新闻动态', 'name' => '新闻动态',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2322,8 +2146,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 7, 'project_id' => 7,
'column_id' => 32, 'column_id' => 32,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 23,
'flow_item_name' => 'end|已完成',
'name' => '产品介绍', 'name' => '产品介绍',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2348,8 +2170,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 7, 'project_id' => 7,
'column_id' => 32, 'column_id' => 32,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 23,
'flow_item_name' => 'end|已完成',
'name' => '案例展示', 'name' => '案例展示',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2374,8 +2194,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 7, 'project_id' => 7,
'column_id' => 32, 'column_id' => 32,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 21,
'flow_item_name' => 'start|待处理',
'name' => '联系我们', 'name' => '联系我们',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2400,8 +2218,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 7, 'project_id' => 7,
'column_id' => 32, 'column_id' => 32,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 21,
'flow_item_name' => 'start|待处理',
'name' => '官网新增一级栏目,“招聘信息”', 'name' => '官网新增一级栏目,“招聘信息”',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2426,8 +2242,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 7, 'project_id' => 7,
'column_id' => 33, 'column_id' => 33,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 21,
'flow_item_name' => 'start|待处理',
'name' => '产品官网', 'name' => '产品官网',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',
@ -2452,8 +2266,6 @@ class ProjectTasksTableSeeder extends Seeder
'project_id' => 5, 'project_id' => 5,
'column_id' => 24, 'column_id' => 24,
'dialog_id' => 0, 'dialog_id' => 0,
'flow_item_id' => 13,
'flow_item_name' => 'start|待处理',
'name' => '版本的确定', 'name' => '版本的确定',
'color' => '', 'color' => '',
'desc' => '', 'desc' => '',

View File

@ -16,13 +16,14 @@ class SettingsTableSeeder extends Seeder
{ {
if (\DB::table('settings')->where('name', 'system')->count() > 0) { if (\DB::table('settings')->count() > 0) {
return; return;
} }
\DB::table('settings')->insert(array ( \DB::table('settings')->insert(array (
0 => 0 =>
array ( array (
'id' => 1,
'name' => 'system', 'name' => 'system',
'desc' => '', 'desc' => '',
'setting' => '{"reg":"open","project_invite":"open","login_code":"auto"}', 'setting' => '{"reg":"open","project_invite":"open","login_code":"auto"}',
@ -31,6 +32,7 @@ class SettingsTableSeeder extends Seeder
), ),
1 => 1 =>
array ( array (
'id' => 2,
'name' => 'priority', 'name' => 'priority',
'desc' => '', 'desc' => '',
'setting' => '[{"name":"\\u91cd\\u8981\\u4e14\\u7d27\\u6025","color":"#ED4014","days":1,"priority":1},{"name":"\\u91cd\\u8981\\u4e0d\\u7d27\\u6025","color":"#F16B62","days":3,"priority":2},{"name":"\\u7d27\\u6025\\u4e0d\\u91cd\\u8981","color":"#19C919","days":5,"priority":3},{"name":"\\u4e0d\\u91cd\\u8981\\u4e0d\\u7d27\\u6025","color":"#2D8CF0","days":0,"priority":4}]', 'setting' => '[{"name":"\\u91cd\\u8981\\u4e14\\u7d27\\u6025","color":"#ED4014","days":1,"priority":1},{"name":"\\u91cd\\u8981\\u4e0d\\u7d27\\u6025","color":"#F16B62","days":3,"priority":2},{"name":"\\u7d27\\u6025\\u4e0d\\u91cd\\u8981","color":"#19C919","days":5,"priority":3},{"name":"\\u4e0d\\u91cd\\u8981\\u4e0d\\u7d27\\u6025","color":"#2D8CF0","days":0,"priority":4}]',

File diff suppressed because one or more lines are too long

View File

@ -4,8 +4,8 @@ services:
php: php:
container_name: "dootask-php-${APP_ID}" container_name: "dootask-php-${APP_ID}"
image: "kuaifan/php:swoole-8.0" image: "kuaifan/php:swoole-8.0"
shm_size: "1024m"
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./docker/crontab/crontab.conf:/etc/supervisor/conf.d/crontab.conf - ./docker/crontab/crontab.conf:/etc/supervisor/conf.d/crontab.conf
- ./docker/php/php.conf:/etc/supervisor/conf.d/php.conf - ./docker/php/php.conf:/etc/supervisor/conf.d/php.conf
- ./docker/php/php.ini:/usr/local/etc/php/php.ini - ./docker/php/php.ini:/usr/local/etc/php/php.ini
@ -45,8 +45,6 @@ services:
- php - php
- office - office
- fileview - fileview
- drawio-webapp
- drawio-export
restart: unless-stopped restart: unless-stopped
redis: redis:
@ -82,16 +80,13 @@ services:
office: office:
container_name: "dootask-office-${APP_ID}" container_name: "dootask-office-${APP_ID}"
image: "onlyoffice/documentserver:7.0.0.132" image: "onlyoffice/documentserver:6.4.2.6"
volumes: volumes:
- ./docker/office/data:/var/www/onlyoffice/Data - ./docker/office/data:/var/www/onlyoffice/Data
- ./docker/office/logs:/var/log/onlyoffice - ./docker/office/logs:/var/log/onlyoffice
- ./docker/office/resources/documenteditor/css/app.css:/var/www/onlyoffice/documentserver/web-apps/apps/documenteditor/main/resources/css/app.css - ./docker/office/resources/documenteditor/css/app.css:/var/www/onlyoffice/documentserver/web-apps/apps/documenteditor/main/resources/css/app.css
- ./docker/office/resources/presentationeditor/css/app.css:/var/www/onlyoffice/documentserver/web-apps/apps/presentationeditor/main/resources/css/app.css - ./docker/office/resources/presentationeditor/css/app.css:/var/www/onlyoffice/documentserver/web-apps/apps/presentationeditor/main/resources/css/app.css
- ./docker/office/resources/spreadsheeteditor/css/app.css:/var/www/onlyoffice/documentserver/web-apps/apps/spreadsheeteditor/main/resources/css/app.css - ./docker/office/resources/spreadsheeteditor/css/app.css:/var/www/onlyoffice/documentserver/web-apps/apps/spreadsheeteditor/main/resources/css/app.css
- ./docker/office/resources/documenteditor/mobile/css/app.css:/var/www/onlyoffice/documentserver/web-apps/apps/documenteditor/mobile/css/app.css
- ./docker/office/resources/presentationeditor/mobile/css/app.css:/var/www/onlyoffice/documentserver/web-apps/apps/presentationeditor/mobile/css/app.css
- ./docker/office/resources/spreadsheeteditor/mobile/css/app.css:/var/www/onlyoffice/documentserver/web-apps/apps/spreadsheeteditor/mobile/css/app.css
environment: environment:
TZ: "Asia/Shanghai" TZ: "Asia/Shanghai"
networks: networks:
@ -101,7 +96,7 @@ services:
fileview: fileview:
container_name: "dootask-fileview-${APP_ID}" container_name: "dootask-fileview-${APP_ID}"
image: "kuaifan/fileview:4.1.0-SNAPSHOT-RC3" image: "kuaifan/fileview:4.1.0-SNAPSHOT"
environment: environment:
TZ: "Asia/Shanghai" TZ: "Asia/Shanghai"
KK_CONTEXT_PATH: "/fileview" KK_CONTEXT_PATH: "/fileview"
@ -110,36 +105,6 @@ services:
ipv4_address: "${APP_IPPR}.7" ipv4_address: "${APP_IPPR}.7"
restart: unless-stopped restart: unless-stopped
drawio-webapp:
container_name: "dootask-drawio-webapp-${APP_ID}"
image: "jgraph/drawio:16.6.1"
volumes:
- ./docker/drawio/webapp/index.html:/usr/local/tomcat/webapps/draw/index.html
- ./docker/drawio/webapp/stencils:/usr/local/tomcat/webapps/draw/stencils
- ./docker/drawio/webapp/js/app.min.js:/usr/local/tomcat/webapps/draw/js/app.min.js
- ./docker/drawio/webapp/js/croppie/croppie.min.css:/usr/local/tomcat/webapps/draw/js/croppie/croppie.min.css
- ./docker/drawio/webapp/js/diagramly/ElectronApp.js:/usr/local/tomcat/webapps/draw/js/diagramly/ElectronApp.js
networks:
extnetwork:
ipv4_address: "${APP_IPPR}.8"
environment:
TZ: "Asia/Shanghai"
depends_on:
- drawio-export
restart: unless-stopped
drawio-export:
container_name: "dootask-drawio-export-${APP_ID}"
image: "jgraph/export-server"
networks:
extnetwork:
ipv4_address: "${APP_IPPR}.9"
environment:
TZ: "Asia/Shanghai"
volumes:
- ./docker/drawio/export/fonts:/usr/share/fonts/drawio
restart: unless-stopped
networks: networks:
extnetwork: extnetwork:
name: "dootask-networks-${APP_ID}" name: "dootask-networks-${APP_ID}"

View File

@ -1 +0,0 @@

View File

@ -1,17 +0,0 @@
# Change
## js/diagramly/ElectronApp.js
- 隐藏文件中的无用菜单
## js/app.min.js
- 隐藏帮助菜单
- 取消未保存关闭窗口提示
- `EmbedFile.prototype.getTitle=...``EmbedFile.prototype.getTitle=function(){return this.desc.title||(urlParams.title?decodeURIComponent(urlParams.title):"")}`
- `c.insertTemplateEnabled&&!c.isOffline()&&this.addMenuItems(b,["insertTemplate"],d)``c.insertTemplateEnabled&&this.addMenuItems(b,["insertTemplate"],d)`
- `390:270``390:285`
## index.html
- 隐藏加载中的提示

View File

@ -1,477 +0,0 @@
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=5" ><![endif]-->
<!DOCTYPE html>
<html>
<head>
<title>Flowchart Maker &amp; Online Diagram Software</title>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="Description" content="diagrams.net is free online diagram software for making flowcharts, process diagrams, org charts, UML, ER and network diagrams">
<meta name="Keywords" content="diagram, online, flow chart, flowchart maker, uml, erd">
<meta itemprop="name" content="diagrams.net - free flowchart maker and diagrams online">
<meta itemprop="description" content="diagrams.net is a free online diagramming application and flowchart maker . You can use it to create UML, entity relationship,
org charts, BPMN and BPM, database schema and networks. Also possible are telecommunication network, workflow, flowcharts, maps overlays and GIS, electronic
circuit and social network diagrams.">
<meta itemprop="image" content="https://lh4.googleusercontent.com/-cLKEldMbT_E/Tx8qXDuw6eI/AAAAAAAAAAs/Ke0pnlk8Gpg/w500-h344-k/BPMN%2Bdiagram%2Brc2f.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="msapplication-config" content="images/browserconfig.xml">
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#d89000">
<script type="text/javascript">
window.EXPORT_URL = window.location.origin + "/drawio/export/";
window.DRAWIO_LIGHTBOX_URL = window.location.origin + "/drawio/webapp";
/**
* URL Parameters and protocol description are here:
*
* https://desk.draw.io/support/solutions/articles/16000042546-what-url-parameters-are-supported
*
* Parameters for developers:
*
* - dev=1: For developers only
* - test=1: For developers only
* - export=URL for export: For developers only
* - ignoremime=1: For developers only (see DriveClient.js). Use Cmd-S to override mime.
* - createindex=1: For developers only (see etc/build/README)
* - filesupport=0: For developers only (see Editor.js in core)
* - savesidebar=1: For developers only (see Sidebar.js)
* - pages=1: For developers only (see Pages.js)
* - lic=email: For developers only (see LicenseServlet.java)
* --
* - networkshapes=1: For testing network shapes (temporary)
*/
var urlParams = (function()
{
var result = new Object();
var params = window.location.search.slice(1).split('&');
for (var i = 0; i < params.length; i++)
{
idx = params[i].indexOf('=');
if (idx > 0)
{
result[params[i].substring(0, idx)] = params[i].substring(idx + 1);
}
}
return result;
})();
// Forces CDN caches by passing URL parameters via URL hash
if (window.location.hash != null && window.location.hash.substring(0, 2) == '#P')
{
try
{
urlParams = JSON.parse(decodeURIComponent(window.location.hash.substring(2)));
if (urlParams.hash != null)
{
window.location.hash = urlParams.hash;
}
}
catch (e)
{
// ignore
}
}
// Global variable for desktop
var mxIsElectron = window && window.process && window.process.type;
// Redirects page if required
if (urlParams['dev'] != '1')
{
(function()
{
var proto = window.location.protocol;
if (!mxIsElectron)
{
var host = window.location.host;
// Redirects apex, drive and rt to www
if (host === 'draw.io' || host === 'rt.draw.io' || host === 'drive.draw.io')
{
host = 'www.draw.io';
}
var href = proto + '//' + host + window.location.href.substring(
window.location.protocol.length +
window.location.host.length + 2);
// Redirects if href changes
if (href != window.location.href)
{
window.location.href = href;
}
}
})();
}
/**
* Adds meta tag to the page.
*/
function mxmeta(name, content, httpEquiv)
{
try
{
var s = document.createElement('meta');
if (name != null)
{
s.setAttribute('name', name);
}
s.setAttribute('content', content);
if (httpEquiv != null)
{
s.setAttribute('http-equiv', httpEquiv);
}
var t = document.getElementsByTagName('meta')[0];
t.parentNode.insertBefore(s, t);
}
catch (e)
{
// ignore
}
};
/**
* Synchronously adds scripts to the page.
*/
function mxscript(src, onLoad, id, dataAppKey, noWrite)
{
var defer = onLoad == null && !noWrite;
if ((urlParams['dev'] != '1' && typeof document.createElement('canvas').getContext === "function") ||
onLoad != null || noWrite)
{
var s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.setAttribute('defer', 'true');
s.setAttribute('src', src);
if (id != null)
{
s.setAttribute('id', id);
}
if (dataAppKey != null)
{
s.setAttribute('data-app-key', dataAppKey);
}
if (onLoad != null)
{
var r = false;
s.onload = s.onreadystatechange = function()
{
if (!r && (!this.readyState || this.readyState == 'complete'))
{
r = true;
onLoad();
}
};
}
var t = document.getElementsByTagName('script')[0];
if (t != null)
{
t.parentNode.insertBefore(s, t);
}
}
else
{
document.write('<script src="' + src + '"' + ((id != null) ? ' id="' + id +'" ' : '') +
((dataAppKey != null) ? ' data-app-key="' + dataAppKey +'" ' : '') + '></scr' + 'ipt>');
}
};
/**
* Asynchronously adds scripts to the page.
*/
function mxinclude(src)
{
var g = document.createElement('script');
g.type = 'text/javascript';
g.async = true;
g.src = src;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(g, s);
};
/**
* Adds meta tags with application name (depends on offline URL parameter)
*/
(function()
{
var name = 'diagrams.net';
mxmeta('apple-mobile-web-app-title', name);
mxmeta('application-name', name);
if (mxIsElectron)
{
mxmeta(null, 'default-src \'self\' \'unsafe-inline\'; connect-src \'self\' https://*.draw.io https://fonts.googleapis.com https://fonts.gstatic.com; img-src * data:; media-src *; font-src *; style-src-elem \'self\' \'unsafe-inline\' https://fonts.googleapis.com', 'Content-Security-Policy');
}
})();
// Checks for local storage
var isLocalStorage = false;
try
{
isLocalStorage = urlParams['local'] != '1' && typeof(localStorage) != 'undefined';
}
catch (e)
{
// ignored
}
var mxScriptsLoaded = false, mxWinLoaded = false;
function checkAllLoaded()
{
if (mxScriptsLoaded && mxWinLoaded)
{
App.main();
}
};
var t0 = new Date();
// Changes paths for local development environment
if (urlParams['dev'] == '1')
{
// Used to request grapheditor/mxgraph sources in dev mode
var mxDevUrl = document.location.protocol + '//devhost.jgraph.com/drawio/src/main';
// Used to request draw.io sources in dev mode
var drawDevUrl = document.location.protocol + '//devhost.jgraph.com/drawio/src/main/webapp/';
var geBasePath = drawDevUrl + '/js/grapheditor';
var mxBasePath = mxDevUrl + '/mxgraph';
if (document.location.protocol == 'file:')
{
geBasePath = './js/grapheditor';
mxBasePath = './mxgraph';
drawDevUrl = './';
// Forces includes for dev environment in node.js
mxForceIncludes = true;
}
mxscript(drawDevUrl + 'js/PreConfig.js');
mxscript(drawDevUrl + 'js/diagramly/Init.js');
mxscript(geBasePath + '/Init.js');
mxscript(mxBasePath + '/mxClient.js');
// Adds all JS code that depends on mxClient. This indirection via Devel.js is
// required in some browsers to make sure mxClient.js (and the files that it
// loads asynchronously) are available when the code loaded in Devel.js runs.
mxscript(drawDevUrl + 'js/diagramly/Devel.js');
// Electron
if (mxIsElectron)
{
mxscript('js/diagramly/DesktopLibrary.js');
mxscript('js/diagramly/ElectronApp.js');
}
mxscript(drawDevUrl + 'js/PostConfig.js');
}
else
{
(function()
{
var hostName = window.location.hostname;
// Supported domains are *.draw.io and the packaged version in Quip
var supportedDomain = (hostName.substring(hostName.length - 8, hostName.length) === '.draw.io') ||
(hostName.substring(hostName.length - 13, hostName.length) === '.diagrams.net');
function loadAppJS()
{
mxscript('js/app.min.js', function()
{
mxScriptsLoaded = true;
checkAllLoaded();
// Electron
if (mxIsElectron)
{
mxscript('js/diagramly/DesktopLibrary.js', function()
{
mxscript('js/diagramly/ElectronApp.js', function()
{
mxscript('js/extensions.min.js', function()
{
mxscript('js/stencils.min.js', function()
{
mxscript('js/shapes-14-6-5.min.js', function()
{
mxscript('js/PostConfig.js');
});
});
});
});
});
}
else if (!supportedDomain)
{
mxscript('js/PostConfig.js');
}
});
};
if (!supportedDomain || mxIsElectron)
{
mxscript('js/PreConfig.js', loadAppJS);
}
else
{
loadAppJS();
}
})();
}
// Adds basic error handling
window.onerror = function()
{
var status = document.getElementById('geStatus');
if (status != null)
{
status.innerHTML = 'Page could not be loaded. Please try refreshing.';
}
};
</script>
<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/plgmlhohecdddhbmmkncjdmlhcmaachm">
<link rel="stylesheet" type="text/css" href="js/croppie/croppie.min.css">
<link rel="stylesheet" type="text/css" href="styles/grapheditor.css">
<link rel="preconnect" href="https://storage.googleapis.com">
<link rel="canonical" href="https://app.diagrams.net">
<link rel="manifest" href="images/manifest.json">
<style type="text/css">
body { overflow:hidden; }
div.picker { z-index: 10007; }
.geSidebarContainer .geTitle input {
font-size:8pt;
color:#606060;
}
.geBlock {
display: none;
z-index:-3;
margin:100px;
margin-top:40px;
margin-bottom:30px;
padding:20px;
text-align:center;
min-width:50%;
}
.geBlock h1, .geBlock h2 {
margin-top:0px;
padding-top:0px;
}
.geEditor *:not(.geScrollable)::-webkit-scrollbar {
width:14px;
height:14px;
}
.geEditor ::-webkit-scrollbar-track {
background-clip:padding-box;
border:solid transparent;
border-width:1px;
}
.geEditor ::-webkit-scrollbar-corner {
background-color:transparent;
}
.geEditor ::-webkit-scrollbar-thumb {
background-color:rgba(0,0,0,.1);
background-clip:padding-box;
border:solid transparent;
border-radius:10px;
}
.geEditor ::-webkit-scrollbar-thumb:hover {
background-color:rgba(0,0,0,.4);
}
.geTemplate {
border:1px solid transparent;
display:inline-block;
_display:inline;
vertical-align:top;
border-radius:3px;
overflow:hidden;
font-size:14pt;
cursor:pointer;
margin:5px;
}
.geDialog h2 {
line-height: 1.2;
}
</style>
<!-- Workaround for binary XHR in IE 9/10, see App.loadUrl -->
<!--[if (IE 9)|(IE 10)]><!-->
<script type="text/vbscript">
Function mxUtilsBinaryToArray(Binary)
Dim i
ReDim byteArray(LenB(Binary))
For i = 1 To LenB(Binary)
byteArray(i-1) = AscB(MidB(Binary, i, 1))
Next
mxUtilsBinaryToArray = byteArray
End Function
</script>
<!--<![endif]-->
</head>
<body class="geEditor">
<div id="geInfo">
<div class="geBlock">
<h1>Flowchart Maker and Online Diagram Software</h1>
<p>
diagrams.net (formerly draw.io) is free online diagram software. You can use it as a flowchart maker, network diagram software, to create UML online, as an ER diagram tool,
to design database schema, to build BPMN online, as a circuit diagram maker, and more. draw.io can import .vsdx, Gliffy&trade; and Lucidchart&trade; files .
</p>
<h2 id="geStatus">Loading...</h2>
<p>
Please ensure JavaScript is enabled.
</p>
</div>
</div>
<script type="text/javascript">
/**
* Main
*/
if (navigator.userAgent != null && navigator.userAgent.toLowerCase().
indexOf(' electron/') >= 0 && typeof process !== 'undefined' && process.versions.electron < 5)
{
// Redirects old Electron app to latest version
var div = document.getElementById('geInfo');
if (div != null)
{
div.innerHTML = '<center><h2>You are using an out of date version of this app.<br>Please download the latest version ' +
'<a href="https://github.com/jgraph/drawio-desktop/releases/latest" target="_blank">here</a>.</h2></center>';
}
}
else
{
if (urlParams['dev'] != '1' && typeof document.createElement('canvas').getContext === "function")
{
window.addEventListener('load', function()
{
mxWinLoaded = true;
checkAllLoaded();
});
}
else
{
App.main();
}
}
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
.croppie-container{width:100%;height:100%}.croppie-container .cr-image{z-index:-1;position:absolute;top:0;left:0;transform-origin:0 0;max-height:none;max-width:none}.croppie-container .cr-boundary{position:relative;overflow:hidden;margin:0 auto;z-index:1;width:100%;height:100%}.croppie-container .cr-resizer,.croppie-container .cr-viewport{position:absolute;border:2px solid #fff;margin:auto;top:0;bottom:0;right:0;left:0;box-shadow:0 0 2000px 2000px rgba(0,0,0,.5);z-index:0}.croppie-container .cr-resizer{z-index:2;box-shadow:none;pointer-events:none}.croppie-container .cr-resizer-horisontal,.croppie-container .cr-resizer-vertical{position:absolute;pointer-events:all}.croppie-container .cr-resizer-horisontal::after,.croppie-container .cr-resizer-vertical::after{display:block;position:absolute;box-sizing:border-box;border:1px solid #000;background:#fff;width:10px;height:10px;content:''}.croppie-container .cr-resizer-vertical{bottom:-5px;cursor:row-resize;width:100%;height:10px}.croppie-container .cr-resizer-vertical::after{left:50%;margin-left:-5px}.croppie-container .cr-resizer-horisontal{right:-5px;cursor:col-resize;width:10px;height:100%}.croppie-container .cr-resizer-horisontal::after{top:50%;margin-top:-5px}.croppie-container .cr-original-image{display:none}.croppie-container .cr-vp-circle{border-radius:50%}.croppie-container .cr-overlay{z-index:1;position:absolute;cursor:move;touch-action:none}.croppie-container .cr-slider-wrap{width:75%;margin:15px auto;text-align:center}.croppie-result{position:relative;overflow:hidden}.croppie-result img{position:absolute}.croppie-container .cr-image,.croppie-container .cr-overlay,.croppie-container .cr-viewport{-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.cr-slider{-webkit-appearance:none;width:300px;max-width:100%;padding-top:8px;padding-bottom:8px;background-color:transparent}.cr-slider::-webkit-slider-runnable-track{width:100%;height:3px;background:rgba(0,0,0,.5);border:0;border-radius:3px}.cr-slider::-webkit-slider-thumb{-webkit-appearance:none;border:none;height:16px;width:16px;border-radius:50%;background:#ddd;margin-top:-6px}.cr-slider:focus{outline:0}.cr-slider::-moz-range-track{width:100%;height:3px;background:rgba(0,0,0,.5);border:0;border-radius:3px}.cr-slider::-moz-range-thumb{border:none;height:16px;width:16px;border-radius:50%;background:#ddd;margin-top:-6px}.cr-slider:-moz-focusring{outline:1px solid #fff;outline-offset:-1px}.cr-slider::-ms-track{width:100%;height:5px;background:0 0;border-color:transparent;border-width:6px 0;color:transparent}.cr-slider::-ms-fill-lower{background:rgba(0,0,0,.5);border-radius:10px}.cr-slider::-ms-fill-upper{background:rgba(0,0,0,.5);border-radius:10px}.cr-slider::-ms-thumb{border:none;height:16px;width:16px;border-radius:50%;background:#ddd;margin-top:1px}.cr-slider:focus::-ms-fill-lower{background:rgba(0,0,0,.5)}.cr-slider:focus::-ms-fill-upper{background:rgba(0,0,0,.5)}.cr-rotate-controls{position:absolute;bottom:5px;left:5px;z-index:1}.cr-rotate-controls button{border:0;background:0 0}.cr-rotate-controls i:before{display:inline-block;font-style:normal;font-weight:900;font-size:22px}.cr-rotate-l i:before{content:'↺'}.cr-rotate-r i:before{content:'↻'}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -18,6 +18,14 @@ upstream service {
server php:20000 weight=5 max_fails=3 fail_timeout=30s; server php:20000 weight=5 max_fails=3 fail_timeout=30s;
keepalive 16; keepalive 16;
} }
upstream office {
server office weight=5 max_fails=3 fail_timeout=30s;
keepalive 16;
}
upstream fileview {
server fileview:8012 weight=5 max_fails=3 fail_timeout=30s;
keepalive 16;
}
server { server {
listen 80; listen 80;
@ -77,23 +85,6 @@ server {
proxy_pass http://service; proxy_pass http://service;
} }
location /fileview {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-Host $the_host;
proxy_set_header X-Forwarded-Proto $the_scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header Server-Protocol $server_protocol;
proxy_set_header Server-Name $server_name;
proxy_set_header Server-Addr $server_addr;
proxy_set_header Server-Port $server_port;
proxy_pass http://fileview:8012;
}
location /office/ { location /office/ {
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
@ -112,11 +103,12 @@ server {
proxy_pass http://office/; proxy_pass http://office/;
} }
location /drawio/webapp/ { location /fileview {
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port; proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-Host $the_host/drawio/webapp; proxy_set_header X-Forwarded-Host $the_host;
proxy_set_header X-Forwarded-Proto $the_scheme; proxy_set_header X-Forwarded-Proto $the_scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
@ -125,27 +117,7 @@ server {
proxy_set_header Server-Name $server_name; proxy_set_header Server-Name $server_name;
proxy_set_header Server-Addr $server_addr; proxy_set_header Server-Addr $server_addr;
proxy_set_header Server-Port $server_port; proxy_set_header Server-Port $server_port;
proxy_set_header Upgrade $http_upgrade; proxy_pass http://fileview;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://drawio-webapp:8080/;
}
location /drawio/export/ {
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-Host $the_host/drawio/export;
proxy_set_header X-Forwarded-Proto $the_scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header Server-Protocol $server_protocol;
proxy_set_header Server-Name $server_name;
proxy_set_header Server-Addr $server_addr;
proxy_set_header Server-Port $server_port;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://drawio-export:8000/;
} }
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More