123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719 |
- <template>
- <div class="shift-performance-container">
- <a-tabs v-model:activeKey="activeKey" type="card">
- <a-tab-pane key="chart">
- <template #tab>
- <span>
- <Icon icon="ant-design:appstore-outlined" :size="14" style="margin: 0" />
- 图表
- </span>
- </template>
- <a-spin wrapperClassName="shift-performance-chart-container" :spinning="loading">
- <div class="chart-container">
- <a-row :gutter="[20, 20]">
- <a-col :span="24">
- <div class="workbench-header">
- <div class="workbench-header-top-title flex">
- <div> 当前日期:<a-date-picker v-model:value="currentDate" @change="(date) => getShiftInfo(3, date)" /> </div>
- <div class="shift-performance-tags flex-1">
- <a-tag :color="shiftColor[index]" @click="() => (currentShift = index)" v-for="(item, index) in shiftPerformanceColumns">
- {{ item.createTime ? item.createTime.substring(5, 16) : '' }} ~
- {{ item.changeShiftTime ? item.changeShiftTime.substring(5, 16) : '' }}
- 【{{ getTeamShift(item.shift, item.shiftGroup) }}】
- <span class="current-shift" :style="{ background: shiftColor[index] }" v-if="index === currentShift"></span>
- </a-tag>
- </div>
- </div>
- <div class="flex flex-1 items-center">
- <div class="statistic-wrapper">
- <a-card v-for="item in statisticColums" :bodyStyle="{ padding: '0 10px' }">
- <a-statistic
- :title="item.title"
- :value="
- shiftPerformanceColumns[currentShift] && shiftPerformanceColumns[currentShift][item.dataIndex]
- ? shiftPerformanceColumns[currentShift][item.dataIndex]
- : 0
- "
- />
- </a-card>
- </div>
- <div class="chart-wrapper-right ml-5">
- <a-button
- size="large"
- type="primary"
- @click="openDetailModal(true, { record: shiftPerformanceColumns[currentShift], ccmNo: machine, isUpdate: true })"
- >
- 浇铸炉次
- </a-button>
- <a-button
- size="large"
- type="primary"
- style="margin-left: 10px"
- @click="
- openPrintOriginalRecordsModal(true, {
- ccmNo: machine,
- queryType: '2',
- shiftText: '',
- time:
- shiftPerformanceColumns[currentShift] && shiftPerformanceColumns[currentShift].changeShiftTime
- ? dayjs(shiftPerformanceColumns[currentShift].changeShiftTime).subtract(3, 'hour').format('YYYY-MM-DD HH:mm:ss')
- : '',
- curShiftInfo: {
- shift: shiftPerformanceColumns[currentShift] ? shiftPerformanceColumns[currentShift].shift : '',
- shiftGroup: shiftPerformanceColumns[currentShift] ? shiftPerformanceColumns[currentShift].shiftGroup : '',
- },
- changeShiftId: shiftPerformanceColumns[currentShift] ? shiftPerformanceColumns[currentShift].id : '',
- })
- "
- >
- 原始数据
- </a-button>
- </div>
- </div>
- </div>
- </a-col>
- </a-row>
- <div class="chart-wrapper">
- <a-row :gutter="[10, 10]">
- <!-- 定尺明细 -->
- <a-col :span="8">
- <a-card title="定尺明细" :bordered="false">
- <Chart
- :list="
- shiftPerformanceColumns[currentShift] && shiftPerformanceColumns[currentShift].sizeDetailsList
- ? shiftPerformanceColumns[currentShift].sizeDetailsList
- : []
- "
- />
- </a-card>
- </a-col>
- <!-- 行车吊运 -->
- <a-col :span="8" class="driving-wrapper">
- <a-card title="行车吊运" :bordered="false">
- <template v-if="shiftPerformanceColumns[currentShift] && shiftPerformanceColumns[currentShift].liftingBillDetailsList">
- <div class="driving-list" v-for="(item, index) in shiftPerformanceColumns[currentShift].liftingBillDetailsList" :key="index">
- <div class="driving-title">
- <div class="title-line"></div>
- <div class="title-txt">{{ item.vehicleNumber }}</div>
- </div>
- <a-row :gutter="20">
- <a-col :span="8" v-if="machine == '6'">
- <div class="driving-list-item">
- <div class="driving-item">热送</div>
- <div class="flex statistic">
- <a-statistic title="支数" class="statistic-left" :value="item.hotSendAmont || 0" />
- <a-statistic title="重量/t" :value="item.hotSendWeight ? item.hotSendWeight.toFixed(3) : 0" />
- </div>
- </div>
- </a-col>
- <a-col :span="8">
- <div class="driving-list-item">
- <div class="driving-item">热装</div>
- <div class="flex statistic">
- <a-statistic title="支数" class="statistic-left" :value="item.hotChargingAmont || 0" />
- <a-statistic title="重量/t" :value="item.hotChargingWeight ? item.hotChargingWeight.toFixed(3) : 0" />
- </div>
- </div>
- </a-col>
- <a-col :span="8">
- <div class="driving-list-item">
- <div class="driving-item">堆垛</div>
- <div class="flex statistic">
- <a-statistic title="支数" class="statistic-left" :value="item.stackingAmont || 0" />
- <a-statistic title="重量/t" :value="item.amontWeight ? item.amontWeight.toFixed(3) : 0" />
- </div>
- </div>
- </a-col>
- </a-row>
- </div>
- </template>
- <a-empty v-else />
- </a-card>
- </a-col>
- <!-- 热送信息 -->
- <a-col class="hot-send-wrapper" :span="8">
- <a-card :bordered="false" class="hot-send-card" :bodyStyle="{ padding: '0' }">
- <template #title>
- <div class="title flex">
- <span>热送信息:</span>
- <div class="statistic-wrapper flex">
- <a-card v-for="item in hotSendCols" :bodyStyle="{ padding: '0 10px' }">
- <a-statistic
- :title="item.title"
- :value-style="{ color: '#3b5999' }"
- :value="shiftPerformanceColumns[currentShift] ? shiftPerformanceColumns[currentShift][item.dataIndex] : 0"
- />
- </a-card>
- </div>
- </div>
- </template>
- <!-- 棒一 -->
- <a-card v-if="machine == '5'" :title="chartColumns['rollClubOneDetails']" :bordered="false">
- <Chart
- :list="
- shiftPerformanceColumns[currentShift] && shiftPerformanceColumns[currentShift]['rollClubOneDetails']
- ? shiftPerformanceColumns[currentShift]['rollClubOneDetails']
- : []
- "
- />
- </a-card>
- <!-- 高线 -->
- <a-card v-if="machine == '6'" :title="chartColumns['rollClubHeightDetails']" :bordered="false">
- <Chart
- :list="
- shiftPerformanceColumns[currentShift] && shiftPerformanceColumns[currentShift]['rollClubHeightDetails']
- ? shiftPerformanceColumns[currentShift]['rollClubHeightDetails']
- : []
- "
- />
- </a-card>
- </a-card>
- </a-col>
- </a-row>
- <div class="title flex">
- <span>装运信息:</span>
- <div class="statistic-wrapper flex">
- <a-card v-for="item in hotChargeCols" :bodyStyle="{ padding: '0 10px' }">
- <a-statistic
- :title="item.title"
- :value-style="{ color: '#2e9900' }"
- :value="shiftPerformanceColumns[currentShift] ? shiftPerformanceColumns[currentShift][item.dataIndex] : 0"
- />
- </a-card>
- </div>
- </div>
- <a-row :gutter="[10, 10]">
- <a-col :span="8" v-for="item in chargeColumns">
- <a-card :title="chartColumns[item]" :bordered="false">
- <Chart
- :list="
- shiftPerformanceColumns[currentShift] && shiftPerformanceColumns[currentShift][item]
- ? shiftPerformanceColumns[currentShift][item]
- : []
- "
- />
- </a-card>
- </a-col>
- </a-row>
- </div>
- </div>
- </a-spin>
- </a-tab-pane>
- <a-tab-pane key="list">
- <template #tab>
- <span>
- <Icon icon="ant-design:bars-outlined" :size="14" style="margin: 0" />
- 列表
- </span>
- </template>
- <BasicTable @register="registerTable">
- <template v-slot:bodyCell="{ column, record, index, text }">
- <template v-if="column.dataIndex.includes('liftingBillDetailsList')">
- <div class="liftingBillDetailsList-content">
- <div class="liftingBillDetailsList-wrap" v-for="item in record.liftingBillDetailsList">{{ item[column.dataIndex[1]] }}</div>
- </div>
- </template>
- </template>
- </BasicTable>
- </a-tab-pane>
- </a-tabs>
- </div>
- <history @register="registerDetailModal" />
- <!-- 打印原始数据 -->
- <printOriginalRecords @register="registerPrintOriginalRecordsModal" />
- </template>
- <script lang="ts" setup>
- import { BasicTable } from '/@/components/Table';
- import { useListPage } from '/@/hooks/system/useListPage';
- import { columns, searchFormSchema } from './ShiftPerformance.data';
- import { list } from './ShiftPerformance.api';
- import { getMachineNum } from '../hotDelivery/common.data';
- import { isJsonArrayString } from '/@/utils/is';
- import { BasicColumn } from '/@/components/Table';
- import { onMounted, ref } from 'vue';
- import Icon from '/@/components/Icon';
- import AStatistic from 'ant-design-vue/lib/statistic/Statistic';
- import { getTeamShift } from '../Dashboard/dashboard.api';
- import Chart from '../Dashboard/components/chart.vue';
- import type { Dayjs } from 'dayjs';
- import dayjs from 'dayjs';
- import { useModal } from '/@/components/Modal';
- import history from './components/history.vue';
- import printOriginalRecords from '../operator/components/printOriginalRecords.vue';
- const currentDate = ref<Dayjs>(dayjs());
- // 棒线堆垛明细
- const [registerDetailModal, { openModal: openDetailModal }] = useModal();
- // 注册打印原始记录modal
- const [registerPrintOriginalRecordsModal, { openModal: openPrintOriginalRecordsModal }] = useModal();
- const machine = getMachineNum();
- const changeColumns = [
- 'sizeDetailsList',
- 'rollClubOneDetails',
- 'rollClubTwoDetails',
- 'rollClubThreeDetails',
- 'rollClubHeightDetails',
- 'rollClubShipDetails',
- ];
- const chartColumns = {
- rollClubOneDetails: '棒一明细',
- rollClubTwoDetails: '棒二明细',
- rollClubThreeDetails: '棒三明细',
- rollClubHeightDetails: '高线明细',
- rollClubShipDetails: '上若明细',
- };
- const chargeColumns = ['rollClubTwoDetails', 'rollClubThreeDetails', 'rollClubShipDetails'];
- // 定义 columnsObj 类型
- type ColumnsObjType = Record<string, { title: string; align: string; dataIndex: any[]; width: number; ellipsis: boolean }[]>;
- const activeKey = ref('chart');
- const statisticColums = [
- {
- title: '当班总数',
- dataIndex: 'shiftSum',
- },
- {
- title: '当班总重',
- dataIndex: 'shiftProduct',
- },
- {
- title: '起垛支数',
- dataIndex: 'shiftStackAmount',
- },
- {
- title: '起垛重量',
- dataIndex: 'shiftStackWeight',
- },
- {
- title: '判废支数',
- dataIndex: 'wasteAmount',
- },
- {
- title: '判废重量',
- dataIndex: 'wasteBlankOutput',
- },
- ];
- const hotSendCols = [
- {
- title: '热送支数',
- dataIndex: 'shiftHotsendAmount',
- },
- {
- title: '热送重量',
- dataIndex: 'shiftHotsendWeight',
- },
- ];
- const hotChargeCols = [
- {
- title: '装运总车次',
- dataIndex: 'allCarNum',
- },
- {
- title: '装运总支数',
- dataIndex: 'counts',
- },
- {
- title: '装运总重量',
- dataIndex: 'blankOutputs',
- },
- {
- title: '热装支数',
- dataIndex: 'shiftHotfeignAmount',
- },
- {
- title: '热装重量',
- dataIndex: 'shiftHotfeignWeight',
- },
- ];
- const shiftPerformanceColumns = ref<any>([]);
- const shiftColor = ['#f50', '#2db7f5', '#87d068'];
- const currentShift = ref(0);
- //注册table数据
- const { tableContext } = useListPage({
- tableProps: {
- title: '',
- api: list,
- beforeFetch: (params) => {
- return Object.assign(params, { ccmNo: machine });
- },
- afterFetch: (data) => {
- if (data.length > 0) {
- const tabColumns = getColumns();
- // 初始化 columnsObj 并明确类型
- const columnsObj: ColumnsObjType = {};
- data.forEach((item) => {
- const keys = Object.keys(item);
- keys.forEach((ele) => {
- if (changeColumns.includes(ele) && item[ele] && isJsonArrayString(item[ele])) {
- let obj = {};
- if (!columnsObj[ele]) columnsObj[ele] = [];
- JSON.parse(item[ele]).forEach((v) => {
- const has = columnsObj[ele].find((vs) => vs.dataIndex[1] === v.size);
- if (!has) {
- columnsObj[ele].push({
- title: v.size,
- align: 'center',
- dataIndex: [ele, v.size],
- ellipsis: false,
- width: 150,
- });
- }
- obj[v.size] = v.nums + '支 | ' + v.blankOutput + '/t';
- });
- item[ele] = obj;
- } else if (ele === 'liftingBillDetailsList' && isJsonArrayString(item[ele])) {
- let obj: any = [];
- JSON.parse(item[ele]).forEach((v) => {
- obj.push({
- vehicleNumber: v.vehicleNumber,
- hotCharging: v.hotChargingAmont + '支 | ' + v.hotChargingWeight.toFixed(4) + '/t',
- hotSend: v.hotSendAmont + '支 | ' + v.hotSendWeight.toFixed(4) + '/t',
- stacking: v.stackingAmont + '支 | ' + v.amontWeight.toFixed(4) + '/t',
- });
- });
- item[ele] = obj;
- }
- });
- });
- const newColumns = tabColumns.map((item) => {
- if (columnsObj[item.dataIndex as string]) {
- return { ...item, children: columnsObj[item.dataIndex as string] };
- } else {
- return item;
- }
- }) as BasicColumn[];
- setColumns(newColumns);
- }
- return data;
- },
- columns,
- canResize: false,
- formConfig: {
- //labelWidth: 120,
- schemas: searchFormSchema,
- autoSubmitOnEnter: true,
- showAdvancedButton: true,
- fieldMapToNumber: [],
- fieldMapToTime: [
- ['changeShiftTime', ['changeShiftTime_begin', 'changeShiftTime_end'], 'YYYY-MM-DD'],
- ['createTime', ['createTime_begin', 'createTime_end'], 'YYYY-MM-DD'],
- ],
- },
- showActionColumn: false,
- striped: true,
- actionColumn: {
- width: 150,
- title: '操作',
- fixed: 'right',
- },
- },
- });
- // 获取班次信息,三条
- const loading = ref(false);
- const getShiftInfo = async (pageSize: number = 3, date?: Dayjs) => {
- try {
- loading.value = true;
- const createTime_begin = date ? date.subtract(1, 'day').format('YYYY-MM-DD 23:55:00') : undefined;
- const createTime_end = date ? date.add(1, 'day').format('YYYY-MM-DD 00:05:00') : undefined;
- const res = await list({
- ccmNo: machine,
- pageNo: 1,
- pageSize: pageSize,
- column: 'createTime',
- order: 'asc',
- ...(date ? { createTime_begin, createTime_end } : {}),
- });
- const { records } = res;
- const arr = (records || []).map((item: any) => {
- const keys = Object.keys(item);
- keys.forEach((ele) => {
- if (changeColumns.includes(ele) && item[ele] && isJsonArrayString(item[ele])) {
- item[ele] = JSON.parse(item[ele]).map((v: any) => {
- return {
- size: v.size,
- weight: v.blankOutput,
- nums: v.nums,
- };
- });
- } else if (ele === 'liftingBillDetailsList' && isJsonArrayString(item[ele])) {
- item[ele] = JSON.parse(item[ele] || '[]');
- }
- });
- return item;
- });
- // if (pageSize === 4) {
- // arr.splice(0, 1);
- // }
- shiftPerformanceColumns.value = arr
- .filter((item) => item.createTime && item.changeShiftTime) // 过滤掉 createTime 为空的数据
- .sort((a, b) => {
- const dateA = new Date(a.createTime).getTime(); // 转换为时间戳
- const dateB = new Date(b.createTime).getTime(); // 转换为时间戳
- if (isNaN(dateA) || isNaN(dateB)) {
- console.warn('Invalid date detected:', a.createTime, b.createTime);
- return 0; // 如果日期无效,视为相等
- }
- return dateA - dateB; // 按时间戳排序
- });
- currentShift.value = shiftPerformanceColumns.value.length > 0 ? shiftPerformanceColumns.value.length - 1 : 0;
- } catch (error) {
- console.error(error);
- } finally {
- loading.value = false;
- }
- };
- const [registerTable, { getColumns, setColumns }] = tableContext;
- onMounted(() => {
- getShiftInfo(4, dayjs());
- });
- </script>
- <style lang="less" scoped>
- .shift-performance-container {
- width: 100%;
- height: 100%;
- padding: 10px;
- .ant-tabs {
- height: 100%;
- :deep(.ant-tabs-content) {
- height: 100%;
- }
- }
- .chart-container {
- height: 100%;
- display: flex;
- flex-direction: column;
- .workbench-header {
- display: flex;
- margin-bottom: 30px;
- min-height: 40px;
- .workbench-header-top-title {
- margin-right: 20px;
- padding-top: 6px;
- font-weight: bold;
- font-size: 18px;
- color: #1a1a1a;
- line-height: 26px;
- text-align: left;
- font-style: normal;
- .txt {
- color: rgba(107, 208, 0, 1);
- }
- }
- .statistic-wrapper {
- flex: 1;
- display: flex;
- flex-wrap: wrap;
- gap: 20px 10px;
- padding-top: 3px;
- .ant-card {
- height: fit-content;
- }
- }
- .ant-statistic {
- display: flex;
- align-items: center;
- gap: 10px;
- :deep(.ant-statistic-title) {
- width: 80px;
- margin: 0;
- color: #000;
- font-size: 16px;
- }
- }
- }
- .shift-performance-tags {
- margin-left: 10px;
- .ant-tag {
- padding: 6px 6px;
- position: relative;
- cursor: pointer;
- margin-bottom: 20px;
- }
- .current-shift {
- position: absolute;
- display: inline-block;
- width: 60px;
- height: 4px;
- border-radius: 4px;
- bottom: -8px;
- left: 50%;
- transform: translateX(-30px);
- }
- }
- .chart-wrapper {
- flex: 1;
- // background-color: #fff;
- .driving-wrapper {
- .driving-list {
- margin-bottom: 4px;
- padding: 12px;
- background: #fafafa;
- border-radius: 4px;
- &:last-child {
- margin-bottom: 0;
- }
- .driving-title {
- display: flex;
- align-items: center;
- margin-bottom: 8px;
- font-weight: 500;
- font-size: 16px;
- color: #333333;
- line-height: 24px;
- padding-bottom: 12px;
- border-bottom: 1px solid #e6e6e6;
- .title-line {
- width: 4px;
- height: 22px;
- background: #90e2a4;
- border-radius: 4px;
- margin-right: 4px;
- }
- }
- .driving-list-item {
- background: #ffffff;
- border-radius: 4px;
- padding: 8px;
- .driving-item {
- font-weight: 500;
- font-size: 12px;
- color: #333333;
- line-height: 22px;
- }
- .ant-statistic {
- display: flex;
- flex-direction: column-reverse;
- &.statistic-left {
- min-width: 60px;
- }
- :deep(.ant-statistic-title) {
- font-weight: 400;
- font-size: 12px;
- color: #c8c8c8;
- line-height: 16px;
- }
- :deep(.ant-statistic-content-value-int),
- :deep(.ant-statistic-content-value-decimal) {
- font-weight: 500;
- font-size: 16px;
- color: #666666;
- line-height: 18px;
- }
- }
- }
- }
- }
- .ant-card {
- height: 100%;
- }
- .title {
- align-items: center;
- color: #000;
- font-size: 16px;
- padding: 10px 0;
- .statistic-wrapper {
- flex: 1;
- display: flex;
- flex-wrap: wrap;
- gap: 20px 10px;
- align-items: center;
- .ant-card {
- height: fit-content;
- }
- .ant-statistic {
- display: flex;
- align-items: center;
- gap: 10px;
- :deep(.ant-statistic-title) {
- width: 80px;
- margin: 0;
- color: #000;
- font-size: 16px;
- }
- }
- }
- }
- }
- }
- .hot-send-wrapper {
- .hot-send-card {
- background-color: transparent;
- }
- }
- .jeecg-basic-table {
- padding: 0;
- }
- :deep(.ant-table-cell) {
- .liftingBillDetailsList-content {
- margin-top: -12px;
- margin-bottom: -12px;
- margin-left: -8px;
- margin-right: -8px;
- }
- .liftingBillDetailsList-wrap {
- border-bottom: 1px solid #f0f0f0;
- line-height: 36px;
- &:last-child {
- border-bottom: none;
- }
- }
- }
- }
- </style>
|