perf: 优化工作报告列表

This commit is contained in:
kuaifan 2025-03-14 22:44:25 +08:00
parent 79ca1aea02
commit b7d10a4c58
6 changed files with 110 additions and 28 deletions

View File

@ -33,6 +33,7 @@ class ReportController extends AbstractController
* @apiName my
*
* @apiParam {Object} [keys] 搜索条件
* - keys.key: 关键词
* - keys.type: 汇报类型weekly:周报daily:日报
* - keys.created_at: 汇报时间
* @apiParam {Number} [page] 当前页,默认:1
@ -49,6 +50,15 @@ class ReportController extends AbstractController
$builder = Report::with(['receivesUser'])->whereUserid($user->userid);
$keys = Request::input('keys');
if (is_array($keys)) {
if ($keys['key']) {
if (str_contains($keys['key'], '@')) {
$builder->whereHas('sendUser', function ($q2) use ($keys) {
$q2->where("users.email", "LIKE", "%{$keys['key']}%");
});
} else {
$builder->where("title", "LIKE", "%{$keys['key']}%");
}
}
if (in_array($keys['type'], [Report::WEEKLY, Report::DAILY])) {
$builder->whereType($keys['type']);
}
@ -70,6 +80,7 @@ class ReportController extends AbstractController
*
* @apiParam {Object} [keys] 搜索条件
* - keys.key: 关键词
* - keys.department_id: 部门ID
* - keys.type: 汇报类型weekly:周报daily:日报
* - keys.status: 状态unread:未读read:已读
* - keys.created_at: 汇报时间
@ -90,10 +101,19 @@ class ReportController extends AbstractController
$keys = Request::input('keys');
if (is_array($keys)) {
if ($keys['key']) {
$builder->where(function($query) use ($keys) {
$query->whereHas('sendUser', function ($q2) use ($keys) {
if (str_contains($keys['key'], '@')) {
$builder->whereHas('sendUser', function ($q2) use ($keys) {
$q2->where("users.email", "LIKE", "%{$keys['key']}%");
})->orWhere("title", "LIKE", "%{$keys['key']}%");
});
} elseif (Base::isNumber($keys['key'])) {
$builder->where("userid", intval($keys['key']));
} else {
$builder->where("title", "LIKE", "%{$keys['key']}%");
}
}
if ($keys['department_id']) {
$builder->whereHas('sendUser', function ($query) use ($keys) {
$query->where("users.department", "LIKE", "%,{$keys['department_id']},%");
});
}
if (in_array($keys['type'], [Report::WEEKLY, Report::DAILY])) {

View File

@ -662,6 +662,27 @@ import {convertLocalResourcePath} from "../components/Replace/utils";
})
}
})
},
/**
* 提取工作报告中的时间
* @param text
* @returns {*|string}
*/
reportExtractTime(text) {
const regex = /(?:.*?)(?:\[([^\[\]]*)\]\s*)?(?:\[([^\[\]]*)\]\s*)?$/;
const match = text.match(regex);
if (!match) return "";
const secondLast = `${match[1] || ""}`.replace(/^\s*\((.*)\)\s*$/, "$1");
const last = `${match[2] || ""}`.replace(/^\s*\((.*)\)\s*$/, "$1");
if (last && secondLast) {
return `${last} (${secondLast})`;
} else if (last) {
return last;
} else if (secondLast) {
return secondLast;
}
return "";
}
});

View File

