优化日志

This commit is contained in:
kuaifan 2022-01-13 09:00:39 +08:00
parent a3e0d89eb0
commit 75a12fc6f5
6 changed files with 127 additions and 54 deletions

View File

@ -1749,7 +1749,7 @@ class ProjectController extends AbstractController
$project_id = intval(Request::input('project_id')); $project_id = intval(Request::input('project_id'));
$task_id = intval(Request::input('task_id')); $task_id = intval(Request::input('task_id'));
// //
$builder = ProjectLog::with(['user']); $builder = ProjectLog::with(['projectTask:id,name']);
if ($task_id > 0) { if ($task_id > 0) {
$task = ProjectTask::userTask($task_id); $task = ProjectTask::userTask($task_id);
$builder->whereTaskId($task->id); $builder->whereTaskId($task->id);

View File

@ -13,9 +13,10 @@ use App\Module\Base;
* @property int|null $task_id 项目ID * @property int|null $task_id 项目ID
* @property int|null $userid 会员ID * @property int|null $userid 会员ID
* @property string|null $detail 详细信息 * @property string|null $detail 详细信息
* @property string|null $record 记录数据 * @property array $record 记录数据
* @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \App\Models\ProjectTask|null $projectTask
* @property-read \App\Models\User|null $user * @property-read \App\Models\User|null $user
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|ProjectLog newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog newQuery() * @method static \Illuminate\Database\Eloquent\Builder|ProjectLog newQuery()
@ -54,4 +55,12 @@ class ProjectLog extends AbstractModel
return $this->hasOne(User::class, 'userid', 'userid'); return $this->hasOne(User::class, 'userid', 'userid');
} }
/**
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function projectTask(): \Illuminate\Database\Eloquent\Relations\HasOne
{
return $this->hasOne(ProjectTask::class, 'id', 'task_id');
}
} }

View File

@ -897,7 +897,7 @@ class ProjectTask extends AbstractModel
if ($complete_at === null) { if ($complete_at === null) {
// 标记未完成 // 标记未完成
$this->complete_at = null; $this->complete_at = null;
$this->addLog("{任务}标记未完成"); $this->addLog("标记{任务}未完成");
} else { } else {
// 标记已完成 // 标记已完成
if ($this->parent_id == 0) { if ($this->parent_id == 0) {
@ -909,7 +909,7 @@ class ProjectTask extends AbstractModel
throw new ApiException('请先领取任务'); throw new ApiException('请先领取任务');
} }
$this->complete_at = $complete_at; $this->complete_at = $complete_at;
$this->addLog("{任务}标记已完成"); $this->addLog("标记{任务}已完成");
} }
$this->save(); $this->save();
}); });

View File

@ -296,7 +296,7 @@ class ProjectLogsTableSeeder extends Seeder
'column_id' => 6, 'column_id' => 6,
'task_id' => 8, 'task_id' => 8,
'userid' => 1, 'userid' => 1,
'detail' => '任务标记已完成:官网项目一期', 'detail' => '标记任务已完成:官网项目一期',
'created_at' => seeders_at('2021-07-01 10:53:47'), 'created_at' => seeders_at('2021-07-01 10:53:47'),
'updated_at' => seeders_at('2021-07-01 10:53:47'), 'updated_at' => seeders_at('2021-07-01 10:53:47'),
), ),
@ -2998,7 +2998,7 @@ class ProjectLogsTableSeeder extends Seeder
'column_id' => 27, 'column_id' => 27,
'task_id' => 77, 'task_id' => 77,
'userid' => 1, 'userid' => 1,
'detail' => '任务标记已完成:🚴 里程碑 1 需求评审完成,资源准备到位', 'detail' => '标记任务已完成:🚴 里程碑 1 需求评审完成,资源准备到位',
'created_at' => seeders_at('2021-07-01 15:39:46'), 'created_at' => seeders_at('2021-07-01 15:39:46'),
'updated_at' => seeders_at('2021-07-01 15:39:46'), 'updated_at' => seeders_at('2021-07-01 15:39:46'),
), ),
@ -3229,7 +3229,7 @@ class ProjectLogsTableSeeder extends Seeder
'column_id' => 32, 'column_id' => 32,
'task_id' => 85, 'task_id' => 85,
'userid' => 1, 'userid' => 1,
'detail' => '子任务标记已完成:首页', 'detail' => '子标记任务已完成:首页',
'created_at' => seeders_at('2021-07-01 16:17:30'), 'created_at' => seeders_at('2021-07-01 16:17:30'),
'updated_at' => seeders_at('2021-07-01 16:17:30'), 'updated_at' => seeders_at('2021-07-01 16:17:30'),
), ),
@ -3240,7 +3240,7 @@ class ProjectLogsTableSeeder extends Seeder
'column_id' => 32, 'column_id' => 32,
'task_id' => 85, 'task_id' => 85,
'userid' => 1, 'userid' => 1,
'detail' => '子任务标记已完成:公司介绍', 'detail' => '子标记任务已完成:公司介绍',
'created_at' => seeders_at('2021-07-01 16:17:31'), 'created_at' => seeders_at('2021-07-01 16:17:31'),
'updated_at' => seeders_at('2021-07-01 16:17:31'), 'updated_at' => seeders_at('2021-07-01 16:17:31'),
), ),
@ -3251,7 +3251,7 @@ class ProjectLogsTableSeeder extends Seeder
'column_id' => 32, 'column_id' => 32,
'task_id' => 85, 'task_id' => 85,
'userid' => 1, 'userid' => 1,
'detail' => '子任务标记已完成:新闻动态', 'detail' => '子标记任务已完成:新闻动态',
'created_at' => seeders_at('2021-07-01 16:17:32'), 'created_at' => seeders_at('2021-07-01 16:17:32'),
'updated_at' => seeders_at('2021-07-01 16:17:32'), 'updated_at' => seeders_at('2021-07-01 16:17:32'),
), ),
@ -3262,7 +3262,7 @@ class ProjectLogsTableSeeder extends Seeder
'column_id' => 32, 'column_id' => 32,
'task_id' => 85, 'task_id' => 85,
'userid' => 1, 'userid' => 1,
'detail' => '子任务标记已完成:产品介绍', 'detail' => '子标记任务已完成:产品介绍',
'created_at' => seeders_at('2021-07-01 16:17:34'), 'created_at' => seeders_at('2021-07-01 16:17:34'),
'updated_at' => seeders_at('2021-07-01 16:17:34'), 'updated_at' => seeders_at('2021-07-01 16:17:34'),
), ),
@ -3273,7 +3273,7 @@ class ProjectLogsTableSeeder extends Seeder
'column_id' => 32, 'column_id' => 32,
'task_id' => 85, 'task_id' => 85,
'userid' => 1, 'userid' => 1,
'detail' => '子任务标记已完成:案例展示', 'detail' => '子标记任务已完成:案例展示',
'created_at' => seeders_at('2021-07-01 16:17:35'), 'created_at' => seeders_at('2021-07-01 16:17:35'),
'updated_at' => seeders_at('2021-07-01 16:17:35'), 'updated_at' => seeders_at('2021-07-01 16:17:35'),
), ),
@ -3284,7 +3284,7 @@ class ProjectLogsTableSeeder extends Seeder
'column_id' => 32, 'column_id' => 32,
'task_id' => 85, 'task_id' => 85,
'userid' => 1, 'userid' => 1,
'detail' => '子任务标记已完成:联系我们', 'detail' => '子标记任务已完成:联系我们',
'created_at' => seeders_at('2021-07-01 16:17:36'), 'created_at' => seeders_at('2021-07-01 16:17:36'),
'updated_at' => seeders_at('2021-07-01 16:17:36'), 'updated_at' => seeders_at('2021-07-01 16:17:36'),
), ),
@ -3295,7 +3295,7 @@ class ProjectLogsTableSeeder extends Seeder
'column_id' => 32, 'column_id' => 32,
'task_id' => 85, 'task_id' => 85,
'userid' => 1, 'userid' => 1,
'detail' => '任务标记已完成:产品官网设计', 'detail' => '标记任务已完成:产品官网设计',
'created_at' => seeders_at('2021-07-01 16:17:37'), 'created_at' => seeders_at('2021-07-01 16:17:37'),
'updated_at' => seeders_at('2021-07-01 16:17:37'), 'updated_at' => seeders_at('2021-07-01 16:17:37'),
), ),
@ -3306,7 +3306,7 @@ class ProjectLogsTableSeeder extends Seeder
'column_id' => 32, 'column_id' => 32,
'task_id' => 85, 'task_id' => 85,
'userid' => 1, 'userid' => 1,
'detail' => '子任务标记未完成:联系我们', 'detail' => '标记子任务未完成:联系我们',
'created_at' => seeders_at('2021-07-01 16:17:41'), 'created_at' => seeders_at('2021-07-01 16:17:41'),
'updated_at' => seeders_at('2021-07-01 16:17:41'), 'updated_at' => seeders_at('2021-07-01 16:17:41'),
), ),
@ -3317,7 +3317,7 @@ class ProjectLogsTableSeeder extends Seeder
'column_id' => 32, 'column_id' => 32,
'task_id' => 85, 'task_id' => 85,
'userid' => 1, 'userid' => 1,
'detail' => '任务标记未完成:产品官网设计', 'detail' => '标记任务未完成:产品官网设计',
'created_at' => seeders_at('2021-07-01 16:17:44'), 'created_at' => seeders_at('2021-07-01 16:17:44'),
'updated_at' => seeders_at('2021-07-01 16:17:44'), 'updated_at' => seeders_at('2021-07-01 16:17:44'),
), ),

View File

@ -2,22 +2,25 @@
<div :class="['project-log', taskId == 0 ? 'is-drawer' : '']"> <div :class="['project-log', taskId == 0 ? 'is-drawer' : '']">
<div class="log-title">{{$L('项目动态')}}</div> <div class="log-title">{{$L('项目动态')}}</div>
<ul class="logs-activity"> <ul class="logs-activity">
<li v-for="items in lists"> <li v-for="itemA in lists">
<div class="logs-date">{{logDate(items)}}</div> <div class="logs-date">{{logDate(itemA)}}</div>
<div class="logs-section"> <div class="logs-section">
<Timeline> <Timeline>
<TimelineItem v-for="(item, index) in items.lists" :key="index"> <TimelineItem v-for="(itemB, index) in itemA.lists" :key="index">
<div slot="dot" class="logs-dot"> <div slot="dot" class="logs-dot">
<UserAvatar v-if="item.userid" :userid="item.userid" :size="18"/> <UserAvatar v-if="itemB.userid" :userid="itemB.userid" :size="18" showName/>
<EAvatar v-else :size="18">A</EAvatar> <div v-else class="avatar-wrapper common-avatar">
<EAvatar :size="18">A</EAvatar>
<div class="avatar-name auto">{{$L('系统')}}</div>
</div> </div>
<div class="log-summary"> </div>
<span class="log-creator">{{item.user ? item.user.nickname : $L('系统')}}</span> <div v-for="log in itemB.lists" class="log-summary">
<ProjectLogDetail class="log-text" :render="logDetail" :item="item"/> <ProjectLogDetail :render="logDetail" :item="log"/>
<span v-if="operationList(item).length > 0" class="log-operation"> <span v-if="operationList(log).length > 0" class="log-operation">
<Button v-for="(op, oi) in operationList(item)" :key="oi" size="small" @click="onOperation(op)">{{op.button}}</Button> <Button v-for="(op, oi) in operationList(log)" :key="oi" size="small" @click="onOperation(op)">{{op.button}}</Button>
</span> </span>
<span class="log-time">{{item.time.ymd}} {{item.time.segment}} {{item.time.hi}}</span></div> <span class="log-time">{{log.time.ymd}} {{log.time.segment}} {{log.time.hi}}</span>
</div>
</TimelineItem> </TimelineItem>
</Timeline> </Timeline>
</div> </div>
@ -30,7 +33,6 @@
</template> </template>
<script> <script>
import {VNode} from "vue";
import ProjectLogDetail from "./ProjectLogDetail"; import ProjectLogDetail from "./ProjectLogDetail";
export default { export default {
@ -50,7 +52,7 @@ export default {
return { return {
loadIng: 0, loadIng: 0,
lists: {}, lists: [],
listPage: 1, listPage: 1,
hasMorePages: false, hasMorePages: false,
totalNum: -1, totalNum: -1,
@ -67,11 +69,11 @@ export default {
watch: { watch: {
projectId() { projectId() {
this.lists = {}; this.lists = [];
this.getLists(true); this.getLists(true);
}, },
taskId() { taskId() {
this.lists = {}; this.lists = [];
this.getLists(true); this.getLists(true);
}, },
loadIng(num) { loadIng(num) {
@ -80,9 +82,9 @@ export default {
}, },
methods: { methods: {
logDate(items) { logDate(itemA) {
let md = $A.formatDate("m-d"); let md = $A.formatDate("m-d");
return md == items.ymd ? (items.ymd + ' ' + this.$L('今天')) : items.key; return md == itemA.ymd ? (itemA.ymd + ' ' + this.$L('今天')) : itemA.key;
}, },
getLists(resetLoad) { getLists(resetLoad) {
@ -101,25 +103,38 @@ export default {
}).then(({data}) => { }).then(({data}) => {
this.loadIng--; this.loadIng--;
if (resetLoad === true) { if (resetLoad === true) {
this.lists = {}; this.lists = [];
} }
data.data.forEach((item) => { data.data.some(log => {
let time = item.time; let tmpTime = log.time;
let key = time.ymd + " " + time.week; let tmpKey = tmpTime.ymd + " " + tmpTime.week;
if (typeof this.lists[key] !== "object") { let itemA = this.lists.find(({key}) => key == tmpKey)
this.$set(this.lists, key, { if (itemA) {
key: key, let itemB = itemA.lists.find(({userid}) => userid == log.userid)
ymd: time.ymd, if (itemB) {
lists: [], itemB.lists.push(log)
}); } else {
itemA.lists.push({
userid: log.userid,
lists: [log]
})
} }
this.lists[key].lists.push(item); } else {
}); this.lists.push({
key: tmpKey,
ymd: log.ymd,
lists: [{
userid: log.userid,
lists: [log]
}]
})
}
})
this.hasMorePages = data.current_page < data.last_page; this.hasMorePages = data.current_page < data.last_page;
this.totalNum = data.total; this.totalNum = data.total;
}).catch(() => { }).catch(() => {
this.loadIng--; this.loadIng--;
this.lists = {}; this.lists = [];
this.hasMorePages = false; this.hasMorePages = false;
this.totalNum = 0; this.totalNum = 0;
}); });

View File

@ -2,6 +2,7 @@
.log-title { .log-title {
display: none; display: none;
} }
&.is-drawer { &.is-drawer {
position: absolute; position: absolute;
top: 0; top: 0;
@ -10,6 +11,7 @@
bottom: 0; bottom: 0;
padding: 20px; padding: 20px;
overflow: auto; overflow: auto;
.log-title { .log-title {
color: #333333; color: #333333;
font-size: 20px; font-size: 20px;
@ -18,96 +20,143 @@
margin-bottom: 24px; margin-bottom: 24px;
} }
} }
.logs-activity { .logs-activity {
position: relative; position: relative;
word-break: break-all; word-break: break-all;
padding: 12px 12px; padding: 12px 12px;
> li { > li {
list-style: none; list-style: none;
padding-top: 0; padding-top: 0;
&.logs-loading, &.logs-loading,
&.logs-more, &.logs-more,
&.logs-none { &.logs-none {
height: 22px; height: 22px;
line-height: 22px; line-height: 22px;
} }
&.logs-loading { &.logs-loading {
display: flex; display: flex;
.common-loading { .common-loading {
margin: 0; margin: 0;
} }
} }
&.logs-more { &.logs-more {
cursor: pointer; cursor: pointer;
&:hover { &:hover {
color: #048be0; color: #048be0;
} }
} }
&.logs-none { &.logs-none {
cursor: pointer; cursor: pointer;
color: #bbbbbb; color: #bbbbbb;
} }
.logs-date { .logs-date {
color: rgba(0, 0, 0, .36); color: rgba(0, 0, 0, .36);
padding-bottom: 14px; padding-bottom: 14px;
} }
.logs-section { .logs-section {
margin: 4px; margin: 4px;
.ivu-timeline { .ivu-timeline {
> li { > li {
padding-bottom: 8px; padding-bottom: 8px;
&:last-child { &:last-child {
padding-bottom: 0; padding-bottom: 0;
} }
.ivu-timeline-item-head-custom { .ivu-timeline-item-head-custom {
position: static;
left: auto;
margin-top: 8px; margin-top: 8px;
margin-left: -13px;
margin-right: 6px;
width: auto;
min-width: 40px;
}
.ivu-timeline-item-content {
padding-left: 20px;
margin-top: -5px;
} }
} }
} }
} }
.logs-dot { .logs-dot {
width: 18px; width: auto;
height: 18px; height: 18px;
margin-left: 10px; margin-left: 10px;
.avatar-box { display: flex;
> em {
transform-origin: bottom right; .avatar-name {
&.auto {
color: #9599a1;
} }
} }
} }
.log-summary { .log-summary {
position: relative;
padding: 4px 0 4px 12px;
&:before {
content: "";
position: absolute;
top: 11px;
left: 0;
width: 5px;
height: 5px;
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.4);
}
> span, > span,
> a { > a {
padding-right: 6px; padding-right: 6px;
word-wrap: break-word; word-wrap: break-word;
word-break: break-word; word-break: break-word;
} }
.log-creator {
color:rgba(0, 0, 0, 0.85)
}
.log-text { .log-text {
display: inline-block; display: inline-block;
color: rgba(0,0,0,.54); color: rgba(0, 0, 0, .5);
.detail-user { .detail-user {
display: inline-block; display: inline-block;
vertical-align: top;
.detail-user-wrap { .detail-user-wrap {
display: flex; display: flex;
.common-avatar { .common-avatar {
margin: 0 2px; margin: 0 2px;
} }
} }
} }
} }
.log-operation { .log-operation {
> button { > button {
font-size: 12px; font-size: 12px;
} }
> button + button { > button + button {
margin-left: 4px; margin-left: 4px;
} }
} }
.log-time { .log-time {
color: rgba(0,0,0,.3); color: rgba(0, 0, 0, .3);
font-size: 12px; font-size: 12px;
} }
} }