perf: 优化标签操作日志

This commit is contained in:
kuaifan 2025-07-08 10:41:41 +08:00
parent 5f0fc78f30
commit b01a54437a
5 changed files with 189 additions and 95 deletions

View File

@ -3062,7 +3062,18 @@ class ProjectController extends AbstractController
]); ]);
// 更新标签 // 更新标签
$project->addLog("修改标签", [ $project->addLog("修改标签", [
'change' => [$tag->name . '(' . $tag->color . ')', $data['name'] . '(' . $data['color'] . ')'] 'change' => [
[
'type' => 'tag',
'name' => $tag->name,
'color' => $tag->color
],
[
'type' => 'tag',
'name' => $data['name'],
'color' => $data['color']
]
],
]); ]);
$tag->update($data); $tag->update($data);
}); });
@ -3077,7 +3088,13 @@ class ProjectController extends AbstractController
])->exists()) { ])->exists()) {
return Base::retError('标签已存在'); return Base::retError('标签已存在');
} }
$project->addLog("添加标签: " . $data['name']); $project->addLog("添加标签", [
'change' => [
'type' => 'tag',
'name' => $name,
'color' => $color
]
]);
$tag = ProjectTag::create($data); $tag = ProjectTag::create($data);
} }
return Base::retSuccess('保存成功', $tag); return Base::retSuccess('保存成功', $tag);
@ -3128,7 +3145,13 @@ class ProjectController extends AbstractController
// 删除任务标签 // 删除任务标签
ProjectTaskTag::where($tagWhere)->delete(); ProjectTaskTag::where($tagWhere)->delete();
// 删除标签 // 删除标签
$project->addLog("删除标签: " . $tag->name); $project->addLog("删除标签", [
'change' => [
'type' => 'tag',
'name' => $tag->name,
'color' => $tag->color
],
]);
$tag->delete(); $tag->delete();
return Base::retSuccess('删除成功'); return Base::retSuccess('删除成功');
}); });

View File

@ -68,7 +68,18 @@ class ProjectTaskUser extends AbstractModel
$item->save(); $item->save();
} }
if ($item->projectTask) { if ($item->projectTask) {
$item->projectTask->addLog("移交{任务}身份", ['userid' => [$originalUserid, ' => ', $newUserid]], 0, 1); $item->projectTask->addLog("移交{任务}身份", [
'change' => [
[
'type' => 'user',
'data' => $originalUserid,
],
[
'type' => 'user',
'data' => $newUserid,
]
],
], 0, 1);
if (!in_array($item->task_pid, $tastIds)) { if (!in_array($item->task_pid, $tastIds)) {
$tastIds[] = $item->task_pid; $tastIds[] = $item->task_pid;
$item->projectTask->syncDialogUser(); $item->projectTask->syncDialogUser();

View File

@ -74,7 +74,18 @@ class ProjectUser extends AbstractModel
$item->project->name = "{$name}{$item->project->name}"; $item->project->name = "{$name}{$item->project->name}";
$item->project->save(); $item->project->save();
} }
$item->project->addLog("移交项目身份", ['userid' => [$originalUserid, ' => ', $newUserid]]); $item->project->addLog("移交项目身份", [
'change' => [
[
'type' => 'user',
'data' => $originalUserid
],
[
'type' => 'user',
'data' => $newUserid
],
],
]);
$item->project->syncDialogUser(); $item->project->syncDialogUser();
$projectIds[] = $item->project_id; $projectIds[] = $item->project_id;
} }

View File

