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

feat: 添加待审核招标和招标查询页面

parent 419e7b55
......@@ -11,6 +11,7 @@
// import trademarkRoute from './brandRoute' // 品牌路由
// import commodity from './commodityRoute' // 商品审核路由
import demandRoute from './demandRoute' //需求单审核
import procurementRoute from './procurementRoute' //招标审核
// import demandQuoteOrderRoute from './demandQuoteOrderRoute' //需求报价单管理
// import logisticsRoutes from './logisticsRoutes'
// import memberAbility from './memberAbility'
......@@ -47,6 +48,7 @@ const routeList = [
// contentRoute,
// balancedRoute,
demandRoute,
procurementRoute,
// demandQuoteOrderRoute,
// capitalAccount,
// messageRoute,
......
/*
* @Author: zwp
* @Date: 2021-03-25 16:20:40
* @LastEditors: zwp
* @LastEditTime: 2021-03-25 16:20:40
* @RouterName: 采购招投标路由
*/
const router = {
path: '/procurement',
name: '招标审核',
routes: [
{
// 待审核招标
path: '/procurement/readyCheckBid',
name: '待审核招标',
hidePageHeader: true,
component: '@/pages/procurement/readyCheckBid',
},
{
// 待审核招标 详情
path: '/procurement/readyCheckBid/detail',
name: '待审核招标详情',
component: '@/pages/procurement/readyCheckBid/detail',
hidePageHeader: true,
hideInMenu: true,
noMargin: true,
},
{
// 招标查询
path: '/procurement/callForBidsSearch',
name: '招标查询',
hidePageHeader: true,
component: '@/pages/procurement/callForBidsSearch',
},
{
// 招标 详情
path: '/procurement/callForBidsSearch/detail',
name: '招标详情',
component: '@/pages/procurement/callForBidsSearch/detail',
hidePageHeader: true,
hideInMenu: true,
noMargin: true,
},
]
}
export default router
.card-list {
font-size: 12px;
line-height: 20px;
margin-top: 12px;
}
.card-list_title {
font-size: 12px;
color: #909399;
}
.paneTitle {
margin: 16px 0 16px 0;
font-size: 14px;
font-weight: 500;
color: #909399;
height: 14px;
line-height: 14px;
.longString {
color: #00B37A;
margin-right: 6px;
height: 14px;
line-height: 14px;
font-size: 14px;
font-weight: bolder;
}
}
// 抽屉内部内容样式
.drawerContainer {
.drawerNav {
position: fixed;
width: 160px;
height: 100%;
&:after {
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;
height: 14px;
line-height: 14px;
.longString {
color: #00B37A;
margin-right: 6px;
height: 14px;
line-height: 14px;
font-size: 14px;
font-weight: bolder;
}
}
}
}
}
}
import React, { ReactNode, useCallback, useContext, useEffect, useRef, useState } from 'react'
import { Modal, Drawer, Button, Tabs, Row, Col, Anchor } from 'antd'
import style from './index.less'
import NiceForm from '../NiceForm'
import { IAntdSchemaFormProps, registerVirtualBox } from '@formily/antd'
/**
* 带锚点定位跳转的抽屉 Drawer
*/
const { Link } = Anchor
export interface AnchorProps extends IAntdSchemaFormProps {
/** 数据源 用于渲染对应的字段值 */
data?: any,
/** 数据项和render渲染函数 仅预览功能下使用 */
dataRenderList?: { title: string, name: string, render?(data?: any), [key: string]: any }[],
/** NiceForm表单模式下 锚点定位title和idName列表 此项生效必须isForm属性为true */
dataIdList?: {title: string, idName: string}[],
title?: string,
visible?: boolean,
/** 自定义底部布局 */
footer?: ReactNode,
/** 点击遮罩回调 */
onClose?: any,
/** 是否使用NiceForm表单 */
isForm?: boolean,
/** Drawer其他配置 */
restDrawer?: any,
}
const AnchorDrawer: React.FC<AnchorProps> = ({
data,
dataRenderList = [],
dataIdList = [],
title = "",
visible = false,
footer,
onClose,
isForm = false,
actions,
restDrawer,
...restProps
}) => {
const [current, setCurrent] = useState<number>(0)
const [offsetTopList, setOffsetTopList] = useState<number[]>([])
// useEffect(() => {
// if (currentRef) {
// currentRef.current = {
// formActions,
// }
// }
// }, [])
useEffect(() => {
let tempArr: any = []
let floors: any = []
if(visible) {
// 获取各个子div距父级的高度
floors = isForm ? document.querySelectorAll(".drawerContent>div>div>form.ant-form>div") : document.querySelectorAll(".drawerContent>div")
floors.forEach((floor: any, index: any) => {
tempArr.push(floor.offsetTop)
})
setOffsetTopList(tempArr)
}
/**
* 开启滚动事件冒泡 (传参说明)
* e: 事件对象
* tempArr: 各目标元素距父级顶部距离数组
* floors: 各锚点目标HTML元素
*/
window.addEventListener("scroll", (e?: any) => onScroll(e, tempArr, floors), true);
// @ts-ignore
return () => window.removeEventListener('scroll', onScroll)
}, [visible])
const onScroll = (e?: { target: { className: string } }, arr?: any, floors?: any) => {
if(visible)
if(e.target.className === 'ant-drawer-body') {
let scrollTop = document.querySelectorAll(".ant-drawer-body")[0].scrollTop
floors.forEach((floor: any, index: any) => {
if(arr[index] - 40 <= scrollTop) {
setCurrent(index)
}
})
}
}
const handleClick = (i: number) => {
let dom = document.querySelectorAll(".ant-drawer-body")[0]
dom.scroll({
'top': offsetTopList[i] - 16,
behavior: "smooth",
})
if(offsetTopList[i] + dom.clientHeight >= dom.scrollHeight) {
setCurrent(i)
}
}
registerVirtualBox("CustomTitle", ({ children, schema }) => {
return (
<div>
<p className={style.paneTitle}>
<span className={style.longString}>|</span>
{schema["x-component-props"]["text"]}
</p>
{children}
</div>
);
});
return (<div id="content">
<Drawer
title={title}
width={800}
bodyStyle={{ paddingLeft: 0, paddingTop: 0 }}
onClose={onClose}
visible={visible}
footer={footer}
{...restDrawer}
>
<div className={style.drawerContainer}>
<Row>
<Col span={6}>
<div className={style.drawerNav}>
<ul>
{
isForm
?
dataIdList.map((item, index) => (
<li key={index} onClick={() => handleClick(index)}><a className={current === index ? style.current : null}>{item['title']}</a></li>
)) :
dataRenderList.map((item, index) => (
<li key={index} onClick={() => handleClick(index)}><a className={current === index ? style.current : null}>{item['title']}</a></li>
))
}
</ul>
</div>
</Col>
<Col span={18}>
<div className={[style.drawerContent, 'drawerContent'].join(' ')}>
{
isForm ? (<NiceForm
actions={actions}
{...restProps}
// onSubmit={values => ref.current.reload(values)}
/>) : (dataRenderList.map((item, index) => (
<div className={style.drawerContentItem} id={item['id']} key={index}>
<div className={style.drawerContentTitle}>
<p><span className={style.longString}>|</span>{item['title']}</p>
</div>
<div className={style.drawerContentInfo}>
{item.render ? item.render(data) : <span>{data[item.name]}</span>}
</div>
</div>
)))
}
</div>
</Col>
</Row>
</div>
</Drawer>
</div>)
}
AnchorDrawer.defaultProps = {}
export default AnchorDrawer
.preWrapper {
padding: 24px;
background: #fff;
}
\ No newline at end of file
import React from 'react'
import styles from './index.less'
import { SkeletonProps } from 'antd/es/skeleton'
import { Skeleton } from 'antd'
export interface PreLoadingProps extends SkeletonProps {}
const PreLoading:React.FC<PreLoadingProps> = (props) => {
const { children, loading, ...restProps } = props
return loading ? (
<div className={styles.preWrapper}>
<Skeleton {...restProps}></Skeleton>
</div>
) : <>{children}</>
}
PreLoading.defaultProps = {}
export default PreLoading
\ No newline at end of file
......@@ -1329,3 +1329,176 @@ export const PAY_CHANNEL = {
[PAY_CHANNEL_CREDIT]: '授信',
[PAY_CHANNEL_COD]: '货到付款',
};
/**** ****/
/** 招标 ** 投标 ** 常量 */
/**** ****/
/** 采购类型 */
export const PURCHASE_TYPE = {
1: '单次采购',
2: '协议采购',
}
/** 招标方式 */
export const PUBLIC_BID = 1;
export const SYSTEM_BID = 2;
export const INVITE_BID = 3;
export const CALLFORBID_TYPE_ENUM = {
[PUBLIC_BID]: '公开招标',
[SYSTEM_BID]: '系统匹配',
[INVITE_BID]: '邀请招标',
}
export const CALLFORBID_TYPE = [
'',
'公开招标',
'系统匹配',
'邀请招标',
]
// 招标 内部状态工作流状态
export enum BidInsideWorkState {
/** 待提交审核招标 */
Not_Submitted_Check_Invite_Tender = 1,
/** 待审核招标 */
Not_Tender_Check = 2,
/** 招标审核通过 */
Tender_Check_Pass = 3,
/** 招标审核不通过 */
Tender_Check_Not_Pass = 4,
/** 已提交招标 */
Submitted_Invite_Tender = 5,
/** 报名审核通过 */
Register_Check_Pass = 6,
/** 报名审核不通过 */
Register_Check_Not_Pass = 7,
/** 资格预审审核通过 */
Qualifications_Check_Pass = 8,
/** 资格预审审核不通过 */
Qualifications_Check_Not_Pass = 9,
/** 提交评标报告 */
Submitted_Selection_Tender = 10,
/** 待提交审核定标 */
Not_Submitted_Check_Finish_Tender = 11,
/** 定标审核通过 */
Finish_Tender_Check_Pass = 12,
/** 定标审核不通过 */
Finish_Tender_Check_Not_Pass = 13,
/** 待中标公示 */
Not_Win_Notice = 14,
/** 待完成招标 */
Not_Finish_Invite_Tender = 15,
/** 完成招标 */
Finish_Invite_Tender = 16,
/** 已废标 */
Discard_Tender = 17,
}
/** 招标 内部状态 */
export const BidInStateTexts = {
1: "待提交审核招标",
2: "待审核招标",
3: '招标审核通过',
4: '招标审核不通过',
5: '已提交招标',
6: '报名审核通过',
7: '报名审核不通过',
8: '资格预审审核通过',
9: '资格预审审核不通过',
10: '提交评标报告',
11: '待提交审核定标',
12: '定标审核通过',
13: '定标审核不通过',
14: '待中标公示',
15: '待完成招标',
16: '完成招标',
17: '已废标',
}
// 招标 外部状态工作流状态
export enum BidOuterWorkState {
/** 提交招标 */
Submitted_Invite_Tender = 1,
/** 待平台审核招标 */
Not_Check_Invite_Tender = 2,
/** 待招标报名 */
Not_Invite_Tender_Register = 3,
/** 待审核报名 */
Not_Check_Register_Check = 4,
/** 待提交资格预审 */
Not_Submitted_Qualifications_Check = 5,
/** 待资格预审 */
Not_Qualifications_Check = 6,
/** 待投标 */
Not_Invite_Tender = 7,
/** 待开标 */
Not_Open_Tender = 8,
/** 待评标 */
Not_Selection_Tender = 9,
/** 待定标 */
Not_Finish_Tender = 10,
/** 待中标公示 */
Not_Win_Notice = 11,
/** 待完成招标 */
Not_Finish_Invite_Tender = 12,
/** 完成招标 */
Finish_Invite_Tender = 13,
/** 已废标 */
Discard_Tender = 14,
}
/** 招标 外部状态 */
export const BidOutStateTexts = {
1: "提交招标",
2: '待平台审核招标',
3: '待招标报名',
4: '待审核报名',
5: '待提交资格预审',
6: '待资格预审',
7: '待投标',
8: '待开标',
9: '待评标',
10: '待定标',
11: '待中标公示',
12: '待完成招标',
13: '完成招标',
14: '已废标',
}
/** 招标 内部操作文本 */
export const BidInOpeartTexts = {
1: "新增招标",
2: "审核招标",
3: "提交招标",
4: "审核报名",
5: "审核资格",
6: "完成评标",
7: "选择中标会员",
8: "审核定标",
9: "确认招标",
10: "发送中标公示",
11: "完成招标",
12: "已废标",
}
/** 招标 外部操作文本 */
export const BidOutOpeartTexts = {
1: "新增招标",
2: "平台审核招标",
3: "招标报名",
4: "审核报名",
5: "提交资格预审",
6: "资格预审",
7: "提交投标",
8: "开标",
9: "评标",
10: "定标",
11: "发送中标公示",
12: "完成招标",
13: "已废标",
}
......@@ -24,7 +24,7 @@ export const usePageStatus = () => {
return {
pageStatus,
id,
preview,
preview,
...rest,
}
}
\ No newline at end of file
}
import { createContext } from 'react';
// 招标详情 Context
export const BidDetailContext = createContext<any>({})
// 待新增招标 详情
export const ReadyAddBidDetailContext = createContext<any>({})
import React, { useRef } from 'react'
import { useCallback, useState, useEffect } from 'react'
import { usePageStatus } from '@/hooks/usePageStatus'
import { PublicApi } from '@/services/api'
import { Link } from 'umi'
import { GlobalConfig } from '@/global/config'
import { formatTimeString } from '@/utils'
import { message } from 'antd'
import { history } from 'umi'
interface OrderDetailHookProps {
/** 招标,投标 */
type: 'callForBid' | 'tender'
}
// 招标详情, 支持(招标、投标)两种模式
export const useBidDetail = (options: OrderDetailHookProps) => {
// 详情数据
const [formData, setFormData] = useState<any>(null)
// 流转记录数据(内/外)
const [interiorProcurementOrderLogResponses, setInteriorProcurementOrderLogResponses] = useState<any>(null)
const [externalProcurementOrderLogResponses, setExternalProcurementOrderLogResponses] = useState<any>(null)
// 地址
const [address, setAddress] = useState<string>(null)
// 内容元素距顶部距离数组
const [offsetTopList, setOffsetTopList] = useState<number[]>([])
const { id } = usePageStatus()
const { type } = options
useEffect(() => {
reloadFormData()
}, [])
const reloadFormData = useCallback(() => {
if (id) {
// 详情
// @todo 需补充投标详情api
const fn = type === 'callForBid' ? PublicApi.getPurchaseInviteTenderGetInviteTender : PublicApi.getPurchaseSubmitTenderGetInviteTender
fn({ id }, { ctlType: "none" }).then(res => {
const { code, data, message: msg } = res
if (code === 1000) {
setFormData(data)
if(data?.deliverAddress) {
PublicApi.getLogisticsReceiverAddressGet({id: data.deliverAddress}).then(_res => {
const { data: _data } = _res
const { provinceName, cityName, districtName, address } = _data
if(res.code === 1000) {
setAddress(`${provinceName}/${cityName}/${districtName}/${address}`)
}
})
}
} else {
message.error(msg)
}
})
// 流转记录(内/外)
// @todo 需补充投标记录api
const inCheckRecordFn = PublicApi.getPurchaseInviteTenderInCheckRecordGetInviteTenderInCheckRecord
inCheckRecordFn({ inviteTenderId: id }, { ctlType: "none" }).then(res => {
const { code, data, message: msg } = res
if (code === 1000) {
setInteriorProcurementOrderLogResponses(data)
} else {
message.error(msg)
}
})
const outCheckRecordFn = PublicApi.getPurchaseTenderOutCheckRecordGetTenderOutCheckRecord
outCheckRecordFn({ inviteTenderId: id }, { ctlType: "none" }).then(res => {
const { code, data, message: msg } = res
if (code === 1000) {
setExternalProcurementOrderLogResponses(data)
} else {
message.error(msg)
}
})
}
}, [id])
// 需共享的状态
const formContext = {
data: formData,
interiorProcurementOrderLogResponses,
externalProcurementOrderLogResponses,
address,
offsetTopList,
ctl: {
setData: setFormData,
setOffsetTopList,
},
reloadFormData
}
return {
formContext,
id,
}
}
.anchorGap {
div {
&:target {
padding-top: 190px;
margin-top: -190px;
}
}
}
import React from 'react';
import PreLoading from '@/components/PreLoading';
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';
import OrderDetailWrapper from '@/pages/orderSystem/components/OrderDetailWrapper';
const CallForBidsSearchDetail: React.FC = () => {
const { formContext, id } = useBidDetail({ type: 'callForBid' })
const { data } = formContext
// type? 用于区分DescriptionsInfo组件的内容
// componentName? 用于区分不同组件的渲染
const anchorTitleList = [
{ title: '流转进度', id: 'transferProcess', componentName: "TransferProcess" },
{ title: '基本信息', id: 'baseicInfo', type: "basicInfo" },
{ title: '招标物料', id: 'bidMaterial', componentName: "BidMaterial" },
{ title: '招标要求', id: 'bidNeed', type: "bidNeed" },
{ title: '报名要求', id: 'registerNeed', type: "registerNeed" },
{ title: '资格预审要求', id: 'checkNeed', type: "checkNeed" },
{ title: '评标要求', id: 'remarkNeed', type: "remarkNeed" },
{ title: '其他要求', id: 'otherNeed', type: "otherNeed" },
{ title: '招标方式', id: 'bidWay', componentName: "BidMethod" },
{ title: '流转记录', id: 'transferRecord', componentName: "BidTransformRecord" },
]
return (
<div>
<BidDetailContext.Provider value={formContext}>
<BidDetailHeader
formContext={formContext}
anchorList={anchorTitleList}
/>
<OrderDetailWrapper>
<PreLoading loading={!formContext.data} active paragraph={{ rows: 6 }}>
<BidDetailSection formContext={formContext} anchorList={anchorTitleList} type="callForBid" />
</PreLoading>
</OrderDetailWrapper>
</BidDetailContext.Provider>
</div>
);
};
export default CallForBidsSearchDetail;
import React from 'react'
import { Card } 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 callForBidsSearch: React.FC<{}> = () => {
const {
ref,
columns
} = useSelfTable()
const fetchTableData = async (params) => {
const { data } = await PublicApi.postPurchaseInviteTenderGetInviteTenderList(params, { ctlType: "none" })
return data
}
return (
<PageHeaderWrapper>
<Card>
<StandardTable
fetchTableData={params => fetchTableData(params)}
currentRef={ref}
columns={columns}
rowKey={'id'}
formilyLayouts={{
justify: 'space-between'
}}
formilyProps={{
ctx: {
inline: false,
schema: tableListSchema,
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
'code',
FORM_FILTER_PATH,
);
},
components: {
DateRangePickerUnix,
Submit
}
}
}}
/>
</Card>
</PageHeaderWrapper>
)
}
export default callForBidsSearch
import React, { useRef } from 'react'
import EyePreview from '@/components/EyePreview'
import { formatTimeString } from '@/utils'
import { CALLFORBID_TYPE, PURCHASE_TYPE } 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 callForBidColumns: any[] = [
{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
render: (text, record, index) => index + 1
},
{
title: '招标编号/项目',
align: 'center',
dataIndex: 'code',
key: 'code',
render: (text, record) => <>
<EyePreview url={`/memberCenter/procurementAbility/callForBids/callForBidsSearch/detail?id=${record.id}`}>
{text}
</EyePreview>
<div>{record['projectName']}</div>
</>
},
{
title: '采购类型',
align: 'center',
dataIndex: 'purchaseType',
key: 'purchaseType',
render: (t) => PURCHASE_TYPE[t]
},
{
title: '招标方式',
align: 'center',
dataIndex: 'inviteTenderType',
key: 'inviteTenderType',
render: (t) => CALLFORBID_TYPE[t]
},
{
title: '发布时间',
align: 'center',
dataIndex: 'createTime',
key: 'createTime',
render: (text, record) => formatTimeString(record.createTime),
width: 200
},
{
title: '报名开始/截止时间',
align: 'center',
dataIndex: 'registerStartTime',
key: 'registerStartTime',
render: (text, record) => <>
<div><PlayCircleOutlined />&nbsp;{formatTimeString(record.registerStartTime)}</div>
<div><PoweroffOutlined />&nbsp;{formatTimeString(record.registerEndTime)}</div>
</>,
width: 200
},
{
title: '资格预审开始/截止时间',
align: 'center',
dataIndex: 'checkStartTime',
key: 'checkStartTime',
render: (text, record) => <>
{record.preCheckStartTime ? <div><PlayCircleOutlined />&nbsp;{formatTimeString(record.preCheckStartTime)}</div> : null}
{record.preCheckEndTime ? <div><PoweroffOutlined />&nbsp;{formatTimeString(record.preCheckEndTime)}</div> : null}
</>,
width: 200
},
{
title: '投标开始/截止时间',
align: 'center',
dataIndex: 'inviteTenderStartTime',
key: 'inviteTenderStartTime',
render: (text, record) => <>
<div><PlayCircleOutlined />&nbsp;{formatTimeString(record.inviteTenderStartTime)}</div>
<div><PoweroffOutlined />&nbsp;{formatTimeString(record.inviteTenderEndTime)}</div>
</>,
width: 200
},
{
title: '外部状态',
align: 'center',
dataIndex: 'outStatus',
key: 'outStatus',
render: text => <CustomTag status={text} type='out' />
},
{
title: '内部状态',
align: 'center',
dataIndex: 'inStatus',
key: 'inStatus',
render: (text) => <CustomBadge status={text} type='inside' />
},
]
return {
ref,
columns: callForBidColumns
}
}
import { ISchema } from '@formily/antd';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { BidInStateTexts, BidOutStateTexts } from '@/constants';
/**
* 招标查询列表高级筛选
*/
export const tableListSchema: ISchema = {
type: 'object',
properties: {
code: {
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: {
projectName: {
type: 'string',
'x-component-props': {
placeholder: '请输入招标项目',
}
},
"[startTime,endTime]": {
type: 'array',
"x-component": 'DateRangePickerUnix',
'x-component-props': {
placeholder: ['发布开始时间','发布结束时间'],
},
},
"[registerStartTime,registerEndTime]": {
type: 'array',
"x-component": 'DateRangePickerUnix',
'x-component-props': {
placeholder: ['报名开始时间','报名结束时间'],
},
},
"outStatus": {
type: 'string',
"x-component-props": {
placeholder: '请选择外部状态'
},
enum: Object.keys(BidOutStateTexts).map(item => ({
label: BidOutStateTexts[item],
value: item,
}))
},
"inStatus": {
type: 'string',
"x-component-props": {
placeholder: '请选择内部状态'
},
enum: Object.keys(BidInStateTexts).map(item => ({
label: BidInStateTexts[item],
value: item,
}))
},
"[preCheckStartTime,preCheckEndTime]": {
type: 'array',
"x-component": 'DateRangePickerUnix',
'x-component-props': {
placeholder: ['预审开始时间','预审结束时间'],
},
},
"[inviteTenderStartTime,inviteTenderEndTime]": {
type: 'array',
"x-component": 'DateRangePickerUnix',
'x-component-props': {
placeholder: ['投标开始时间','投标结束时间'],
},
},
submit: {
'x-component': 'Submit',
'x-component-props': {
children: '查询',
},
},
},
},
}
}
import React, { useContext, useEffect, useState } from 'react'
import ModalForm from '@/components/ModalForm'
import { createFormActions, registerVirtualBox, FormEffectHooks } from '@formily/antd'
import { Checkbox } from 'antd'
import { BidDetailContext } from '../../_public/bid/context'
export interface ApprovedModalProps {
currentRef: any,
onConfirm(),
loading?: boolean,
title?: string,
}
const ApproveSchema = {
type: 'object',
properties: {
NO_SUBMIT: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelAlign: 'top',
},
properties: {
checkStatus: {
type: 'radio',
enum: [
{ label: '审核通过', value: true },
{ label: '审核不通过', value: false },
],
default: true,
"x-component-props": {
disabled: false,
},
"x-linkages": [
{
type: 'value:visible',
target: 'checkRemark',
condition: "{{!$value}}"
},
]
},
checkRemark: {
type: 'textarea',
"x-component-props": {
rows: 4,
placeholder: '在此输入你的原因, 最多60个汉字'
},
title: '审核不通过原因',
"x-rules": [
{
required: true,
message: '请输入审核不通过原因'
},
{
limitByte: true,
maxByte: 30
}
]
}
}
}
}
}
const approvedActions = createFormActions()
// 需要弹窗确认的审核
const ApprovedModal:React.FC<ApprovedModalProps> = (props) => {
const { currentRef, onConfirm, title, children, loading } = props
const { data } = useContext(BidDetailContext)
useEffect(() => {
if (currentRef) {
currentRef.current = Object.assign({}, currentRef.current, {actions: approvedActions})
}
}, [currentRef])
return <ModalForm
modalTitle={title || '提示'}
currentRef={currentRef}
confirm={onConfirm}
actions={approvedActions}
schema={ApproveSchema}
effects={($, ctx) => {
$('onFormInit').subscribe(() => {
// // 上级审核不通过
// if(data && (data.purchaseOrderInteriorState === 6 || data.purchaseOrderInteriorState === 7 || data.purchaseOrderInteriorState === 8)) {
// ctx.setFieldValue("state", 0)
// ctx.setFieldState("state", state => {
// state.props["x-component-props"] = {
// disabled: true
// }
// })
// }
})
}}
modalProps={{confirmLoading: loading}}
/>
}
ApprovedModal.defaultProps = {}
export default ApprovedModal
import React, { useState, useRef, useContext, useEffect } from 'react'
import { Form, Input, Checkbox, Row, Col, InputNumber } from 'antd';
import style from '../../index.less'
/**
* 招标定标表格中 授标的每一项
*/
export interface GivenBidItemProps {
}
export const GivenBidItem:React.FC<GivenBidItemProps> = ({}) => {
const onChangeInput = (v) => {
console.log(v, '改变')
}
const chanegChecked = (e) => {
if(e.target.checked) {
e.nativeEvent.target.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.style.border = '1px solid #00B37A'
e.nativeEvent.target.parentElement.parentElement.nextSibling.style.display = 'inline-block'
} else {
e.nativeEvent.target.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.style.border = 'none'
e.nativeEvent.target.parentElement.parentElement.nextSibling.style.display = 'none'
}
}
return <div className={style.throwBidInfo}>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>含税单价:</p></Col>
<Col><p>¥19.00</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>含税金额:</p></Col>
<Col><p>¥30000</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>是否含税:</p></Col>
<Col><p></p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>税率:</p></Col>
<Col><p>7%</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>授标:</p></Col>
<Col>
<p>
<Checkbox defaultChecked={false} style={{marginRight: 16}} onChange={chanegChecked} />
<InputNumber
defaultValue={100}
min={0}
max={100}
formatter={value => `${value}%`}
parser={value => value.replace('%', '')}
onChange={onChangeInput}
style={{display: 'none'}}
/>
</p>
</Col>
</Row>
</div>
</div>
}
GivenBidItem.defaultProps = {}
export default GivenBidItem
import React, { useState, useRef, useContext, useEffect } from 'react'
import { Form, Input, Divider, Row, Col } from 'antd';
import style from '../../index.less'
/**
* 招标定标表格底部的 合计模块
*/
export interface TotalAmountProps {
}
export const TotalAmount:React.FC<TotalAmountProps> = ({}) => {
return <div className={style.totalWrapper}>
<Row>
<Col span={4}></Col>
<Col span={4}></Col>
<Col span={4}>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>报价小计:</p></Col>
<Col><p>¥156,000.00(含税)</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>报价排名:</p></Col>
<Col><p>1</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>最低标价:</p></Col>
<Col><p>3</p></Col>
</Row>
</div>
</Col>
<Col span={4}>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>报价小计:</p></Col>
<Col><p>¥158,000.00(含税)</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>报价排名:</p></Col>
<Col><p>2</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>最低标价:</p></Col>
<Col><p>2</p></Col>
</Row>
</div>
</Col>
<Col span={4}>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>报价小计:</p></Col>
<Col><p>¥168,000.00(含税)</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>报价排名:</p></Col>
<Col><p>3</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>最低标价:</p></Col>
<Col><p>0</p></Col>
</Row>
</div>
</Col>
<Col span={4}>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>报价小计:</p></Col>
<Col><p>¥176,000.00(含税)</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>报价排名:</p></Col>
<Col><p>4</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>最低标价:</p></Col>
<Col><p>3</p></Col>
</Row>
</div>
</Col>
</Row>
<Divider dashed={true} style={{margin: 0, marginBottom: 8}} />
<Row>
<Col span={4}></Col>
<Col span={4}></Col>
<Col span={4}>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>授标数量:</p></Col>
<Col><p>3</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>授标总额:</p></Col>
<Col><p>¥100,000.00(含税)</p></Col>
</Row>
</div>
</Col>
<Col span={4}>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>授标数量:</p></Col>
<Col><p>1</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>授标总额:</p></Col>
<Col><p>¥54,000.00(含税)</p></Col>
</Row>
</div>
</Col>
<Col span={4}>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>授标数量:</p></Col>
<Col><p>0</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>授标总额:</p></Col>
<Col><p>0</p></Col>
</Row>
</div>
</Col>
<Col span={4}>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>授标数量:</p></Col>
<Col><p>3</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>授标总额:</p></Col>
<Col><p>0</p></Col>
</Row>
</div>
</Col>
</Row>
</div>
}
TotalAmount.defaultProps = {}
export default TotalAmount
.card-list {
font-size: 12px;
// line-height: 20px;
// margin-top: 24px;
// border: 1px solid #F4F5F7;
// padding: 12px;
p {
margin-bottom: 8px;
}
}
.card-list_title {
font-size: 12px;
color: #909399;
}
.bidConfirmWrapper {
:global {
.ant-row {
.ant-col {
.ant-row {
.ant-col-4 {
padding-top: 0;
padding-bottom: 0;
margin-bottom: 2px;
margin-top: 2px;
}
}
}
}
}
background: #F4F5F7;
.bidTableHead {
height: 32px;
line-height: 32px;
background: #F4F5F7;
border: 4px solid #F4F5F7;
color: #303133;
padding-left: 16px;
img {
width: 24px;
height: 24px;
}
.levelCircle {
display: inline-block;
width: 20px;
height: 20px;
line-height: 20px;
background: #EBECF0;
border-radius: 50%;
color: #909399;
margin-right: 8px;
text-align: center;
}
}
.materialInfo, .amountInfo, .throwBidInfo, .totalWrapper {
height: 162px;
background-color: #fff;
padding: 16px;
position: relative;
overflow: hidden;
}
.rankNumber {
width: 32px;
height: 32px;
font-size: 12px;
font-weight: 500;
color: #606266;
line-height: 44px;
border-radius: 50%;
background-color: #F4F5F7;
position: absolute;
top: -16px;
left: -16px;
text-align: right;
padding-right: 6px;
}
}
import React, { useContext, useState } from 'react'
import { Row, Col } from 'antd'
import MellowCard from '@/components/MellowCard'
import { BidDetailContext } from '../../_public/bid/context';
import style from './index.less'
import TotalAmount from './components/totalAmount';
import GivenBidItem from './components/givenBidItem';
import level1 from '../../../../asserts/rank1.png'
import level2 from '../../../../asserts/rank2.png'
import level3 from '../../../../asserts/rank3.png'
/**
* 招标定标
*/
export interface BidConfirmProps {
cardTitle?: string;
}
const BidConfirm: React.FC<BidConfirmProps> = ({cardTitle}) => {
const bidDetailContext = useContext(BidDetailContext)
const { data, ctl } = bidDetailContext
return (
<MellowCard
title={cardTitle}
style={{marginTop: 24}}
bordered={false}
fullHeight
>
<div className={style.bidConfirmWrapper}>
<Row gutter={[0, 4]}>
<Col span={24}>
<Row>
<Col span={4}><p className={style.bidTableHead}>采购物料</p></Col>
<Col span={4}><p className={style.bidTableHead}>采购数量</p></Col>
<Col span={4}><p className={style.bidTableHead}><img src={level1} alt="排名一"/>广州白马皮具交易中心</p></Col>
<Col span={4}><p className={style.bidTableHead}><img src={level2} alt="排名二"/>东莞绿洲皮具有限公司</p></Col>
<Col span={4}><p className={style.bidTableHead}><img src={level3} alt="排名三"/>江门华飞皮具有限公司</p></Col>
<Col span={4}><p className={style.bidTableHead}><span className={style.levelCircle}>4</span>广州万福皮具有限公司</p></Col>
</Row>
<Row gutter={[0, 4]} style={{margin: '0 4px'}}>
<Col span={4}>
<div className={style.materialInfo}>
<span className={style.rankNumber}>1</span>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>物料编号:</p></Col>
<Col><p>Q89YTE1</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>物料名称:</p></Col>
<Col><p>进口头层牛皮荔枝纹</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>规格型号:</p></Col>
<Col><p>红色/XL/厚1.5mm</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>品类:</p></Col>
<Col><p>牛皮</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>品牌:</p></Col>
<Col><p>PELLE</p></Col>
</Row>
</div>
</div>
</Col>
<Col span={4}>
<div className={style.amountInfo}>
<span>3000</span>
<br />
<span style={{color: "#909399"}}>(次)</span>
</div>
</Col>
<Col span={4}>
<GivenBidItem />
</Col>
<Col span={4}>
<GivenBidItem />
</Col>
<Col span={4}>
<GivenBidItem />
</Col>
<Col span={4}>
<GivenBidItem />
</Col>
</Row>
<Row gutter={[0, 4]} style={{margin: '0 4px'}}>
<Col span={4}>
<div className={style.materialInfo}>
<span className={style.rankNumber}>2</span>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>物料编号:</p></Col>
<Col><p>Q89YTE1</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>物料名称:</p></Col>
<Col><p>进口头层牛皮荔枝纹</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>规格型号:</p></Col>
<Col><p>红色/XL/厚1.5mm</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>品类:</p></Col>
<Col><p>牛皮</p></Col>
</Row>
</div>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>品牌:</p></Col>
<Col><p>PELLE</p></Col>
</Row>
</div>
</div>
</Col>
<Col span={4}>
<div className={style.amountInfo}>
<span>3000</span>
<br />
<span style={{color: "#909399"}}>(次)</span>
</div>
</Col>
<Col span={4}>
<GivenBidItem />
</Col>
<Col span={4}>
<GivenBidItem />
</Col>
<Col span={4}>
<GivenBidItem />
</Col>
<Col span={4}>
<GivenBidItem />
</Col>
</Row>
<Row gutter={[0, 4]} style={{margin: '0 4px'}}>
<Col span={24}>
<TotalAmount />
</Col>
</Row>
</Col>
</Row>
</div>
</MellowCard>)
}
BidConfirm.defaultProps = {}
export default BidConfirm
.titleAvator {
width:48px;
height:48px;
background:rgba(135,119,217,1);
border-radius:4px;
border:1px solid rgba(223,225,230,1);
line-height: 48px;
text-align: center;
color: #fff;
margin: 0 24px;
}
.titleAvatorText {
font-size: 16px;
font-weight: 500;
color: #303133;
margin-left: 8px;
}
.detailHeader {
background: #fff;
padding: 24px 24px 0;
:global {
.ant-row {
.ant-col-2 {
.ant-btn {
position: absolute;
top: 0;
right: 0;
}
}
}
.ant-anchor-wrapper {
min-height: auto;
}
.ant-anchor {
display: flex;
}
.ant-anchor-ink{
display: none;
}
.ant-anchor-link {
padding: 0;
text-align: center;
a {
display: inline-block;
font-size: 14px;
color: #909399;
margin: 0 16px;
height: 48px;
line-height: 48px;
}
}
.ant-anchor-link-active {
a{
font-weight: 500;
color: #303133;
border-bottom: 2px solid #00B37A;
}
}
}
}
.detailCol {
display: flex;
margin-top: 20px;
color: #303133;
}
.colLabel {
color: #909399;
margin-right: 16px;
}
// tabs标签锚点
.anchorTitle {
// height: 48px;
ul {
padding-left: 0;
display: flex;
li {
height: 48px;
line-height: 48px;
text-align: center;
list-style: none;
a {
display: inline-block;
height: 48px;
font-size: 14px;
color: #909399;
line-height: 48px;
margin: 0 16px;
}
.current {
font-weight: 500;
color: #303133;
border-bottom: 2px solid #00B37A;
}
}
}
}
.anchorTitleFixed {
position: fixed;
top: 0;
width: 100%;
z-index: 10;
:global {
.ant-row {
.ant-col-2 {
.ant-btn {
position: fixed;
top: 16px;
right: 16px;
}
}
}
}
}
import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'react'
import { Row, Col, Skeleton, Anchor } from 'antd'
import { history } from 'umi'
import { ArrowLeftOutlined, BugTwoTone } from '@ant-design/icons'
import style from './index.less'
const { Link } = Anchor;
export interface BidDetailHeaderProps {
extraRight?: ReactNode,
// detailList?: { label: string, name: string, render?(text, record?), [key: string]: any }[],
formContext?: any,
anchorList?: any,
backLink?: string,
contentRef?: any,
}
/**
* 招标详情头部
*/
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 [isFixed, setIsFixed] = useState<boolean>(false)
useEffect(() => {
window.addEventListener("scroll", onScroll)
return (() => {
window.removeEventListener('scroll', onScroll)
})
}, [])
const onScroll = () => {
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
let floors = document.querySelectorAll(".anchorContent>div")
floors.forEach((floor: any, index: any) => {
if (floor.offsetTop - 100 <= scrollTop) {
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
}
if (distance <= 0) {
setIsFixed(true)
}
if (document.documentElement.scrollTop <= flagRef.current.distanceTop) {
setIsFixed(false)
}
}
}
const clickItem = (index: any) => {
let distance = formContext.offsetTopList[index] - 140
window.scrollTo({
top: distance < 0 ? 0 : distance,
behavior: "smooth"
})
let dom = document.documentElement || document.body
if (formContext.offsetTopList[index] - 189 + dom.clientHeight >= dom.scrollHeight) {
setCurrent(index)
}
}
return (
<div className={isFixed ? [style.detailHeader, style.anchorTitleFixed].join(' ') : style.detailHeader} id="detailHeader">
{
isLoading ?
<Row>
{
<>
<Col span={22}>
<Row align='middle'>
<Col>
<ArrowLeftOutlined onClick={() => backLink ? history.push(backLink) : history.goBack()} />
</Col>
<Col>
<div className={style.titleAvatorText}>{formContext.data.projectName}&nbsp;|&nbsp;{formContext.data.code}</div>
</Col>
</Row>
<Row>
<Col>
<div className={style.anchorTitle} id="anchorTitle">
{/* <ul className={style.anchorUl}>
{
anchorList.map((item, index) => (
<li key={index} onClick={()=>clickItem(index)}>
<a className={current === index ? style.current : null}>{item}</a>
</li>
))
}
</ul> */}
<Anchor onClick={(e) => e.preventDefault()} showInkInFixed={false} targetOffset={200}>
{
anchorList.map((item, index) => (
<Link key={index} href={`#${item['id']}`} title={item['title']} />
))
}
</Anchor>
</div>
</Col>
</Row>
</Col>
<Col span={2}>{extraRight}</Col>
</>
}
</Row>
: <Skeleton avatar={{ shape: 'square' }} active paragraph={{ rows: 3 }} />
}
</div>
)
}
BidDetailHeader.defaultProps = {}
export default BidDetailHeader
.anchorContentWrap {
div {
&:target {
padding-top: 200px;
margin-top: -200px;
}
}
}
import React, { useEffect } from 'react'
import { findLastIndexFlowState } from '@/utils'
import style from './index.less'
import TransferProcess from '../transferProcess'
import DescriptionsInfo from '../descriptionsInfo'
import BidMaterial from '../bidMaterial'
import BidMethod from '../bidMethod'
import BidTransformRecord from '../transferRecord'
import BidParticulars from '../bidParticulars'
import RemarkBidReport from '../remarkBidReport'
import ParticipateInfo from '../participateInfo'
import BidConfirm from '../bidConfirm'
import MemberWinInfo from '../memberWinInfo'
export interface BidDetailSectionProps {
formContext: any,
/** callForBid 招标 | tender 投标 */
type?: 'callForBid' | 'tender',
anchorList?: any,
}
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)
}, [])
// 名称与组件映射
const NameMapComponent = {
// 流转进度组件
"TransferProcess": TransferProcess,
// 信息 基本信息组件
"DescriptionsInfo": DescriptionsInfo,
// 物料组件
"BidMaterial": BidMaterial,
// 招标方式组件
"BidMethod": BidMethod,
// 流转记录组件
"BidTransformRecord": BidTransformRecord,
// 中标明细组件
"BidParticulars": BidParticulars,
// 评标报告
"RemarkBidReport": RemarkBidReport,
// 会员参标信息
"ParticipateInfo": ParticipateInfo,
// 招标定标
"BidConfirm": BidConfirm,
// 会员中标信息
"MemberWinInfo": MemberWinInfo,
}
const RenderDetailSection = ({ componentList }) => {
if(componentList && componentList.length > 0) {
return componentList.map((item, index) => (
<div key={index} id={item['id']}>{ RenderCertainContent(item) }</div>
))
} else {
return null
}
}
const RenderCertainContent = ({ id, title, type = null, componentName = null }) => {
let RcDom: any = null;
switch(componentName) {
//@todo 需另外调用接口获取数据
case 'TransferProcess':
RcDom = (<TransferProcess
cardTitle={title}
customTitleKey='operationalProcess'
customKey='state'
outerVerifyCurrent={findLastIndexFlowState(formContext.data.externalWorkflowFlowRecordLogResponses)}
innerVerifyCurrent={findLastIndexFlowState(formContext.data.interiorWorkflowFlowRecordLogResponses)}
outerVerifySteps={
formContext.data.externalWorkflowFlowRecordLogResponses ?
formContext.data.externalWorkflowFlowRecordLogResponses.map(item => ({
...item,
status: item.isExecute ? 'finish' : 'wait',
})) :
[]
}
innerVerifySteps={
formContext.data.interiorWorkflowFlowRecordLogResponses ?
formContext.data.interiorWorkflowFlowRecordLogResponses.map(item => ({
...item,
status: item.isExecute ? 'finish' : 'wait',
})) :
[]
}
></TransferProcess>)
break;
case "BidMaterial":
RcDom = (<BidMaterial cardTitle={title} />)
break;
case "BidMethod":
RcDom = (<BidMethod cardTitle={title} />)
break;
case "BidTransformRecord":
RcDom = (<BidTransformRecord cardTitle={title} />)
break;
case "BidParticulars":
RcDom = (<BidParticulars cardTitle={title} />)
break;
case "RemarkBidReport":
RcDom = (<RemarkBidReport cardTitle={title} />)
break;
case "ParticipateInfo":
RcDom = (<ParticipateInfo cardTitle={title} />)
break;
case "BidConfirm":
RcDom = (<BidConfirm cardTitle={title} />)
break;
case "MemberWinInfo":
RcDom = (<MemberWinInfo cardTitle={title} />)
break;
default:
RcDom = (<DescriptionsInfo cardTitle={title} type={type} />)
}
return RcDom;
}
return (
formContext.data &&
<div className={[style.anchorContentWrap, "anchorContent"].join(' ')}>
<RenderDetailSection componentList={anchorList} />
</div>
)
}
BidDetailSection.defaultProps = {}
export default BidDetailSection
.card-list {
font-size: 12px;
line-height: 20px;
margin-top: 12px;
}
.card-list_title {
font-size: 12px;
color: #909399;
}
// 抽屉内部内容样式
.drawerContainer {
.drawerNav {
position: fixed;
width: 160px;
height: 100%;
&:after {
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;
height: 14px;
line-height: 14px;
.longString {
color: #00B37A;
margin-right: 6px;
height: 14px;
line-height: 14px;
}
// &:before {
// content: "";
// border: 2px solid #00B37A;
// margin-right: 6px;
// }
}
}
}
}
}
import React, { useContext, useEffect, useRef, useState } from 'react'
import { Table, Drawer, Button, Tabs, Row, Col } from 'antd'
import MellowCard from '@/components/MellowCard'
import { BidDetailContext } from '../../_public/bid/context';
import EyePreview from '@/components/EyePreview';
import style from './index.less'
import AnchorDrawer from '@/components/AnchorDrawer';
/**
* 招标物料表格
*/
export interface BidMaterialProps {
cardTitle?: string;
}
const BidMaterial: React.FC<BidMaterialProps> = ({cardTitle}) => {
const bidDetailContext = useContext(BidDetailContext)
const { data, ctl } = bidDetailContext
const { materielList } = data
const [visible, setVisible] = useState<boolean>(false)
const [currentRow, setCurrentRow] = useState<any>()
const dataList = currentRow?.code ? [
{
title: '基本信息',
id: 'baseInfo',
name: '',
render: (data) => (<>
<Row className={style['card-list']}>
<Col span={4} className={style['card-list_title']}>物料编号:</Col>
<Col>{currentRow['code']}</Col>
</Row>
<Row className={style['card-list']}>
<Col span={4} className={style['card-list_title']}>物料名称:</Col>
<Col>{currentRow['name']}</Col>
</Row>
<Row className={style['card-list']}>
<Col span={4} className={style['card-list_title']}>规格型号:</Col>
<Col>{currentRow['type']}</Col>
</Row>
<Row className={style['card-list']}>
<Col span={4} className={style['card-list_title']}>品类:</Col>
<Col>{currentRow['categoryName']}</Col>
</Row>
<Row className={style['card-list']}>
<Col span={4} className={style['card-list_title']}>品牌:</Col>
<Col>{currentRow['brandName']}</Col>
</Row>
</>)
},
// {
// title: '产地',
// name: '',
// id: 'productLocatoin',
// render: (data) => (<>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>产地:</Col>
// <Col>产地</Col>
// </Row>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>产地:</Col>
// <Col>产地</Col>
// </Row>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>产地:</Col>
// <Col>产地</Col>
// </Row>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>产地:</Col>
// <Col>产地</Col>
// </Row>
// </>)
// },
// {
// title: '外观尺寸',
// name: '',
// id: 'aspect',
// render: (data) => (<>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>外观尺寸:</Col>
// <Col>外观尺寸</Col>
// </Row>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>外观尺寸:</Col>
// <Col>外观尺寸</Col>
// </Row>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>外观尺寸:</Col>
// <Col>外观尺寸</Col>
// </Row>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>外观尺寸:</Col>
// <Col>外观尺寸</Col>
// </Row>
// </>)
// },
// {
// title: '工艺',
// name: '',
// id: 'technique',
// render: (data) => (<>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>工艺:</Col>
// <Col>工艺</Col>
// </Row>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>工艺:</Col>
// <Col>工艺</Col>
// </Row>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>工艺:</Col>
// <Col>工艺</Col>
// </Row>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>工艺:</Col>
// <Col>工艺</Col>
// </Row>
// </>)
// },
// {
// title: '特殊说明',
// name: '',
// id: 'specificText',
// render: (data) => (<>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>特殊说明:</Col>
// <Col>特殊说明</Col>
// </Row>
// <Row className={style['card-list']}>
// <Col span={4} className={style['card-list_title']}>特殊说明:</Col>
// <Col>特殊说明</Col>
// </Row>
// </>)
// },
{
title: '附件',
name: '',
id: 'file',
render: (data) => (<>
<Row className={style['card-list']}>
<Col span={4} className={style['card-list_title']}>附件:</Col>
{
currentRow.file?.length ? currentRow['file'].map(item => <Col key={item.id}><a href={item.url} target="_blank">{item.name}</a></Col>) : null
}
</Row>
</>)
},
{
title: '采购数量',
name: '',
id: 'purchaseAmount',
render: (data) => (<>
<Row className={style['card-list']}>
<Col span={4} className={style['card-list_title']}>单位:</Col>
<Col>{currentRow['unitName']}</Col>
</Row>
<Row className={style['card-list']}>
<Col span={4} className={style['card-list_title']}>采购数量:</Col>
<Col>{currentRow['count']}</Col>
</Row>
</>)
},
] : []
const columns = [
{
title: '物料编号',
dataIndex: 'code',
key: 'code',
render: (text, record) => <>
<EyePreview type="button" handleClick={()=>clickPreview(record)}>
{text}
</EyePreview>
</>
},
{
title: '物料名称',
dataIndex: 'name',
key: 'name',
},
{
title: '规格型号',
dataIndex: 'type',
key: 'type',
},
{
title: '品类',
dataIndex: 'categoryName',
key: 'categoryName',
},
{
title: '品牌',
dataIndex: 'brandName',
key: 'brandName',
},
{
title: '单位',
dataIndex: 'unitName',
key: 'unitName',
},
{
title: '采购数量',
dataIndex: 'count',
key: 'count',
},
];
const clickPreview = (record) => {
console.log(record, '查看物料')
setCurrentRow(record)
setVisible(true)
}
const footer = (<div
style={{
textAlign: 'right',
}}
>
<Button onClick={()=>setVisible(false)} style={{ marginRight: 8 }}>
取消
</Button>
<Button onClick={()=>setVisible(false)} type="primary">
确定
</Button>
</div>)
return (<>
<MellowCard
title={cardTitle}
style={{marginTop: 24}}
bordered={false}
fullHeight
>
<Table dataSource={materielList} columns={columns} pagination={{size: "small"}} />
</MellowCard>
<AnchorDrawer
title="物料详情"
visible={visible}
dataRenderList={dataList}
footer={footer}
onClose={() => setVisible(false)}
/>
</>)
}
BidMaterial.defaultProps = {}
export default BidMaterial
.card-list {
font-size: 12px;
line-height: 20px;
margin-top: 24px;
}
.card-list_title {
font-size: 12px;
color: #909399;
}
import React, { useContext, useState } from 'react'
import { Table, Button, Switch, Tooltip, Row, Col } from 'antd'
import MellowCard from '@/components/MellowCard'
import { BidDetailContext } from '../../_public/bid/context';
import { QuestionCircleOutlined } from '@ant-design/icons';
import style from './index.less'
import { CALLFORBID_TYPE, INVITE_BID } from '@/constants';
import BASE_CONFIG from '../../../../../config/base.config.json'
const shopInfo = BASE_CONFIG.web.shopInfo
/**
* 招标方式
*/
export interface BidMethodProps {
cardTitle?: string;
}
const BidMethod: React.FC<BidMethodProps> = ({cardTitle}) => {
const bidDetailContext = useContext(BidDetailContext)
const { data, ctl } = bidDetailContext
const columns = [
{
title: '序号',
dataIndex: 'id',
key: 'id',
render: (t, r, i) => ++i
},
{
title: '会员名称',
dataIndex: 'memberName',
key: 'memberName',
},
{
title: '会员类型',
dataIndex: 'memberTypeName',
key: 'memberTypeName',
},
{
title: '会员角色',
dataIndex: 'memberRoleName',
key: 'memberRoleName',
},
{
title: '是否归属会员',
dataIndex: 'isAffiliate',
key: 'isAffiliate',
render: (t, r) => t ? '是' : '否',
},
{
title: <>状态<Tooltip title="打开开关,审核通过后,将招标发至对应的会员"><span>&nbsp;<QuestionCircleOutlined /></span></Tooltip></>,
dataIndex: 'status',
key: 'status',
render: (text, record) => <Switch disabled defaultChecked onChange={() => onChange(record)} />
},
{
title: '操作',
dataIndex: 'ctl',
key: 'ctl',
render: (text, record) => <Button type="link" target="blank" href={`/shop?shopId=${btoa(JSON.stringify({ roleId: record.roleId, memberId: record.memberId }))}`}>进入店铺</Button>
}
];
const onChange = (record) => {
console.log(record)
}
return (
<MellowCard
title={cardTitle}
style={{marginTop: 24}}
bordered={false}
fullHeight
>
<div className={style['card-list']}>
<Row>
<Col span={2}><p className={style['card-list_title']}>招标方式</p></Col>
<Col><p>{CALLFORBID_TYPE[data.inviteTenderType]}</p></Col>
</Row>
</div>
{
data.inviteTenderType === INVITE_BID ?
<Table dataSource={data.memberList} columns={columns} pagination={{size: "small"}} />
:
<div className={style['card-list']}>
<Row>
<Col span={2}><p className={style['card-list_title']}>发布商城</p></Col>
<Col>
<p>
{
data.inviteTenderShopList.map(item => {
return shopInfo.find(_item => _item.type === item.type && _item.environment === item.environment)['name']
}).join(' / ')
}
</p>
</Col>
</Row>
</div>
}
</MellowCard>)
}
BidMethod.defaultProps = {}
export default BidMethod
.particulars {
margin-top: 24px;
:global {
.ant-table-tbody > tr.ant-table-row:hover > td {
border-top: 1px solid #00B37A;
border-bottom: 1px solid #00B37A;
background: #fff;
&:first-child {
border-left: 1px solid #00B37A;
}
&:last-child {
border-right: 1px solid #00B37A;
}
}
.ant-table-expanded-row td {
padding: 0;
}
}
}
.childrenWrap {
background-color: #fff;
.childrenTitle {
height: 100%;
background: linear-gradient(to left, #FFFFFF, #DAF2E7);
color: #00B37A;
p {
padding-left: 16px;
margin: 0;
font-size: 12px;
height: 14px;
line-height: 14px;
}
padding: 12px 0;
}
.childrenContent {
margin-top: 8px;
p {
margin: 0;
span {
height: 12px;
font-size: 12px;
font-weight: 400;
color: #909399;
line-height: 12px;
padding-right: 10px;
}
}
}
}
import React, { useContext, useEffect, useRef, useState } from 'react'
import { Table, Drawer, Button, Tabs, Row, Col } from 'antd'
import MellowCard from '@/components/MellowCard'
import { BidDetailContext } from '../../_public/bid/context';
import EyePreview from '@/components/EyePreview';
import style from './index.less'
import { CaretDownOutlined, CaretRightOutlined } from '@ant-design/icons';
/**
* 中标明细和投标物料嵌套表格
*/
export interface BidParticularsProps {
cardTitle?: string;
}
const BidParticulars: React.FC<BidParticularsProps> = ({cardTitle}) => {
const bidDetailContext = useContext(BidDetailContext)
const { data, ctl } = bidDetailContext
const columns = [
{ title: '物料编号/名称', dataIndex: 'name', key: 'name' },
{ title: '规格型号', dataIndex: 'age', key: 'age' },
{ title: '品类', dataIndex: 'address', key: 'address' },
{ title: '品牌', dataIndex: 'brand', key: 'brand' },
{ title: '采购数量/单位', dataIndex: 'number', key: 'number' },
{ title: '含税/税率', dataIndex: 'tax', key: 'tax' },
{ title: '单价(含税)', dataIndex: 'price', key: 'price' },
{ title: <span>金额(含税)<br />合计: ¥152,000.00</span>, dataIndex: 'amount', key: 'amount' },
];
const dataSource = [
{
key: 1,
name: <span>Q89YTE1<br />进口头层牛皮荔枝纹</span>,
age: '红色/XL/厚1.5mm',
address: '牛皮',
brand: 'PELLE',
number: <span>2000<br /></span>,
tax: <span><br />6%</span>,
price: "¥18.00",
amount: "¥38,000.00",
description: <div className={style.childrenWrap}>
<Row>
<Col span={3}>
<div className={style.childrenTitle}>
<p>对应</p>
<p>招标商品</p>
</div>
</Col>
<Col span={6}>
<div className={style.childrenContent}>
<p><span>商品编号:</span>Q89YTE1</p>
<p><span>商品名称:</span>进口头层黄牛皮荔枝纹</p>
</div>
</Col>
<Col span={6}>
<div className={style.childrenContent}>
<p><span>规格型号:</span>Q89YTE1</p>
<p><span>品类:</span>进口头层黄牛皮荔枝纹</p>
</div>
</Col>
<Col span={6}>
<div className={style.childrenContent}>
<p><span>品牌:</span>Q89YTE1</p>
</div>
</Col>
<Col span={3}>
<div className={style.childrenContent}>
<p><a href="">查看</a></p>
</div>
</Col>
</Row>
</div>,
},
{
key: 2,
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
},
{
key: 3,
name: 'Not Expandable',
age: 29,
address: 'Jiangsu No. 1 Lake Park',
description: 'This not expandable',
},
{
key: 4,
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.',
},
];
return (<>
<MellowCard
title={cardTitle}
bordered={false}
fullHeight
className={style.particulars}
style={{marginTop: 24}}
>
<Table
columns={columns}
expandable={{
expandedRowRender: record => <p style={{ margin: 0 }}>{record.description}</p>,
rowExpandable: record => record.name !== 'Not Expandable',
expandIcon: ({ expanded, onExpand, record }) =>
expanded ? (
<CaretDownOutlined onClick={e => onExpand(record, e)} />
) : (
<CaretRightOutlined onClick={e => onExpand(record, e)} />
)
}}
dataSource={dataSource}
pagination={{size: "small"}}
/>
</MellowCard>
</>)
}
BidParticulars.defaultProps = {}
export default BidParticulars
import React from 'react'
import { Tag } from 'antd'
import { BidInStateTexts, BidOutStateTexts } from '@/constants'
// 用于标签状态控制
export interface StatusColorsProps {
status: number,
type: 'out' | 'inside'
}
// 颜色映射
const mapColor = [
"#606266", // 灰
"#FF991F", // 黄
"#3F7ED2", // 蓝
"#6554C0", // 紫
"#E63F3B", // 红
"#00B37A", // 绿
]
// className映射
const classNameMap = [
"commonStatusStop", // 灰色
"commonStatusInvalid", // 黄色
"commonStatusModify", // 蓝色
"commonStatusValid", // 绿色
"commonStatusStop", // 灰色
"commonStatusInvalid", // 黄色
"commonStatusModify", // 蓝色
"commonStatusValid", // 绿色
"commonStatusStop", // 灰色
"commonStatusInvalid", // 黄色
"commonStatusModify", // 蓝色
"commonStatusValid", // 绿色
]
// 订单内部状态显示
const CustomBadge: React.FC<StatusColorsProps> = (props) => {
const { status, type } = props
const typeMaps = {
'out': BidOutStateTexts,
'inside': BidInStateTexts,
}
const statusText = typeMaps[type]
return (status ? <><span className={`${classNameMap[status]}`}></span>{statusText[status]}</> : null)
}
CustomBadge.defaultProps = {}
export default CustomBadge
import React from 'react'
import { Tag } from 'antd'
import { BidInStateTexts, BidOutStateTexts } from '@/constants'
// 用于标签状态控制
export interface StatusColorsProps {
status: number,
/** 外部状态 内部状态 外部流转状态 内部流转状态 */
type: 'out' | 'inside' | 'transformInside' | 'transformOut'
}
// 颜色映射
const mapColor = [
"rgb(96, 98, 102)", // 灰
"rgb(255, 153, 31)", // 黄
"rgb(63, 126, 210)", // 蓝
"rgb(101, 84, 192)", // 紫
"rgb(230, 63, 59)", // 红
"rgb(0, 179, 122)", // 绿
"rgb(96, 98, 102)", // 灰
"rgb(255, 153, 31)", // 黄
"rgb(63, 126, 210)", // 蓝
"rgb(101, 84, 192)", // 紫
"rgb(230, 63, 59)", // 红
"rgb(0, 179, 122)", // 绿
]
// 订单内部状态显示
const CustomTag: React.FC<StatusColorsProps> = (props) => {
const { status, type } = props
const typeMaps = {
'out': BidOutStateTexts,
'inside': BidInStateTexts,
}
const statusText = typeMaps[type]
const color = mapColor[status]
// const statusShowColor = matchStatusColor(status)
return (
status ? <span style={{
color: color,
padding: '2px 4px',
backgroundColor: `rgba(${color.slice(4, color.length-1)}, 0.1)`,
borderRadius: '4px',
}}>{statusText[status]}</span> : null
)
}
CustomTag.defaultProps = {}
export default CustomTag
.card-list {
font-size: 12px;
line-height: 20px;
margin-top: 24px;
}
.card-list_title {
font-size: 12px;
color: #909399;
}
.resultFail {
font-size: 16px;
font-weight: 500;
color: #303133;
}
.resultFailSubtitle {
font-size: 12px;
font-weight: 400;
color: #303133;
padding-left: 32px;
}
.thankModal{
:global{
.ant-modal-header {
display: none;
}
.ant-modal-content {
height: 440px;
background: url("/static/imgs/thankLetterBg.png") center center no-repeat;
// background: url('../../../../assets/imgs/thankLetterBg.png') center center no-repeat;
}
.ant-modal-footer {
display: none;
}
}
}
.thankLetter {
// width: 660px;
// height: 440px;
h2 {
text-align: center;
font-size: 24px;
font-weight: 500;
color: #303133;
// height: 36px;
// line-height: 36px;
padding-top: 20px;
}
h4 {
text-align: center;
font-size: 16px;
font-weight: 500;
color: #C0C4CC;
line-height: 16px;
padding: 0 24px;
}
p {
font-size: 14px;
font-weight: 400;
color: #303133;
line-height: 24px;
padding: 0 24px;
}
.name {
font-weight: 500;
text-align: left;
padding: 0 24px;
}
.company {
text-align: right;
padding: 0 24px;
margin-top: 100px;
}
.time {
text-align: right;
padding: 0 24px;
}
}
This diff is collapsed.
import React, { useContext, useEffect, useState } from 'react'
import ModalForm from '@/components/ModalForm'
import { createFormActions, registerVirtualBox, FormEffectHooks } from '@formily/antd'
import { Checkbox } from 'antd'
import { BidDetailContext } from '../../_public/bid/context';
import moment from 'moment';
export interface DestroyModalProps {
currentRef: any,
onConfirm(),
loading?: boolean,
title?: string,
formSchema?: any,
}
const destroyActions = createFormActions()
// 通用弹框
const DestroyModal:React.FC<DestroyModalProps> = (props) => {
const { currentRef, onConfirm, title, children, loading, formSchema } = props
const { data } = useContext(BidDetailContext)
useEffect(() => {
if (currentRef) {
currentRef.current = Object.assign({}, currentRef.current, {actions: destroyActions})
}
}, [currentRef])
return <ModalForm
modalTitle={title || '提示'}
currentRef={currentRef}
confirm={onConfirm}
actions={destroyActions}
schema={formSchema}
effects={($, ctx) => {
// $('onFormInit').subscribe(() => {
// })
}}
modalProps={{confirmLoading: loading}}
/>
}
DestroyModal.defaultProps = {}
export default DestroyModal
.card-list {
font-size: 12px;
line-height: 20px;
margin-top: 16px;
border: 1px solid #F4F5F7;
padding: 12px;
background-color: #FAFBFC;
position: relative;
img {
display: block;
position: absolute;
top: 0;
right: 8px;
}
}
.card-list_title {
font-size: 12px;
color: #909399;
}
.amount {
font-size: 16px;
font-weight: 500;
color: #303133;
}
import React, { useContext, useState } from 'react'
import { Table, Button, Radio, Divider, Row, Col } from 'antd'
import MellowCard from '@/components/MellowCard'
import { QuestionCircleOutlined, UserOutlined } from '@ant-design/icons';
import style from './index.less'
import winBid from '../../../../asserts/winBid.png'
import { BidDetailContext } from '../../_public/bid/context';
/**
* 会员中标信息
*/
export interface MemberWinInfoProps {
cardTitle?: string;
}
const MemberWinInfo: React.FC<MemberWinInfoProps> = ({cardTitle}) => {
const bidDetailContext = useContext(BidDetailContext)
const { data, ctl } = bidDetailContext
return (
<MellowCard
title={cardTitle}
style={{marginTop: 24}}
bordered={false}
fullHeight
>
<div className={style.remarkBidReportWrapper}>
<div className={style.bidMemberContainer}>
<h3 className="commonPanelTitle">中标会员</h3>
<Row gutter={[16, 0]}>
<Col span={6}>
<div className={style['card-list']}>
<h4>广州室间隔度过后工地</h4>
<Row>
<Col span={8}><p className={style['card-list_title']}>中标总金额(含税):</p></Col>
<Col><p className={style.amount}>¥160,000.00</p></Col>
</Row>
<img src={winBid} alt="已中标"/>
</div>
</Col>
<Col span={6}>
<div className={style['card-list']}>
<h4>广州室间隔度过后工地</h4>
<Row>
<Col span={8}><p className={style['card-list_title']}>中标总金额(含税):</p></Col>
<Col><p className={style.amount}>¥160,000.00</p></Col>
</Row>
<img src={winBid} alt="已中标"/>
</div>
</Col>
</Row>
</div>
<Divider dashed />
<div className={style.remarkCommitteeContainer}>
<h3 className="commonPanelTitle">中标理由</h3>
<Row gutter={[16, 0]}>
<Col span={4}>
<div className={style['card-list']}>
<Row>
<Col span={8}><p className={style['card-list_title']}>中标理由</p></Col>
<Col><p>七天无理由中标</p></Col>
</Row>
<Row>
<Col span={8}><p className={style['card-list_title']}>中标附件</p></Col>
<Col><p>666.pdf</p></Col>
</Row>
</div>
</Col>
</Row>
</div>
</div>
</MellowCard>)
}
MemberWinInfo.defaultProps = {}
export default MemberWinInfo
.card-list {
font-size: 12px;
line-height: 20px;
margin-top: 24px;
// border: 1px solid #F4F5F7;
// padding: 12px;
}
.card-list_title {
font-size: 12px;
color: #909399;
}
.participateContent {
border: 1px solid #F4F5F7;
padding: 12px;
margin-bottom: 16px;
border-top: 1px solid #00B37A;
}
.amount {
font-weight: bold;
border-bottom: 1px dashed #EBECF0;
margin-bottom: 0;
padding-bottom: 12px;
span {
color: #909399
}
}
import React, { useContext, useState } from 'react'
import { Table, Button, Radio, Tooltip, Row, Col } from 'antd'
import MellowCard from '@/components/MellowCard'
import { BidDetailContext } from '../../_public/bid/context';
import { QuestionCircleOutlined, UserOutlined } from '@ant-design/icons';
import style from './index.less'
import CustomTag from '../CustomTag';
/**
* 会员参标信息
*/
export interface ParticipateInfoProps {
cardTitle?: string;
}
const ParticipateInfo: React.FC<ParticipateInfoProps> = ({cardTitle}) => {
const bidDetailContext = useContext(BidDetailContext)
const { data, ctl } = bidDetailContext
const mockData = [
{
company: '广州第三个官方工地公司',
amount: 13516,
isTax: true,
status: 1,
createTime: '2012-12-14 23:35:43',
no: 'HEGF05495',
},
{
company: '广州第三个官方工地公司',
amount: 13516,
isTax: false,
status: 1,
createTime: '2012-12-14 23:35:43',
no: 'HEGF05495',
},
{
company: '广州第三个官方工地公司',
amount: 13516,
isTax: false,
status: 2,
createTime: '2012-12-14 23:35:43',
no: 'HEGF05495',
},
{
company: '广州第三个官方工地公司',
amount: 13516,
isTax: true,
status: 1,
createTime: '2012-12-14 23:35:43',
no: 'HEGF05495',
},
{
company: '广州第三个官方工地公司',
amount: 13516,
isTax: true,
status: 0,
createTime: '2012-12-14 23:35:43',
no: 'HEGF05495',
},
{
company: '广州第三个官方工地公司',
amount: 13516,
isTax: true,
status: 1,
createTime: '2012-12-14 23:35:43',
no: 'HEGF05495',
},
{
company: '广州第三个官方工地公司',
amount: 13516,
isTax: true,
status: 2,
createTime: '2012-12-14 23:35:43',
no: 'HEGF05495',
},
]
return (
<MellowCard
title={cardTitle}
style={{marginTop: 24}}
bordered={false}
fullHeight
>
<div className={style.participateWrapper}>
<Row gutter={[16, 0]}>
{
mockData.map((item, index) => (<Col span={4} key={index}>
<div className={style.participateContent}>
<div className={style.topWrapper}>
<h3>{item.company}</h3>
<p className={style.amount}>{item.amount}<span>{item.isTax ? ' (含税)' : ' (不含税)'}</span></p>
</div>
<div className={style.contentWrapper}>
<Row className={style['card-list']}>
<Col span={8} className={style['card-list_title']}>环节状态:</Col>
<Col>
<CustomTag type="out" status={item.status} />
</Col>
</Row>
<Row className={style['card-list']}>
<Col span={8} className={style['card-list_title']}>投标时间:</Col>
<Col>{item.createTime}</Col>
</Row>
<Row className={style['card-list']}>
<Col span={8} className={style['card-list_title']}>投标单号:</Col>
<Col>{item.no}</Col>
</Row>
</div>
</div>
</Col>
))
}
</Row>
</div>
</MellowCard>)
}
ParticipateInfo.defaultProps = {}
export default ParticipateInfo
.card-list {
font-size: 12px;
line-height: 20px;
margin-top: 24px;
border: 1px solid #F4F5F7;
padding: 12px;
}
.card-list_title {
font-size: 12px;
color: #909399;
}
.headColor {
font-weight: 500;
color: #909399;
}
.rankContainer {
.levelCircle {
display: inline-block;
width: 20px;
height: 20px;
background: #EBECF0;
border-radius: 50%;
color: #909399;
margin-right: 8px;
text-align: center;
}
p {
display: flex;
justify-content: space-between;
margin-left: 8px;
}
h5 {
margin-left: 8px;
}
}
.remarkBidReportWrapper {
// 评标委员会
.remarkCommitteeContainer {
margin-bottom: 24px;
.committeeItem {
position: relative;
display: flex;
background-color: #FAFBFC;
text-align: center;
padding-top: 12px;
padding-left: 12px;
p {
align-items: center;
height: 56px;
line-height: 56px;
}
.avater {
width: 72px;
img {
width: 32px;
height: 32px;
}
p {
height: 12px;
font-size: 12px;
font-weight: 400;
color: #909399;
line-height: 12px;
}
}
.status {
position: absolute;
right: 0;
top: 0;
height: 12px;
font-size: 12px;
font-weight: 400;
color: #00B37A;
line-height: 12px;
padding: 2px 4px;
background-color: #E4F7EF;
}
}
}
// 评标记录
.remarkRecordContainer {
.remarkRecordHead {
display: flex;
justify-content: space-between;
}
:global {
.ant-radio-button-wrapper:hover {
color: #606266;
}
.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
color: #fff;
background: #6B778C;
border-color: #6B778C;
}
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)::before {
background-color: #6B778C;
}
.ant-table-thead > tr > th {
color: #909399;
}
}
}
}
This diff is collapsed.
.cardWrap {
:global {
.ant-radio-button-wrapper:hover {
color: #606266;
}
.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
color: #fff;
background: #6B778C;
border-color: #6B778C;
}
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)::before {
background-color: #6B778C;
}
}
}
/**
* 带按钮式Radio切换的流转进度
*/
import React, { useEffect, useState } from 'react';
import {
Steps,
Tabs,
Radio
} from 'antd';
import MellowCard from '@/components/MellowCard';
import style from './index.less'
interface TransferProcessProp {
outerVerifyCurrent?: number;
innerVerifyCurrent?: number;
outerVerifySteps?: {
step: number,
stepName: string,
roleName: string,
status?: 'wait' | 'process' | 'finish' | 'error',
}[];
innerVerifySteps?: {
step: number,
stepName: string,
roleName: string,
status?: 'wait' | 'process' | 'finish' | 'error',
}[];
customTitleKey?: string;
customKey?: string;
cardTitle?: string;
};
export enum TransferEnum {
/** 外部流转 */
Outer = 1,
/** 内部流转 */
Interior = 2,
}
const TransferProcess: React.FC<TransferProcessProp> = ({
outerVerifyCurrent = 0,
innerVerifyCurrent = 0,
outerVerifySteps = [],
innerVerifySteps = [],
customTitleKey,
customKey,
cardTitle = ''
}) => {
const [transferRadio, setTransferRadio] = useState<TransferEnum>(TransferEnum.Outer)
useEffect(() => {
let judgeDefault = [outerVerifySteps?.length, innerVerifySteps?.length].filter(Boolean)
if(judgeDefault.length === 1) {
if(outerVerifySteps?.length)
setTransferRadio(TransferEnum.Outer)
else
setTransferRadio(TransferEnum.Interior)
}
}, [])
const handleChangeType = (e) => {
setTransferRadio(e.target.value)
}
return (
<MellowCard
title={cardTitle}
bordered={false}
extra={
<Radio.Group value={transferRadio} buttonStyle="solid" size="small" onChange={handleChangeType}>
{outerVerifySteps?.length ? <Radio.Button value={TransferEnum.Outer}>外部流转</Radio.Button> : null}
{innerVerifySteps?.length ? <Radio.Button value={TransferEnum.Interior}>内部流转</Radio.Button> : null}
</Radio.Group>
}
className={style.cardWrap}
>
{
(outerVerifySteps?.length && transferRadio === TransferEnum.Outer) ?
<Steps style={{ marginTop: 30, overflow: "auto", paddingTop: 5, paddingBottom: 5, }} progressDot current={outerVerifyCurrent}>
{outerVerifySteps.map(item => (
<Steps.Step
key={customKey ? item[customKey] : item.step}
title={customTitleKey ? item[customTitleKey] : item.stepName}
description={item.roleName}
status={item.status}
/>
))}
</Steps>
: null
}
{
(innerVerifySteps?.length && transferRadio === TransferEnum.Interior) ?
<Steps style={{ marginTop: 30, overflow: "auto", paddingTop: 5, paddingBottom: 5, }} progressDot current={innerVerifyCurrent}>
{innerVerifySteps.map(item => (
<Steps.Step
key={customKey ? item[customKey] : item.step}
title={customTitleKey ? item[customTitleKey] : item.stepName}
description={item.roleName}
status={item.status}
/>
))}
</Steps>
: null
}
</MellowCard>
)
};
export default TransferProcess;
.cardWrap {
:global {
.ant-radio-button-wrapper:hover {
color: #606266;
}
.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
color: #fff;
background: #6B778C;
border-color: #6B778C;
}
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)::before {
background-color: #6B778C;
}
}
}
import React, { useContext, useEffect, useState } from 'react'
import { Tabs, Table, Radio } from 'antd'
import { formatTimeString } from '@/utils'
import { BidDetailContext } from '../../_public/bid/context';
import MellowCard from '@/components/MellowCard'
import CustomTag from '../CustomTag';
import { TransferEnum } from '../transferProcess';
import style from './index.less'
import { BidInOpeartTexts, BidOutOpeartTexts } from '@/constants';
/**
* 招标流转记录
*/
export interface BidTransformRecordProps {
cardTitle?: string;
}
const outReocrdCols: any[] = [
{
title: '流转顺序号',
dataIndex: 'no',
align: 'center',
key: 'no',
render: (_, __, index: number) => index + 1
},
{
title: '操作角色',
dataIndex: 'memberRoleName',
align: 'center',
key: 'memberRoleName',
},
{
title: '状态',
dataIndex: 'status',
align: 'center',
key: 'status',
render: text => <CustomTag status={text} type='out'/>
},
{
title: '操作',
dataIndex: 'operation',
align: 'center',
key: 'operation',
render: text => BidOutOpeartTexts[text]
},
{
title: '操作时间',
dataIndex: 'createTime',
align: 'center',
key: 'createTime',
render: time => formatTimeString(time)
},
{
title: '审核意见',
dataIndex: 'checkRemark',
align: 'center',
key: 'checkRemark',
},
]
const insideRecordCols: any[] = [
{
title: '流转记录',
dataIndex: 'no',
align: 'center',
key: 'no',
render: (_, __, index: number) => index + 1
},
{
title: '操作人',
dataIndex: 'memberRoleName',
align: 'center',
key: 'memberRoleName',
},
{
title: '部门',
dataIndex: 'department',
align: 'center',
key: 'department',
},
{
title: '职位',
dataIndex: 'position',
align: 'center',
key: 'position',
},
{
title: '状态',
dataIndex: 'status',
align: 'center',
key: 'status',
render: text => <CustomTag status={text} type='inside'/>
},
{
title: '操作',
dataIndex: 'operation',
align: 'center',
key: 'operation',
render: text => BidInOpeartTexts[text]
},
{
title: '操作时间',
dataIndex: 'createTime',
align: 'center',
key: 'createTime',
render: text => formatTimeString(text)
},
{
title: '审核意见',
dataIndex: 'checkRemark',
align: 'center',
key: 'checkRemark',
},
]
const BidTransformRecord:React.FC<BidTransformRecordProps> = ({cardTitle}) => {
const { data, externalProcurementOrderLogResponses, interiorProcurementOrderLogResponses } = useContext(BidDetailContext)
const [transferRadio, setTransferRadio] = useState<TransferEnum>(TransferEnum.Outer)
useEffect(() => {
let judgeDefault = [externalProcurementOrderLogResponses?.length, interiorProcurementOrderLogResponses?.length].filter(Boolean)
if(judgeDefault.length === 1) {
if(externalProcurementOrderLogResponses?.length)
setTransferRadio(TransferEnum.Outer)
else
setTransferRadio(TransferEnum.Interior)
}
}, [])
const handleChangeType = (e) => {
setTransferRadio(e.target.value)
}
return (
<MellowCard
title={cardTitle}
style={{marginTop: 24}}
bordered={false}
extra={
<Radio.Group value={transferRadio} buttonStyle="solid" size="small" onChange={handleChangeType}>
{externalProcurementOrderLogResponses?.length ? <Radio.Button value={TransferEnum.Outer}>外部流转</Radio.Button> : null}
{interiorProcurementOrderLogResponses?.length ? <Radio.Button value={TransferEnum.Interior}>内部流转</Radio.Button> : null}
</Radio.Group>
}
className={style.cardWrap}
>
{
(externalProcurementOrderLogResponses?.length && transferRadio === TransferEnum.Outer) ?
<Table
columns={outReocrdCols}
dataSource={externalProcurementOrderLogResponses}
pagination={false}
rowKey="id"
/> : null
}
{
(interiorProcurementOrderLogResponses?.length && transferRadio === TransferEnum.Interior) ?
<Table
columns={insideRecordCols}
dataSource={interiorProcurementOrderLogResponses}
pagination={false}
rowKey="id"
/> : null
}
</MellowCard>
)
}
BidTransformRecord.defaultProps = {}
export default BidTransformRecord
import React from 'react'
import {history} from 'umi'
import { formatTimeString } from '@/utils'
import EyePreview from '@/components/EyePreview'
import { PlayCircleOutlined, PoweroffOutlined } from '@ant-design/icons'
import CustomTag from '@/pages/procurement/components/CustomTag'
import CustomBadge from '@/pages/procurement/components/customBadge'
import { CALLFORBID_TYPE, PURCHASE_TYPE } from '@/constants'
// 招投标内部状态
export const insideStatusText = [
"待提交审核",
"审核通过",
"报名审核通过",
"资格预审审核通过",
"待开标",
"待评标",
"待提交审核定标",
"定标审核通过(二级)",
"完成招标",
"已废标",
]
// 招投标外部状态
export const outStatusText = [
"待提交招标",
"待平台审核招标",
"待招标报名",
"待资格预审",
"待开标",
"待评标",
"待定标",
"待中标公示",
"完成招标",
"已废标",
]
// 评标中的环节状态
export const remarkProcessStatus = [
"未报名",
"已评标",
"未评标",
"未报名",
"未报价",
"报名审核未通过",
"资格审核未通过",
]
// 招标表格基本列
export const baseBidListColumns: any[] = [
{
title: '招标编号/项目',
align: 'center',
dataIndex: 'code',
key: 'code',
render: (text, record) => <>
<EyePreview url={`${history.location.pathname}/detail?id=${record.id}`}>
{text}
</EyePreview>
<div>{record['projectName']}</div>
</>
},
{
title: '采购类型',
align: 'center',
dataIndex: 'purchaseType',
key: 'purchaseType',
render: (t) => PURCHASE_TYPE[t]
},
{
title: '招标方式',
align: 'left',
dataIndex: 'inviteTenderType',
key: 'inviteTenderType',
render: (t) => CALLFORBID_TYPE[t]
},
{
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) => <>
<div><PlayCircleOutlined />&nbsp;{formatTimeString(record.createTime)}</div>
<div><PoweroffOutlined />&nbsp;{formatTimeString(record.createTime)}</div>
</>,
width: 200
},
{
title: '外部状态',
align: 'center',
dataIndex: 'outStatus',
key: 'outStatus',
render: text => <CustomTag status={text} type='out' />
},
{
title: '内部状态',
align: 'center',
dataIndex: 'inStatus',
key: 'inStatus',
render: (text) => <CustomBadge status={text} type='inside' />
},
]
// 投标表格基本列
export const baseTenderListColumns: any[] = [
{
title: '投标编号/项目',
align: 'center',
dataIndex: 'orderNo',
key: 'orderNo',
render: (text, record) => <>
<EyePreview url={`${history.location.pathname}/detail?id=${record.id}`}>
{text}
</EyePreview>
<div>{text}</div>
</>
},
{
title: '招标编号/会员',
align: 'center',
dataIndex: 'orderNo',
key: 'orderNo',
render: (text, record) => <>
<EyePreview url={`${history.location.pathname}/detail?id=${record.id}`}>
{text}
</EyePreview>
<div>{text}</div>
</>
},
{
title: '投标开始/截止时间',
align: 'center',
dataIndex: 'createTime',
key: 'createTime',
render: (text, record) => <>
<div><PlayCircleOutlined />{formatTimeString(record.createTime)}</div>
<div><PoweroffOutlined />{formatTimeString(record.createTime)}</div>
</>,
width: 200
},
{
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' />
},
]
import React, { useCallback, useRef } from 'react';
import { Button } from 'antd';
import {history} from 'umi';
import PreLoading from '@/components/PreLoading';
import { usePageStatus } from '@/hooks/usePageStatus'
import { BidDetailContext } from '../../_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';
import ApprovedModal from '@/pages/procurement/components/approvedModal';
import { useHttpRequest } from '@/hooks/useHttpRequest';
import { PublicApi } from '@/services/api';
import OrderDetailWrapper from '@/pages/orderSystem/components/OrderDetailWrapper';
const FirstCheckedBidDetail: React.FC = () => {
const { formContext, id } = useBidDetail({type: 'callForBid'})
const {data} = formContext
const approvedRef = useRef<any>({})
const { action = null } = usePageStatus()
const { run, loading } = useHttpRequest(PublicApi.postPurchaseInviteTenderCheckInviteTender)
const handleClick = useCallback(() => {
approvedRef.current.setVisible(true)
}, [])
// 提交审核表单
const handleSubmit = useCallback(() => {
approvedRef.current.actions.submit().then(async ({values}) => {
const params = {
id: Number(id),
...values
}
const result = await run(params)
if (result.code === 1000) {
approvedRef.current.setVisible(false)
history.goBack()
}
})
}, [])
const anchorTitleList = [
{ title: '流转进度', id: 'transferProcess', componentName: "TransferProcess" },
{ title: '基本信息', id: 'baseicInfo', type: "basicInfo" },
{ title: '招标物料', id: 'bidMaterial', componentName: "BidMaterial" },
{ title: '招标要求', id: 'bidNeed', type: "bidNeed" },
{ title: '报名要求', id: 'registerNeed', type: "registerNeed" },
{ title: '资格预审要求', id: 'checkNeed', type: "checkNeed" },
{ title: '评标要求', id: 'remarkNeed', type: "remarkNeed" },
{ title: '其他要求', id: 'otherNeed', type: "otherNeed" },
{ title: '招标方式', id: 'bidWay', componentName: "BidMethod" },
{ title: '流转记录', id: 'transferRecord', componentName: "BidTransformRecord" },
]
return (
<div>
<BidDetailContext.Provider value={formContext}>
<BidDetailHeader
formContext={formContext}
anchorList={anchorTitleList}
extraRight={
action ? <Button type='primary' onClick={handleClick}>
单据审核
</Button> : null
}
/>
<OrderDetailWrapper>
<PreLoading loading={!formContext.data} active paragraph={{rows: 6}}>
<BidDetailSection formContext={formContext} anchorList={anchorTitleList} type="callForBid" />
</PreLoading>
</OrderDetailWrapper>
{/* 点击审核触发的弹窗集合 */}
<ApprovedModal
currentRef={approvedRef}
onConfirm={handleSubmit}
loading={loading}
title="单据审核"
/>
</BidDetailContext.Provider>
</div>
);
};
export default FirstCheckedBidDetail;
import React from 'react'
import { Card, Button, Space, message } from 'antd'
import { StandardTable } from 'god'
import { PageHeaderWrapper } from '@ant-design/pro-layout'
import { PublicApi } from '@/services/api'
import { useSelfTable } from './model/useSelfTable'
import { tableListSchema } from './schema'
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch'
import { FORM_FILTER_PATH } from '@/formSchema/const'
import Submit from '@/components/NiceForm/components/Submit'
import DateRangePickerUnix from '@/components/NiceForm/components/DateRangePickerUnix'
import { BidInsideWorkState } from '@/constants'
import { useHttpRequest } from '@/hooks/useHttpRequest'
// 待审核 招标
export interface FirstCheckedBidProps {}
const fetchTableData = async (params) => {
const { data } = await PublicApi.postPurchaseInviteTenderGetInviteTenderList({
...params,
outStatus: 1,
inStatusList: [2]
}, { ctlType: "none" })
return data
}
const FirstCheckedBid:React.FC<FirstCheckedBidProps> = (props) => {
const {
columns,
ref,
rowSelection,
rowSelectionCtl
} = useSelfTable()
const { run, loading } = useHttpRequest(PublicApi.postPurchaseInviteTenderCheckInviteTenderBatch)
const handleSubmitBatch = async () => {
if (rowSelectionCtl.selectRow.length === 0) {
message.error('请先选择招标')
return ;
}
const canBitch = !rowSelectionCtl.selectRow.some(v => v.inStatus !== BidInsideWorkState.Not_Tender_Check)
if (canBitch) {
const { code } = await run({idList: rowSelectionCtl.selectedRowKeys})
if (code === 1000) {
ref.current.reload()
rowSelectionCtl.setSelectRow([])
rowSelectionCtl.setSelectedRowKeys([])
}
} else {
message.error('只能批量提交内部状态为待审核招标的招标')
}
}
return <PageHeaderWrapper>
<Card>
<StandardTable
fetchTableData={params => fetchTableData(params)}
rowSelection={rowSelection}
columns={columns}
currentRef={ref}
rowKey={'id'}
formilyLayouts={{
justify: 'space-between'
}}
formilyProps={{
ctx: {
inline: false,
schema: tableListSchema,
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
'code',
FORM_FILTER_PATH,
);
},
components: {
DateRangePickerUnix,
Submit
}
},
layouts: {
order: 2,
span: 24
}
}}
formilyChilds={{
children: <Space>
<Button onClick={handleSubmitBatch} loading={loading}>批量审核通过</Button>
</Space>,
layouts: {
span: 8
}
}}
/>
</Card>
</PageHeaderWrapper>
}
FirstCheckedBid.defaultProps = {}
export default FirstCheckedBid
import React, { useRef } from 'react'
import { Button } from 'antd'
import { history } from 'umi'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
import { BidInsideWorkState } from '@/constants'
import { baseBidListColumns } from '@/pages/procurement/constants'
// 待审核招标 hook
export const useSelfTable = () => {
const ref = useRef<any>({})
const [rowSelection, rowSelectionCtl] = useRowSelectionTable({customKey: 'id'})
const handleSubmit = async (record) => {
if (record.inStatus === BidInsideWorkState.Not_Tender_Check) {
history.push(`/memberCenter/procurementAbility/callForBids/firstCheckedBid/detail?id=${record.id}&action=1`)
}
}
const secondColumns: any[] = baseBidListColumns.concat([
{
title: '操作',
align: 'center',
dataIndex: 'ctl',
key: 'ctl',
render: (text, record) => <Button type='link' onClick={() => handleSubmit(record)}>审核</Button>
}
])
return {
columns: secondColumns,
ref,
rowSelection,
rowSelectionCtl
}
}
import { ISchema } from '@formily/antd';
import { FORM_FILTER_PATH } from '@/formSchema/const';
/**
* 除了订单必填字段, 默认
*/
export const tableListSchema: ISchema = {
type: 'object',
properties: {
code: {
type: 'string',
"x-component": 'SearchFilter',
'x-component-props': {
placeholder: '请输入招标编号',
align: 'flex-end',
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'flex-layout',
'x-component-props': {
inline: true,
colStyle: {
marginLeft: 20
}
},
properties: {
projectName: {
type: 'string',
'x-component-props': {
placeholder: '请输入招标项目',
}
},
"[startTime,endTime]": {
type: 'array',
"x-component": 'DateRangePickerUnix',
'x-component-props': {
placeholder: ['发布开始时间','发布结束时间'],
},
},
submit: {
'x-component': 'Submit',
'x-component-props': {
children: '查询',
},
},
},
},
}
}
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