计划管理-生产计划管理-搅拌生产计划

main
jiangxucong 1 month ago
parent 298d1b15a7
commit 68f0f8d373

@ -0,0 +1,312 @@
import React, { useMemo, useState } from 'react';
import { Select, Space, Button, Switch, message, Input, Modal, InputNumber } from 'antd';
import { PlusOutlined, SearchOutlined, ReloadOutlined, ExportOutlined } from '@ant-design/icons';
import StandardTable from '@/components/StandardTable';
import styles from './MixingProductionPlan.less';
const MixingProductionPlan = () => {
const [searchKeyword, setSearchKeyword] = useState('');
// 列表筛选与数据(演示数据,可替换为接口)
const [filters, setFilters] = useState({
listCategory: undefined,
listStatus: undefined,
});
const columns = useMemo(() => {
return [
{ title: '计划编号', dataIndex: 'planNo', key: 'planNo', width: 90 },
{ title: '油品名称', dataIndex: 'planName', key: 'planName', width: 100 },
{ title: '计划类型', dataIndex: 'planType', key: 'planType', width: 120 },
{ title: '来源油品', dataIndex: 'sourceOil', key: 'sourceOil', width: 220 },
{ title: '目标油品', dataIndex: 'targetOil', key: 'targetOil', width: 160 },
{ title: '来源罐', dataIndex: 'sourceTank', key: 'sourceTank', width: 90 },
{ title: '目标罐', dataIndex: 'targetTank', key: 'targetTank', width: 90 },
{ title: '调和配方', dataIndex: 'formula', key: 'formula', width: 260 },
{ title: '计划时间', dataIndex: 'planTime', key: 'planTime', width: 160 },
{ title: '状态', dataIndex: 'status', key: 'status', width: 90 },
{ title: '进度', dataIndex: 'progress', key: 'progress', width: 90 },
{ title: '创建人', dataIndex: 'creator', key: 'creator', width: 90 },
{
title: '操作',
key: 'action',
fixed: 'right',
width: 100,
render: (_, record) => (
<Space size={12}>
<Button
type="link"
size="small"
className={styles.primaryActionBtn}
onClick={() => handlePrimaryAction(record)}
>
{record.actionText}
</Button>
</Space>
),
},
];
}, []);
const [tableData, setTableData] = useState([
{
key: 'BP001',
planNo: 'BP001',
planName: '92#汽油',
planType: '油品调和',
sourceOil: 'MTBE、重整汽油、催化汽油',
targetOil: '92# 3000立方米',
sourceTank: 'T-103',
targetTank: 'T-203',
qty: 600,
planTime: '2024-05-01 14:00',
status: '执行中',
progress: '45%',
creator: '郑双',
actionText: '更新进度',
formula: 'MTBEA%、重整对油B5%、精化对油30%'
},
{
key: 'BP002',
planNo: 'BP002',
planName: '95#汽油',
planType: '油品调和',
sourceOil: 'MTBE、重整汽油、催化汽油',
targetOil: '95#',
sourceTank: 'T-102',
targetTank: 'T-202',
qty: 500,
planTime: '2024-05-01 14:00',
status: '执行中',
progress: '40%',
creator: '钱添西',
actionText: '跟踪进度',
formula: 'MTBEA%、重整对油B18%、精化对油60%'
},
{
key: 'BP003',
planNo: 'BP003',
planName: '92#汽油',
planType: '油品调和',
sourceOil: 'MTBE、重整汽油、催化汽油',
targetOil: '92#',
sourceTank: 'T-101',
targetTank: 'T-201',
qty: 300,
planTime: '2024-05-01 15:00',
status: '待执行',
progress: '0%',
creator: '郑璞',
actionText: '开始执行',
formula: 'MTBEA%、重整对油B2%、精化对油40%'
},
{
key: 'BP004',
planNo: 'BP004',
planName: '95#汽油',
planType: '油品调和',
sourceOil: 'MTBE、重整汽油、催化汽油',
targetOil: '95#',
sourceTank: 'T-104',
targetTank: 'T-204',
qty: 200,
planTime: '2024-05-01 12:00',
status: '待审核',
progress: '50%',
creator: '孙建操',
actionText: '开始执行',
formula: 'MTBEA%、重整对油B14%、精化对油40%'
},
{
key: 'BP005',
planNo: 'BP005',
planName: '92#汽油',
planType: '油品调和',
sourceOil: 'MTBE、重整汽油、催化汽油',
targetOil: '92#',
sourceTank: 'T-105',
targetTank: 'T-205',
qty: 100,
planTime: '2024-05-01 11:00',
status: '审核中',
progress: '90%',
creator: '李莉娜',
actionText: '更新进度',
formula: 'MTBEA%、重整对油B18%、精化对油30%'
},
{
key: 'BP006',
planNo: 'BP006',
planName: '95#汽油',
planType: '油品调和',
sourceOil: 'MTBE、重整汽油、催化汽油',
targetOil: '95#',
sourceTank: 'T-106',
targetTank: 'T-206',
qty: 150,
planTime: '2024-05-01 10:00',
status: '已完成',
progress: '30%',
creator: '李钰',
actionText: '查看详情',
formula: 'MTBEA%、重整对油B18%、精化对油20%'
},
]);
const [progressState, setProgressState] = useState({ open: false, value: 0, recordKey: null });
const handlePrimaryAction = (record) => {
const action = record.actionText;
if (action === '更新进度') {
const current = parseInt(String(record.progress).replace('%', ''), 10) || 0;
setProgressState({ open: true, value: current, recordKey: record.key });
} else if (action === '跟踪进度') {
message.info(`当前进度:${record.progress}`);
} else if (action === '开始执行') {
Modal.confirm({
title: '确认开始执行?',
onOk: () => {
setTableData((prev) => prev.map((item) =>
item.key === record.key
? { ...item, status: '执行中', progress: item.progress || '0%', actionText: '更新进度' }
: item
));
message.success('已开始执行');
},
});
} else if (action === '查看详情') {
Modal.info({
title: '计划详情',
content: (
<div>
<div>计划编号{record.planNo}</div>
<div>油品名称{record.planName}</div>
<div>计划类型{record.planType}</div>
<div>来源油品{record.sourceOil}</div>
<div>目标油品{record.targetOil}</div>
<div>来源罐{record.sourceTank}</div>
<div>目标罐{record.targetTank}</div>
<div>调和配方{record.formula}</div>
<div>计划时间{record.planTime}</div>
<div>数量{record.qty}</div>
<div>状态{record.status}</div>
<div>进度{record.progress}</div>
<div>创建人{record.creator}</div>
</div>
),
});
}
};
return (
<div className={styles.container}>
<div className={styles.searchSection}>
<div className={styles.sectionHeader}>
<span className={styles.sectionBar} />
<span className={styles.sectionTitle}>查询条件</span>
</div>
<div className={styles.filterContent}>
<div className={styles.filterItem}>
<Input.Search
placeholder="搜索关键词"
allowClear
value={searchKeyword}
onChange={(e) => setSearchKeyword(e.target.value)}
onSearch={(val) => setSearchKeyword(val)}
style={{ minWidth: 150 }}
/>
</div>
<div className={styles.filterItem}>
<span className={styles.filterLabel}>状态:</span>
<Select
value={filters.listStatus}
onChange={(v) => setFilters({ ...filters, listStatus: v })}
placeholder="全部"
options={[
{ label: '全部', value: undefined },
{ label: '启用', value: '启用' },
{ label: '停用', value: '停用' },
]}
allowClear
/>
</div>
<Space className={styles.filterButtons}>
<Button
type="primary"
icon={<SearchOutlined />}
className={styles.queryBtn}
>
查询
</Button>
<Button
icon={<ReloadOutlined />}
className={styles.resetBtn}
>
重置
</Button>
</Space>
</div>
</div>
<div className={styles.searchSection}>
<div className={styles.sectionHeader}>
<span className={styles.sectionBar} />
<span className={styles.sectionTitle}>搅拌生产计划列表</span>
<Space className={styles.headerActions}>
<Button
type="primary"
icon={<PlusOutlined />}
className={styles.addBtn}
>
新增计划
</Button>
</Space>
</div>
<div className={styles.tableWrapper}>
<StandardTable
rowKey="key"
columns={columns}
data={{
list: tableData,
pagination: {
total: tableData.length,
pageSize: 10,
current: 1,
showTotal: (total) => `${total}`,
},
}}
// selectionType="checkbox"
/>
</div>
<Modal
title="更新进度"
open={progressState.open}
onOk={() => {
setTableData((prev) => prev.map((item) =>
item.key === progressState.recordKey
? { ...item, progress: `${progressState.value}%` }
: item
));
setProgressState({ open: false, value: 0, recordKey: null });
message.success('进度已更新');
}}
onCancel={() => setProgressState({ open: false, value: 0, recordKey: null })}
>
<Space>
<span>当前进度%</span>
<InputNumber
min={0}
max={100}
value={progressState.value}
onChange={(v) => setProgressState((s) => ({ ...s, value: Number(v) || 0 }))}
/>
</Space>
</Modal>
</div>
</div>
);
};
export default MixingProductionPlan;

