Merge remote-tracking branch 'origin/develop' into develop

# Conflicts:
#	app/Http/Controllers/Api/FileController.php
#	public/js/build/208.js
#	public/js/build/252.js
#	public/js/build/400.js
#	public/js/build/76.js
This commit is contained in:
韦荣超 2022-02-11 11:01:05 +08:00
commit 230d1a1f86
78 changed files with 805 additions and 311 deletions

View File

@ -9,6 +9,7 @@ use App\Models\WebSocketDialog;
use App\Models\WebSocketDialogMsg;
use App\Models\WebSocketDialogMsgRead;
use App\Module\Base;
use Carbon\Carbon;
use Request;
use Response;
@ -269,7 +270,7 @@ class DialogController extends AbstractController
} else {
$data = Base::upload([
"file" => Request::file('files'),
"type" => 'file',
"type" => 'more',
"path" => $path,
"fileName" => $fileName,
]);
@ -349,6 +350,9 @@ class DialogController extends AbstractController
* @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 返回信息(错误描述)
@ -359,11 +363,20 @@ class DialogController extends AbstractController
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') {

View File

@ -9,14 +9,11 @@ use App\Models\FileContent;
use App\Models\FileLink;
use App\Models\FileUser;
use App\Models\User;
use App\Models\WebSocketDialogMsg;
use App\Module\Base;
use App\Module\Ihttp;
use App\Tasks\BatchRemoveFileTask;
use Hhxsv5\LaravelS\Swoole\Task\Task;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Request;
use Response;
/**
* @apiDefine file
@ -318,11 +315,11 @@ class FileController extends AbstractController
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function move($id = 0)
public function move()
{
$user = User::auth();
//
$id = empty($id) ? intval(Request::input('id')) : $id;
$id = intval(Request::input('id'));
$pid = intval(Request::input('pid'));
//
$file = File::permissionFind($id, 1000);
@ -348,44 +345,6 @@ class FileController extends AbstractController
return Base::retSuccess('操作成功', $file);
}
/**
* @api {get} api/file/batch/move 批量移动文件
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup file
* @apiName batch__move
*
* @apiParam {Array} ids 文件ID
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*
* @return array
*/
public function batch__move(): array
{
$ids = Request::input('ids');
if ( empty($ids) || !is_array($ids) ) {
return Base::retError("请选择要移动的文件");
}
// 去重
$ids = array_unique($ids);
$data = [];
// 暂时不考虑异步
AbstractModel::transaction( function () use ($ids, &$data) {
foreach ($ids as $id) {
$res = $this->move($id);
if ( Base::isError($res) )
throw new ApiException($res["msg"]);
$data[] = $res["data"];
}
} );
return Base::retSuccess('操作成功', $data);
}
/**
* @api {get} api/file/remove 07. 删除文件()
*
@ -412,33 +371,6 @@ class FileController extends AbstractController
return Base::retSuccess('删除成功', $file);
}
/**
* @api {get} api/file/batch/remove 批量删除文件
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup file
* @apiName batchRemove
*
* @apiParam {Array} ids 文件ID
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*
* @return array
*/
public function batch__remove(): array
{
$ids = Request::input('ids');
if ( empty($ids) || !is_array($ids) ) {
return Base::retError("请选择要删除的文件");
}
$task = new BatchRemoveFileTask($ids, User::userid());
Task::deliver($task);
return Base::retSuccess('操作成功');
}
/**
* @api {get} api/file/content 08. 获取文件内容
*
@ -450,7 +382,10 @@ class FileController extends AbstractController
* @apiParam {Number|String} id
* - Number: 文件ID需要登录
* - String: 链接码(不需要登录,用于预览)
* @apiParam {String} down 直接下载
* @apiParam {String} only_update_at 仅获取update_at字段
* - no (默认)
* - yes
* @apiParam {String} down 直接下载
* - no: 浏览(默认)
* - yes: 下载office文件直接下载
*
@ -462,6 +397,7 @@ class FileController extends AbstractController
{
$id = Request::input('id');
$down = Request::input('down', 'no');
$only_update_at = Request::input('only_update_at', 'no');
//
if (Base::isNumber($id)) {
User::auth();
@ -476,6 +412,13 @@ class FileController extends AbstractController
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();
return FileContent::formatContent($file, $content?->content, $down == 'yes');
}
@ -631,10 +574,11 @@ class FileController extends AbstractController
}
//
$dirs = explode("/", $webkitRelativePath);
AbstractModel::transaction(function() use ($user, $userid, $dirs, &$pid) {
while (count($dirs) > 1) {
$dirName = array_shift($dirs);
if ($dirName) {
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([
@ -645,17 +589,19 @@ class FileController extends AbstractController
'created_id' => $user->userid,
]);
if ($dirRow->save()) {
$tmpRow = File::find($dirRow->id);
$tmpRow->pushMsg('add', $tmpRow);
$pushMsg[] = File::find($dirRow->id);
}
}
if (empty($dirRow)) {
throw new ApiException('创建文件夹失败');
}
$pid = $dirRow->id;
});
foreach ($pushMsg as $tmpRow) {
$tmpRow->pushMsg('add', $tmpRow);
}
}
});
}
//
$path = 'uploads/file/' . date("Ym") . '/u' . $user->userid . '/';
$data = Base::upload([

View File

@ -204,6 +204,9 @@ class ProjectController extends AbstractController
* @apiParam {String} name 项目名称
* @apiParam {String} [desc] 项目介绍
* @apiParam {String} [columns] 列表格式列表名称1,列表名称2
* @apiParam {String} [flow] 开启流程
* - open: 开启
* - close: 关闭(默认)
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
@ -215,6 +218,7 @@ class ProjectController extends AbstractController
// 项目名称
$name = trim(Request::input('name', ''));
$desc = trim(Request::input('desc', ''));
$flow = trim(Request::input('flow', 'close'));
if (mb_strlen($name) < 2) {
return Base::retError('项目名称不可以少于2个字');
} elseif (mb_strlen($name) > 32) {
@ -251,7 +255,7 @@ class ProjectController extends AbstractController
'desc' => $desc,
'userid' => $user->userid,
]);
AbstractModel::transaction(function() use ($insertColumns, $project) {
AbstractModel::transaction(function() use ($flow, $insertColumns, $project) {
$project->save();
ProjectUser::createInstance([
'project_id' => $project->id,
@ -268,6 +272,10 @@ class ProjectController extends AbstractController
}
$project->dialog_id = $dialog->id;
$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);
@ -1091,7 +1099,10 @@ class ProjectController extends AbstractController
* @apiGroup project
* @apiName task__filedetail
*
* @apiParam {Number} file_id 文件ID
* @apiParam {Number} file_id 文件ID
* @apiParam {String} only_update_at 仅获取update_at字段
* - no (默认)
* - yes
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
@ -1102,11 +1113,20 @@ class ProjectController extends AbstractController
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');
//
@ -1641,95 +1661,7 @@ class ProjectController extends AbstractController
//
$project = Project::userProject($project_id, true, true);
//
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 ($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' => $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);
});
return Base::retSuccess('保存成功', $project->addFlow($flows));
}
/**

View File

@ -101,12 +101,16 @@ class SystemController extends AbstractController
}
/**
* @api {post} api/system/priority 03. 获取优先级、保存优先级
* @api {post} api/system/priority 03. 任务优先级
*
* @apiDescription 获取任务优先级、保存任务优先级
* @apiVersion 1.0.0
* @apiGroup system
* @apiName priority
*
* @apiParam {String} type
* - get: 获取(默认)
* - save: 保存(限管理员)
* @apiParam {Array} list 优先级数据,格式:[{name,color,days,priority}]
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
@ -145,6 +149,53 @@ class SystemController extends AbstractController
return Base::retSuccess('success', $setting);
}
/**
* @api {post} api/system/column/template 03. 创建项目模板
*
* @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 04. 获取终端详细信息
*

View File

@ -21,6 +21,9 @@ class VerifyCsrfToken extends Middleware
// 保存任务优先级
'api/system/priority/',
// 保存创建项目列表模板
'api/system/column/template/',
// 添加任务
'api/project/task/add/',

View File

@ -3,6 +3,7 @@
namespace App\Models;
use App\Exceptions\ApiException;
use App\Module\Base;
use App\Tasks\PushTask;
use Carbon\Carbon;
use DB;
@ -211,7 +212,7 @@ class Project extends AbstractModel
*/
public function relationUserids()
{
return $this->projectUser->pluck('userid')->toArray();
return ProjectUser::whereProjectId($this->id)->orderBy('id')->pluck('userid')->toArray();
}
/**
@ -350,6 +351,104 @@ 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;
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,
]);
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($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

View File

@ -851,7 +851,7 @@ class ProjectTask extends AbstractModel
*/
public function relationUserids()
{
$userids = $this->taskUser->pluck('userid')->toArray();
$userids = ProjectTaskUser::whereTaskId($this->id)->orderByDesc('owner')->orderByDesc('id')->pluck('userid')->toArray();
$items = ProjectTask::with(['taskUser'])->where('parent_id', $this->id)->whereNull('archived_at')->get();
foreach ($items as $item) {
$userids = array_merge($userids, $item->taskUser->pluck('userid')->toArray());

View File

@ -2236,7 +2236,7 @@ class Base
$type = ['zip'];
break;
case 'file':
$type = ['jpg', 'jpeg', 'png', 'gif', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'esp', 'pdf', 'rar', 'zip', 'gz'];
$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'];
break;
case 'firmware':
$type = ['img', 'tar', 'bin'];

View File

@ -0,0 +1,40 @@
<?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

@ -16,14 +16,13 @@ class SettingsTableSeeder extends Seeder
{
if (\DB::table('settings')->count() > 0) {
if (\DB::table('settings')->where('name', 'system')->count() > 0) {
return;
}
\DB::table('settings')->insert(array (
0 =>
array (
'id' => 1,
'name' => 'system',
'desc' => '',
'setting' => '{"reg":"open","project_invite":"open","login_code":"auto"}',
@ -32,7 +31,6 @@ class SettingsTableSeeder extends Seeder
),
1 =>
array (
'id' => 2,
'name' => 'priority',
'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}]',

View File

@ -87,6 +87,9 @@ services:
- ./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/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:
TZ: "Asia/Shanghai"
networks:

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

2
electron/build.js vendored
View File

@ -33,7 +33,7 @@ function startBuild(data, publish) {
// index.html
let indexFile = path.resolve(electronDir, "index.html");
let indexString = fs.readFileSync(indexFile, 'utf8');
indexString = indexString.replace(`<title></title>`, `<title>${data.name}</title>`);
indexString = indexString.replace(/<title>(.*?)<\/title>/g, `<title>${data.name}</title>`);
fs.writeFileSync(indexFile, indexString, 'utf8');
// package.json Backup
fse.copySync(packageFile, packageBakFile)

View File

@ -1,6 +1,6 @@
{
"name": "DooTask",
"version": "0.7.72",
"version": "0.7.94",
"description": "DooTask is task management system.",
"main": "main.js",
"license": "MIT",

View File

@ -1,6 +1,6 @@
{
"name": "DooTask",
"version": "0.7.72",
"version": "0.7.94",
"description": "DooTask is task management system.",
"scripts": {
"start": "./cmd dev",

2
public/css/app.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
public/js/app.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
/*!
* html2canvas 1.4.1 <https://html2canvas.hertzen.com>
* html2canvas 1.4.0 <https://html2canvas.hertzen.com>
* Copyright (c) 2022 Niklas von Hertzen <https://hertzen.com>
* Released under MIT License
*/

1
public/js/build/135.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
"use strict";(self.webpackChunkDooTask=self.webpackChunkDooTask||[]).push([[159],{26071:(e,t,i)=>{i.d(t,{Z:()=>r});var n=i(1519),o=i.n(n)()((function(e){return e[1]}));o.push([e.id,".component-only-office[data-v-c9bf06c2]{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0}.component-only-office .placeholder[data-v-c9bf06c2]{flex:1;height:100%;width:100%}.component-only-office .office-loading[data-v-c9bf06c2]{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:2}",""]);const r=o},36159:(e,t,i)=>{i.r(t),i.d(t,{default:()=>u});var n=i(20629);function o(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function r(e){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?o(Object(i),!0).forEach((function(t){s(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):o(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function s(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}const l={name:"OnlyOffice",props:{id:{type:String,default:function(){return"office_"+Math.round(1e4*Math.random())}},code:{type:String,default:""},value:{type:[Object,Array],default:function(){return{}}},readOnly:{type:Boolean,default:!1}},data:function(){return{loadIng:0,docEditor:null}},mounted:function(){},beforeDestroy:function(){null!==this.docEditor&&(this.docEditor.destroyEditor(),this.docEditor=null)},computed:r(r({},(0,n.rn)(["userToken","userInfo","themeIsDark"])),{},{fileType:function(){return this.getType(this.value.type)},fileName:function(){return this.value.name}}),watch:{"value.id":{handler:function(e){var t=this;e&&(this.loadIng++,$A.loadScript($A.apiUrl("../office/web-apps/apps/api/documents/api.js"),(function(e){t.loadIng--,null!==e?$A.modalAlert("组件加载失败!"):t.loadFile()})))},immediate:!0}},methods:{getType:function(e){switch(e){case"word":return"docx";case"excel":return"xlsx";case"ppt":return"pptx"}return e},loadFile:function(){var e=this;null!==this.docEditor&&(this.docEditor.destroyEditor(),this.docEditor=null);var t="zh";switch(this.getLanguage()){case"CN":case"TC":t="zh";break;default:t="en"}var i=this.code||this.value.id,n=$A.strExists(this.fileName,".")?this.fileName:this.fileName+"."+this.fileType,o={document:{fileType:this.fileType,key:this.fileType+"-"+i,title:n,url:"http://nginx/api/file/content/?id="+i+"&token="+this.userToken},editorConfig:{mode:"edit",lang:t,user:{id:this.userInfo.userid,name:this.userInfo.nickname},customization:{uiTheme:this.themeIsDark?"theme-dark":"theme-classic-light"},callbackUrl:"http://nginx/api/file/content/office?id="+i+"&token="+this.userToken}};if(/\/hideenOfficeTitle\//.test(window.navigator.userAgent)&&(o.document.title=" "),$A.leftExists(i,"msgFile_")?o.document.url="http://nginx/api/dialog/msg/download/?msg_id="+$A.leftDelete(i,"msgFile_")+"&token="+this.userToken:$A.leftExists(i,"taskFile_")&&(o.document.url="http://nginx/api/project/task/filedown/?file_id="+$A.leftDelete(i,"taskFile_")+"&token="+this.userToken),this.readOnly&&(o.editorConfig.mode="view",o.editorConfig.callbackUrl=null,!o.editorConfig.user.id)){var r=$A.getStorageInt("viewer");r||(r=$A.randNum(1e3,99999),$A.setStorage("viewer",r)),o.editorConfig.user.id="viewer_"+r,o.editorConfig.user.name="Viewer_"+r}this.$nextTick((function(){e.docEditor=new DocsAPI.DocEditor(e.id,o)}))}}};var a=i(93379),c=i.n(a),d=i(26071),f={insert:"head",singleton:!1};c()(d.Z,f);d.Z.locals;const u=(0,i(51900).Z)(l,(function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("div",{staticClass:"component-only-office"},[i("div",{staticClass:"placeholder",attrs:{id:this.id}}),e._v(" "),e.loadIng>0?i("div",{staticClass:"office-loading"},[i("Loading")],1):e._e()])}),[],!1,null,"c9bf06c2",null).exports}}]);

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

1
public/js/build/258.js vendored Normal file
View File

@ -0,0 +1 @@
"use strict";(self.webpackChunkDooTask=self.webpackChunkDooTask||[]).push([[258],{98258:(t,e,s)=>{s.r(e),s.d(e,{default:()=>o});function n(t,e){var s=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),s.push.apply(s,n)}return s}function i(t){for(var e=1;e<arguments.length;e++){var s=null!=arguments[e]?arguments[e]:{};e%2?n(Object(s),!0).forEach((function(e){r(t,e,s[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(s)):n(Object(s)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(s,e))}))}return t}function r(t,e,s){return e in t?Object.defineProperty(t,e,{value:s,enumerable:!0,configurable:!0,writable:!0}):t[e]=s,t}const a={data:function(){return{curPath:this.$route.path,show768Menu:!0,version:window.systemInfo.version}},mounted:function(){},computed:i(i({},(0,s(20629).rn)(["userInfo","userIsAdmin"])),{},{menu:function(){var t=[{path:"personal",name:"个人设置"},{path:"password",name:"密码设置"}];return this.userIsAdmin&&t.push.apply(t,[{path:"system",name:"系统设置",divided:!0}]),t},titleNameRoute:function(){var t=this.curPath,e=this.menu,s="";return e.some((function(e){if($A.leftExists(t,"/manage/setting/"+e.path))return s=e.name,!0})),s||"设置"}}),watch:{$route:function(t){this.curPath=t.path}},methods:{toggleRoute:function(t){this.show768Menu=!1,this.goForward({path:"/manage/setting/"+t})},classNameRoute:function(t,e){return{active:$A.leftExists(this.curPath,"/manage/setting/"+t),divided:!!e}}}};const o=(0,s(51900).Z)(a,(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{staticClass:"page-setting"},[s("PageTitle",{attrs:{title:t.$L(t.titleNameRoute)}}),t._v(" "),s("div",{staticClass:"setting-head"},[s("div",{staticClass:"setting-titbox"},[s("div",{staticClass:"setting-title"},[s("h1",[t._v(t._s(t.$L("设置")))]),t._v(" "),s("div",{staticClass:"setting-more",on:{click:function(e){t.show768Menu=!t.show768Menu}}},[s("Icon",{attrs:{type:t.show768Menu?"md-close":"md-more"}})],1)])])]),t._v(" "),s("div",{staticClass:"setting-box"},[s("div",{staticClass:"setting-menu",class:{"show768-menu":t.show768Menu}},[s("ul",[t._l(t.menu,(function(e,n){return s("li",{key:n,class:t.classNameRoute(e.path,e.divided),on:{click:function(s){return t.toggleRoute(e.path)}}},[t._v(t._s(t.$L(e.name)))])})),t._v(" "),s("li",{staticClass:"version divided"},[s("AutoTip",[t._v(t._s(t.$L("版本"))+": "+t._s(t.version))])],1)],2)]),t._v(" "),s("div",{staticClass:"setting-content"},[s("div",{staticClass:"setting-content-title"},[t._v(t._s(t.$L(t.titleNameRoute)))]),t._v(" "),s("div",{staticClass:"setting-content-view"},[s("router-view",{staticClass:"setting-router-view"})],1)])])],1)}),[],!1,null,null,null).exports}}]);

File diff suppressed because one or more lines are too long

2
public/js/build/400.js vendored Normal file

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
public/js/build/755.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
"use strict";(self.webpackChunkDooTask=self.webpackChunkDooTask||[]).push([[805],{80805:(t,e,o)=>{o.r(e),o.d(e,{default:()=>s});function n(t,e){var o=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),o.push.apply(o,n)}return o}function r(t,e,o){return e in t?Object.defineProperty(t,e,{value:o,enumerable:!0,configurable:!0,writable:!0}):t[e]=o,t}const a={data:function(){return{loadIng:0,formDatum:[],nullDatum:{name:"",priority:1,days:1,color:"#8bcf70"}}},mounted:function(){this.systemSetting()},computed:function(t){for(var e=1;e<arguments.length;e++){var o=null!=arguments[e]?arguments[e]:{};e%2?n(Object(o),!0).forEach((function(e){r(t,e,o[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(o)):n(Object(o)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(o,e))}))}return t}({},(0,o(20629).rn)(["taskPriority"])),watch:{taskPriority:{handler:function(t){this.formDatum=$A.cloneJSON(t),0===this.formDatum.length&&this.addDatum()},immediate:!0}},methods:{submitForm:function(){var t=this;this.$refs.formDatum.validate((function(e){e&&t.systemSetting(!0)}))},resetForm:function(){this.formDatum=$A.cloneJSON(this.taskPriority)},addDatum:function(){this.formDatum.push($A.cloneJSON(this.nullDatum))},delDatum:function(t){this.formDatum.splice(t,1),0===this.formDatum.length&&this.addDatum()},systemSetting:function(t){var e=this;this.loadIng++,this.$store.dispatch("call",{url:"system/priority?type="+(t?"save":"get"),method:"post",data:{list:this.formDatum}}).then((function(o){var n=o.data;t&&$A.messageSuccess("修改成功"),e.loadIng--,e.$store.state.taskPriority=$A.cloneJSON(n)})).catch((function(o){var n=o.msg;t&&$A.modalError(n),e.loadIng--}))}}};const s=(0,o(51900).Z)(a,(function(){var t=this,e=t.$createElement,o=t._self._c||e;return o("div",{staticClass:"setting-item submit"},[o("Form",{ref:"formDatum",attrs:{"label-width":"auto"},nativeOn:{submit:function(t){t.preventDefault()}}},[o("Row",{staticClass:"setting-color"},[o("Col",{attrs:{span:"12"}},[t._v(t._s(t.$L("名称")))]),t._v(" "),o("Col",{attrs:{span:"4"}},[o("ETooltip",{attrs:{content:t.$L("数值越小级别越高"),"max-width":"auto",placement:"top",transfer:""}},[o("div",[o("Icon",{staticClass:"information",attrs:{type:"ios-information-circle-outline"}}),t._v(" "+t._s(t.$L("级别")))],1)])],1),t._v(" "),o("Col",{attrs:{span:"4"}},[o("ETooltip",{attrs:{content:t.$L("任务完成时间"),"max-width":"auto",placement:"top",transfer:""}},[o("div",[o("Icon",{staticClass:"information",attrs:{type:"ios-information-circle-outline"}}),t._v(" "+t._s(t.$L("天数")))],1)])],1),t._v(" "),o("Col",{attrs:{span:"4"}},[t._v(t._s(t.$L("颜色")))])],1),t._v(" "),t._l(t.formDatum,(function(e,n){return o("Row",{key:n,staticClass:"setting-color"},[o("Col",{attrs:{span:"12"}},[o("Input",{attrs:{maxlength:20,placeholder:t.$L("请输入名称"),clearable:""},on:{"on-clear":function(e){return t.delDatum(n)}},model:{value:e.name,callback:function(o){t.$set(e,"name",o)},expression:"item.name"}})],1),t._v(" "),o("Col",{attrs:{span:"4"}},[o("Input",{attrs:{type:"number"},model:{value:e.priority,callback:function(o){t.$set(e,"priority",o)},expression:"item.priority"}})],1),t._v(" "),o("Col",{attrs:{span:"4"}},[o("Input",{attrs:{type:"number"},model:{value:e.days,callback:function(o){t.$set(e,"days",o)},expression:"item.days"}})],1),t._v(" "),o("Col",{attrs:{span:"4"}},[o("ColorPicker",{attrs:{recommend:"",transfer:""},model:{value:e.color,callback:function(o){t.$set(e,"color",o)},expression:"item.color"}})],1)],1)})),t._v(" "),o("Button",{attrs:{type:"default",icon:"md-add"},on:{click:t.addDatum}},[t._v(t._s(t.$L("添加优先级")))])],2),t._v(" "),o("div",{staticClass:"setting-footer"},[o("Button",{attrs:{loading:t.loadIng>0,type:"primary"},on:{click:t.submitForm}},[t._v(t._s(t.$L("提交")))]),t._v(" "),o("Button",{staticStyle:{"margin-left":"8px"},attrs:{loading:t.loadIng>0},on:{click:t.resetForm}},[t._v(t._s(t.$L("重置")))])],1)],1)}),[],!1,null,null,null).exports}}]);

File diff suppressed because one or more lines are too long

1
public/js/build/942.js vendored Normal file
View File

@ -0,0 +1 @@
"use strict";(self.webpackChunkDooTask=self.webpackChunkDooTask||[]).push([[942],{85916:(e,t,i)=>{i.d(t,{Z:()=>r});var n=i(1519),o=i.n(n)()((function(e){return e[1]}));o.push([e.id,".component-only-office[data-v-1ec144f0]{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0}.component-only-office .placeholder[data-v-1ec144f0]{flex:1;height:100%;width:100%}.component-only-office .office-loading[data-v-1ec144f0]{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:2}",""]);const r=o},17942:(e,t,i)=>{i.r(t),i.d(t,{default:()=>f});var n=i(20629);function o(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function r(e){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?o(Object(i),!0).forEach((function(t){c(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):o(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function c(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}const a={name:"OnlyOffice",props:{id:{type:String,default:function(){return"office_"+Math.round(1e4*Math.random())}},code:{type:String,default:""},value:{type:[Object,Array],default:function(){return{}}},readOnly:{type:Boolean,default:!1},documentKey:Function},data:function(){return{loadIng:0,docEditor:null}},mounted:function(){},beforeDestroy:function(){null!==this.docEditor&&(this.docEditor.destroyEditor(),this.docEditor=null)},computed:r(r({},(0,n.rn)(["userToken","userInfo","themeIsDark"])),{},{fileType:function(){return this.getType(this.value.type)},fileName:function(){return this.value.name}}),watch:{"value.id":{handler:function(e){var t=this;e&&(this.loadIng++,$A.loadScript($A.apiUrl("../office/web-apps/apps/api/documents/api.js"),(function(e){if(t.loadIng--,null===e)if(t.documentKey){var i=t.documentKey();i&&i.then?i.then(t.loadFile):t.loadFile()}else t.handleClose();else $A.modalAlert("组件加载失败!")})))},immediate:!0}},methods:{getType:function(e){switch(e){case"word":return"docx";case"excel":return"xlsx";case"ppt":return"pptx"}return e},loadFile:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";null!==this.docEditor&&(this.docEditor.destroyEditor(),this.docEditor=null);var i="zh";switch(this.getLanguage()){case"CN":case"TC":i="zh";break;default:i="en"}var n=this.code||this.value.id,o=$A.strExists(this.fileName,".")?this.fileName:this.fileName+"."+this.fileType,r={document:{fileType:this.fileType,key:"".concat(this.fileType,"-").concat(n,"-").concat(t),title:o,url:"http://nginx/api/file/content/?id=".concat(n,"&token=").concat(this.userToken)},editorConfig:{mode:"edit",lang:i,user:{id:this.userInfo.userid,name:this.userInfo.nickname},customization:{uiTheme:this.themeIsDark?"theme-dark":"theme-classic-light"},callbackUrl:"http://nginx/api/file/content/office?id=".concat(n,"&token=").concat(this.userToken)}};if(/\/hideenOfficeTitle\//.test(window.navigator.userAgent)&&(r.document.title=" "),$A.leftExists(n,"msgFile_")?r.document.url="http://nginx/api/dialog/msg/download/?msg_id=".concat($A.leftDelete(n,"msgFile_"),"&token=").concat(this.userToken):$A.leftExists(n,"taskFile_")&&(r.document.url="http://nginx/api/project/task/filedown/?file_id=".concat($A.leftDelete(n,"taskFile_"),"&token=").concat(this.userToken)),this.readOnly&&(r.editorConfig.mode="view",r.editorConfig.callbackUrl=null,!r.editorConfig.user.id)){var c=$A.getStorageInt("viewer");c||(c=$A.randNum(1e3,99999),$A.setStorage("viewer",c)),r.editorConfig.user.id="viewer_"+c,r.editorConfig.user.name="Viewer_"+c}this.$nextTick((function(){e.docEditor=new DocsAPI.DocEditor(e.id,r)}))}}};var l=i(93379),s=i.n(l),d=i(85916),u={insert:"head",singleton:!1};s()(d.Z,u);d.Z.locals;const f=(0,i(51900).Z)(a,(function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("div",{staticClass:"component-only-office"},[i("div",{staticClass:"placeholder",attrs:{id:this.id}}),e._v(" "),e.loadIng>0?i("div",{staticClass:"office-loading"},[i("Loading")],1):e._e()])}),[],!1,null,"1ec144f0",null).exports}}]);

View File

@ -45,13 +45,14 @@ export default {
},
computed: {
...mapState([
'isDesktop',
'wsOpenNum',
]),
repoTitle() {
return this.repoStatus == 2 ? '更新客户端' : '客户端下载';
},
showButton() {
return this.repoStatus && !this.$store.state.windowMax768 && ['login', 'manage-dashboard'].includes(this.$route.name)
return this.repoStatus && this.isDesktop && ['login', 'manage-dashboard'].includes(this.$route.name)
}
},
watch: {

View File

@ -225,9 +225,12 @@
this.$refs.upload.fileList.splice(fileList.indexOf(item), 1);
this.$emit('input', this.$refs.upload.fileList);
},
handleProgress() {
handleProgress(event, file) {
//
this.$emit('update:uploadIng', this.uploadIng + 1);
if (file._uploadIng === undefined) {
file._uploadIng = true;
this.$emit('update:uploadIng', this.uploadIng + 1);
}
},
handleSuccess (res, file) {
//

View File

@ -248,9 +248,12 @@
/********************文件上传部分************************/
handleProgress() {
handleProgress(event, file) {
//
this.uploadIng++;
if (file._uploadIng === undefined) {
file._uploadIng = true;
this.uploadIng++;
}
},
handleSuccess(res, file) {

View File

@ -60,6 +60,7 @@ export default {
type: Boolean,
default: false
},
documentKey: Function
},
data() {
@ -90,7 +91,7 @@ export default {
fileName() {
return this.value.name;
}
},
},
watch: {
@ -104,8 +105,17 @@ export default {
this.loadIng--;
if (e !== null) {
$A.modalAlert("组件加载失败!");
return;
}
if (!this.documentKey) {
this.handleClose();
return
}
const documentKey = this.documentKey();
if (documentKey && documentKey.then) {
documentKey.then(this.loadFile);
} else {
this.loadFile()
this.loadFile();
}
})
},
@ -126,7 +136,7 @@ export default {
return type;
},
loadFile() {
loadFile(keyAppend = '') {
if (this.docEditor !== null) {
this.docEditor.destroyEditor();
this.docEditor = null;
@ -148,9 +158,9 @@ export default {
const config = {
"document": {
"fileType": this.fileType,
"key": this.fileType + '-' + fileKey,
"key": `${this.fileType}-${fileKey}-${keyAppend}`,
"title": fileName,
"url": 'http://nginx/api/file/content/?id=' + fileKey + '&token=' + this.userToken,
"url": `http://nginx/api/file/content/?id=${fileKey}&token=${this.userToken}`,
},
"editorConfig": {
"mode": "edit",
@ -162,16 +172,16 @@ export default {
"customization": {
"uiTheme": this.themeIsDark ? "theme-dark" : "theme-classic-light",
},
"callbackUrl": 'http://nginx/api/file/content/office?id=' + fileKey + '&token=' + this.userToken,
"callbackUrl": `http://nginx/api/file/content/office?id=${fileKey}&token=${this.userToken}`,
}
};
if (/\/hideenOfficeTitle\//.test(window.navigator.userAgent)) {
config.document.title = " ";
}
if ($A.leftExists(fileKey, "msgFile_")) {
config.document.url = 'http://nginx/api/dialog/msg/download/?msg_id=' + $A.leftDelete(fileKey, "msgFile_") + '&token=' + this.userToken;
config.document.url = `http://nginx/api/dialog/msg/download/?msg_id=${$A.leftDelete(fileKey, "msgFile_")}&token=${this.userToken}`;
} else if ($A.leftExists(fileKey, "taskFile_")) {
config.document.url = 'http://nginx/api/project/task/filedown/?file_id=' + $A.leftDelete(fileKey, "taskFile_") + '&token=' + this.userToken;
config.document.url = `http://nginx/api/project/task/filedown/?file_id=${$A.leftDelete(fileKey, "taskFile_")}&token=${this.userToken}`;
}
if (this.readOnly) {
config.editorConfig.mode = "view";

View File

@ -145,7 +145,7 @@
transfer: false,
uploadIng: 0,
uploadFormat: ['jpg', 'jpeg', 'png', 'gif', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'esp', 'pdf', 'rar', 'zip', 'gz'],
uploadFormat: ['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'],
actionUrl: $A.apiUrl('system/fileupload'),
maxSize: 10240
};
@ -474,9 +474,12 @@
/********************文件上传部分************************/
handleProgress() {
handleProgress(event, file) {
//
this.uploadIng++;
if (file._uploadIng === undefined) {
file._uploadIng = true;
this.uploadIng++;
}
},
handleSuccess(res, file) {

View File

@ -520,6 +520,15 @@
return (ua.match(/Chrome/i) + '' === 'chrome');
},
/**
* 是否桌面端
* @returns {boolean}
*/
isDesktop(){
let ua = typeof window !== 'undefined' && window.navigator.userAgent;
return !ua.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
},
/**
* 获取对象
* @param obj

View File

@ -118,6 +118,9 @@ export default {
* @param language
*/
setLanguage(language) {
if (language === undefined) {
return
}
this.__initLanguageData();
setTimeout(() => {
window.localStorage['__language:type__'] = language;

View File

@ -138,9 +138,15 @@
</FormItem>
<FormItem v-else :label="$L('项目模板')">
<Select :value="0" @on-change="selectChange" :placeholder="$L('请选择模板')">
<Option v-for="(item, index) in columns" :value="index" :key="index">{{ item.label }}</Option>
<Option v-for="(item, index) in columns" :value="index" :key="index">{{ item.name }}</Option>
</Select>
</FormItem>
<FormItem prop="flow" :label="$L('开启工作流')">
<RadioGroup v-model="addData.flow">
<Radio label="open">{{$L('开启')}}</Radio>
<Radio label="close">{{$L('关闭')}}</Radio>
</RadioGroup>
</FormItem>
</Form>
<div slot="footer" class="adaption">
<Button type="default" @click="addShow=false">{{$L('取消')}}</Button>
@ -250,6 +256,7 @@ export default {
addData: {
name: '',
columns: '',
flow: 'open',
},
addRule: {},
@ -258,8 +265,6 @@ export default {
dialogMsgSubscribe: null,
columns: [],
projectKeyValue: '',
projectKeyAlready: {},
projectKeyLoading: 0,
@ -331,6 +336,7 @@ export default {
'projectTotal',
'taskId',
'wsOpenNum',
'columnTemplate',
'themeMode',
'themeList',
@ -370,7 +376,6 @@ export default {
{path: 'password', name: '密码设置'},
{path: 'clearCache', name: '清除缓存'},
{path: 'system', name: '系统设置', divided: true},
{path: 'priority', name: '任务等级'},
{path: 'workReport', name: '工作报告', divided: true},
{path: 'allUser', name: '团队管理'},
{path: 'allProject', name: '所有项目'},
@ -387,6 +392,15 @@ export default {
}
},
columns() {
const array = $A.cloneJSON(this.columnTemplate);
array.unshift({
name: this.$L('空白模板'),
columns: [],
})
return array
},
projectLists() {
const {projectKeyValue, cacheProjects} = this;
const data = cacheProjects.sort((a, b) => {
@ -483,16 +497,6 @@ export default {
methods: {
initLanguage() {
this.columns = [{
label: this.$L('空白模板'),
value: [],
}, {
label: this.$L('软件开发'),
value: [this.$L('产品规划'), this.$L('前端开发'), this.$L('后端开发'), this.$L('测试'), this.$L('发布'), this.$L('其它')],
}, {
label: this.$L('产品开发'),
value: [this.$L('产品计划'), this.$L('正在设计'), this.$L('正在研发'), this.$L('测试'), this.$L('准备发布'), this.$L('发布成功')],
}];
this.addRule = {
name: [
{ required: true, message: this.$L('请填写项目名称!'), trigger: 'change' },
@ -512,6 +516,9 @@ export default {
},
setTheme(mode) {
if (mode === undefined) {
return;
}
if (!$A.isChrome()) {
$A.modalWarning("仅客户端或Chrome浏览器支持主题功能");
return;
@ -571,7 +578,7 @@ export default {
title: '退出登录',
content: '你确定要登出系统?',
onOk: () => {
this.$store.dispatch("logout")
this.$store.dispatch("logout", false)
}
});
return;
@ -593,6 +600,7 @@ export default {
},
onAddShow() {
this.$store.dispatch("getColumnTemplate").catch(() => {})
this.addShow = true;
this.$nextTick(() => {
this.$refs.projectName.focus();
@ -643,7 +651,7 @@ export default {
selectChange(index) {
this.$nextTick(() => {
this.$set(this.addData, 'columns', this.columns[index].value.join(','));
this.$set(this.addData, 'columns', this.columns[index].columns.join(','));
})
},

View File

@ -34,7 +34,27 @@ export default {
data() {
return {
uploadFormat: ['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'],
uploadFormat: [
'docx', 'wps', 'doc', 'xls', 'xlsx', 'ppt', 'pptx',
'jpg', 'jpeg', 'png', 'gif', 'bmp', 'ico', 'raw',
'rar', 'zip', 'jar', '7-zip', 'tar', 'gzip', '7z',
'tif', 'tiff',
'dwg', 'dxf',
'ofd',
'pdf',
'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', 'md', 'markdown', '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',
'avi', 'mov', 'wmv', 'mkv', '3gp', 'rm',
'xmind',
'rp',
],
actionUrl: $A.apiUrl('dialog/msg/sendfile'),
}
},
@ -59,7 +79,7 @@ export default {
methods: {
handleProgress(event, file) {
//
if (typeof file.tempId === "undefined") {
if (file.tempId === undefined) {
file.tempId = $A.randomString(8);
this.$emit('on-progress', file);
}

View File

@ -159,10 +159,10 @@ export default {
computed: {
...mapState([
'isDesktop',
'userId',
'cacheDialogs',
'dialogMsgs',
'windowMax768',
]),
dialogData() {
@ -181,7 +181,7 @@ export default {
},
isAutoBottom() {
if (this.windowMax768 && this.inputFocus) {
if (this.inputFocus && !this.isDesktop) {
return false;
}
return this.autoBottom
@ -268,7 +268,7 @@ export default {
text: this.msgText,
},
});
if (this.windowMax768) {
if (!this.isDesktop) {
this.$refs.input.blur();
}
this.autoToBottom();
@ -368,7 +368,7 @@ export default {
userid: this.userId,
msg: { },
});
if (this.windowMax768) {
if (!this.isDesktop) {
this.$refs.input.blur();
}
this.autoToBottom();

View File

@ -52,7 +52,7 @@
</template>
<Flow v-else-if="file.type=='flow'" ref="myFlow" v-model="contentDetail" @saveData="handleClick('saveBefore')"/>
<Minder v-else-if="file.type=='mind'" ref="myMind" v-model="contentDetail" @saveData="handleClick('saveBefore')"/>
<OnlyOffice v-else-if="['word', 'excel', 'ppt'].includes(file.type)" v-model="contentDetail"/>
<OnlyOffice v-else-if="['word', 'excel', 'ppt'].includes(file.type)" v-model="contentDetail" :documentKey="documentKey"/>
<AceEditor v-else-if="['code', 'txt'].includes(file.type)" v-model="contentDetail.content" :ext="file.ext" @saveData="handleClick('saveBefore')"/>
</div>
</template>
@ -330,6 +330,22 @@ export default {
this.unsaveTip = false;
},
documentKey() {
return new Promise(resolve => {
this.$store.dispatch("call", {
url: 'file/content',
data: {
id: this.fileId,
only_update_at: 'yes'
},
}).then(({data}) => {
resolve($A.Date(data.update_at, true))
}).catch(() => {
resolve(0)
});
})
},
formatName(file) {
let {name, ext} = file;
if (ext != '') {

View File

@ -29,7 +29,7 @@
</template>
<Flow v-else-if="file.type=='flow'" ref="myFlow" v-model="contentDetail" readOnly/>
<Minder v-else-if="file.type=='mind'" ref="myMind" v-model="contentDetail" readOnly/>
<OnlyOffice v-else-if="['word', 'excel', 'ppt'].includes(file.type)" v-model="contentDetail" :code="code" readOnly/>
<OnlyOffice v-else-if="['word', 'excel', 'ppt'].includes(file.type)" v-model="contentDetail" :code="code" :documentKey="documentKey" readOnly/>
<AceEditor v-else-if="['code', 'txt'].includes(file.type)" v-model="contentDetail.content" :ext="file.ext" readOnly/>
</div>
</template>
@ -144,6 +144,22 @@ export default {
})
},
documentKey() {
return new Promise(resolve => {
this.$store.dispatch("call", {
url: 'file/content',
data: {
id: this.code || this.file.id,
only_update_at: 'yes'
},
}).then(({data}) => {
resolve($A.Date(data.update_at, true))
}).catch(() => {
resolve(0)
});
})
},
exportMenu(act) {
switch (this.file.type) {
case 'mind':

View File

@ -91,7 +91,7 @@
<Draggable
:list="columnList"
:animation="150"
:disabled="sortDisabled || windowMax768"
:disabled="sortDisabled || !isDesktop"
class="column-list"
tag="ul"
draggable=".column-item"
@ -146,7 +146,7 @@
<Draggable
:list="column.tasks"
:animation="150"
:disabled="sortDisabled || windowMax768"
:disabled="sortDisabled || !isDesktop"
class="task-list"
draggable=".task-draggable"
group="task"
@ -528,8 +528,8 @@ export default {
computed: {
...mapState([
'isDesktop',
'windowWidth',
'windowMax768',
'userId',
'cacheDialogs',

View File

@ -61,6 +61,7 @@
<Draggable
:list="data.project_flow_item"
:animation="150"
:disabled="!isDesktop"
class="taskflow-config-table-list-wrapper"
tag="div"
draggable=".column-border"
@ -172,6 +173,7 @@
<script>
import Draggable from "vuedraggable";
import UserInput from "../../../components/UserInput";
import {mapState} from "vuex";
export default {
name: "ProjectWorkflow",
@ -199,7 +201,7 @@ export default {
},
computed: {
...mapState(['isDesktop'])
},
watch: {

View File

@ -30,7 +30,7 @@
:plugins="taskPlugins"
:options="taskOptions"
:option-full="taskOptionFull"
:placeholder="$L($store.state.windowMax768 ? '详细描述,选填...' : '详细描述,选填...(点击右键使用工具栏)')"
:placeholder="$L(isDesktop ? '详细描述,选填...(点击右键使用工具栏)' : '详细描述,选填...')"
:placeholderFull="$L('详细描述...')"
inline/>
</div>
@ -82,7 +82,8 @@
v-model="addData.owner"
:multiple-max="10"
:placeholder="$L('选择任务负责人')"
:project-id="addData.project_id"/>
:project-id="addData.project_id"
:transfer="false"/>
<div v-if="showAddAssist" class="task-add-assist">
<Checkbox v-model="addData.add_assist" :true-value="1" :false-value="0">{{$L('加入任务协助人员列表')}}</Checkbox>
<ETooltip :content="$L('你不是任务负责人时建议加入任务协助人员列表')">
@ -231,7 +232,7 @@ export default {
},
computed: {
...mapState(['userId', 'cacheProjects', 'projectId', 'cacheColumns', 'taskPriority']),
...mapState(['isDesktop', 'userId', 'cacheProjects', 'projectId', 'cacheColumns', 'taskPriority']),
taskDays() {
const {times} = this.addData;

View File

@ -41,6 +41,7 @@
<Poptip
ref="owner"
class="subtask-avatar"
popper-class="task-detail-user-popper"
:title="$L('修改负责人')"
:width="240"
placement="bottom"
@ -52,7 +53,8 @@
v-model="ownerData.owner_userid"
:multiple-max="1"
:project-id="taskDetail.project_id"
:placeholder="$L('选择任务负责人')"/>
:placeholder="$L('选择任务负责人')"
:transfer="false"/>
<div class="task-detail-avatar-buttons">
<Button size="small" type="primary" @click="$refs.owner.ok()">{{$L('确定')}}</Button>
</div>
@ -189,6 +191,7 @@
:title="$L('修改负责人')"
:width="240"
class="item-content user"
popper-class="task-detail-user-popper"
placement="bottom"
@on-popper-show="openOwner"
@on-ok="onOwner"
@ -198,7 +201,8 @@
v-model="ownerData.owner_userid"
:multiple-max="10"
:project-id="taskDetail.project_id"
:placeholder="$L('选择任务负责人')"/>
:placeholder="$L('选择任务负责人')"
:transfer="false"/>
<div class="task-detail-avatar-buttons">
<Button size="small" type="primary" @click="$refs.owner.ok()">{{$L('确定')}}</Button>
</div>
@ -217,6 +221,7 @@
:title="$L(getAssist.length > 0 ? '修改协助人员' : '添加协助人员')"
:width="280"
class="item-content user"
popper-class="task-detail-user-popper"
placement="bottom"
@on-popper-show="openAssist"
@on-ok="onAssist"
@ -227,7 +232,8 @@
:multiple-max="10"
:project-id="taskDetail.project_id"
:disabled-choice="assistData.disabled"
:placeholder="$L('选择任务协助人员')"/>
:placeholder="$L('选择任务协助人员')"
:transfer="false"/>
<div class="task-detail-avatar-buttons">
<Button size="small" type="primary" @click="$refs.assist.ok()">{{$L('确定')}}</Button>
</div>

View File

@ -41,6 +41,8 @@
<Option value="">{{$L('全部')}}</Option>
<Option value="admin">{{$L('管理员')}}</Option>
<Option value="disable">{{$L('禁用')}}</Option>
<Option value="noadmin">{{$L('非管理员')}}</Option>
<Option value="nodisable">{{$L('非禁用')}}</Option>
</Select>
</div>
</li>

View File

@ -657,7 +657,7 @@ export default {
const file = this.files.find(({id}) => id == row.id);
if (file) {
setTimeout(() => {
this.$set(file, '_edit', b);
this.setEdit(file.id, b)
}, 100);
}
},
@ -909,7 +909,7 @@ export default {
case 'rename':
this.$set(item, 'newname', item.name);
this.$set(item, '_edit', true);
this.setEdit(item.id, true)
this.autoBlur(item.id)
break;
@ -1107,18 +1107,18 @@ export default {
if (isCreate) {
this.$store.dispatch("forgetFile", item.id);
} else {
this.$set(item, '_edit', false);
this.setEdit(item.id, false)
}
return;
}
if (item.newname == item.name) {
this.$set(item, '_edit', false);
this.setEdit(item.id, false)
return;
}
if (item._load) {
return;
}
this.$set(item, '_load', true);
this.setLoad(item.id, true)
this.$store.dispatch("call", {
url: 'file/add',
data: {
@ -1129,21 +1129,35 @@ export default {
},
}).then(({data, msg}) => {
$A.messageSuccess(msg)
this.$set(item, '_load', false);
this.$set(item, '_edit', false);
this.setLoad(item.id, false)
this.setEdit(item.id, false)
this.$store.dispatch("saveFile", data);
if (isCreate) {
this.$store.dispatch("forgetFile", item.id);
}
}).catch(({msg}) => {
$A.modalError(msg)
this.$set(item, '_load', false);
this.setLoad(item.id, false)
if (isCreate) {
this.$store.dispatch("forgetFile", item.id);
}
})
},
setEdit(fileId, is) {
let item = this.$store.state.files.find(({id}) => id == fileId)
if (item) {
this.$set(item, '_edit', is);
}
},
setLoad(fileId, is) {
let item = this.$store.state.files.find(({id}) => id == fileId)
if (item) {
this.$set(item, '_load', is);
}
},
onSearchFocus() {
this.$nextTick(() => {
this.$refs.searchInput.focus({
@ -1267,7 +1281,10 @@ export default {
handleProgress(event, file, fileList) {
//
this.uploadIng++;
if (file._uploadIng === undefined) {
file._uploadIng = true;
this.uploadIng++;
}
this.uploadUpdate(fileList);
},

View File

@ -56,7 +56,6 @@ export default {
if (this.userIsAdmin) {
menu.push(...[
{path: 'system', name: '系统设置', divided: true},
{path: 'priority', name: '任务等级'},
])
}
return menu;

View File

@ -0,0 +1,120 @@
<template>
<div class="setting-system-item">
<Form ref="formDatum" label-width="auto" @submit.native.prevent>
<Row class="setting-template">
<Col span="8">{{$L('名称')}}</Col>
<Col span="16">{{$L('项目模板')}}</Col>
</Row>
<Row v-for="(item, key) in formDatum" :key="key" class="setting-template">
<Col span="8">
<Input
v-model="item.name"
:maxlength="20"
:placeholder="$L('请输入名称')"
clearable
@on-clear="delDatum(key)"/>
</Col>
<Col span="16">
<TagInput v-model="item.columns"/>
</Col>
</Row>
<Button type="default" icon="md-add" @click="addDatum">{{$L('添加模板')}}</Button>
</Form>
<div class="setting-footer">
<Button :loading="loadIng > 0" type="primary" @click="submitForm">{{$L('提交')}}</Button>
<Button :loading="loadIng > 0" @click="resetForm" style="margin-left: 8px">{{$L('重置')}}</Button>
</div>
</div>
</template>
<script>
import {mapState} from "vuex";
export default {
name: 'SystemColumnTemplate',
data() {
return {
loadIng: 0,
formDatum: [],
nullDatum: {
'name': '',
'columns': '',
}
}
},
mounted() {
this.systemSetting();
},
computed: {
...mapState(['columnTemplate']),
},
watch: {
columnTemplate: {
handler(data) {
this.formDatum = $A.cloneJSON(data);
if (this.formDatum.length === 0) {
this.addDatum();
}
},
immediate: true,
}
},
methods: {
submitForm() {
this.$refs.formDatum.validate((valid) => {
if (valid) {
this.systemSetting(true);
}
})
},
resetForm() {
this.formDatum = $A.cloneJSON(this.columnTemplate);
},
addDatum() {
this.formDatum.push($A.cloneJSON(this.nullDatum));
},
delDatum(key) {
this.formDatum.splice(key, 1);
if (this.formDatum.length === 0) {
this.addDatum();
}
},
systemSetting(save) {
this.loadIng++;
this.$store.dispatch("call", {
url: 'system/column/template?type=' + (save ? 'save' : 'get'),
method: 'post',
data: {
list: this.formDatum
},
}).then(({data}) => {
if (save) {
$A.messageSuccess('修改成功');
}
this.loadIng--;
this.$store.state.columnTemplate = $A.cloneJSON(data).map(item => {
if ($A.isArray(item.columns)) {
item.columns = item.columns.join(",")
}
return item;
});
}).catch(({msg}) => {
if (save) {
$A.modalError(msg);
}
this.loadIng--;
});
}
}
}
</script>

View File

@ -0,0 +1,29 @@
<template>
<div class="setting-item submit">
<Tabs v-model="tabAction">
<TabPane :label="$L('系统设置')" name="setting">
<SystemSetting/>
</TabPane>
<TabPane :label="$L('任务优先级')" name="taskPriority">
<SystemTaskPriority/>
</TabPane>
<TabPane :label="$L('项目模板')" name="columnTemplate">
<SystemColumnTemplate/>
</TabPane>
</Tabs>
</div>
</template>
<script>
import SystemSetting from "./setting";
import SystemTaskPriority from "./taskPriority";
import SystemColumnTemplate from "./columnTemplate";
export default {
components: {SystemColumnTemplate, SystemTaskPriority, SystemSetting},
data() {
return {
tabAction: 'setting',
}
},
}
</script>

View File

@ -1,5 +1,5 @@
<template>
<div class="setting-item submit">
<div class="setting-system-item">
<Form ref="formDatum" :model="formDatum" label-width="auto" @submit.native.prevent>
<FormItem :label="$L('允许注册')" prop="reg">
<RadioGroup v-model="formDatum.reg">
@ -69,6 +69,8 @@
<script>
export default {
name: 'SystemSetting',
data() {
return {
loadIng: 0,

View File

@ -1,5 +1,5 @@
<template>
<div class="setting-item submit">
<div class="setting-system-item">
<Form ref="formDatum" label-width="auto" @submit.native.prevent>
<Row class="setting-color">
<Col span="12">{{$L('名称')}}</Col>
@ -47,6 +47,7 @@
import {mapState} from "vuex";
export default {
name: 'SystemTaskPriority',
data() {
return {
loadIng: 0,
@ -66,8 +67,6 @@ export default {
this.systemSetting();
},
computed: {
...mapState(['taskPriority']),
},

View File

@ -4,7 +4,7 @@
<Loading v-if="loadIng > 0"/>
<template v-else>
<AceEditor v-if="isCode" v-model="codeContent" :ext="codeExt" class="view-editor" readOnly/>
<OnlyOffice v-else-if="isOffice" v-model="officeContent" :code="officeCode" readOnly/>
<OnlyOffice v-else-if="isOffice" v-model="officeContent" :code="officeCode" :documentKey="documentKey" readOnly/>
<iframe v-else-if="isPreview" class="preview-iframe" :src="previewUrl"/>
<div v-else class="no-support">{{$L('不支持单独查看此消息')}}</div>
</template>
@ -68,6 +68,10 @@ export default {
},
},
computed: {
msgId() {
return $A.runNum(this.$route.params.id);
},
title() {
const {msg} = this.msgDetail;
if (msg && msg.name) {
@ -99,7 +103,7 @@ export default {
return {
id: this.isOffice ? this.msgDetail.id : 0,
type: this.msgDetail.msg.ext,
name: this.title
name: this.title,
}
},
officeCode() {
@ -121,15 +125,14 @@ export default {
},
methods: {
getInfo() {
let msg_id = $A.runNum(this.$route.params.id);
if (msg_id <= 0) {
if (this.msgId <= 0) {
return;
}
this.loadIng++;
this.$store.dispatch("call", {
url: 'dialog/msg/detail',
data: {
msg_id,
msg_id: this.msgId,
},
}).then(({data}) => {
this.loadIng--;
@ -145,6 +148,21 @@ export default {
}
});
});
},
documentKey() {
return new Promise(resolve => {
this.$store.dispatch("call", {
url: 'dialog/msg/detail',
data: {
msg_id: this.msgId,
only_update_at: 'yes'
},
}).then(({data}) => {
resolve($A.Date(data.update_at, true))
}).catch(() => {
resolve(0)
});
});
}
}
}

View File

@ -4,7 +4,7 @@
<Loading v-if="loadIng > 0"/>
<template v-else>
<AceEditor v-if="isCode" v-model="codeContent" :ext="codeExt" class="view-editor" readOnly/>
<OnlyOffice v-else-if="isOffice" v-model="officeContent" :code="officeCode" readOnly/>
<OnlyOffice v-else-if="isOffice" v-model="officeContent" :code="officeCode" :documentKey="documentKey" readOnly/>
<iframe v-else-if="isPreview" class="preview-iframe" :src="previewUrl"/>
<div v-else class="no-support">{{$L('不支持单独查看此消息')}}</div>
</template>
@ -68,6 +68,10 @@ export default {
},
},
computed: {
fileId() {
return $A.runNum(this.$route.params.id);
},
title() {
const {name} = this.fileDetail;
if (name) {
@ -99,7 +103,7 @@ export default {
return {
id: this.isOffice ? this.fileDetail.id : 0,
type: this.fileDetail.ext,
name: this.title
name: this.title,
}
},
officeCode() {
@ -121,15 +125,14 @@ export default {
},
methods: {
getInfo() {
let file_id = $A.runNum(this.$route.params.id);
if (file_id <= 0) {
if (this.fileId <= 0) {
return;
}
this.loadIng++;
this.$store.dispatch("call", {
url: 'project/task/filedetail',
data: {
file_id,
file_id: this.fileId,
},
}).then(({data}) => {
this.loadIng--;
@ -145,6 +148,21 @@ export default {
}
});
});
},
documentKey() {
return new Promise(resolve => {
this.$store.dispatch("call", {
url: 'project/task/filedetail',
data: {
file_id: this.fileId,
only_update_at: 'yes'
},
}).then(({data}) => {
resolve($A.Date(data.update_at, true))
}).catch(() => {
resolve(0)
});
})
}
}
}

View File

@ -49,12 +49,7 @@ export default [
{
name: 'manage-setting-system',
path: 'system',
component: () => import('./pages/manage/setting/system.vue'),
},
{
name: 'manage-setting-priority',
path: 'priority',
component: () => import('./pages/manage/setting/priority.vue'),
component: () => import('./pages/manage/setting/system/index.vue'),
},
]
},

View File

@ -367,10 +367,14 @@ export default {
* 登出打开登录页面
* @param state
* @param dispatch
* @param appendFrom
*/
logout({state, dispatch}) {
logout({state, dispatch}, appendFrom = true) {
dispatch("handleClearCache", {}).then(() => {
const from = ["/", "/login"].includes(window.location.pathname) ? "" : encodeURIComponent(window.location.href);
let from = ["/", "/login"].includes(window.location.pathname) ? "" : encodeURIComponent(window.location.href);
if (appendFrom === false) {
from = null;
}
$A.goForward({name: 'login', query: from ? {from: from} : {}}, true);
});
},
@ -427,11 +431,12 @@ export default {
dispatch("saveFile", file);
});
} else if ($A.isJson(data)) {
let base = {_load: false, _edit: false};
let index = state.files.findIndex(({id}) => id == data.id);
if (index > -1) {
state.files.splice(index, 1, Object.assign({}, state.files[index], data));
state.files.splice(index, 1, Object.assign(base, state.files[index], data));
} else {
state.files.push(data)
state.files.push(Object.assign(base, data))
}
}
},
@ -1623,6 +1628,26 @@ export default {
});
},
/**
* 获取添加项目列表预设数据
* @param state
* @param dispatch
* @returns {Promise<unknown>}
*/
getColumnTemplate({state, dispatch}) {
return new Promise(function (resolve, reject) {
dispatch("call", {
url: 'system/column/template',
}).then(result => {
state.columnTemplate = result.data;
resolve(result)
}).catch(e => {
console.warn(e);
reject(e);
});
});
},
/**
* 保存完成任务临时表
* @param state
@ -2082,8 +2107,9 @@ export default {
}
let dialog = state.cacheDialogs.find(({id}) => id == data.dialog_id);
// 更新对话列表
if (dialog) {
if (dialog && state.cacheUnreads[data.id] === undefined) {
// 新增未读数
state.cacheUnreads[data.id] = true;
dialog.unread++;
}
Store.set('dialogMsgPush', data);

View File

@ -1,4 +1,7 @@
const stateData = {
// 是否桌面端
isDesktop: $A.isDesktop(),
// 浏览器宽度
windowWidth: window.innerWidth,
@ -19,6 +22,7 @@ const stateData = {
// Dialog
cacheDialogs: $A.getStorageArray("cacheDialogs"),
cacheUnreads: {},
// Project
cacheProjects: $A.getStorageArray("cacheProjects"),
@ -78,6 +82,9 @@ const stateData = {
// 任务优先级
taskPriority: [],
// 项目创建列表模板
columnTemplate: [],
// 列表背景色
columnColorList: [
{name: '默认', color: ''},

View File

@ -35,6 +35,11 @@
align-items: center;
margin-top: 14px;
overflow: auto;
&::-webkit-scrollbar {
display: none;
}
> li {
position: relative;
list-style: none;

View File

@ -333,6 +333,7 @@
display: inline-block;
margin-right: 3px;
text-align: center;
cursor: pointer;
&.start {
background-color: rgba(38, 38, 38, 0.05);
border-color: rgba(38, 38, 38, 0.05);
@ -762,6 +763,12 @@
}
}
.task-detail-user-popper {
.ivu-poptip-body-content {
overflow: visible;
}
}
.task-detail-avatar-buttons {
margin-top: 12px;
margin-bottom: 4px;

View File

@ -113,7 +113,8 @@
.ivu-form {
overflow: auto;
}
.setting-color {
.setting-color,
.setting-template {
min-width: 400px;
max-width: 600px;
margin-bottom: 12px;
@ -128,7 +129,6 @@
width: 60px;
flex: auto;
flex-shrink: 0;
max-width: 60px;
}
.ivu-color-picker {
width: 100%;
@ -138,6 +138,17 @@
color: #999999;
}
}
.setting-template {
> div {
flex-shrink: 0;
text-align: left;
&:last-child {
flex: 1;
width: auto;
max-width: none;
}
}
}
.setting-footer {
> button {
height: 34px;
@ -166,6 +177,35 @@
padding: 24px 40px;
overflow: auto;
}
.ivu-tabs {
flex: 1;
padding: 16px 32px 0;
display: flex;
flex-direction: column;
.ivu-tabs-content {
flex: 1;
height: 0;
.ivu-tabs-tabpane {
position: relative;
.setting-system-item {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
flex: 1;
display: flex;
flex-direction: column;
.ivu-form {
padding: 8px 12px;
}
.setting-footer {
margin: 0 -32px;
}
}
}
}
}
.setting-footer {
flex-shrink: 0;
position: static;