Commit a53c3146 authored by 郭志伟's avatar 郭志伟

Merge branch 'feature-afterSalesRefund' into 'master'

feat: 售后全流程

See merge request !69
parents 8ebe9dd6 8e6792d0
......@@ -146,6 +146,13 @@ export default {
icon: 'smile',
component: './AfterSaleManage/index',
},
{
title: '商户管理后台',
path: '/afterSalesClaimForm',
name: 'afterSalesClaimForm',
icon: 'smile',
component: './AfterSalesClaimForm/index',
},
{
title: '商户管理后台',
path: '/afterSaleManageOld',
......
const isProduction = process.env.NODE_ENV === 'production';
const isPre = process.env.PRE_ENV === 'pre';
const environment = 'xyqb';
const environment = 'yxm2';
const envAPi = {
api: `https://security-${environment}.liangkebang.net`, //'https://security-xyqb.liangkebang.net',
kdspOpApi: `https://sc-merchant-api-${environment}.liangkebang.net`,
......
import React, { useState, forwardRef, useImperativeHandle } from 'react';
import { Form } from '@ant-design/compatible';
import { Modal, Button } from 'antd';
// 0: 待财务审核
// 1: 审核通过
// 2: 审核拒绝,
const ExamineFormModal = forwardRef((props, ref) => {
const { form, claimVisible, closeClaimDescription, refresh } = props;
const [detailData, setDetailData] = useState({});
useImperativeHandle(ref, () => ({
setDetailData,
...form,
}));
const onCancelEvent = () => {
closeClaimDescription();
};
const footerButton = [
<Button type="primary" key="cancel" onClick={onCancelEvent}>
关闭
</Button>,
];
return (
<Modal
title="赔款说明"
centered
visible={claimVisible}
footer={detailData.audit ? footerButton : null}
bodyStyle={{ padding: '12px 0' }}
onCancel={onCancelEvent}
></Modal>
);
});
export default Form.create()(ExamineFormModal);
import React, { useState, useRef, useEffect } from 'react';
import ProTable from '@ant-design/pro-table';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Button, Image } from 'antd';
import { saveAs } from 'file-saver';
import { columnsConfig, getLastItem, checkImage } from './staticdata';
import { getQueryClamsList } from './service';
import ClaimDescription from './ClaimDescription';
/**
* 售后赔款单
* 售后赔款单
* @param {*} router options
* @returns ReactDOM
*/
const AfterSalesClaimForm = ({ route }) => {
const ref = useRef();
const actionRef = useRef();
const [claimVisible, setclaimVisible] = useState(false);
const [claimLoading, setclaimLoading] = useState(false);
const [imagePreView, setImagePreView] = useState({
src: '',
visible: false,
});
const search = {
collapsed: false,
collapseRender: () => null,
};
const query = async params => {
const { createdAt, singleType, singleNumber, current: pageNo, ...other } = params;
const queryParams = { ...other, pageNo };
if (singleType && singleNumber) {
if (+singleType === 0) queryParams.id = singleNumber;
if (+singleType === 1) queryParams.orderNo = singleNumber;
}
if (createdAt?.length) {
const [startTime, endTime] = createdAt;
queryParams.startTime = startTime;
queryParams.endTime = endTime;
}
const { data } = await getQueryClamsList(queryParams);
return {
total: data.total,
data: data?.records,
};
};
const openSetclaimModal = async (row, audit) => {
setclaimLoading(true);
setclaimVisible(true);
setclaimLoading(false);
};
const closeClaimDescription = () => {
setclaimVisible(false);
};
const refreshTable = () => {
ref.current.reload();
};
// eslint-disable-next-line consistent-return
const downLoadFile = async url => {
if (await checkImage(url)) {
setImagePreView({ src: url, visible: true });
return null;
}
saveAs(url, getLastItem(url));
};
// const toolBarRender = () => [
// <Button type="link" onClick={openSetclaimModal}>
// 赔款说明
// </Button>,
// ];
// toolBarRender={toolBarRender}
const onReset = () => {};
return (
<PageHeaderWrapper>
<ProTable
bordered
loading={claimLoading}
type="cardList"
request={query}
tableClassName="capital"
columns={columnsConfig({ downLoadFile })}
rowKey={row => row.id}
search={search}
options={false}
actionRef={ref}
pagination={{ pageSize: 10 }}
onReset={onReset}
scroll={{ x: '100%', y: 430 }}
/>
<ClaimDescription
refresh={refreshTable}
claimVisible={claimVisible}
wrappedComponentRef={actionRef}
closeClaimDescription={closeClaimDescription}
/>
<Image
width={200}
style={{ display: 'none' }}
src={imagePreView.src}
preview={{
visible: imagePreView.visible,
scaleStep: '1',
src: imagePreView.src,
onVisibleChange: value => {
setImagePreView({
src: '',
visible: false,
});
},
}}
/>
</PageHeaderWrapper>
);
};
export default AfterSalesClaimForm;
import request from '@/utils/request';
import config from '@/../config/env.config';
export const getQueryClamsList = params =>
request.post('/api/kdsp/queryClams', {
prefix: config.goodsApi,
data: params || {},
});
import React from 'react';
import { Image as ImageComponent, Button } from 'antd';
export const getLastItem = thePath => thePath.substring(thePath.lastIndexOf('/') + 1);
export const isImageType = url => {
const index = url.lastIndexOf('.');
const ext = url.substr(index + 1);
return ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp', 'psd', 'svg', 'tiff'].includes(
ext.toLowerCase(),
);
};
export const checkImage = url =>
new Promise(resolve => {
const image = new Image();
image.onload = () => {
resolve(true);
};
image.onerror = () => {
resolve(false);
};
image.src = url;
});
const csListStyle = {
color: '#1890FF',
textAlign: 'left',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden',
cursor: 'pointer',
};
export const typeConfig = {
1: {
text: '退运费',
},
2: {
text: '商品破损',
},
};
const singleNumberSearch = {
0: {
text: '赔款单号',
},
1: {
text: '订单编号',
},
};
export const columnsConfig = props => [
{
title: '单号搜索',
key: 'singleType',
dataIndex: 'singleType',
hideInTable: true,
valueEnum: singleNumberSearch,
},
{
key: 'singleNumber',
dataIndex: 'singleNumber',
hideInTable: true,
},
{
title: '赔款单号',
key: 'id',
dataIndex: 'id',
align: 'center',
hideInSearch: true,
},
{
title: '订单号',
key: 'orderNo',
dataIndex: 'orderNo',
align: 'center',
hideInSearch: true,
},
{
title: '赔款金额',
key: 'amount',
dataIndex: 'amount',
align: 'center',
width: 100,
hideInSearch: true,
},
{
title: '赔款类型',
key: 'type',
dataIndex: 'type',
align: 'center',
valueEnum: typeConfig,
},
{
title: '索赔原因',
key: 'reason',
dataIndex: 'reason',
align: 'center',
hideInSearch: true,
},
{
title: '退款说明',
key: 'remark',
dataIndex: 'remark',
align: 'center',
ellipsis: true,
hideInSearch: true,
},
{
title: '创建时间',
key: 'createdAt',
dataIndex: 'createdAt',
align: 'center',
valueType: 'dateRange',
},
{
title: '用户凭证',
key: 'proof',
dataIndex: 'proof',
align: 'center',
width: 190,
hideInSearch: true,
render: value =>
(value.userList || []).map(item => (
<ImageComponent style={{ paddingLeft: 5, marginTop: 5 }} key={item} width={50} src={item} />
)),
},
{
title: '审核意见',
key: 'proof',
dataIndex: 'proof',
align: 'center',
width: 190,
hideInSearch: true,
render: value =>
(value.csList || []).map(item => (
<div style={csListStyle} onClick={() => props.downLoadFile(item)}>
{item}
</div>
)),
},
];
......@@ -2,6 +2,7 @@ import { Upload, Icon, Modal, message, Button, notification } from 'antd';
import React, { useState, useEffect } from 'react';
import config from '../../../../config/env.config';
import styles from '../style.less';
import UUID from '../../../utils/uuid';
import { qiniuToken } from '@/services/qiniu';
const qiniu = require('@/utils/qiniu.min.js');
......@@ -60,7 +61,7 @@ class PicturesWall extends React.Component {
}
const vm = this;
// eslint-disable-next-line new-cap
const data = `${filename}-${new Date().getTime()}.${suffix}`;
const data = `${UUID.createUUID()}.${suffix}`;
const observable = qiniu.upload(file, data, token);
const observer = {
next() {
......
......@@ -104,8 +104,14 @@ export function columns(res, pages) {
align: 'center',
},
{
title: '蓝字金额',
title: () => (
<div style={{ textAlign: 'center' }}>
<div>蓝字金额</div>
<div style={{ color: '#f00' }}>(开票金额)</div>
</div>
),
dataIndex: 'currentRefundAmount',
key: 'currentRefundAmount',
width: '100px',
hideInSearch: true,
align: 'center',
......@@ -113,9 +119,16 @@ export function columns(res, pages) {
{
title: '应付金额',
dataIndex: 'payableAmount',
width: '100px',
width: '140px',
hideInSearch: true,
align: 'center',
render: (value, row) => (
<div>
<div>{row.payableAmount}</div>
<div style={{ color: '#f00' }}>赔付 ({row.claimAmount})</div>
<div>(实付 {row.needPayAmount})</div>
</div>
),
},
{
title: '是否缺少红字发票',
......
......@@ -68,6 +68,15 @@ export function columns(pages) {
width: '100px',
hideInSearch: true,
align: 'center',
render: (value, row) => {
const msg = row.billType === 20 ? <div>包含赔付金额</div> : null;
return (
<div>
<div>{value}</div>
{msg}
</div>
);
},
},
{
title: '笔数',
......@@ -75,6 +84,15 @@ export function columns(pages) {
width: '100px',
hideInSearch: true,
align: 'center',
render: (value, row) => {
const msg = row.billType === 20 ? <div>包含赔付笔数</div> : null;
return (
<div>
<div>{value}</div>
{msg}
</div>
);
},
},
{
title: '状态',
......
......@@ -97,6 +97,12 @@ export function columns(pages) {
width: '100px',
hideInSearch: true,
align: 'center',
render: (value, row) => (
<div>
<div>{value}</div>
<div style={{ color: '#f00' }}>(赔付{row.claimAmount})</div>
</div>
),
},
{
title: '结算金额',
......
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