Commit 7b2e0976 authored by 沈翠玲's avatar 沈翠玲

第三个看板开发

parent ed85b5a3
......@@ -118,13 +118,13 @@ export default [
layout: false,
component: './kanban/paintingProcessKanban',
},
// {
// path: 'productionProgressKanban',
// name: 'productionProgressKanban',
// target: '_blank',
// layout: false,
// component: './kanban/ProductionProgress',
// },
{
path: 'productionProgressKanban',
name: 'productionProgressKanban',
target: '_blank',
layout: false,
component: './kanban/ProductionProgress',
},
// {
// path: 'materialSynthesisKanban',
// name: 'materialSynthesisKanban',
......
......@@ -54,7 +54,11 @@ export default {
'状态': 'สถานะ',
'产线选择': 'การเลือกสายการผลิต',
'日产出': 'นิสสัน',
'生产计划看板': 'แผนการผลิต Kanban'
'生产计划看板': 'แผนการผลิต Kanban',
'日期': 'วันที่',
'产品': 'ผลิตภัณฑ์',
'计划数': 'จำนวนแผน',
'工序': 'ขั้นตอนการทำงาน'
}
;
\ No newline at end of file
......@@ -54,6 +54,10 @@ export default {
'状态': '状态',
'产线选择': '产线选择',
'日产出': '日产出',
'生产计划看板': '生产计划看板'
'生产计划看板': '生产计划看板',
'日期': '日期',
'产品': '产品',
'计划数': '计划数',
'工序': '工序'
};
\ No newline at end of file
......@@ -67,6 +67,11 @@
background-image: url('./img/2.png');
}
}
&:nth-child(3) {
.imgWapper {
background-image: url('./img/3.png');
}
}
}
.logout {
position: absolute;
......
......@@ -52,10 +52,15 @@ div.no_right_border {
}
.row_segment1_section1 {
width: 132px;
height: auto;
&:extend(.row_section);
&>div {
display: flex;
align-items: center;
}
}
.row_segment1_section2 {
width: 150px;
width: 170px;
&:extend(.row_section);
}
.row_segment1_section3 {
......@@ -66,23 +71,31 @@ div.no_right_border {
width: calc(100% - 132px) !important;
}
.row_segment1_section4_header {
width: calc(100% - 150px - 100px - 132px);
width: calc(100% - 160px - 100px - 132px);
&:extend(.row_section);
}
.row_segment1_section4 {
width: calc(100% - 150px - 100px);
width: calc(100% - 160px - 100px);
&:extend(.row_section);
display: flex;
flex-wrap: wrap;
}
.process_item {
width: calc(100% / 4) !important;
&>div{
border: 1px solid #0ff;
}
}
.process_value {
display: flex;
width: 100%;
&>div {
width: calc(100% / 3) !important;
display: flex;
align-items: center;
color: #fff;
justify-content: center;
border: 1px solid #0ff;
}
}
......@@ -97,3 +110,13 @@ div.no_right_border {
word-wrap: break-word;
word-break: break-all;
}
.leftWrapper {
height: 100%;
overflow: auto;
-ms-overflow-style: none; /* IE 和 Edge */
scrollbar-width: none; /* Firefox */
}
.leftWrapper::-webkit-scrollbar {
display: none; /* Chrome, Safari 和 Opera */
}
\ No newline at end of file
import React, { useState, useEffect, useMemo, useCallback } from 'react';
import { NodeGroup } from 'react-move';
import { interpolate, interpolateTransformSvg } from 'd3-interpolate';
import React, { useState, useEffect, useMemo, useCallback, useRef } from 'react';
import styles from './index.less';
import StepCell from '../StepCell';
import { Modal } from 'antd';
import ProductionDetail from './productionDetail';
import ProductionAbnormal from './productionAbnormal';
import moment from 'moment';
import { useIntl } from 'umi';
type ErrorDetailCriteria = KANBAN.ProductionComprehens.ErrorDetailCriteria;
type ProductionProgressKanbanData = KANBAN.ProductionProgress.ProductionProgressKanbanDataDto;
......@@ -14,7 +9,7 @@ type ProductionProgressKanbanSetting = KANBAN.ProductionProgress.ProductionProgr
type ProgressTableProps = {
lineName: string;
data: ProductionProgressKanbanData[];
data: object;
conditionKey: string;
rowMovingTime: number;
};
......@@ -25,151 +20,89 @@ const ProgressTable: React.FC<ProgressTableProps> = ({
conditionKey,
rowMovingTime,
}) => {
const rowHight = 60;
const displayCount = 13;
const rowHight = 72;
const [displayData, setDisplayData] = useState<ProductionProgressKanbanData[]>([]);
const [displayAt, setDisplayAt] = useState(0);
const [lastConditionKey, setLastConditionKey] = useState('');
const [pause, setPause] = useState(false);
const [scollOnce, setScollOnce] = useState(false);
const leftScroll = useRef<HTMLDivElement>(null);
let timer: NodeJS.Timer | null = null;
const intl = useIntl();
const updateDisplayData = (da: number, sData: ProductionProgressKanbanData[]) => {
let endAt1 = da + displayCount;
let endAt2 = 0;
if (endAt1 > sData.length) {
endAt2 = endAt1 - sData.length;
endAt1 = sData.length;
}
const ret = sData.slice(da, endAt1);
if (sData.length > displayCount) {
sData.slice(0, endAt2).forEach((i) => ret.push(i));
}
setDisplayData(ret);
console.log('res', ret)
};
useEffect(() => {
if (lastConditionKey !== conditionKey) {
setLastConditionKey(conditionKey);
setDisplayAt(0);
updateDisplayData(0, data.taskPlanDayList);
const list = []
list.push(...(data.taskPlanDayList || []))
setDisplayData(list)
stopLoop()
startLoop()
return () => {
stopLoop()
}
}, [conditionKey, lastConditionKey, data]);
}, [rowMovingTime, data]);
const scoll = useCallback(() => {
if (pause) {
return;
const stopLoop = () => {
if (timer) {
clearInterval(timer);
timer = null;
}
let da = 0;
if (data.length > displayCount) {
da = displayAt + 1;
if (da >= data.length) {
da = 0;
};
const onMouseEnter = () => {
stopLoop()
}
const onMouseLeave = () => {
startLoop()
}
setDisplayAt(da);
updateDisplayData(da, data.taskPlanDayList);
}, [data, displayAt, pause]);
useEffect(() => {
const t = setInterval(() => {
scoll();
}, rowMovingTime * 1000);
return () => {
clearTimeout(t);
};
}, [rowMovingTime, scoll]);
const [criteria, setCriteria] = useState({} as ErrorDetailCriteria);
const [productionDetailParams, setProductionDetailParams] = useState({
kanbanSettingId: '',
aufnr: '',
processName: '',
const startLoop = () => {
stopLoop();
if (leftScroll && leftScroll.current && leftScroll.scrollTop) {
timer = setInterval(() => {
let scrollTop = leftScroll.current.scrollTop
if (scrollTop + 60 + leftScroll.current.offsetHeight >= leftScroll.current.scrollHeight) {
leftScroll.current.scrollTo({
top: 0,
behavior: 'instant',
});
useEffect(() => {
if (scollOnce) {
scoll();
setScollOnce(false);
} else {
leftScroll.current.scrollTop += 60
}
}, rowMovingTime * 1000)
}
}, [scollOnce, scoll]);
};
return (
<div className={styles.main}>
<div className={styles.main} onMouseEnter={onMouseEnter}//移出关闭
onMouseLeave={onMouseLeave}>
<div className={styles.row_container} style={{ height: rowHight }}>
<div className={styles.row_segment1}>
<div
className={`${styles.row_segment1_section1} ${styles.no_top_border} ${styles.no_left_border}`}
>
<div className={styles.cell}>日期</div>
<div className={styles.cell}>{intl.formatMessage({id:'日期'})}</div>
</div>
<div className={`${styles.row_segment1_section2} ${styles.no_top_border}`}>
<div className={styles.cell}>产品</div>
<div className={styles.cell}>{intl.formatMessage({id:'产品'})}</div>
</div>
<div className={`${styles.row_segment1_section3} ${styles.no_top_border}`}>
<div className={styles.cell}>计划数</div>
<div className={styles.cell}>{intl.formatMessage({id:'计划数'})}</div>
</div>
<div className={`${styles.row_segment1_section4_header} ${styles.no_top_border} ${styles.no_right_border}`}>
<div className={styles.cell}>工序</div>
</div>
</div>
</div>
<NodeGroup
data={displayData}
keyAccessor={(d) => d.startDate}
start={(d, i) => {
return { y: i * rowHight, opacity: 0 };
}}
enter={() => {
return { opacity: [1], timing: { duration: 1000 } };
}}
update={(d, i) => {
return { y: [i * rowHight], opacity: [1], timing: { duration: 1000 } };
}}
leave={() => {
return { y: [-rowHight], opacity: [0], timing: { duration: 1000 } };
}}
interpolation={(begValue, endValue, attr) => {
if (attr === 'transform') {
return interpolateTransformSvg(begValue, endValue);
}
return interpolate(begValue, endValue);
}}
>
{(nodes) => (
<div
className={styles.data_rowcontent}
onMouseEnter={() => setPause(true)}
onMouseLeave={() => {
setPause(false);
setScollOnce(true);
}}
onClick={()=>{console.log('nodes', nodes)}}
>
{nodes.map((node: { [key: string]: any; data: ProductionProgressKanbanData }) => (
<div className={styles.cell}>{intl.formatMessage({id:'工序'})}</div>
</div>
</div>
</div>
<div ref={leftScroll} className={styles.leftWrapper} >
{displayData.map((node: any, index: number) => (
<div
className={styles.row_container}
key={node.key}
style={{
position: 'absolute',
// width: '100%',
left: 0,
top: 0,
transform: `translate(0px, ${node.state.y}px)`,
opacity: node.state.opacity,
}}
key={index}
>
<div className={styles.row_segment1}>
<div
className={styles.row_segment1_section1}
>
<div className={styles.cell}>{node.data['startDate']}</div>
<div className={styles.cell}>{node['startDate']}</div>
</div>
{node.data.productList.map((item) => (
{node.productList.map((item) => (
<div className={`${styles.row_container} ${styles.other_data}`}>
<div className={styles.row_segment1_section2}>
<div className={styles.cell}>{item.itemCode}</div>
......@@ -180,13 +113,14 @@ const ProgressTable: React.FC<ProgressTableProps> = ({
<div className={styles.row_segment1_section4}>
{item.processList.map((processitem) => (
<div className={styles.process_item} style={{
height: rowHight
height: rowHight,
background: processitem.state === 2 ? '#ff0000' : processitem.state === 1 ? '#009242' : 'transparent'
}}>
<div className={styles.cell}>{processitem.processName}</div>
<div className={styles.process_value}>
<div className={styles.cell}>{processitem.planQuantity}</div>
<div className={styles.cell}>{processitem.planQuantity}</div>
<div className={styles.cell}>{processitem.planQuantity}</div>
<div className={styles.cell}>{processitem.reportQuantity}</div>
<div className={styles.cell}>{processitem.qualifyQuantity}</div>
<div className={styles.cell}>{processitem.qualifiedRate}%</div>
</div>
</div>
......@@ -211,8 +145,6 @@ const ProgressTable: React.FC<ProgressTableProps> = ({
</div>
))}
</div>
)}
</NodeGroup>
</div>
);
};
......
......@@ -7,6 +7,7 @@ import ProForm, {
ProFormRadio,
ProFormSelect,
} from '@ant-design/pro-form';
import { Button } from 'antd';
import type { ProFormInstance } from '@ant-design/pro-form';
import { queryProductionComprehensKanbanData } from '../../services/api';
type KanbanSetting = KANBAN.ProductionComprehens.ProductionComprehensKanbanDataDto;
......@@ -38,11 +39,38 @@ export type SettingFormProps = {
const SettingForm: React.FC<SettingFormProps> = (props) => {
const formRef = useRef<ProFormInstance>();
const btn = useRef<HTMLButtonElement>(null);
const btn1 = useRef<HTMLButtonElement>(null);
const intl = useIntl();
const [lineName, setLineName] = useState<
KanbanSetting[]
>([]);
const [lineNameFocus, setlineNameFocus] = useState(false);
const onPressEnter = (e) => {
setlineNameFocus(true)
};
const onInputKeyDown = (e) => {
const a = document.getElementsByClassName('ant-select-open')
if (e.code === "ArrowDown" && a.length === 0) {
e.preventDefault()
btn.current?.focus()
}
}
const cancelBtn = (e) => {
if (e.code === "ArrowRight") {
btn1.current?.focus()
} else if (e.code === "ArrowUp") {
setlineNameFocus(true)
}
}
const submitBtn = (e) => {
if (e.code === "ArrowLeft") {
btn.current?.focus()
}
}
const onBlurlineName = () => {
setlineNameFocus(false)
}
return (
<DrawerForm
formRef={formRef}
......@@ -52,6 +80,29 @@ const SettingForm: React.FC<SettingFormProps> = (props) => {
searchConfig: {
resetText: intl.formatMessage({id: '取消'}),
submitText: intl.formatMessage({id: '确认'}),
},
render: (props1, doms) => {
console.log(props1);
return [
<button
type='button'
key="rest"
ref={btn}
onKeyDown={cancelBtn}
onClick={() => props.onVisibleChange(false)}
>
{intl.formatMessage({id: '取消'})}
</button>,
<button
type='button'
ref={btn1}
key="submit"
onKeyDown={submitBtn}
onClick={() => props1.form?.submit?.()}
>
{intl.formatMessage({id: '确认'})}
</button>,
];
}
}}
visible={props.visible}
......@@ -61,6 +112,7 @@ const SettingForm: React.FC<SettingFormProps> = (props) => {
...props.values
});
}
setlineNameFocus(false)
props.onVisibleChange(visible);
}}
onFinish={async (values: FormSettingDto) => {
......@@ -83,12 +135,14 @@ const SettingForm: React.FC<SettingFormProps> = (props) => {
required
width="xl"
min={1}
fieldProps={{ precision: 0 }}
fieldProps={{ precision: 0, onPressEnter: onPressEnter }}
/>
<div >
<ProFormSelect
name="lineName"
label={intl.formatMessage({id: '产线选择'})}
required
fieldProps={{ autoFocus: lineNameFocus, onInputKeyDown: onInputKeyDown, onBlur: () => onBlurlineName }}
width="xl"
request={async () => {
const { data } = await queryProductionComprehensKanbanData();
......@@ -101,6 +155,10 @@ const SettingForm: React.FC<SettingFormProps> = (props) => {
return data.map((a) => ({ label: a, value: a }));
}}
/>
</div>
</DrawerForm>
);
};
......
......@@ -60,6 +60,7 @@ const Main: React.FC = () => {
<KanbanStyle
headerText={intl.formatMessage({id:'生产计划看板'})}
subTitle={setting?.lineName}
headerStyle={{fontSize: '30px'}}
autoResize={setting.autoResize}
onHeaderClick={() => {
setSettingFormVisible(true);
......
......@@ -28,8 +28,8 @@
}
.leftheader {
width: 220px;
padding: 26px 0 0 50px;
width: 245px;
padding: 26px 0 0 25px;
color: #fff;
font-size: 21px;
text-align: center;
......
......@@ -7,6 +7,7 @@ import ProForm, {
ProFormRadio,
ProFormSelect,
} from '@ant-design/pro-form';
import { Button } from 'antd';
import type { ProFormInstance } from '@ant-design/pro-form';
import { queryProductionComprehensKanbanData } from '../../services/api';
type KanbanSetting = KANBAN.ProductionComprehens.ProductionComprehensKanbanDataDto;
......@@ -37,31 +38,39 @@ export type SettingFormProps = {
};
const SettingForm: React.FC<SettingFormProps> = (props) => {
const intervalTimeRef = useRef<HTMLDivElement>(null);
const rowMovingTimeRef = useRef<HTMLDivElement>(null);
const lineNameRef = useRef<HTMLDivElement>(null);
const formRef = useRef<ProFormInstance>();
const btn = useRef<HTMLButtonElement>(null);
const btn1 = useRef<HTMLButtonElement>(null);
const intl = useIntl();
const [lineName, setLineName] = useState<
KanbanSetting[]
>([]);
const handleKeyDown = (e, name) => {
if (e.key === 'ArrowUp') {
if(name === 'lineName') {
rowMovingTimeRef.current?.children[0].focus()
} else if (name === 'rowMovingTime') {
intervalTimeRef.current?.children[0].focus()
const [lineNameFocus, setlineNameFocus] = useState(false);
const onPressEnter = (e) => {
setlineNameFocus(true)
};
const onInputKeyDown = (e) => {
const a = document.getElementsByClassName('ant-select-open')
if (e.code === "ArrowDown" && a.length === 0) {
e.preventDefault()
btn.current?.focus()
}
// 在这里添加你的增加逻辑
} else if (e.key === 'ArrowDown') {
if(name === 'intervalTime') {
rowMovingTimeRef.current?.children[0].focus()
} else if (name === 'rowMovingTime') {
lineNameRef.current?.children[0].focus()
}
// 在这里添加你的减少逻辑
const cancelBtn = (e) => {
if (e.code === "ArrowRight") {
btn1.current?.focus()
} else if (e.code === "ArrowUp") {
setlineNameFocus(true)
}
}
const submitBtn = (e) => {
if (e.code === "ArrowLeft") {
btn.current?.focus()
}
}
const onBlurlineName = () => {
setlineNameFocus(false)
}
};
return (
<DrawerForm
formRef={formRef}
......@@ -71,6 +80,29 @@ const SettingForm: React.FC<SettingFormProps> = (props) => {
searchConfig: {
resetText: intl.formatMessage({id: '取消'}),
submitText: intl.formatMessage({id: '确认'}),
},
render: (props1, doms) => {
console.log(props1);
return [
<button
type='button'
key="rest"
ref={btn}
onKeyDown={cancelBtn}
onClick={() => props.onVisibleChange(false)}
>
{intl.formatMessage({id: '取消'})}
</button>,
<button
type='button'
ref={btn1}
key="submit"
onKeyDown={submitBtn}
onClick={() => props1.form?.submit?.()}
>
{intl.formatMessage({id: '确认'})}
</button>,
];
}
}}
visible={props.visible}
......@@ -80,6 +112,7 @@ const SettingForm: React.FC<SettingFormProps> = (props) => {
...props.values
});
}
setlineNameFocus(false)
props.onVisibleChange(visible);
}}
onFinish={async (values: FormSettingDto) => {
......@@ -88,7 +121,6 @@ const SettingForm: React.FC<SettingFormProps> = (props) => {
}}
>
<ProFormCheckbox name="autoResize" label={intl.formatMessage({id: '适配窗口'})} width="xl" />
<div onKeyDown={(e)=>handleKeyDown(e, 'intervalTime')} ref={intervalTimeRef}>
<ProFormDigit
name="intervalTime"
label={intl.formatMessage({id: '刷新时间间隔(秒)'})}
......@@ -97,23 +129,20 @@ const SettingForm: React.FC<SettingFormProps> = (props) => {
min={10}
fieldProps={{ precision: 0 }}
/>
</div>
<div onKeyDown={(e)=>handleKeyDown(e, 'rowMovingTime')} ref={rowMovingTimeRef}>
<ProFormDigit
name="rowMovingTime"
label={intl.formatMessage({id: '内容滚动(秒)'})}
required
width="xl"
min={1}
fieldProps={{ precision: 0 }}
fieldProps={{ precision: 0, onPressEnter: onPressEnter }}
/>
</div>
<div onKeyDown={(e)=>handleKeyDown(e, 'lineName')}>
<div >
<ProFormSelect
name="lineName"
label={intl.formatMessage({id: '产线选择'})}
required
ref={lineNameRef}
fieldProps={{ autoFocus: lineNameFocus, onInputKeyDown: onInputKeyDown, onBlur: () => onBlurlineName }}
width="xl"
request={async () => {
const { data } = await queryProductionComprehensKanbanData();
......@@ -128,6 +157,8 @@ const SettingForm: React.FC<SettingFormProps> = (props) => {
/>
</div>
</DrawerForm>
);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment