Commit 69acfb9e authored by Bill's avatar Bill

添加结算管理

parent 13c32d69
/*
* @Author: Bill
* @Date: 2020-10-22 15:05:27
* @Description: 平台结算管理
*/
const router = {
path: '/balanced',
name: 'balanced',
icon: 'SmileOutlined',
key: 'balanced',
routes: [
// 平台对公账号账号配置
{
path: '/balanced/corporateAccount',
name: 'corporateAccount',
component: '@/pages/platformSettlement/corporateAccount'
},
// 发票信息管理
{
path: '/balanced/receipt',
name: 'receipt',
component: '@/pages/platformSettlement/receipt'
},
{
path: '/balanced/receipt/add',
name: 'receiptAdd',
component: '@/pages/platformSettlement/receipt/info',
hidePageHeader: true
},
{
path: '/balanced/receipt/detail',
name: 'receiptDetail',
component: '@/pages/platformSettlement/receipt/info',
hidePageHeader: true
}
]
}
export default router;
/*
* @Author: LeeJiancong
* @Date: 2020-08-04 15:47:40
* @LastEditors: XieZhiXiong
* @LastEditTime: 2020-10-21 14:48:29
*/
/**
......@@ -20,7 +18,8 @@ import ruleSettingRoutes from './ruleSettingRoutes'
import authConfig from './authConfig'
import rfqRoute from './rfqRoute' // 询价单路由
import commentRoutes from './commentRoutes';
import contentRoute from './contentRoute';
import contentRoute from './contentRoute'; // 内容管理
import balancedRoute from './balancedRoute'; // 平台结算管理
const routeList = [
pageCustomized,
calssPropertyRoute,
......@@ -33,6 +32,7 @@ const routeList = [
authConfig,
commentRoutes,
contentRoute,
balancedRoute
]
const router = [
{
......
......@@ -2,7 +2,7 @@
* @Author: LeeJiancong
* @Date: 2020-08-04 15:05:52
* @LastEditors: Please set LastEditors
* @LastEditTime: 2020-10-20 18:29:21
* @LastEditTime: 2020-10-22 15:46:18
*/
import utils from '@/utils'
import menu from '../en-US/menu'
......@@ -169,5 +169,13 @@ export default {
'menu.orderSystem.orderSystemDetail': '订单详情',
'menu.orderSystem.readyConfirmPayList': '待确认支付订单',
'menu.orderSystem.readyConfirmPayDetail': '待确认支付订单',
// 平台结算管理
'menu.balanced': '结算管理',
'menu.balanced.corporateAccount': '对公账号配置',
'menu.balanced.receipt': '发票管理',
'menu.balanced.receiptAdd': '新建发票',
'menu.balanced.receiptDetail': '发票详情'
}
// export default utils.transformDataPre(data, 'menu')
/*
* @Author: your name
* @Date: 2020-10-21 15:59:41
* @desc:确认对账完成
*/
import React from 'react';
const ConfirmAccount = () => {
return (
<div>
<h3 style={{margin: 0}}>是否确认以下对账已完成?</h3>
<div style={{margin: '24px 0'}}>
<span style={{color: '#909399', width: '60px', display: 'inline-block'}}>结算日期:</span>
<span>2020-08-25</span>
</div>
<div>
<span style={{color: '#909399', width: '60px', display: 'inline-block'}}>付款方:</span>
<span>平台</span>
</div>
</div>
)
}
export default ConfirmAccount
\ No newline at end of file
import React, { Component } from 'react';
class ModalContainer extends Component {
state = {
visible: false
}
handleCancel = () => {
this.setState({
visible: false
})
}
show = () => {
this.setState({
visible: true
})
}
render() {
const { visible } = this.state;
const { children } = this.props;
return (
children({
visible: visible,
show: this.show,
cancel: this.handleCancel
})
)
}
}
export default ModalContainer;
\ No newline at end of file
/*
* @Author: your name
* @Date: 2020-10-20 16:25:45
* @Description: switch 组件
*/
import React, { useEffect } from 'react';
import { Radio } from 'antd';
const SchemaRadio = (props) => {
const editable = props.editable;
const componentProps = props.props["x-component-props"];
const options = componentProps.enum
const handleChange = (checked) => {
props.mutators.change(checked)
}
useEffect(() => {
const componentProps = props.props['x-component-props'] || {};
const defaultValue = componentProps.default || {};
if(typeof props.initialValue == 'undefined') {
props.mutators.change(defaultValue)
} else {
props.mutators.change(props.initialValue)
}
}, [props.initialValue])
return (
<Radio.Group onChange={handleChange} value={props.value || componentProps.default}>
{
options.map((item) => {
return (
<Radio value={item.value} key={item.value}>{item.label}</Radio>
)
})
}
</Radio.Group>
)
}
SchemaRadio.isFieldComponent = true;
export default SchemaRadio
\ No newline at end of file
/*
* @Author: your name
* @Date: 2020-10-20 16:25:45
* @Description: switch 组件
*/
import React from 'react';
import { Switch } from 'antd';
const SchemaSwitch = (props) => {
const editable = props.editable;
const handleChange = (checked) => {
props.mutators.change(checked)
}
return (
<Switch disabled={!editable} checked={props.value} onChange={handleChange} />
)
}
SchemaSwitch.isFieldComponent = true;
export default SchemaSwitch
\ No newline at end of file
/*
* @Author: Bill
* @Date: 2020-10-21 18:13:06
* @Description: 上传付款凭证
*/
import React from 'react';
import Voucher from '../Voucher';
const UploadPayVoucher = () => {
return (
<div>
<div>
<span>账户名称</span>
<span>温州市隆昌皮具有限公司</span>
</div>
<div>
<span>银行账号</span>
<span>3214 454646 145 46 1231</span>
</div>
<div>
<span>开户行</span>
<span>中国建设银行广州市分行营业部</span>
</div>
<h1>上传支付凭证</h1>
<Voucher />
</div>
)
}
export default UploadPayVoucher;
\ No newline at end of file
.container {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
background: #FAFBFC;
border-radius: 4px;
color: @main-color;
font-size: 12px;
height: 32px;
padding: 0 10px;
.image {
width: 20px;
height: 20px;
margin-right: 15px;
.icon {
width: 100%;
height: 100%;
}
}
.view {
margin-left: auto;
}
}
\ No newline at end of file
/*
* @Author: Bill
* @Date: 2020-10-21 16:05:03
* @Description: 付款凭证
*/
import React from 'react';
import styles from './index.less'
import image_icon from '@/assets/imgs/image_icon.png';
const Voucher = () => {
return (
<div className={styles.container}>
{/* <div></div>/ */}
<div className={styles.image}>
<img src={image_icon} className={styles.icon} />
</div>
<div className={styles.text}>20187878.jpg</div>
<div className={styles.view}>预览</div>
</div>
)
}
export default Voucher;
@margin-bottom: 24px;
@font-size: 14px;
@margin-right: 16px;
@color: #909399;
.container {
background: #fff;
margin-bottom: @margin-bottom;
padding: @margin-bottom;
.error {
margin: 0 66px;
color: #ff4d4f;
}
}
.item {
display: flex;
flex-direction: row;
align-items: center;
font-size: @font-size;
.image {
width: 48px;
height: 48px;
border-radius: 50%;
margin-right: @margin-right;
.img {
width: 100%;
height: 100%;
}
}
.itemName {
margin-right: @margin-right;
color: @color;
}
.itemValue {
margin-right: @margin-right;;
color: #303133;
}
.edit {
cursor: pointer;
}
}
\ No newline at end of file
import React, { useState, useEffect } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout'
import styles from './index.less'
import { FormOutlined } from '@ant-design/icons';
import { Button, Input, Space } from 'antd';
// import bank from '@/assets/imgs/bank.png';
// import bank_account from '@/assets/imgs/bank_account.png';
// import company from '@/assets/imgs/company.png';
import { PublicApi } from '@/services/api';
import { getAuth } from '@/utils/auth';
import { Prompt } from 'umi'
interface Config {
name: string,
image: any,
value: string,
isEdit: boolean,
canEdit: boolean,
cacheValue: string,
changeEdit?: any,
pattern?: any,
message?: string
}
const CONFIGS: Config[] = [
{
name: '账号名称',
image: null,
value: '',
cacheValue: '',
isEdit: false,
canEdit: false
},
{
name: '银行账号',
image: null,
value: '',
cacheValue: '',
isEdit: false,
canEdit: true,
pattern: /^([1-9]{1})(\d{14}|\d{18})$/,
message: '请输入正确的银行账号'
},
{
name: '开户行',
image: null,
value: '',
cacheValue: '',
isEdit: false,
canEdit: true,
pattern: /^[\u4e00-\u9fa5]{0,50}|[0-9a-zA-Z]{0,100}$/,
message: '最多50个汉字'
},
]
const ItemRender: React.FC<Config> = (props) => {
const { isEdit, name, canEdit, value, image, changeEdit, pattern, message } = props;
const [validError, setValidError] = useState(false);
// const [inputValue, setInputValue] = useState(value);
const handleClick = (name:string) => {
changeEdit(name, { isEdit: true }, 'change')
}
// 内容修改
const handleChange = (value:string, name: string) => {
if(!pattern.test(value)) {
setValidError(true)
} else {
setValidError(false)
}
changeEdit(name, {value: value}, 'change')
}
// 取消按钮
const handleCancel = (name: string) => {
setValidError(false);
changeEdit(name, { isEdit: false }, 'cancel')
}
// 确定提交
const handleConfirm = (name: string) => {
if(validError) {
return
}
changeEdit(name, { isEdit: false }, 'confirm');
}
return (
<div className={styles.container}>
<div className={styles.item}>
<div className={styles.image}>
<img src={image} className={styles.img} />
</div>
<div className={styles.itemName}>{name}</div>
<div className={styles.itemValue}>
{isEdit ? <Input value={value} style={{width: '300px'}} onChange={(e) => handleChange(e.target.value, name)}/> : value}
</div>
{
canEdit
? !isEdit
? <div className={styles.edit} style={{width: '300px'}} onClick={() => handleClick(name)} >
<FormOutlined />
</div>
: <div>
<Space>
<Button type="primary" onClick={() => handleConfirm(name)} >确定</Button>
<Button onClick={() => handleCancel(name)}>取消</Button>
</Space>
</div>
: null
}
</div>
<div className={styles.error}>{validError ? message : ''}</div>
</div>
)
}
const CorporateAccount = () => {
const [configs, setConfigs] = useState<Config[]>(CONFIGS);
const [unsaved, setUnsaved] = useState<Boolean>(false)
const changeEdit = (name: string, res: any, type: string) => {
let temp = [...configs];
const index = temp.findIndex((row) => row.name === name);
const target = temp[index];
if(type == 'change') {
setUnsaved(true);
temp[index] = {
...target,
...res,
}
} else if(type == 'cancel') {
setUnsaved(false);
temp[index] = {
...target,
...res,
value: type == 'cancel' ? target.cacheValue : target.value,
}
} else if(type == 'confirm') {
setUnsaved(false);
temp[index] = {
...target,
...res,
cacheValue: type == 'confirm' ? target.value : target.cacheValue
}
}
setConfigs(temp);
}
useEffect(() => {
const { memberId } = getAuth() || {};
// 进行基础赋值, fetchData
// async function fetchData() {
// const res = await PublicApi.getSettleAccountsCorporateAccountConfig({memberId: memberId});
// console.log(res);
// }
// fetchData();
}, [])
return (
<div>
{
configs.map((item: Config, key) => {
return (
<ItemRender key={item.name} {...item} changeEdit={changeEdit} />
)
})
}
<Prompt when={unsaved} message="信息还未保存,确定离开吗?"></Prompt>
</div>
)
}
export default CorporateAccount
\ No newline at end of file
.item {
background-color: #fff;
padding: 36px 24px;
font-size: 12px;
position: relative;
.row {
margin-bottom: 24px;
}
.controller {
position: absolute;
top: 20px;
right: 24px;
display: flex;
flex-direction: row;
align-items: center;
font-size: 15px;
.edit {
margin-right: 12px;
cursor: pointer;
}
.remove {
cursor: pointer;
}
}
}
.margin {
margin-bottom: 24px;
}
.add {
height: 100%;
min-height: 352px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: #FAFBFC;
border-radius: 2px;
border: 1px solid #DCDFE6;
cursor: pointer;
}
\ No newline at end of file
/*
* @Author: Bill
* @Date: 2020-10-19 11:53:43
* @desc 发票管理 发票列表
*/
import React, { useState, useEffect } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Row, Col, Switch, Popconfirm } from 'antd';
import { FormOutlined, DeleteOutlined, PlusOutlined } from '@ant-design/icons'
import styles from './index.less';
import { history, Link } from 'umi';
import { PublicApi } from '@/services/api'
interface iProps {
}
enum Kind {
common = 1, // 增值税普通发票(默认
special = 2 // 增值税专用发票
}
enum ItemIpropType {
business = 1, //企业
person = 2 // 个人
}
interface ReceiptProps {
id: number,
kind: Kind,
type: ItemIpropType,
invoiceTitle: string,
taxNo: string,
bankOfDeposit: string,
account: string,
addres: string,
tel: string
isDefault: number
}
interface ItemIprops extends ReceiptProps {
onRemove: (id: number | string) => Promise<void>,
}
/**
* 每个发票Item
* @param props ItemIprops
*/
const ReceiptItem: React.FC<ItemIprops> = (props: ItemIprops) => {
const { id, kind, type, invoiceTitle, taxNo, bankOfDeposit, account, addres, tel, isDefault } = props;
const handleRouterPush = () => {
history.push(`/balance/receipt/detail?id=${id}`);
}
const handleDelete = (id: number | string) => {
props.onRemove(id);
}
return (
<div className={styles.item}>
<div className={styles.controller}>
<div className={styles.edit} onClick={handleRouterPush}><FormOutlined /></div>
<div className={styles.remove}>
<Popconfirm
title="确定删除这条信息吗?"
onConfirm={() => handleDelete(id)}
okText="确定"
cancelText="取消"
>
<DeleteOutlined />
</Popconfirm>
</div>
</div>
<Row className={styles.row}>
<Col span={6}>开具类型</Col>
<Col span={18}>{type == 1 ? '企业' : '个人'}</Col>
</Row>
<Row className={styles.row}>
<Col span={6}>发票种类</Col>
<Col span={18}>{kind == 1 ? '增值税普通发票' : '增值税专用发票'}</Col>
</Row>
<Row className={styles.row}>
<Col span={6}>发票抬头</Col>
<Col span={18}>{invoiceTitle}</Col>
</Row>
<Row className={styles.row}>
<Col span={6}>纳税号</Col>
<Col span={18}>{taxNo}</Col>
</Row>
<Row className={styles.row}>
<Col span={6}>账号</Col>
<Col span={18}>{account}</Col>
</Row>
<Row className={styles.row}>
<Col span={6}>开户行</Col>
<Col span={18}>{bankOfDeposit}</Col>
</Row>
<Row className={styles.row}>
<Col span={6}>地址</Col>
<Col span={18}>{addres}</Col>
</Row>
<Row className={styles.row}>
<Col span={6}>电话</Col>
<Col span={18}>{tel}</Col>
</Row>
<Row>
<Col span={6}>是否默认</Col>
<Col span={18}><Switch disabled checked={isDefault ? true : false}/></Col>
</Row>
</div>
)
}
/**
* 发票列表
*/
const Receipt: React.FC<iProps> = () => {
const [list, setList] = useState<ReceiptProps[]>([]);
const fetchData = async () => {
// /settle/platform/config/getPlatformInvoiceList
// const { data } = await PublicApi.getSettlePlatformConfigGetPlatformInvoiceList();
// return data;
return []
}
useEffect(() => {
fetchData().then((data) => {
setList(data);
})
}, [])
const handleRouterAdd = () => {
history.push('/balance/receipt/add')
}
// 删除发票
const remove = async (id: number | string) => {
console.log(id);
// const res = await PublicApi.postSettleAccountsInvoiceMessageDelete({id});
// if(res.code == 1000) {
// const newList = list.filter((item) => item.id !== id);
// setList(newList);
// }
}
return (
<div>
<Row gutter={24}>
{
list.map((item) => {
return (
<Col span={8} key={item.id} className={styles.margin}>
<ReceiptItem onRemove={remove} {...item}/>
</Col>
)
})
}
<Col span={8} className={styles.margin}>
<div className={styles.add} onClick={handleRouterAdd}>
<div>
<PlusOutlined />
</div>
<div>新建发票</div>
</div>
</Col>
</Row>
</div>
)
}
export default Receipt
\ No newline at end of file
/*
* @Author: Bill
* @Date: 2020-10-19 15:51:44
* @Description: 结算规则配置 -> 发票管理 -> 新增发票 / 修改发票
*/
import React, { useState, useEffect } from 'react';
import NiceForm from '@/components/NiceForm';
import { createFormActions, FormButtonGroup, Submit, Reset } from '@formily/antd';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Card, Switch, Button } from 'antd';
import SchemaSwitch from '../components/SchemaSwitch';
import SchemaRadio from '../components/SchemaRadio';
import { PublicApi } from '@/services/api';
import { usePageStatus } from '@/hooks/usePageStatus';
import { history, Prompt } from 'umi';
const formActions = createFormActions();
const schema = {
type: 'object',
properties: {
layout: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
labelCol: 4,
wrapperCol: 8,
labelAlign: 'left',
},
properties: {
type: {
type: 'string',
title: '开具类型',
'x-component': 'SchemaRadio',
'x-component-props': {
default: 1,
enum: [
{label: '企业(默认)', value: 1},
{label: '个人', value: 2},
],
},
'x-rules': [
{required: true, message: '请选择发货人'}
]
},
kind: {
type: 'string',
title: '发票种类',
'x-component': 'SchemaRadio',
'x-component-props': {
default: 1,
enum: [
{label: '增值税普通发票(默认)', value: 1},
{label: '增值税专用发票', value: 2}
],
},
'x-rules': [
{required: true, message: '请选择发票种类'}
]
},
invoiceTitle: {
type: 'string',
title: '发票抬头',
'x-rules': [
{required: true, message: '请填写发票抬头'},
{limitByte: true, maxByte: 40 }
],
},
taxNo: {
type: 'string',
title: '纳税号',
'x-rules': [
{required: true, message: '请填写纳税号'},
{limitByte: true, maxByte: 20, allowChineseTransform: false }
]
},
bankOfDeposit: {
type: 'string',
title: '开户行',
'x-rules': [
{limitByte: true, maxByte: 40 }
]
},
account: {
type: 'string',
title: '账号',
'x-rules': [
{pattern: /^([1-9]{1})(\d{14}|\d{18})$/, message: '请填写正确的银行账号'}
]
},
addres: {
type: 'text',
title: '地址',
'x-component': 'textarea',
'x-rules': [
{limitByte: true, maxByte: 80 }
]
},
tel: {
type: 'string',
title: '电话号码',
'x-rules': [
{limitByte: true, maxByte: 80 },
{pattern: /^0\d{2,3}-?\d{7,8}$/, message: '请填写正确的电话号码'}
]
},
isDefault: {
type: 'object',
title: '是否默认',
'x-component': 'SchemaSwitch'
},
}
}
}
}
const Info: React.FC = () => {
const [initialValue, setInitialValue] = useState({});
const { id, preview } = usePageStatus();
const [submitLoading, setSubmitLoading ] = useState(false);
const [unsaved, setUnsaved] = useState(true);
const isEdit = id && !preview;
const isAdd = !id && !preview;
const isView = id && preview;
const handleSubmit = (value) => {
console.log(value);
// return value;
const serviceActions = isAdd
? PublicApi.postSettleAccountsInvoiceMessageAdd
: PublicApi.postSettleAccountsInvoiceMessageUpdate
let tempData = {...value, isDefault: value.isDefault ? 1 : 0};
const postData = isAdd ? tempData : {...tempData, id};
setSubmitLoading(true);
setUnsaved(false);
serviceActions(postData).then((data) => {
setSubmitLoading(false);
if(data.code === 1000) {
history.push('/memberCenter/balance/settleRules/receiptList')
}
})
}
useEffect(() => {
if(id) {
async function fetchData() {
const { data } = await PublicApi.getSettleAccountsInvoiceMessageDetails({id});
setInitialValue(data)
}
fetchData()
}
;
}, [id])
const handleCancel = () => {
history.push('/memberCenter/balance/settleRules/receiptList')
}
return (
<PageHeaderWrapper>
<Card>
<NiceForm
components={{SchemaSwitch, SchemaRadio}}
actions={formActions}
initialValues={initialValue}
expressionScope={{}}
onSubmit={handleSubmit}
schema={schema}
>
<FormButtonGroup offset={4}>
<Submit loading={submitLoading}>提交</Submit>
<Button onClick={handleCancel}>取消</Button>
</FormButtonGroup>
</NiceForm>
</Card>
<Prompt when={unsaved} message={"内容未保存,确定要离开?"} />
</PageHeaderWrapper>
)
}
export default Info
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