237 lines
7.9 KiB
Vue
237 lines
7.9 KiB
Vue
<script setup lang="ts">
|
|
import { computed, nextTick, reactive, watch } from 'vue';
|
|
import { useForm, useFormRules } from '@/hooks/common/form';
|
|
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
|
|
import BusinessFormSection from '@/components/custom/business-form-section.vue';
|
|
import BusinessUserSelect from '@/components/custom/business-user-select.vue';
|
|
import { getPreviousManagerRoleOptions, shouldRequireManagerHandover } from '../shared';
|
|
|
|
defineOptions({ name: 'MemberOperateDialog' });
|
|
|
|
type OperateMode = 'create' | 'edit';
|
|
|
|
interface Props {
|
|
mode: OperateMode;
|
|
member: Api.Product.ProductMember | null;
|
|
currentManager: Api.Product.ProductMember | null;
|
|
roleOptions: Api.SystemManage.RoleSimple[];
|
|
userOptions: Api.SystemManage.UserSimple[];
|
|
/** 已是有效成员、需在下拉中禁选并标记"已添加"的 userId 集合 */
|
|
disabledUserIds?: readonly string[];
|
|
}
|
|
|
|
interface SubmitPayload {
|
|
mode: OperateMode;
|
|
memberId?: string;
|
|
managerChanged: boolean;
|
|
payload: Api.Product.CreateProductMemberParams | Api.Product.UpdateProductMemberParams;
|
|
}
|
|
|
|
interface Emits {
|
|
(e: 'submit', payload: SubmitPayload): void;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
disabledUserIds: () => []
|
|
});
|
|
const emit = defineEmits<Emits>();
|
|
|
|
const visible = defineModel<boolean>('visible', {
|
|
default: false
|
|
});
|
|
|
|
const { formRef, validate } = useForm();
|
|
const { createRequiredRule } = useFormRules();
|
|
|
|
interface Model {
|
|
userId: string;
|
|
roleId: string;
|
|
remark: string;
|
|
reason: string;
|
|
previousManagerRoleId: string;
|
|
}
|
|
|
|
const model = reactive<Model>({
|
|
userId: '',
|
|
roleId: '',
|
|
remark: '',
|
|
reason: '',
|
|
previousManagerRoleId: ''
|
|
});
|
|
|
|
const dialogTitle = computed(() => (props.mode === 'create' ? '新增团队成员' : '调整成员角色'));
|
|
const selectedUserId = computed(() => (props.mode === 'create' ? model.userId : props.member?.userId || ''));
|
|
const showManagerHandover = computed(() => {
|
|
return (
|
|
shouldRequireManagerHandover(model.roleId, props.currentManager) &&
|
|
Boolean(selectedUserId.value) &&
|
|
selectedUserId.value !== props.currentManager?.userId
|
|
);
|
|
});
|
|
const previousManagerRoleOptions = computed(() =>
|
|
getPreviousManagerRoleOptions(props.roleOptions, props.currentManager?.roleId || '')
|
|
);
|
|
const userLabelMap = computed(() => new Map(props.userOptions.map(item => [item.id, item.nickname])));
|
|
|
|
const rules = computed(
|
|
() =>
|
|
({
|
|
userId: props.mode === 'create' ? [createRequiredRule('请选择成员用户')] : [],
|
|
roleId: [createRequiredRule('请选择角色')],
|
|
previousManagerRoleId: showManagerHandover.value ? [createRequiredRule('请选择原产品经理交接后角色')] : []
|
|
}) satisfies Record<string, App.Global.FormRule[]>
|
|
);
|
|
|
|
async function handleConfirm() {
|
|
await validate();
|
|
|
|
const sharedPayload = {
|
|
roleId: model.roleId,
|
|
remark: model.remark.trim() || null,
|
|
previousManagerUserId: showManagerHandover.value ? props.currentManager?.userId || null : null,
|
|
previousManagerRoleId: showManagerHandover.value ? model.previousManagerRoleId : null
|
|
};
|
|
|
|
if (props.mode === 'create') {
|
|
emit('submit', {
|
|
mode: 'create',
|
|
managerChanged: showManagerHandover.value,
|
|
payload: {
|
|
userId: model.userId,
|
|
roleId: sharedPayload.roleId,
|
|
remark: sharedPayload.remark,
|
|
previousManagerUserId: sharedPayload.previousManagerUserId,
|
|
previousManagerRoleId: sharedPayload.previousManagerRoleId
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
|
|
emit('submit', {
|
|
mode: 'edit',
|
|
memberId: props.member?.id,
|
|
managerChanged: showManagerHandover.value,
|
|
payload: {
|
|
roleId: sharedPayload.roleId,
|
|
remark: sharedPayload.remark,
|
|
reason: model.reason.trim() || null,
|
|
previousManagerUserId: sharedPayload.previousManagerUserId,
|
|
previousManagerRoleId: sharedPayload.previousManagerRoleId
|
|
}
|
|
});
|
|
}
|
|
|
|
watch(
|
|
() => visible.value,
|
|
async value => {
|
|
if (!value) {
|
|
return;
|
|
}
|
|
|
|
model.userId = props.mode === 'create' ? '' : props.member?.userId || '';
|
|
model.roleId = props.mode === 'create' ? '' : props.member?.roleId || '';
|
|
model.remark = props.mode === 'create' ? '' : props.member?.remark || '';
|
|
model.reason = '';
|
|
model.previousManagerRoleId = '';
|
|
|
|
await nextTick();
|
|
formRef.value?.clearValidate();
|
|
}
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<BusinessFormDialog v-model="visible" :title="dialogTitle" preset="sm" @confirm="handleConfirm">
|
|
<ElForm ref="formRef" :model="model" :rules="rules" label-position="top" :validate-on-rule-change="false">
|
|
<BusinessFormSection title="成员信息">
|
|
<ElRow :gutter="16">
|
|
<ElCol :span="24">
|
|
<ElFormItem v-if="mode === 'create'" label="成员用户" prop="userId">
|
|
<BusinessUserSelect
|
|
v-model="model.userId"
|
|
:options="userOptions"
|
|
:disabled-user-ids="props.disabledUserIds"
|
|
disabled-label="已添加"
|
|
placeholder="请选择成员用户"
|
|
/>
|
|
</ElFormItem>
|
|
<ElFormItem v-else label="成员用户">
|
|
<ElInput
|
|
:model-value="member?.userNickname || userLabelMap.get(member?.userId || '') || ''"
|
|
readonly
|
|
class="member-operate-dialog__readonly-input"
|
|
placeholder="未获取到成员用户"
|
|
/>
|
|
</ElFormItem>
|
|
</ElCol>
|
|
<ElCol :span="24">
|
|
<ElFormItem label="目标角色" prop="roleId">
|
|
<ElSelect v-model="model.roleId" class="w-full" placeholder="请选择角色">
|
|
<ElOption v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
|
|
</ElSelect>
|
|
</ElFormItem>
|
|
</ElCol>
|
|
<ElCol :span="24">
|
|
<ElFormItem label="备注">
|
|
<ElInput
|
|
v-model="model.remark"
|
|
type="textarea"
|
|
:rows="3"
|
|
maxlength="500"
|
|
show-word-limit
|
|
placeholder="请输入备注"
|
|
/>
|
|
</ElFormItem>
|
|
</ElCol>
|
|
</ElRow>
|
|
</BusinessFormSection>
|
|
|
|
<BusinessFormSection v-if="mode === 'edit'" title="角色调整说明">
|
|
<ElFormItem label="变更原因">
|
|
<ElInput
|
|
v-model="model.reason"
|
|
type="textarea"
|
|
:rows="3"
|
|
maxlength="500"
|
|
show-word-limit
|
|
placeholder="请输入变更原因"
|
|
/>
|
|
</ElFormItem>
|
|
</BusinessFormSection>
|
|
|
|
<BusinessFormSection v-if="showManagerHandover" title="产品经理交接">
|
|
<ElAlert
|
|
:title="`当前产品经理 ${currentManager?.userNickname || currentManager?.userId || ''} 将完成交接,请选择其交接后角色。`"
|
|
type="warning"
|
|
:closable="false"
|
|
class="mb-16px"
|
|
/>
|
|
<ElFormItem label="原产品经理交接后角色" prop="previousManagerRoleId">
|
|
<ElSelect v-model="model.previousManagerRoleId" class="w-full" placeholder="请选择原产品经理交接后角色">
|
|
<ElOption v-for="item in previousManagerRoleOptions" :key="item.id" :label="item.name" :value="item.id" />
|
|
</ElSelect>
|
|
</ElFormItem>
|
|
</BusinessFormSection>
|
|
</ElForm>
|
|
</BusinessFormDialog>
|
|
</template>
|
|
|
|
<style scoped>
|
|
:deep(.member-operate-dialog__readonly-input .el-input__wrapper) {
|
|
background: linear-gradient(180deg, rgb(241 245 249 / 98%), rgb(226 232 240 / 94%)), rgb(241 245 249);
|
|
box-shadow: 0 0 0 1px rgb(203 213 225 / 96%) inset;
|
|
cursor: default;
|
|
}
|
|
|
|
:deep(.member-operate-dialog__readonly-input .el-input__wrapper:hover),
|
|
:deep(.member-operate-dialog__readonly-input.is-focus .el-input__wrapper) {
|
|
box-shadow: 0 0 0 1px rgb(203 213 225 / 96%) inset;
|
|
}
|
|
|
|
:deep(.member-operate-dialog__readonly-input .el-input__inner) {
|
|
color: rgb(51 65 85 / 96%);
|
|
cursor: default;
|
|
-webkit-text-fill-color: rgb(51 65 85 / 96%);
|
|
}
|
|
</style>
|