Commit 20370d9f authored by 卢均锐's avatar 卢均锐

Merge branch 'v2' of http://10.0.0.22:3000/lingxi/lingxi-business-paltform into v2

* 'v2' of http://10.0.0.22:3000/lingxi/lingxi-business-paltform: feat: 采购能力 -> 采购竞价国际化
parents ffe9ddf7 3378e9da
......@@ -14,7 +14,7 @@ export default defineConfig({
// "@formily/antd-components": 'FormilyComponent',
// "@lingxi-design/ui": 'LingxiDesignUI',
// 对antd的组件做一个远程映射
...ExternalsAntd
// ...ExternalsAntd
},
scripts: [
'http://lingxi-frontend-prod.oss-cn-hangzhou.aliyuncs.com/static/js/react.production.min.js',
......@@ -23,7 +23,7 @@ export default defineConfig({
'http://lingxi-frontend-prod.oss-cn-hangzhou.aliyuncs.com/static/js/data-set.js',
'http://lingxi-frontend-prod.oss-cn-hangzhou.aliyuncs.com/static/js/BizCharts.min.js',
// 'http://lingxi-frontend-prod.oss-cn-hangzhou.aliyuncs.com/static/js/LingXiUI.min.js',
'http://lingxi-frontend-prod.oss-cn-hangzhou.aliyuncs.com/static/js/antd.min.js',
// 'http://lingxi-frontend-prod.oss-cn-hangzhou.aliyuncs.com/static/js/antd.min.js',
// 'http://lingxi-frontend-prod.oss-cn-hangzhou.aliyuncs.com/static/js/formily-component.min.js',
// 'http://lingxi-frontend-prod.oss-cn-hangzhou.aliyuncs.com/static/js/lingxi-design-ui.min.js',
],
......
......@@ -2,8 +2,10 @@ const PurchaseLocales = {
// table
'table.purchase.added': '新建',
'table.purchase.more': '更多',
'table.purchase.showMore': '显示更多',
'table.purchase.eidt': '修改',
'table.purchase.submit': '提交',
'table.purchase.confirm': '确认',
'table.purchase.delete': '删除',
'table.purchase.purchasePlanNo': '需求计划编号/摘要',
'table.purchase.purchasePlanNo1': '需求计划编号/摘要',
......@@ -17,6 +19,7 @@ const PurchaseLocales = {
'table.purchase.audit': '审核',
'table.purchase.see': '查看',
'table.purchase.id': '序号',
'table.purchase.bidManage': '竞价管理',
'table.purchase.result': '确认授标结果',
'table.purchase.code': '招标编号/项目',
'table.purchase.memberName': '招标会员',
......@@ -104,17 +107,27 @@ const PurchaseLocales = {
'table.purchase.moduleWarning1': '请先创建采购门户!',
// detail
'detail.purchase.rankHeader': '竞价排名',
'detail.purchase.email': '电子邮箱',
'detail.purchase.unitAddress': '单位地址',
'detail.purchase.startSignUp': '报名要求时间',
'detail.purchase.demandUrls': '报名要求附件',
'detail.purchase.biddingStartTime': '竞价时间',
'detail.purchase.startingPrice': '起拍价',
'detail.purchase.isStartingPrice': '是否有起拍价',
'detail.purchase.isStartingPrice1': '是否有目标价',
'detail.purchase.targetPrice': '目标价',
'detail.purchase.minPrice': '最小价差',
'detail.purchase.minPrice1': '最低价',
'detail.purchase.nowMinPrice1': '当前最低价',
'detail.purchase.isMinPrice': '是否有最小价差',
'detail.purchase.allowPurchaseCount': '允许报价次数',
'detail.purchase.allowPurchaseCount1': '报价次数',
'detail.purchase.offerRank': '报价排名',
'detail.purchase.isOpenPurchase': '公开当前最低报价',
'detail.purchase.isOpenPurchase1': '是否公开当前最低报价',
'detail.purchase.isOpenRanking': '公开报价排名',
'detail.purchase.isOpenRanking1': '是否公开报价排名',
'detail.purchase.externalLogStates': '外部流转',
'detail.purchase.interiorLogStates': '内部流转',
'detail.purchase.examineInteriorLogStates': '竞价结果内部流转',
......@@ -142,8 +155,10 @@ const PurchaseLocales = {
'detail.purchase.summary': '采购计划摘要',
'detail.purchase.innerStatus': '内部状态',
'detail.purchase.startTime': '采购计划开始',
'detail.purchase.startTime1': '开始时间',
'detail.purchase.purchaseStartTime': '计划开始时间',
'detail.purchase.endTime': '采购计划截止',
'detail.purchase.endTime1': '结束时间',
'detail.purchase.purchaseEndTime': '计划结束时间',
'detail.purchase.operate': '编制部门',
'detail.purchase.department': '编制人',
......@@ -164,6 +179,7 @@ const PurchaseLocales = {
'detail.purchase.unitName': '单位',
'detail.purchase.unitNameId': '单位ID',
'detail.purchase.isTax': '含税',
'detail.purchase.isTax1': '含税/税率',
'detail.purchase.taxProbability': '税率',
'detail.purchase.taxUnitPrice': '单价(含税)',
'detail.purchase.taxPrice': '金额(含税)',
......@@ -242,6 +258,21 @@ const PurchaseLocales = {
'detail.purchase.entryMall': '进入店铺',
'detail.purchase.jointType': '对接方式',
'detail.purchase.seeBidStep': '查看竞价过程',
'detail.purchase.cancelOffer': '取消报价',
'detail.purchase.statusBoxStatus': '当前状态',
'detail.purchase.stillRunStart': '竞价中',
'detail.purchase.stillRunend': '竞价结束',
'detail.purchase.distanceStillRunend': '距离竞价结束还剩',
'detail.purchase.hour': '小时',
'detail.purchase.minute': '分钟',
'detail.purchase.second': '秒',
'detail.purchase.offerRule': '报价规则',
'detail.purchase.offerRule1': '项目总价(含税)',
'detail.purchase.offerRule2': '公开最低报价',
'detail.purchase.offerRule3': '我要报价',
'detail.purchase.offerRule4': '按项目总价排名',
'detail.purchase.offerRule5': '按项目总价排名',
'detail.purchase.null': '无',
'detail.purchase.modalTitle': '公开招标',
'detail.purchase.modalTitle1': '选择货品',
......@@ -257,6 +288,7 @@ const PurchaseLocales = {
'detail.purchase.modalTitle11': '确认竞价结果',
'detail.purchase.modalTitle12': '提交竞价结果',
'detail.purchase.modalTitle13': '报价明细',
'detail.purchase.modalTitle14': '竞价详情',
'detail.purchase.message1': '投标开始时间必须大于报名截止时间',
'detail.purchase.message2': '投标开始时间必须大于资质预审截止时间',
......@@ -300,6 +332,20 @@ const PurchaseLocales = {
'detail.purchase.message40': '请选择对接方式',
'detail.purchase.message41': '请选择会员',
'detail.purchase.message42': '请勾选要汇总生成订单',
'detail.purchase.message43': '请输入竞价单摘要',
'detail.purchase.message44': '请添加适用地市',
'detail.purchase.message45': '请选择报名要求时间',
'detail.purchase.message46': '报名结束需要早于竞价开始时间',
'detail.purchase.message47': '请选择竞价时间',
'detail.purchase.message48': '竞价开始时间需要晚于报名截止时间',
'detail.purchase.message49': '起拍价不可为0',
'detail.purchase.message50': '目标价不可为0',
'detail.purchase.message51': '最小价差不可为0',
'detail.purchase.message52': '允许报价次数最小价差',
'detail.purchase.message53': '允许报价次数不可为0',
'detail.purchase.message54': '请选择交付日期',
'detail.purchase.message55': '请选择交付地址',
'detail.purchase.message56': '请输入金额',
'detail.purchase.placeholder': '选择开始日期',
'detail.purchase.placeholder1': '确定要执行这个操作?',
......@@ -307,6 +353,13 @@ const PurchaseLocales = {
'detail.purchase.placeholder3': '最长12个字符,6个汉字',
'detail.purchase.placeholder4': '最长60个字符,30个汉字',
'detail.purchase.placeholder5': '最长100字符,50个汉字',
'detail.purchase.placeholder6': '请选择市',
'detail.purchase.placeholder7': '请选择省',
'detail.purchase.placeholder8': '最长200个字符,100个汉字',
'detail.purchase.placeholder9': '请输入起拍价',
'detail.purchase.placeholder10': '请输入目标价',
'detail.purchase.placeholder11': '请输入最小价差',
'detail.purchase.placeholder12': '请输入报价次数',
'detail.purchase.priceMethod': '比价方式',
'detail.purchase.purchaseType1': '有固定采购金额',
......@@ -331,6 +384,9 @@ const PurchaseLocales = {
'detail.purchase.tips14': '选择公开报价排名,竞价过程中将供应商当前报价排名在竞价页面即时公开。',
'detail.purchase.isMix1': '公开当前最低',
'detail.purchase.isMix2': '报价',
'detail.purchase.tips15': '当前报价金额不满足最小价差要求,请修改后再报价!',
'detail.purchase.tips16': '当前报价次数已超过允许报价次数!',
}
export default PurchaseLocales
import React, { useState, useRef, useEffect } from 'react';
import { history } from 'umi';
import { getIntl, history } from 'umi';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { SaveOutlined } from '@ant-design/icons';
import { Tabs, Card, Button, Badge } from 'antd';
......@@ -17,6 +17,7 @@ import BidRequirement from './components/bidRequirement';
import Condition from './components/condition';
import File from './components/file';
const intl = getIntl();
const { TabPane } = Tabs;
......@@ -198,15 +199,15 @@ const AddForm = () => {
return (
<PageHeaderWrapper
onBack={() => history.goBack()}
backIcon={<ReutrnEle description="返回" />}
backIcon={<ReutrnEle description={intl.formatMessage({ id: 'detail.purchase.back' })} />}
extra={
<Button loading={loading} type="primary" onClick={handleSubmit}><SaveOutlined /> 保存</Button>
<Button loading={loading} type="primary" onClick={handleSubmit}><SaveOutlined /> {intl.formatMessage({ id: 'detail.purchase.save' })}</Button>
}
>
<Card>
<Tabs type='card'>
{/* 基本信息 */}
<TabPane key='1' tab={<TabFormErrors dot={badge[0]}>基本信息</TabFormErrors>} forceRender>
<TabPane key='1' tab={<TabFormErrors dot={badge[0]}>{intl.formatMessage({ id: 'detail.purchase.basicLayout' })}</TabFormErrors>} forceRender>
<Basic
currentRef={currentBasic}
fetchdata={basic}
......@@ -214,7 +215,7 @@ const AddForm = () => {
/>
</TabPane>
{/* 添加采购物料 */}
<TabPane key='2' tab={<TabFormErrors dot={badge[1]}>采购物料</TabFormErrors>} forceRender>
<TabPane key='2' tab={<TabFormErrors dot={badge[1]}>{intl.formatMessage({ id: 'detail.purchase.materialLayout' })}</TabFormErrors>} forceRender>
<Material
currentRef={currentMaterial}
fetchdata={material}
......@@ -222,7 +223,7 @@ const AddForm = () => {
/>
</TabPane>
{/* 竞价规则 */}
<TabPane key='3' tab={<TabFormErrors dot={badge[2]}>竞价规则</TabFormErrors>} forceRender>
<TabPane key='3' tab={<TabFormErrors dot={badge[2]}>{intl.formatMessage({ id: 'detail.purchase.bidRulesLayout' })}</TabFormErrors>} forceRender>
<BidRules
currentRef={currentRules}
fetchdata={rules}
......@@ -231,7 +232,7 @@ const AddForm = () => {
/>
</TabPane>
{/* 报名要求 */}
<TabPane key='4' tab={<TabFormErrors dot={badge[3]}>报名要求</TabFormErrors>} forceRender>
<TabPane key='4' tab={<TabFormErrors dot={badge[3]}>{intl.formatMessage({ id: 'detail.purchase.signUpLayout' })}</TabFormErrors>} forceRender>
<BidRequirement
currentRef={currentRequirement}
fetchdata={requirement}
......@@ -240,7 +241,7 @@ const AddForm = () => {
/>
</TabPane>
{/* 交易条件 */}
<TabPane key='5' tab={<TabFormErrors dot={badge[4]}>交易条件</TabFormErrors>} forceRender>
<TabPane key='5' tab={<TabFormErrors dot={badge[4]}>{intl.formatMessage({ id: 'detail.purchase.conditionLayout' })}</TabFormErrors>} forceRender>
<Condition
currentRef={currentCondition}
fetchdata={condition}
......@@ -248,7 +249,7 @@ const AddForm = () => {
/>
</TabPane>
{/* 需求对接 */}
<TabPane key='6' tab={<TabFormErrors dot={badge[5]}>需求对接</TabFormErrors>} forceRender>
<TabPane key='6' tab={<TabFormErrors dot={badge[5]}>{intl.formatMessage({ id: 'detail.purchase.demandLayout' })}</TabFormErrors>} forceRender>
<Demand
currentRef={currentDemand}
fetchdata={demand}
......@@ -256,7 +257,7 @@ const AddForm = () => {
badgeIndex={5}
/>
</TabPane>
<TabPane key='7' tab='附件' forceRender>
<TabPane key='7' tab={intl.formatMessage({ id: 'detail.purchase.file' })} forceRender>
<File
fetchdata={file}
currentRef={currentFile}
......
......@@ -133,7 +133,7 @@ const BasicInfo: React.FC<Iprops> = (props: any) => {
if (requisitionFormAddress[idx].provinceCode && requisitionFormAddress[idx].cityCode) {
setrequisitionFormAddress([...requisitionFormAddress, address])
} else {
message.error('请完善适用城市信息')
message.error(intl.formatMessage({ id: 'detail.purchase.message35' }))
}
}
......@@ -217,23 +217,23 @@ const BasicInfo: React.FC<Iprops> = (props: any) => {
className={style.form}
>
<Form.Item
label='竞价单摘要'
label={intl.formatMessage({ id: 'detail.purchase.biddingDetails' })}
name='details'
rules={[
{ required: true, message: '请输入竞价单摘要' },
{ required: true, message: intl.formatMessage({ id: 'detail.purchase.message43' }) },
{
validator: (r, v) => validatorByte(v, 60)
}
]}
>
<Input maxLength={60} placeholder='最长60个字符,30个汉字' />
<Input maxLength={60} placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder4' })} />
</Form.Item>
<Form.Item
rules={[
{ required: true, message: '请添加适用地市' },
{ required: true, message: intl.formatMessage({ id: 'detail.purchase.message44' }) },
]}
required
label={<Tooltip placement="right" title='设置了归属地市后,此商品可根据地市进行筛选,未设置时默认为所有地市'>适用地市<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
label={<Tooltip placement="right" title={intl.formatMessage({ id: 'detail.purchase.tips4' })}>{intl.formatMessage({ id: 'detail.purchase.areas' })}<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
style={{ marginBottom: '0' }}
>
{requisitionFormAddress.map((item: any, idx: number) => {
......@@ -246,7 +246,7 @@ const BasicInfo: React.FC<Iprops> = (props: any) => {
onChange={(value) => {
handProvince(value, idx, 1)
}}
placeholder='请选择省'
placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder7' })}
>
{province.map(items => {
return (
......@@ -265,7 +265,7 @@ const BasicInfo: React.FC<Iprops> = (props: any) => {
onChange={(value) => {
handProvince(value, idx, 2)
}}
placeholder='请选择市'
placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder6' })}
>
{(item.provinceCode && city.length > 0 && city[idx]) && city[idx].citydata.map(items => {
return (
......@@ -294,7 +294,7 @@ const BasicInfo: React.FC<Iprops> = (props: any) => {
})}
</Form.Item>
<Form.Item
label='会员名称'
label={intl.formatMessage({ id: 'detail.purchase.memberName' })}
name='memberName'
>
<Text strong>{(fetchdata && fetchdata.memberName) && fetchdata.memberName}</Text>
......@@ -306,7 +306,7 @@ const BasicInfo: React.FC<Iprops> = (props: any) => {
<Text strong>{(fetchdata && fetchdata.createTime) && formatTimeString(fetchdata.createTime)}</Text>
</Form.Item>
<Form.Item
label='竞价单号'
label={intl.formatMessage({ id: 'detail.purchase.biddingNo' })}
name='purchaseInquiryNo'
>
<Text strong>{(fetchdata && fetchdata.biddingNo) && fetchdata.biddingNo}</Text>
......
......@@ -16,6 +16,9 @@ import { getAuth } from '@/utils/auth'
import { validatorByte } from '../../validator';
import styles from './index.less';
import { getIntl } from 'umi';
const intl = getIntl();
const { TextArea } = Input;
const layout: any = {
......@@ -79,7 +82,7 @@ const BidRequirement: React.FC<Iprops> = (props: any) => {
const beforeDocUpload = (file: any) => {
const isLt20M = file.size / 1024 / 1024 < 20;
if (!isLt20M) {
message.error('上传文件大小不超过 20M!');
message.error(intl.formatMessage({ id: 'detail.purchase.message21' }));
}
return isLt20M;
}
......@@ -117,17 +120,17 @@ const BidRequirement: React.FC<Iprops> = (props: any) => {
className={styles.revise_style}
>
<Form.Item
label='报名要求时间'
label={intl.formatMessage({ id: 'detail.purchase.startSignUp' })}
name='signUpTime'
rules={[
{ required: true, message: '请选择报名要求时间' }, () => ({
{ required: true, message: intl.formatMessage({ id: 'detail.purchase.message45' }) }, () => ({
async validator(_, value) {
let _exVal = await exRef.current.biddingTime();
if (_exVal[0] && moment(value[1]).isAfter(_exVal[0])) {
return Promise.reject(new Error('报名结束需要早于竞价开始时间'));
return Promise.reject(new Error(intl.formatMessage({ id: 'detail.purchase.message46' })));
}
if (!value[0] || !value[1]) {
return Promise.reject(new Error('请选择报名要求时间'));
return Promise.reject(new Error(intl.formatMessage({ id: 'detail.purchase.message45' })));
} else {
return Promise.resolve();
}
......@@ -138,13 +141,13 @@ const BidRequirement: React.FC<Iprops> = (props: any) => {
<DatePicker.RangePicker
showTime
format="YYYY-MM-DD HH:mm:ss"
placeholder={['开始时间', '结束时间']}
placeholder={[intl.formatMessage({ id: 'detail.purchase.startTime1' }), intl.formatMessage({ id: 'detail.purchase.endTime1' })]}
disabledDate={(current) => {
return current && current < moment().startOf('second')
}} />
</Form.Item>
<Form.Item
label="报名要求"
label={intl.formatMessage({ id: 'detail.purchase.signUpLayout' })}
name="demand"
rules={[
// { required: true, message: '请输入报名要求' },
......@@ -153,10 +156,10 @@ const BidRequirement: React.FC<Iprops> = (props: any) => {
}
]}
>
<TextArea rows={3} maxLength={200} placeholder="最长200个字符,100个汉字" />
<TextArea rows={3} maxLength={200} placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder8' })} />
</Form.Item>
<Form.Item
label="报名要求附件"
label={intl.formatMessage({ id: 'detail.purchase.demandUrls' })}
name="demandUrls"
// rules={[{ required: true, message: '请上传报名要求附件' }]}
>
......@@ -182,8 +185,8 @@ const BidRequirement: React.FC<Iprops> = (props: any) => {
onChange={handleChange}
headers={{ token }}
>
<Button loading={loading} icon={<UploadOutlined />}>上传文件</Button>
<div style={{ marginTop: '8px' }}>一次上传一个文件,每个附件大小不能超过 20M</div>
<Button loading={loading} icon={<UploadOutlined />}>{intl.formatMessage({ id: 'detail.purchase.uploadFile' })}</Button>
<div style={{ marginTop: '8px' }}>{intl.formatMessage({ id: 'detail.purchase.placeholder2' })}</div>
</Upload>
</Form.Item>
</Form>
......
import React, { useState, useEffect } from 'react';
import {
Form,
Input,
Tooltip,
DatePicker,
Checkbox,
Form,
Input,
Tooltip,
DatePicker,
Checkbox,
} from 'antd';
import { QuestionCircleOutlined } from '@ant-design/icons';
import moment from 'moment';
import styles from './index.less';
import { getIntl } from 'umi';
const intl = getIntl();
const layout: any = {
colon: false,
labelCol: { style: { width: '174px' } },
wrapperCol: { span: 9 },
labelAlign: "left"
colon: false,
labelCol: { style: { width: '174px' } },
wrapperCol: { span: 9 },
labelAlign: "left"
}
interface Iprops {
currentRef: any,
fetchdata: any,
onBadge: (num: number, idx: number) => void,
exRef: any
currentRef: any,
fetchdata: any,
onBadge: (num: number, idx: number) => void,
exRef: any
}
const BidRules: React.FC<Iprops> = (props: any) => {
const { currentRef, fetchdata, onBadge, exRef } = props;
const [isStartingPrice, setIsStartingPrice] = useState<boolean>(true)
const [isTargetPrice, setIsTargetPrice] = useState<boolean>(true)
const [isMinPrice, setIsMinPrice] = useState<boolean>(true)
const [isOpenPurchase, setIsOpenPurchase] = useState<boolean>(false)
const [isOpenRanking, setIsOpenRanking] = useState<boolean>(false)
const [startingPrice, setStartingPrice] = useState<any>('');
const [targetPrice, setTargetPrice] = useState<any>('');
const [minPrice, setMinPrice] = useState<any>('');
const [allowPurchaseCount, setAllowPurchaseCount] = useState<any>('');
const [form] = Form.useForm();
useEffect(() => {
currentRef.current = {
get: () => new Promise((resolve: any) => {
form.validateFields().then(res => {
let _formData = { ...res };
resolve({
state: true,
name: 'rules',
data: {
biddingStartTime: moment(_formData.biddingTime[0]).format('x'),
biddingEndTime: moment(_formData.biddingTime[1]).format('x'),
isStartingPrice: Number(isStartingPrice),
isTargetPrice: Number(isTargetPrice),
isMinPrice: Number(isMinPrice),
isOpenPurchase: Number(isOpenPurchase),
isOpenRanking: Number(isOpenRanking),
startingPrice: _formData.startingPrice,
targetPrice: _formData.targetPrice,
allowPurchaseCount: _formData.allowPurchaseCount,
minPrice: _formData.minPrice,
},
})
onBadge(0, 2)
}).catch(error => {
if (error && error.errorFields) {
onBadge(error.errorFields.length, 2)
}
})
}),
biddingTime: () => form.getFieldValue('biddingTime')
}
})
useEffect(() => {
fetchdata.isStartingPrice != undefined && setIsStartingPrice(!!fetchdata.isStartingPrice);
fetchdata.isTargetPrice != undefined && setIsTargetPrice(!!fetchdata.isTargetPrice);
fetchdata.isMinPrice != undefined && setIsMinPrice(!!fetchdata.isMinPrice);
setIsOpenPurchase(!!fetchdata.isOpenPurchase);
setIsOpenRanking(!!fetchdata.isOpenRanking);
setStartingPrice(fetchdata.startingPrice);
setTargetPrice(fetchdata.targetPrice);
setMinPrice(fetchdata.minPrice);
setAllowPurchaseCount(fetchdata.allowPurchaseCount);
form.setFieldsValue({
biddingTime: [fetchdata.biddingStartTime ? moment(fetchdata.biddingStartTime) : '', fetchdata.biddingEndTime ? moment(fetchdata.biddingEndTime) : ''],
isStartingPrice: !!fetchdata.isStartingPrice,
isTargetPrice: !!fetchdata.isTargetPrice,
isMinPrice: !!fetchdata.isMinPrice,
isOpenPurchase: !!fetchdata.isOpenPurchase,
isOpenRanking: !!fetchdata.isOpenRanking,
startingPrice: fetchdata.startingPrice,
targetPrice: fetchdata.targetPrice,
allowPurchaseCount: fetchdata.allowPurchaseCount,
minPrice: fetchdata.minPrice
const { currentRef, fetchdata, onBadge, exRef } = props;
const [isStartingPrice, setIsStartingPrice] = useState<boolean>(true)
const [isTargetPrice, setIsTargetPrice] = useState<boolean>(true)
const [isMinPrice, setIsMinPrice] = useState<boolean>(true)
const [isOpenPurchase, setIsOpenPurchase] = useState<boolean>(false)
const [isOpenRanking, setIsOpenRanking] = useState<boolean>(false)
const [startingPrice, setStartingPrice] = useState<any>('');
const [targetPrice, setTargetPrice] = useState<any>('');
const [minPrice, setMinPrice] = useState<any>('');
const [allowPurchaseCount, setAllowPurchaseCount] = useState<any>('');
const [form] = Form.useForm();
useEffect(() => {
currentRef.current = {
get: () => new Promise((resolve: any) => {
form.validateFields().then(res => {
let _formData = { ...res };
resolve({
state: true,
name: 'rules',
data: {
biddingStartTime: moment(_formData.biddingTime[0]).format('x'),
biddingEndTime: moment(_formData.biddingTime[1]).format('x'),
isStartingPrice: Number(isStartingPrice),
isTargetPrice: Number(isTargetPrice),
isMinPrice: Number(isMinPrice),
isOpenPurchase: Number(isOpenPurchase),
isOpenRanking: Number(isOpenRanking),
startingPrice: _formData.startingPrice,
targetPrice: _formData.targetPrice,
allowPurchaseCount: _formData.allowPurchaseCount,
minPrice: _formData.minPrice,
},
})
onBadge(0, 2)
}).catch(error => {
if (error && error.errorFields) {
onBadge(error.errorFields.length, 2)
}
})
}, [fetchdata])
}),
biddingTime: () => form.getFieldValue('biddingTime')
}
})
useEffect(() => {
fetchdata.isStartingPrice != undefined && setIsStartingPrice(!!fetchdata.isStartingPrice);
fetchdata.isTargetPrice != undefined && setIsTargetPrice(!!fetchdata.isTargetPrice);
fetchdata.isMinPrice != undefined && setIsMinPrice(!!fetchdata.isMinPrice);
setIsOpenPurchase(!!fetchdata.isOpenPurchase);
setIsOpenRanking(!!fetchdata.isOpenRanking);
setStartingPrice(fetchdata.startingPrice);
setTargetPrice(fetchdata.targetPrice);
setMinPrice(fetchdata.minPrice);
setAllowPurchaseCount(fetchdata.allowPurchaseCount);
form.setFieldsValue({
biddingTime: [fetchdata.biddingStartTime ? moment(fetchdata.biddingStartTime) : '', fetchdata.biddingEndTime ? moment(fetchdata.biddingEndTime) : ''],
isStartingPrice: !!fetchdata.isStartingPrice,
isTargetPrice: !!fetchdata.isTargetPrice,
isMinPrice: !!fetchdata.isMinPrice,
isOpenPurchase: !!fetchdata.isOpenPurchase,
isOpenRanking: !!fetchdata.isOpenRanking,
startingPrice: fetchdata.startingPrice,
targetPrice: fetchdata.targetPrice,
allowPurchaseCount: fetchdata.allowPurchaseCount,
minPrice: fetchdata.minPrice
})
}, [fetchdata])
const onCheckboxChange = (e: { target: { checked: boolean } }, func: Function, name?: string) => {
func(e.target.checked);
if (!e.target.checked && name) {
form.setFieldsValue({ [`${name}`]: '' })
}
};
const onCheckboxChange = (e: { target: { checked: boolean } }, func: Function, name?: string) => {
func(e.target.checked);
if (!e.target.checked && name) {
form.setFieldsValue({ [`${name}`]: '' })
}
};
return (
<>
<Form
{...layout}
form={form}
className={styles.form}
>
<Form.Item
label='竞价时间'
name='biddingTime'
rules={[
{ required: true, message: '请选择竞价时间' }, () => ({
async validator(_, value) {
let _exVal = await exRef.current.signUpTime();
if (_exVal[1] && moment(value[0]).isBefore(_exVal[1])) {
return Promise.reject(new Error('竞价开始时间需要晚于报名截止时间'));
}
if (!value[0] || !value[1]) {
return Promise.reject(new Error('请选择竞价时间'));
} else {
return Promise.resolve();
}
},
})
]}
>
<DatePicker.RangePicker
showTime
format="YYYY-MM-DD HH:mm:ss"
placeholder={['开始时间', '结束时间']}
disabledDate={(current) => {
return current && current < moment().startOf('second')
}}
/>
</Form.Item>
<Form.Item
name='isStartingPrice'
label={<Tooltip placement="right" title='初始起拍价,首次报价要低于或等于起拍价'>起拍价<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
>
<Checkbox checked={isStartingPrice} onChange={(e) => { onCheckboxChange(e, setIsStartingPrice, 'startingPrice') }}>是否有起拍价</Checkbox>
</Form.Item>
{isStartingPrice && (<Form.Item
label=" "
name='startingPrice'
className={styles.hidden}
rules={[{
required: isStartingPrice ? true : false,
message: '请输入起拍价',
type: 'number',
whitespace: true,
transform(value) {
if (value) {
return parseFloat(value)
}
},
}, () => ({
validator(_, value) {
if (Number(value) <= 0) {
return Promise.reject(new Error('起拍价不可为0'));
} else {
return Promise.resolve();
}
},
})
]}
>
<Input
addonBefore={'¥'}
value={startingPrice}
placeholder='请输入起拍价'
onChange={(e) => {
let _val = e.target.value.replace(/^\D*(\d*(?:\.\d{0,2})?).*$/g, '$1');
setStartingPrice(_val);
form.setFieldsValue({ startingPrice: _val });
}} />
</Form.Item>)}
<Form.Item
label={<Tooltip placement="right" title='期望成交价格'>目标价<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
name='isTargetPrice'
>
<Checkbox checked={isTargetPrice} onChange={(e) => { onCheckboxChange(e, setIsTargetPrice, 'targetPrice') }}>是否有目标价</Checkbox>
</Form.Item>
{isTargetPrice && (<Form.Item
label=" "
name='targetPrice'
className={styles.hidden}
rules={[{
required: isTargetPrice ? true : false,
message: '请输入目标价',
type: 'number',
whitespace: true,
transform(value) {
if (value) {
return parseFloat(value)
}
},
}, () => ({
validator(_, value) {
if (Number(value) <= 0) {
return Promise.reject(new Error('目标价不可为0'));
} else {
return Promise.resolve();
}
},
})
]}
>
<Input
addonBefore={'¥'}
value={targetPrice}
placeholder='请输入目标价'
onChange={(e) => {
let _val = e.target.value.replace(/^\D*(\d*(?:\.\d{0,2})?).*$/g, '$1');
setTargetPrice(_val);
form.setFieldsValue({ targetPrice: _val });
}} />
</Form.Item>)}
<Form.Item
label={<Tooltip placement="right" title='每次报价降价幅度须大于或等于最小价差'>最小价差<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
name='isMinPrice'
>
<Checkbox checked={isMinPrice} onChange={(e) => { onCheckboxChange(e, setIsMinPrice, 'minPrice') }}>是否有最小价差</Checkbox>
</Form.Item>
{isMinPrice && (<Form.Item
name='minPrice'
label=" "
className={styles.hidden}
rules={[{
required: isMinPrice ? true : false,
message: '请输入最小价差',
type: 'number',
whitespace: true,
transform(value) {
if (value) {
return parseFloat(value)
}
},
}, () => ({
validator(_, value) {
if (Number(value) <= 0) {
return Promise.reject(new Error('最小价差不可为0'));
} else {
return Promise.resolve();
}
},
})
]}
>
<Input
addonBefore={'¥'}
value={minPrice}
placeholder='请输入最小价差'
onChange={(e) => {
let _val = e.target.value.replace(/^\D*(\d*(?:\.\d{0,2})?).*$/g, '$1');
setMinPrice(_val);
form.setFieldsValue({ minPrice: _val });
}}/>
</Form.Item>)}
<Form.Item
label={<Tooltip placement="right" title='允许每个供应商最多可以报价的次数'>允许报价次数<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
name='allowPurchaseCount'
rules={[{
required: true,
message: '允许报价次数最小价差',
type: 'number',
whitespace: true,
pattern: new RegExp(/^[1-9]\d*$/, "g"),
transform(value) {
if (value) {
return parseInt(value);
}
},
}, () => ({
validator(_, value) {
if (Number(value) <= 0) {
return Promise.reject(new Error('允许报价次数不可为0'));
} else {
return Promise.resolve();
}
},
})
]}
>
<Input
value={allowPurchaseCount}
placeholder='请输入报价次数'
onChange={(e) => {
let _val = e.target.value.replace(/[^\d]/g, '').replace(/^0{1,}/g, '');
setAllowPurchaseCount(_val);
form.setFieldsValue({ allowPurchaseCount: _val });
}} />
</Form.Item>
<Form.Item
label={<Tooltip placement="right" title='选择公开当前最低报价,竞价过程中将供应商所报当前最低价在竞价页面即时公开。'>公开当前最低报价<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
name='isOpenPurchase'
>
<Checkbox checked={isOpenPurchase} onChange={(e) => { onCheckboxChange(e, setIsOpenPurchase) }}>是否公开当前最低报价</Checkbox>
</Form.Item>
<Form.Item
label={<Tooltip placement="right" title='选择公开报价排名,竞价过程中将供应商当前报价排名在竞价页面即时公开。'>公开报价排名<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
name='isOpenRanking'
>
<Checkbox checked={isOpenRanking} onChange={(e) => { onCheckboxChange(e, setIsOpenRanking) }}>是否公开报价排名</Checkbox>
</Form.Item>
</Form>
</>
)
return (
<>
<Form
{...layout}
form={form}
className={styles.form}
>
<Form.Item
label={intl.formatMessage({ id: 'detail.purchase.biddingStartTime' })}
name='biddingTime'
rules={[
{ required: true, message: intl.formatMessage({ id: 'detail.purchase.message47' }) }, () => ({
async validator(_, value) {
let _exVal = await exRef.current.signUpTime();
if (_exVal[1] && moment(value[0]).isBefore(_exVal[1])) {
return Promise.reject(new Error(intl.formatMessage({ id: 'detail.purchase.message48' })));
}
if (!value[0] || !value[1]) {
return Promise.reject(new Error(intl.formatMessage({ id: 'detail.purchase.message47' })));
} else {
return Promise.resolve();
}
},
})
]}
>
<DatePicker.RangePicker
showTime
format="YYYY-MM-DD HH:mm:ss"
placeholder={[intl.formatMessage({ id: 'detail.purchase.startTime1' }), intl.formatMessage({ id: 'detail.purchase.endTime1' })]}
disabledDate={(current) => {
return current && current < moment().startOf('second')
}}
/>
</Form.Item>
<Form.Item
name='isStartingPrice'
label={<Tooltip placement="right" title={intl.formatMessage({ id: 'ddetail.purchase.tips9' })}>{intl.formatMessage({ id: 'detail.purchase.startingPrice' })}<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
>
<Checkbox checked={isStartingPrice} onChange={(e) => { onCheckboxChange(e, setIsStartingPrice, 'startingPrice') }}>{intl.formatMessage({ id: 'detail.purchase.isStartingPrice' })}</Checkbox>
</Form.Item>
{isStartingPrice && (<Form.Item
label=" "
name='startingPrice'
className={styles.hidden}
rules={[{
required: isStartingPrice ? true : false,
message: intl.formatMessage({ id: 'detail.purchase.placeholder9' }),
type: 'number',
whitespace: true,
transform(value) {
if (value) {
return parseFloat(value)
}
},
}, () => ({
validator(_, value) {
if (Number(value) <= 0) {
return Promise.reject(new Error(intl.formatMessage({ id: 'detail.purchase.message49' })));
} else {
return Promise.resolve();
}
},
})
]}
>
<Input
addonBefore={'¥'}
value={startingPrice}
placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder9' })}
onChange={(e) => {
let _val = e.target.value.replace(/^\D*(\d*(?:\.\d{0,2})?).*$/g, '$1');
setStartingPrice(_val);
form.setFieldsValue({ startingPrice: _val });
}} />
</Form.Item>)}
<Form.Item
label={<Tooltip placement="right" title={intl.formatMessage({ id: 'detail.purchase.tips10' })}>{intl.formatMessage({ id: 'detail.purchase.targetPrice' })}<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
name='isTargetPrice'
>
<Checkbox checked={isTargetPrice} onChange={(e) => { onCheckboxChange(e, setIsTargetPrice, 'targetPrice') }}>{intl.formatMessage({ id: 'detail.purchase.isStartingPrice1' })}</Checkbox>
</Form.Item>
{isTargetPrice && (<Form.Item
label=" "
name='targetPrice'
className={styles.hidden}
rules={[{
required: isTargetPrice ? true : false,
message: intl.formatMessage({ id: 'detail.purchase.placeholder10' }),
type: 'number',
whitespace: true,
transform(value) {
if (value) {
return parseFloat(value)
}
},
}, () => ({
validator(_, value) {
if (Number(value) <= 0) {
return Promise.reject(new Error(intl.formatMessage({ id: 'detail.purchase.message50' })));
} else {
return Promise.resolve();
}
},
})
]}
>
<Input
addonBefore={'¥'}
value={targetPrice}
placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder10' })}
onChange={(e) => {
let _val = e.target.value.replace(/^\D*(\d*(?:\.\d{0,2})?).*$/g, '$1');
setTargetPrice(_val);
form.setFieldsValue({ targetPrice: _val });
}} />
</Form.Item>)}
<Form.Item
label={<Tooltip placement="right" title={intl.formatMessage({ id: 'detail.purchase.tips11' })}>{intl.formatMessage({ id: 'detail.purchase.minPrice' })}<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
name='isMinPrice'
>
<Checkbox checked={isMinPrice} onChange={(e) => { onCheckboxChange(e, setIsMinPrice, 'minPrice') }}>{intl.formatMessage({ id: 'detail.purchase.isMinPrice' })}</Checkbox>
</Form.Item>
{isMinPrice && (<Form.Item
name='minPrice'
label=" "
className={styles.hidden}
rules={[{
required: isMinPrice ? true : false,
message: intl.formatMessage({ id: 'detail.purchase.placeholder11' }),
type: 'number',
whitespace: true,
transform(value) {
if (value) {
return parseFloat(value)
}
},
}, () => ({
validator(_, value) {
if (Number(value) <= 0) {
return Promise.reject(new Error(intl.formatMessage({ id: 'detail.purchase.message51' })));
} else {
return Promise.resolve();
}
},
})
]}
>
<Input
addonBefore={'¥'}
value={minPrice}
placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder11' })}
onChange={(e) => {
let _val = e.target.value.replace(/^\D*(\d*(?:\.\d{0,2})?).*$/g, '$1');
setMinPrice(_val);
form.setFieldsValue({ minPrice: _val });
}} />
</Form.Item>)}
<Form.Item
label={<Tooltip placement="right" title={intl.formatMessage({ id: 'detail.purchase.tips12' })}>{intl.formatMessage({ id: 'detail.purchase.allowPurchaseCount' })}<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
name='allowPurchaseCount'
rules={[{
required: true,
message: intl.formatMessage({ id: 'detail.purchase.message52' }),
type: 'number',
whitespace: true,
pattern: new RegExp(/^[1-9]\d*$/, "g"),
transform(value) {
if (value) {
return parseInt(value);
}
},
}, () => ({
validator(_, value) {
if (Number(value) <= 0) {
return Promise.reject(new Error(intl.formatMessage({ id: 'detail.purchase.message53' })));
} else {
return Promise.resolve();
}
},
})
]}
>
<Input
value={allowPurchaseCount}
placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder12' })}
onChange={(e) => {
let _val = e.target.value.replace(/[^\d]/g, '').replace(/^0{1,}/g, '');
setAllowPurchaseCount(_val);
form.setFieldsValue({ allowPurchaseCount: _val });
}} />
</Form.Item>
<Form.Item
label={<Tooltip placement="right" title={intl.formatMessage({ id: 'detail.purchase.tips13' })}>{intl.formatMessage({ id: 'detail.purchase.isOpenPurchase' })}<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
name='isOpenPurchase'
>
<Checkbox checked={isOpenPurchase} onChange={(e) => { onCheckboxChange(e, setIsOpenPurchase) }}>{intl.formatMessage({ id: 'detail.purchase.isOpenPurchase1' })}</Checkbox>
</Form.Item>
<Form.Item
label={<Tooltip placement="right" title={intl.formatMessage({ id: 'detail.purchase.tips14' })}>{intl.formatMessage({ id: 'detail.purchase.isOpenRanking' })}<QuestionCircleOutlined style={{ marginLeft: '5px' }} /></Tooltip>}
name='isOpenRanking'
>
<Checkbox checked={isOpenRanking} onChange={(e) => { onCheckboxChange(e, setIsOpenRanking) }}>{intl.formatMessage({ id: 'detail.purchase.isOpenRanking1' })}</Checkbox>
</Form.Item>
</Form>
</>
)
}
export default BidRules
......@@ -7,6 +7,7 @@ import { getLogisticsSelectListReceiverAddress } from '@/services/LogisticsV2Api
import { validatorByte } from '../../validator';
import style from './index.less';
import { getIntl } from 'umi';
const { TextArea } = Input;
const { Option } = Select;
......@@ -23,6 +24,8 @@ interface Iprops {
onBadge: (num: number, idx: number) => void
}
const intl = getIntl();
export type ADDRESS_TYPE = {
address: string,
addressId: number,
......@@ -117,9 +120,9 @@ const Condition: React.FC<Iprops> = (props: any) => {
className={style.form}
>
<Form.Item
label="交付日期"
label={intl.formatMessage({ id: 'table.purchase.deliveryTime' })}
name="deliver"
rules={[{ required: true, message: '请选择交付日期' }]}
rules={[{ required: true, message: intl.formatMessage({ id: 'detail.purchase.message54' }) }]}
>
<DatePicker style={{ width: '100%' }}
disabledDate={(current) => {
......@@ -128,13 +131,13 @@ const Condition: React.FC<Iprops> = (props: any) => {
/>
</Form.Item>
<Form.Item
label="交付地址"
label={intl.formatMessage({ id: 'detail.purchase.address' })}
name='addressId'
rules={[{ required: true, message: '请选择交付地址' }]}
rules={[{ required: true, message: intl.formatMessage({ id: 'detail.purchase.message55' }) }]}
>
<Select
onSelect={handleSelectAddress}
placeholder='请选择交付地址'
placeholder={intl.formatMessage({ id: 'detail.purchase.message55' })}
>
{address.map(v => (
<Option key={v.id} value={v.id}>{v.fullAddress}</Option>
......@@ -142,7 +145,7 @@ const Condition: React.FC<Iprops> = (props: any) => {
</Select>
</Form.Item>
<Form.Item
label="报价要求"
label={intl.formatMessage({ id: 'detail.purchase.offerAsk' })}
name="offer"
rules={[
// { required: true, message: '请输入报价要求' },
......@@ -151,10 +154,10 @@ const Condition: React.FC<Iprops> = (props: any) => {
}
]}
>
<TextArea rows={3} maxLength={100} placeholder="最长100个字符,50个汉字" />
<TextArea rows={3} maxLength={100} placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder5' })} />
</Form.Item>
<Form.Item
label="付款方式"
label={intl.formatMessage({ id: 'detail.purchase.paymentType' })}
name="paymentType"
rules={[
// { required: true, message: '请输入付款方式' },
......@@ -163,10 +166,10 @@ const Condition: React.FC<Iprops> = (props: any) => {
}
]}
>
<TextArea rows={3} maxLength={100} placeholder="最长100个字符,50个汉字" />
<TextArea rows={3} maxLength={100} placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder5' })} />
</Form.Item>
<Form.Item
label="税费要求"
label={intl.formatMessage({ id: 'detail.purchase.taxesAsk' })}
name="taxes"
rules={[
// { required: true, message: '请输入税费要求' },
......@@ -175,10 +178,10 @@ const Condition: React.FC<Iprops> = (props: any) => {
}
]}
>
<TextArea rows={3} maxLength={100} placeholder="最长100个字符,50个汉字" />
<TextArea rows={3} maxLength={100} placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder5' })} />
</Form.Item>
<Form.Item
label="物流要求"
label={intl.formatMessage({ id: 'detail.purchase.logisticsAsk' })}
name="logistics"
rules={[
// { required: true, message: '请输入物流要求' },
......@@ -187,10 +190,10 @@ const Condition: React.FC<Iprops> = (props: any) => {
}
]}
>
<TextArea rows={3} maxLength={100} placeholder="最长100个字符,50个汉字" />
<TextArea rows={3} maxLength={100} placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder5' })} />
</Form.Item>
<Form.Item
label="包装要求"
label={intl.formatMessage({ id: 'detail.purchase.packRequireAsk' })}
name="packRequire"
rules={[
// { required: true, message: '请输入包装要求' },
......@@ -199,10 +202,10 @@ const Condition: React.FC<Iprops> = (props: any) => {
}
]}
>
<TextArea rows={3} maxLength={100} placeholder="最长100个字符,50个汉字" />
<TextArea rows={3} maxLength={100} placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder5' })} />
</Form.Item>
<Form.Item
label="其他要求"
label={intl.formatMessage({ id: 'detail.purchase.otherRequireAsk' })}
name="otherRequire"
rules={[
// { required: true, message: '请输入其他要求' },
......@@ -211,7 +214,7 @@ const Condition: React.FC<Iprops> = (props: any) => {
}
]}
>
<TextArea rows={3} maxLength={100} placeholder="最长100个字符,50个汉字" />
<TextArea rows={3} maxLength={100} placeholder={intl.formatMessage({ id: 'detail.purchase.placeholder5' })} />
</Form.Item>
</Form>
</>
......
......@@ -6,6 +6,7 @@ import { UPLOAD_TYPE } from '@/constants'
import { getAuth } from '@/utils/auth'
import styles from './index.less';
import { getIntl } from 'umi';
const layout: any = {
colon: false,
......@@ -14,6 +15,7 @@ const layout: any = {
labelAlign: "left"
};
const intl = getIntl()
export interface IProps {
fetchdata: any,
currentRef: any
......@@ -30,7 +32,7 @@ const File: React.FC<IProps> = (props) => {
const beforeDocUpload = (file: any) => {
const isLt20M = file.size / 1024 / 1024 < 20;
if (!isLt20M) {
message.error('上传文件大小不超过 20M!');
message.error(intl.formatMessage({ id: 'detail.purchase.message21' }));
}
return isLt20M;
}
......@@ -109,8 +111,8 @@ const File: React.FC<IProps> = (props) => {
onChange={handleChange}
headers={{ token }}
>
<Button loading={loading} icon={<UploadOutlined />}>上传文件</Button>
<div style={{ marginTop: '8px' }}>一次上传一个文件,每个附件大小不能超过 20M</div>
<Button loading={loading} icon={<UploadOutlined />}>{intl.formatMessage({ id: 'detail.purchase.uploadFile' })}</Button>
<div style={{ marginTop: '8px' }}>{intl.formatMessage({ id: 'detail.purchase.placeholder2' })}</div>
</Upload>
</Form.Item>
</Form>
......
......@@ -14,71 +14,71 @@ import Table from '../../components/table'
const intl = getIntl();
import {
BID_EXTERNALSTATE_COLOR,
BID_INTERNALSTATE_COLOR
BID_EXTERNALSTATE_COLOR,
BID_INTERNALSTATE_COLOR
} from '../../constants/purchaseBid';
const { Text } = Typography;
const ReadyBid = () => {
const ref = useRef<any>({});
const columns: ColumnType<any>[] = [{
title: '序号',
align: 'center',
dataIndex: 'id',
key: 'id',
render: (t, r, i) => ++i
}, {
title: intl.formatMessage({ id: 'table.purchase.biddingNo' }),
key: 'biddingNo',
dataIndex: 'biddingNo',
render: (text: any, record: any) => (
<Space direction='vertical' style={{width: 300}}>
<EyePreview url={`/memberCenter/procurementAbility/purchaseBid/readyBid/detail?id=${record.id}&number=${text}`}>{text}</EyePreview>
<Text type='secondary'>{record.details}</Text>
</Space>
)
}, {
title: intl.formatMessage({ id: 'table.purchase.biddingStartTime' }),
key: 'biddingStartTime',
dataIndex: 'biddingStartTime',
render: (text: any, record: any) => <>
<div><PlayCircleOutlined />&nbsp;{formatTimeString(record.biddingStartTime)}</div>
<div><PoweroffOutlined />&nbsp;{formatTimeString(record.biddingEndTime)}</div>
</>,
width: 180
}, {
title: intl.formatMessage({ id: 'table.purchase.dementCreateTime' }),
key: 'createTime',
dataIndex: 'createTime',
render: (text: any, record: any) => formatTimeString(text),
width: 180
}, {
title: intl.formatMessage({ id: 'table.purchase.externalStatus' }),
key: 'externalState',
dataIndex: 'externalState',
render: (text: any, record: any) => <StatusTag type={BID_EXTERNALSTATE_COLOR(text)} title={record.externalStateName} />
}, {
title: intl.formatMessage({ id: 'table.purchase.innerStatus' }),
key: 'interiorState',
dataIndex: 'interiorState',
render: (text: any, record: any) => <Badge status={BID_INTERNALSTATE_COLOR(text)} text={record.interiorStateName} />
}, {
title: intl.formatMessage({ id: 'table.purchase.operate' }),
key: 'operate',
dataIndex: 'operate',
align: 'center',
render: (text: any, record: any) => <Button onClick={() => history.push(`/memberCenter/procurementAbility/purchaseBid/readyBid/management?id=${record.id}&number=${record.biddingNo}`)} type='link'>竞价管理</Button>
}];
return (
<Table
reload={ref}
schemaType="PURCHASEBIDOSIGNUP_SCHEMA"
columns={columns}
effects="biddingNo"
fetch={getPurchaseBiddingStayBiddingList}
/>
const ref = useRef<any>({});
const columns: ColumnType<any>[] = [{
title: intl.formatMessage({ id: 'table.purchase.id' }),
align: 'center',
dataIndex: 'id',
key: 'id',
render: (t, r, i) => ++i
}, {
title: intl.formatMessage({ id: 'table.purchase.biddingNo' }),
key: 'biddingNo',
dataIndex: 'biddingNo',
render: (text: any, record: any) => (
<Space direction='vertical' style={{ width: 300 }}>
<EyePreview url={`/memberCenter/procurementAbility/purchaseBid/readyBid/detail?id=${record.id}&number=${text}`}>{text}</EyePreview>
<Text type='secondary'>{record.details}</Text>
</Space>
)
}, {
title: intl.formatMessage({ id: 'table.purchase.biddingStartTime' }),
key: 'biddingStartTime',
dataIndex: 'biddingStartTime',
render: (text: any, record: any) => <>
<div><PlayCircleOutlined />&nbsp;{formatTimeString(record.biddingStartTime)}</div>
<div><PoweroffOutlined />&nbsp;{formatTimeString(record.biddingEndTime)}</div>
</>,
width: 180
}, {
title: intl.formatMessage({ id: 'table.purchase.dementCreateTime' }),
key: 'createTime',
dataIndex: 'createTime',
render: (text: any, record: any) => formatTimeString(text),
width: 180
}, {
title: intl.formatMessage({ id: 'table.purchase.externalStatus' }),
key: 'externalState',
dataIndex: 'externalState',
render: (text: any, record: any) => <StatusTag type={BID_EXTERNALSTATE_COLOR(text)} title={record.externalStateName} />
}, {
title: intl.formatMessage({ id: 'table.purchase.innerStatus' }),
key: 'interiorState',
dataIndex: 'interiorState',
render: (text: any, record: any) => <Badge status={BID_INTERNALSTATE_COLOR(text)} text={record.interiorStateName} />
}, {
title: intl.formatMessage({ id: 'table.purchase.operate' }),
key: 'operate',
dataIndex: 'operate',
align: 'center',
render: (text: any, record: any) => <Button onClick={() => history.push(`/memberCenter/procurementAbility/purchaseBid/readyBid/management?id=${record.id}&number=${record.biddingNo}`)} type='link'>{intl.formatMessage({ id: 'table.purchase.bidManage' })}</Button>
}];
return (
<Table
reload={ref}
schemaType="PURCHASEBIDOSIGNUP_SCHEMA"
columns={columns}
effects="biddingNo"
fetch={getPurchaseBiddingStayBiddingList}
/>
)
}
export default ReadyBid
......@@ -10,59 +10,61 @@ import TriangleTag from '../triangleTag';
import RankRow from '../rankRow';
import styles from './index.less';
import { getIntl } from 'umi';
const { TabPane } = Tabs;
const intl = getIntl();
interface RankItemDetail {
dynamic : any,
queryPriceDynamics : any,
signupMembers : any
dynamic: any,
queryPriceDynamics: any,
signupMembers: any
}
interface RankItemProps {
onTabChange: (key: string) => void,
detail: RankItemDetail
onTabChange: (key: string) => void,
detail: RankItemDetail
}
const RankItem: React.FC<RankItemProps> = (props: any) => {
const { onTabChange, detail } = props;
const { queryPriceDynamics = [], signupMembers = [], dynamic = {} } = detail;
const [showMoreQuery, setShowMoreQuery] = useState<boolean>(false);
const [showMoreSign, setShowMoreSign] = useState<boolean>(false);
const { onTabChange, detail } = props;
const { queryPriceDynamics = [], signupMembers = [], dynamic = {} } = detail;
const [showMoreQuery, setShowMoreQuery] = useState<boolean>(false);
const [showMoreSign, setShowMoreSign] = useState<boolean>(false);
const queryPriceDynamicsData = showMoreQuery ? [...queryPriceDynamics].splice(0, 10) : queryPriceDynamics;
const signupMembersData = showMoreSign ? [...signupMembers].splice(0, 10) : signupMembers;
const queryPriceDynamicsData = showMoreQuery ? [...queryPriceDynamics].splice(0, 10) : queryPriceDynamics;
const signupMembersData = showMoreSign ? [...signupMembers].splice(0, 10) : signupMembers;
return (
<div className={styles.rank}>
<div className={styles.rankHeader}>
<h5>竞价排名</h5>
<div className={styles.rankHeaderBox}>
<img src={level1} alt={`排名1`} />
<h4>
<div style={{ display: 'inline-block', position: 'relative', left: '-3%', top: '-5%' }}>
{dynamic?.memberName && <TriangleTag text='最低价' wrapStyle={{ backgroundColor: '#EA8000' }} bgcolor='#EA8000' direction='right' />}
</div>
{dynamic?.memberName}
</h4>
<div className={styles.rankHeaderBoxInfo}>
<div className={styles.rankHeaderBoxInfoChild}>当前最低价:<span>{dynamic?.minPrice ? `¥ ${priceFormat(dynamic?.minPrice)}` : '-'}</span></div>
<div className={styles.rankHeaderBoxInfoChild}>报价次数:<span>{dynamic?.count ?? '-'}</span></div>
</div>
</div>
return (
<div className={styles.rank}>
<div className={styles.rankHeader}>
<h5>{intl.formatMessage({ id: 'detail.purchase.rankHeader' })}</h5>
<div className={styles.rankHeaderBox}>
<img src={level1} alt={`排名1`} />
<h4>
<div style={{ display: 'inline-block', position: 'relative', left: '-3%', top: '-5%' }}>
{dynamic?.memberName && <TriangleTag text={intl.formatMessage({ id: 'detail.purchase.minPrice1' })} wrapStyle={{ backgroundColor: '#EA8000' }} bgcolor='#EA8000' direction='right' />}
</div>
<Tabs defaultActiveKey="1" onChange={onTabChange}>
<TabPane tab="报价排名" key="1">
{queryPriceDynamicsData?.map((item) => <RankRow detail={item} key={`queryPriceDynamicsData_${item.id}`} />)}
{queryPriceDynamics.length > 10 && !showMoreQuery && <Button type="link" block onClick={() => { setShowMoreQuery(true) }}>显示更多</Button>}
</TabPane>
<TabPane tab="报名会员" key="2">
{signupMembersData?.map((item) => <RankRow detail={item} key={`signupMembersData_${item.id}`} rowType={2} />)}
{signupMembers.length > 10 && !showMoreSign && <Button type="link" block onClick={() => { setShowMoreSign(true) }}>显示更多</Button>}
</TabPane>
</Tabs>
{dynamic?.memberName}
</h4>
<div className={styles.rankHeaderBoxInfo}>
<div className={styles.rankHeaderBoxInfoChild}>{intl.formatMessage({ id: 'detail.purchase.nowMinPrice1' })}<span>{dynamic?.minPrice ? `¥ ${priceFormat(dynamic?.minPrice)}` : '-'}</span></div>
<div className={styles.rankHeaderBoxInfoChild}>{intl.formatMessage({ id: 'detail.purchase.allowPurchaseCount1' })}<span>{dynamic?.count ?? '-'}</span></div>
</div>
</div>
)
</div>
<Tabs defaultActiveKey="1" onChange={onTabChange}>
<TabPane tab={intl.formatMessage({ id: 'detail.purchase.offerRank' })} key="1">
{queryPriceDynamicsData?.map((item) => <RankRow detail={item} key={`queryPriceDynamicsData_${item.id}`} />)}
{queryPriceDynamics.length > 10 && !showMoreQuery && <Button type="link" block onClick={() => { setShowMoreQuery(true) }}>{intl.formatMessage({ id: 'table.purchase.showMore' })}</Button>}
</TabPane>
<TabPane tab={intl.formatMessage({ id: 'detail.purchase.inviteMemberName' })} key="2">
{signupMembersData?.map((item) => <RankRow detail={item} key={`signupMembersData_${item.id}`} rowType={2} />)}
{signupMembers.length > 10 && !showMoreSign && <Button type="link" block onClick={() => { setShowMoreSign(true) }}>{intl.formatMessage({ id: 'table.purchase.showMore' })}</Button>}
</TabPane>
</Tabs>
</div>
)
}
export default RankItem;
......@@ -11,82 +11,84 @@ import IMBtn from '../../../../../components/detail/components/iMBtn';
import TriangleTag from '../triangleTag';
import styles from './index.less';
import { getIntl } from 'umi';
const intl = getIntl();
interface RankRowProps {
detail: any,
rowType?: (1 | 2) & number
detail: any,
rowType?: (1 | 2) & number
}
const RankForLeve = {
1: level1,
2: level2,
3: level3,
1: level1,
2: level2,
3: level3,
}
const RankRow: React.FC<RankRowProps> = (props: any) => {
const { detail = {}, rowType } = props;
const { detail = {}, rowType } = props;
const _returnBadge = (number) => {
const _number = Number(number);
switch (_number) {
case 1:
case 2:
case 3:
return <img src={RankForLeve[_number]} alt={`第${_number}名`} />;
default:
return <div className={styles.rankRowLeftTopRank}>{_number}</div>
}
const _returnBadge = (number) => {
const _number = Number(number);
switch (_number) {
case 1:
case 2:
case 3:
return <img src={RankForLeve[_number]} alt={`第${_number}名`} />;
default:
return <div className={styles.rankRowLeftTopRank}>{_number}</div>
}
const _returnRow = () => {
if (rowType === 1) {
return (
<div className={`${styles.rankRow} ${styles[`rankRow_level_${detail.ranking}`]}`}>
<div className={styles.rankRowLeft}>
<div className={styles.rankRowLeftTop}>
{_returnBadge(detail.ranking)}
<Tooltip placement="top" title={detail.memberName}>
<div className={styles.rankRowLeftTopRankCalc}>{detail.memberName}</div>
</Tooltip>
{detail.ranking === 1 && <TriangleTag text='最低价' wrapStyle={{ backgroundColor: '#EA8000', marginLeft: '8px' }} bgcolor='#EA8000' direction='left' />}
</div>
<div className={styles.rankRowLeftBottom}>
¥{priceFormat(detail.sumPrice)}
<div className={styles.rankRowLeftBottomTag}>{detail.count}</div>
</div>
</div>
<div className={styles.rankRowRight}>
{detail.contacts}
<IMBtn func={() => toChatRoom(detail.memberId)} />
</div>
</div>
)
} else {
return (
<div className={`${styles.rankRow}`}>
<div className={styles.rankRowLeft}>
<Tooltip placement="top" title={detail.memberName}>
<div className={styles.rankRowLeftEllipsisTitle}>{detail.memberName}</div>
</Tooltip>
<div className={styles.rankRowLeftBottomPhone}>{detail.tel.replace(/^(.{3})(.*)(.{4})$/, '$1 $2 $3')}</div>
</div>
<div>
<div className={styles.rankRowRight}>
{detail.contacts}
<IMBtn func={() => toChatRoom(detail.memberId)} />
</div>
</div>
</div>
)
}
}
const _returnRow = () => {
if (rowType === 1) {
return (
<div className={`${styles.rankRow} ${styles[`rankRow_level_${detail.ranking}`]}`}>
<div className={styles.rankRowLeft}>
<div className={styles.rankRowLeftTop}>
{_returnBadge(detail.ranking)}
<Tooltip placement="top" title={detail.memberName}>
<div className={styles.rankRowLeftTopRankCalc}>{detail.memberName}</div>
</Tooltip>
{detail.ranking === 1 && <TriangleTag text={intl.formatMessage({ id: 'detail.purchase.minPrice1' })} wrapStyle={{ backgroundColor: '#EA8000', marginLeft: '8px' }} bgcolor='#EA8000' direction='left' />}
</div>
<div className={styles.rankRowLeftBottom}>
¥{priceFormat(detail.sumPrice)}
<div className={styles.rankRowLeftBottomTag}>{detail.count}</div>
</div>
</div>
<div className={styles.rankRowRight}>
{detail.contacts}
<IMBtn func={() => toChatRoom(detail.memberId)} />
</div>
</div>
)
} else {
return (
<div className={`${styles.rankRow}`}>
<div className={styles.rankRowLeft}>
<Tooltip placement="top" title={detail.memberName}>
<div className={styles.rankRowLeftEllipsisTitle}>{detail.memberName}</div>
</Tooltip>
<div className={styles.rankRowLeftBottomPhone}>{detail.tel.replace(/^(.{3})(.*)(.{4})$/, '$1 $2 $3')}</div>
</div>
<div>
<div className={styles.rankRowRight}>
{detail.contacts}
<IMBtn func={() => toChatRoom(detail.memberId)} />
</div>
</div>
</div>
)
}
}
return (
_returnRow()
)
return (
_returnRow()
)
}
RankRow.defaultProps = {
rowType: 1
rowType: 1
}
export default RankRow;
......@@ -8,6 +8,7 @@ import { postPurchaseOnlineBiddingSubmitReportPrice } from '@/services/PurchaseV
import BtnItem from '../../../../../../components/detail/components/bidDetailBtnItem';
import styles from './index.less';
import { getIntl } from 'umi';
const { Text } = Typography;
......@@ -17,9 +18,11 @@ interface DetailBottomDrawerProps {
detail: any
}
const intl = getIntl();
const transforType = {
1: '是',
0: '否'
1: intl.formatMessage({ id: 'detail.purchase.okText' }),
0: intl.formatMessage({ id: 'detail.purchase.cancelText' })
}
const DetailBottomDrawer: React.FC<DetailBottomDrawerProps> = (props: any) => {
......@@ -40,7 +43,7 @@ const DetailBottomDrawer: React.FC<DetailBottomDrawerProps> = (props: any) => {
}, [visible])
const columns: ColumnType<any>[] = [
{
title: '物料编号/名称',
title: intl.formatMessage({ id: 'detail.purchase.type' }),
dataIndex: 'number',
key: 'number',
render: (text: any, record: any) => (
......@@ -50,11 +53,11 @@ const DetailBottomDrawer: React.FC<DetailBottomDrawerProps> = (props: any) => {
</Space>
)
},
{ title: '规格型号', key: 'model', dataIndex: 'model', },
{ title: '品类', key: 'category', dataIndex: 'category', },
{ title: '品牌', key: 'brand', dataIndex: 'brand', },
{ title: intl.formatMessage({ id: 'detail.purchase.nameCode' }), key: 'model', dataIndex: 'model', },
{ title: intl.formatMessage({ id: 'detail.purchase.customerCategory' }), key: 'category', dataIndex: 'category', },
{ title: intl.formatMessage({ id: 'detail.purchase.brand' }), key: 'brand', dataIndex: 'brand', },
{
title: '采购数量/单位',
title: intl.formatMessage({ id: 'detail.purchase.purchaseCount1' }),
dataIndex: 'unit',
key: 'unit',
render: (text: any, record: any) => (
......@@ -65,7 +68,7 @@ const DetailBottomDrawer: React.FC<DetailBottomDrawerProps> = (props: any) => {
)
},
{
title: '含税/税率',
title: intl.formatMessage({ id: 'detail.purchase.isTax1' }),
dataIndex: 'isTax',
key: 'isTax',
render: (text: any, record: any) => (activeItem ?
......@@ -76,7 +79,7 @@ const DetailBottomDrawer: React.FC<DetailBottomDrawerProps> = (props: any) => {
: <Input value={record.taxRate} onChange={(e) => { _changeTax(record, e.target.value) }} addonAfter="%" />)
},
{
title: '单价(含税)',
title: intl.formatMessage({ id: 'detail.purchase.taxUnitPrice' }),
dataIndex: 'unitPrice',
key: 'unitPrice',
render: (text: any, record: any, index: number) => (activeItem ?
......@@ -85,13 +88,13 @@ const DetailBottomDrawer: React.FC<DetailBottomDrawerProps> = (props: any) => {
<Form.Item
name={`unitPrice_${index}`}
style={{ margin: 0 }}
rules={[{ required: true, message: '请输入金额' }]}
rules={[{ required: true, message: intl.formatMessage({ id: 'detail.purchase.message56' }) }]}
>
<Input value={record.unitPrice} onChange={(e) => { _changeUnitPrice(record, e.target.value) }} addonBefore="¥" />
</Form.Item>)
},
{
title: '金额(含税)',
title: intl.formatMessage({ id: 'detail.purchase.taxPrice' }),
dataIndex: 'price',
key: 'price',
render: (text: any, record: any) => <Text type='secondary'>{text && `¥${priceFormat(text)}`}</Text>
......@@ -149,7 +152,7 @@ const DetailBottomDrawer: React.FC<DetailBottomDrawerProps> = (props: any) => {
form.validateFields().then(() => {
const _price = dataSource2.reduce((total: any, cur: any) => total + Number(cur.price), 0);
if (detail?.minLowPrice && Number(detail.minLowPrice) - _price < detail.minPrice) {
message.error('当前报价金额不满足最小价差要求,请修改后再报价!');
message.error(intl.formatMessage({ id: 'detail.purchase.tips15' }));
return;
}
let _dataSource2 = dataSource2.map((item) => {
......@@ -174,7 +177,7 @@ const DetailBottomDrawer: React.FC<DetailBottomDrawerProps> = (props: any) => {
return (
<Drawer
title="竞价详情"
title={intl.formatMessage({ id: 'detail.purchase.modalTitle14' })}
placement={'bottom'}
closable={true}
onClose={onClose}
......@@ -182,7 +185,7 @@ const DetailBottomDrawer: React.FC<DetailBottomDrawerProps> = (props: any) => {
key={'bottom'}
height={450}
className={styles.drawer}
closeIcon={<div>取消报价</div>}
closeIcon={<div>{intl.formatMessage({ id: 'detail.purchase.cancelOffer' })}</div>}
>
<div style={{ width: '100%', overflowX: 'auto' }}>
<Row gutter={[8, 8]} style={{ marginBottom: '10px' }} wrap={false}>
......
import React, { useState } from 'react';
import { Button, Divider,message } from 'antd';
import { Button, Divider, message } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import { priceFormat } from '@/utils/numberFomat';
......@@ -8,79 +8,81 @@ import useCountDown from '@/hooks/useCountDown';
import DetailBottomDrawer from './detailBottomDrawer'
import styles from './index.less'
import { getIntl } from 'umi';
interface StatuBoxProps {
detail: any,
hasBidBtn?: boolean,
detail: any,
hasBidBtn?: boolean,
}
const intl = getIntl();
const transforType = {
1: '是',
0: '否'
1: intl.formatMessage({ id: 'detail.purchase.okText' }),
0: intl.formatMessage({ id: 'detail.purchase.cancelText' })
}
const StatuBox: React.FC<StatuBoxProps> = (props: any) => {
const { hasBidBtn, detail } = props;
const [hour, minute, second, stillRun] = useCountDown(detail?.biddingEndTime / 1000);
const [visible, setVisible] = useState<boolean>(false);
const { hasBidBtn, detail } = props;
const [hour, minute, second, stillRun] = useCountDown(detail?.biddingEndTime / 1000);
const [visible, setVisible] = useState<boolean>(false);
const _handleBid = () => {
if(detail.allowPurchaseCount > detail.offerCount){
setVisible(true)
}else{
message.error('当前报价次数已超过允许报价次数!');
}
const _handleBid = () => {
if (detail.allowPurchaseCount > detail.offerCount) {
setVisible(true)
} else {
message.error(intl.formatMessage({ id: 'detail.purchase.tips16' }));
}
}
return (
<>
<div className='ant-card ant-card-bordered'>
<div className='ant-card-body'>
<div className={styles.statusBox}>
<div className={styles.statusBoxStatus}>当前状态:<span>{stillRun ? `竞价中` : '竞价结束'}</span></div>
<p className={styles.statusBoxTips}>距离竞价结束还剩</p>
<div className={styles.statusBoxTime}>
<div className={styles.statusBoxTimeChild}>
<div className={styles.statusBoxTimeChild_top}>{hour}</div>
<p className={styles.statusBoxTimeChild_bottom}>小时</p>
</div>
<span>:</span>
<div className={styles.statusBoxTimeChild}>
<div className={styles.statusBoxTimeChild_top}>{minute}</div>
<p className={styles.statusBoxTimeChild_bottom}>分钟</p>
</div>
<span>:</span>
<div className={styles.statusBoxTimeChild}>
<div className={styles.statusBoxTimeChild_top}>{second}</div>
<p className={styles.statusBoxTimeChild_bottom}></p>
</div>
</div>
<Divider dashed style={{ color: '#EBECF0', margin: '6px 0' }} />
<h4>竞价规则</h4>
<div className={styles.statusBoxText}><div>报价规则:</div>项目总价(含税)</div>
<div className={styles.statusBoxText}><div>起拍价:</div>{detail.isStartingPrice ? `¥ ${priceFormat(detail?.startingPrice)}`: '无' }</div>
{!hasBidBtn && <div className={styles.statusBoxText}><div>目标价:</div>{detail.isTargetPrice ? `¥ ${priceFormat(detail?.targetPrice)}`: '无' }</div>}
<div className={styles.statusBoxText}><div>最小价差:</div>{detail.isMinPrice ? `¥ ${priceFormat(detail?.minPrice)}`: '无' }</div>
<div className={styles.statusBoxText}><div>允许报价次数:</div>{detail?.allowPurchaseCount}</div>
<div className={styles.statusBoxText}><div>报价排名:</div>{hasBidBtn ? (detail.isOpenPurchase ? '按项目总价排名' : '无' ): '按项目总价排名'}</div>
{hasBidBtn ? (
<Button disabled={!stillRun} type="primary" icon={<PlusOutlined />} block onClick={_handleBid} size={'large'} style={{ margin: '15px 0' }}>我要报价</Button>
) : (
<>
<div className={styles.statusBoxText}><div>公开最低报价:</div>{transforType[detail?.isOpenPurchase]}</div>
<div className={styles.statusBoxText}><div>公开报价排名:</div>{transforType[detail?.isOpenRanking]}</div>
</>
)}
</div>
</div>
return (
<>
<div className='ant-card ant-card-bordered'>
<div className='ant-card-body'>
<div className={styles.statusBox}>
<div className={styles.statusBoxStatus}>{intl.formatMessage({ id: 'detail.purchase.statusBoxStatus' })}<span>{stillRun ? intl.formatMessage({ id: 'detail.purchase.stillRunStart' }) : intl.formatMessage({ id: 'detail.purchase.stillRunend' })}</span></div>
<p className={styles.statusBoxTips}>{intl.formatMessage({ id: 'detail.purchase.distanceStillRunend' })}</p>
<div className={styles.statusBoxTime}>
<div className={styles.statusBoxTimeChild}>
<div className={styles.statusBoxTimeChild_top}>{hour}</div>
<p className={styles.statusBoxTimeChild_bottom}>{intl.formatMessage({ id: 'detail.purchase.hour' })}</p>
</div>
<span>:</span>
<div className={styles.statusBoxTimeChild}>
<div className={styles.statusBoxTimeChild_top}>{minute}</div>
<p className={styles.statusBoxTimeChild_bottom}>{intl.formatMessage({ id: 'detail.purchase.minute' })}</p>
</div>
<span>:</span>
<div className={styles.statusBoxTimeChild}>
<div className={styles.statusBoxTimeChild_top}>{second}</div>
<p className={styles.statusBoxTimeChild_bottom}>{intl.formatMessage({ id: 'detail.purchase.second' })}</p>
</div>
</div>
<DetailBottomDrawer
visible={visible}
onClose={() => { setVisible(false) }}
detail={detail}
/>
</>
)
<Divider dashed style={{ color: '#EBECF0', margin: '6px 0' }} />
<h4>{intl.formatMessage({ id: 'detail.purchase.bidRulesLayout' })}</h4>
<div className={styles.statusBoxText}><div>{intl.formatMessage({ id: 'detail.purchase.offerRule' })}</div>{intl.formatMessage({ id: 'detail.purchase.offerRule1' })}</div>
<div className={styles.statusBoxText}><div>{intl.formatMessage({ id: 'detail.purchase.startingPrice' })}</div>{detail.isStartingPrice ? `¥ ${priceFormat(detail?.startingPrice)}` : intl.formatMessage({ id: 'detail.purchase.null' })}</div>
{!hasBidBtn && <div className={styles.statusBoxText}><div>{intl.formatMessage({ id: 'detail.purchase.targetPrice' })}</div>{detail.isTargetPrice ? `¥ ${priceFormat(detail?.targetPrice)}` : intl.formatMessage({ id: 'detail.purchase.null' })}</div>}
<div className={styles.statusBoxText}><div>{intl.formatMessage({ id: 'detail.purchase.minPrice' })}</div>{detail.isMinPrice ? `¥ ${priceFormat(detail?.minPrice)}` : intl.formatMessage({ id: 'detail.purchase.null' })}</div>
<div className={styles.statusBoxText}><div>{intl.formatMessage({ id: 'detail.purchase.allowPurchaseCount' })}</div>{detail?.allowPurchaseCount}</div>
<div className={styles.statusBoxText}><div>{intl.formatMessage({ id: 'detail.purchase.offerRank' })}</div>{hasBidBtn ? (detail.isOpenPurchase ? intl.formatMessage({ id: 'detail.purchase.offerRule4' }) : intl.formatMessage({ id: 'detail.purchase.null' })) : intl.formatMessage({ id: 'detail.purchase.offerRule5' })}</div>
{hasBidBtn ? (
<Button disabled={!stillRun} type="primary" icon={<PlusOutlined />} block onClick={_handleBid} size={'large'} style={{ margin: '15px 0' }}>{intl.formatMessage({ id: 'detail.purchase.offerRule3' })}</Button>
) : (
<>
<div className={styles.statusBoxText}><div>公开最低报价:</div>{transforType[detail?.isOpenPurchase]}</div>
<div className={styles.statusBoxText}><div>{intl.formatMessage({ id: 'detail.purchase.isOpenRanking' })}</div>{transforType[detail?.isOpenRanking]}</div>
</>
)}
</div>
</div>
</div>
<DetailBottomDrawer
visible={visible}
onClose={() => { setVisible(false) }}
detail={detail}
/>
</>
)
}
export default StatuBox
\ No newline at end of file
export default StatuBox
......@@ -3,41 +3,41 @@ import React from 'react';
import styles from './index.less';
interface TriangleTagProps {
text: string,
wrapStyle: React.CSSProperties,
bgcolor?: string,
direction?: string,
text: string,
wrapStyle: React.CSSProperties,
bgcolor?: string,
direction?: string,
}
const TriangleTag: React.FC<TriangleTagProps> = (props: any) => {
const { text, bgcolor, direction, wrapStyle } = props;
const _returndirectionStyle = () => {
if(direction === 'left'){
return {
borderColor: `transparent ${bgcolor} transparent transparent`,
left: '-8px',
top : '26%'
}
}else if(direction === 'right'){
return {
borderColor: `transparent ${bgcolor} transparent transparent`,
transform: 'rotate(180deg)',
right: '-8px',
top : '26%'
}
}
const { text, bgcolor, direction, wrapStyle } = props;
const _returndirectionStyle = () => {
if (direction === 'left') {
return {
borderColor: `transparent ${bgcolor} transparent transparent`,
left: '-8px',
top: '26%'
}
} else if (direction === 'right') {
return {
borderColor: `transparent ${bgcolor} transparent transparent`,
transform: 'rotate(180deg)',
right: '-8px',
top: '26%'
}
}
return (
<div className={styles.triangleTag} style={wrapStyle}>
<div className={styles.directionTriangle} style={_returndirectionStyle()}></div>
{text}
</div>
)
}
return (
<div className={styles.triangleTag} style={wrapStyle}>
<div className={styles.directionTriangle} style={_returndirectionStyle()}></div>
{text}
</div>
)
}
TriangleTag.defaultProps = {
bgcolor: '#EA8000',
direction: 'left'
bgcolor: '#EA8000',
direction: 'left'
}
export default TriangleTag;
import React, { useEffect, useState } from 'react';
import { history } from 'umi';
import { getIntl, history } from 'umi';
import { Row, Col } from 'antd';
import { ArrowLeftOutlined } from '@ant-design/icons';
import { isEmpty } from 'lodash'
......@@ -19,6 +19,8 @@ import StatusBox from './components/statusBox';
import styles from './index.less';
const intl = getIntl();
const Management = () => {
const {
query: {
......@@ -52,7 +54,7 @@ const Management = () => {
setAwardProcess(_data.awardProcesss);
setLowestList({
type: 'min',
title: '最低价',
title: intl.formatMessage({ id: 'detail.purchase.minPrice1' }),
list: _data.awardProcesss ? _data.awardProcesss.map((item) => { return { type: 'min', time: formatTimeString(item.peportTime, 'HH:mm:ss'), value: priceFormat(item.sumPice, 0) } }) : []
})
}
......@@ -114,7 +116,7 @@ const Management = () => {
setAwardProcess(data);
setLowestList({
type: 'min',
title: '最低价',
title: intl.formatMessage({ id: 'detail.purchase.minPrice1' }),
list: data ? data.map((item) => { return { type: 'min', time: formatTimeString(item.peportTime, 'HH:mm:ss'), value: priceFormat(item.sumPice, 0) } }) : []
})
})
......
......@@ -28,7 +28,7 @@ const ReadyConfirm = () => {
const [confirmBidResultVisible, setConfirmBidResultVisible] = useState<boolean>(false);
const [confirmRecord, setConfirmRecord] = useState<any>();
const columns: ColumnType<any>[] = [{
title: '序号',
title: intl.formatMessage({ id: 'table.purchase.id' }),
align: 'center',
dataIndex: 'id',
key: 'id',
......@@ -44,7 +44,7 @@ const ReadyConfirm = () => {
</Space>
)
}, {
title: '授标会员',
title: intl.formatMessage({ id: 'table.purchase..biddingMemberName' }),
key: 'memberName',
dataIndex: 'memberName',
render: (text: any, record: any) => (
......@@ -80,7 +80,7 @@ const ReadyConfirm = () => {
key: 'operate',
dataIndex: 'operate',
align: 'center',
render: (text: any, record: any) => <Button onClick={() => { handleConfirm(record) }} type='link'>确认</Button>
render: (text: any, record: any) => <Button onClick={() => { handleConfirm(record) }} type='link'>{intl.formatMessage({ id: 'table.purchase.confirm' })}</Button>
}];
const handleConfirm = (record: any) => {
......@@ -105,7 +105,7 @@ const ReadyConfirm = () => {
/>
<ConfirmBidResultModal
record={confirmRecord}
title="确认竞价结果"
title={intl.formatMessage({ id: 'detail.purchase.modalTitle11' })}
visible={confirmBidResultVisible}
fetch={postPurchaseBiddingStayConfirmBidding}
onCancel={() => setConfirmBidResultVisible(false)}
......
......@@ -68,7 +68,7 @@ const ReadyExamineOne = () => {
key: 'operate',
dataIndex: 'operate',
align: 'center',
render: (text: any, record: any) => <Button onClick={() => { handleExamine(record) }} type='link'>审核</Button>
render: (text: any, record: any) => <Button onClick={() => { handleExamine(record) }} type='link'>{intl.formatMessage({ id: 'table.purchase.audit' })}</Button>
}];
/** 批量审核 */
......@@ -114,7 +114,7 @@ const ReadyExamineOne = () => {
onClick={() => fetchSubmitBatch()}
disabled={rowkeys.length === 0}
>
批量审核通过
{intl.formatMessage({ id: 'table.purchase.submitBatch' })}
</Button>
</Space>
</Col>
......@@ -123,7 +123,7 @@ const ReadyExamineOne = () => {
/>
<ModalOperate
id={id}
title="单据审核"
title={intl.formatMessage({ id: 'table.purchase.modelTitle' })}
modalType="audit"
visible={visible}
fetch={postPurchaseBiddingExamine1}
......
......@@ -38,7 +38,7 @@ const ReadyExamineResultOne = () => {
</Space>
)
}, {
title: '授标会员',
title: intl.formatMessage({ id: 'table.purchase..biddingMemberName' }),
key: 'memberName',
dataIndex: 'memberName',
render: (text: any, record: any) => (
......@@ -74,7 +74,7 @@ const ReadyExamineResultOne = () => {
key: 'operate',
dataIndex: 'operate',
align: 'center',
render: (text: any, record: any) => <Button onClick={() => { handleExamine(record) }} type='link'>审核</Button>
render: (text: any, record: any) => <Button onClick={() => { handleExamine(record) }} type='link'>{intl.formatMessage({ id: 'table.purchase.audit' })}</Button>
}];
/** 批量审核 */
......@@ -120,7 +120,7 @@ const ReadyExamineResultOne = () => {
onClick={() => fetchSubmitBatch()}
disabled={rowkeys.length === 0}
>
批量审核通过
{intl.formatMessage({ id: 'table.purchase.submitBatch' })}
</Button>
</Space>
</Col>
......@@ -129,7 +129,7 @@ const ReadyExamineResultOne = () => {
/>
<ModalOperate
id={id}
title="单据审核"
title={intl.formatMessage({ id: 'table.purchase.modelTitle' })}
modalType="audit"
visible={visible}
fetch={postPurchaseBiddingSubmitBidding1}
......
......@@ -38,7 +38,7 @@ const ReadyExamineResultTwo = () => {
</Space>
)
}, {
title: '授标会员',
title: intl.formatMessage({ id: 'table.purchase..biddingMemberName' }),
key: 'memberName',
dataIndex: 'memberName',
render: (text: any, record: any) => (
......@@ -74,7 +74,7 @@ const ReadyExamineResultTwo = () => {
key: 'operate',
dataIndex: 'operate',
align: 'center',
render: (text: any, record: any) => <Button onClick={() => { handleExamine(record) }} type='link'>审核</Button>
render: (text: any, record: any) => <Button onClick={() => { handleExamine(record) }} type='link'>{intl.formatMessage({ id: 'table.purchase.audit' })}</Button>
}];
/** 批量审核 */
......@@ -120,7 +120,7 @@ const ReadyExamineResultTwo = () => {
onClick={() => fetchSubmitBatch()}
disabled={rowkeys.length === 0}
>
批量审核通过
{intl.formatMessage({ id: 'table.purchase.submitBatch' })}
</Button>
</Space>
</Col>
......@@ -129,7 +129,7 @@ const ReadyExamineResultTwo = () => {
/>
<ModalOperate
id={id}
title="单据审核"
title={intl.formatMessage({ id: 'table.purchase.modelTitle' })}
modalType="audit"
visible={visible}
fetch={postPurchaseBiddingSubmitBidding2}
......
......@@ -27,7 +27,7 @@ const ReadyExamineSignUp = () => {
const [id, setId] = useState<any>();
const [visible, setVisible] = useState<boolean>(false);
const columns: ColumnType<any>[] = [{
title: '序号',
title: intl.formatMessage({ id: 'table.purchase.id' }),
align: 'center',
dataIndex: 'id',
key: 'id',
......@@ -43,7 +43,7 @@ const ReadyExamineSignUp = () => {
</Space>
)
}, {
title: '报名会员/时间',
title: intl.formatMessage({ id: 'table.purchase.signUpTime' }),
key: 'signUpTime',
dataIndex: 'signUpTime',
render: (text: any, record: any) => (
......@@ -53,7 +53,7 @@ const ReadyExamineSignUp = () => {
</Space>
)
}, {
title: '报名开始/结束时间',
title: intl.formatMessage({ id: 'table.purchase.startSignUp' }),
key: 'startSignUp',
dataIndex: 'startSignUp',
render: (text: any, record: any) => <>
......@@ -82,7 +82,7 @@ const ReadyExamineSignUp = () => {
key: 'operate',
dataIndex: 'operate',
align: 'center',
render: (text: any, record: any) => <Button onClick={() => { handleExamine(record) }} type='link'>审核</Button>
render: (text: any, record: any) => <Button onClick={() => { handleExamine(record) }} type='link'>{intl.formatMessage({ id: 'table.purchase.audit' })}</Button>
}];
const handleExamine = (record: any) => {
......@@ -107,7 +107,7 @@ const ReadyExamineSignUp = () => {
/>
<ModalOperate
id={id}
title="单据审核"
title={intl.formatMessage({ id: 'table.purchase.modelTitle' })}
modalType="audit"
visible={visible}
fetch={postPurchaseBiddingExaminBiddingSignup}
......
......@@ -68,7 +68,7 @@ const ReadyExamineTwo = () => {
key: 'operate',
dataIndex: 'operate',
align: 'center',
render: (text: any, record: any) => <Button onClick={() => { handleExamine(record) }} type='link'>审核</Button>
render: (text: any, record: any) => <Button onClick={() => { handleExamine(record) }} type='link'>{intl.formatMessage({ id: 'table.purchase.audit' })}</Button>
}];
/** 批量审核 */
......@@ -114,7 +114,7 @@ const ReadyExamineTwo = () => {
onClick={() => fetchSubmitBatch()}
disabled={rowkeys.length === 0}
>
批量审核通过
{intl.formatMessage({ id: 'table.purchase.submitBatch' })}
</Button>
</Space>
</Col>
......@@ -123,7 +123,7 @@ const ReadyExamineTwo = () => {
/>
<ModalOperate
id={id}
title="单据审核"
title={intl.formatMessage({ id: 'detail.purchase.modelTitle' })}
modalType="audit"
visible={visible}
fetch={postPurchaseBiddingExamine2}
......
......@@ -68,7 +68,7 @@ const ReadySubmit = () => {
key: 'operate',
dataIndex: 'operate',
align: 'center',
render: (text: any, record: any) => <Button onClick={() => { handleExamine(record) }} type='link'>提交</Button>
render: (text: any, record: any) => <Button onClick={() => { handleExamine(record) }} type='link'>{intl.formatMessage({ id: 'table.purchase.submit' })}</Button>
}];
/** 批量审核 */
......@@ -114,7 +114,7 @@ const ReadySubmit = () => {
onClick={() => fetchSubmitBatch()}
disabled={rowkeys.length === 0}
>
批量提交
{intl.formatMessage({ id: 'detail.purchase.submitBatch1' })}
</Button>
</Space>
</Col>
......@@ -123,7 +123,7 @@ const ReadySubmit = () => {
/>
<ModalOperate
id={id}
title="单据审核"
title={intl.formatMessage({ id: 'detail.purchase.modelTitle' })}
modalType="audit"
visible={visible}
fetch={postPurchaseBiddingSubmit}
......
import React, { useRef, useState } from 'react';
import { history } from 'umi';
import { getIntl, history } from 'umi';
import { ColumnType } from 'antd/lib/table/interface';
import { Space, Button, Typography, Badge } from 'antd';
import { PlayCircleOutlined, PoweroffOutlined } from '@ant-design/icons';
......@@ -11,6 +11,7 @@ import { ENTERPRISE_CENTER_URL } from '@/constants'
import Table from '../../components/table'
import SubmitResultModal from '../components/submitResultModal'
const intl = getIntl();
import {
BID_EXTERNALSTATE_COLOR,
......@@ -39,7 +40,7 @@ const ReadySubmitExamineResult = () => {
</Space>
)
}, {
title: '授标会员',
title: intl.formatMessage({ id: 'table.purchase..biddingMemberName' }),
key: 'memberName',
dataIndex: 'memberName',
render: (text: any, record: any) => (
......@@ -75,7 +76,7 @@ const ReadySubmitExamineResult = () => {
key: 'operate',
dataIndex: 'operate',
align: 'center',
render: (text: any, record: any) => <Button disabled={!(record.button === 1 || record.button === 2)} onClick={() => handleSubmit(record)} type='link'>{record.button === 1 ? '修改' : '提交审核'}</Button>
render: (text: any, record: any) => <Button disabled={!(record.button === 1 || record.button === 2)} onClick={() => handleSubmit(record)} type='link'>{record.button === 1 ? intl.formatMessage({ id: 'table.purchase.eidt' }) : intl.formatMessage({ id: 'detail.purchase.submit' })}</Button>
}];
const handleSubmit = (record: any) => {
......@@ -116,7 +117,7 @@ const ReadySubmitExamineResult = () => {
fetch={getPurchaseBiddingStaySubmitBiddingList}
/>
<SubmitResultModal
title={'提交竞价结果'}
title={intl.formatMessage({ id: 'detail.purchase.modalTitle12' })}
visible={visible}
onOk={_handleBiddingReturn}
onCancel={() => { setVisible(false) }}
......
......@@ -26,7 +26,7 @@ const Search = () => {
const [id, setId] = useState<number>();
const [visible, setVisible] = useState<boolean>(false);
const columns: ColumnType<any>[] = [{
title: '序号',
title: intl.formatMessage({ id: 'table.purchase.id' }),
align: 'center',
dataIndex: 'id',
key: 'id',
......@@ -80,7 +80,7 @@ const Search = () => {
setVisible(true);
}}
>
作废
{intl.formatMessage({ id: 'table.purchase.undo' })}
</Button>
)
}];
......@@ -103,7 +103,7 @@ const Search = () => {
/>
<ModalOperate
id={id}
title="作废原因"
title={intl.formatMessage({ id: 'table.purchase.undoCause' })}
visible={visible}
modalType='discard'
maxNumber={50}
......
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