265 lines
7.7 KiB
Vue
265 lines
7.7 KiB
Vue
<script setup lang="tsx">
|
|
import { computed, ref, watch } from 'vue';
|
|
import { ElButton, ElEmpty, ElTag } from 'element-plus';
|
|
import dayjs from 'dayjs';
|
|
import {
|
|
fetchDeleteOrgLeaderRelation,
|
|
fetchGetOrgLeaderCandidateUsers,
|
|
fetchGetOrgLeaderListByDept,
|
|
fetchGetUserPage
|
|
} from '@/service/api';
|
|
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
|
|
import BusinessTableActionCell from '@/components/custom/business-table-action-cell';
|
|
import { $t } from '@/locales';
|
|
import UserOrgLeaderOperateDialog from './user-org-leader-operate-dialog.vue';
|
|
|
|
defineOptions({ name: 'UserOrgLeaderDialog' });
|
|
|
|
interface Props {
|
|
dept?: Api.SystemManage.Dept | null;
|
|
}
|
|
|
|
const props = defineProps<Props>();
|
|
|
|
const visible = defineModel<boolean>('visible', {
|
|
default: false
|
|
});
|
|
|
|
const loading = ref(false);
|
|
const relations = ref<Api.SystemManage.OrgLeaderRelation[]>([]);
|
|
const candidateUsers = ref<Api.SystemManage.OrgLeaderCandidateUser[]>([]);
|
|
const operateVisible = ref(false);
|
|
const operateType = ref<UI.TableOperateType>('add');
|
|
const editingData = ref<Api.SystemManage.OrgLeaderRelation | null>(null);
|
|
|
|
const title = computed(() => {
|
|
if (props.dept?.name) {
|
|
return `${$t('page.system.user.orgLeaderTitle')} / ${props.dept.name}`;
|
|
}
|
|
|
|
return $t('page.system.user.orgLeaderTitle');
|
|
});
|
|
|
|
const total = computed(() => relations.value.length);
|
|
|
|
function formatTime(value?: number | null) {
|
|
if (!value) {
|
|
return '--';
|
|
}
|
|
|
|
return dayjs(value).format('YYYY-MM-DD HH:mm:ss');
|
|
}
|
|
|
|
function isCandidateUser(item: unknown): item is Api.SystemManage.OrgLeaderCandidateUser {
|
|
if (!item || typeof item !== 'object') {
|
|
return false;
|
|
}
|
|
|
|
const record = item as Record<string, unknown>;
|
|
|
|
return typeof record.id === 'number' && typeof record.nickname === 'string' && typeof record.deptId === 'number';
|
|
}
|
|
|
|
function mapUsersToCandidateUsers(users: Api.SystemManage.User[]): Api.SystemManage.OrgLeaderCandidateUser[] {
|
|
const now = Date.now();
|
|
|
|
return users
|
|
.filter(item => !item.resignedAt || item.resignedAt > now)
|
|
.map(item => ({
|
|
id: String(item.id),
|
|
nickname: item.nickname?.trim() || item.username,
|
|
deptId: item.deptId,
|
|
deptName: item.deptName ?? null
|
|
}));
|
|
}
|
|
|
|
async function loadCandidateUsers(deptId: number) {
|
|
const candidateResult = await fetchGetOrgLeaderCandidateUsers(deptId);
|
|
|
|
if (!candidateResult.error && Array.isArray(candidateResult.data) && candidateResult.data.every(isCandidateUser)) {
|
|
return candidateResult.data;
|
|
}
|
|
|
|
const userResult = await fetchGetUserPage({
|
|
pageNo: 1,
|
|
pageSize: 200,
|
|
deptId,
|
|
status: 0
|
|
});
|
|
|
|
if (userResult.error) {
|
|
return [];
|
|
}
|
|
|
|
return mapUsersToCandidateUsers(userResult.data.list);
|
|
}
|
|
|
|
async function loadData() {
|
|
if (!props.dept?.id) {
|
|
relations.value = [];
|
|
candidateUsers.value = [];
|
|
return;
|
|
}
|
|
|
|
loading.value = true;
|
|
|
|
const [relationResult, candidates] = await Promise.all([
|
|
fetchGetOrgLeaderListByDept(props.dept.id),
|
|
loadCandidateUsers(props.dept.id)
|
|
]);
|
|
|
|
loading.value = false;
|
|
|
|
relations.value = relationResult.error ? [] : relationResult.data;
|
|
candidateUsers.value = candidates;
|
|
}
|
|
|
|
function openAdd() {
|
|
operateType.value = 'add';
|
|
editingData.value = null;
|
|
operateVisible.value = true;
|
|
}
|
|
|
|
function openEdit(row: Api.SystemManage.OrgLeaderRelation) {
|
|
operateType.value = 'edit';
|
|
editingData.value = row;
|
|
operateVisible.value = true;
|
|
}
|
|
|
|
async function handleDelete(row: Api.SystemManage.OrgLeaderRelation) {
|
|
const { error } = await fetchDeleteOrgLeaderRelation(row.id);
|
|
|
|
if (error) {
|
|
return;
|
|
}
|
|
|
|
window.$message?.success($t('common.deleteSuccess'));
|
|
await loadData();
|
|
}
|
|
|
|
async function handleDeleteAction(row: Api.SystemManage.OrgLeaderRelation) {
|
|
try {
|
|
await window.$messageBox?.confirm($t('common.confirmDelete'), $t('common.warning'), {
|
|
confirmButtonText: $t('common.confirm'),
|
|
cancelButtonText: $t('common.cancel'),
|
|
type: 'warning'
|
|
});
|
|
} catch {
|
|
return;
|
|
}
|
|
|
|
await handleDelete(row);
|
|
}
|
|
|
|
async function handleSubmitted() {
|
|
operateVisible.value = false;
|
|
await loadData();
|
|
}
|
|
|
|
watch(
|
|
() => [visible.value, props.dept?.id] as const,
|
|
async ([dialogVisible, deptId]) => {
|
|
if (!dialogVisible || !deptId) {
|
|
return;
|
|
}
|
|
|
|
await loadData();
|
|
}
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<BusinessFormDialog v-model="visible" :title="title" preset="lg" :show-footer="false">
|
|
<div class="flex-col-stretch gap-16px">
|
|
<div class="flex items-center justify-between gap-12px">
|
|
<div class="flex items-center gap-8px">
|
|
<ElTag type="primary" effect="light">{{ dept?.name || $t('common.noData') }}</ElTag>
|
|
<ElTag effect="plain">{{ total }}</ElTag>
|
|
</div>
|
|
<div class="flex items-center gap-8px">
|
|
<ElButton type="primary" plain size="small" @click="openAdd">
|
|
<template #icon>
|
|
<icon-ic-round-plus class="text-icon" />
|
|
</template>
|
|
{{ $t('common.add') }}
|
|
</ElButton>
|
|
<ElButton plain size="small" @click="loadData">
|
|
<template #icon>
|
|
<icon-mdi-refresh class="text-icon" />
|
|
</template>
|
|
{{ $t('common.refresh') }}
|
|
</ElButton>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-loading="loading" class="min-h-260px">
|
|
<template v-if="relations.length">
|
|
<div class="min-h-260px">
|
|
<ElTable border :data="relations" :max-height="420">
|
|
<ElTableColumn type="index" :label="$t('common.index')" width="64" />
|
|
<ElTableColumn prop="userNickname" :label="$t('page.system.user.orgLeader')" min-width="140" />
|
|
<ElTableColumn
|
|
prop="effectiveFrom"
|
|
:label="$t('page.system.user.effectiveFrom')"
|
|
min-width="170"
|
|
:formatter="row => formatTime(row.effectiveFrom)"
|
|
/>
|
|
<ElTableColumn
|
|
prop="effectiveUntil"
|
|
:label="$t('page.system.user.effectiveUntil')"
|
|
min-width="170"
|
|
:formatter="row => formatTime(row.effectiveUntil)"
|
|
/>
|
|
<ElTableColumn
|
|
prop="remark"
|
|
:label="$t('page.system.user.relationRemark')"
|
|
min-width="180"
|
|
show-overflow-tooltip
|
|
/>
|
|
<ElTableColumn
|
|
prop="createTime"
|
|
:label="$t('page.system.user.createTime')"
|
|
min-width="170"
|
|
:formatter="row => formatTime(row.createTime)"
|
|
/>
|
|
<ElTableColumn :label="$t('common.operate')" width="196" align="center" fixed="right">
|
|
<template #default="{ row }">
|
|
<BusinessTableActionCell
|
|
:actions="[
|
|
{
|
|
key: 'edit',
|
|
label: $t('common.edit'),
|
|
buttonType: 'primary',
|
|
onClick: () => openEdit(row)
|
|
},
|
|
{
|
|
key: 'delete',
|
|
label: $t('common.delete'),
|
|
buttonType: 'danger',
|
|
onClick: () => handleDeleteAction(row)
|
|
}
|
|
]"
|
|
/>
|
|
</template>
|
|
</ElTableColumn>
|
|
</ElTable>
|
|
</div>
|
|
</template>
|
|
|
|
<div v-else class="min-h-260px flex items-center justify-center">
|
|
<ElEmpty :description="$t('page.system.user.emptyLeader')" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<UserOrgLeaderOperateDialog
|
|
v-model:visible="operateVisible"
|
|
:operate-type="operateType"
|
|
:row-data="editingData"
|
|
:dept="dept"
|
|
:candidate-users="candidateUsers"
|
|
@submitted="handleSubmitted"
|
|
/>
|
|
</BusinessFormDialog>
|
|
</template>
|