Commit 8257523a authored by 前端-黄佳鑫's avatar 前端-黄佳鑫
parents 4013268c 5b3f1013
......@@ -91,6 +91,12 @@ const AuthConfigRoute: RouterChild = {
name: 'collection',
component: '@/pages/systemSetting/collection',
},
// 优惠券
{
path: '/memberCenter/systemSetting/coupon',
name: 'myCoupon',
component: '@/pages/systemSetting/coupon',
},
// 账户安全设置
{
path: '/memberCenter/systemSetting/accountSetting',
......
......@@ -366,6 +366,82 @@ const BalancedRoute = {
},
],
},
// 业务请款
{
path: '/memberCenter/balance/businessRequestFunds',
relationParentCode: 'balance',
name: '业务请款',
routes: [
{
path: '/memberCenter/balance/businessRequestFunds/search',
component: '@/pages/balance/businessRequestFunds/search',
relationParentCode: 'balance',
name: '请款单查询',
icon: 'smile',
},
{
path: '/memberCenter/balance/businessRequestFunds/search/preview',
component: '@/pages/balance/businessRequestFunds/detail',
relationParentCode: 'balance',
name: '请款单查询-详情',
icon: 'smile',
hideInMenu: true,
noMargin: true,
},
{
path: '/memberCenter/balance/businessRequestFunds/admin',
component: '@/pages/balance/businessRequestFunds/admin',
relationParentCode: 'balance',
name: '请款单管理',
icon: 'smile',
},
{
path: '/memberCenter/balance/businessRequestFunds/admin/preview',
component: '@/pages/balance/businessRequestFunds/detail',
relationParentCode: 'balance',
name: '请款单管理-详情',
icon: 'smile',
hideInMenu: true,
noMargin: true,
},
{
path: '/memberCenter/balance/businessRequestFunds/admin/add',
component: '@/pages/balance/businessRequestFunds/admin/add',
relationParentCode: 'balance',
name: '新增请款单',
icon: 'smile',
hideInMenu: true,
noMargin: true,
},
{
path: '/memberCenter/balance/businessRequestFunds/admin/edit',
component: '@/pages/balance/businessRequestFunds/admin/add',
relationParentCode: 'balance',
name: '编辑请款单',
icon: 'smile',
hideInMenu: true,
noMargin: true,
},
{
path: '/memberCenter/balance/businessRequestFunds/admin/funds',
component: '@/pages/balance/businessRequestFunds/admin/add',
relationParentCode: 'balance',
name: '对账请款单',
icon: 'smile',
hideInMenu: true,
noMargin: true,
},
{
path: '/memberCenter/balance/businessRequestFunds/admin/fundsEdit',
component: '@/pages/balance/businessRequestFunds/admin/add',
relationParentCode: 'balance',
name: '对账请款单',
icon: 'smile',
hideInMenu: true,
noMargin: true,
},
],
},
],
};
......
......@@ -57,6 +57,17 @@ const SchemaSubmit = createVirtualBox('schemaSubmit', Submit)
const SchemaReset = createVirtualBox('schemaReset', Reset)
export const FlexBox = createVirtualBox('flexBox', props => <Row {...props} />)
export const isFieldLegal = (value: any): boolean => {
if (Array.isArray(value) && !value.length) {
return false;
}
// 校验数值 及 字符串数值,这里主要是处理 数值 0 是合法的问题
if (!isNaN(parseFloat(value))) {
return true;
}
return !!value;
};
// 自定义校验规则
registerValidationRules({
limitByte: (value, desc, rules) => {
......@@ -71,12 +82,11 @@ registerValidationRules({
},
required: (value, desc, rules) => {
const { required } = desc;
let str = value;
let message = ``
if (required) {
message += `${intl.formatMessage({id: 'common.bitian'})}`
}
return (required && str === null) ? message : ''
return (required && !isFieldLegal(value)) ? message : ''
}
});
......
......@@ -305,6 +305,8 @@ export default {
'purchaseOrder.tijiaoshenhe': 'Submit for review',
'purchaseOrder.tijiaodingdan': 'Submit order',
'purchaseOrder.piliangtijiao': 'Batch submission',
'purchaseOrder.pilianglingqu': 'Batch to receive',
'purchaseOrder.lingqu': 'receive',
'purchaseOrder.shougongshouhuo': 'Manual receipt',
'purchaseOrder.ququerenshouhuo': 'Go to confirm receipt',
'purchaseOrder.di': '第',
......
......@@ -305,6 +305,8 @@ export default {
'purchaseOrder.tijiaoshenhe': '제출 심사',
'purchaseOrder.tijiaodingdan': '주문 전송',
'purchaseOrder.piliangtijiao': '대량 제출',
'purchaseOrder.pilianglingqu': '대량으로 수령하다',
'purchaseOrder.lingqu': '받다',
'purchaseOrder.shougongshouhuo': '수공 수령',
'purchaseOrder.ququerenshouhuo': '수령을 확인하러 가다',
'purchaseOrder.di': '다음을 수행합니다.',
......
......@@ -495,6 +495,7 @@ export default {
'menu.systemSetting.authConfig.userDetail': '查看用户',
'menu.systemSetting.collection': '收藏管理',
'menu.systemSetting.myCoupon': '优惠券',
'menu.systemSetting.accountSetting': '账号安全设置',
'menu.systemSetting.editAccount': '编辑账号信息',
......
......@@ -305,6 +305,8 @@ export default {
'purchaseOrder.tijiaoshenhe': '提交审核',
'purchaseOrder.tijiaodingdan': '提交订单',
'purchaseOrder.piliangtijiao': '批量提交',
'purchaseOrder.pilianglingqu': '批量领取',
'purchaseOrder.lingqu': '领取',
'purchaseOrder.shougongshouhuo': '手工收货',
'purchaseOrder.ququerenshouhuo': '去确认收货',
'purchaseOrder.di': '第',
......
......@@ -200,7 +200,7 @@ const SearchDetail = () => {
}
return (
<div style={{ margin: '-24px -24px 0' }}>
<>
<PeripheralLayout
no={dataSource?.reconciliationNo}
detail={dataSource?.reconciliationAbstract}
......@@ -221,7 +221,7 @@ const SearchDetail = () => {
}
/>
<WriteOffDrawer visible={writeOffVisible} onClose={() => { setWriteOffVisible(false) }} />
</div>
</>
)
}
export default SearchDetail;
import React, { useRef } from 'react';
import { Drawer, Button } from 'antd';
import React, { useRef, useState, useMemo } from 'react';
import { Drawer, Button, Form, Input } from 'antd';
import { ColumnType } from 'antd/lib/table/interface';
import StandardTable from '@/components/StandardTable';
import { formatTimeString } from '@/utils'
import { priceFormat } from '@/utils/numberFomat'
import { getSettleAccountsBusinessReconciliationToReconciliationList } from '@/services/SettleV2Api'
import { postSettleAccountsBusinessApplyAmountFindCanApplyAmountRos } from '@/services/SettleV2Api'
import StatusTag from '@/components/StatusTag';
import { getIntl } from 'umi';
interface WriteOffDrawerProps {
visible: boolean,
record: any,
editAble?: boolean,
onClose?: () => void,
onOk?: (rows: any[]) => void
}
const intl = getIntl();
const WriteOffDrawer: React.FC<WriteOffDrawerProps> = (props: WriteOffDrawerProps) => {
const { visible, onClose } = props;
const { visible, record, editAble = false, onClose, onOk } = props;
const ref = useRef<any>({})
const [tabelSource, setTabelSource] = useState<any>([]);
const [form] = Form.useForm();
const loadingTableData = async (params) => {
const _params = { ...params }
const { data } = await getSettleAccountsBusinessReconciliationToReconciliationList(_params)
_params.pageSize = editAble ? 100000 : _params.pageSize
_params.billId = record.billId
_params.sourceContractId = record.sourceContractId
_params.taxRate = record.taxRate
_params.notQueryDetailId = 0
const { data } = await postSettleAccountsBusinessApplyAmountFindCanApplyAmountRos(_params)
setTabelSource(data.data)
return data;
}
const _changeNumbers = (record: any, value: any) => {
let _val = value.replace(/^\D*(\d*(?:\.\d{0,3})?).*$/g, '$1');
let _dataSource = [...tabelSource];
const _i = _dataSource.findIndex((item) => item.id === record.id);
let _item = { ..._dataSource[_i] };
_item.currentMoney = Number(_val);
_dataSource[_i] = _item;
setTabelSource(_dataSource);
}
const _handleOk = () => {
if (editAble) {
form.validateFields().then(formRes => {
onOk?.(tabelSource)
})
} else {
onClose?.()
}
}
const columns: ColumnType<any>[] = [{
title: '请款单号',
key: 'billNo',
dataIndex: 'billNo',
key: 'applyNo',
dataIndex: 'applyNo',
}, {
title: '请款摘要',
key: 'payer',
dataIndex: 'payer',
key: 'applyAbstract',
dataIndex: 'applyAbstract',
}, {
title: '请款类型',
key: 'deliveryBatch',
dataIndex: 'deliveryBatch',
key: 'applyTypeName',
dataIndex: 'applyTypeName',
}, {
title: '单据号',
key: 'deliveryNo',
dataIndex: 'deliveryNo',
key: 'applyRowBillNo',
dataIndex: 'applyRowBillNo',
}, {
title: '单据摘要',
key: 'deliveryNo',
dataIndex: 'deliveryNo',
key: 'applyRowBillAbstract',
dataIndex: 'applyRowBillAbstract',
}, {
title: '单据时间',
key: 'deliveryTime',
dataIndex: 'deliveryTime',
key: 'applyBillDate',
dataIndex: 'applyBillDate',
render: (text: any, record: any) => formatTimeString(text, 'YYYY-MM-DD HH:mm'),
width: 180
}, {
title: '单据状态',
key: 'receiveNo',
dataIndex: 'receiveNo',
key: 'applyStatusName',
dataIndex: 'applyStatusName',
render: (text: any, record: any) => <StatusTag type='primary' title={text} />
}, {
title: intl.formatMessage({ id: 'balance.hanshuishuil' }),
key: 'applyRowBillTaxRate',
dataIndex: 'applyRowBillTaxRate',
width: 100,
render: (text: any) => {
return text > 0 ? `是/${text}%` : '否';
}
}, {
title: '请款金额',
key: 'receiveTime',
dataIndex: 'receiveTime',
key: 'applyRowPayment',
dataIndex: 'applyRowPayment',
}, {
title: '核销金额',
key: 'orderStatus',
dataIndex: 'orderStatus',
key: 'writeOffAmount',
dataIndex: 'writeOffAmount',
render: (text: any) => ${priceFormat(text)}`
}, {
title: '可核销金额',
key: 'orderType',
dataIndex: 'orderType',
render: (text: any) => ${priceFormat(text)}`
key: 'canWriteAmount',
dataIndex: 'canWriteAmount',
render: (text: any, record: any) => ${priceFormat(text)}`
}];
const editColumns: ColumnType<any>[] = columns.concat([{
title: '本次核销金额',
key: 'canWriteAmount',
dataIndex: 'canWriteAmount',
render: (text: any, record: any) => (
<Form.Item
name={`canWriteAmount_${record.id}_${record.applyRowId}`}
style={{ margin: 0 }}
rules={[
{
validator: (_, value) => {
return value > record.canWriteAmount ? Promise.reject(new Error('可以核销金额')) : Promise.resolve()
}
},
]}
>
<Input type='number' addonBefore='¥' max={record.canWriteAmount} value={record.canWriteAmount} onChange={(e) => { _changeNumbers(record, e.target.value) }} />
</Form.Item>
)
}])
const _key = useMemo(() => record.billId, [record])
return (
<Drawer
......@@ -76,26 +138,31 @@ const WriteOffDrawer: React.FC<WriteOffDrawerProps> = (props: WriteOffDrawerProp
placement={'right'}
onClose={onClose}
visible={visible}
key={'right'}
key={_key}
width={'80%'}
footer={
<div style={{ textAlign: 'right' }}>
<Button onClick={onClose} style={{ marginRight: 8 }}>
{intl.formatMessage({ id: 'balance.quxiao' })}
</Button>
<Button onClick={onClose} type="primary">
<Button onClick={_handleOk} type="primary">
{'确定'}
</Button>
</div>
}
>
<StandardTable
keepAlive={false}
fetchTableData={params => loadingTableData(params)}
columns={columns}
currentRef={ref}
rowKey="billId"
/>
<Form
form={form}
>
<StandardTable
keepAlive={false}
fetchTableData={params => loadingTableData(params)}
columns={editAble ? editColumns : columns}
currentRef={ref}
tableProps={{ pagination: !editAble }}
rowKey="id"
/>
</Form>
</Drawer>
);
}
......
......@@ -130,9 +130,10 @@ const ClassProperty: React.FC<{}> = () => {
}
const handlePlateformSelect = (key, node) => {
if (node.children && node.children.length > 0) {
return;
}
// @ 取消关联平台品类仅选择最后一级
// if (node.children && node.children.length > 0) {
// return;
// }
setPlateformSelectNode({ id: key * 1, name: node._title })
}
......
......@@ -127,6 +127,8 @@ const VerifyComingDataDrawer: React.FC<IProps> = (props: IProps) => {
setFieldState('reason', state => {
state.title = fieldState.value === 0 ? intl.formatMessage({ id: 'member.management.common.form.reason.noPass' }) : intl.formatMessage({ id: 'member.management.common.form.reason.pass' });
state.required = fieldState.value === 0;
// 手动改变一个 value,目的是为了触发 必填校验
state.value = state.value || '';
setTimeout(() => {
formActions.validate('reason');
}, 0);
......
@import '~antd/es/style/themes/default.less';
@import '../../../../../global/styles/utils.less';
@card-prefix: coupon-card;
.@{card-prefix} {
display: flex;
align-items: center;
padding: @padding-md;
background-color: #FFFFFF;
border-radius: @border-radius-base * 4;
&-left {
flex: 1;
overflow: hidden;
}
&-right {
flex-shrink: 0;
}
&-belong {
padding: 0 @padding-xss;
border: none;
}
&-name {
margin-top: @margin-xss - 2;
font-size: @font-size-lg;
color: @text-color;
.textOverflow();
}
&-date,
&-code,
&-description {
margin-top: @margin-xss - 2;
font-size: @font-size-base;
color: @text-color-secondary;
}
&-description {
text-align: right;
}
&-yuanWrap {
text-align: right;
}
&-yuan {
font-size: @font-size-sm;
color: @error-color;
}
&-denomination {
font-size: @font-size-sm * 2;
color: @error-color;
}
&-actions {
margin-top: @margin-xss - 2;
text-align: right;
}
}
\ No newline at end of file
/**
* @Description 优惠券卡片
*/
import React from 'react';
import { Button, Tag, Tooltip } from 'antd';
import moment from 'moment';
import { MERCHANT_COUPON_TYPE_VOUCHER } from '@/constants/marketing';
import { COUPON_STATE_UNUSED, COUPON_STATE_USED, COUPON_STATE_EXPIRED } from '../../utils';
import styles from './index.less';
type CouponCardDate = {
/**
* 领取记录id
*/
id: number
/**
* 优惠券id
*/
couponId: number
/**
* 所属类型1-平台2-商家
*/
belongType: number
/**
* 优惠券名称
*/
name: string
/**
* 优惠券类型,如果所属类型为平台则有1-0元抵扣券2-平台通用优惠券,如果所属类型为商家则有1-0元抵扣券2-商家通用优惠券3-品类优惠券4-品牌优惠券5-商品优惠券
*/
type: number
/**
* 优惠券类型名称
*/
typeName: string
/**
* 券面额
*/
denomination: number
/**
* 使用条件,满多少金额可用
*/
useConditionMoney: number
/**
* 有效时间开始
*/
validTimeStart: number
/**
* 有效时间结束
*/
validTimeEnd: number
/**
* 领取时间
*/
crateTime: number
/**
* 品牌id集合(品牌优惠券才有) ,Long
*/
brandIds: number[]
/**
* 品类id集合(品类优惠券才有) ,Long
*/
categoryIds: number[]
/**
* 商品Id集合(商品优惠券才有) ,Long
*/
productIds: number[]
}
interface CouponCardProps {
/**
* 数据,后台数据没有返回 status
* 所以自己整一个 status
*/
data: CouponCardDate,
/**
* 优惠券状态
*/
status: number,
}
const CouponCard: React.FC<CouponCardProps> = (props: CouponCardProps) => {
const { data, status } = props;
const ACTIONS_MAP = {
[COUPON_STATE_UNUSED]: (<Button type="primary" size="small">立即使用</Button>),
[COUPON_STATE_USED]: (<Button type="primary" size="small" disabled>已使用</Button>),
[COUPON_STATE_EXPIRED]: (<Button type="primary" size="small" disabled>已过期</Button>),
};
return (
<div className={styles['coupon-card']}>
<div className={styles['coupon-card-left']}>
{data.type !== MERCHANT_COUPON_TYPE_VOUCHER ? (
<>
{data.belongType === 1 ? (
<Tag color="cyan" className={styles['coupon-card-belong']}>平台通用</Tag>
) : (
<Tag color="red" className={styles['coupon-card-belong']}>商家优惠券</Tag>
)}
</>
) : (
<Tag color="gold" className={styles['coupon-card-belong']}>0元购买抵扣劵</Tag>
)}
<Tooltip title={data.name}>
<div className={styles['coupon-card-name']}>
{data.name}
</div>
</Tooltip>
<div className={styles['coupon-card-date']}>
{`${data.validTimeStart ? moment(data.validTimeStart).format('YYYY-MM-DD') : ''}-${data.validTimeEnd ? moment(data.validTimeEnd).format('YYYY-MM-DD') : ''}`}
</div>
<div className={styles['coupon-card-code']}>券码:Y27NPES1</div>
</div>
<div className={styles['coupon-card-right']}>
<div className={styles['coupon-card-yuanWrap']}>
<span className={styles['coupon-card-yuan']}>¥</span>
<span className={styles['coupon-card-denomination']}>{data.denomination}</span>
</div>
<div className={styles['coupon-card-description']}>
{data.useConditionMoney}
元可用
</div>
<div className={styles['coupon-card-actions']}>
{ACTIONS_MAP[status]}
</div>
</div>
</div>
);
};
export default CouponCard;
@import '~antd/es/style/themes/default.less';
.myCoupon {
:global {
.ant-tabs-top
> .ant-tabs-nav {
margin: 0;
&::before {
border-bottom: none;
}
}
.ant-tabs-tab {
font-size: @font-size-lg;
}
}
&-list {
margin-top: @margin-md;
}
&-loading {
padding: 30px 50px;
text-align: center;
}
}
\ No newline at end of file
/**
* @Description 优惠券
*/
import React, { useState } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Tabs, Row, Col, Spin } from 'antd';
import {
getMarketingWebCouponDetailCount,
getMarketingWebCouponDetailPage,
GetMarketingWebCouponDetailCountResponse,
GetMarketingWebCouponDetailPageResponse,
} from '@/services/MarketingV2Api';
import { useHttpRequest } from '@/hooks/useHttpRequest';
// import { getAuth } from '@/utils/auth';
import { COUPON_STATE_UNUSED, COUPON_STATE_USED, COUPON_STATE_EXPIRED } from './utils';
import MellowCard from '@/components/MellowCard';
import CouponCard from './components/CouponCard';
import styles from './index.less';
const { TabPane } = Tabs;
const MyCoupon: React.FC = () => {
const [activeKey, setActiveKey] = useState(`${COUPON_STATE_UNUSED}`);
// const userInfo = getAuth();
const {
data: analysis,
} = useHttpRequest<GetMarketingWebCouponDetailCountResponse>(() => getMarketingWebCouponDetailCount({
shopId: `${66}`,
memberId: undefined, // 这里传入 memberId 反倒查不出数据,只能跟app、小程序一致不传了
roleId: undefined, // 这里传入 roleId 反倒查不出数据,只能跟app、小程序一致不传了
}), { manual: false });
const {
data: couponList,
run: fetchCouponList,
loading,
} = useHttpRequest<GetMarketingWebCouponDetailPageResponse>((
params = {
shopId: `${66}`,
status: `${COUPON_STATE_UNUSED}`,
memberId: undefined, // 这里传入 memberId 反倒查不出数据,只能跟app、小程序一致不传了
roleId: undefined, // 这里传入 roleId 反倒查不出数据,只能跟app、小程序一致不传了
current: `1`,
pageSize: `99999`,
},
) => getMarketingWebCouponDetailPage(params), {
manual: false,
});
const handleTabsChange = (activeKey: string) => {
setActiveKey(activeKey);
fetchCouponList({
shopId: `${66}`,
status: activeKey,
memberId: undefined, // 这里传入 memberId 反倒查不出数据,只能跟app、小程序一致不传了
roleId: undefined, // 这里传入 roleId 反倒查不出数据,只能跟app、小程序一致不传了
current: `1`,
pageSize: `99999`,
});
};
return (
<PageHeaderWrapper>
<MellowCard
bodyStyle={{
paddingTop: 0,
paddingBottom: 0,
}}
>
<div className={styles.myCoupon}>
<Tabs activeKey={activeKey} onChange={handleTabsChange}>
<TabPane tab={`未使用 (${analysis?.receiveCount})`} key={`${COUPON_STATE_UNUSED}`} />
<TabPane tab={`已使用 (${analysis?.userCount})`} key={`${COUPON_STATE_USED}`} />
<TabPane tab={`已过期 (${analysis?.expireCount})`} key={`${COUPON_STATE_EXPIRED}`} />
</Tabs>
</div>
</MellowCard>
<div className={styles['myCoupon-list']}>
{!loading ? (
<Row gutter={[16, 16]}>
{couponList?.data?.map((item) => (
<Col span={12} key={item.id}>
<CouponCard data={item} status={+activeKey} />
</Col>
))}
</Row>
) : (
<div className={styles['myCoupon-loading']}>
<Spin />
</div>
)}
</div>
</PageHeaderWrapper>
);
};
export default MyCoupon;
/**
* 未使用
*/
export const COUPON_STATE_UNUSED = 1;
/**
* 已使用
*/
export const COUPON_STATE_USED = 2;
/**
* 已过期
*/
export const COUPON_STATE_EXPIRED = 3;
\ No newline at end of file
......@@ -79,7 +79,7 @@ const ReadyDistributionOrder:React.FC<ReadyDistributionOrderProps> = (props) =>
}}
formilyChilds={{
children: <Space>
<Button onClick={handleBitchPush} loading={loading}>{intl.formatMessage({ id: 'purchaseOrder.piliangtijiao', defaultMessage: '批量提交' })}</Button>
<Button onClick={handleBitchPush} loading={loading}>{intl.formatMessage({ id: 'purchaseOrder.pilianglingqu', defaultMessage: '批量领取' })}</Button>
</Space>,
layouts: {
span: 8
......
......@@ -19,7 +19,7 @@ export const useSelfTable = () => {
align: 'center',
dataIndex: 'ctl',
key: 'ctl',
render: (text, record) => <Button type='link' onClick={() => handleSubmit(record.orderId)}>{intl.formatMessage({ id: 'purchaseOrder.tijiaodingdan', defaultMessage: '提交订单' })}</Button>
render: (text, record) => <Button type='link' onClick={() => handleSubmit(record.orderId)}>{intl.formatMessage({ id: 'purchaseOrder.lingqu', defaultMessage: '领取' })}</Button>
}
])
......
......@@ -79,7 +79,7 @@ const ReadyDistributionOrder:React.FC<ReadyDistributionOrderProps> = (props) =>
}}
formilyChilds={{
children: <Space>
<Button onClick={handleBitchPush} loading={loading}>{intl.formatMessage({ id: 'purchaseOrder.piliangtijiao', defaultMessage: '批量提交' })}</Button>
<Button onClick={handleBitchPush} loading={loading}>{intl.formatMessage({ id: 'purchaseOrder.pilianglingqu', defaultMessage: '批量领取' })}</Button>
</Space>,
layouts: {
span: 8
......
......@@ -19,7 +19,7 @@ export const useSelfTable = () => {
align: 'center',
dataIndex: 'ctl',
key: 'ctl',
render: (text, record) => <Button type='link' onClick={() => handleSubmit(record.orderId)}>{intl.formatMessage({ id: 'purchaseOrder.tijiaodingdan', defaultMessage: '提交订单' })}</Button>
render: (text, record) => <Button type='link' onClick={() => handleSubmit(record.orderId)}>{intl.formatMessage({ id: 'purchaseOrder.lingqu', defaultMessage: '领取' })}</Button>
}
])
......
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