old mode 100644
new mode 100755
| | |
| | | <script setup lang="tsx"> |
| | | import { computed, ref, watch } from 'vue'; |
| | | import { useLoading } from '@sa/hooks'; |
| | | import { $t } from '@/locales'; |
| | | import { fetchGetCheckitemTree } from '@/service/api/qm/checkitem'; |
| | | import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'; |
| | | import type { DataTableColumns, DataTableRowKey } from 'naive-ui'; |
| | | import { NDivider } from 'naive-ui'; |
| | | import { useLoading } from '@sa/hooks'; |
| | | import { jsonClone } from '@sa/utils'; |
| | | import { fetchBatchDeleteCheckitem, fetchGetCheckitemTree } from '@/service/api/qm/checkitem'; |
| | | import { useAuth } from '@/hooks/business/auth'; |
| | | import { $t } from '@/locales'; |
| | | import ButtonIcon from '@/components/custom/button-icon.vue'; |
| | | import CheckitemOperateDrawer from '@/views/qm/checkitem/modules/checkitem-operate-drawer.vue'; |
| | | |
| | | defineOptions({ |
| | | name: 'StdSubTable' |
| | |
| | | |
| | | interface Props { |
| | | stdId?: CommonType.IdType | null; |
| | | stdCode?: string | ''; |
| | | } |
| | | |
| | | const props = withDefaults(defineProps<Props>(), { |
| | | stdId: null |
| | | stdId: null, |
| | | stdCode: '' |
| | | }); |
| | | |
| | | interface StdSubRow extends Api.Qm.Checkitem { |
| | |
| | | } |
| | | |
| | | const { loading, startLoading, endLoading } = useLoading(); |
| | | const { hasAuth } = useAuth(); |
| | | const rows = ref<StdSubRow[]>([]); |
| | | const checkedRowKeys = ref<CommonType.IdType[]>([]); |
| | | const drawerVisible = ref(false); |
| | | const operateType = ref<NaiveUI.TableOperateType>('add'); |
| | | const editingData = ref<Api.Qm.Checkitem | null>(null); |
| | | const showFullscreen = ref(false); |
| | | const fullscreenStyle = ref<Record<string, string>>({}); |
| | | const onFullscreenKeydown = (event: KeyboardEvent) => { |
| | | if (event.key === 'Escape') { |
| | | showFullscreen.value = false; |
| | | } |
| | | }; |
| | | |
| | | const cardTitle = computed(() => `规程明细${props.stdCode || ''}`); |
| | | |
| | | async function getSubList() { |
| | | if (!props.stdId) { |
| | | if (!props.stdId && !props.stdCode) { |
| | | rows.value = []; |
| | | return; |
| | | } |
| | |
| | | const { data, error } = await fetchGetCheckitemTree({ |
| | | pageNum: 1, |
| | | pageSize: 9999, |
| | | stdCode: String(props.stdId) |
| | | stdCode: props.stdId != null ? String(props.stdId) : String(props.stdCode) |
| | | }); |
| | | if (error) { |
| | | rows.value = []; |
| | |
| | | } |
| | | |
| | | watch( |
| | | () => props.stdId, |
| | | () => [props.stdId, props.stdCode], |
| | | async () => { |
| | | checkedRowKeys.value = []; |
| | | await getSubList(); |
| | | }, |
| | | { 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>('.std-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 handleAdd() { |
| | | if (!props.stdId && !props.stdCode) { |
| | | window.$message?.warning('请先选择规程'); |
| | | return; |
| | | } |
| | | operateType.value = 'add'; |
| | | editingData.value = null; |
| | | drawerVisible.value = true; |
| | | } |
| | | |
| | | function handleEdit(row: StdSubRow) { |
| | | operateType.value = 'edit'; |
| | | editingData.value = jsonClone(row); |
| | | drawerVisible.value = true; |
| | | } |
| | | |
| | | async function handleBatchDelete() { |
| | | if (checkedRowKeys.value.length === 0) return; |
| | | const { error } = await fetchBatchDeleteCheckitem(checkedRowKeys.value); |
| | | if (error) return; |
| | | window.$message?.success($t('common.deleteSuccess')); |
| | | checkedRowKeys.value = []; |
| | | await getSubList(); |
| | | } |
| | | |
| | | async function handleDelete(id: CommonType.IdType) { |
| | | const { error } = await fetchBatchDeleteCheckitem([id]); |
| | | if (error) return; |
| | | window.$message?.success($t('common.deleteSuccess')); |
| | | await getSubList(); |
| | | } |
| | | |
| | | const columns = computed<DataTableColumns<StdSubRow>>(() => [ |
| | | { |
| | | type: 'selection', |
| | | align: 'center', |
| | | width: 48 |
| | | }, |
| | | { |
| | | key: 'index', |
| | | title: $t('common.index'), |
| | |
| | | title: '描述', |
| | | align: 'center', |
| | | minWidth: 160 |
| | | }, |
| | | { |
| | | key: 'operate', |
| | | title: $t('common.operate'), |
| | | align: 'center', |
| | | width: 130, |
| | | render: row => { |
| | | const divider = () => { |
| | | if (!hasAuth('qm:checkitem:edit') || !hasAuth('qm:checkitem:remove')) { |
| | | return null; |
| | | } |
| | | return <NDivider vertical />; |
| | | }; |
| | | |
| | | const editBtn = () => { |
| | | if (!hasAuth('qm:checkitem: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:checkitem: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> |
| | | ); |
| | | } |
| | | } |
| | | ]); |
| | | |
| | |
| | | |
| | | <template> |
| | | <NCard |
| | | title="规程明细" |
| | | :title="cardTitle" |
| | | :bordered="false" |
| | | size="small" |
| | | class="flex-col-stretch card-wrapper" |
| | | :content-style="{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }" |
| | | > |
| | | <template #header-extra> |
| | | <span class="text-13px text-gray-500">{{ props.stdId ? `STD CODE:${props.stdId}` : '' }}</span> |
| | | <NSpace align="center"> |
| | | <TableHeaderOperation |
| | | :disabled-delete="checkedRowKeys.length === 0" |
| | | :loading="loading" |
| | | :show-add="hasAuth('qm:checkitem:add')" |
| | | :show-delete="hasAuth('qm:checkitem:remove')" |
| | | :show-export="false" |
| | | @add="handleAdd" |
| | | @delete="handleBatchDelete" |
| | | @refresh="getSubList" |
| | | /> |
| | | <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"> |
| | | <div v-if="!props.stdId" class="h-full flex-center text-gray-400">请点击上方表格行查看明细</div> |
| | | <div v-if="!props.stdId && !props.stdCode" class="h-full flex-center text-gray-400">请点击上方表格行查看明细</div> |
| | | <NDataTable |
| | | v-else |
| | | v-model:checked-row-keys="checkedRowKeys" |
| | | :columns="columns as any" |
| | | :data="rows" |
| | | size="small" |
| | |
| | | /> |
| | | </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 |
| | | :disabled-delete="checkedRowKeys.length === 0" |
| | | :loading="loading" |
| | | :show-add="hasAuth('qm:checkitem:add')" |
| | | :show-delete="hasAuth('qm:checkitem:remove')" |
| | | :show-export="false" |
| | | @add="handleAdd" |
| | | @delete="handleBatchDelete" |
| | | @refresh="getSubList" |
| | | /> |
| | | <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.stdId && !props.stdCode" class="h-full flex-center text-gray-400"> |
| | | 请点击上方表格行查看明细 |
| | | </div> |
| | | <NDataTable |
| | | v-else |
| | | v-model:checked-row-keys="checkedRowKeys" |
| | | :columns="columns as any" |
| | | :data="rows" |
| | | size="small" |
| | | flex-height |
| | | children-key="children" |
| | | :row-key="rowKey" |
| | | striped |
| | | class="fullscreen-table" |
| | | /> |
| | | </NSpin> |
| | | </NCard> |
| | | </div> |
| | | </Teleport> |
| | | |
| | | <CheckitemOperateDrawer |
| | | v-model:visible="drawerVisible" |
| | | :operate-type="operateType" |
| | | :row-data="editingData" |
| | | :std-code="props.stdId" |
| | | @submitted="getSubList" |
| | | /> |
| | | </template> |
| | | |
| | | <style scoped> |
| | |
| | | :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> |