fix(工作报告、我的绩效、产品/项目、消息通知): 修复已知的一些问题。

This commit is contained in:
dk
2026-06-28 14:04:28 +08:00
parent a4884035cd
commit 499f2115b2
10 changed files with 189 additions and 58 deletions

View File

@@ -3,6 +3,7 @@ import { computed, ref } from 'vue';
import dayjs from 'dayjs';
import { fetchRemindTeamReport } from '@/service/api';
import { formatIsoWeekRangeLabel } from '../utils';
import { formatWeeklyPeriodLabel } from '../types';
defineOptions({ name: 'TeamReportSummary' });
@@ -26,7 +27,7 @@ const emit = defineEmits<{
}>();
const remindingAll = ref(false);
const remindingUserId = ref('');
const remindingItemKey = ref('');
const canRemind = computed(() => props.periodKeys.length > 0);
function formatSummaryPeriodLabel() {
@@ -57,22 +58,54 @@ function formatSummaryPeriodLabel() {
const displayPeriodLabel = computed(() => formatSummaryPeriodLabel());
const cards = computed(() => [
{ label: '应填数', value: props.summary?.totalShouldSubmit ?? 0 },
{ label: '已提交', value: props.summary?.submittedCount ?? 0 },
{ label: '提交', value: props.summary?.unsubmittedCount ?? 0, key: 'unsubmitted' as const },
{ label: '待审批', value: props.summary?.pendingApprovalCount ?? 0 }
{ label: '应填报告数', value: props.summary?.expectedReportCount ?? 0 },
{ label: '已提交报告数', value: props.summary?.submittedReportCount ?? 0 },
{ label: '提交报告数', value: props.summary?.unsubmittedReportCount ?? 0, key: 'unsubmitted' as const },
{ label: '待审批报告数', value: props.summary?.pendingApprovalReportCount ?? 0 }
]);
function getUnsubmittedReportSecondaryText(item: Api.WorkReport.Common.TeamReportUnsubmittedReport) {
if (props.reportType === 'project') {
return item.projectName ? `${item.projectName} · ${item.periodLabel}` : item.periodLabel;
}
if (props.reportType === 'weekly') {
const weeklyPeriodMatch = item.periodKey.match(/^weekly-(\d{4}-\d{2}-\d{2})-(\d{4}-\d{2}-\d{2})$/u);
if (weeklyPeriodMatch) {
return formatWeeklyPeriodLabel(weeklyPeriodMatch[1], weeklyPeriodMatch[2], item.periodLabel);
}
const weeklyRangeMatch = item.periodLabel.match(/^(\d{4}-\d{2}-\d{2})\s*至\s*(\d{4}-\d{2}-\d{2})$/u);
if (weeklyRangeMatch) {
return formatWeeklyPeriodLabel(weeklyRangeMatch[1], weeklyRangeMatch[2], item.periodLabel);
}
return formatWeeklyPeriodLabel(undefined, undefined, item.periodLabel);
}
return item.periodLabel;
}
function getUnsubmittedReportKey(item: Api.WorkReport.Common.TeamReportUnsubmittedReport) {
return `${item.userId}-${item.projectId || 'none'}-${item.periodKey}`;
}
function getSingleRemindSuccessText(remindedCount: number, preciseProjectReminder: boolean) {
if (preciseProjectReminder) {
return `已发送 ${remindedCount} 条催办提醒`;
}
return `已催办 ${remindedCount}`;
}
async function handleRemind(userIds?: string[]) {
if (!props.periodKeys.length) return;
const targetUserId = userIds?.length === 1 ? userIds[0] : '';
const isSingleUserReminder = userIds?.length === 1;
if (targetUserId) {
remindingUserId.value = targetUserId;
} else {
remindingAll.value = true;
}
remindingAll.value = true;
const results = await Promise.all(
props.periodKeys.map(periodKey =>
@@ -84,10 +117,7 @@ async function handleRemind(userIds?: string[]) {
)
);
if (!targetUserId) {
remindingAll.value = false;
}
remindingUserId.value = '';
remindingAll.value = false;
const remindedCount = results.reduce((total, result) => {
if (result.error) return total;
@@ -96,7 +126,33 @@ async function handleRemind(userIds?: string[]) {
if (!remindedCount) return;
window.$message?.success(props.periodKeys.length > 1 ? '已按所选区间发送催办提醒' : `已催办 ${remindedCount}`);
window.$message?.success(
props.periodKeys.length > 1
? '已按所选区间发送催办提醒'
: getSingleRemindSuccessText(remindedCount, props.reportType === 'project' && isSingleUserReminder)
);
emit('reminded');
}
async function handleRemindItem(item: Api.WorkReport.Common.TeamReportUnsubmittedReport) {
const itemKey = getUnsubmittedReportKey(item);
remindingItemKey.value = itemKey;
const result = await fetchRemindTeamReport({
reportType: props.reportType,
periodKey: item.periodKey,
userIds: [item.userId],
projectId: props.reportType === 'project' ? item.projectId : undefined
});
remindingItemKey.value = '';
if (result.error) return;
const remindedCount = result.data?.remindedCount ?? 0;
if (!remindedCount) return;
window.$message?.success(getSingleRemindSuccessText(remindedCount, props.reportType === 'project'));
emit('reminded');
}
</script>
@@ -116,26 +172,31 @@ async function handleRemind(userIds?: string[]) {
</template>
<div class="team-report-summary__popover">
<div class="team-report-summary__popover-title">未提交人员</div>
<div v-if="props.summary?.unsubmittedUsers?.length" class="team-report-summary__user-list">
<div class="team-report-summary__popover-title">未提交报告</div>
<div v-if="props.summary?.unsubmittedReports?.length" class="team-report-summary__user-list">
<div
v-for="user in props.summary.unsubmittedUsers"
:key="user.userId"
v-for="item in props.summary.unsubmittedReports"
:key="getUnsubmittedReportKey(item)"
class="team-report-summary__user-item"
>
<span class="team-report-summary__user-name">{{ user.userNickname }}</span>
<div class="team-report-summary__user-content">
<div class="team-report-summary__user-name">{{ item.userNickname }}</div>
<div class="team-report-summary__user-meta">
{{ getUnsubmittedReportSecondaryText(item) }}
</div>
</div>
<ElButton
v-if="canRemind"
link
type="primary"
:loading="remindingUserId === user.userId"
@click="handleRemind([user.userId])"
:loading="remindingItemKey === getUnsubmittedReportKey(item)"
@click="handleRemindItem(item)"
>
催办
</ElButton>
</div>
</div>
<ElEmpty v-else :image-size="60" description="暂无提交人员" />
<ElEmpty v-else :image-size="60" description="暂无提交报告" />
<div v-if="canRemind" class="team-report-summary__popover-footer">
<ElButton
@@ -143,7 +204,7 @@ async function handleRemind(userIds?: string[]) {
type="primary"
plain
:loading="remindingAll"
:disabled="!props.summary?.unsubmittedUsers?.length"
:disabled="!props.summary?.unsubmittedReports?.length"
@click="handleRemind()"
>
一键催办全部
@@ -239,6 +300,21 @@ async function handleRemind(userIds?: string[]) {
.team-report-summary__user-name {
min-width: 0;
color: var(--el-text-color-regular);
font-weight: 500;
}
.team-report-summary__user-content {
min-width: 0;
display: grid;
gap: 4px;
}
.team-report-summary__user-meta {
min-width: 0;
color: var(--el-text-color-secondary);
font-size: 12px;
line-height: 1.4;
word-break: break-all;
}
.team-report-summary__popover-footer {