feat: 任务流转自动负责人支持转让模式

This commit is contained in:
kuaifan 2022-01-11 20:07:58 +08:00
parent b7417f41c5
commit e7ae86e261
11 changed files with 247 additions and 10 deletions

View File

@ -10,7 +10,7 @@ if (!function_exists('asset_main')) {
if (!function_exists('seeders_at')) {
function seeders_at($data)
{
$diff = time() - strtotime("2021-07-01");
$diff = time() - strtotime("2021-07-02");
$time = strtotime($data) + $diff;
return date("Y-m-d H:i:s", $time);
}

View File

@ -1405,6 +1405,60 @@ class ProjectController extends AbstractController
return Base::retSuccess('删除成功', ['id' => $task->id]);
}
/**
* @api {get} api/project/task/resetfromlog 29. 根据日志重置任务
*
* @apiDescription 需要token身份项目、任务负责人
* @apiVersion 1.0.0
* @apiGroup project
* @apiName task__resetfromlog
*
* @apiParam {Number} task_id 任务ID
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function task__resetfromlog()
{
User::auth();
//
$id = intval(Request::input('id'));
//
$projectLog = ProjectLog::find($id);
if (empty($projectLog) || empty($projectLog->task_id)) {
return Base::retError('记录不存在');
}
$record = $projectLog->record;
//
$task = ProjectTask::userTask($projectLog->task_id, null, true);
//
if ($record['type'] == 'flow') {
$newFlowItem = ProjectFlowItem::find(intval($record['flow_item_id']));
if (empty($newFlowItem)) {
return Base::retError('流程不存在或已被删除');
}
return AbstractModel::transaction(function() use ($record, $task, $newFlowItem) {
$data = array_intersect_key($record, array_flip(['complete_at', 'owner', 'assist']));
$currentFlowItem = $task->flow_item_id ? ProjectFlowItem::find($task->flow_item_id) : null;
// 更新任务
$task->flow_item_id = $newFlowItem->id;
$task->flow_item_name = $newFlowItem->name;
$updateMarking = [];
$task->addLog("重置{任务}状态:{$currentFlowItem?->name} => {$newFlowItem->name}");
$task->updateTask($data, $updateMarking);
//
$data = ProjectTask::oneTask($task->id)->toArray();
$data['update_marking'] = $updateMarking ?: json_decode('{}');
$task->pushMsg('update', $data);
//
return Base::retSuccess('重置成功', $data);
});
} else {
return Base::retError('暂不支持此操作');
}
}
/**
* @api {get} api/project/task/flow 29. 任务工作流信息
*
@ -1574,6 +1628,7 @@ class ProjectController extends AbstractController
'sort' => intval($item['sort']),
'turns' => $turns,
'userids' => $userids,
'usertype' => $item['usertype'],
]);
if ($flow) {
$ids[] = $flow->id;

View File

@ -14,6 +14,7 @@ use App\Module\Base;
* @property string|null $status 状态
* @property array $turns 可流转
* @property array $userids 自动负责人ID
* @property string|null $usertype 流转模式
* @property int|null $sort 排序
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
@ -31,6 +32,7 @@ use App\Module\Base;
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereTurns($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereUserids($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereUsertype($value)
* @mixin \Eloquent
*/
class ProjectFlowItem extends AbstractModel

View File

@ -2,6 +2,8 @@
namespace App\Models;
use App\Module\Base;
/**
* App\Models\ProjectLog
*
@ -11,6 +13,7 @@ namespace App\Models;
* @property int|null $task_id 项目ID
* @property int|null $userid 会员ID
* @property string|null $detail 详细信息
* @property string|null $record 记录数据
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \App\Models\User|null $user
@ -22,6 +25,7 @@ namespace App\Models;
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereDetail($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereProjectId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereRecord($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereTaskId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereUserid($value)
@ -30,6 +34,18 @@ namespace App\Models;
class ProjectLog extends AbstractModel
{
/**
* @param $value
* @return array
*/
public function getRecordAttribute($value)
{
if (is_array($value)) {
return $value;
}
return Base::json2array($value);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/

View File

@ -495,6 +495,11 @@ class ProjectTask extends AbstractModel
if ($this->flow_item_id == $data['flow_item_id']) {
throw new ApiException('任务状态未发生改变');
}
$recordData = [
'type' => 'flow',
'flow_item_id' => $this->flow_item_id,
'flow_item_name' => $this->flow_item_name,
];
$currentFlowItem = null;
$newFlowItem = ProjectFlowItem::whereProjectId($this->project_id)->find(intval($data['flow_item_id']));
if (empty($newFlowItem) || empty($newFlowItem->projectFlow)) {
@ -510,24 +515,38 @@ class ProjectTask extends AbstractModel
if ($newFlowItem->status == 'end') {
// 判断自动完成
if (!$this->complete_at) {
$recordData['complete_at'] = $this->complete_at;
$data['complete_at'] = date("Y-m-d H:i");
}
} else {
// 判断自动打开
if ($this->complete_at) {
$recordData['complete_at'] = $this->complete_at;
$data['complete_at'] = false;
}
}
if ($newFlowItem->userids) {
// 判断自动添加负责人
if (!Arr::exists($data, 'owner')) {
$data['owner'] = $this->taskUser->pluck('userid')->toArray();
$recordData['owner'] = $data['owner'] = $this->taskUser->where('owner', 1)->pluck('userid')->toArray();
if ($newFlowItem->usertype == "replace") {
// 流转模式
if ($this->parent_id === 0) {
$recordData['assist'] = $data['assist'] = $this->taskUser->where('owner', 0)->pluck('userid')->toArray();
$data['assist'] = array_merge($data['assist'], $data['owner']);
}
$data['owner'] = $newFlowItem->userids;
} else {
// 添加模式
$data['owner'] = array_merge($data['owner'], $newFlowItem->userids);
}
$data['owner'] = array_values(array_unique($data['owner']));
if (isset($data['assist'])) {
$data['assist'] = array_values(array_unique(array_diff($data['assist'], $data['owner'])));
}
$data['owner'] = array_values(array_unique(array_merge($data['owner'], $newFlowItem->userids)));
}
$this->flow_item_id = $newFlowItem->id;
$this->flow_item_name = $newFlowItem->status . "|" . $newFlowItem->name;
$this->addLog("修改{任务}状态:{$currentFlowItem?->name} => {$newFlowItem->name}");
$this->addLog("修改{任务}状态:{$currentFlowItem?->name} => {$newFlowItem->name}", 0, $recordData);
}
// 状态
if (Arr::exists($data, 'complete_at')) {
@ -559,7 +578,7 @@ class ProjectTask extends AbstractModel
}
// 负责人
if (Arr::exists($data, 'owner')) {
$count = $this->taskUser->count();
$count = $this->taskUser->where('owner', 1)->count();
$array = [];
$owner = is_array($data['owner']) ? $data['owner'] : [$data['owner']];
if (count($owner) > 10) {
@ -947,18 +966,23 @@ class ProjectTask extends AbstractModel
* 添加任务日志
* @param string $detail
* @param int $userid
* @param $record
* @return ProjectLog
*/
public function addLog($detail, $userid = 0)
public function addLog($detail, $userid = 0, $record = null)
{
$detail = str_replace("{任务}", $this->parent_id > 0 ? "子任务" : "任务", $detail);
$log = ProjectLog::createInstance([
$array = [
'project_id' => $this->project_id,
'column_id' => $this->column_id,
'task_id' => $this->parent_id ?: $this->id,
'userid' => $userid ?: User::userid(),
'detail' => $detail,
]);
];
if ($record) {
$array['record'] = $record;
}
$log = ProjectLog::createInstance($array);
$log->save();
return $log;
}

View File

@ -55,6 +55,7 @@ use Carbon\Carbon;
* @method static \Illuminate\Database\Eloquent\Builder|User whereUserid($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereUserimg($value)
* @mixin \Eloquent
* @method static \Database\Factories\UserFactory factory(...$parameters)
*/
class User extends AbstractModel
{

View File

@ -0,0 +1,42 @@
<?php
use App\Models\ProjectFlowItem;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ProjectFlowItemsAddUsertype extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$isAdd = false;
Schema::table('project_flow_items', function (Blueprint $table) use (&$isAdd) {
if (!Schema::hasColumn('project_flow_items', 'usertype')) {
$isAdd = true;
$table->string('usertype', 10)->nullable()->default('')->after('userids')->comment('流转模式');
}
});
if ($isAdd) {
ProjectFlowItem::where("usertype", "")->update([
'usertype' => 'add',
]);
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('project_flow_items', function (Blueprint $table) {
$table->dropColumn("usertype");
});
}
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ProjectLogsAddRecord extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('project_logs', function (Blueprint $table) {
if (!Schema::hasColumn('project_logs', 'record')) {
$table->text('record')->nullable()->after('detail')->comment('记录数据');
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('project_logs', function (Blueprint $table) {
$table->dropColumn("record");
});
}
}

View File

@ -14,6 +14,9 @@
<div class="log-summary">
<span class="log-creator">{{item.user ? item.user.nickname : $L('系统')}}</span>
<span class="log-text">{{$L(item.detail)}}</span>
<span v-if="operationList(item).length > 0" class="log-operation">
<Button v-for="(op, oi) in operationList(item)" :key="oi" size="small" @click="onOperation(op)">{{op.button}}</Button>
</span>
<span class="log-time">{{item.time.ymd}} {{item.time.segment}} {{item.time.hi}}</span></div>
</TimelineItem>
</Timeline>
@ -123,6 +126,44 @@ export default {
this.listPage++;
this.getLists();
},
operationList({id, record}) {
let list = [];
if (!$A.isJson(record)) {
return list
}
if (this.taskId > 0 && record.type === 'flow') {
list.push({
id,
button: '重置',
content: `确定重置为【${record.flow_item_name}】吗?`,
})
}
return list;
},
onOperation(item) {
$A.modalConfirm({
content: item.content,
loading: true,
onOk: () => {
this.$store.dispatch("call", {
url: 'project/task/resetfromlog',
data: {
id: item.id
}
}).then(({data, msg}) => {
$A.messageSuccess(msg);
this.$Modal.remove();
this.$store.dispatch("saveTask", data);
this.getLists(true);
}).catch(({msg}) => {
$A.modalError(msg, 301);
this.$Modal.remove();
});
}
});
}
}
}
</script>

View File

@ -144,7 +144,14 @@
<Form :model="userData" label-width="auto" @submit.native.prevent>
<FormItem prop="userids" :label="userData.name">
<UserInput v-if="userShow" v-model="userData.userids" :project-id="projectId" :multiple-max="5" :placeholder="$L('选择成员')"/>
<div class="form-tip">{{$L('任务流转到此流程时自动添加负责人')}}</div>
</FormItem>
<FormItem prop="usertype" :label="$L('流转模式')">
<RadioGroup v-model="userData.usertype">
<Radio label="add">{{$L('添加模式')}}</Radio>
<Radio label="replace">{{$L('流转模式')}}</Radio>
</RadioGroup>
<div v-if="userData.usertype=='replace'" class="form-tip">{{$L('流转到此流程时改变负责人原本的负责人移至协助人员')}}</div>
<div v-else class="form-tip">{{$L('流转到此流程时添加负责人。')}}</div>
</FormItem>
</Form>
<div slot="footer" class="adaption">
@ -259,6 +266,7 @@ export default {
"status": "start",
"turns": [-10, -11, -12, -13],
"userids": [],
"usertype": 'add',
},
{
"id": -11,
@ -266,6 +274,7 @@ export default {
"status": "progress",
"turns": [-10, -11, -12, -13],
"userids": [],
"usertype": 'add',
},
{
"id": -12,
@ -273,6 +282,7 @@ export default {
"status": "end",
"turns": [-10, -11, -12, -13],
"userids": [],
"usertype": 'add',
},
{
"id": -13,
@ -280,6 +290,7 @@ export default {
"status": "end",
"turns": [-10, -11, -12, -13],
"userids": [],
"usertype": 'add',
}
]
})
@ -331,6 +342,7 @@ export default {
this.$set(this.userData, 'id', item.id);
this.$set(this.userData, 'name', item.name);
this.$set(this.userData, 'userids', item.userids);
this.$set(this.userData, 'usertype', item.usertype);
this.userShow = true;
break;
@ -350,6 +362,7 @@ export default {
let item = data.project_flow_item.find(item => item.id == this.userData.id)
if (item) {
this.$set(item, 'userids', this.userData.userids)
this.$set(item, 'usertype', this.userData.usertype)
}
})
},
@ -395,6 +408,7 @@ export default {
status: 'end',
turns,
userids: [],
usertype: 'add',
})
data.project_flow_item.some(item => {
item.turns.push(id)

View File

@ -88,6 +88,14 @@
.log-text {
color: rgba(0,0,0,.54);
}
.log-operation {
> button {
font-size: 12px;
}
> button + button {
margin-left: 4px;
}
}
.log-time {
color: rgba(0,0,0,.3);
font-size: 12px;