fix(我的事项、产品/项目、工作台我的待办): 修复已知的一些问题。
This commit is contained in:
@@ -255,9 +255,9 @@ function openView(row: Api.PersonalItem.PersonalItem) {
|
||||
function buildRowActions(row: Api.PersonalItem.PersonalItem): PersonalItemRowAction[] {
|
||||
currentStatusItem.value = row;
|
||||
|
||||
const isCompleted = row.statusCode === 'completed';
|
||||
const rawLifecycleActions = [...(row.availableActions ?? [])];
|
||||
const pauseAction = rawLifecycleActions.find(action => action.actionCode === 'pause') ?? null;
|
||||
const cancelAction = rawLifecycleActions.find(action => action.actionCode === 'cancel') ?? null;
|
||||
const completeAction = rawLifecycleActions.find(action => action.actionCode === 'complete') ?? null;
|
||||
|
||||
const lifecycleActions = rawLifecycleActions
|
||||
@@ -292,26 +292,30 @@ function buildRowActions(row: Api.PersonalItem.PersonalItem): PersonalItemRowAct
|
||||
openOperateDialog();
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
tooltip: '删除',
|
||||
icon: markRaw(IconMdiDeleteOutline),
|
||||
type: 'danger',
|
||||
onClick: async () => handleDelete(row)
|
||||
},
|
||||
{
|
||||
key: 'status-pause',
|
||||
tooltip: pauseAction?.actionName ?? '暂停',
|
||||
icon: markRaw(IconMdiPause),
|
||||
type: 'warning',
|
||||
disabled: !pauseAction,
|
||||
onClick: async () =>
|
||||
handleStatusAction(row, {
|
||||
actionCode: pauseAction?.actionCode ?? 'pause',
|
||||
actionName: pauseAction?.actionName ?? '暂停',
|
||||
needReason: pauseAction?.needReason ?? false
|
||||
})
|
||||
},
|
||||
...(!isCompleted
|
||||
? ([
|
||||
{
|
||||
key: 'delete',
|
||||
tooltip: '删除',
|
||||
icon: markRaw(IconMdiDeleteOutline),
|
||||
type: 'danger',
|
||||
onClick: async () => handleDelete(row)
|
||||
},
|
||||
{
|
||||
key: 'status-pause',
|
||||
tooltip: pauseAction?.actionName ?? '暂停',
|
||||
icon: markRaw(IconMdiPause),
|
||||
type: 'warning',
|
||||
disabled: !pauseAction,
|
||||
onClick: async () =>
|
||||
handleStatusAction(row, {
|
||||
actionCode: pauseAction?.actionCode ?? 'pause',
|
||||
actionName: pauseAction?.actionName ?? '暂停',
|
||||
needReason: pauseAction?.needReason ?? false
|
||||
})
|
||||
}
|
||||
] satisfies PersonalItemRowAction[])
|
||||
: []),
|
||||
// {
|
||||
// key: 'status-cancel',
|
||||
// tooltip: cancelAction?.actionName ?? '取消',
|
||||
@@ -326,19 +330,23 @@ function buildRowActions(row: Api.PersonalItem.PersonalItem): PersonalItemRowAct
|
||||
// })
|
||||
// },
|
||||
...lifecycleActions,
|
||||
{
|
||||
key: 'status-complete',
|
||||
tooltip: completeAction?.actionName ?? '完成',
|
||||
icon: markRaw(IconMdiCheckCircleOutline),
|
||||
type: 'success',
|
||||
disabled: !completeAction,
|
||||
onClick: async () =>
|
||||
handleStatusAction(row, {
|
||||
actionCode: completeAction?.actionCode ?? 'complete',
|
||||
actionName: completeAction?.actionName ?? '完成',
|
||||
needReason: completeAction?.needReason ?? false
|
||||
})
|
||||
}
|
||||
...(!isCompleted
|
||||
? ([
|
||||
{
|
||||
key: 'status-complete',
|
||||
tooltip: completeAction?.actionName ?? '完成',
|
||||
icon: markRaw(IconMdiCheckCircleOutline),
|
||||
type: 'success',
|
||||
disabled: !completeAction,
|
||||
onClick: async () =>
|
||||
handleStatusAction(row, {
|
||||
actionCode: completeAction?.actionCode ?? 'complete',
|
||||
actionName: completeAction?.actionName ?? '完成',
|
||||
needReason: completeAction?.needReason ?? false
|
||||
})
|
||||
}
|
||||
] satisfies PersonalItemRowAction[])
|
||||
: [])
|
||||
];
|
||||
}
|
||||
|
||||
@@ -452,7 +460,7 @@ async function handleStatusActionSubmit(reason: string | null) {
|
||||
|
||||
async function handleDelete(row: Api.PersonalItem.PersonalItem) {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除个人事项“${row.taskTitle}”吗?`, '删除确认', {
|
||||
await ElMessageBox.confirm(`确定删除我的事项“${row.taskTitle}”吗?`, '删除确认', {
|
||||
type: 'warning',
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消'
|
||||
@@ -473,12 +481,12 @@ async function handleDelete(row: Api.PersonalItem.PersonalItem) {
|
||||
|
||||
async function handleBatchDelete() {
|
||||
if (!checkedRowIds.value.length) {
|
||||
window.$message?.warning('请先选择个人事项');
|
||||
window.$message?.warning('请先选择我的事项');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除选中的 ${selectedCount.value} 条个人事项吗?`, '删除确认', {
|
||||
await ElMessageBox.confirm(`确定删除选中的 ${selectedCount.value} 条我的事项吗?`, '删除确认', {
|
||||
type: 'warning',
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消'
|
||||
@@ -500,7 +508,7 @@ async function handleBatchDelete() {
|
||||
|
||||
function handleOpenBindExecution() {
|
||||
if (!checkedRowIds.value.length) {
|
||||
window.$message?.warning('请先选择个人事项');
|
||||
window.$message?.warning('请先选择我的事项');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -541,7 +549,7 @@ onActivated(() => {
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between gap-12px">
|
||||
<div class="flex items-center gap-10px">
|
||||
<p>个人事项</p>
|
||||
<p>我的事项</p>
|
||||
<ElTag effect="plain">{{ mobilePagination.total || data.length }}</ElTag>
|
||||
</div>
|
||||
<TableHeaderOperation v-model:columns="columnChecks" :loading="loading" @refresh="reloadTable">
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref, watch } from 'vue';
|
||||
import { fetchGetPersonalItemExecutionOptions } from '@/service/api';
|
||||
import {
|
||||
fetchGetMyOwnedProjectPage,
|
||||
fetchGetMyParticipatedProjectPage,
|
||||
fetchGetProjectExecutionPage
|
||||
} from '@/service/api';
|
||||
import { useForm, useFormRules } from '@/hooks/common/form';
|
||||
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
|
||||
|
||||
@@ -28,44 +32,113 @@ const visible = defineModel<boolean>('visible', {
|
||||
const { formRef, validate } = useForm();
|
||||
const { createRequiredRule } = useFormRules();
|
||||
|
||||
const loading = ref(false);
|
||||
const executionOptions = ref<Api.PersonalItem.PersonalItemExecutionOption[]>([]);
|
||||
interface ProjectOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface ExecutionOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const projectLoading = ref(false);
|
||||
const executionLoading = ref(false);
|
||||
const projectOptions = ref<ProjectOption[]>([]);
|
||||
const executionOptions = ref<ExecutionOption[]>([]);
|
||||
const loading = computed(() => projectLoading.value || executionLoading.value);
|
||||
|
||||
const model = reactive({
|
||||
projectId: '',
|
||||
executionId: ''
|
||||
});
|
||||
|
||||
const rules = computed(
|
||||
() =>
|
||||
({
|
||||
projectId: [createRequiredRule('请选择项目')],
|
||||
executionId: [createRequiredRule('请选择执行')]
|
||||
}) satisfies Record<string, App.Global.FormRule[]>
|
||||
);
|
||||
|
||||
function getExecutionOptionLabel(option: Api.PersonalItem.PersonalItemExecutionOption) {
|
||||
if (option.projectName?.trim()) {
|
||||
return `${option.projectName} / ${option.executionName}`;
|
||||
}
|
||||
function createProjectOptions(
|
||||
participated: Api.Project.MyParticipatedProjectItem[],
|
||||
owned: Api.Project.MyOwnedProjectItem[]
|
||||
): ProjectOption[] {
|
||||
const optionMap = new Map<string, ProjectOption>();
|
||||
|
||||
return option.executionName;
|
||||
owned.forEach(item => {
|
||||
if (!item.id || !item.name?.trim()) return;
|
||||
optionMap.set(item.id, {
|
||||
label: item.name.trim(),
|
||||
value: item.id
|
||||
});
|
||||
});
|
||||
|
||||
participated.forEach(item => {
|
||||
if (!item.id || !item.name?.trim()) return;
|
||||
if (item.statusCode === 'completed' || item.statusCode === 'cancelled' || item.statusCode === 'archived') {
|
||||
return;
|
||||
}
|
||||
if (!optionMap.has(item.id)) {
|
||||
optionMap.set(item.id, {
|
||||
label: item.name.trim(),
|
||||
value: item.id
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(optionMap.values());
|
||||
}
|
||||
|
||||
async function loadExecutionOptions() {
|
||||
loading.value = true;
|
||||
const { error, data } = await fetchGetPersonalItemExecutionOptions();
|
||||
loading.value = false;
|
||||
async function loadProjectOptions() {
|
||||
projectLoading.value = true;
|
||||
const [participatedResult, ownedResult] = await Promise.all([
|
||||
fetchGetMyParticipatedProjectPage({ pageNo: 1, pageSize: -1 }),
|
||||
fetchGetMyOwnedProjectPage({ pageNo: 1, pageSize: -1 })
|
||||
]);
|
||||
projectLoading.value = false;
|
||||
|
||||
if (participatedResult.error || ownedResult.error || !participatedResult.data || !ownedResult.data) {
|
||||
projectOptions.value = [];
|
||||
executionOptions.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
projectOptions.value = createProjectOptions(participatedResult.data.list, ownedResult.data.list);
|
||||
}
|
||||
|
||||
async function loadExecutionOptions(projectId: string) {
|
||||
if (!projectId) {
|
||||
executionOptions.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
executionLoading.value = true;
|
||||
const { error, data } = await fetchGetProjectExecutionPage(projectId, {
|
||||
pageNo: 1,
|
||||
pageSize: -1
|
||||
});
|
||||
executionLoading.value = false;
|
||||
|
||||
if (error || !data) {
|
||||
executionOptions.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
executionOptions.value = data.map(item => ({ ...item }));
|
||||
executionOptions.value = data.list
|
||||
.filter(item => !item.terminal && item.statusCode !== 'completed' && item.statusCode !== 'cancelled')
|
||||
.map(item => ({
|
||||
label: item.executionName,
|
||||
value: item.id
|
||||
}));
|
||||
}
|
||||
|
||||
async function initDialog() {
|
||||
model.projectId = '';
|
||||
model.executionId = '';
|
||||
await loadExecutionOptions();
|
||||
executionOptions.value = [];
|
||||
await loadProjectOptions();
|
||||
formRef.value?.clearValidate();
|
||||
}
|
||||
|
||||
@@ -85,42 +158,84 @@ watch(
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => model.projectId,
|
||||
async (projectId, previousProjectId) => {
|
||||
if (projectId === previousProjectId) return;
|
||||
|
||||
model.executionId = '';
|
||||
|
||||
if (!projectId) {
|
||||
executionOptions.value = [];
|
||||
formRef.value?.clearValidate('executionId');
|
||||
return;
|
||||
}
|
||||
|
||||
await loadExecutionOptions(projectId);
|
||||
formRef.value?.clearValidate('executionId');
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BusinessFormDialog
|
||||
v-model="visible"
|
||||
title="批量关联执行"
|
||||
preset="sm"
|
||||
preset="md"
|
||||
:loading="loading"
|
||||
:confirm-loading="props.submitLoading"
|
||||
@confirm="handleConfirm"
|
||||
>
|
||||
<ElAlert
|
||||
:title="`已选中 ${props.selectedCount} 条个人事项,关联成功后这些事项会从当前列表移除。`"
|
||||
:title="`已选中 ${props.selectedCount} 条我的事项,关联成功后这些事项会从当前列表移除。`"
|
||||
type="info"
|
||||
:closable="false"
|
||||
class="mb-16px"
|
||||
/>
|
||||
|
||||
<ElForm ref="formRef" :model="model" :rules="rules" label-position="top" :validate-on-rule-change="false">
|
||||
<ElFormItem label="执行" prop="executionId">
|
||||
<ElSelect
|
||||
v-model="model.executionId"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择执行"
|
||||
class="w-full"
|
||||
:loading="loading"
|
||||
>
|
||||
<ElOption
|
||||
v-for="option in executionOptions"
|
||||
:key="option.executionId"
|
||||
:label="getExecutionOptionLabel(option)"
|
||||
:value="option.executionId"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElRow :gutter="16">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="项目" prop="projectId">
|
||||
<ElSelect
|
||||
v-model="model.projectId"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择项目"
|
||||
class="w-full"
|
||||
:loading="projectLoading"
|
||||
>
|
||||
<ElOption
|
||||
v-for="option in projectOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="执行" prop="executionId">
|
||||
<ElSelect
|
||||
v-model="model.executionId"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择执行"
|
||||
class="w-full"
|
||||
:loading="executionLoading"
|
||||
:disabled="!model.projectId"
|
||||
>
|
||||
<ElOption
|
||||
v-for="option in executionOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</ElForm>
|
||||
</BusinessFormDialog>
|
||||
</template>
|
||||
|
||||
@@ -132,7 +132,7 @@ async function promptCompleteItemIfNeeded() {
|
||||
const { error } = await fetchCompletePersonalItem(detailData.value.id);
|
||||
|
||||
if (!error) {
|
||||
window.$message?.success('个人事项已完成');
|
||||
window.$message?.success('我的事项已完成');
|
||||
await refreshDetail();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,10 +70,10 @@ const model = reactive<Model>(createDefaultModel());
|
||||
|
||||
const title = computed(() => {
|
||||
if (isView.value) {
|
||||
return '个人事项详情';
|
||||
return '我的事项详情';
|
||||
}
|
||||
|
||||
return isEdit.value ? '编辑个人事项' : '新增个人事项';
|
||||
return isEdit.value ? '编辑我的事项' : '新增我的事项';
|
||||
});
|
||||
|
||||
function createDefaultModel(): Model {
|
||||
@@ -195,7 +195,7 @@ async function handleSubmit() {
|
||||
|
||||
await Promise.all([attachmentUploaderRef.value?.commit(), richTextEditorRef.value?.commit()]);
|
||||
|
||||
window.$message?.success(isEdit.value ? '个人事项修改成功' : '个人事项创建成功');
|
||||
window.$message?.success(isEdit.value ? '我的事项修改成功' : '我的事项创建成功');
|
||||
visible.value = false;
|
||||
emit('submitted');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user