@ -176,104 +176,154 @@ export default {
/** /**
* 日志详情 * 日志详情
* @param h * @param h
* @param id
* @param detail * @param detail
* @param record * @param record
* @returns {*[]} * @returns {*[]}
*/ */
logDetail(h, {detail, record}) { logDetail(h, {id, detail, record}) {
let vNode = [h('span', detail)]; const nodes = (nodeData) => {
if ($A.isJson(record)) { const {type, data} = nodeData;
if ($A.isArray(record.change)) { switch (type) {
let [before, now] = record.change case 'tag':
vNode.push(h('span', ': ')) return h('span', {
if (before && before != now) { class: 'change-tags'
vNode.push(h('span', {class:'change-value'}, `${before || '-'}`)) }, [
vNode.push(h('span', ' => ')) h('TaskTag', {
vNode.push(h('span', {class:'change-value'}, `${now || '-'}`)) props: {
} else { tags: [nodeData]
vNode.push(h('span', {class:'change-value'}, now || '-')) }
} })
} ])
if ($A.isArray(record.tags)) {
vNode.push(h('span', { case 'tags':
class: 'change-tags' return h('span', {
}, [ class: 'change-tags'
h('TaskTag', { }, [
props: { h('TaskTag', {
tags: record.tags props: {
tags: data
}
})
])
case 'link':
const {title, url} = data;
return h('a', {
attrs: {
href: $A.mainUrl(url),
target: '_blank'
},
on: {
click: e => {
const path = `/${url}`
if (this.$Electron) {
e.preventDefault()
this.$store.dispatch('openChildWindow', {
name: `project-log-${id}`,
path: path,
force: false,
config: {
title: this.$L(title),
parent: null,
width: Math.min(window.screen.availWidth, 1440),
height: Math.min(window.screen.availHeight, 900),
},
});
} else if (this.$isEEUIApp) {
e.preventDefault()
this.$store.dispatch('openAppChildPage', {
pageType: 'app',
pageTitle: this.$L(title),
url: 'web.js',
params: {
url: $A.urlReplaceHash(path)
},
})
}
}
}
}, this.$L(title))
case 'user':
case 'userid':
const userNode = [];
const userids = $A.isArray(data) ? data : [data];
userids.some(userid => {
if (/^\d+$/.test(userid)) {
userNode.push(h('UserAvatar', {
props: {
size: 18,
userid
}
}))
} else {
userNode.push(h('span', userid))
} }
}) })
])) if (userNode.length > 0) {
} return h('div', {
if ($A.isJson(record.link)) { class: 'detail-user'
const {title, url} = record.link }, [
vNode.push(h('span', ': ')) h('div', {
vNode.push(h('a', { class: 'detail-user-wrap'
attrs: { }, userNode)
href: url, ])
target: '_blank'
},
on: {
click: e => {
e.preventDefault()
const path = `/${url}`
if (this.$Electron) {
this.$store.dispatch('openChildWindow', {
name: `project-log-${record.id}`,
path: path,
force: false,
config: {
title: this.$L(title),
parent: null,
width: Math.min(window.screen.availWidth, 1440),
height: Math.min(window.screen.availHeight, 900),
},
});
} else if (this.$isEEUIApp) {
this.$store.dispatch('openAppChildPage', {
pageType: 'app',
pageTitle: this.$L(title),
url: 'web.js',
params: {
url: $A.urlReplaceHash(path)
},
})
} else {
window.open($A.mainUrl(path.substring(1)))
}
}
} }
}, this.$L(title))) return null
}
if (record.userid) { case 'value':
let userids = $A.isArray(record.userid) ? record.userid : [record.userid] return h('span', {class: 'change-value'}, data || '-')
let userNode = [];
userids.some(userid => { default:
if (/^\d+$/.test(userid)) { return null
userNode.push(h('UserAvatar', {
props: {
size: 18,
userid
}
}))
} else {
userNode.push(h('span', userid))
}
})
if (userNode.length > 0) {
vNode.push(h('div', {
class: 'detail-user'
}, [
h('div', {
class: 'detail-user-wrap'
}, userNode)
]))
}
} }
} }
return h('span', { const vNode = [h('span', detail)];
class: 'log-text' if ($A.isJson(record)) {
}, vNode) let changes = [];
if ($A.isArray(record.tags)) {
changes.push({
'type': 'tags',
'data': record.tags
})
} else if ($A.isJson(record.link)) {
changes.push({
'type': 'link',
'data': record.link
})
} else if (record.userid) {
changes.push({
'type': 'user',
'data': record.userid
})
} else if (record.change) {
if ($A.isArray(record.change)) {
changes.push(...record.change.map(item => {
if ($A.isJson(item)) {
return item
}
return {
type: 'value',
data: item
}
}));
} else if ($A.isJson(record.change)) {
changes.push(record.change);
}
}
if (changes.length > 0) {
const connector = changes.length > 2 ? ', ' : ' => '
vNode.push(h('span', ': '))
changes.forEach((change, index) => {
if (index > 0) {
vNode.push(h('span', connector))
}
vNode.push(nodes(change))
})
}
}
return h('span', { class: 'log-text' }, vNode)
}, },
/** /**

View File

@ -146,7 +146,6 @@
.change-tags { .change-tags {
display: inline-block; display: inline-block;
margin-left: 6px;
.tags-box { .tags-box {
gap: 6px; gap: 6px;
> li { > li {