@ -0,0 +1,233 @@
@section-border: rgba(118, 194, 181, 1);
@section-bg: rgba(243, 249, 248, 1);
.container {
margin: 0;
padding: 0;
background: #fff;
display: flex;
flex-direction: column;
gap: 15px;
width: 100%;
height: 100%;
// 底部区域 - 油品列表
.searchSection {
flex: 1;
display: flex;
flex-direction: column;
// border: 1px solid @section-border;
background: #fff;
padding: 30px 20px 0 20px;
// 区域头部
.sectionHeader {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 15px;
// 将右侧动作区推到最右侧
.headerActions {
display: flex;
gap: 12px;
margin-left: auto;
.addBtn {
background-image: url('@/assets/business_basic/Bt_bg1.png');
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border: none;
}
}
// 装饰条
.sectionBar {
width: 2px;
height: 16px;
background: rgba(0, 102, 101, 1);
border-radius: 1px;
}
// 标题
.sectionTitle {
font-size: 18px;
font-weight: 600;
color: #333;
}
}
// 筛选内容区域
.filterContent {
display: flex;
align-items: center;
gap: 20px;
// margin-bottom: 20px;
flex-wrap: wrap;
// justify-content: space-between;
// 筛选项
.filterItem {
display: flex;
align-items: center;
gap: 12px;
// 筛选标签
.filterLabel {
color: #333;
font-size: 14px;
}
:global {
// 统一 Input.Search 边框颜色为绿主题
.ant-input-affix-wrapper {
border-radius: 0px !important;
border-color: rgba(44, 158, 157, 1) !important;
}
.ant-input-search-button {
border-radius: 0px !important;
border-color: rgba(44, 158, 157, 1) !important;
}
.ant-select {
min-width: 140px;
// 选择框样式
.ant-select-selector {
border-color: rgba(44, 158, 157, 1) !important;
border-radius: 2px !important;
}
&:hover .ant-select-selector {
border-color: rgba(44, 158, 157, 1) !important;
}
&.ant-select-focused .ant-select-selector {
border-color: rgba(44, 158, 157, 1) !important;
box-shadow: 0 0 0 2px rgba(44, 158, 157, 0.2) !important;
}
}
}
}
// 筛选按钮组
.filterButtons {
display: flex;
gap: 12px;
.queryBtn {
background-image: url('@/assets/business_basic/Bt_bg1.png');
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border: none;
}
.resetBtn {
background-image: url('@/assets/business_basic/Bt_bg2.png');
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border: none;
color: #006665;
}
}
}
// 表格包装器
.tableWrapper {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
.primaryActionBtn {
color: #2D9E9D;
}
:global(.ant-table-wrapper) {
flex: 1;
display: flex;
flex-direction: column;
}
// 表头样式
:global {
.ant-table-thead>tr>th {
color: rgba(51, 51, 51, 1) !important;
font-weight: 450 !important;
background-color: rgba(240, 247, 247, 1) !important;
text-align: center !important;
}
// 表体样式
.ant-table-tbody>tr>td {
color: rgba(78, 88, 86, 1) !important;
font-weight: 400 !important;
text-align: center !important;
}
// 操作列按钮样式
.viewDetailBtn {
color: rgba(0, 102, 101, 1) !important;
&:hover {
color: rgba(0, 102, 101, 1) !important;
}
}
.editBtn {
color: rgba(45, 158, 157, 1) !important;
&:hover {
color: rgba(45, 158, 157, 1) !important;
}
}
.deleteBtn {
color: rgba(255, 130, 109, 1) !important;
&:hover {
color: rgba(255, 130, 109, 1) !important;
}
}
// 状态列 Switch 样式
.statusSwitch {
// 启用状态背景色
&.ant-switch-checked {
background-color: rgba(20, 106, 89, 1) !important;
}
// 停用状态背景色
&:not(.ant-switch-checked) {
background-color: rgba(153, 153, 153, 1) !important;
}
}
// 复选框样式
.ant-checkbox-inner {
border-color: rgba(0, 102, 101, 1) !important;
&::after {
background-color: rgba(0, 102, 101, 1) !important;
}
}
.ant-checkbox-wrapper:hover .ant-checkbox-inner,
.ant-checkbox:hover .ant-checkbox-inner {
border-color: rgba(0, 102, 101, 1) !important;
}
.ant-checkbox-checked .ant-checkbox-inner {
background-color: rgba(0, 102, 101, 1) !important;
border-color: rgba(0, 102, 101, 1) !important;
}
}
}
}
}
Loading…
Cancel
Save