<script setup lang="tsx">
|
import { computed, ref } from 'vue';
|
import { NDivider } from 'naive-ui';
|
import { fetchBatchDeleteStoreSilk, fetchGetStoreSilkList } from '@/service/api/analy/store-silk';
|
import { useAppStore } from '@/store/modules/app';
|
import { useAuth } from '@/hooks/business/auth';
|
import { useDownload } from '@/hooks/business/download';
|
import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
|
import { $t } from '@/locales';
|
import ButtonIcon from '@/components/custom/button-icon.vue';
|
import StoreSilkOperateDrawer from './modules/store-silk-operate-drawer.vue';
|
import StoreSilkSearch from './modules/store-silk-search.vue';
|
import StoreSilkDetail from './modules/store-silk-detail.vue';
|
import StoreSilkSankey from './modules/store-silk-sankey.vue';
|
|
defineOptions({
|
name: 'StoreSilkList'
|
});
|
|
const appStore = useAppStore();
|
const { download } = useDownload();
|
const { hasAuth } = useAuth();
|
|
|
|
const selectedRollerDetailList = ref<any[]>([]);
|
const selectedPackerDetailList = ref<any[]>([]);
|
|
// 桑基图start
|
const showSankey = ref(false);
|
const rollerRecordList = ref<any[]>([]);
|
const packerRecordList = ref<any[]>([]);
|
// 桑基图end
|
|
const sankeyRollerBoxList = computed(() => {
|
return (rollerRecordList.value || []).map(item => {
|
const v = calcRollerBox((item as any).output);
|
const output = v === null ? null : Number(v.toFixed(2));
|
return { ...(item as any), output };
|
});
|
});
|
|
const sankeyPackerBoxList = computed(() => {
|
return (packerRecordList.value || []).map(item => {
|
const v = calcPackerBox((item as any).output);
|
const output = v === null ? null : Number(v.toFixed(2));
|
return { ...(item as any), output };
|
});
|
});
|
|
const searchParams = ref<Api.Analy.StoreSilkSearchParams>({
|
pageNum: 1,
|
pageSize: 10,
|
materialname: null,
|
batchcode: null,
|
actualstarttime: null,
|
distimebegin: null,
|
distimeend: null,
|
siloid: null,
|
params: {
|
beginTime: `${new Date(new Date().getTime() - 3 * 24 * 60 * 60 * 1000).getFullYear()}-${String(new Date(new Date().getTime() - 3 * 24 * 60 * 60 * 1000).getMonth() + 1).padStart(2, '0')}-${String(new Date(new Date().getTime() - 3 * 24 * 60 * 60 * 1000).getDate()).padStart(2, '0')} 00:00:00`,
|
endTime: `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, '0')}-${String(new Date().getDate()).padStart(2, '0')} 23:59:59`
|
}
|
});
|
|
const tableSize = ref<'small' | 'medium' | 'large'>('small');
|
|
function handleTableSizeChange(size: 'small' | 'medium' | 'large') {
|
tableSize.value = size;
|
}
|
|
const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
|
useNaivePaginatedTable<any, any>({
|
api: () => fetchGetStoreSilkList(searchParams.value),
|
transform: response => {
|
const respData = (response as any).data;
|
const error = (response as any).error;
|
|
if (!error) {
|
const rows = Array.isArray(respData?.rows) ? respData.rows : [];
|
const apiRollerRecordList = respData?.rollerRecordList;
|
const apiPackerRecordList = respData?.packerRecordList;
|
|
rollerRecordList.value =
|
Array.isArray(apiRollerRecordList) && apiRollerRecordList.length > 0
|
? apiRollerRecordList
|
: rows.flatMap((r: any) => (Array.isArray(r?.rollerDetailList) ? r.rollerDetailList : []));
|
|
packerRecordList.value =
|
Array.isArray(apiPackerRecordList) && apiPackerRecordList.length > 0
|
? apiPackerRecordList
|
: rows.flatMap((r: any) => (Array.isArray(r?.packerDetailList) ? r.packerDetailList : []));
|
} else {
|
rollerRecordList.value = [];
|
packerRecordList.value = [];
|
}
|
|
return defaultTransform(response as any);
|
},
|
onPaginationParamsChange: params => {
|
searchParams.value.pageNum = params.page;
|
searchParams.value.pageSize = params.pageSize;
|
},
|
columns: () => [
|
{
|
key: 'index',
|
title: $t('common.index'),
|
align: 'center',
|
width: 64,
|
render: (_, index) => index + 1
|
},
|
{
|
key: 'materialname',
|
title: '牌号',
|
align: 'center',
|
minWidth: 96
|
},
|
{
|
key: 'batchcode',
|
title: '批次号',
|
align: 'center',
|
minWidth: 110
|
},
|
{
|
key: 'rollerOutput',
|
title: '卷接产量(箱)',
|
align: 'center',
|
minWidth: 112,
|
render: row => {
|
const v = calcRollerBox((row as any).rollerOutput);
|
if (v === null) return '-';
|
return v.toFixed(1);
|
}
|
},
|
{
|
key: 'rollerUnitCost',
|
title: '卷接单耗',
|
align: 'center',
|
minWidth: 96,
|
render: row => {
|
const box = calcRollerBox((row as any).rollerOutput);
|
if (box === null || box <= 0) return '-';
|
const jobinput = Number((row as any).jobinput);
|
const weight = Number((row as any).weight);
|
const diff = jobinput - weight;
|
if (!Number.isFinite(diff)) return '-';
|
const val = diff / box;
|
if (!Number.isFinite(val)) return '-';
|
return val.toFixed(2);
|
}
|
},
|
{
|
key: 'packerOutput',
|
title: '包装产量(箱)',
|
align: 'center',
|
minWidth: 112,
|
render: row => {
|
const v = calcPackerBox((row as any).packerOutput);
|
if (v === null) return '-';
|
return v.toFixed(1);
|
}
|
},
|
{
|
key: 'packerUnitCost',
|
title: '包装单耗',
|
align: 'center',
|
minWidth: 96,
|
render: row => {
|
const box = calcPackerBox((row as any).packerOutput);
|
if (box === null || box <= 0) return '-';
|
const jobinput = Number((row as any).jobinput);
|
const weight = Number((row as any).weight);
|
const diff = jobinput - weight;
|
if (!Number.isFinite(diff)) return '-';
|
const val = diff / box;
|
if (!Number.isFinite(val)) return '-';
|
return val.toFixed(2);
|
}
|
},
|
{
|
key: 'actualstarttime',
|
title: '投料日期',
|
align: 'center',
|
width: 160
|
},
|
{
|
key: 'jobinput',
|
title: '投料重量',
|
align: 'center',
|
minWidth: 96
|
},
|
{
|
key: 'weight',
|
title: '储丝柜重量',
|
align: 'center',
|
minWidth: 96
|
},
|
{
|
key: 'distimebegin',
|
title: '储丝柜出料开始时间',
|
align: 'center',
|
width: 160
|
},
|
{
|
key: 'distimeend',
|
title: '储丝柜出料结束时间',
|
align: 'center',
|
width: 160
|
},
|
{
|
key: 'siloid',
|
title: '柜子号(末位)',
|
align: 'center',
|
width: 120
|
}
|
]
|
});
|
|
const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
|
useTableOperate<any>(data, 'id', getData);
|
|
async function handleBatchDelete() {
|
// request
|
const { error } = await fetchBatchDeleteStoreSilk(checkedRowKeys.value);
|
if (error) return;
|
onBatchDeleted();
|
}
|
|
async function handleDelete(id: CommonType.IdType) {
|
// request
|
const { error } = await fetchBatchDeleteStoreSilk([id]);
|
if (error) return;
|
onDeleted();
|
}
|
|
function edit(id: CommonType.IdType) {
|
handleEdit(id);
|
}
|
|
function handleExport() {
|
download('/analy/storeSilk/export', searchParams.value, `储丝柜产量_${new Date().getTime()}.xlsx`);
|
}
|
|
function calcRollerBox(val: unknown) {
|
if (val === null || val === undefined) return null;
|
const v = Number(val) / 50;
|
if (!Number.isFinite(v)) return null;
|
return v;
|
}
|
|
function calcPackerBox(val: unknown) {
|
if (val === null || val === undefined) return null;
|
const v = Number(val) / 10 / 250;
|
if (!Number.isFinite(v)) return null;
|
return v;
|
}
|
|
function handleRowClick(row: any) {
|
return {
|
onClick: () => {
|
selectedRollerDetailList.value = row.rollerDetailList || [];
|
selectedPackerDetailList.value = row.packerDetailList || [];
|
},
|
style: 'cursor: pointer;'
|
};
|
}
|
</script>
|
|
<template>
|
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
<StoreSilkSearch v-model:model="searchParams" @search="getDataByPage" />
|
<NCard title="储丝柜产量列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
|
<template #header-extra>
|
<TableHeaderOperation
|
v-model:columns="columnChecks"
|
:disabled-delete="checkedRowKeys.length === 0"
|
:loading="loading"
|
:show-add="false"
|
:show-delete="false"
|
:show-export="!showSankey && hasAuth('analy:storeSilk:export')"
|
@add="handleAdd"
|
@delete="handleBatchDelete"
|
@export="handleExport"
|
@refresh="getData"
|
>
|
<template #prefix>
|
<NButton
|
size="small"
|
ghost
|
:type="showSankey ? 'primary' : 'default'"
|
@click="showSankey = !showSankey"
|
>
|
{{ showSankey ? '列表' : '桑基图' }}
|
</NButton>
|
</template>
|
<template #suffix>
|
<NPopover placement="bottom-end" trigger="click">
|
<template #trigger>
|
<NButton size="small">
|
<template #icon>
|
<icon-mdi-table-large class="text-icon" />
|
</template>
|
表格大小
|
</NButton>
|
</template>
|
<NRadioGroup :value="tableSize" @update:value="handleTableSizeChange">
|
<NSpace vertical>
|
<NRadio value="small">小</NRadio>
|
<NRadio value="medium">中</NRadio>
|
<NRadio value="large">大</NRadio>
|
</NSpace>
|
</NRadioGroup>
|
</NPopover>
|
</template>
|
</TableHeaderOperation>
|
</template>
|
<StoreSilkSankey
|
v-if="showSankey"
|
:roller-record-list="sankeyRollerBoxList"
|
:packer-record-list="sankeyPackerBoxList"
|
:rows="data"
|
class="h-full"
|
/>
|
<NDataTable
|
v-else
|
:columns="columns as any"
|
:data="data"
|
:size="tableSize"
|
:flex-height="!appStore.isMobile"
|
:scroll-x="scrollX"
|
:loading="loading"
|
remote
|
:row-key="row => row.id"
|
:pagination="mobilePagination"
|
:row-props="handleRowClick"
|
class="sm:h-full"
|
/>
|
<StoreSilkOperateDrawer
|
v-model:visible="drawerVisible"
|
:operate-type="operateType"
|
:row-data="editingData"
|
@submitted="getDataByPage"
|
/>
|
</NCard>
|
<StoreSilkDetail
|
v-if="!showSankey"
|
:roller-detail-list="selectedRollerDetailList"
|
:packer-detail-list="selectedPackerDetailList"
|
class="h-[192px] overflow-hidden"
|
/>
|
</div>
|
</template>
|
|
<style scoped>
|
:deep(.n-data-table-th),
|
:deep(.n-data-table-td) {
|
padding: 4px 6px;
|
}
|
</style>
|