@ -296,7 +296,7 @@
v-model="workReportShow"
placement="right"
:size="1200">
<Report v-if="workReportShow" v-model="reportTabs" @on-read="$store.dispatch('getReportUnread', 1000)" />
<Report v-if="workReportShow" v-model="workReportTab" @on-read="$store.dispatch('getReportUnread', 1000)" />
</DrawerOverlay>
<!--查看所有团队-->
@ -435,7 +435,6 @@ export default {
visibleMenu: false,
showMobileMenu: false,
workReportShow: false,
allUserShow: false,
allProjectShow: false,
archivedProjectShow: false,
@ -443,7 +442,8 @@ export default {
natificationReady: false,
notificationManage: null,
reportTabs: "my",
workReportShow: false,
workReportTab: "my",
operateStyles: {},
operateVisible: false,
@ -465,6 +465,7 @@ export default {
emitter.on('createGroup', this.onCreateGroup);
emitter.on('dialogMsgPush', this.addDialogMsg);
emitter.on('approveDetails', this.openApproveDetails);
emitter.on('openReport', this.openReport);
//
document.addEventListener('keydown', this.shortcutEvent);
},
@ -487,6 +488,7 @@ export default {
emitter.off('createGroup', this.onCreateGroup);
emitter.off('dialogMsgPush', this.addDialogMsg);
emitter.off('approveDetails', this.openApproveDetails);
emitter.off('openReport', this.openReport);
//
document.removeEventListener('keydown', this.shortcutEvent);
},
@ -801,10 +803,7 @@ export default {
this.exportApproveShow = true;
return;
case 'workReport':
if (this.reportUnreadNumber > 0) {
this.reportTabs = "receive";
}
this.workReportShow = true;
this.openReport(this.reportUnreadNumber > 0 ? 'receive' : 'my');
return;
case 'version':
emitter.emit('updateNotification', null);
@ -1144,6 +1143,11 @@ export default {
})
},
openReport(tab) {
this.workReportTab = tab;
this.workReportShow = true;
},
handleLongpress(event, el) {
const projectId = $A.getAttr(el, 'data-id')
const projectItem = this.projectLists.find(item => item.id == projectId)

View File

@ -40,11 +40,6 @@
</div>
</div>
<!--工作报告-->
<DrawerOverlay v-model="workReportShow" placement="right" :size="1200">
<Report v-if="workReportShow" v-model="workReportTabs" @on-read="$store.dispatch('getReportUnread', 1000)" />
</DrawerOverlay>
<!--AI-->
<DrawerOverlay v-model="aibotShow" placement="right" :size="720">
<div v-if="aibotShow" class="ivu-modal-wrap-apply">
@ -244,7 +239,6 @@
import {mapState} from "vuex";
import DrawerOverlay from "../../components/DrawerOverlay";
import UserSelect from "../../components/UserSelect";
import Report from "../manage/components/Report";
import SystemAibot from "./setting/components/SystemAibot";
import SystemCheckin from "./setting/components/SystemCheckin";
import Checkin from "./setting/checkin";
@ -259,7 +253,6 @@ export default {
components: {
UserSelect,
DrawerOverlay,
Report,
SystemAibot,
SystemCheckin,
Checkin,
@ -273,9 +266,6 @@ export default {
applyList: [],
applyListTypes: ['base', 'admin'],
//
workReportShow: false,
workReportTabs: "my",
//
aibotList: AIBotList,
aibotShow: false,
aibotSettingShow: false,
@ -421,8 +411,7 @@ export default {
});
break;
case 'report':
this.workReportTabs = area == 'badge' ? 'receive' : 'my';
this.workReportShow = true;
emitter.emit('openReport', area == 'badge' ? 'receive' : 'my');
break;
case 'robot':
this.getAITags();

View File

@ -3,6 +3,14 @@
<div class="search-expand">
<div class="search-container lr">
<ul>
<li>
<div class="search-label">
{{ $L("关键词") }}
</div>
<div class="search-content">
<Input v-model="keys.key" :placeholder="$L('输入关键词搜索')" clearable/>
</div>
</li>
<li>
<div class="search-label">
{{ $L("汇报类型") }}
@ -77,11 +85,20 @@ export default {
return {
loadIng: 0,
columns: [{
title: this.$L("名称"),
title: this.$L("标题"),
key: 'title',
minWidth: 180,
render: (h, {row}) => {
return h('AutoTip', row.title);
const displayTitle = `${row.title || ""}`.replace(/(\[([^\[\]]*)\]\s*){0,2}$/, '');
return h('AutoTip', displayTitle);
}
}, {
title: this.$L("时间"),
key: 'time',
sortable: true,
minWidth: 180,
render: (h, {row}) => {
return h('AutoTip', $A.reportExtractTime(row.title) || '-');
}
}, {
title: this.$L("类型"),

View File

@ -10,6 +10,25 @@
<Input v-model="keys.key" :placeholder="$L('输入关键词搜索')" clearable/>
</div>
</li>
<li>
<div class="search-label">
{{ $L("汇报部门") }}
</div>
<div class="search-content">
<Select
v-model="keys.department_id"
:placeholder="$L('全部')">
<Option value="">{{$L('全部')}}</Option>
<Option
v-for="(item, index) in departmentList"
:value="item.id"
:key="index"
:label="item.chains.join(' - ')">
<div :class="`department-level-name level-${item.level}`">{{ item.name }}</div>
</Option>
</Select>
</div>
</li>
<li>
<div class="search-label">
{{ $L("汇报类型") }}
@ -113,7 +132,8 @@ export default {
sortable: true,
minWidth: 180,
render: (h, {row}) => {
let arr = []
const displayTitle = `${row.title || ""}`.replace(/(\[([^\[\]]*)\]\s*){0,2}$/, '');
const arr = []
const myUser = row.receives_user.find(({userid}) => userid == this.userId)
if (myUser && myUser.pivot.read == 0) {
arr.push(
@ -125,11 +145,11 @@ export default {
flexShrink: 0,
}
}, this.$L("未读")),
h('AutoTip', row.title)
h('AutoTip', displayTitle)
)
} else {
arr.push(
h('AutoTip', row.title)
h('AutoTip', displayTitle)
)
}
return h('div', {
@ -139,6 +159,14 @@ export default {
}
}, arr)
}
}, {
title: this.$L("时间"),
key: 'time',
sortable: true,
minWidth: 180,
render: (h, {row}) => {
return h('AutoTip', $A.reportExtractTime(row.title) || '-');
}
}, {
title: this.$L("类型"),
key: 'type',
@ -209,10 +237,13 @@ export default {
{value: "unread", label: this.$L('仅未读')},
{value: "read", label: this.$L('仅已读')},
],
departmentList: [],
}
},
mounted() {
async mounted() {
this.getLists();
this.departmentList = await this.$store.dispatch("getDepartmentList")
},
watch: {
keyIs(v) {