Commit aafd9e85 authored by 前端-钟卫鹏's avatar 前端-钟卫鹏

fix:更改锚点定位的方式

parent d6dc0508
......@@ -52,12 +52,13 @@ const memberCenterRoute = {
path:'/memberCenter/procurementAbility/callForBids',
name:'招标',
routes:[
// 招标查询
{
path: '/memberCenter/procurementAbility/callForBids/callForBidsSearch',
name: '招标查询',
component: '@/pages/procurement/callForBids/callForBidsSearch'
},
// 招标-详情
// 招标查询-详情
{
path: '/memberCenter/procurementAbility/callForBids/callForBidsSearch/preview',
name: '招标详情',
......@@ -65,6 +66,20 @@ const memberCenterRoute = {
hideInMenu: true,
noMargin: true,
},
// 投标查询
{
path: '/memberCenter/procurementAbility/callForBids/tenderSearch',
name: '投标查询',
component: '@/pages/procurement/callForBids/tenderSearch',
},
// 投标查询-详情
{
path: '/memberCenter/procurementAbility/callForBids/tenderSearch/preview',
name: '投标详情',
component: '@/pages/procurement/callForBids/tenderSearch/detail',
hideInMenu: true,
noMargin: true,
},
]
},
],
......
import { createContext } from 'react';
// 招标详情 Context
export const BidDetailContext = createContext<any>({})
......@@ -20,6 +20,9 @@ export const useBidDetail = (options: OrderDetailHookProps) => {
// 当前的支付信息id 默认第一个
const [currentPayInfoId, setCurrentPayInfoId] = useState<any>(null)
// 内容元素距顶部距离数组
const [offsetTopList, setOffsetTopList] = useState<number[]>([])
// 支付信息列表
const [payList, setPaylist] = useState<any[]>([])
const { id } = usePageStatus()
......@@ -71,10 +74,12 @@ export const useBidDetail = (options: OrderDetailHookProps) => {
const formContext = {
data: formData,
currentPayInfoId,
offsetTopList,
payList,
ctl: {
setData: setFormData,
setPayId: setCurrentPayInfoId,
setOffsetTopList,
},
reloadFormData
}
......
......@@ -15,7 +15,8 @@ const CallForBidsSearchDetail: React.FC = () => {
const {data, currentPayInfoId} = formContext
const payRef = useRef<any>({})
/** 约定好 对应的锚点title和元素id映射 */
/** destroy */
const anchorTitleMapId = [
{ title: '流转进度', id: 'transferProcess' },
{ title: '基本信息', id: 'baseicInfo' },
......@@ -29,13 +30,26 @@ const CallForBidsSearchDetail: React.FC = () => {
{ title: '流转记录', id: 'transferRecord' },
]
const anchorTitleList = [
'流转进度',
'基本信息',
'招标物料',
'招标要求',
'报名要求',
'资格预审要求',
'评标要求',
'其他要求',
'招标方式',
'流转记录',
]
return (
<div>
<BidDetailContext.Provider value={formContext}>
<BidDetailHeader
detailList={detailList}
detailData={formContext.data}
anchorList={anchorTitleMapId}
formContext={formContext}
anchorList={anchorTitleList}
backLink="/memberCenter/procurementAbility/callForBids/callForBidsSearch"
extraRight={
<>
......@@ -51,7 +65,7 @@ const CallForBidsSearchDetail: React.FC = () => {
/>
<OrderDetailWrapper>
<PreLoading loading={!formContext.data} active paragraph={{rows: 6}}>
<BidDetailSection formContext={formContext} anchorList={anchorTitleMapId} />
<BidDetailSection formContext={formContext} anchorList={anchorTitleList} type="callForBid" />
</PreLoading>
</OrderDetailWrapper>
......
.anchorGap {
div {
&:target {
padding-top: 190px;
margin-top: -190px;
}
}
}
import React, { useState, useCallback, useRef, useContext, useEffect, createRef } from 'react';
import { history } from 'umi'
import { Button } from 'antd';
import style from './index.less'
import OrderDetailWrapper from '@/pages/transaction/components/OrderDetailWrapper';
import PreLoading from '@/components/PreLoading';
import OrderPayModal from '@/pages/transaction/components/orderPayModal';
import { BidDetailContext } from '@/pages/procurement/_public/bid/context';
import { useBidDetail } from '@/pages/procurement/_public/bid/effects/useBidDetail';
import BidDetailHeader from '@/pages/procurement/components/bidDetailHeader';
import BidDetailSection from '@/pages/procurement/components/bidDetailSection';
const TenderSearchDetail: React.FC = () => {
const { formContext, id, detailList } = useBidDetail({type: 'purchaseOrder'})
const {data, currentPayInfoId} = formContext
const payRef = useRef<any>({})
const contentRef = useRef<any>({})
/** 约定好 对应的锚点title和元素id映射 */
const anchorTitleMapId = [
{ title: '流转进度', id: 'transferProcess' },
{ title: '基本信息', id: 'baseicInfo' },
{ title: '招标物料', id: 'bidMaterial' },
{ title: '招标要求', id: 'bidNeed' },
{ title: '报名要求', id: 'registerNeed' },
{ title: '资格预审要求', id: 'checkNeed' },
{ title: '评标要求', id: 'remarkNeed' },
{ title: '其他要求', id: 'otherNeed' },
{ title: '招标方式', id: 'bidWay' },
{ title: '流转记录', id: 'transferRecord' },
]
return (
<div>
<BidDetailContext.Provider value={formContext}>
<BidDetailHeader
detailList={detailList}
detailData={formContext.data}
anchorList={anchorTitleMapId}
backLink="/memberCenter/procurementAbility/callForBids/tenderSearch"
extraRight={
<>
<Button type='primary'>
去支付
</Button>
<div style={{ textAlign: 'right' }}>
<p style={{ marginTop: 12, fontSize: 12, color: '#6B778C' }}>本次需支付</p>
{ formContext.data && <p>¥666</p> }
</div>
</>
}
/>
<OrderDetailWrapper>
<PreLoading loading={!formContext.data} active paragraph={{rows: 6}}>
<BidDetailSection formContext={formContext} anchorList={anchorTitleMapId} type="tender" />
</PreLoading>
</OrderDetailWrapper>
<OrderPayModal
currentRef={payRef}
/>
</BidDetailContext.Provider>
</div>
);
};
export default TenderSearchDetail;
import React, { useRef } from 'react'
import { Button, Popconfirm, Card, Space} from 'antd'
import { PageHeaderWrapper } from '@ant-design/pro-layout'
import { StandardTable } from 'god'
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch'
import { FORM_FILTER_PATH } from '@/formSchema/const'
import { useSelfTable } from './model/useSelfTable'
import { tableListSchema } from './schema'
import Submit from '@/components/NiceForm/components/Submit'
import DateRangePickerUnix from '@/components/NiceForm/components/DateRangePickerUnix'
import { PublicApi } from '@/services/api'
const TenderSearch: React.FC<{}> = () => {
const {
ref,
columns
} = useSelfTable()
const fetchTableData = async (params) => {
const { data } = await PublicApi.getOrderPendingOrderList(params)
return data
}
return (
<PageHeaderWrapper>
<Card>
<StandardTable
fetchTableData={params => fetchTableData(params)}
currentRef={ref}
columns={columns}
rowKey={'orderNo'}
formilyLayouts={{
justify: 'space-between'
}}
formilyProps={{
ctx: {
inline: false,
schema: tableListSchema,
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
'orderNo',
FORM_FILTER_PATH,
);
},
components: {
DateRangePickerUnix,
Submit
}
}
}}
/>
</Card>
</PageHeaderWrapper>
)
}
export default TenderSearch
import React, { useRef } from 'react'
import { history, Link } from 'umi'
import { Button, Row, Col, Progress, Popconfirm } from 'antd'
import { PublicApi } from '@/services/api'
import EyePreview from '@/components/EyePreview'
import { formatTimeString } from '@/utils'
import { ORDER_TYPE, PurchaseOrderInsideWorkState, PurchaseOrderOutWorkState } from '@/constants'
import { PlayCircleOutlined, PoweroffOutlined } from '@ant-design/icons'
import CustomTag from '@/pages/procurement/components/CustomTag'
import CustomBadge from '@/pages/procurement/components/customBadge'
// 投标查询
export const useSelfTable = () => {
const ref = useRef<any>({})
const handleCancel = (param) => {
PublicApi.postOrderPurchaseOrderCancel({id: param}).then(res => {
if(res.code === 1000) {
ref.current.reload()
}
})
}
const callForBidColumns: any[] = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
render: (text, record, index) => index + 1
},
{
title: '招标编号/项目',
align: 'center',
dataIndex: 'orderNo',
key: 'orderNo',
render: (text, record) => <>
<EyePreview url={`/memberCenter/procurementAbility/callForBids/callForBidsSearch/preview?id=${record.id}`}>
{text}
</EyePreview>
<div>{text}</div>
</>
},
{
title: '投标编号/会员',
align: 'center',
dataIndex: 'orderNo',
key: 'orderNo',
render: (text, record) => <>
<EyePreview url={`/memberCenter/procurementAbility/callForBids/callForBidsSearch/preview?id=${record.id}`}>
{text}
</EyePreview>
<div>{text}</div>
</>
},
{
title: '投标时间',
align: 'center',
dataIndex: 'createTime',
key: 'createTime',
render: (text, record) => formatTimeString(record.createTime),
width: 200
},
{
title: '开标时间',
align: 'center',
dataIndex: 'createTime',
key: 'createTime',
render: (text, record) => formatTimeString(record.createTime),
width: 200
},
{
title: '是否中标',
align: 'center',
dataIndex: 'externalState',
key: 'externalState',
},
{
title: '外部状态',
align: 'center',
dataIndex: 'externalState',
key: 'externalState',
render: text => <CustomTag status={text} type='out' />
},
{
title: '内部状态',
align: 'center',
dataIndex: 'interiorState',
key: 'interiorState',
render: (text) => <CustomBadge status={text} type='inside' />
},
// {
// title: '操作',
// align: 'center',
// dataIndex: 'ctl',
// key: 'ctl',
// render: (text, record) => <>
// <Button type='link'>复制</Button>
// <Popconfirm
// title="是否要取消该订单?"
// onConfirm={() => handleCancel(record.id)}
// okText="是"
// cancelText="否"
// >
// <Button type='link'>废标</Button>
// </Popconfirm>
// </>
// }
]
return {
ref,
columns: callForBidColumns
}
}
import { ISchema } from '@formily/antd';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { OrderTypeMap, PurchaseOrderInsideWorkStateTexts, PurchaseOrderOutWorkStateTexts } from '@/constants';
/**
* 招标查询列表高级筛选
*/
export const tableListSchema: ISchema = {
type: 'object',
properties: {
orderNo: {
type: 'string',
"x-component": 'SearchFilter',
'x-component-props': {
placeholder: '请输入招标编号',
align: 'flex-start',
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'flex-layout',
'x-component-props': {
inline: true,
rowStyle: {
justifyContent: 'start',
},
colStyle: {
marginRight: 20
}
},
properties: {
orderThe: {
type: 'string',
'x-component-props': {
placeholder: '请输入投标项目',
}
},
tenderCode: {
type: 'string',
'x-component-props': {
placeholder: '请输入招标编码',
}
},
"[startEnterTime,endEnterTime]": {
type: 'array',
"x-component": 'DateRangePickerUnix',
'x-component-props': {
placeholder: ['开标开始时间','开标结束时间'],
},
},
tenderMember: {
type: 'string',
'x-component-props': {
placeholder: '请输入投标会员',
}
},
"externalState": {
type: 'string',
"x-component-props": {
placeholder: '请选择外部状态'
},
enum: Object.keys(PurchaseOrderOutWorkStateTexts).map(item => ({
label: PurchaseOrderOutWorkStateTexts[item],
value: item,
}))
},
// "interiorState": {
// type: 'string',
// "x-component-props": {
// placeholder: '请选择内部状态'
// },
// enum: Object.keys(PurchaseOrderInsideWorkStateTexts).map(item => ({
// label: PurchaseOrderInsideWorkStateTexts[item],
// value: item,
// }))
// },
submit: {
'x-component': 'Submit',
'x-component-props': {
children: '查询',
},
},
},
},
}
}
import React, { ReactNode, useEffect, useRef, useState } from 'react'
import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'react'
import { Row, Col, Skeleton } from 'antd'
import { history } from 'umi'
import { ArrowLeftOutlined, BugTwoTone } from '@ant-design/icons'
......@@ -7,27 +7,35 @@ import style from './index.less'
export interface BidDetailHeaderProps {
extraRight?: ReactNode,
detailList?: { label: string, name: string, render?(text, record?), [key: string]: any }[],
detailData?: any,
formContext?: any,
anchorList?: any,
backLink?: string,
contentRef?: any,
}
/**
* 招标详情头部
*/
const BidDetailHeader:React.FC<BidDetailHeaderProps> = ({ extraRight, detailList = [], detailData, anchorList = [], backLink}) => {
const isLoading = !!detailData
const BidDetailHeader:React.FC<BidDetailHeaderProps> = ({
extraRight,
detailList = [],
formContext,
anchorList = [],
backLink,
}) => {
const isLoading = !!formContext.data
const flagRef = useRef({
flag: false,
distanceTop: 0
})
const [current, setCurrent] = useState<number>(0)
// const itemList = ['#components1', '#components2', '#components3', '#components31A', '#components32A', '#components4']
const [isFixed, setIsFixed] = useState<boolean>(false)
useEffect(() => {
window.addEventListener("scroll", onScroll);
// window.addEventListener("scroll", debounce(onScroll, 500));
window.addEventListener("scroll", onScroll)
return (()=>{
window.removeEventListener('scroll', onScroll)
})
......@@ -41,31 +49,51 @@ const BidDetailHeader:React.FC<BidDetailHeaderProps> = ({ extraRight, detailList
setCurrent(index)
}
})
// 锚点导航距离顶端距离
let navDom: any = document.getElementById("anchorTitle")
if(navDom) {
let distance = navDom.offsetTop - document.documentElement.scrollTop
if(!flagRef.current.flag) {
flagRef.current.distanceTop = navDom.offsetTop
flagRef.current.flag = true
}
// // @todo 不使用防抖情况下 焦点会出现抖动;使用防抖,固定头部会延迟或者无效
// // 锚点导航距离顶端距离
// let navDom: any = document.getElementById("anchorTitle")
// if(navDom) {
// let distance = navDom.offsetTop - document.documentElement.scrollTop
// if(!flagRef.current.flag) {
// flagRef.current.distanceTop = navDom.offsetTop
// flagRef.current.flag = true
// }
if(distance <= 0) {
setIsFixed(true)
}
if(document.documentElement.scrollTop <= flagRef.current.distanceTop) {
setIsFixed(false)
}
}
// if(distance <= 0) {
// setIsFixed(true)
// }
// if(document.documentElement.scrollTop <= flagRef.current.distanceTop) {
// setIsFixed(false)
// }
// }
}
const clickItem = (index: any) => {
setCurrent(index)
console.log(formContext.offsetTopList, 'context', formContext.offsetTopList[index])
let distance = formContext.offsetTopList[index] - 140
window.scrollTo({
top: distance < 0 ? 0 : distance,
behavior: "smooth"
});
if(index > 0) setIsFixed(true)
else setIsFixed(false)
}
// // 简单的防抖动函数
// const debounce = (func, wait, immediate?) => {
// // setIsFixed(true)
// // 定时器变量
// let timeout;
// return () => {
// // 每次触发 scroll handler 时先清除定时器
// clearTimeout(timeout);
// // 指定 xx ms 后触发真正想进行的操作 handler
// timeout = setTimeout(func, wait);
// };
// }
return (
<div className={isFixed ? [style.detailHeader, style.anchorTitleFixed].join(' '): style.detailHeader} id="detailHeader">
{
......@@ -78,18 +106,17 @@ const BidDetailHeader:React.FC<BidDetailHeaderProps> = ({ extraRight, detailList
<ArrowLeftOutlined onClick={() => backLink ? history.push(backLink) : history.goBack()}/>
</Col>
<Col>
<div className={style.titleAvatorText}>订单号: {detailData.orderNo}</div>
<div className={style.titleAvatorText}>订单号: {formContext.data.orderNo}</div>
</Col>
</Row>
<Row>
<Col>
{/* <div className={isFixed ? [style.anchorTitle, style.anchorTitleFixed].join(' '): style.anchorTitle} id="anchorTitle"> */}
<div className={style.anchorTitle} id="anchorTitle">
<ul className={style.anchorUl}>
{
anchorList.map((item, index) => (
<li key={index} onClick={()=>clickItem(index)}>
<a href={`#${item.id}`} className={current === index ? style.current : null}>{item.title}</a>
<a className={current === index ? style.current : null}>{item}</a>
</li>
))
}
......
import React from 'react'
import React, { useEffect } from 'react'
import { findLastIndexFlowState } from '@/utils'
import style from './index.less'
import TransferProcess from '../transferProcess'
......@@ -9,17 +9,34 @@ import BidTransformRecord from '../transferRecord'
export interface BidDetailSectionProps {
formContext: any,
type?: 'purchaseOrder' | 'saleOrder',
/** callForBid 招标 | tender 投标 */
type?: 'callForBid' | 'tender',
anchorList?: any,
}
const BidDetailSection:React.FC<BidDetailSectionProps> = ({formContext, type = 'purchaseOrder', anchorList = []}) => {
const BidDetailSection:React.FC<BidDetailSectionProps> = ({
formContext,
type = 'callForBid',
anchorList = [],
}) => {
useEffect(() => {
// 获取各个子div距父级的高度
let floors = document.querySelectorAll(".anchorContent>div")
let tempArr = []
floors.forEach((floor: any, index: any) => {
tempArr.push(floor.offsetTop)
})
// 各内容div存入context
formContext.ctl.setOffsetTopList(tempArr)
}, [])
return (
formContext.data &&
<div className={[style.anchorContentWrap, "anchorContent"].join(' ')}>
<div id={anchorList[0]['id']}>
<div>
<TransferProcess
cardTitle={anchorList[0]['title']}
cardTitle={anchorList[0]}
customTitleKey='operationalProcess'
customKey='state'
outerVerifyCurrent={findLastIndexFlowState(formContext.data.externalWorkflowFlowRecordLogResponses)}
......@@ -42,32 +59,32 @@ const BidDetailSection:React.FC<BidDetailSectionProps> = ({formContext, type = '
}
></TransferProcess>
</div>
<div id={anchorList[1]['id']}>
<DescriptionsInfo cardTitle={anchorList[1]['title']} type="basicInfo" />
<div>
<DescriptionsInfo cardTitle={anchorList[1]} type="basicInfo" />
</div>
<div id={anchorList[2]['id']}>
<BidMaterial cardTitle={anchorList[2]['title']} />
<div>
<BidMaterial cardTitle={anchorList[2]} />
</div>
<div id={anchorList[3]['id']}>
<DescriptionsInfo cardTitle={anchorList[3]['title']} type="bidNeed" />
<div>
<DescriptionsInfo cardTitle={anchorList[3]} type="bidNeed" />
</div>
<div id={anchorList[4]['id']}>
<DescriptionsInfo cardTitle={anchorList[4]['title']} type="registerNeed" />
<div>
<DescriptionsInfo cardTitle={anchorList[4]} type="registerNeed" />
</div>
<div id={anchorList[5]['id']}>
<DescriptionsInfo cardTitle={anchorList[5]['title']} type="checkNeed" />
<div>
<DescriptionsInfo cardTitle={anchorList[5]} type="checkNeed" />
</div>
<div id={anchorList[6]['id']}>
<DescriptionsInfo cardTitle={anchorList[6]['title']} type="remarkNeed" />
<div>
<DescriptionsInfo cardTitle={anchorList[6]} type="remarkNeed" />
</div>
<div id={anchorList[7]['id']}>
<DescriptionsInfo cardTitle={anchorList[7]['title']} type="otherNeed" />
<div>
<DescriptionsInfo cardTitle={anchorList[7]} type="otherNeed" />
</div>
<div id={anchorList[8]['id']}>
<BidMethod cardTitle={anchorList[8]['title']} />
<div>
<BidMethod cardTitle={anchorList[8]} />
</div>
<div id={anchorList[9]['id']}>
<BidTransformRecord cardTitle={anchorList[9]['title']} />
<div>
<BidTransformRecord cardTitle={anchorList[9]} />
</div>
</div>
......
.card-list {
font-size: 12px;
line-height: 20px;
margin-top: 6px;
margin-top: 12px;
}
.card-list_title {
font-size: 12px;
color: #909399;
}
// 抽屉内部内容样式
.drawerContainer {
.drawerNav {
position: fixed;
width: 160px;
height: 100%;
&:after {
content: "";
content: "";
height: 100%;
width: 1px;
background-color: #F4F5F7;
position: absolute;
top: 0;
right: 0;
}
ul {
padding-left: 0;
margin: 0;
width: 160px;
list-style: none;
li {
width: 160px;
height: 48px;
line-height: 48px;
background: #FFFFFF;
a {
height: 24px;
font-size: 12px;
font-weight: 500;
color: #606266;
line-height: 24px;
padding-left: 16px;
padding-top: 6px;
padding-bottom: 6px;
}
.current {
color: #303133;
border-left: 2px solid #00B37A;
}
}
}
}
.drawerContent {
.drawerContentItem {
.drawerContentTitle {
p {
margin: 16px 0 16px 0;
font-size: 14px;
font-weight: 500;
color: #909399;
&:before {
content: "";
border: 2px solid #00B37A;
margin-right: 6px;
}
}
}
}
}
}
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