Commit 257c22c1 authored by 前端-黄佳鑫's avatar 前端-黄佳鑫

feat: 待比价详情重构页面

parent a865d9dd
......@@ -24,9 +24,9 @@ export const confirmOfferRoute = [
},
{
/** 比价 */
path: '/memberCenter/procurementAbility/confirmOffer/detail',
path: '/memberCenter/procurementAbility/confirmOffer/contrast',
name: '待比价',
component: '@/pages/transaction/purchaseAbility/confirmOffer/detail',
component: '@/pages/transaction/purchaseAbility/confirmOffer/contrast',
hideInMenu: true,
noMargin: true,
},
......
.cell {
display: flex;
h5 { margin-bottom: 2em; }
.label {
flex: 0 0 25%;
color: #909399;
}
}
/** 详情通用 - 基本信息 */
import React from 'react';
import { Row, Col } from 'antd';
import Card from '../../../card';
import style from './index.less';
export interface BasicInfoProps {
effect?: any,
}
const count = 0;
const BasicLayout: React.FC<BasicInfoProps> = (props: any) => {
const { effect } = props;
return (
<Card
id='basicLayout'
title='基本信息'
>
<Row gutter={[8, 8]}>
{effect.length > count && effect.map((item, index) => (
<Col key={`effect_${index + 1}`} span={8}>
{ item.col.map((it, idx) => (
<div className={style.cell} key={`effect_col_${idx + 1}`}>
<h5 className={style.label}>{it.label}: </h5>
<h5 className={style.content}>{it.extra}</h5>
</div>
))}
</Col>
))}
</Row>
</Card>
)
}
export default BasicLayout
import React, { useContext } from 'react';
import { Row, Col, Checkbox, InputNumber, Divider, Form } from 'antd';
import style from './index.less';
import { useBidTable } from '../../effects/useBidTable';
import { useBidTable } from '../../../effects/useBidTable';
import { BidDetailContext } from '../context'
import level1 from '@/assets/icons/the_first.png';
import level2 from '@/assets/icons/the_second.png';
import level3 from '@/assets/icons/the_third.png';
const BidTable = () => {
export interface ReduxProps {
redux?(e: any),
}
const BidTable: React.FC<ReduxProps> = (props: any) => {
const { redux } = props;
const [form] = Form.useForm();
const {
formContext: {
......@@ -17,6 +22,13 @@ const BidTable = () => {
}
} = useBidTable();
/**
*
* @param v
* @param index 最外层数据下标
* @param idx 当前选择的公司下标
* @param checked 是否选择
*/
const setAwardTaxProbability = (v, index, idx, checked?) => {
const params = [...bidDetailContext];
const company = [...params[index].company];
......@@ -46,17 +58,11 @@ const BidTable = () => {
})
})
setDataSource([...params]);
redux([...params])
}
const bidDetailContext = useContext(BidDetailContext);
/**
*
* @param e
* @param item 最外层数据
* @param index 最外层数据下标
* @param it 当前选择的公司
* @param idx 当前选择的公司下标
*/
const onChangeInput = (v, index, idx) => {
setAwardTaxProbability(v, index, idx)
}
......
.cell {
display: flex;
h5 { margin-bottom: 2em; }
.label {
flex: 0 0 25%;
color: #909399;
}
}
/** 详情通用 - 交易条件 */
import React from 'react';
import { Row, Col } from 'antd';
import Card from '../../../card';
import style from './index.less';
export interface ConditionProps {
effect?: any,
}
const count = 0
const ConditionLayout: React.FC<ConditionProps> = (props: any) => {
const { effect } = props;
return (
<Card
id='conditionLayout'
title='基本信息'
>
<Row gutter={[8, 8]}>
{effect.length > count && effect.map((item, index) => (
<Col key={`effect_${index + 1}`} span={8}>
{ item.col.map((it, idx) => (
<div className={style.cell} key={`effect_col_${idx + 1}`}>
<h5 className={style.label}>{it.label}: </h5>
<h5 className={style.content}>{it.extra}</h5>
</div>
))}
</Col>
))}
</Row>
</Card>
)
}
export default ConditionLayout
import { createContext } from 'react';
// 招标详情 Context
/** 详情 */
export const Context = createContext<any>({})
/**招标详情 Context */
export const BidDetailContext = createContext<any>({})
.divider {
font-size: 12px;
margin-bottom: 12px;
.vertical {
width: 2px;
height: 16px;
margin: 0px 5px 0px 0px ;
background-color: #00B37A;
}
}
import React, { useContext, useEffect, useState } from 'react';
import { Space, Button, Tabs, Divider, Skeleton, Typography, message } from 'antd';
import { StandardTable } from 'god';
import { history } from 'umi';
import moment from 'moment';
import Card from '../../../card';
import { PRICECONTRAST_TYPE } from '../../../../constants';
import style from './index.less';
import EyePreview from '@/components/EyePreview';
import { PublicApi } from '@/services/api';
import BidTable from '../bidTable';
import { Context, BidDetailContext } from '../context';
import { useBidTable } from '../../../effects/useBidTable';
export interface ContrastProps {
effect?: any,
redux?(e: any),
}
const ContrastLyout: React.FC<ContrastProps> = (props: any) => {
const {
effect: {
id,
turn
},
redux,
} = props;
const {
formContext: {
dataSource,
ctl: { setDataSource }
}
} = useBidTable();
const format = (text) => {
return <>{moment(text).format("YYYY-MM-DD HH:mm:ss")}</>
}
const columns = [
{
title: '报价单号/摘要',
key: 'quotedPriceNo',
dataIndex: 'quotedPriceNo',
render: (text: any, record: any) => (
<Space direction='vertical'>
<EyePreview>{text}</EyePreview>
<Typography.Text>{record.details}</Typography.Text>
</Space>
)
},
{
title: '报价会员',
key: 'createMemberName',
dataIndex: 'createMemberName'
},
{
title: '报价时间',
key: 'createTime',
dataIndex: 'createTime',
render: (text: any, record: any) => (
<Typography.Text>{format(text)}</Typography.Text>
)
},
{
title: '报价总额',
key: 'sumPrice',
dataIndex: 'sumPrice'
},
{
title: '联系人/电话',
key: 'contacts',
dataIndex: 'contacts',
render: (text: any, record: any) => (
<Space direction='vertical'>
<Typography.Text>{text}</Typography.Text>
<Typography.Text>{record.tel}</Typography.Text>
</Space>
)
},
{
title: '解密状态',
key: 'isDecrypt',
dataIndex: 'isDecrypt',
render: (text: any, record: any) => (
<Typography.Text>{text === 1 ? '未加密' : '未解密'}</Typography.Text>
)
},
]
const context = useContext(Context);
const [loading, setLoading] = useState<boolean>(false);
const [disabled, setDisabled] = useState<boolean>(false);
const fetchTableData = (params: any) => {
return new Promise(resolve => {
PublicApi.getPurchaseConfirmQuotedPriceQuotedPriceInfo({ ...params, id, turn }).then(res => {
if (res.code === 1000) {
resolve(res.data)
}
})
})
}
const setBoolean = (flag: boolean) => {
setLoading(flag);
setDisabled(flag);
}
/** 格式化数据 */
const formatting = (data: any) => {
const arr: any = data[0].awardInfoResponses.sort((a, b) => { return a.goodsId - b.goodsId }) || []
const params: any = [];
arr.forEach((i: any, index: number) => {
let item = {
goodsId: i.goodsId,
number: i.number,
name: i.name,
model: i.model,
category: i.category,
brand: i.brand,
unit: i.unit,
purchaseCount: i.purchaseCount,
company: null
}
let companyArr = [];
data.forEach((it: any) => {
const sort = it.awardInfoResponses.sort((a, b) => { return a.goodsId - b.goodsId })
let cItem = {
itemId: sort[index].id,
awardTaxProbability: sort[index].awardTaxProbability || 0,
taxPrice: sort[index].taxPrice,
taxProbability: sort[index].taxProbability,
taxUnitPrice: sort[index].taxUnitPrice,
isTax: sort[index].isTax,
unit: sort[index].unit,
awardCount: it.awardCount,
id: it.id,
memberId: it.memberId,
memberName: it.memberName,
memberRoleId: it.memberRoleId,
minimum: it.minimum,
ranking: it.ranking,
subtotal: it.subtotal,
sumPrice: it.sumPrice,
}
companyArr.push(cItem)
})
item.company = companyArr;
params.push(item);
})
setDataSource(params);
}
/** 立即比价 */
const atonceContrast = () => {
const PRICECONTRAST = context.priceContrast;
if (PRICECONTRAST === PRICECONTRAST_TYPE.UNENCRYPTED) {
setBoolean(true);
const params = {
id,
turn
}
PublicApi.getPurchaseConfirmQuotedPriceRightOffContrastPrice(params).then((res: any) => {
if (res.code === 1000) {
const { data } = res;
if (data.length > 0) {
formatting(data);
} else {
message.error('当前暂无比价信息');
setDisabled(true);
}
setLoading(false);
} else {
setBoolean(false);
}
}).catch(err => {
setBoolean(false)
})
} else {
message.error('当前报价为密封报价,请先解密报价单');
}
}
const reduxFetch = (data: any) => {
redux(data)
}
return (
<BidDetailContext.Provider value={dataSource}>
<Card
id='contrastLyout'
title='报价信息'
extra={
<Space>
<Button onClick={() => history.goBack()}>发起下轮报价</Button>
{context.priceContrast === PRICECONTRAST_TYPE.UNDECRYPTED &&
<Button>
解密报价单
</Button>}
<Button
type='primary'
disabled={disabled}
onClick={atonceContrast}
>
立即比价
</Button>
</Space>
}
>
<Tabs>
<Tabs.TabPane
key='1'
tab='第一轮'
>
<div className={style.divider}>
<Divider type='vertical' className={style.vertical} />
供应商信息
</div>
<StandardTable
columns={columns}
tableProps={{ rowKew: 'id' }}
fetchTableData={(params: any) => fetchTableData(params)}
/>
<Skeleton
active
loading={loading}
/>
{dataSource.length > 0
&& (
<>
<div className={style.divider}>
<Divider type='vertical' className={style.vertical} />
比价信息
</div>
<BidTable redux={reduxFetch} />
</>
)}
</Tabs.TabPane>
</Tabs>
</Card>
</BidDetailContext.Provider>
)
}
export default ContrastLyout;
/** 详情通用 - 流转进度 */
import React, { useContext, useState } from 'react';
import { Radio, Steps } from 'antd';
import { Context } from '../context';
import Card from '../../../card';
import style from './index.less';
const LOGSTATESTYPE = {
/** 外部流转 */
EXTERNALSTATES: 1,
/** 内部流转 */
INTERIORSTATES: 2
}
export interface ProgressProps {}
const ProgressLayout: React.FC<ProgressProps> = () => {
const context = useContext(Context);
const [logStatesStatus, setLogStatesStatus] = useState<number>(LOGSTATESTYPE.EXTERNALSTATES);
return (
<Card
id='progressLayout'
title='流转进度'
extra={
<Radio.Group
onChange={(e) => setLogStatesStatus(e.target.value)}
defaultValue={LOGSTATESTYPE.EXTERNALSTATES}
>
{context.externalLogStates && <Radio.Button value={LOGSTATESTYPE.EXTERNALSTATES}>外部流转</Radio.Button>}
{context.interiorLogStates && <Radio.Button value={LOGSTATESTYPE.INTERIORSTATES}>内部流转</Radio.Button>}
</Radio.Group>
}
>
<Steps
progressDot
>
{logStatesStatus === LOGSTATESTYPE.EXTERNALSTATES ?
context.externalLogStates && context.externalLogStates.map(item => (
<Steps.Step
key={item.state}
title={item.roleName}
description={item.operationalProcess}
status={item.isExecute ? 'finish' : 'wait'}
/>
)) :
context.interiorLogStates && context.interiorLogStates.map(item => (
<Steps.Step
key={item.state}
title={item.roleName}
description={item.operationalProcess}
status={item.isExecute ? 'finish' : 'wait'}
/>
))
}
</Steps>
</Card>
)
}
export default ProgressLayout
/** 详情通用 - 流转进度 */
import React, { useContext, useState } from 'react';
import { Radio, Table } from 'antd';
import { Context } from '../context';
import Card from '../../../card';
import {
EXTERNALLOGS,
INTERNALLOGS,
} from '../../../../constants/columns';
const LOGSTATESTYPE = {
/** 外部流转 */
EXTERNALSTATES: 1,
/** 内部流转 */
INTERIORSTATES: 2
}
export interface ProgressProps {}
const RecordLayout: React.FC<ProgressProps> = () => {
const context = useContext(Context);
const [logStatus, setLogStatus] = useState<number>(LOGSTATESTYPE.EXTERNALSTATES);
return (
<Card
id='recordLyout'
title='流转进度'
extra={
<Radio.Group
onChange={(e) => setLogStatus(e.target.value)}
defaultValue={LOGSTATESTYPE.EXTERNALSTATES}
>
{context.externalLogs && <Radio.Button value={LOGSTATESTYPE.EXTERNALSTATES}>外部流转</Radio.Button>}
{context.externalLogs && <Radio.Button value={LOGSTATESTYPE.INTERIORSTATES}>内部流转</Radio.Button>}
</Radio.Group>
}
>
<Table
columns={logStatus === LOGSTATESTYPE.EXTERNALSTATES ? EXTERNALLOGS : INTERNALLOGS}
dataSource={
logStatus === LOGSTATESTYPE.EXTERNALSTATES ?
context.externalLogs :
context.interiorLogs
}
rowKey={(record) => record.id}
pagination={{
hideOnSinglePage: true
}}
/>
</Card>
)
}
export default RecordLayout
.anchorWrap {
.wrap {
.title {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 16px;
.titleBox {
display: flex;
align-items: center;
.goBack {
font-size: 14px;
color: #909399;
}
.titleContext {
color: #303133;
font-size: 16px;
font-weight: 500;
margin-left: 8px;
}
}
}
.anchor {
display: flex;
padding: 0 16px;
}
.layout {
margin: 24px;
:global {
.ant-card {
margin-bottom: 24px;
.ant-card-head {
> .ant-card-head-wrapper {
padding: 12px 0;
}
}
.ant-card-extra {
padding: 0 0;
.ant-radio-button-wrapper {
height: 24px;
line-height: 23px;
}
.ant-radio-button-wrapper:hover {
color: #606266;
}
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
color: #fff;
background: #6B778C;
border-color: #6B778C;
}
}
}
.god-table-control {
margin-bottom: 0;
}
}
}
:global {
.ant-anchor {
display: flex;
......@@ -24,53 +79,5 @@
}
}
}
.titleBox {
padding: 8px 16px;
}
.anchorBox {
display: flex;
padding: 0 16px;
}
}
/** 卡片样式 */
.card {
margin: 24px;
:global {
.ant-card {
margin-bottom: 24px;
.ant-card-head {
> .ant-card-head-wrapper {
padding: 12px 0;
}
}
.ant-card-extra {
padding: 0 0;
.ant-radio-button-wrapper {
height: 24px;
line-height: 23px;
}
.ant-radio-button-wrapper:hover {
color: #606266;
}
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
color: #fff;
background: #6B778C;
border-color: #6B778C;
}
}
}
.god-table-control {
margin-bottom: 0;
}
}
.list {
display: flex;
h5 {
margin-bottom: 2em;
}
.listLable {
flex: 0 0 25%;
color: #909399;
}
}
}
import React, { useEffect, useState, useRef } from 'react';
import { Anchor, Radio, Steps, Row, Col } from 'antd';
import React, { useEffect, useState, useContext } from 'react';
import { Anchor, Button } from 'antd';
import { Context } from './components/context';
import style from './index.less';
import { ArrowLeftOutlined } from '@ant-design/icons';
import { StandardTable } from 'god';
const { Link } = Anchor;
const { Step } = Steps;
import { ArrowLeftOutlined, CheckCircleOutlined } from '@ant-design/icons';
const activeAnchorClassName = 'ant-anchor-link-active'
const Detail = (props:any) => {
const ref = useRef({});
const [currLink, setCurrLink] = useState(activeAnchorClassName)
const [tabPane] = useState([
{ id: 'progress', title: '流转进度' },
{ id: 'process', title: '基本流程' },
{ id: 'materials', title: '采购材料' },
{ id: 'conditions', title: '交易条件' },
{ id: 'docking', title: '需求对接' },
{ id: 'record', title: '流转记录' },
])
export type tabLink = {
id: string,
title: string
}
export interface IProps {
/** 单号 */
no?: string,
/** 锚点Link */
tabLink?: Array<tabLink>,
/** 审核操作按钮放这 */
effect?: React.ReactNode,
/** 页面的组件 */
components?: React.ReactNode,
}
const PeripheralLayout: React.FC<IProps> = (props: any) => {
const {
no,
tabLink,
effect,
components,
} = props;
const dataSource = useContext(Context)
/** the argument */
const [targetOffset, setTargetOffset] = useState<number | undefined>(undefined);
useEffect(() => {
setTargetOffset(window.innerHeight / 6);
}, []);
const handleAnchorClick = (e) => {
e.preventDefault()
}
const handleAnchorChange = (link) => {
const [currLink, setCurrLink] = useState(activeAnchorClassName)
/** the event */
const onChange = (link) => {
if (link && currLink) {
setCurrLink('')
} else if (!link && !currLink) {
setCurrLink(activeAnchorClassName)
}
};
/** 采购物料 */
const columns = [
{
title: '物料编号',
key: 'productId',
dataIndex: 'productId',
},
{
title: '物料名称',
key: 'productId',
dataIndex: 'productId',
},
{
title: '规格型号',
key: 'productId',
dataIndex: 'productId',
},
{
title: '品类',
key: 'productId',
dataIndex: 'productId',
},
{
title: '品牌',
key: 'productId',
dataIndex: 'productId',
},
{
title: '单位',
key: 'productId',
dataIndex: 'productId',
},
{
title: '采购数量',
key: 'productId',
dataIndex: 'productId',
},
]
/** 基本信息 */
const basicInfo = {
col1: [
{ label: '需求单号', extra: 'SPTY12' },
{ label: '外部状态', extra: '待提交采购需求单' },
{ label: '内部状态', extra: '待审核采购需求单(一级)' },
{ label: '单据时间', extra: '2020-12-25 09:00' },
],
col2: [
{ label: '需求摘要', extra: '进口头层黄牛皮荔枝纹' },
{ label: '招标采购类型', extra: '协议采购' },
{ label: '比价方式', extra: '非密封补价' },
{ label: '会员名称', extra: '温州龙昌手袋有限公司' },
],
col3: [
{ label: '适用地市', extra: '进口头层黄牛皮荔枝纹' },
],
}
/** 交易条件 */
const dealCondition = {
col1: [
{ label: '交付日期', extra: '2020-08-25' },
{ label: '交付地址', extra: '东莞市石龙镇西湖路53号' },
{ label: '交付日期', extra: '2020-08-25 18:00' },
],
col2: [
{ label: '报价要求', extra: '实价' },
{ label: '付款方式', extra: '首付30%,收货后70%' },
{ label: '税费要求', extra: '含税' },
],
col3: [
{ label: '物流要求', extra: '要求送至指定收货地址' },
{ label: '包装要求', extra: '纸箱' },
{ label: '其他要求', extra: '无' },
],
const onClick = (e) => {
e.preventDefault();
}
useEffect(() => {
setTargetOffset(window.innerHeight / 6);
}, [])
return (
<div className={style.anchorWrap}>
<div className={style.wrap}>
<Anchor
targetOffset={targetOffset}
onChange={handleAnchorChange}
onClick={handleAnchorClick}
onChange={onChange}
onClick={onClick}
>
{/* 头部信息 */}
<div style={{ flex: 1 }}>
<div className={style.titleBox}>
<div
style={{
display: 'flex',
alignItems: 'center',
}}
>
<ArrowLeftOutlined
style={{
fontSize: '14px',
color: '#909399',
}}
/>
<span
style={{
fontSize: '16px',
color: '#303133',
fontWeight: 500,
marginLeft: '8px',
}}
>
进口头层黄牛皮荔枝纹 | SPTY12
</span>
<div className={style.title}>
<div className={style.titleBox}>
<ArrowLeftOutlined className={style.goBack} />
<span className={style.titleContext}>
{dataSource.details}
|
{no}
</span>
</div>
{effect}
</div>
<div className={style.anchorBox}>
{tabPane.map((item, idx) => (
<Link className={!idx && currLink} key={`link${idx + 1}`} href={`#${item.id}`} title={item.title} />
<div className={style.anchor}>
{tabLink.map((item, index) => (
<Anchor.Link
className={!index && currLink}
key={`link${index + 1}`}
href={`#${item.id}`}
title={item.title}
/>
))}
</div>
</div>
</Anchor>
<div id='content' className={style.card}>
{/* 流转进度 */}
<div id='progress' className='ant-card ant-card-bordered'>
<div className='ant-card-head'>
<div className='ant-card-head-wrapper'>
<div className='ant-card-head-wrapper'>
流转进度
</div>
<div className='ant-card-extra'>
<Radio.Group defaultValue="a">
<Radio.Button value="a">外部流转</Radio.Button>
<Radio.Button value="b">内部流转</Radio.Button>
</Radio.Group>
</div>
</div>
</div>
<div className='ant-card-body'>
<Steps current={1} progressDot>
<Step title="Finished" description="This is a description" />
<Step title="In Process" description="This is a description" />
<Step title="Waiting" description="This is a description" />
</Steps>
</div>
</div>
{/* 基本信息 */}
<div id='process' className='ant-card ant-card-bordered'>
<div className='ant-card-head'>
<div className='ant-card-head-wrapper'>
<div className='ant-card-head-wrapper'>
基本信息
</div>
</div>
</div>
<div className='ant-card-body'>
<Row gutter={[8, 8]}>
<Col span={8}>
{basicInfo.col1.map((item: any, index: number) => (
<div className={style.list} key={`col1_${index + 1}`}>
<h5 className={style.listLable}>{item.label}</h5>
<h5 className={style.listContent}>{item.extra}</h5>
</div>
))}
</Col>
<Col span={8}>
{basicInfo.col2.map((item: any, index: number) => (
<div className={style.list} key={`col2_${index + 1}`}>
<h5 className={style.listLable}>{item.label}</h5>
<h5 className={style.listContent}>{item.extra}</h5>
</div>
))}
</Col>
<Col span={8}>
{basicInfo.col3.map((item: any, index: number) => (
<div className={style.list} key={`col3_${index + 1}`}>
<h5 className={style.listLable}>{item.label}</h5>
<h5 className={style.listContent}>{item.extra}</h5>
</div>
))}
</Col>
</Row>
</div>
</div>
{/* 采购材料 */}
<div id='materials' className='ant-card ant-card-bordered'>
<div className='ant-card-head'>
<div className='ant-card-head-wrapper'>
<div className='ant-card-head-wrapper'>
采购材料
</div>
</div>
</div>
<div className='ant-card-body'>
<StandardTable
currentRef={ref}
columns={columns}
tableProps={{ rowKew: 'id' }}
/>
</div>
</div>
{/* 交易条件 */}
<div id='conditions' className='ant-card ant-card-bordered'>
<div className='ant-card-head'>
<div className='ant-card-head-wrapper'>
<div className='ant-card-head-wrapper'>
交易条件
</div>
</div>
</div>
<div className='ant-card-body'>
<Row gutter={[8, 8]}>
<Col span={8}>
{dealCondition.col1.map((item: any, index: number) => (
<div className={style.list} key={`col1_${index + 1}`}>
<h5 className={style.listLable}>{item.label}</h5>
<h5 className={style.listContent}>{item.extra}</h5>
</div>
))}
</Col>
<Col span={8}>
{dealCondition.col2.map((item: any, index: number) => (
<div className={style.list} key={`col2_${index + 1}`}>
<h5 className={style.listLable}>{item.label}</h5>
<h5 className={style.listContent}>{item.extra}</h5>
</div>
))}
</Col>
<Col span={8}>
{dealCondition.col3.map((item: any, index: number) => (
<div className={style.list} key={`col3_${index + 1}`}>
<h5 className={style.listLable}>{item.label}</h5>
<h5 className={style.listContent}>{item.extra}</h5>
</div>
))}
</Col>
</Row>
</div>
</div>
{/* 交易条件 */}
<div id='docking' className='ant-card ant-card-bordered'>
<div className='ant-card-head'>
<div className='ant-card-head-wrapper'>
<div className='ant-card-head-wrapper'>
需求对接
</div>
</div>
</div>
<div className='ant-card-body'>
<StandardTable
currentRef={ref}
columns={columns}
tableProps={{ rowKew: 'id' }}
/>
</div>
</div>
{/* 流转记录 */}
<div id='record' className='ant-card ant-card-bordered'>
<div className='ant-card-head'>
<div className='ant-card-head-wrapper'>
<div className='ant-card-head-wrapper'>
流转记录
</div>
<div className='ant-card-extra'>
<Radio.Group defaultValue="a">
<Radio.Button value="a">外部流转</Radio.Button>
<Radio.Button value="b">内部流转</Radio.Button>
</Radio.Group>
</div>
</div>
</div>
<div className='ant-card-body'>
<Steps current={1} progressDot>
<Step title="Finished" description="This is a description" />
<Step title="In Process" description="This is a description" />
<Step title="Waiting" description="This is a description" />
</Steps>
</div>
</div>
<div className={style.layout}>
{components}
</div>
</div>
)
}
export default Detail;
export default PeripheralLayout
......@@ -7,11 +7,11 @@ import {
Upload,
message
} from 'antd';
import { BidDetailContext } from '../context'
import { UploadOutlined, LinkOutlined, DeleteOutlined } from '@ant-design/icons';
import { UPLOAD_TYPE } from '@/constants'
import style from './index.less'
import { PublicApi } from '@/services/api';
import { BidDetailContext } from '../components/context';
const { TextArea } = Input;
......@@ -26,10 +26,10 @@ export interface IProps {
const BidModal: React.FC<IProps> = (props: any) => {
const [form] = Form.useForm();
const { id, turn, visible, handleConfirm, onCancel } = props;
const bidDetailContext = useContext(BidDetailContext);
const [files, setFiles] = useState([]);
const [loading, setloading] = useState(false);
const [priceParityInfos, setPriceParityInfos] = useState<any>([]);
const dataSource = useContext(BidDetailContext);
/**判断文件类型和大小 */
const beforeDocUpload = (file: any) => {
const isLt20M = file.size / 1024 / 1024 < 20;
......@@ -61,8 +61,10 @@ const BidModal: React.FC<IProps> = (props: any) => {
}
useEffect(() => {
if (bidDetailContext.length > 0) {
const arr: any = bidDetailContext[0].company || [];
console.log(dataSource, 10086)
if (dataSource.length > 0) {
console.log(dataSource, 10086)
const arr: any = dataSource[0].company || [];
const params: any = [];
arr.forEach((it: any, idx: number) => {
let item = {
......@@ -77,14 +79,12 @@ const BidModal: React.FC<IProps> = (props: any) => {
sumPrice: it.sumPrice,
awardInfoResponses: [],
}
console.log(item)
let awardInfoResponses = [];
bidDetailContext.forEach((item: any, index: number) => {
dataSource.forEach((item: any, index: number) => {
let cItem = {
brand: item.brand,
category: item.category,
goodsId: item.goodsId,
id: item.id,
unit: item.unit,
model: item.model,
name: item.name,
......@@ -96,6 +96,7 @@ const BidModal: React.FC<IProps> = (props: any) => {
taxUnitPrice: item.company[idx].taxUnitPrice,
isPrize: item.company[idx].isPrize,
isTax: item.company[idx].isTax,
id: item.company[idx].itemId,
}
awardInfoResponses.push(cItem)
})
......
import { useState } from 'react'
import { useEffect, useState } from 'react'
export const useBidTable = () => {
const [dataSource, setDataSource] = useState<any>([]);
......@@ -6,11 +6,14 @@ export const useBidTable = () => {
const formContext = {
dataSource: dataSource,
ctl: {
dataSource: dataSource,
setDataSource: setDataSource,
},
}
useEffect(() => {
console.log(dataSource, 10086)
}, [dataSource])
return {
formContext
}
......
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { Modal, Button, Popconfirm } from 'antd';
import {
SchemaForm, SchemaMarkupField as Field,
createFormActions,
FormEffectHooks,
} from '@formily/antd'
import { Input, Radio, DatePicker } from '@formily/antd-components'
import { Input, Radio, DatePicker, Checkbox } from '@formily/antd-components'
import moment from 'moment';
const actions = createFormActions()
const { onFieldChange$ } = FormEffectHooks;
......@@ -14,7 +14,7 @@ export interface IProps {
title: string,
visible: boolean,
id: number,
modalType: 'audit' | 'abandon' | 'date',
modalType: 'audit' | 'abandon' | 'date' | 'next' | 'key',
onCancel?: () => void,
onOk?: () => void,
fetch?: () => Promise<unknown>,
......@@ -44,6 +44,15 @@ const ModalOperate: React.FC<IProps> = (props: any) => {
})
})
}
if (modalType === 'date') {
onFieldChange$('checkbox').subscribe(({ value }) => {
if (value && value.length > 0) {
actions.setFieldValue('quotedPriceTime', moment().format());
} else {
actions.setFieldValue('quotedPriceTime', undefined);
}
})
}
}
const disabledDate = (current) => {
......@@ -72,24 +81,65 @@ const ModalOperate: React.FC<IProps> = (props: any) => {
required
x-component="DatePicker"
x-component-props={{
style: {
width: '100%'
},
format: 'YYYY-MM-DD HH:mm:ss',
disabledDate,
}}
/>
case 'date':
return <>
<Field
title="报价截止时间"
name="quotedPriceTime"
required
x-component="DatePicker"
x-component-props={{
style: {
width: '100%'
},
format: 'YYYY-MM-DD HH:mm:ss',
disabledDate,
}}
/>
<Field
name="checkbox"
x-component="CheckboxGroup"
description="勾选后供应商不能再提交报价单"
enum={[{label: '立即截止报价', value: 1}]}
/>
</>
case 'next':
return <Field
title="报价截止时间"
title="下轮报价截止时间"
name="quotedPriceTime"
required
x-component="DatePicker"
x-component-props={{
style: {
width: '100%'
},
format: 'YYYY-MM-DD HH:mm:ss',
disabledDate,
}}
/>
case 'key':
return <Field
title="请输入解密密钥"
x-component="Input"
name="password"
required
x-component-props={{}}
/>
}
}
useEffect(() => {
if (modalType === 'next') {
actions.setFieldValue('quotedPriceTime', moment().format())
}
}, [])
const handleSubmit = (val: any) => {
let value = { ...val }
......@@ -100,8 +150,12 @@ const ModalOperate: React.FC<IProps> = (props: any) => {
} else if (modalType === 'abandon') {
params.reason = value.reason
params.reasonTime = new Date(value.reasonTime).getTime();
} else {
} else if (modalType === 'date') {
params.quotedPriceTime = new Date(value.quotedPriceTime).getTime();
} else if (modalType === 'next') {
params.quotedPriceTime = new Date(value.quotedPriceTime).getTime();
} else {
params.password = value.password;
}
fetch({ id, ...params }).then(res => {
if (res.code === 1000) {
......@@ -120,27 +174,9 @@ const ModalOperate: React.FC<IProps> = (props: any) => {
width={600}
title={title}
visible={visible}
onCancel={handleClose}
onOk={() => actions.submit()}
afterClose={() => actions.reset()}
footer={
<>
<Button onClick={handleClose}>取消</Button>
{ modalType === 'date'
&& (
<Popconfirm
title="是否立即截止报价?点击确定后供应商不能再提交报价单。"
okText="是"
cancelText="否"
onConfirm={() => {
actions.setFieldValue('quotedPriceTime', moment().format());
actions.submit()
}}>
<Button type="primary">立即截止报价</Button>
</Popconfirm>
)}
<Button type="primary" onClick={() => actions.submit()}>确定</Button>
</>
}
>
<SchemaForm
layout="vertical"
......@@ -150,6 +186,8 @@ const ModalOperate: React.FC<IProps> = (props: any) => {
Radio: Radio.Group,
TextArea: Input.TextArea,
DatePicker,
Checkbox,
CheckboxGroup: Checkbox.Group
}}
actions={actions}
effects={() => useFormEffects()}
......
import React, { useState, useEffect, Fragment } from 'react';
import { PublicApi } from '@/services/api';
import { Tag, Badge, Tooltip, Button } from 'antd';
import { Context, BidDetailContext } from '../../components/detail/components/context';
import { history } from 'umi';
import PeripheralLayout from '../../components/detail';
import ProgressLayout from '../../components/detail/components/progressLayout';
import BasicLayout from '../../components/detail/components/basicLayout';
import ConditionLayout from '../../components/detail/components/conditionLayout';
import ContrastLyout from '../../components/detail/components/contrastLyout';
import RecordLyout from '../../components/detail/components/recordLyout';
import {
OFFTER_EXTERNALSTATE,
OFFTER_EXTERNALSTATE_COLOR,
OFFTER_INTERNALSTATE,
OFFTER_INTERNALSTATE_COLOR,
} from '../../constants';
import { CheckCircleOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import moment from 'moment';
import BidModal from '../../components/detail/modal';
const ICONSTYLE: any = {
color: '#C0C4CC',
fontSize: '14px',
marginLeft: '5px'
}
const TABLINK = [
{ id: 'progressLayout', title: '流转进度' },
{ id: 'basicLayout', title: '基本信息' },
{ id: 'conditionLayout', title: '交易条件' },
{ id: 'contrastLyout', title: '报价信息' },
{ id: 'recordLyout', title: '流转记录' },
]
const ContrastPrice = () => {
const format = (text) => {
return <>{moment(text).format("YYYY-MM-DD HH:mm:ss")}</>
}
const { query: { id, turn } } = history.location;
const [dataSource, setDataSource] = useState<any>({});
const [basicEffect, setBasicEffect] = useState<any>([]);
const [conditionEffect, setConditionEffect] = useState<any>([]);
const [visible, setVisible] = useState<boolean>(false);
const [auditDataSource, setAuditDataSource] = useState<any>([]);
const handleBasicEffect = (data: any) => {
setBasicEffect([
{
col: [
{ label: '需求单号', extra: data.purchaseInquiryNo },
{ label: '需求摘要', extra: data.details },
{ label: '外部状态', extra: <Tag color={OFFTER_EXTERNALSTATE_COLOR[data.externalState]}>{OFFTER_EXTERNALSTATE[data.externalState]}</Tag> },
{ label: '内部状态', extra: <Badge status={OFFTER_INTERNALSTATE_COLOR[data.interiorState]} text={OFFTER_INTERNALSTATE[data.interiorState]} /> },
]
},
{
col: [
{
label: '采购类型',
extra: (
<Tooltip placement="top" title='有固定采购金额:采购金额固定,合同期内不可超过采购金额,无固定采购金额:采购金额不固定,可在合同期内按需采购'>
{data.purchaseType === 1 ? '有固定采购金额' : '无固定采购金额'}<QuestionCircleOutlined style={ICONSTYLE} />
</Tooltip>
)
},
{
label: '比价方式',
extra: (
<Tooltip placement="top" title='密封比价:只能看到供应商是否有报价,不能看到供应商的报价明细,只能解封后才能看到报价明细,非密封比价:可以在供应商报完价后立即看到报价明细,无须解封'>
{data.priceContrast === 1 ? '密封比价' : '非密封比价'}<QuestionCircleOutlined style={ICONSTYLE} />
</Tooltip>
)
},
{ label: '会员名称', extra: data.memberName },
]
},
{
col: [
{ label: '单据时间', extra: format(data.createTime) },
{ label: '适用地市', extra: '-' },
]
},
])
}
const handleConditionEffect = (data: any) => {
setConditionEffect([
{
col: [
{ label: '交付日期', extra: format(data.deliveryTime) },
{ label: '交付地址', extra: data.address },
{ label: '报价截止时间', extra: format(data.offerEndTime) },
]
},
{
col: [
{ label: '报价要求', extra: data.offer },
{ label: '付款方式', extra: data.paymentType },
{ label: '税费要求', extra: data.taxes },
]
},
{
col: [
{ label: '物流要求', extra: data.logistics },
{ label: '包装要求', extra: data.packRequire },
{ label: '其他要求', extra: data.otherRequire },
]
},
])
}
const handleGetDataSource = async (trunId: string) => {
const parmas = {
id,
turn: trunId,
}
await PublicApi.getPurchaseConfirmQuotedPriceDetails({ ...parmas }).then(res => {
if (res.code === 1000) {
const { data } = res;
setDataSource(data)
handleBasicEffect(data);
handleConditionEffect(data);
}
})
}
useEffect(() => {
handleGetDataSource(turn)
}, [])
const handleConfirm = () => {
setVisible(false);
history.goBack();
}
const handleContrastLyoutData = (data: any) => {
setAuditDataSource(data)
}
return (
<Context.Provider value={dataSource}>
<PeripheralLayout
no={dataSource.purchaseInquiryNo}
tabLink={TABLINK}
effect={
<Button
type='primary'
onClick={() => setVisible(true)}
>
<CheckCircleOutlined />
单据审核
</Button>
}
components={
<Fragment>
<ProgressLayout />
<BasicLayout effect={basicEffect} />
<ConditionLayout effect={conditionEffect} />
<ContrastLyout effect={{ id, turn }} redux={handleContrastLyoutData} />
<RecordLyout />
</Fragment>
}
/>
<BidDetailContext.Provider value={auditDataSource}>
<BidModal
id={id}
turn={turn}
visible={visible}
handleConfirm={handleConfirm}
onCancel={() => setVisible(false)}
/>
</BidDetailContext.Provider>
</Context.Provider>
)
}
export default ContrastPrice
.anchorWrap {
:global {
.ant-anchor {
display: flex;
.ant-anchor-ink {
display: none;
}
.ant-anchor-link {
padding: 14px 0 !important;
margin: 0 16px;
.ant-anchor-link-title {
font-size: 14px;
color: #909399;
}
}
.ant-anchor-link-active {
position: relative;
border-bottom: 2px solid #00B37A;
box-sizing: border-box;
.ant-anchor-link-title {
font-weight: 500;
color: #303133;
}
}
}
}
.titleBox {
padding: 8px 16px;
}
.anchorBox {
display: flex;
padding: 0 16px;
}
}
/** 卡片样式 */
.card {
margin: 24px;
:global {
.ant-card {
margin-bottom: 24px;
.ant-card-head {
> .ant-card-head-wrapper {
padding: 12px 0;
}
}
.ant-card-extra {
padding: 0 0;
.ant-radio-button-wrapper {
height: 24px;
line-height: 23px;
}
.ant-radio-button-wrapper:hover {
color: #606266;
}
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
color: #fff;
background: #6B778C;
border-color: #6B778C;
}
}
}
.god-table-control {
margin-bottom: 0;
}
}
.list {
display: flex;
h5 {
margin-bottom: 2em;
}
.listLable {
flex: 0 0 25%;
color: #909399;
}
}
}
.label {
margin-bottom: 0px !important;
:global {
.ant-form-item-control-input-content {
display: flex;
.ant-input-number {
margin-left: 16px;
width: 64px;
}
}
}
}
.flex {
display: flex;
align-items: center;
}
.badge {
display: inline-block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
border-radius: 10px;
background-color: #EBECF0;
color: #909399;
margin-right: 5px;
}
.affix_title {
font-size: 12px;
margin-bottom: 12px;
.divider_style {
width: 2px;
height: 16px;
margin: 0px 5px 0px 0px ;
background-color: #00B37A;
}
}
// .tableCard {
// :global {
// .ant-table table {
// border: 3px solid #F4F5F7 !important;
// border-bottom: 2px !important;
// }
// .ant-table-thead {
// .ant-table-cell {
// background-color: #F4F5F7;
// }
// }
// .ant-table-tbody {
// .ant-table-cell {
// border-bottom: 3px solid #F4F5F7;
// }
// }
// }
// }
.percentum_icon {
width: 32px;
height: 32px;
text-align: center;
line-height: 30px;
background-color: #F7F8FA;
color: #909399;
border: 1px solid #d9d9d9;
border-left: none;
}
import React, { useEffect, useState, useRef } from 'react';
import {
Anchor,
Radio,
Steps,
Row,
Col,
Tag,
Badge,
Tooltip,
Table,
Tabs,
Space,
Button,
Divider,
Typography,
message,
Skeleton,
} from 'antd';
import style from './index.less';
import { ArrowLeftOutlined, CheckCircleOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import { history } from 'umi';
import { PublicApi } from '@/services/api';
import {
OFFTER_EXTERNALSTATE,
OFFTER_EXTERNALSTATE_COLOR,
OFFTER_INTERNALSTATE,
OFFTER_INTERNALSTATE_COLOR,
PRICECONTRAST_TYPE
} from '../../constants';
import {
EXTERNALLOGS,
INTERNALLOGS,
} from '../../constants/columns';
import moment from 'moment';
import { StandardTable } from 'god';
import EyePreview from '@/components/EyePreview';
import BidTable from './components/bidTable';
import { BidDetailContext } from './components/context'
import { useBidTable } from './effects/useBidTable';
import BidModal from './components/modal';
import Card from '../../components/card';
const { TabPane } = Tabs;
const { Link } = Anchor;
const { Step } = Steps;
const { Text } = Typography;
const activeAnchorClassName = 'ant-anchor-link-active'
const LogType = {
externalLogs: 1,
interiorLogs: 2,
}
const LogStatesType = {
externalLogStates: 1,
interiorLogStates: 2,
}
const iconStyle: any = {
color: '#C0C4CC',
fontSize: '14px',
marginLeft: '5px'
}
const Detail = () => {
const {
formContext: {
dataSource,
ctl: { setDataSource }
}
} = useBidTable()
const format = (text) => {
return <>{moment(text).format("YYYY-MM-DD HH:mm:ss")}</>
}
const ref = useRef({});
const [currLink, setCurrLink] = useState(activeAnchorClassName)
const [tabPane] = useState([
{ id: 'progress', title: '流转进度' },
{ id: 'basic', title: '基本信息' },
{ id: 'conditions', title: '交易条件' },
{ id: 'docking', title: '报价信息' },
{ id: 'record', title: '流转记录' },
])
const [targetOffset, setTargetOffset] = useState<number | undefined>(undefined);
const { query: { id, turn }, pathname } = history.location;
const [path] = useState(pathname.split('/')[pathname.split('/').length - 1]);
const [links] = useState(pathname.split('/')[pathname.split('/').length - 2]);
const [data, setData] = useState<any>({});
const [logStatesStatus, setLogStatesStatus] = useState<number>(LogStatesType.externalLogStates);
const [logStatus, setLogStatus] = useState<number>(LogType.externalLogs);
// const [dataSource, setDataSource] = useState<any>([]);
const [disivble, setDisivble] = useState<boolean>(false);
const [loading, setloading] = useState<boolean>(false);
const [visible, setVisible] = useState<boolean>(false);
/** 数据格式化 */
const handleGetDataSource = (resolve: any) => {
const arr: any = resolve[0].awardInfoResponses.sort((a, b) => { return a.goodsId - b.goodsId }) || []
const params: any = [];
arr.forEach((i: any, index: number) => {
let item = {
id: i.id,
goodsId: i.goodsId,
number: i.number,
name: i.name,
model: i.model,
category: i.category,
brand: i.brand,
unit: i.unit,
purchaseCount: i.purchaseCount,
company: null
}
let companyArr = [];
resolve.forEach((it: any, idx: number) => {
const sort = it.awardInfoResponses.sort((a, b) => { return a.goodsId - b.goodsId })
let cItem = {
awardTaxProbability: sort[index].awardTaxProbability || 0,
taxPrice: sort[index].taxPrice,
taxProbability: sort[index].taxProbability,
taxUnitPrice: sort[index].taxUnitPrice,
isTax: sort[index].isTax,
unit: sort[index].unit,
awardCount: it.awardCount,
id: it.id,
memberId: it.memberId,
memberName: it.memberName,
memberRoleId: it.memberRoleId,
minimum: it.minimum,
ranking: it.ranking,
subtotal: it.subtotal,
sumPrice: it.sumPrice
}
companyArr.push(cItem)
})
item.company = companyArr;
params.push(item);
// if (arr.length - 1 === index) {
// params.push(item);
// params.push(item);
// }
})
setDataSource(params)
}
/** 获取报价详情 */
const handleGetQuotedDetail = async (num: string) => {
const parmas = {
id,
turn: num,
}
await PublicApi.getPurchaseConfirmQuotedPriceDetails(parmas).then(res => {
if (res.code === 1000) {
setData(res.data)
}
})
}
/**报价单详情-物料详情列表分页查询 */
const handleGetMaterielDetailed = (params: any) => {
return new Promise(resolve => {
PublicApi.getPurchaseConfirmQuotedPriceQuotedPriceInfo({ ...params, id, turn }).then(res => {
if (res.code === 1000) {
resolve(res.data)
}
})
})
}
useEffect(() => {
setTargetOffset(window.innerHeight / 6);
handleGetQuotedDetail(turn)
}, []);
const handleAnchorClick = (e) => {
e.preventDefault()
}
const handleAnchorChange = (link) => {
if (link && currLink) {
setCurrLink('')
} else if (!link && !currLink) {
setCurrLink(activeAnchorClassName)
}
};
/** 基本信息 */
const basicInfo = {
col1: [
{ label: '需求单号', extra: data.purchaseInquiryNo },
{ label: '需求摘要', extra: data.details },
{ label: '外部状态', extra: <Tag color={OFFTER_EXTERNALSTATE_COLOR[data.externalState]}>{OFFTER_EXTERNALSTATE[data.externalState]}</Tag> },
{ label: '内部状态', extra: <Badge status={OFFTER_INTERNALSTATE_COLOR[data.interiorState]} text={OFFTER_INTERNALSTATE[data.interiorState]} /> },
],
col2: [
{
label: '采购类型',
extra: (
<Tooltip placement="top" title='有固定采购金额:采购金额固定,合同期内不可超过采购金额,无固定采购金额:采购金额不固定,可在合同期内按需采购'>
{data.purchaseType === 1 ? '有固定采购金额' : '无固定采购金额'}<QuestionCircleOutlined style={iconStyle} />
</Tooltip>
)
},
{
label: '比价方式',
extra: (
<Tooltip placement="top" title='密封比价:只能看到供应商是否有报价,不能看到供应商的报价明细,只能解封后才能看到报价明细,非密封比价:可以在供应商报完价后立即看到报价明细,无须解封'>
{data.priceContrast === 1 ? '密封比价' : '非密封比价'}<QuestionCircleOutlined style={iconStyle} />
</Tooltip>
)
},
{ label: '会员名称', extra: data.memberName },
],
col3: [
{ label: '单据时间', extra: format(data.createTime) },
{ label: '适用地市', extra: '-' },
],
}
/** 交易条件 */
const dealCondition = {
col1: [
{ label: '交付日期', extra: format(data.deliveryTime) },
{ label: '交付地址', extra: data.address },
{ label: '报价截止时间', extra: format(data.offerEndTime) },
],
col2: [
{ label: '报价要求', extra: data.offer },
{ label: '付款方式', extra: data.paymentType },
{ label: '税费要求', extra: data.taxes },
],
col3: [
{ label: '物流要求', extra: data.logistics },
{ label: '包装要求', extra: data.packRequire },
{ label: '其他要求', extra: data.otherRequire },
],
}
const StandardTableColumns = [
{
title: '报价单号/摘要',
key: 'quotedPriceNo',
dataIndex: 'quotedPriceNo',
render: (text: any, record: any) => (
<Space direction='vertical'>
<EyePreview>{text}</EyePreview>
<Text>{record.details}</Text>
</Space>
)
},
{
title: '报价会员',
key: 'createMemberName',
dataIndex: 'createMemberName'
},
{
title: '报价时间',
key: 'createTime',
dataIndex: 'createTime',
render: (text: any, record: any) => (
<Text>{format(text)}</Text>
)
},
{
title: '报价总额',
key: 'sumPrice',
dataIndex: 'sumPrice'
},
{
title: '联系人/电话',
key: 'contacts',
dataIndex: 'contacts',
render: (text: any, record: any) => (
<Space direction='vertical'>
<Text>{text}</Text>
<Text>{record.tel}</Text>
</Space>
)
},
{
title: '解密状态',
key: 'isDecrypt',
dataIndex: 'isDecrypt',
render: (text: any, record: any) => (
<Text>{text === 1 ? '未加密' : '未解密'}</Text>
)
},
]
/** 立即比价 */
const handlePriceContrast = () => {
const PRICECONTRAST = data.priceContrast;
if (PRICECONTRAST === PRICECONTRAST_TYPE.UNENCRYPTED) {
setloading(true);
setDisivble(true);
const params = {
id,
turn
}
PublicApi.getPurchaseConfirmQuotedPriceRightOffContrastPrice(params).then((res: any) => {
if (res.code === 1000) {
setloading(false);
handleGetDataSource(res.data);
} else {
setDisivble(false);
setloading(false);
}
}).catch(err => {
setDisivble(false);
setloading(false);
})
} else {
message.error('当前报价为密封报价,请先解密报价单');
}
}
const handleConfirm = () => {
setVisible(false);
history.goBack()
}
return (
<BidDetailContext.Provider value={dataSource}>
<div className={style.anchorWrap}>
<Anchor
targetOffset={targetOffset}
onChange={handleAnchorChange}
onClick={handleAnchorClick}
>
<div style={{ flex: 1 }}>
<div className={style.titleBox}>
<div
style={{
display: 'flex',
alignItems: 'center',
}}
>
<ArrowLeftOutlined
style={{
fontSize: '14px',
color: '#909399',
}}
/>
<span
style={{
fontSize: '16px',
color: '#303133',
fontWeight: 500,
marginLeft: '8px',
}}
>
{data.details} | {data.purchaseInquiryNo}
</span>
</div>
<Button
type='primary'
onClick={() => setVisible(true)}
>
<CheckCircleOutlined />
单据审核
</Button>
</div>
<div className={style.anchorBox}>
{tabPane.map((item, idx) => (
<Link className={!idx && currLink} key={`link${idx + 1}`} href={`#${item.id}`} title={item.title} />
))}
</div>
</div>
</Anchor>
<div id='content' className={style.card}>
{/* 流转进度 */}
<Card
id='progress'
title='流转进度'
extra={
<Radio.Group
onChange={(e) => setLogStatesStatus(e.target.value)}
defaultValue={LogStatesType.externalLogStates}
>
{data.externalLogStates && <Radio.Button value={LogStatesType.externalLogStates}>外部流转</Radio.Button>}
{data.interiorLogStates && <Radio.Button value={LogStatesType.interiorLogStates}>内部流转</Radio.Button>}
</Radio.Group>
}
>
<Steps
progressDot
>
{logStatesStatus === LogStatesType.externalLogStates ?
data.externalLogStates && data.externalLogStates.map(item => (
<Step
key={item.state}
title={item.roleName}
description={item.operationalProcess}
status={item.isExecute ? 'finish' : 'wait'}
/>
)) :
data.interiorLogStates && data.interiorLogStates.map(item => (
<Step
key={item.state}
title={item.roleName}
description={item.operationalProcess}
status={item.isExecute ? 'finish' : 'wait'}
/>
))
}
</Steps>
</Card>
{/* 基本信息 */}
<Card
id='basic'
title='基本信息'
>
<Row gutter={[8, 8]}>
<Col span={8}>
{basicInfo.col1.map((item: any, index: number) => (
<div className={style.list} key={`col1_${index + 1}`}>
<h5 className={style.listLable}>{item.label}</h5>
<h5 className={style.listContent}>{item.extra}</h5>
</div>
))}
</Col>
<Col span={8}>
{basicInfo.col2.map((item: any, index: number) => (
<div className={style.list} key={`col2_${index + 1}`}>
<h5 className={style.listLable}>{item.label}</h5>
<h5 className={style.listContent}>{item.extra}</h5>
</div>
))}
</Col>
<Col span={8}>
{basicInfo.col3.map((item: any, index: number) => (
<div className={style.list} key={`col3_${index + 1}`}>
<h5 className={style.listLable}>{item.label}</h5>
<h5 className={style.listContent}>{item.extra}</h5>
</div>
))}
</Col>
</Row>
</Card>
{/* 交易条件 */}
<Card
id='conditions'
title='交易条件'
>
<Row gutter={[8, 8]}>
<Col span={8}>
{dealCondition.col1.map((item: any, index: number) => (
<div className={style.list} key={`col1_${index + 1}`}>
<h5 className={style.listLable}>{item.label}</h5>
<h5 className={style.listContent}>{item.extra}</h5>
</div>
))}
</Col>
<Col span={8}>
{dealCondition.col2.map((item: any, index: number) => (
<div className={style.list} key={`col2_${index + 1}`}>
<h5 className={style.listLable}>{item.label}</h5>
<h5 className={style.listContent}>{item.extra}</h5>
</div>
))}
</Col>
<Col span={8}>
{dealCondition.col3.map((item: any, index: number) => (
<div className={style.list} key={`col3_${index + 1}`}>
<h5 className={style.listLable}>{item.label}</h5>
<h5 className={style.listContent}>{item.extra}</h5>
</div>
))}
</Col>
</Row>
</Card>
{/* 报价信息 */}
<Card
id='docking'
title='报价信息'
extra={
<Space>
<Button>发起下轮报价</Button>
{data.priceContrast === PRICECONTRAST_TYPE.UNDECRYPTED && <Button>解密报价单</Button>}
<Button disabled={disivble} onClick={() => handlePriceContrast()} type='primary'>立即比价</Button>
</Space>
}
>
<Tabs>
<TabPane key='1' tab='第三轮'>
<div className={style.affixTitle}>
<Divider type="vertical" className={style.dividerStyle} />
供应商信息
</div>
<StandardTable
tableProps={{ rowKew: 'id' }}
columns={StandardTableColumns}
fetchTableData={(params: any) => handleGetMaterielDetailed(params)}
/>
<Skeleton
active
loading={loading}
/>
{dataSource.length > 0
&& (
<>
<div className={style.affixTitle}>
<Divider type="vertical" className={style.dividerStyle} />
比价信息
</div>
<BidTable />
</>
)}
</TabPane>
</Tabs>
</Card>
{/* 流转记录 */}
<Card
id='record'
title='流转记录'
extra={
<Radio.Group
onChange={(e) => setLogStatus(e.target.value)}
defaultValue={LogType.externalLogs}>
{data.externalLogs && <Radio.Button value={LogType.externalLogs}>外部流转</Radio.Button>}
{data.interiorLogs && <Radio.Button value={LogType.interiorLogs}>内部流转</Radio.Button>}
</Radio.Group>
}
>
<Table
columns={logStatus === LogType.externalLogs ? EXTERNALLOGS : INTERNALLOGS}
dataSource={
logStatus === LogType.externalLogs ?
data.externalLogs :
data.interiorLogs
}
rowKey={(record) => record.id}
pagination={{
hideOnSinglePage: true
}}
/>
</Card>
</div>
<BidModal
id={id}
turn={turn}
visible={visible}
onConfirm={handleConfirm}
onCancel={() => setVisible(false)}
/>
</div>
</BidDetailContext.Provider>
)
}
export default Detail;
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