refactor(work-report): 将项目报告周期从月份半月改为自由的日期范围
- 移除项目报告中的 flag 字段必填限制,改为可选 - 将项目报告创建对话框中的月份和半月选择改为日期范围选择器 - 更新项目报告详情对话框,移除半月周期显示字段 - 修改项目报告搜索面板,调整周期字段标签和类型 - 更新团队报告汇总组件中的项目报告催办逻辑 - 调整项目报告表格列宽和标签显示 - 重构项目报告周期构建逻辑,支持灵活的日期范围输入 - 更新相关类型定义和 API 接口中的 flag 字段为可选 - 统一将"项目半月报"更名为"研发简报"以反映新的日期范围特性
This commit is contained in:
@@ -172,7 +172,7 @@ const local: App.I18n.Schema = {
|
|||||||
'personal-center_work-report': '工作报告',
|
'personal-center_work-report': '工作报告',
|
||||||
'personal-center_work-report_weekly': '个人周报',
|
'personal-center_work-report_weekly': '个人周报',
|
||||||
'personal-center_work-report_monthly': '个人月报',
|
'personal-center_work-report_monthly': '个人月报',
|
||||||
'personal-center_work-report_project': '项目半月报',
|
'personal-center_work-report_project': '研发简报',
|
||||||
'personal-center_my-performance': '绩效管理',
|
'personal-center_my-performance': '绩效管理',
|
||||||
'personal-center_my-application': '我的申请',
|
'personal-center_my-application': '我的申请',
|
||||||
'personal-center_overtime-application': '业务学习',
|
'personal-center_overtime-application': '业务学习',
|
||||||
|
|||||||
4
src/typings/api/work-report.d.ts
vendored
4
src/typings/api/work-report.d.ts
vendored
@@ -300,7 +300,7 @@ declare namespace Api {
|
|||||||
periodLabel: string;
|
periodLabel: string;
|
||||||
periodStartDate: string;
|
periodStartDate: string;
|
||||||
periodEndDate: string;
|
periodEndDate: string;
|
||||||
flag: number;
|
flag?: number | null;
|
||||||
statusCode: Common.WorkReportStatusCode | string;
|
statusCode: Common.WorkReportStatusCode | string;
|
||||||
statusName: string;
|
statusName: string;
|
||||||
allowEdit: boolean;
|
allowEdit: boolean;
|
||||||
@@ -332,7 +332,7 @@ declare namespace Api {
|
|||||||
periodLabel: string;
|
periodLabel: string;
|
||||||
periodStartDate: string;
|
periodStartDate: string;
|
||||||
periodEndDate: string;
|
periodEndDate: string;
|
||||||
flag: number;
|
flag?: number | null;
|
||||||
projectStatusDesc?: string | null;
|
projectStatusDesc?: string | null;
|
||||||
projectProgressPlan?: string | null;
|
projectProgressPlan?: string | null;
|
||||||
projectKeyPoints?: string | null;
|
projectKeyPoints?: string | null;
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ const teamContext = computed<TeamViewContext | null>(() => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 项目选项是否加载成功(用于项目半月报列表内部判断) */
|
/** 项目选项是否加载成功(用于项目汇报列表内部判断) */
|
||||||
const projectOptionsLoaded = ref(false);
|
const projectOptionsLoaded = ref(false);
|
||||||
|
|
||||||
const visibleTabs = computed<Array<{ label: string; name: WorkReportType }>>(() => {
|
const visibleTabs = computed<Array<{ label: string; name: WorkReportType }>>(() => {
|
||||||
@@ -194,7 +194,7 @@ function handleCreateConfirm(
|
|||||||
| {
|
| {
|
||||||
reportType: 'project';
|
reportType: 'project';
|
||||||
projectId: string;
|
projectId: string;
|
||||||
flag: number;
|
flag?: number;
|
||||||
period: typeof initialPeriod.value extends infer T ? T : never;
|
period: typeof initialPeriod.value extends infer T ? T : never;
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
@@ -203,7 +203,7 @@ function handleCreateConfirm(
|
|||||||
currentRow.value = null;
|
currentRow.value = null;
|
||||||
initialPeriod.value = payload.period as typeof initialPeriod.value;
|
initialPeriod.value = payload.period as typeof initialPeriod.value;
|
||||||
initialProjectId.value = 'projectId' in payload ? payload.projectId : '';
|
initialProjectId.value = 'projectId' in payload ? payload.projectId : '';
|
||||||
initialFlag.value = 'flag' in payload ? payload.flag : 1;
|
initialFlag.value = 'flag' in payload ? (payload.flag ?? 1) : 1;
|
||||||
pageDialogVisible.value = true;
|
pageDialogVisible.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {
|
|||||||
resolveWorkReportStatusTagType,
|
resolveWorkReportStatusTagType,
|
||||||
transformWorkReportPage
|
transformWorkReportPage
|
||||||
} from '../shared/types';
|
} from '../shared/types';
|
||||||
import { buildProjectPeriodFromMonth, resolveWorkReportSummaryPeriod } from '../shared/utils';
|
import { resolveWorkReportSummaryPeriod } from '../shared/utils';
|
||||||
import ProjectReportSearch from './modules/search-panel.vue';
|
import ProjectReportSearch from './modules/search-panel.vue';
|
||||||
import IconMdiDeleteOutline from '~icons/mdi/delete-outline';
|
import IconMdiDeleteOutline from '~icons/mdi/delete-outline';
|
||||||
import IconMdiEyeOutline from '~icons/mdi/eye-outline';
|
import IconMdiEyeOutline from '~icons/mdi/eye-outline';
|
||||||
@@ -86,7 +86,7 @@ const normalizedPeriodRange = computed(() => {
|
|||||||
return periodRange;
|
return periodRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [start.startOf('month').format('YYYY-MM-DD'), end.endOf('month').format('YYYY-MM-DD')];
|
return [start.format('YYYY-MM-DD'), end.format('YYYY-MM-DD')];
|
||||||
});
|
});
|
||||||
|
|
||||||
const table = useUIPaginatedTable<
|
const table = useUIPaginatedTable<
|
||||||
@@ -110,8 +110,8 @@ const table = useUIPaginatedTable<
|
|||||||
...(isTeamMode.value
|
...(isTeamMode.value
|
||||||
? [{ prop: 'projectOwnerName', label: '提交人', minWidth: 100, showOverflowTooltip: true }]
|
? [{ prop: 'projectOwnerName', label: '提交人', minWidth: 100, showOverflowTooltip: true }]
|
||||||
: []),
|
: []),
|
||||||
{ prop: 'projectName', label: '项目名称', minWidth: 200, showOverflowTooltip: true },
|
{ prop: 'projectName', label: '项目名称', minWidth: 210, showOverflowTooltip: true },
|
||||||
{ prop: 'periodLabel', label: '半月周期', minWidth: 120, formatter: row => formatPeriod(row) },
|
{ prop: 'periodLabel', label: '周期', minWidth: 150, formatter: row => formatPeriod(row) },
|
||||||
{ prop: 'projectOwnerName', label: '项目负责人', minWidth: 80 },
|
{ prop: 'projectOwnerName', label: '项目负责人', minWidth: 80 },
|
||||||
{
|
{
|
||||||
prop: 'technicalOwnerName',
|
prop: 'technicalOwnerName',
|
||||||
@@ -145,42 +145,12 @@ const table = useUIPaginatedTable<
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
// 团队统计始终使用当前周期(当前半月),不跟随列表第一条数据的周期
|
|
||||||
const summaryPeriod = computed(() =>
|
const summaryPeriod = computed(() =>
|
||||||
resolveWorkReportSummaryPeriod('project', {
|
resolveWorkReportSummaryPeriod('project', {
|
||||||
periodRange: normalizedPeriodRange.value
|
periodRange: normalizedPeriodRange.value
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const summaryPeriodKeys = computed(() => {
|
const summaryPeriodKeys = computed(() => []);
|
||||||
const dateRange = normalizedPeriodRange.value;
|
|
||||||
const fallbackKey = summaryPeriod.value.periodKey;
|
|
||||||
|
|
||||||
if (!dateRange?.length) {
|
|
||||||
return fallbackKey ? [fallbackKey] : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const [startDate, endDate] = dateRange;
|
|
||||||
const start = dayjs(startDate);
|
|
||||||
const end = dayjs(endDate || startDate);
|
|
||||||
|
|
||||||
if (!start.isValid() || !end.isValid()) {
|
|
||||||
return fallbackKey ? [fallbackKey] : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const keys: string[] = [];
|
|
||||||
const endBoundary = end.endOf('month');
|
|
||||||
|
|
||||||
for (
|
|
||||||
let cursor = start.startOf('month');
|
|
||||||
cursor.isBefore(endBoundary, 'month') || cursor.isSame(endBoundary, 'month');
|
|
||||||
cursor = cursor.add(1, 'month')
|
|
||||||
) {
|
|
||||||
keys.push(buildProjectPeriodFromMonth(cursor, 1).periodKey);
|
|
||||||
keys.push(buildProjectPeriodFromMonth(cursor, 2).periodKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return keys;
|
|
||||||
});
|
|
||||||
const hasSearchedDateRange = computed(() => searchParams.periodStartDate?.length === 2);
|
const hasSearchedDateRange = computed(() => searchParams.periodStartDate?.length === 2);
|
||||||
|
|
||||||
function getRowActions(row: Api.WorkReport.Project.ProjectReport): BusinessTableAction[] {
|
function getRowActions(row: Api.WorkReport.Project.ProjectReport): BusinessTableAction[] {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
|
|||||||
import {
|
import {
|
||||||
type WorkReportPeriodOption,
|
type WorkReportPeriodOption,
|
||||||
buildMonthlyPeriodFromMonth,
|
buildMonthlyPeriodFromMonth,
|
||||||
buildProjectPeriodFromMonth,
|
buildProjectPeriodFromDateRange,
|
||||||
buildWeeklyPeriodFromDate,
|
buildWeeklyPeriodFromDate,
|
||||||
formatPeriodDisplayLabel,
|
formatPeriodDisplayLabel,
|
||||||
getReportTypePeriodOptions
|
getReportTypePeriodOptions
|
||||||
@@ -40,7 +40,7 @@ const emit = defineEmits<{
|
|||||||
| {
|
| {
|
||||||
reportType: 'project';
|
reportType: 'project';
|
||||||
projectId: string;
|
projectId: string;
|
||||||
flag: number;
|
flag?: number;
|
||||||
period: WorkReportPeriodOption['period'];
|
period: WorkReportPeriodOption['period'];
|
||||||
}
|
}
|
||||||
): void;
|
): void;
|
||||||
@@ -50,8 +50,7 @@ const selectedPeriodKey = ref('');
|
|||||||
const selectedProjectId = ref('');
|
const selectedProjectId = ref('');
|
||||||
const rawCustomWeekDate = ref('');
|
const rawCustomWeekDate = ref('');
|
||||||
const customMonth = ref('');
|
const customMonth = ref('');
|
||||||
const customProjectMonth = ref('');
|
const customProjectDateRange = ref<string[]>([]);
|
||||||
const customProjectFlag = ref(1);
|
|
||||||
|
|
||||||
// 自定义周报周期:无论用户点哪一天,都归一到该 ISO 周的周一,
|
// 自定义周报周期:无论用户点哪一天,都归一到该 ISO 周的周一,
|
||||||
// 这样 ElDatePicker 使用内置 dayjs 的 ww(locale week)也能正确显示 ISO 周数。
|
// 这样 ElDatePicker 使用内置 dayjs 的 ww(locale week)也能正确显示 ISO 周数。
|
||||||
@@ -74,10 +73,7 @@ const selectedReportType = computed<WorkReportType>(() => {
|
|||||||
const periodOptionMap = computed(() => getReportTypePeriodOptions());
|
const periodOptionMap = computed(() => getReportTypePeriodOptions());
|
||||||
const activePeriodOptions = computed(() => periodOptionMap.value[selectedReportType.value]);
|
const activePeriodOptions = computed(() => periodOptionMap.value[selectedReportType.value]);
|
||||||
const dialogTitle = computed(() => `新增${WORK_REPORT_TYPE_LABEL[selectedReportType.value]}`);
|
const dialogTitle = computed(() => `新增${WORK_REPORT_TYPE_LABEL[selectedReportType.value]}`);
|
||||||
const projectHalfOptions = [
|
const isProjectReport = computed(() => selectedReportType.value === 'project');
|
||||||
{ label: '上半月', value: 1 },
|
|
||||||
{ label: '下半月', value: 2 }
|
|
||||||
];
|
|
||||||
|
|
||||||
const defaultCustomMonth = computed(() => {
|
const defaultCustomMonth = computed(() => {
|
||||||
const period = activePeriodOptions.value[0]?.period;
|
const period = activePeriodOptions.value[0]?.period;
|
||||||
@@ -85,7 +81,7 @@ const defaultCustomMonth = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const customPeriod = computed<WorkReportPeriodOption['period'] | null>(() => {
|
const customPeriod = computed<WorkReportPeriodOption['period'] | null>(() => {
|
||||||
if (selectedPeriodKey.value !== 'custom') return null;
|
if (!isProjectReport.value && selectedPeriodKey.value !== 'custom') return null;
|
||||||
|
|
||||||
if (selectedReportType.value === 'weekly') {
|
if (selectedReportType.value === 'weekly') {
|
||||||
if (!customWeekDate.value) return null;
|
if (!customWeekDate.value) return null;
|
||||||
@@ -97,16 +93,15 @@ const customPeriod = computed<WorkReportPeriodOption['period'] | null>(() => {
|
|||||||
return buildMonthlyPeriodFromMonth(customMonth.value);
|
return buildMonthlyPeriodFromMonth(customMonth.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!customProjectMonth.value) return null;
|
if (customProjectDateRange.value.length !== 2) return null;
|
||||||
return buildProjectPeriodFromMonth(customProjectMonth.value, customProjectFlag.value);
|
return buildProjectPeriodFromDateRange(customProjectDateRange.value[0], customProjectDateRange.value[1]);
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedPeriod = computed(
|
const selectedPeriod = computed(
|
||||||
() => activePeriodOptions.value.find(item => item.key === selectedPeriodKey.value) ?? activePeriodOptions.value[0]
|
() => activePeriodOptions.value.find(item => item.key === selectedPeriodKey.value) ?? activePeriodOptions.value[0]
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedPeriodValue = computed(() =>
|
const selectedPeriodValue = computed(() =>
|
||||||
selectedPeriodKey.value === 'custom' ? customPeriod.value : selectedPeriod.value?.period
|
isProjectReport.value || selectedPeriodKey.value === 'custom' ? customPeriod.value : selectedPeriod.value?.period
|
||||||
);
|
);
|
||||||
const customPeriodPreviewLabel = computed(() =>
|
const customPeriodPreviewLabel = computed(() =>
|
||||||
customPeriod.value ? formatPeriodDisplayLabel(customPeriod.value.periodLabel) : ''
|
customPeriod.value ? formatPeriodDisplayLabel(customPeriod.value.periodLabel) : ''
|
||||||
@@ -114,14 +109,14 @@ const customPeriodPreviewLabel = computed(() =>
|
|||||||
|
|
||||||
const confirmDisabled = computed(() => {
|
const confirmDisabled = computed(() => {
|
||||||
if (!selectedPeriodValue.value) return true;
|
if (!selectedPeriodValue.value) return true;
|
||||||
if (selectedReportType.value === 'project' && !selectedProjectId.value) return true;
|
if (isProjectReport.value && !selectedProjectId.value) return true;
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
selectedReportType,
|
selectedReportType,
|
||||||
type => {
|
type => {
|
||||||
selectedPeriodKey.value = periodOptionMap.value[type][0]?.key || '';
|
selectedPeriodKey.value = type === 'project' ? 'custom' : periodOptionMap.value[type][0]?.key || '';
|
||||||
|
|
||||||
if (type === 'project' && !selectedProjectId.value) {
|
if (type === 'project' && !selectedProjectId.value) {
|
||||||
selectedProjectId.value = props.projectOptions[0]?.id || '';
|
selectedProjectId.value = props.projectOptions[0]?.id || '';
|
||||||
@@ -134,27 +129,34 @@ watch(visible, isVisible => {
|
|||||||
if (!isVisible) return;
|
if (!isVisible) return;
|
||||||
|
|
||||||
selectedProjectId.value = props.projectOptions[0]?.id || '';
|
selectedProjectId.value = props.projectOptions[0]?.id || '';
|
||||||
selectedPeriodKey.value = periodOptionMap.value[selectedReportType.value][0]?.key || '';
|
selectedPeriodKey.value = isProjectReport.value
|
||||||
|
? 'custom'
|
||||||
|
: periodOptionMap.value[selectedReportType.value][0]?.key || '';
|
||||||
customWeekDate.value = activePeriodOptions.value[0]?.period.periodStartDate || '';
|
customWeekDate.value = activePeriodOptions.value[0]?.period.periodStartDate || '';
|
||||||
customMonth.value = defaultCustomMonth.value;
|
customMonth.value = defaultCustomMonth.value;
|
||||||
customProjectMonth.value = defaultCustomMonth.value;
|
customProjectDateRange.value = [
|
||||||
customProjectFlag.value = activePeriodOptions.value[0]?.flag || 1;
|
activePeriodOptions.value[0]?.period.periodStartDate || '',
|
||||||
|
activePeriodOptions.value[0]?.period.periodEndDate || ''
|
||||||
|
].filter(Boolean);
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
const period = selectedPeriodValue.value;
|
const period = selectedPeriodValue.value;
|
||||||
if (!period) return;
|
if (!period) return;
|
||||||
|
|
||||||
if (selectedReportType.value === 'project') {
|
if (isProjectReport.value) {
|
||||||
emit('confirm', {
|
emit('confirm', {
|
||||||
reportType: 'project',
|
reportType: 'project',
|
||||||
projectId: selectedProjectId.value,
|
projectId: selectedProjectId.value,
|
||||||
flag: selectedPeriodKey.value === 'custom' ? customProjectFlag.value : selectedPeriod.value.flag || 1,
|
flag: period.flag,
|
||||||
period
|
period
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
const reportType = selectedReportType.value;
|
||||||
|
if (reportType !== 'weekly' && reportType !== 'monthly') return;
|
||||||
|
|
||||||
emit('confirm', {
|
emit('confirm', {
|
||||||
reportType: selectedReportType.value,
|
reportType,
|
||||||
period
|
period
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -194,7 +196,7 @@ function handleConfirm() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="work-report-create-dialog__section">
|
<div class="work-report-create-dialog__section">
|
||||||
<div class="work-report-create-dialog__grid is-period">
|
<div v-if="!isProjectReport" class="work-report-create-dialog__grid is-period">
|
||||||
<button
|
<button
|
||||||
v-for="item in activePeriodOptions"
|
v-for="item in activePeriodOptions"
|
||||||
:key="item.key"
|
:key="item.key"
|
||||||
@@ -214,18 +216,16 @@ function handleConfirm() {
|
|||||||
>
|
>
|
||||||
<div class="work-report-create-dialog__choice-title">自定义周期</div>
|
<div class="work-report-create-dialog__choice-title">自定义周期</div>
|
||||||
<div class="work-report-create-dialog__choice-desc">
|
<div class="work-report-create-dialog__choice-desc">
|
||||||
{{
|
{{ selectedReportType === 'weekly' ? '选择某一周作为周报周期。' : '选择某一月作为月报周期。' }}
|
||||||
selectedReportType === 'weekly'
|
|
||||||
? '选择某一周作为周报周期。'
|
|
||||||
: selectedReportType === 'monthly'
|
|
||||||
? '选择某一月作为月报周期。'
|
|
||||||
: '选择某个月的上半月或下半月。'
|
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="selectedPeriodKey === 'custom'" class="work-report-create-dialog__custom-period">
|
<div
|
||||||
|
v-if="isProjectReport || selectedPeriodKey === 'custom'"
|
||||||
|
class="work-report-create-dialog__custom-period"
|
||||||
|
:class="{ 'work-report-create-dialog__custom-period--project': isProjectReport }"
|
||||||
|
>
|
||||||
<div v-if="selectedReportType === 'weekly'" class="work-report-create-dialog__custom-row">
|
<div v-if="selectedReportType === 'weekly'" class="work-report-create-dialog__custom-row">
|
||||||
<div class="work-report-create-dialog__field work-report-create-dialog__field--inline">
|
<div class="work-report-create-dialog__field work-report-create-dialog__field--inline">
|
||||||
<label class="work-report-create-dialog__label">周报周期</label>
|
<label class="work-report-create-dialog__label">周报周期</label>
|
||||||
@@ -260,27 +260,19 @@ function handleConfirm() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="work-report-create-dialog__custom-project">
|
<div v-else class="work-report-create-dialog__custom-project">
|
||||||
<div class="work-report-create-dialog__custom-project-grid">
|
|
||||||
<div class="work-report-create-dialog__custom-project-item">
|
<div class="work-report-create-dialog__custom-project-item">
|
||||||
<div class="work-report-create-dialog__custom-project-item-label">选择月份</div>
|
<div class="work-report-create-dialog__custom-project-item-label">选择周期</div>
|
||||||
<ElDatePicker
|
<ElDatePicker
|
||||||
v-model="customProjectMonth"
|
v-model="customProjectDateRange"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
type="month"
|
type="daterange"
|
||||||
value-format="YYYY-MM"
|
value-format="YYYY-MM-DD"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
popper-class="work-report-create-date-popper"
|
popper-class="work-report-create-date-popper"
|
||||||
placeholder="请选择月份"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="work-report-create-dialog__custom-project-item">
|
|
||||||
<div class="work-report-create-dialog__custom-project-item-label">选择半月</div>
|
|
||||||
<ElSegmented
|
|
||||||
v-model="customProjectFlag"
|
|
||||||
:options="projectHalfOptions"
|
|
||||||
class="work-report-create-dialog__half-segmented"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-if="customPeriodPreviewLabel" class="work-report-create-dialog__period-preview">
|
<div v-if="customPeriodPreviewLabel" class="work-report-create-dialog__period-preview">
|
||||||
<ElIcon class="work-report-create-dialog__period-preview-icon"><Calendar /></ElIcon>
|
<ElIcon class="work-report-create-dialog__period-preview-icon"><Calendar /></ElIcon>
|
||||||
<span class="work-report-create-dialog__period-preview-text">已选周期:</span>
|
<span class="work-report-create-dialog__period-preview-text">已选周期:</span>
|
||||||
@@ -422,6 +414,10 @@ function handleConfirm() {
|
|||||||
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.06);
|
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.work-report-create-dialog__custom-period--project {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.work-report-create-dialog__custom-row {
|
.work-report-create-dialog__custom-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
@@ -438,13 +434,6 @@ function handleConfirm() {
|
|||||||
gap: 14px;
|
gap: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.work-report-create-dialog__custom-project-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
|
|
||||||
gap: 14px;
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.work-report-create-dialog__custom-project-item {
|
.work-report-create-dialog__custom-project-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -471,24 +460,6 @@ function handleConfirm() {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.work-report-create-dialog__half-segmented {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.work-report-create-dialog__half-segmented :deep(.el-segmented__group) {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
||||||
width: 100%;
|
|
||||||
gap: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.work-report-create-dialog__half-segmented :deep(.el-segmented__item) {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.work-report-create-dialog__period-preview {
|
.work-report-create-dialog__period-preview {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -532,10 +503,8 @@ function handleConfirm() {
|
|||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.work-report-create-dialog__custom-row,
|
.work-report-create-dialog__custom-row {
|
||||||
.work-report-create-dialog__custom-project-grid {
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.work-report-create-dialog__field--inline {
|
.work-report-create-dialog__field--inline {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import {
|
|||||||
formatPeriod,
|
formatPeriod,
|
||||||
formatPeriodDateRange,
|
formatPeriodDateRange,
|
||||||
formatWeeklyPeriodLabel,
|
formatWeeklyPeriodLabel,
|
||||||
getProjectReportFlagLabel,
|
|
||||||
getWorkReportStatusLabel
|
getWorkReportStatusLabel
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
@@ -100,9 +99,6 @@ function getPersonalDetail() {
|
|||||||
<BusinessFormSection title="项目信息">
|
<BusinessFormSection title="项目信息">
|
||||||
<ElDescriptions :column="2" border size="small">
|
<ElDescriptions :column="2" border size="small">
|
||||||
<ElDescriptionsItem label="项目名称">{{ getProjectDetail()?.projectName }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="项目名称">{{ getProjectDetail()?.projectName }}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="半月周期">
|
|
||||||
{{ getProjectReportFlagLabel(getProjectDetail()?.flag) }}
|
|
||||||
</ElDescriptionsItem>
|
|
||||||
<ElDescriptionsItem label="项目负责人">{{ getProjectDetail()?.projectOwnerName }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="项目负责人">{{ getProjectDetail()?.projectOwnerName }}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="技术负责人">
|
<ElDescriptionsItem label="技术负责人">
|
||||||
{{ formatEmptyText(getProjectDetail()?.technicalOwnerName) }}
|
{{ formatEmptyText(getProjectDetail()?.technicalOwnerName) }}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ const emit = defineEmits<{
|
|||||||
const REPORT_TYPE_TEXT: Record<WorkReportType, string> = {
|
const REPORT_TYPE_TEXT: Record<WorkReportType, string> = {
|
||||||
weekly: '个人周报',
|
weekly: '个人周报',
|
||||||
monthly: '个人月报',
|
monthly: '个人月报',
|
||||||
project: '项目半月报'
|
project: '研发简报'
|
||||||
};
|
};
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ const fields = computed<SearchField[]>(() => {
|
|||||||
|
|
||||||
const monthPeriodField: SearchField = {
|
const monthPeriodField: SearchField = {
|
||||||
key: 'periodStartDate',
|
key: 'periodStartDate',
|
||||||
label: props.reportType === 'project' ? '月份' : '月份',
|
label: '月份',
|
||||||
type: 'dateRange',
|
type: 'dateRange',
|
||||||
dateRangeType: 'monthrange',
|
dateRangeType: 'monthrange',
|
||||||
valueFormat: 'YYYY-MM-DD',
|
valueFormat: 'YYYY-MM-DD',
|
||||||
@@ -107,7 +107,7 @@ const fields = computed<SearchField[]>(() => {
|
|||||||
if (props.reportType === 'project') {
|
if (props.reportType === 'project') {
|
||||||
return [
|
return [
|
||||||
baseFields[0],
|
baseFields[0],
|
||||||
monthPeriodField,
|
{ key: 'periodStartDate', label: '周期', type: 'dateRange', placeholder: '请选择周期' },
|
||||||
{
|
{
|
||||||
key: 'projectId',
|
key: 'projectId',
|
||||||
label: '项目',
|
label: '项目',
|
||||||
|
|||||||
@@ -28,7 +28,10 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const remindingAll = ref(false);
|
const remindingAll = ref(false);
|
||||||
const remindingItemKey = ref('');
|
const remindingItemKey = ref('');
|
||||||
const canRemind = computed(() => props.periodKeys.length > 0);
|
const canProjectRemind = computed(() => Boolean(props.summary?.unsubmittedReports?.length));
|
||||||
|
const canRemind = computed(() =>
|
||||||
|
props.reportType === 'project' ? canProjectRemind.value : props.periodKeys.length > 0
|
||||||
|
);
|
||||||
|
|
||||||
function formatSummaryPeriodLabel() {
|
function formatSummaryPeriodLabel() {
|
||||||
if (!props.summary?.periodStartDate || !props.summary?.periodEndDate) {
|
if (!props.summary?.periodStartDate || !props.summary?.periodEndDate) {
|
||||||
@@ -42,12 +45,16 @@ function formatSummaryPeriodLabel() {
|
|||||||
return `${props.summary.periodStartDate} 至 ${props.summary.periodEndDate}`;
|
return `${props.summary.periodStartDate} 至 ${props.summary.periodEndDate}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.reportType === 'monthly' || props.reportType === 'project') {
|
if (props.reportType === 'monthly') {
|
||||||
const startMonth = start.format('YYYY-MM');
|
const startMonth = start.format('YYYY-MM');
|
||||||
const endMonth = end.format('YYYY-MM');
|
const endMonth = end.format('YYYY-MM');
|
||||||
return startMonth === endMonth ? startMonth : `${startMonth} 至 ${endMonth}`;
|
return startMonth === endMonth ? startMonth : `${startMonth} 至 ${endMonth}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (props.reportType === 'project') {
|
||||||
|
return `${start.format('YYYY-MM-DD')} 至 ${end.format('YYYY-MM-DD')}`;
|
||||||
|
}
|
||||||
|
|
||||||
if (props.reportType === 'weekly') {
|
if (props.reportType === 'weekly') {
|
||||||
return formatIsoWeekRangeLabel(props.summary.periodStartDate, props.summary.periodEndDate);
|
return formatIsoWeekRangeLabel(props.summary.periodStartDate, props.summary.periodEndDate);
|
||||||
}
|
}
|
||||||
@@ -101,9 +108,36 @@ function getSingleRemindSuccessText(remindedCount: number, preciseProjectReminde
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleRemind(userIds?: string[]) {
|
async function handleRemind(userIds?: string[]) {
|
||||||
if (!props.periodKeys.length) return;
|
if (props.reportType === 'project') {
|
||||||
|
const unsubmittedReports = props.summary?.unsubmittedReports || [];
|
||||||
|
if (!unsubmittedReports.length) return;
|
||||||
|
|
||||||
const isSingleUserReminder = userIds?.length === 1;
|
remindingAll.value = true;
|
||||||
|
const results = await Promise.all(
|
||||||
|
unsubmittedReports.map(item =>
|
||||||
|
fetchRemindTeamReport({
|
||||||
|
reportType: 'project',
|
||||||
|
periodKey: item.periodKey,
|
||||||
|
userIds: userIds?.length ? userIds : [item.userId],
|
||||||
|
projectId: item.projectId || undefined
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
remindingAll.value = false;
|
||||||
|
|
||||||
|
const remindedCount = results.reduce((total, result) => {
|
||||||
|
if (result.error) return total;
|
||||||
|
return total + (result.data?.remindedCount ?? 0);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
if (!remindedCount) return;
|
||||||
|
|
||||||
|
window.$message?.success('已按当前未提交明细发送催办提醒');
|
||||||
|
emit('reminded');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!props.periodKeys.length) return;
|
||||||
|
|
||||||
remindingAll.value = true;
|
remindingAll.value = true;
|
||||||
|
|
||||||
@@ -127,9 +161,7 @@ async function handleRemind(userIds?: string[]) {
|
|||||||
if (!remindedCount) return;
|
if (!remindedCount) return;
|
||||||
|
|
||||||
window.$message?.success(
|
window.$message?.success(
|
||||||
props.periodKeys.length > 1
|
props.periodKeys.length > 1 ? '已按所选区间发送催办提醒' : getSingleRemindSuccessText(remindedCount, false)
|
||||||
? '已按所选区间发送催办提醒'
|
|
||||||
: getSingleRemindSuccessText(remindedCount, props.reportType === 'project' && isSingleUserReminder)
|
|
||||||
);
|
);
|
||||||
emit('reminded');
|
emit('reminded');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,13 +38,13 @@ export const WORK_REPORT_PROJECT_OWNER_PERMISSION = 'project:work-report:project
|
|||||||
export const WORK_REPORT_TYPE_LABEL: Record<WorkReportType, string> = {
|
export const WORK_REPORT_TYPE_LABEL: Record<WorkReportType, string> = {
|
||||||
weekly: '个人周报',
|
weekly: '个人周报',
|
||||||
monthly: '个人月报',
|
monthly: '个人月报',
|
||||||
project: '项目半月报'
|
project: '研发简报'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TEAM_WORK_REPORT_TYPE_LABEL: Record<WorkReportType, string> = {
|
export const TEAM_WORK_REPORT_TYPE_LABEL: Record<WorkReportType, string> = {
|
||||||
weekly: '团队周报',
|
weekly: '团队周报',
|
||||||
monthly: '团队月报',
|
monthly: '团队月报',
|
||||||
project: '团队项目半月报'
|
project: '团队研发简报'
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getWorkReportTypeDisplayLabel(reportType: WorkReportType, isTeamMode = false) {
|
export function getWorkReportTypeDisplayLabel(reportType: WorkReportType, isTeamMode = false) {
|
||||||
@@ -145,7 +145,7 @@ export function formatWeeklyPeriodLabel(
|
|||||||
export function formatPeriodLabel(value?: string | null) {
|
export function formatPeriodLabel(value?: string | null) {
|
||||||
return String(value || '')
|
return String(value || '')
|
||||||
.trim()
|
.trim()
|
||||||
.replace(/\s*(周报|月报|项目半月报|半月报)\s*$/u, '');
|
.replace(/\s*(周报|月报|项目汇报|项目半月报|半月报|研发简报)\s*$/u, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatPeriod(row: Pick<WorkReportRow, 'periodLabel' | 'periodStartDate' | 'periodEndDate'>) {
|
export function formatPeriod(row: Pick<WorkReportRow, 'periodLabel' | 'periodStartDate' | 'periodEndDate'>) {
|
||||||
@@ -472,7 +472,7 @@ export function createProjectSaveParams(
|
|||||||
periodLabel: '',
|
periodLabel: '',
|
||||||
periodStartDate: '',
|
periodStartDate: '',
|
||||||
periodEndDate: '',
|
periodEndDate: '',
|
||||||
flag: 1,
|
flag: undefined,
|
||||||
projectStatusDesc: '',
|
projectStatusDesc: '',
|
||||||
projectProgressPlan: '',
|
projectProgressPlan: '',
|
||||||
projectKeyPoints: '',
|
projectKeyPoints: '',
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export interface WorkReportPeriodOption {
|
|||||||
periodLabel: string;
|
periodLabel: string;
|
||||||
periodStartDate: string;
|
periodStartDate: string;
|
||||||
periodEndDate: string;
|
periodEndDate: string;
|
||||||
|
flag?: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ function formatRangeLabel(start: dayjs.Dayjs, end: dayjs.Dayjs) {
|
|||||||
export function formatPeriodDisplayLabel(label?: string | null) {
|
export function formatPeriodDisplayLabel(label?: string | null) {
|
||||||
return String(label || '')
|
return String(label || '')
|
||||||
.trim()
|
.trim()
|
||||||
.replace(/\s*(周报|月报|项目半月报|半月报)\s*$/u, '');
|
.replace(/\s*(周报|月报|项目汇报|项目半月报|半月报|研发简报)\s*$/u, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用 ISO 周数,确保与 buildWeeklyPeriodFromDate 的计算一致
|
// 使用 ISO 周数,确保与 buildWeeklyPeriodFromDate 的计算一致
|
||||||
@@ -119,12 +120,43 @@ export function buildProjectPeriodFromMonth(month: string | dayjs.Dayjs, flag: n
|
|||||||
if (flag === 2) {
|
if (flag === 2) {
|
||||||
const start = monthStart.date(16);
|
const start = monthStart.date(16);
|
||||||
const end = selectedMonth.endOf('month');
|
const end = selectedMonth.endOf('month');
|
||||||
return buildPeriod('project', start, end, `${selectedMonth.format('YYYY-MM')} 下半月`, 2);
|
return buildProjectPeriodFromDateRange(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
const start = monthStart.startOf('month');
|
const start = monthStart.startOf('month');
|
||||||
const end = monthStart.date(15);
|
const end = monthStart.date(15);
|
||||||
return buildPeriod('project', start, end, `${selectedMonth.format('YYYY-MM')} 上半月`, 1);
|
return buildProjectPeriodFromDateRange(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildProjectPeriodFromDateRange(startDate: string | dayjs.Dayjs, endDate: string | dayjs.Dayjs) {
|
||||||
|
const start = dayjs(startDate).startOf('day');
|
||||||
|
const end = dayjs(endDate).startOf('day');
|
||||||
|
|
||||||
|
if (!start.isValid() || !end.isValid()) {
|
||||||
|
return {
|
||||||
|
periodKey: '',
|
||||||
|
periodLabel: '',
|
||||||
|
periodStartDate: '',
|
||||||
|
periodEndDate: '',
|
||||||
|
flag: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let flag: number | undefined;
|
||||||
|
let label = formatRangeLabel(start, end);
|
||||||
|
|
||||||
|
if (start.isSame(end, 'month') && start.date() === 1 && end.date() === 15) {
|
||||||
|
flag = 1;
|
||||||
|
label = `${start.format('YYYY-MM')} 上半月`;
|
||||||
|
} else if (start.isSame(end, 'month') && start.date() === 16 && end.date() === end.daysInMonth()) {
|
||||||
|
flag = 2;
|
||||||
|
label = `${start.format('YYYY-MM')} 下半月`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...buildPeriod('project', start, end, label, flag),
|
||||||
|
flag
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeeklyPeriodOptions(now = dayjs()): WorkReportPeriodOption[] {
|
export function getWeeklyPeriodOptions(now = dayjs()): WorkReportPeriodOption[] {
|
||||||
@@ -177,59 +209,30 @@ export function getMonthlyPeriodOptions(now = dayjs()): WorkReportPeriodOption[]
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getProjectPeriodOptions(now = dayjs()): WorkReportPeriodOption[] {
|
export function getProjectPeriodOptions(now = dayjs()): WorkReportPeriodOption[] {
|
||||||
const currentMonthStart = now.startOf('month');
|
const recent15Start = now.subtract(14, 'day').startOf('day');
|
||||||
const currentMonthEnd = now.endOf('month');
|
const recent30Start = now.subtract(29, 'day').startOf('day');
|
||||||
const currentFirstHalfEnd = currentMonthStart.date(15);
|
const today = now.startOf('day');
|
||||||
const currentSecondHalfStart = currentMonthStart.date(16);
|
const recent15Period = buildProjectPeriodFromDateRange(recent15Start, today);
|
||||||
const previousMonth = now.subtract(1, 'month');
|
const recent30Period = buildProjectPeriodFromDateRange(recent30Start, today);
|
||||||
const previousMonthStart = previousMonth.startOf('month');
|
|
||||||
const previousMonthEnd = previousMonth.endOf('month');
|
|
||||||
const previousSecondHalfStart = previousMonthStart.date(16);
|
|
||||||
const isCurrentFirstHalf = now.date() <= 15;
|
|
||||||
|
|
||||||
const currentOption: WorkReportPeriodOption = isCurrentFirstHalf
|
return [
|
||||||
? {
|
{
|
||||||
key: 'current-first-half',
|
key: 'recent-15-days',
|
||||||
label: '上半月',
|
label: '最近15天',
|
||||||
description: `${now.format('YYYY-MM')} 上半月`,
|
description: formatRangeLabel(recent15Start, today),
|
||||||
reportType: 'project',
|
reportType: 'project',
|
||||||
flag: 1,
|
flag: recent15Period.flag,
|
||||||
period: buildPeriod('project', currentMonthStart, currentFirstHalfEnd, `${now.format('YYYY-MM')} 上半月`, 1)
|
period: recent15Period
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'recent-30-days',
|
||||||
|
label: '最近30天',
|
||||||
|
description: formatRangeLabel(recent30Start, today),
|
||||||
|
reportType: 'project',
|
||||||
|
flag: recent30Period.flag,
|
||||||
|
period: recent30Period
|
||||||
}
|
}
|
||||||
: {
|
];
|
||||||
key: 'current-second-half',
|
|
||||||
label: '下半月',
|
|
||||||
description: `${now.format('YYYY-MM')} 下半月`,
|
|
||||||
reportType: 'project',
|
|
||||||
flag: 2,
|
|
||||||
period: buildPeriod('project', currentSecondHalfStart, currentMonthEnd, `${now.format('YYYY-MM')} 下半月`, 2)
|
|
||||||
};
|
|
||||||
|
|
||||||
const previousOption: WorkReportPeriodOption = isCurrentFirstHalf
|
|
||||||
? {
|
|
||||||
key: 'previous-second-half',
|
|
||||||
label: '下半月',
|
|
||||||
description: `${previousMonth.format('YYYY-MM')} 下半月`,
|
|
||||||
reportType: 'project',
|
|
||||||
flag: 2,
|
|
||||||
period: buildPeriod(
|
|
||||||
'project',
|
|
||||||
previousSecondHalfStart,
|
|
||||||
previousMonthEnd,
|
|
||||||
`${previousMonth.format('YYYY-MM')} 下半月`,
|
|
||||||
2
|
|
||||||
)
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
key: 'previous-first-half',
|
|
||||||
label: '上半月',
|
|
||||||
description: `${now.format('YYYY-MM')} 上半月`,
|
|
||||||
reportType: 'project',
|
|
||||||
flag: 1,
|
|
||||||
period: buildPeriod('project', currentMonthStart, currentFirstHalfEnd, `${now.format('YYYY-MM')} 上半月`, 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
return [currentOption, previousOption];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getReportTypePeriodOptions(now = dayjs()) {
|
export function getReportTypePeriodOptions(now = dayjs()) {
|
||||||
@@ -293,18 +296,18 @@ export function resolveWorkReportSummaryPeriod(
|
|||||||
return referenceDate ? buildMonthlyPeriodFromMonth(referenceDate) : buildMonthlyPeriodFromMonth(fallbackNow);
|
return referenceDate ? buildMonthlyPeriodFromMonth(referenceDate) : buildMonthlyPeriodFromMonth(fallbackNow);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (referenceDate) {
|
if (periodRange?.length) {
|
||||||
const resolvedFlag = inferProjectSummaryFlag(referenceDate, flag);
|
const [startDate, endDate] = periodRange;
|
||||||
return {
|
const fallbackEndDate = endDate || startDate;
|
||||||
...buildProjectPeriodFromMonth(referenceDate, resolvedFlag),
|
if (startDate && fallbackEndDate) {
|
||||||
flag: resolvedFlag
|
return buildProjectPeriodFromDateRange(startDate, fallbackEndDate);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fallbackOption = getProjectPeriodOptions(fallbackNow)[0];
|
if (referenceDate) {
|
||||||
|
const resolvedFlag = inferProjectSummaryFlag(referenceDate, flag);
|
||||||
|
return buildProjectPeriodFromMonth(referenceDate, resolvedFlag);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return buildProjectPeriodFromDateRange(fallbackNow.subtract(29, 'day'), fallbackNow);
|
||||||
...fallbackOption.period,
|
|
||||||
flag: fallbackOption.flag
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ const deadlineFilters: Array<{ key: Exclude<WorkbenchTodoDeadlineFilter, null>;
|
|||||||
const approvalBizTabs: Array<{ key: ApprovalBizType; label: string }> = [
|
const approvalBizTabs: Array<{ key: ApprovalBizType; label: string }> = [
|
||||||
{ key: 'weekly', label: '周报' },
|
{ key: 'weekly', label: '周报' },
|
||||||
{ key: 'monthly', label: '月报' },
|
{ key: 'monthly', label: '月报' },
|
||||||
{ key: 'project', label: '项目半月报' },
|
{ key: 'project', label: '研发简报' },
|
||||||
{ key: 'overtime_application', label: '业务学习' }
|
{ key: 'overtime_application', label: '业务学习' }
|
||||||
];
|
];
|
||||||
const confirmBizTabs: Array<{ key: Extract<ApprovalBizType, 'performance' | 'monthly'>; label: string }> = [
|
const confirmBizTabs: Array<{ key: Extract<ApprovalBizType, 'performance' | 'monthly'>; label: string }> = [
|
||||||
@@ -261,7 +261,7 @@ const APPROVAL_ENTRY_ICON = markRaw(IconMdiClipboardCheckOutline);
|
|||||||
function getApprovalCategoryLabel(bizType: ApprovalBizType) {
|
function getApprovalCategoryLabel(bizType: ApprovalBizType) {
|
||||||
if (bizType === 'weekly') return '周报';
|
if (bizType === 'weekly') return '周报';
|
||||||
if (bizType === 'monthly') return '月报';
|
if (bizType === 'monthly') return '月报';
|
||||||
if (bizType === 'project') return '项目半月报';
|
if (bizType === 'project') return '研发简报';
|
||||||
if (bizType === 'performance') return '绩效表';
|
if (bizType === 'performance') return '绩效表';
|
||||||
if (bizType === 'overtime_application') return '业务学习';
|
if (bizType === 'overtime_application') return '业务学习';
|
||||||
return '待审批';
|
return '待审批';
|
||||||
|
|||||||
Reference in New Issue
Block a user