<script setup lang="tsx">
|
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
import type { DataTableRowKey } from 'naive-ui';
|
import { NDivider } from 'naive-ui';
|
import { jsonClone } from '@sa/utils';
|
import { fetchBatchDeleteJudgeDetails, fetchGetJudgeDetailsTree } from '@/service/api/qm/judge-details';
|
import { useAuth } from '@/hooks/business/auth';
|
import { useNaiveTable } from '@/hooks/common/table';
|
import { $t } from '@/locales';
|
import ButtonIcon from '@/components/custom/button-icon.vue';
|
import JudgeDetailsOperateDrawer from './judge-details-operate-drawer.vue';
|
|
defineOptions({
|
name: 'JudgeDetailsSubTable'
|
});
|
|
interface Props {
|
judgeId?: CommonType.IdType | null;
|
}
|
|
const props = withDefaults(defineProps<Props>(), {
|
judgeId: null
|
});
|
|
interface JudgeDetailsSubRow extends Api.Qm.JudgeDetails {
|
children?: JudgeDetailsSubRow[];
|
}
|
|
const { hasAuth } = useAuth();
|
|
const checkedRowKeys = ref<CommonType.IdType[]>([]);
|
const drawerVisible = ref(false);
|
const operateType = ref<NaiveUI.TableOperateType>('add');
|
const editingData = ref<Api.Qm.JudgeDetails | null>(null);
|
const showFullscreen = ref(false);
|
const fullscreenStyle = ref<Record<string, string>>({});
|
|
function handleAdd() {
|
if (!props.judgeId) {
|
window.$message?.warning('请先选择判定依据');
|
return;
|
}
|
operateType.value = 'add';
|
editingData.value = { judgeId: props.judgeId } as any;
|
drawerVisible.value = true;
|
}
|
|
function handleEdit(row: JudgeDetailsSubRow) {
|
operateType.value = 'edit';
|
editingData.value = jsonClone(row);
|
drawerVisible.value = true;
|
}
|
|
async function handleBatchDelete() {
|
if (checkedRowKeys.value.length === 0) return;
|
const { error } = await fetchBatchDeleteJudgeDetails(checkedRowKeys.value);
|
if (error) return;
|
window.$message?.success($t('common.deleteSuccess'));
|
checkedRowKeys.value = [];
|
await getData();
|
}
|
|
async function handleDelete(id: CommonType.IdType) {
|
const { error } = await fetchBatchDeleteJudgeDetails([id]);
|
if (error) return;
|
window.$message?.success($t('common.deleteSuccess'));
|
await getData();
|
}
|
|
const {
|
columns,
|
columnChecks,
|
data: rows,
|
loading,
|
getData,
|
scrollX
|
} = useNaiveTable<Api.Common.PaginatingQueryRecord<Api.Qm.JudgeDetails>, Api.Qm.JudgeDetails>({
|
api: async () => {
|
if (!props.judgeId) return { rows: [], total: 0, pageNum: 1 } as any;
|
const { data } = await fetchGetJudgeDetailsTree({
|
pageNum: 1,
|
pageSize: 9999,
|
judgeId: props.judgeId
|
});
|
return data;
|
},
|
columns: () => [
|
{
|
type: 'selection',
|
align: 'center',
|
width: 48
|
},
|
{
|
key: 'index',
|
title: $t('common.index'),
|
align: 'center',
|
width: 56,
|
render: (_: any, index: number) => index + 1
|
},
|
{
|
key: 'itemName',
|
title: '判定项',
|
align: 'left',
|
width: 250,
|
tree: true
|
} as any,
|
{
|
key: 'value3',
|
title: '标准值',
|
align: 'center',
|
width: 100
|
},
|
{
|
key: 'value1',
|
title: '下限值',
|
align: 'center',
|
width: 100
|
},
|
{
|
key: 'value2',
|
title: '上限值',
|
align: 'center',
|
width: 100
|
},
|
{
|
key: 'cls',
|
title: '级别',
|
align: 'center',
|
width: 80
|
},
|
{
|
key: 'stdscore',
|
title: '分值',
|
align: 'center',
|
minWidth: 150
|
},
|
{
|
key: 'decisionDes',
|
title: '备注',
|
align: 'center',
|
minWidth: 150
|
},
|
{
|
key: 'updateUser',
|
title: '修改人',
|
align: 'center',
|
minWidth: 150
|
},
|
{
|
key: 'operate',
|
title: $t('common.operate'),
|
fixed: 'right',
|
align: 'center',
|
width: 130,
|
render: (row: any) => {
|
const divider = () => {
|
if (!hasAuth('qm:judgeDetails:edit') || !hasAuth('qm:judgeDetails:remove')) {
|
return null;
|
}
|
return <NDivider vertical />;
|
};
|
|
const editBtn = () => {
|
if (!hasAuth('qm:judgeDetails:edit')) {
|
return null;
|
}
|
return (
|
<ButtonIcon
|
text
|
type="primary"
|
icon="material-symbols:drive-file-rename-outline-outline"
|
tooltipContent={$t('common.edit')}
|
onClick={() => handleEdit(row)}
|
/>
|
);
|
};
|
|
const deleteBtn = () => {
|
if (!hasAuth('qm:judgeDetails:remove')) {
|
return null;
|
}
|
return (
|
<ButtonIcon
|
text
|
type="error"
|
icon="material-symbols:delete-outline"
|
tooltipContent={$t('common.delete')}
|
popconfirmContent={$t('common.confirmDelete')}
|
onPositiveClick={() => handleDelete(row.id)}
|
/>
|
);
|
};
|
|
return (
|
<div class="flex-center gap-8px">
|
{editBtn()}
|
{divider()}
|
{deleteBtn()}
|
</div>
|
);
|
}
|
}
|
],
|
transform: response => {
|
return response?.rows || [];
|
}
|
});
|
|
const onFullscreenKeydown = (event: KeyboardEvent) => {
|
if (event.key === 'Escape') {
|
showFullscreen.value = false;
|
}
|
};
|
|
const cardTitle = computed(() => `判定明细维护`);
|
|
watch(
|
() => props.judgeId,
|
async () => {
|
checkedRowKeys.value = [];
|
await getData();
|
},
|
{ immediate: true }
|
);
|
|
watch(
|
showFullscreen,
|
visible => {
|
if (visible) {
|
updateFullscreenStyle();
|
window.addEventListener('keydown', onFullscreenKeydown);
|
window.addEventListener('resize', updateFullscreenStyle);
|
window.addEventListener('scroll', updateFullscreenStyle, true);
|
return;
|
}
|
window.removeEventListener('keydown', onFullscreenKeydown);
|
window.removeEventListener('resize', updateFullscreenStyle);
|
window.removeEventListener('scroll', updateFullscreenStyle, true);
|
},
|
{ immediate: true }
|
);
|
|
onBeforeUnmount(() => {
|
window.removeEventListener('keydown', onFullscreenKeydown);
|
window.removeEventListener('resize', updateFullscreenStyle);
|
window.removeEventListener('scroll', updateFullscreenStyle, true);
|
});
|
|
onMounted(() => {
|
updateFullscreenStyle();
|
});
|
|
function updateFullscreenStyle() {
|
const container = document.querySelector<HTMLElement>('.judge-content-area');
|
if (!container) {
|
fullscreenStyle.value = {
|
position: 'fixed',
|
inset: '0',
|
zIndex: '20'
|
};
|
return;
|
}
|
const rect = container.getBoundingClientRect();
|
fullscreenStyle.value = {
|
position: 'fixed',
|
left: `${rect.left}px`,
|
top: `${rect.top}px`,
|
width: `${rect.width}px`,
|
height: `${rect.height}px`,
|
zIndex: '20'
|
};
|
}
|
|
function rowKey(row: JudgeDetailsSubRow): DataTableRowKey {
|
return String(row.id);
|
}
|
</script>
|
|
<template>
|
<div class="flex-col-stretch">
|
<NCard
|
:title="cardTitle"
|
:bordered="false"
|
size="small"
|
class="flex-col-stretch card-wrapper flex-1-hidden"
|
:content-style="{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }"
|
>
|
<template #header-extra>
|
<NSpace align="center">
|
<TableHeaderOperation
|
v-model:columns="columnChecks"
|
:disabled-delete="checkedRowKeys.length === 0"
|
:loading="loading"
|
:show-add="hasAuth('qm:judgeDetails:add')"
|
:show-delete="hasAuth('qm:judgeDetails:remove')"
|
:show-export="false"
|
@add="handleAdd"
|
@delete="handleBatchDelete"
|
@refresh="getData"
|
/>
|
<NButton size="small" @click="showFullscreen = true">
|
<template #icon>
|
<icon-mdi-fullscreen class="text-icon" />
|
</template>
|
全屏
|
</NButton>
|
</NSpace>
|
</template>
|
|
<NSpin :show="loading" class="h-full" content-class="h-full flex-col-stretch flex-1-hidden">
|
<div v-if="!props.judgeId" class="h-full flex-center text-gray-400">请点击上方表格行查看明细</div>
|
<NDataTable
|
v-else
|
v-model:checked-row-keys="checkedRowKeys"
|
:columns="columns"
|
:data="rows"
|
size="small"
|
flex-height
|
children-key="children"
|
:row-key="rowKey"
|
default-expand-all
|
striped
|
class="flex-1-hidden"
|
/>
|
</NSpin>
|
</NCard>
|
|
<Teleport to="body">
|
<div v-if="showFullscreen" class="fullscreen-mask" :style="fullscreenStyle" @click.self="showFullscreen = false">
|
<NCard
|
:title="cardTitle"
|
:bordered="false"
|
size="small"
|
class="fullscreen-card flex-col-stretch"
|
:content-style="{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }"
|
>
|
<template #header-extra>
|
<NSpace align="center">
|
<TableHeaderOperation
|
v-model:columns="columnChecks"
|
:disabled-delete="checkedRowKeys.length === 0"
|
:loading="loading"
|
:show-add="hasAuth('qm:judgeDetails:add')"
|
:show-delete="hasAuth('qm:judgeDetails:remove')"
|
:show-export="false"
|
@add="handleAdd"
|
@delete="handleBatchDelete"
|
@refresh="getData"
|
/>
|
<NButton size="small" ghost type="error" @click="showFullscreen = false">
|
<template #icon>
|
<icon-mdi-close class="text-icon" />
|
</template>
|
关闭
|
</NButton>
|
</NSpace>
|
</template>
|
|
<NSpin :show="loading" class="h-full" content-class="h-full">
|
<div v-if="!props.judgeId" class="h-full flex-center text-gray-400">请点击上方表格行查看明细</div>
|
<NDataTable
|
v-else
|
v-model:checked-row-keys="checkedRowKeys"
|
:columns="columns"
|
:data="rows"
|
size="small"
|
flex-height
|
children-key="children"
|
:row-key="rowKey"
|
striped
|
class="fullscreen-table"
|
/>
|
</NSpin>
|
</NCard>
|
</div>
|
</Teleport>
|
|
<JudgeDetailsOperateDrawer
|
v-model:visible="drawerVisible"
|
:operate-type="operateType"
|
:row-data="editingData"
|
@submitted="getData"
|
/>
|
</div>
|
</template>
|
|
<style scoped>
|
:deep(.n-card__content) {
|
padding: 8px 12px;
|
}
|
|
:deep(.n-data-table-th),
|
:deep(.n-data-table-td) {
|
padding: 4px 6px;
|
}
|
|
.fullscreen-mask {
|
position: absolute;
|
inset: 0;
|
z-index: 20;
|
background: #fff;
|
padding: 0;
|
display: flex;
|
}
|
|
.fullscreen-card {
|
width: 100%;
|
height: 100%;
|
}
|
|
.fullscreen-table {
|
height: 100%;
|
}
|
</style>
|