pref: 优化任务日志的显示

This commit is contained in:
kuaifan 2022-01-13 00:29:31 +08:00
parent 1df55b78c2
commit 87cdee4fe8
8 changed files with 166 additions and 46 deletions

View File

@ -310,7 +310,9 @@ class ProjectController extends AbstractController
$project = Project::userProject($project_id, true, true);
//
if ($project->name != $name) {
$project->addLog("修改项目名称:{$project->name} => {$name}");
$project->addLog("修改项目名称", [
'change' => [$project->name, $name]
]);
$project->name = $name;
}
if ($project->desc != $desc) {
@ -495,7 +497,7 @@ class ProjectController extends AbstractController
$projectInvite->save();
//
$projectInvite->project->syncDialogUser();
$projectInvite->project->addLog("会员ID" . $user->userid . " 通过邀请链接加入项目");
$projectInvite->project->addLog("通过邀请链接加入项目");
//
$data = $projectInvite->toArray();
$data['already'] = true;
@ -539,7 +541,7 @@ class ProjectController extends AbstractController
'owner' => 1,
]);
$project->syncDialogUser();
$project->addLog("移交项目给会员ID" . $owner_userid);
$project->addLog("移交项目给", ['userid' => $owner_userid]);
});
//
$project->pushMsg('detail');
@ -634,7 +636,7 @@ class ProjectController extends AbstractController
$row = ProjectUser::whereProjectId($project->id)->whereUserid($user->userid)->first();
$row?->exitProject();
$project->syncDialogUser();
$project->addLog("会员ID" . $user->userid . " 退出项目");
$project->addLog("退出项目");
$project->pushMsg('delete', null, $user->userid);
});
return Base::retSuccess('退出成功', ['id' => $project->id]);
@ -1429,23 +1431,27 @@ class ProjectController extends AbstractController
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']));
$record = $projectLog->record;
if ($record['flow'] && is_array($record['flow'])) {
$rawData = $record['flow'];
$newFlowItem = ProjectFlowItem::find(intval($rawData['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']));
return AbstractModel::transaction(function() use ($rawData, $task, $newFlowItem) {
$currentFlowItem = $task->flow_item_id ? ProjectFlowItem::find($task->flow_item_id) : null;
// 更新任务
//
$task->flow_item_id = $newFlowItem->id;
$task->flow_item_name = $newFlowItem->name;
$task->addLog("重置{任务}状态", [
'change' => [$currentFlowItem?->name, $newFlowItem->name]
]);
//
$updateMarking = [];
$task->addLog("重置{任务}状态:{$currentFlowItem?->name} => {$newFlowItem->name}");
$data = array_intersect_key($rawData, array_flip(['complete_at', 'owner', 'assist']));
$task->updateTask($data, $updateMarking);
//
$data = ProjectTask::oneTask($task->id)->toArray();

View File

@ -285,18 +285,23 @@ class Project extends AbstractModel
/**
* 添加项目日志
* @param string $detail
* @param array $record
* @param int $userid
* @return ProjectLog
*/
public function addLog($detail, $userid = 0)
public function addLog($detail, $record = [], $userid = 0)
{
$log = ProjectLog::createInstance([
$array = [
'project_id' => $this->id,
'column_id' => 0,
'task_id' => 0,
'userid' => $userid ?: User::userid(),
'detail' => $detail,
]);
];
if ($record) {
$array['record'] = $record;
}
$log = ProjectLog::createInstance($array);
$log->save();
return $log;
}

View File

@ -472,7 +472,7 @@ class ProjectTask extends AbstractModel
self::addTask($subtask);
}
}
$task->addLog("创建{任务}" . $task->name);
$task->addLog("创建{任务}");
return $task;
});
}
@ -495,8 +495,7 @@ class ProjectTask extends AbstractModel
if ($this->flow_item_id == $data['flow_item_id']) {
throw new ApiException('任务状态未发生改变');
}
$recordData = [
'type' => 'flow',
$flowData = [
'flow_item_id' => $this->flow_item_id,
'flow_item_name' => $this->flow_item_name,
];
@ -526,23 +525,23 @@ class ProjectTask extends AbstractModel
if ($newFlowItem->status == 'end') {
// 判断自动完成
if (!$this->complete_at) {
$recordData['complete_at'] = $this->complete_at;
$flowData['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;
$flowData['complete_at'] = $this->complete_at;
$data['complete_at'] = false;
}
}
if ($newFlowItem->userids) {
// 判断自动添加负责人
$recordData['owner'] = $data['owner'] = $this->taskUser->where('owner', 1)->pluck('userid')->toArray();
$flowData['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();
$flowData['assist'] = $data['assist'] = $this->taskUser->where('owner', 0)->pluck('userid')->toArray();
$data['assist'] = array_merge($data['assist'], $data['owner']);
}
$data['owner'] = $newFlowItem->userids;
@ -557,7 +556,10 @@ class ProjectTask extends AbstractModel
}
$this->flow_item_id = $newFlowItem->id;
$this->flow_item_name = $newFlowItem->status . "|" . $newFlowItem->name;
$this->addLog("修改{任务}状态:{$currentFlowItem?->name} => {$newFlowItem->name}", 0, $recordData);
$this->addLog("修改{任务}状态", [
'flow' => $flowData,
'change' => [$currentFlowItem?->name, $newFlowItem->name]
]);
}
// 状态
if (Arr::exists($data, 'complete_at')) {
@ -584,7 +586,9 @@ class ProjectTask extends AbstractModel
} elseif (mb_strlen($data['name']) > 255) {
throw new ApiException('任务描述最多只能设置255个字');
}
$this->addLog("修改{任务}标题:{$this->name} => {$data['name']}");
$this->addLog("修改{任务}标题", [
'change' => [$this->name, $data['name']]
]);
$this->name = $data['name'];
}
// 负责人
@ -616,12 +620,12 @@ class ProjectTask extends AbstractModel
if ($count == 0 && count($array) == 1 && $array[0] == User::userid()) {
$this->addLog("认领{任务}");
} else {
$this->addLog("修改{任务}负责人" . implode(",", $array));
$this->addLog("修改{任务}负责人", ['userid' => $array]);
}
}
$rows = ProjectTaskUser::whereTaskId($this->id)->whereOwner(1)->whereNotIn('userid', $array)->get();
if ($rows->isNotEmpty()) {
$this->addLog("删除{任务}负责人" . $rows->implode('userid', ','));
$this->addLog("删除{任务}负责人", ['userid' => $rows->implode('userid', ',')]);
foreach ($rows as $row) {
$row->delete();
}
@ -719,11 +723,11 @@ class ProjectTask extends AbstractModel
$array[] = $uid;
}
if ($array) {
$this->addLog("修改{任务}协助人员" . implode(",", $array));
$this->addLog("修改{任务}协助人员", ['userid' => $array]);
}
$rows = ProjectTaskUser::whereTaskId($this->id)->whereOwner(0)->whereNotIn('userid', $array)->get();
if ($rows->isNotEmpty()) {
$this->addLog("删除{任务}协助人员" . $rows->implode('userid', ','));
$this->addLog("删除{任务}协助人员", ['userid' => $rows->implode('userid', ',')]);
foreach ($rows as $row) {
$row->delete();
}
@ -732,7 +736,9 @@ class ProjectTask extends AbstractModel
}
// 背景色
if (Arr::exists($data, 'color') && $this->color != $data['color']) {
$this->addLog("修改{任务}背景色:{$this->color} => {$data['color']}");
$this->addLog("修改{任务}背景色", [
'change' => [$this->color, $data['color']]
]);
$this->color = $data['color'];
}
// 列表
@ -742,7 +748,9 @@ class ProjectTask extends AbstractModel
if (empty($column)) {
throw new ApiException('请选择正确的列表');
}
$this->addLog("修改{任务}列表:{$oldName} => {$column->name}");
$this->addLog("修改{任务}列表", [
'change' => [$oldName, $column->name]
]);
$this->column_id = $column->id;
}
// 内容
@ -892,7 +900,7 @@ class ProjectTask extends AbstractModel
if ($complete_at === null) {
// 标记未完成
$this->complete_at = null;
$this->addLog("{任务}标记未完成" . $this->name);
$this->addLog("{任务}标记未完成");
} else {
// 标记已完成
if ($this->parent_id == 0) {
@ -904,7 +912,7 @@ class ProjectTask extends AbstractModel
throw new ApiException('请先领取任务');
}
$this->complete_at = $complete_at;
$this->addLog("{任务}标记已完成" . $this->name);
$this->addLog("{任务}标记已完成");
}
$this->save();
});
@ -924,21 +932,21 @@ class ProjectTask extends AbstractModel
$this->archived_at = null;
$this->archived_userid = User::userid();
$this->archived_follow = 0;
$this->addLog("任务取消归档" . $this->name);
$this->addLog("任务取消归档");
$this->pushMsg('add', ProjectTask::oneTask($this->id));
} else {
// 归档任务
if ($isAuto === true) {
$logText = "自动任务归档" . $this->name;
$logText = "自动任务归档";
$userid = 0;
} else {
$logText = "任务归档" . $this->name;
$logText = "任务归档";
$userid = User::userid();
}
$this->archived_at = $archived_at;
$this->archived_userid = $userid;
$this->archived_follow = 0;
$this->addLog($logText, $userid);
$this->addLog($logText, [], $userid);
$this->pushMsg('archived');
}
self::whereParentId($this->id)->update([
@ -964,7 +972,7 @@ class ProjectTask extends AbstractModel
$dialog?->deleteDialog();
}
self::whereParentId($this->id)->delete();
$this->addLog("删除{任务}" . $this->name);
$this->addLog("删除{任务}");
$this->delete();
});
if ($pushMsg) {
@ -976,13 +984,13 @@ class ProjectTask extends AbstractModel
/**
* 添加任务日志
* @param string $detail
* @param array $record
* @param int $userid
* @param $record
* @return ProjectLog
*/
public function addLog($detail, $userid = 0, $record = null)
public function addLog($detail, $record = [], $userid = 0)
{
$detail = str_replace("{任务}", $this->parent_id > 0 ? "子任务" : "任务", $detail);
$detail = str_replace("{任务}", $this->parent_id ? "子任务" : "任务", $detail);
$array = [
'project_id' => $this->project_id,
'column_id' => $this->column_id,
@ -990,6 +998,9 @@ class ProjectTask extends AbstractModel
'userid' => $userid ?: User::userid(),
'detail' => $detail,
];
if ($this->parent_id) {
$record['subtitle'] = $this->name;
}
if ($record) {
$array['record'] = $record;
}

View File

@ -13,7 +13,7 @@
</div>
<div class="log-summary">
<span class="log-creator">{{item.user ? item.user.nickname : $L('系统')}}</span>
<span class="log-text">{{$L(item.detail)}}</span>
<ProjectLogDetail class="log-text" :render="logDetail" :item="item"/>
<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>
@ -30,8 +30,12 @@
</template>
<script>
import {VNode} from "vue";
import ProjectLogDetail from "./ProjectLogDetail";
export default {
name: "ProjectLog",
components: {ProjectLogDetail},
props: {
projectId: {
type: Number,
@ -130,21 +134,77 @@ export default {
this.getLists();
},
/**
* 日志详情
* @param h
* @param detail
* @param record
* @returns {*[]}
*/
logDetail(h, {detail, record}) {
let vNode = [h('span', this.$L(detail))];
if ($A.isJson(record)) {
if ($A.isArray(record.change)) {
let [before, now] = record.change
vNode.push(h('span', ': '))
if (before) {
vNode.push(h('span', `${before} => ${now}`))
} else {
vNode.push(h('span', now))
}
}
if (record.userid) {
let userids = $A.isArray(record.userid) ? record.userid : [record.userid]
let userNode = [];
userids.some(userid => {
userNode.push(h('UserAvatar', {
props: {
size: 18,
userid
}
}))
})
if (userNode.length > 0) {
vNode.push(h('div', {
class: 'detail-user'
}, [
h('div', {
class: 'detail-user-wrap'
}, userNode)
]))
}
}
}
return h('span', {
class: 'log-text'
}, vNode)
},
/**
* 可操作事件
* @param id
* @param record
* @returns {*[]}
*/
operationList({id, record}) {
let list = [];
if (!$A.isJson(record)) {
return list
}
if (this.taskId > 0 && record.type === 'flow') {
if (this.taskId > 0 && $A.isJson(record.flow)) {
list.push({
id,
button: '重置',
content: `确定重置为【${record.flow_item_name}】吗?`,
content: `确定重置为【${$A.getMiddle(record.flow.flow_item_name, "|")}】吗?`,
})
}
return list;
},
/**
* 执行操作
* @param item
*/
onOperation(item) {
$A.modalConfirm({
content: item.content,

View File

@ -0,0 +1,11 @@
export default {
name: 'ProjectLogDetail',
functional: true,
props: {
render: Function,
item: Object,
},
render: (h, ctx) => {
return ctx.props.render(h, ctx.props.item);
}
};

View File

@ -2,7 +2,11 @@
<!--子任务-->
<li v-if="ready && taskDetail.parent_id > 0">
<div class="subtask-icon">
<TaskMenu :ref="`taskMenu_${taskDetail.id}`" :task="taskDetail" :load-status="taskDetail.loading === true"/>
<TaskMenu
:ref="`taskMenu_${taskDetail.id}`"
:task="taskDetail"
:load-status="taskDetail.loading === true"
@on-update="getLogLists"/>
</div>
<div v-if="taskDetail.flow_item_name" class="subtask-flow">
<span :class="taskDetail.flow_item_status" @click.stop="openMenu(taskDetail)">{{taskDetail.flow_item_name}}</span>
@ -65,7 +69,13 @@
<div v-else-if="ready" v-show="taskDetail.id > 0" :class="{'task-detail':true, 'open-dialog': hasOpenDialog, 'completed': taskDetail.complete_at}">
<div class="task-info">
<div class="head">
<TaskMenu :ref="`taskMenu_${taskDetail.id}`" :task="taskDetail" class="icon" size="medium" :color-show="false"/>
<TaskMenu
:ref="`taskMenu_${taskDetail.id}`"
:task="taskDetail"
class="icon"
size="medium"
:color-show="false"
@on-update="getLogLists"/>
<div v-if="taskDetail.flow_item_name" class="flow">
<span :class="taskDetail.flow_item_status" @click.stop="openMenu(taskDetail)">{{taskDetail.flow_item_name}}</span>
</div>
@ -105,7 +115,13 @@
<i class="taskfont open" @click="openNewWin">&#xe776;</i>
</ETooltip>
<div class="menu">
<TaskMenu :task="taskDetail" icon="ios-more" completed-icon="ios-more" size="medium" :color-show="false"/>
<TaskMenu
:task="taskDetail"
icon="ios-more"
completed-icon="ios-more"
size="medium"
:color-show="false"
@on-update="getLogLists"/>
</div>
</div>
</div>

View File

@ -233,9 +233,10 @@ export default {
//
this.$store.dispatch("taskUpdate", Object.assign(updata, {
task_id: this.task.id,
})).then(({msg}) => {
})).then(({data, msg}) => {
$A.messageSuccess(msg);
resolve()
this.$emit("on-update", data)
}).catch(({msg}) => {
$A.modalError(msg);
this.$store.dispatch("getTaskOne", this.task.id);

View File

@ -86,7 +86,17 @@
color:rgba(0, 0, 0, 0.85)
}
.log-text {
display: inline-block;
color: rgba(0,0,0,.54);
.detail-user {
display: inline-block;
.detail-user-wrap {
display: flex;
.common-avatar {
margin: 0 2px;
}
}
}
}
.log-operation {
> button {