Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
merchant-manage-ui
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ui
merchant-manage-ui
Commits
17b8b15c
Commit
17b8b15c
authored
Oct 18, 2022
by
李腾
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 完善消息提醒业务逻辑
parent
e2eb48fd
Changes
33
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
2362 additions
and
10 deletions
+2362
-10
config.js
config/config.js
+7
-0
env.config.js
config/env.config.js
+8
-4
index.jsx
src/components/FormSearch/index.jsx
+177
-0
index.less
src/components/FormSearch/index.less
+32
-0
MessageIcon.jsx
src/components/GlobalHeader/MessageIcon.jsx
+33
-0
RightContent.jsx
src/components/GlobalHeader/RightContent.jsx
+4
-1
index.less
src/components/GlobalHeader/index.less
+21
-0
index.jsx
src/components/MessageReminder/Complex/index.jsx
+136
-0
index.less
src/components/MessageReminder/Complex/index.less
+58
-0
index.jsx
src/components/MessageReminder/Empty/index.jsx
+17
-0
index.less
src/components/MessageReminder/Empty/index.less
+11
-0
index.jsx
src/components/MessageReminder/Simple/index.jsx
+192
-0
index.less
src/components/MessageReminder/Simple/index.less
+169
-0
index.jsx
src/components/MessageReminder/index.jsx
+9
-0
global.less
src/global.less
+16
-0
BasicLayout.jsx
src/layouts/BasicLayout.jsx
+52
-3
messageReminder.js
src/models/messageReminder.js
+49
-0
index.jsx
src/pages/Admin/index.jsx
+10
-0
AfterLog.jsx
src/pages/AfterSaleManageNew/components/AfterLog.jsx
+38
-0
auditModal.jsx
src/pages/AfterSaleManageNew/components/auditModal.jsx
+243
-0
detailTable.jsx
src/pages/AfterSaleManageNew/components/detailTable.jsx
+29
-0
proofsModal.jsx
src/pages/AfterSaleManageNew/components/proofsModal.jsx
+43
-0
rejectModal.jsx
src/pages/AfterSaleManageNew/components/rejectModal.jsx
+61
-0
data.js
src/pages/AfterSaleManageNew/data.js
+377
-0
index.jsx
src/pages/AfterSaleManageNew/index.jsx
+220
-0
index.less
src/pages/AfterSaleManageNew/index.less
+37
-0
services.js
src/pages/AfterSaleManageNew/services.js
+104
-0
storeModal.jsx
src/pages/chainStoreManage/components/storeModal.jsx
+1
-0
index.jsx
src/pages/orderManage/pendingDeliveryOrder/index.jsx
+33
-2
index.less
src/pages/orderManage/pendingDeliveryOrder/index.less
+21
-0
messageReminder.js
src/services/messageReminder.js
+40
-0
constants.js
src/utils/constants.js
+1
-0
websocket.js
src/utils/websocket.js
+113
-0
No files found.
config/config.js
View file @
17b8b15c
...
@@ -146,6 +146,13 @@ export default {
...
@@ -146,6 +146,13 @@ export default {
icon
:
'
smile
'
,
icon
:
'
smile
'
,
component
:
'
./AfterSaleManage/index
'
,
component
:
'
./AfterSaleManage/index
'
,
},
},
{
title
:
'
商户管理后台
'
,
path
:
'
/afterSaleManageNew
'
,
name
:
'
afterSaleManageNew
'
,
icon
:
'
smile
'
,
component
:
'
./AfterSaleManageNew/index
'
,
},
{
{
title
:
'
商户管理后台
'
,
title
:
'
商户管理后台
'
,
path
:
'
/auditPending
'
,
path
:
'
/auditPending
'
,
...
...
config/env.config.js
View file @
17b8b15c
...
@@ -2,10 +2,10 @@ const isProduction = process.env.NODE_ENV === 'production';
...
@@ -2,10 +2,10 @@ const isProduction = process.env.NODE_ENV === 'production';
const
isPre
=
process
.
env
.
PRE_ENV
===
'
pre
'
;
const
isPre
=
process
.
env
.
PRE_ENV
===
'
pre
'
;
const
envAPi
=
{
const
envAPi
=
{
api
:
'
https://security-
xyqb
.liangkebang.net
'
,
//'https://security-xyqb.liangkebang.net',
api
:
'
https://security-
sc
.liangkebang.net
'
,
//'https://security-xyqb.liangkebang.net',
kdspOpApi
:
'
https://sc-merchant-api-
xyqb
.liangkebang.net
'
,
kdspOpApi
:
'
https://sc-merchant-api-
sc
.liangkebang.net
'
,
kdspApi
:
'
https://sc-merchant-api-
xyqb
.liangkebang.net
'
,
kdspApi
:
'
https://sc-merchant-api-
sc
.liangkebang.net
'
,
goodsApi
:
'
https://sc-merchant-api-
xyqb
.liangkebang.net
'
,
goodsApi
:
'
https://sc-merchant-api-
sc
.liangkebang.net
'
,
// kdspOpApi: 'https://kdsp-operation-xyqb.liangkebang.net',
// kdspOpApi: 'https://kdsp-operation-xyqb.liangkebang.net',
// kdspApi: 'https://sc-op-api-xyqb.liangkebang.net',
// kdspApi: 'https://sc-op-api-xyqb.liangkebang.net',
// goodsApi: 'https://sc-op-api-xyqb.liangkebang.net',
// goodsApi: 'https://sc-op-api-xyqb.liangkebang.net',
...
@@ -15,6 +15,8 @@ const envAPi = {
...
@@ -15,6 +15,8 @@ const envAPi = {
// qiniuHost: 'https://appsync.lkbang.net',
// qiniuHost: 'https://appsync.lkbang.net',
qiniuHost
:
'
https://kdspstatic.q-gp.com/
'
,
qiniuHost
:
'
https://kdspstatic.q-gp.com/
'
,
opapiHost
:
'
https://opapi-sc.liangkebang.net
'
,
opapiHost
:
'
https://opapi-sc.liangkebang.net
'
,
wsApi
:
'
ws://ws-sc.liangkebang.net
'
,
msgApi
:
'
https://msgapi-sc.liangkebang.net
'
,
};
};
const
prodApi
=
{
const
prodApi
=
{
...
@@ -30,6 +32,8 @@ const prodApi = {
...
@@ -30,6 +32,8 @@ const prodApi = {
// opapiHost: 'https://opapi.q-gp.com',
// opapiHost: 'https://opapi.q-gp.com',
// querysApi: 'https://sc-settlement-api.q-gp.com',
// querysApi: 'https://sc-settlement-api.q-gp.com',
querysApi
:
'
https://sc-merchant-api.q-gp.com/admin/merchant/sc-settlement
'
,
querysApi
:
'
https://sc-merchant-api.q-gp.com/admin/merchant/sc-settlement
'
,
wssApi
:
''
,
msgApi
:
'
https://msgapi.q-gp.com
'
,
};
};
const
preProdApi
=
{
const
preProdApi
=
{
...
...
src/components/FormSearch/index.jsx
0 → 100644
View file @
17b8b15c
import
React
from
'
react
'
;
import
{
Form
,
Input
,
Select
,
DatePicker
,
Button
,
Space
}
from
'
antd
'
;
import
{
moment
,
Moment
}
from
'
moment
'
;
import
style
from
'
./index.less
'
;
const
{
Option
}
=
Select
;
const
{
RangePicker
}
=
DatePicker
;
const
SEARCH_TYPE
=
{
SELECT
:
'
select
'
,
RANGE_PICKER
:
'
range_picker
'
,
INPUT
:
'
input
'
,
DATE_PICKER
:
'
date_picker
'
,
};
const
FormSearch
=
props
=>
{
const
{
width
=
'
100%
'
,
form
,
initialValues
=
{},
onFinish
=
()
=>
{},
formConfig
,
formOptions
,
btnConfig
,
}
=
props
;
const
FormItemBox
=
({
bindKey
,
label
,
column
,
children
,
afterRender
})
=>
{
const
columnValue
=
column
;
// if (afterRender) {
// columnValue = '';
// }
return
(
<
Form
.
Item
className=
{
style
[
'
custom-form-item
'
]
}
column=
{
columnValue
}
name=
{
bindKey
}
label=
{
label
}
>
{
children
}
</
Form
.
Item
>
);
};
// 下拉框类型
const
FormItemSelect
=
config
=>
{
const
{
bindKey
,
options
:
configOptions
=
[],
originOptions
=
{},
afterRender
=
null
,
afterOptions
=
{},
column
,
}
=
config
;
const
attrs
=
{
placeholder
:
'
请选择
'
,
...
originOptions
};
// 提取公共部分
const
BaseSelectElement
=
()
=>
(
<
FormItemBox
{
...
config
}
>
<
Select
name=
{
bindKey
}
className=
{
style
[
'
form-item-tag
'
]
}
{
...
attrs
}
>
{
configOptions
.
map
(
option
=>
(
<
Option
key=
{
option
.
value
}
value=
{
option
.
value
}
>
{
option
.
name
}
</
Option
>
))
}
</
Select
>
</
FormItemBox
>
);
if
(
afterRender
)
{
return
(
<>
{
/* // <div className={style['custom-form-item-group']}> */
}
<
BaseSelectElement
/>
<
FormItemBox
column=
{
column
}
{
...
afterOptions
}
>
{
afterRender
()
}
</
FormItemBox
>
{
/* // </div> */
}
</>
);
}
return
<
BaseSelectElement
/>;
};
// 选择日期范围类型
const
FormItemRangePicker
=
config
=>
{
const
{
originOptions
=
{}
}
=
config
;
const
attrs
=
{
placeholder
:
[
'
开始日期
'
,
'
结束日期
'
],
...
originOptions
};
return
(
<
FormItemBox
{
...
config
}
>
<
RangePicker
className=
{
style
[
'
form-item-tag
'
]
}
{
...
attrs
}
/>
</
FormItemBox
>
);
};
// 选择日期
const
FormItemDatePicker
=
config
=>
{
const
{
originOptions
=
{}
}
=
config
;
const
attrs
=
{
placeholder
:
'
请选择日期
'
,
...
originOptions
};
return
(
<
FormItemBox
{
...
config
}
>
<
DatePicker
className=
{
style
[
'
form-item-tag
'
]
}
{
...
attrs
}
/>
</
FormItemBox
>
);
};
// 多级联动
// 输入框类型
const
FormItemInput
=
config
=>
{
const
{
originOptions
=
{}
}
=
config
;
const
attrs
=
{
placeholder
:
'
请输入
'
,
...
originOptions
};
return
(
<
FormItemBox
{
...
config
}
>
<
Input
className=
{
style
[
'
form-item-tag
'
]
}
{
...
attrs
}
/>
</
FormItemBox
>
);
};
// 表单内容元素
const
FormItemElement
=
()
=>
formConfig
.
map
(
config
=>
{
const
{
type
}
=
config
;
switch
(
type
)
{
case
SEARCH_TYPE
.
SELECT
:
return
<
FormItemSelect
key=
{
config
.
bindKey
}
{
...
config
}
/>;
case
SEARCH_TYPE
.
RANGE_PICKER
:
return
<
FormItemRangePicker
key=
{
config
.
bindKey
}
{
...
config
}
/>;
case
SEARCH_TYPE
.
INPUT
:
return
<
FormItemInput
key=
{
config
.
bindKey
}
{
...
config
}
/>;
case
SEARCH_TYPE
.
DATE_PICKER
:
return
<
FormItemDatePicker
key=
{
config
.
bindKey
}
{
...
config
}
/>;
default
:
return
<></>;
}
});
/**
* @module 按钮操作
*/
const
FormItemButton
=
()
=>
(
<
Space
size=
{
10
}
>
{
btnConfig
.
map
(
config
=>
{
const
{
label
,
onClick
=
()
=>
{},
type
=
'
primary
'
,
clickType
=
'
search
'
}
=
config
;
const
htmlType
=
clickType
===
'
reset
'
?
'
reset
'
:
'
submit
'
;
const
callback
=
()
=>
{
setTimeout
(()
=>
{
onClick
({
type
:
clickType
,
params
:
form
.
getFieldValue
()
});
});
};
return
(
<
Button
key=
{
clickType
}
type=
{
type
}
htmlType=
{
htmlType
}
onClick=
{
callback
}
>
{
label
}
</
Button
>
);
})
}
</
Space
>
);
return
(
<
div
className=
{
style
[
'
form-search
'
]
}
>
<
Form
style=
{
{
width
}
}
layout=
"inline"
form=
{
form
}
initialValues=
{
initialValues
}
onFinish=
{
onFinish
}
{
...
formOptions
}
>
<
FormItemElement
></
FormItemElement
>
<
Form
.
Item
>
<
FormItemButton
></
FormItemButton
>
</
Form
.
Item
>
</
Form
>
</
div
>
);
};
export
{
FormSearch
,
SEARCH_TYPE
};
src/components/FormSearch/index.less
0 → 100644
View file @
17b8b15c
.form-search {
padding: 15px;
background: #fff;
}
.custom-form-item {
min-width: 320px;
margin-bottom: 20px !important;
&[column='1'] {
width: 100%;
}
&[column='2'] {
width: calc(50% - 16px);
}
&[column='3'] {
width: calc(33.3333% - 32px);
}
&[column='4'] {
width: calc(25% - 48px);
}
&[column='5'] {
width: calc(20% - 54px);
}
}
.form-item-tag {
width: 100%;
}
// .custom-form-item-group {
// display: flex;
// }
src/components/GlobalHeader/MessageIcon.jsx
0 → 100644
View file @
17b8b15c
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
{
Tag
,
message
,
Badge
}
from
'
antd
'
;
import
{
connect
}
from
'
dva
'
;
import
groupBy
from
'
lodash/groupBy
'
;
import
moment
from
'
moment
'
;
import
{
BellOutlined
}
from
'
@ant-design/icons
'
;
import
NoticeIcon
from
'
../NoticeIcon
'
;
import
styles
from
'
./index.less
'
;
const
GlobalHeaderRight
=
props
=>
{
const
{
messageReminderComplexRef
,
unReadCount
=
0
}
=
props
;
const
[
count
,
setCount
]
=
useState
(
0
);
const
open
=
()
=>
{
messageReminderComplexRef
.
current
.
open
();
};
useEffect
(()
=>
{
setCount
(
unReadCount
);
},
[
unReadCount
]);
return
(
<
span
className=
{
styles
[
'
badge-box
'
]
}
onClick=
{
open
}
>
<
Badge
count=
{
count
}
className=
{
styles
[
'
badge-box__self
'
]
}
>
<
BellOutlined
className=
{
styles
[
'
badge-box__icon
'
]
}
/>
</
Badge
>
</
span
>
);
};
export
default
connect
(({
messageReminder
})
=>
({
unReadCount
:
messageReminder
.
unReadCount
,
}))(
GlobalHeaderRight
);
src/components/GlobalHeader/RightContent.jsx
View file @
17b8b15c
import
{
Tooltip
}
from
'
antd
'
;
import
{
Tooltip
}
from
'
antd
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
NotificationOutlined
}
from
'
@ant-design/icons
'
;
import
{
connect
}
from
'
dva
'
;
import
{
connect
}
from
'
dva
'
;
import
Avatar
from
'
./AvatarDropdown
'
;
import
Avatar
from
'
./AvatarDropdown
'
;
import
HeaderSearch
from
'
../HeaderSearch
'
;
import
HeaderSearch
from
'
../HeaderSearch
'
;
import
styles
from
'
./index.less
'
;
import
styles
from
'
./index.less
'
;
import
MessageIcon
from
'
./MessageIcon
'
;
const
GlobalHeaderRight
=
props
=>
{
const
GlobalHeaderRight
=
props
=>
{
const
{
theme
,
layout
}
=
props
;
const
{
theme
,
layout
,
messageReminderComplexRef
}
=
props
;
let
className
=
styles
.
right
;
let
className
=
styles
.
right
;
if
(
theme
===
'
dark
'
&&
layout
===
'
topmenu
'
)
{
if
(
theme
===
'
dark
'
&&
layout
===
'
topmenu
'
)
{
...
@@ -15,6 +17,7 @@ const GlobalHeaderRight = props => {
...
@@ -15,6 +17,7 @@ const GlobalHeaderRight = props => {
return
(
return
(
<
div
className=
{
className
}
>
<
div
className=
{
className
}
>
<
MessageIcon
messageReminderComplexRef=
{
messageReminderComplexRef
}
/>
<
Avatar
/>
<
Avatar
/>
</
div
>
</
div
>
);
);
...
...
src/components/GlobalHeader/index.less
View file @
17b8b15c
...
@@ -132,3 +132,24 @@
...
@@ -132,3 +132,24 @@
}
}
}
}
}
}
// Badge
.badge-box {
display: inline-block;
height: 100%;
padding: 0 12px;
cursor: pointer;
transition: all 0.3s;
&:hover {
background-color: rgba(0, 0, 0, 0.025);
}
&__self {
font-size: 16px !important;
}
&__icon {
padding: 4px;
vertical-align: middle;
}
}
src/components/MessageReminder/Complex/index.jsx
0 → 100644
View file @
17b8b15c
import
React
,
{
useState
,
useEffect
,
forwardRef
,
useImperativeHandle
}
from
'
react
'
;
import
{
Modal
,
Tabs
,
Pagination
}
from
'
antd
'
;
import
styles
from
'
./index.less
'
;
const
Complex
=
(
props
,
ref
)
=>
{
const
[
visible
,
setVisible
]
=
useState
(
false
);
const
[
dataTotal
,
setDataTotal
]
=
useState
(
10
);
const
[
pagination
,
setPagination
]
=
useState
({
pageSize
:
20
,
pageNo
:
1
,
});
// 分页操作
const
onPageChange
=
(
page
,
size
)
=>
{
const
current
=
pagination
.
pageSize
!==
size
?
1
:
page
;
setPagination
({
pageNo
:
current
,
pageSize
:
size
,
});
};
useEffect
(()
=>
{},
[
pagination
]);
const
open
=
()
=>
{
setVisible
(
true
);
};
const
close
=
()
=>
{
setVisible
(
false
);
};
useImperativeHandle
(
ref
,
()
=>
({
open
,
}));
const
modalProps
=
{
width
:
'
1000px
'
,
height
:
'
600px
'
,
visible
,
title
:
'
消息提醒
'
,
footer
:
null
,
onCancel
:
close
,
};
return
(
<
Modal
{
...
modalProps
}
>
<
Tabs
tabPosition=
"left"
>
<
Tabs
.
TabPane
tab=
{
<
span
>
1111
<
span
style=
{
{
background
:
'
red
'
}
}
>
abc
</
span
>
</
span
>
}
key=
"1"
>
<
div
className=
{
styles
[
'
complex-list
'
]
}
>
<
div
className=
{
styles
[
'
complex-list__item
'
]
}
>
<
div
className=
{
styles
[
'
complex-list__item--header
'
]
}
>
<
span
className=
{
styles
.
notice
}
>
新的xxx订单,请查看
</
span
>
<
span
className=
{
styles
.
orderNumber
}
>
订单编号:1562742258351251456
</
span
>
<
span
className=
{
styles
.
time
}
>
2022-10-13 12:22:03
</
span
>
</
div
>
<
div
className=
{
styles
[
'
complex-list__item--body
'
]
}
>
<
div
className=
{
styles
.
good
}
>
<
span
className=
{
styles
.
good__name
}
>
商品名称商品名称商品名称商品名称
</
span
>
<
span
className=
{
styles
.
good__count
}
>
x10
</
span
>
</
div
>
<
div
className=
{
styles
.
good
}
>
<
span
className=
{
styles
.
good__name
}
>
商品名称商品名称商品名称商品名称
</
span
>
<
span
className=
{
styles
.
good__count
}
>
x10
</
span
>
</
div
>
<
div
className=
{
styles
.
good
}
>
<
span
className=
{
styles
.
good__name
}
>
商品名称商品名称商品名称商品名称
</
span
>
<
span
className=
{
styles
.
good__count
}
>
x10
</
span
>
</
div
>
</
div
>
<
div
className=
{
styles
[
'
complex-list__item--footer
'
]
}
>
<
div
className=
{
styles
.
actions
}
>
<
a
>
标记为已读
</
a
>
<
a
>
立即查看
</
a
>
</
div
>
</
div
>
</
div
>
<
div
className=
{
styles
[
'
complex-list__item
'
]
}
>
<
div
className=
{
styles
[
'
complex-list__item--header
'
]
}
>
<
span
className=
{
styles
.
notice
}
>
新的xxx订单,请查看
</
span
>
<
span
className=
{
styles
.
orderNumber
}
>
订单编号:1562742258351251456
</
span
>
<
span
className=
{
styles
.
time
}
>
2022-10-13 12:22:03
</
span
>
</
div
>
<
div
className=
{
styles
[
'
complex-list__item--body
'
]
}
>
<
div
className=
{
styles
.
good
}
>
<
span
className=
{
styles
.
good__name
}
>
商品名称商品名称商品名称商品名称
</
span
>
<
span
className=
{
styles
.
good__count
}
>
x10
</
span
>
</
div
>
<
div
className=
{
styles
.
good
}
>
<
span
className=
{
styles
.
good__name
}
>
商品名称商品名称商品名称商品名称
</
span
>
<
span
className=
{
styles
.
good__count
}
>
x10
</
span
>
</
div
>
<
div
className=
{
styles
.
good
}
>
<
span
className=
{
styles
.
good__name
}
>
商品名称商品名称商品名称商品名称
</
span
>
<
span
className=
{
styles
.
good__count
}
>
x10
</
span
>
</
div
>
</
div
>
<
div
className=
{
styles
[
'
complex-list__item--footer
'
]
}
>
<
div
className=
{
styles
.
actions
}
>
<
a
>
标记为已读
</
a
>
<
a
>
立即查看
</
a
>
</
div
>
</
div
>
</
div
>
</
div
>
</
Tabs
.
TabPane
>
<
Tabs
.
TabPane
tab=
"售后消息"
key=
"2"
>
<
div
className=
{
styles
[
'
complex-list
'
]
}
></
div
>
</
Tabs
.
TabPane
>
</
Tabs
>
<
div
className=
{
styles
.
pagination
}
>
<
Pagination
onChange=
{
onPageChange
}
total=
{
dataTotal
}
showTotal=
{
(
total
,
range
)
=>
`第${range[0]}-${range[1]}条 /总共${total}条`
}
pageSize=
{
pagination
.
pageSize
}
current=
{
pagination
.
pageNo
}
/>
</
div
>
</
Modal
>
);
};
export
default
forwardRef
(
Complex
);
src/components/MessageReminder/Complex/index.less
0 → 100644
View file @
17b8b15c
.complex-list {
height: 500px;
overflow-y: auto;
border: 1px solid #efefef;
& :first-child {
margin: 0;
}
&__item {
margin-top: 15px;
&--header {
display: flex;
width: 100%;
height: 40px;
padding: 0 20px;
line-height: 40px;
background: #f8f8f8;
.orderNumber {
flex: 1;
padding: 0 20px;
}
.notice {
color: green;
}
}
&--body {
padding: 10px 15px;
.good {
display: flex;
padding: 5px 0;
line-height: 1.5;
&__name {
flex: 1;
}
}
}
&--footer {
display: flex;
justify-content: end;
padding: 0 15px;
border-top: 1px solid #efefef;
border-bottom: 1px solid #efefef;
.actions {
display: flex;
margin-left: 10px;
line-height: 40px;
a {
margin-left: 15px;
}
}
}
}
}
.pagination {
text-align: right;
}
src/components/MessageReminder/Empty/index.jsx
0 → 100644
View file @
17b8b15c
import
React
from
'
react
'
;
import
styles
from
'
./index.less
'
;
const
MessageReminderEmpty
=
props
=>
{
const
{
text
}
=
props
;
return
(
<
div
className=
{
styles
.
notFound
}
>
<
img
src=
"https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
alt=
"not found"
/>
<
div
>
{
text
}
</
div
>
</
div
>
);
};
export
default
MessageReminderEmpty
;
src/components/MessageReminder/Empty/index.less
0 → 100644
View file @
17b8b15c
@import '~antd/es/style/themes/default.less';
.notFound {
padding: 73px 0 88px;
color: @text-color-secondary;
text-align: center;
img {
display: inline-block;
height: 76px;
margin-bottom: 16px;
}
}
src/components/MessageReminder/Simple/index.jsx
0 → 100644
View file @
17b8b15c
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
{
Badge
,
notification
}
from
'
antd
'
;
import
{
CloseOutlined
}
from
'
@ant-design/icons
'
;
import
classNames
from
'
classnames
'
;
import
{
connect
}
from
'
dva
'
;
import
{
apiGetBussinessMsgList
}
from
'
@/services/messageReminder
'
;
import
Empty
from
'
../Empty
'
;
import
styles
from
'
./index.less
'
;
import
{
CHANNEL_ID
}
from
'
@/utils/constants
'
;
const
Horn
=
props
=>
{
const
{
count
,
toggle
,
animationClass
}
=
props
;
return
(
<
div
className=
{
classNames
(
styles
.
horn
,
styles
[
animationClass
])
}
onClick=
{
toggle
}
>
<
Badge
count=
{
count
}
>
<
div
className=
{
styles
[
'
horn--num
'
]
}
>
消息提醒
</
div
>
</
Badge
>
</
div
>
);
};
const
Message
=
props
=>
{
const
{
toggle
,
animationClass
,
messageData
,
openComplex
,
onMark
}
=
props
;
const
ReminderItem
=
args
=>
{
const
{
item
}
=
args
;
const
{
orderNo
,
createdAt
}
=
JSON
.
parse
(
item
.
sendContent
||
'
{}
'
);
return
(
<
div
className=
{
styles
.
item
}
>
<
div
className=
{
styles
.
info
}
>
<
span
className=
{
styles
[
'
order-number
'
]
}
>
{
orderNo
}
</
span
>
<
span
className=
{
styles
[
'
mark-read
'
]
}
onClick=
{
()
=>
onMark
([
item
.
id
])
}
>
标记为已读
</
span
>
</
div
>
<
div
className=
{
styles
.
time
}
>
<
span
>
{
createdAt
}
</
span
>
</
div
>
<
div
className=
{
styles
.
notice
}
>
<
a
>
您有新的xxxxx订单,请查看
</
a
>
</
div
>
</
div
>
);
};
return
(
<
div
className=
{
classNames
(
styles
[
'
message-reminder
'
],
styles
[
animationClass
])
}
>
<
div
className=
{
styles
[
'
message-reminder__header
'
]
}
>
<
div
className=
{
styles
[
'
message-reminder__header--title
'
]
}
>
消息提醒
<
span
className=
{
styles
.
close
}
onClick=
{
toggle
}
>
<
CloseOutlined
/>
</
span
>
</
div
>
</
div
>
<
div
className=
{
styles
[
'
message-reminder__body
'
]
}
>
<
div
className=
{
styles
[
'
message-reminder__body--list
'
]
}
>
{
messageData
.
length
?
(
messageData
.
filter
((
e
,
i
)
=>
i
<
10
)
.
map
(
item
=>
<
ReminderItem
key=
{
item
.
id
}
item=
{
item
}
/>)
)
:
(
<
Empty
text=
"暂无数据"
/>
)
}
</
div
>
</
div
>
<
div
className=
{
styles
[
'
message-reminder__footer
'
]
}
>
<
div
className=
{
styles
[
'
message-reminder__footer--actions
'
]
}
>
<
div
className=
{
styles
.
more
}
onClick=
{
openComplex
}
>
查看更多
</
div
>
<
div
className=
{
styles
[
'
mark-all
'
]
}
onClick=
{
()
=>
{
onMark
(
messageData
.
filter
((
e
,
i
)
=>
i
<
10
).
map
(
item
=>
item
.
id
));
}
}
>
全部标记为已读
</
div
>
</
div
>
</
div
>
</
div
>
);
};
const
Simple
=
props
=>
{
const
{
dispatch
,
unReadCount
,
complexRef
,
unReadData
}
=
props
;
const
[
visible
,
setVisible
]
=
useState
(
false
);
const
[
count
,
setCount
]
=
useState
(
0
);
const
[
hornClass
,
setHornClass
]
=
useState
(
''
);
const
[
messageClass
,
setMessageClass
]
=
useState
(
''
);
const
[
messageData
,
setMessageData
]
=
useState
([]);
const
userInfo
=
JSON
.
parse
(
localStorage
.
getItem
(
'
user
'
)
||
'
{}
'
);
const
toggle
=
()
=>
{
setVisible
(
!
visible
);
};
// 初始化获取数据
const
getMsgList
=
async
()
=>
{
const
params
=
{
pageNo
:
1
,
pageSize
:
1000
,
};
const
data
=
{
channelId
:
CHANNEL_ID
,
bussinessId
:
userInfo
.
supplierCode
,
readStatus
:
0
,
};
const
res
=
await
apiGetBussinessMsgList
(
data
,
params
);
if
(
res
.
code
!==
'
0000
'
)
{
notification
.
error
(
res
.
msg
);
return
;
}
console
.
log
(
res
);
const
{
content
}
=
res
.
data
;
setVisible
(
!!
content
.
length
);
dispatch
({
type
:
'
messageReminder/setUnReadData
'
,
payload
:
content
,
options
:
{
unReadCount
:
content
.
length
,
},
});
};
// 打开消息提醒弹框
const
openComplex
=
()
=>
{
complexRef
.
current
.
open
();
toggle
();
};
// 标记已读信息
const
onMark
=
idList
=>
{
const
payload
=
{
channelId
:
CHANNEL_ID
,
bussinessId
:
userInfo
.
supplierCode
,
idList
,
};
dispatch
({
type
:
'
messageReminder/setMarkRead
'
,
payload
,
});
};
useEffect
(()
=>
{
setCount
(
unReadCount
);
},
[
unReadCount
]);
useEffect
(()
=>
{
setHornClass
(
visible
?
'
hide
'
:
'
show
'
);
setMessageClass
(
visible
?
'
show
'
:
'
hide
'
);
},
[
visible
]);
useEffect
(()
=>
{
getMsgList
();
},
[]);
useEffect
(()
=>
{
setMessageData
(
unReadData
);
},
[
unReadData
]);
const
hornProps
=
{
animationClass
:
hornClass
,
toggle
,
count
,
};
const
messageProps
=
{
animationClass
:
messageClass
,
toggle
,
messageData
,
openComplex
,
onMark
,
};
// 隐藏消息提醒
return
(
<>
<
Horn
{
...
hornProps
}
/>
<
Message
{
...
messageProps
}
/>
</>
);
};
export
default
connect
(({
messageReminder
})
=>
({
unReadCount
:
messageReminder
.
unReadCount
,
unReadData
:
messageReminder
.
unReadData
,
}))(
Simple
);
src/components/MessageReminder/Simple/index.less
0 → 100644
View file @
17b8b15c
.horn {
position: fixed;
right: 30px;
bottom: 10px;
// width: 112px;
// height: 50px;
color: #fff;
background: #2d8cf0;
transform: translateY(0);
cursor: pointer;
opacity: 1;
transition: 0.2s ease-in;
&.hide {
transform: translateY(100%) scale(0.3);
opacity: 0;
transition: 0.2s ease-out;
}
&--num {
width: 112px;
height: 50px;
color: #fff;
font-size: 16px;
line-height: 50px;
text-align: center;
&::before {
display: inline-block;
width: 20px;
height: 20px;
margin-right: 5px;
vertical-align: -3px;
background: url('https://img.lkbang.net/notice.94d42513.png') no-repeat;
background-size: 100% 100%;
content: '';
}
}
}
.message-reminder {
position: fixed;
right: 10px;
bottom: 10px;
z-index: 19;
display: flex;
flex-direction: column;
width: 404px;
height: 412px;
background: #fff;
transform: translate(50%, 110%) scale(0.5);
transition: 0.2s ease-in;
&.hide {
transform: translate(50%, 110%) scale(0.5);
opacity: 0;
transition: 0.2s ease-out;
}
&.show {
transform: translateY(0) scale(1);
opacity: 1;
transition: 0.2s ease-in;
}
&__header {
&--title {
position: relative;
padding-left: 35px;
color: #fff;
font-weight: 700;
font-size: 16px;
line-height: 50px;
background: #1890ff url('https://img.lkbang.net/notice.94d42513.png') no-repeat 10px center;
background-size: 20px 20px;
.close {
position: absolute;
right: 20px;
font-weight: 400;
cursor: pointer;
}
}
}
&__body {
flex: 1;
padding: 15px;
overflow: auto;
background: #f8f8f9;
&--list {
& .item:first-child {
margin-top: 0;
}
.item {
margin-top: 15px;
padding: 15px 0;
background: #fff;
border: 1px solid #efefef;
&:hover {
// border-color: #ccc;
// transition: 0.2s linear;
}
}
.info {
display: flex;
padding: 0 15px;
.order-number {
flex: 1;
padding-left: 20px;
background: url('https://img.lkbang.net/order_no.f4e0a8b3.png') no-repeat scroll 0 center;
}
.mark-read {
color: #178fff;
cursor: pointer;
}
}
.time {
display: flex;
margin-top: 12px;
padding: 0 15px;
span {
flex: 1;
padding-left: 20px;
background: url('https://img.lkbang.net/datetime.1b5f9199.png') no-repeat scroll 0 center;
}
}
.notice {
margin-top: 12px;
padding: 10px 15px 0;
border-top: 1px solid #efefef;
a {
position: relative;
display: block;
color: #ff1515;
&::after {
position: absolute;
top: 50%;
right: 0;
display: block;
width: 0;
height: 0;
margin-top: -3px;
border: 6px solid transparent;
border-left: 8px solid #999;
content: '';
}
}
}
}
}
&__footer {
background-color: #fff;
border: 1px solid #efefef;
&--actions {
display: flex;
& div:first-child {
border: none;
}
> div {
flex: 1;
color: #2d8cf0;
line-height: 40px;
text-align: center;
border-left: 1px solid #efefef;
cursor: pointer;
// &:hover {
// background: #f9f9f9;
// cursor: pointer;
// }
}
}
}
}
src/components/MessageReminder/index.jsx
0 → 100644
View file @
17b8b15c
import
Simple
from
'
./Simple
'
;
import
Complex
from
'
./Complex
'
;
const
MessageReminder
=
{};
MessageReminder
.
Simple
=
Simple
;
MessageReminder
.
Complex
=
Complex
;
export
default
MessageReminder
;
src/global.less
View file @
17b8b15c
...
@@ -53,3 +53,19 @@ ol {
...
@@ -53,3 +53,19 @@ ol {
}
}
}
}
}
}
// Button
@btn-warning-color: #f50;
.ant-btn {
&-warning,
&-warning:active,
&-warning:hover,
&-warning:visited {
color: #fff !important;
background-color: @btn-warning-color !important;
border-color: @btn-warning-color !important;
&:hover {
opacity: 0.7;
}
}
}
src/layouts/BasicLayout.jsx
View file @
17b8b15c
...
@@ -5,17 +5,20 @@
...
@@ -5,17 +5,20 @@
*/
*/
/* eslint-disable no-underscore-dangle, no-confusing-arrow */
/* eslint-disable no-underscore-dangle, no-confusing-arrow */
import
ProLayout
from
'
@ant-design/pro-layout
'
;
import
ProLayout
from
'
@ant-design/pro-layout
'
;
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
React
,
{
useState
,
useEffect
,
useRef
}
from
'
react
'
;
import
{
Link
}
from
'
umi
'
;
import
{
Link
}
from
'
umi
'
;
import
{
connect
}
from
'
dva
'
;
import
{
connect
}
from
'
dva
'
;
import
{
Icon
as
LegacyIcon
}
from
'
@ant-design/compatible
'
;
import
{
Icon
as
LegacyIcon
}
from
'
@ant-design/compatible
'
;
import
{
Result
,
Button
,
Layout
,
Menu
}
from
'
antd
'
;
import
{
Result
,
Button
,
Layout
,
Menu
}
from
'
antd
'
;
import
Authorized
from
'
@/utils/Authorized
'
;
import
Authorized
from
'
@/utils/Authorized
'
;
import
RightContent
from
'
@/components/GlobalHeader/RightContent
'
;
import
RightContent
from
'
@/components/GlobalHeader/RightContent
'
;
import
MessageReminder
from
'
@/components/MessageReminder
'
;
import
{
getAuthorityFromRouter
}
from
'
@/utils/utils
'
;
import
{
getAuthorityFromRouter
}
from
'
@/utils/utils
'
;
import
logo
from
'
../assets/logo.png
'
;
import
logo
from
'
../assets/logo.png
'
;
import
style
from
'
./BasicLayout.less
'
;
import
style
from
'
./BasicLayout.less
'
;
import
Socket
from
'
@/utils/websocket
'
;
const
{
Sider
}
=
Layout
;
const
{
Sider
}
=
Layout
;
const
{
SubMenu
}
=
Menu
;
const
{
SubMenu
}
=
Menu
;
...
@@ -48,12 +51,45 @@ const BasicLayout = props => {
...
@@ -48,12 +51,45 @@ const BasicLayout = props => {
}
=
props
;
}
=
props
;
const
[
siderCollapsed
,
setSiderCollapsed
]
=
useState
(
false
);
const
[
siderCollapsed
,
setSiderCollapsed
]
=
useState
(
false
);
const
messageReminderComplexRef
=
useRef
();
/**
/**
* constructor
* constructor
*/
*/
useEffect
(()
=>
{
useEffect
(()
=>
{
const
token
=
window
.
localStorage
.
getItem
(
'
token
'
);
const
channelId
=
100001
;
const
socket
=
new
Socket
({
url
:
`ws://ws-sc.liangkebang.net/ws?token=
${
token
}
&channelId=
${
channelId
}
`
,
});
socket
.
connection
();
socket
.
event
.
on
(
'
open
'
,
()
=>
{
console
.
log
(
'
连接成功3
'
);
});
socket
.
event
.
on
(
'
message
'
,
msg
=>
{
dispatch
({
type
:
'
messageReminder/setUnReadData
'
,
payload
:
JSON
.
parse
(
msg
.
data
),
});
});
let
a
=
100000000000
;
setInterval
(()
=>
{
a
++
;
socket
.
sendMessage
([
{
id
:
a
,
channelId
:
100001
,
bussinessId
:
'
self_40
'
,
type
:
0
,
sendContent
:
`{"name":"商品21111", "orderNo":
${
a
}
,"createdAt":"2022-10-13 12:12:12", "count":11}`
,
readStatus
:
0
,
createdAt
:
'
2022-10-18 14:05:12
'
,
updatedAt
:
'
2022-10-18 17:15:19
'
,
},
]);
},
5000
);
if
(
dispatch
)
{
if
(
dispatch
)
{
dispatch
({
dispatch
({
type
:
'
settings/getSetting
'
,
type
:
'
settings/getSetting
'
,
...
@@ -61,6 +97,14 @@ const BasicLayout = props => {
...
@@ -61,6 +97,14 @@ const BasicLayout = props => {
dispatch
({
dispatch
({
type
:
'
menu/getMenuData
'
,
type
:
'
menu/getMenuData
'
,
});
});
dispatch
({
type
:
'
messageReminder/getUnReadMsgList
'
,
});
setTimeout
(()
=>
{
dispatch
({
type
:
'
messageReminder/getUnReadCount
'
,
});
},
2000
);
}
}
},
[]);
},
[]);
/**
/**
...
@@ -156,7 +200,9 @@ const BasicLayout = props => {
...
@@ -156,7 +200,9 @@ const BasicLayout = props => {
);
);
}
}
}
}
menuDataRender=
{
()
=>
menuData
}
menuDataRender=
{
()
=>
menuData
}
rightContentRender=
{
rightProps
=>
<
RightContent
{
...
rightProps
}
/>
}
rightContentRender=
{
rightProps
=>
(
<
RightContent
{
...
rightProps
}
messageReminderComplexRef=
{
messageReminderComplexRef
}
/>
)
}
pageTitleRender=
{
()
=>
''
}
pageTitleRender=
{
()
=>
''
}
menuHeaderRender=
{
()
=>
(
menuHeaderRender=
{
()
=>
(
<
div
className=
{
style
[
'
custom-title-box
'
]
}
onClick=
{
toIndex
}
>
<
div
className=
{
style
[
'
custom-title-box
'
]
}
onClick=
{
toIndex
}
>
...
@@ -175,6 +221,9 @@ const BasicLayout = props => {
...
@@ -175,6 +221,9 @@ const BasicLayout = props => {
<
Authorized
authority=
{
authorized
.
authority
}
noMatch=
{
noMatch
}
>
<
Authorized
authority=
{
authorized
.
authority
}
noMatch=
{
noMatch
}
>
{
children
}
{
children
}
</
Authorized
>
</
Authorized
>
<
MessageReminder
.
Simple
complexRef=
{
messageReminderComplexRef
}
/>
<
MessageReminder
.
Complex
ref=
{
messageReminderComplexRef
}
/>
</
ProLayout
>
</
ProLayout
>
);
);
};
};
...
...
src/models/messageReminder.js
0 → 100644
View file @
17b8b15c
import
{
apiUpdageBusinessMsgStatus
}
from
'
@/services/messageReminder
'
;
const
MessageReminderModel
=
{
namespace
:
'
messageReminder
'
,
state
:
{
unReadCount
:
0
,
// 未读总数
unReadData
:
[],
// 未读数据
},
effects
:
{
*
setUnReadData
({
payload
,
options
},
{
put
,
call
})
{
yield
setTimeout
(()
=>
{
put
({
type
:
'
setUnReadData
'
,
payload
,
options
,
});
});
},
*
setMarkRead
({
payload
,
options
},
{
put
,
call
})
{
// const res = yield call(apiUpdageBusinessMsgStatus, payload)
// console.log(res)
yield
put
({
type
:
'
updateUnReadData
'
,
payload
,
options
,
});
},
},
reducers
:
{
setUnReadData
(
state
,
{
payload
,
options
=
{}
})
{
const
currentData
=
[...
payload
,
...
state
.
unReadData
];
let
unReadCount
=
state
.
unReadCount
+
1
;
if
(
options
.
unReadCount
||
options
.
unReadCount
===
0
)
{
// eslint-disable-next-line prefer-destructuring
unReadCount
=
options
.
unReadCount
;
}
return
{
...
state
,
unReadData
:
currentData
,
unReadCount
};
},
updateUnReadData
(
state
,
{
payload
,
options
=
{}
})
{
// 删除已读的数据
const
currentData
=
state
.
unReadData
.
filter
(
message
=>
!
payload
.
idList
.
includes
(
message
.
id
));
// 重置当前未读数量
const
unReadCount
=
currentData
.
length
;
// state.unReadCount - (options.readCount || payload.idList.length || 1)
return
{
...
state
,
unReadCount
,
unReadData
:
currentData
};
},
},
};
export
default
MessageReminderModel
;
src/pages/Admin/index.jsx
View file @
17b8b15c
...
@@ -107,6 +107,16 @@ const Admin = props => {
...
@@ -107,6 +107,16 @@ const Admin = props => {
<
p
>
退款待审核
{
'
<
'
}
24小时
</
p
>
<
p
>
退款待审核
{
'
<
'
}
24小时
</
p
>
</
Link
>
</
Link
>
</
Col
>
</
Col
>
<
Col
span=
{
4
}
>
<
Link
to=
{
{
pathname
:
'
afterSaleManage
'
,
}
}
>
<
strong
>
{
pendingNum
?.
interceptRefundPendingAuditNum
||
0
}
</
strong
>
<
p
>
物流拦截待审核
{
'
<
'
}
48小时
</
p
>
</
Link
>
</
Col
>
</>
</>
)
:
(
)
:
(
''
''
...
...
src/pages/AfterSaleManageNew/components/AfterLog.jsx
0 → 100644
View file @
17b8b15c
/* eslint-disable no-restricted-syntax */
/* eslint-disable guard-for-in */
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
{
Modal
,
Timeline
,
Button
}
from
'
antd
'
;
import
styles
from
'
../index.less
'
;
const
LogisticsCom
=
props
=>
{
const
{
visible
,
onCancel
,
data
}
=
props
;
return
(
<
Modal
destroyOnClose
title=
"查看记录"
visible=
{
visible
}
onCancel=
{
()
=>
onCancel
()
}
onOk=
{
()
=>
onCancel
()
}
footer=
{
false
}
>
{
data
?.
length
?
(
<
Timeline
>
{
data
?.
map
((
item
,
index
)
=>
(
// eslint-disable-next-line react/no-array-index-key
<
Timeline
.
Item
color=
{
index
>
0
?
'
gray
'
:
'
blue
'
}
key=
{
index
}
>
<
p
>
{
item
.
optDesc
}
</
p
>
<
p
>
{
item
.
optTime
}
</
p
>
</
Timeline
.
Item
>
))
}
</
Timeline
>
)
:
(
'
暂无查看记录
'
)
}
<
Button
type=
"primary"
onClick=
{
props
.
onCancel
}
className=
{
styles
.
logBtn
}
>
关闭
</
Button
>
</
Modal
>
);
};
export
default
LogisticsCom
;
src/pages/AfterSaleManageNew/components/auditModal.jsx
0 → 100644
View file @
17b8b15c
import
React
from
'
react
'
;
import
{
Form
}
from
'
@ant-design/compatible
'
;
import
'
@ant-design/compatible/assets/index.css
'
;
import
{
Modal
,
Input
,
Cascader
,
notification
,
InputNumber
}
from
'
antd
'
;
import
{
shopAudit
}
from
'
../services
'
;
import
styles
from
'
../index.less
'
;
const
FormItem
=
Form
.
Item
;
const
{
TextArea
}
=
Input
;
const
{
confirm
}
=
Modal
;
const
AuditModal
=
props
=>
{
const
{
visible
,
onCancel
,
form
:
{
getFieldDecorator
,
getFieldValue
,
validateFields
,
resetFields
},
formData
=
{},
}
=
props
;
const
handleCancel
=
isSuccess
=>
{
resetFields
();
onCancel
(
isSuccess
);
};
const
treeData
=
[
{
label
:
'
同意
'
,
value
:
1
,
},
{
label
:
'
不同意
'
,
value
:
2
,
children
:
[
{
label
:
'
商品与出售商品不符
'
,
value
:
1
,
},
{
label
:
'
影响二次销售
'
,
value
:
2
,
},
{
label
:
'
未提供商品照片,需要上传照片
'
,
value
:
4
,
},
{
label
:
'
快递正在配送中
'
,
value
:
5
,
},
{
label
:
'
订单已经取消
'
,
value
:
6
,
},
{
label
:
'
商品已超过售后期
'
,
value
:
7
,
},
{
label
:
'
其他
'
,
value
:
3
,
},
],
},
];
const
submitCheckResult
=
async
fieldsValue
=>
{
const
{
auditResult
}
=
fieldsValue
;
const
data
=
await
shopAudit
({
...
fieldsValue
,
refuseCode
:
auditResult
?.[
1
],
auditResult
:
auditResult
?.[
0
],
serviceNo
:
formData
?.
serviceNo
,
});
if
(
data
.
businessCode
===
'
0000
'
)
{
notification
.
success
({
message
:
'
审核成功
'
});
handleCancel
(
true
);
}
};
const
handleOk
=
()
=>
{
validateFields
((
error
,
fieldsValue
)
=>
{
if
(
!
error
)
{
const
{
auditResult
}
=
fieldsValue
;
// 如果为仅退款 并且 审核同意 弹出二次确认提示
if
(
+
formData
.
serviceType
===
1
&&
auditResult
?.[
0
]
===
1
)
{
confirm
({
title
:
'
温馨提示
'
,
content
:
(
<
div
>
当前类型为【
<
span
className=
{
styles
.
redTipBold
}
>
仅退款
</
span
>
】,请核查该订单物流状态,如有在途物流,务必自行拦截后点击确认;
</
div
>
),
okText
:
'
确认退款
'
,
onOk
()
{
submitCheckResult
(
fieldsValue
);
},
onCancel
()
{
handleCancel
(
true
);
},
});
}
else
{
submitCheckResult
(
fieldsValue
);
}
}
});
};
const
layout
=
{
labelCol
:
{
span
:
6
},
wrapperCol
:
{
span
:
16
},
};
const
auditResult
=
getFieldValue
(
'
auditResult
'
);
const
isAgree
=
()
=>
auditResult
?.[
0
]
===
1
;
const
isRefuse
=
()
=>
auditResult
&&
auditResult
[
0
]
!==
1
;
return
(
<
Modal
title=
"售后操作确认"
visible=
{
visible
}
onOk=
{
()
=>
handleOk
()
}
onCancel=
{
()
=>
handleCancel
()
}
>
{
+
formData
.
serviceType
===
1
&&
(
<
div
className=
{
styles
.
redTip
}
>
温馨提示:当前售后类型为用户未收到产品,申请
<
span
className=
{
styles
.
redTipBold
}
>
仅退款
</
span
>
,请务必检查此单物流状态后审核。
</
div
>
)
}
<
Form
{
...
layout
}
name=
"formData"
>
<
FormItem
label=
"审核结果"
>
{
getFieldDecorator
(
'
auditResult
'
,
{
rules
:
[
{
required
:
true
,
message
:
'
请选择审核结果!
'
,
},
],
})(
<
Cascader
allowClear
showSearch
style=
{
{
width
:
'
315px
'
}
}
dropdownStyle=
{
{
maxHeight
:
400
,
overflow
:
'
auto
'
}
}
options=
{
treeData
}
placeholder=
"请选择"
/>,
)
}
</
FormItem
>
{
isAgree
()
&&
+
formData
.
serviceType
===
2
&&
(
<
div
>
<
FormItem
label=
"退货地址"
>
{
getFieldDecorator
(
'
receiveAddress
'
,
{
initialValue
:
formData
.
address
,
rules
:
[
{
required
:
true
,
message
:
'
请填写退货地址!
'
,
},
{
message
:
'
格式有误,请填写正确的退货地址!
'
,
pattern
:
/
[
a-zA-Z0-9_
\u
4e00-
\u
9fa5
]
/g
,
},
],
})(<
Input
placeholder=
"最多输入50个字符"
maxLength=
"50"
allowClear
/>)
}
</
FormItem
>
<
FormItem
label=
"收件人"
>
{
getFieldDecorator
(
'
receiverName
'
,
{
initialValue
:
formData
.
name
,
rules
:
[
{
required
:
true
,
message
:
'
请填写收件人!
'
,
},
{
message
:
'
格式有误,请输入中英文、数字!
'
,
pattern
:
/^
[
A-Za-z0-9
\u
4e00-
\u
9fa5
]
+$/
,
},
],
})(<
Input
placeholder=
"最多输入25个字符"
maxLength=
"25"
allowClear
/>)
}
</
FormItem
>
<
FormItem
label=
"手机号码"
>
{
getFieldDecorator
(
'
receiverPhone
'
,
{
initialValue
:
formData
.
phone
,
rules
:
[
//
{
// pattern: new RegExp(/^1[3456789]\d
{
9
}
$
/
,
'
g
'
),
// message: '手机号码格式不正确!',
//
},
{
pattern
:
new
RegExp
(
/^
[
0-9
]
*$/
),
message
:
'
手机号码格式不正确!
'
,
},
{
required
:
true
,
message
:
'
请填写手机号码!
'
,
},
],
})(<
Input
placeholder=
"请填写手机号码"
maxLength=
"11"
allowClear
/>)
}
</
FormItem
>
</
div
>
)
}
{
isRefuse
()
&&
auditResult
[
1
]
===
3
&&
(
<
FormItem
label=
"拒绝原因"
>
{
getFieldDecorator
(
'
refuseDesc
'
,
{
initialValue
:
formData
.
refuseDesc
,
rules
:
[
{
required
:
true
,
message
:
'
请填写拒绝原因!
'
,
},
],
})(
<
TextArea
placeholder=
"请填写拒绝原因"
allowClear
autoSize=
{
{
minRows
:
3
,
maxRows
:
6
}
}
/>,
)
}
</
FormItem
>
)
}
{
isRefuse
()
&&
auditResult
[
1
]
!==
3
&&
(
<
FormItem
label=
"补充说明"
>
{
getFieldDecorator
(
'
refuseDesc
'
,
{
initialValue
:
formData
.
refuseDesc
,
rules
:
[
{
message
:
'
请填写补充说明!
'
,
},
],
})(
<
TextArea
placeholder=
"请填写补充说明"
allowClear
autoSize=
{
{
minRows
:
3
,
maxRows
:
6
}
}
maxLength=
{
120
}
showCount
/>,
)
}
</
FormItem
>
)
}
</
Form
>
</
Modal
>
);
};
export
default
Form
.
create
()(
AuditModal
);
src/pages/AfterSaleManageNew/components/detailTable.jsx
0 → 100644
View file @
17b8b15c
import
React
from
'
react
'
;
import
{
Modal
,
Table
}
from
'
antd
'
;
export
default
props
=>
{
const
{
visible
,
onCancel
,
dataSource
}
=
props
;
const
handleCancel
=
()
=>
{
onCancel
();
};
const
columns
=
[
{
title
:
'
商品名称
'
,
width
:
400
,
dataIndex
:
'
skuName
'
,
},
{
title
:
'
商品属性
'
,
dataIndex
:
'
skuAttr
'
,
},
{
title
:
'
商品件数
'
,
dataIndex
:
'
count
'
,
},
];
return
(
<
Modal
title=
"订单详情"
visible=
{
visible
}
onCancel=
{
handleCancel
}
footer=
{
null
}
width=
{
800
}
>
<
Table
dataSource=
{
dataSource
}
columns=
{
columns
}
key=
"skuName"
pagination=
{
false
}
bordered
/>
</
Modal
>
);
};
src/pages/AfterSaleManageNew/components/proofsModal.jsx
0 → 100644
View file @
17b8b15c
import
React
,
{
useState
}
from
'
react
'
;
import
{
Modal
}
from
'
antd
'
;
import
style
from
'
../index.less
'
;
export
default
props
=>
{
const
{
visible
,
onCancel
,
data
}
=
props
;
const
[
detailModal
,
setDetailModal
]
=
useState
(
false
);
const
[
detailSrc
,
setDetailSrc
]
=
useState
(
null
);
const
handleCancel
=
()
=>
{
onCancel
();
};
const
clickImg
=
src
=>
{
setDetailSrc
(
src
);
setDetailModal
(
true
);
};
return
(
<
Modal
title=
"售后凭证"
visible=
{
visible
}
onCancel=
{
handleCancel
}
footer=
{
null
}
width=
{
600
}
>
<
div
className=
{
style
.
proofsWrap
}
>
{
data
.
map
(
item
=>
(
<
img
src=
{
item
}
key=
{
item
}
alt=
{
item
}
className=
{
style
.
proofs
}
width=
{
250
}
onClick=
{
()
=>
clickImg
(
item
)
}
/>
))
}
</
div
>
<
Modal
title=
"凭证详情"
visible=
{
detailModal
}
onCancel=
{
()
=>
setDetailModal
(
false
)
}
footer=
{
null
}
width=
{
700
}
>
<
p
className=
{
style
.
detailWrap
}
>
<
img
src=
{
detailSrc
}
alt=
{
detailSrc
}
/>
</
p
>
</
Modal
>
</
Modal
>
);
};
src/pages/AfterSaleManageNew/components/rejectModal.jsx
0 → 100644
View file @
17b8b15c
import
React
from
'
react
'
;
import
{
Form
}
from
'
@ant-design/compatible
'
;
import
'
@ant-design/compatible/assets/index.css
'
;
import
{
Modal
,
Input
,
notification
}
from
'
antd
'
;
import
{
shopCheck
}
from
'
../services
'
;
const
FormItem
=
Form
.
Item
;
const
{
TextArea
}
=
Input
;
const
RejectModal
=
props
=>
{
const
{
visible
,
onCancel
,
form
:
{
getFieldDecorator
,
validateFields
,
resetFields
},
serviceNo
=
null
,
}
=
props
;
const
handleCancel
=
isSuccess
=>
{
resetFields
();
onCancel
(
isSuccess
);
};
const
handleOk
=
()
=>
{
validateFields
(
async
(
error
,
fieldsValue
)
=>
{
if
(
!
error
)
{
const
data
=
await
shopCheck
({
...
fieldsValue
,
serviceNo
,
auditResult
:
2
,
});
if
(
data
.
code
===
'
0000
'
)
{
notification
.
success
({
message
:
'
操作成功
'
});
handleCancel
(
true
);
}
}
});
};
const
layout
=
{
labelCol
:
{
span
:
6
},
wrapperCol
:
{
span
:
16
},
};
return
(
<
Modal
title=
"驳回"
visible=
{
visible
}
onOk=
{
()
=>
handleOk
()
}
onCancel=
{
()
=>
handleCancel
()
}
>
<
Form
{
...
layout
}
name=
"formData"
>
<
FormItem
label=
"原因"
>
{
getFieldDecorator
(
'
refuseDesc
'
,
{
rules
:
[
{
required
:
true
,
message
:
'
请填写原因!
'
,
},
],
})(
<
TextArea
placeholder=
"请填写原因"
allowClear
autoSize=
{
{
minRows
:
3
,
maxRows
:
6
}
}
/>,
)
}
</
FormItem
>
</
Form
>
</
Modal
>
);
};
export
default
Form
.
create
()(
RejectModal
);
src/pages/AfterSaleManageNew/data.js
0 → 100644
View file @
17b8b15c
import
{
Tag
,
Badge
,
Statistic
,
Button
}
from
'
antd
'
;
import
React
from
'
react
'
;
import
moment
from
'
moment
'
;
import
{
SEARCH_TYPE
}
from
'
@/components/FormSearch
'
;
const
{
Countdown
}
=
Statistic
;
// 商户审核中/商户审核拒绝/待填写退货物流信息/待退货入库/退货拒收/退款成功/用户撤销”
// 仅退款(未发货)/仅退款/退货退款,新增【仅退款(未发货)】即取消订单待审核
// 售后类型
const
AFTER_TYPE
=
[
{
value
:
'
1
'
,
name
:
'
商户审核中
'
,
},
{
value
:
'
2
'
,
name
:
'
商户审核拒绝
'
,
},
{
value
:
'
3
'
,
name
:
'
待填写退货物流信息
'
,
},
{
value
:
'
4
'
,
name
:
'
待退货入库
'
,
},
{
value
:
'
5
'
,
name
:
'
退货拒收
'
,
},
{
value
:
'
5
'
,
name
:
'
退款成功
'
,
},
{
value
:
'
6
'
,
name
:
'
用户撤销”
'
,
},
];
// 售后状态
const
AFTER_STATUS
=
[
{
value
:
'
1
'
,
name
:
'
仅退款(未发货)
'
,
},
{
value
:
'
1
'
,
name
:
'
仅退款
'
,
},
{
value
:
'
1
'
,
name
:
'
退货退款
'
,
},
];
export
const
getFormConfig
=
(
props
=
{})
=>
{
const
{
setTableParams
}
=
props
;
return
{
formConfig
:
[
{
type
:
SEARCH_TYPE
.
INPUT
,
label
:
'
订单ID
'
,
bindKey
:
'
orderNo
'
,
column
:
5
,
},
{
type
:
SEARCH_TYPE
.
INPUT
,
label
:
'
售后单ID
'
,
bindKey
:
'
serviceNo
'
,
column
:
5
,
},
{
type
:
SEARCH_TYPE
.
SELECT
,
label
:
'
售后状态
'
,
column
:
5
,
bindKey
:
'
dealStatus
'
,
options
:
AFTER_STATUS
,
},
{
type
:
SEARCH_TYPE
.
SELECT
,
label
:
'
售后类型
'
,
column
:
5
,
bindKey
:
'
type
'
,
options
:
AFTER_TYPE
,
},
{
type
:
SEARCH_TYPE
.
INPUT
,
label
:
'
收货人姓名
'
,
column
:
5
,
bindKey
:
'
receiverName
'
,
},
{
type
:
SEARCH_TYPE
.
INPUT
,
label
:
'
收货人手机号
'
,
column
:
5
,
bindKey
:
'
receiverPhone
'
,
},
{
type
:
SEARCH_TYPE
.
DATE_PICKER
,
label
:
'
订单开始日期
'
,
column
:
5
,
bindKey
:
'
startDate
'
,
},
{
type
:
SEARCH_TYPE
.
DATE_PICKER
,
label
:
'
订单结束日期
'
,
column
:
5
,
bindKey
:
'
endDate
'
,
},
],
btnConfig
:
[
{
label
:
'
筛选
'
,
clickType
:
'
submit
'
,
onClick
:
({
type
,
params
})
=>
{
setTableParams
(
params
);
},
},
{
label
:
'
重置
'
,
type
:
''
,
clickType
:
'
reset
'
,
onClick
:
()
=>
{
setTableParams
({});
},
},
],
};
};
export
const
appealType
=
{
1
:
'
已申诉
'
,
0
:
'
未申诉
'
,
};
export
const
getColumns
=
props
=>
{
const
{
openAudit
,
viewAppeal
,
viewProofs
,
openLogistics
,
viewDetail
,
viewLog
,
canEditable
,
}
=
props
;
return
[
{
title
:
'
审核倒计时
'
,
dataIndex
:
'
serviceTime
'
,
key
:
'
serviceTime
'
,
hideInSearch
:
true
,
width
:
150
,
render
:
(
val
,
record
)
=>
{
const
serviceTime
=
moment
(
record
.
approvalEndTime
).
valueOf
();
return
(
<
Countdown
format
=
"
HH时mm分ss秒
"
value
=
{
serviceTime
}
valueStyle
=
{{
color
:
'
red
'
,
fontSize
:
'
14px
'
}}
/
>
);
},
},
{
title
:
'
售后状态
'
,
dataIndex
:
'
serviceStatus
'
,
hideInSearch
:
true
,
width
:
120
,
},
{
title
:
'
售后类型
'
,
dataIndex
:
'
serviceType
'
,
hideInSearch
:
true
,
width
:
120
,
render
:
serviceType
=>
{
if
(
+
serviceType
===
1
)
{
return
<
span
style
=
{{
color
:
'
#ff1616
'
}}
>
仅退款
<
/span>
;
}
return
<
span
>
退货退款
<
/span>
;
},
},
{
title
:
'
订单ID
'
,
dataIndex
:
'
orderNo
'
,
hideInTable
:
true
,
width
:
200
,
},
{
title
:
'
售后单ID
'
,
dataIndex
:
'
serviceNo
'
,
width
:
300
,
render
:
(
serviceNo
,
r
)
=>
(
<
div
>
{
r
.
timeout
?
<
Tag
color
=
"
red
"
>
{
serviceNo
}
<
/Tag> : serviceNo
}
{
<
Badge
count
=
{
r
.
reminderFlag
?
'
催
'
:
''
}
size
=
"
default
"
/>
}
<
/div
>
),
},
{
title
:
'
订单ID
'
,
dataIndex
:
'
orderNo
'
,
hideInSearch
:
true
,
width
:
300
,
},
{
title
:
'
售后状态
'
,
dataIndex
:
'
dealStatus
'
,
hideInTable
:
true
,
valueEnum
:
{
0
:
'
待审核
'
,
10
:
'
三方审核中
'
,
11
:
'
三方审核通过
'
,
12
:
'
三方审核拒绝
'
,
13
:
'
客服审核通过
'
,
14
:
'
商户审核中
'
,
15
:
'
商户审核通过
'
,
16
:
'
商户审核拒绝
'
,
20
:
'
审核拒绝
'
,
21
:
'
申诉中
'
,
30
:
'
待填写退货物流信息
'
,
40
:
'
待退货入库
'
,
50
:
'
退货拒收
'
,
60
:
'
待退款
'
,
61
:
'
退货处理中
'
,
70
:
'
售后成功
'
,
99
:
'
用户取消
'
,
},
width
:
100
,
},
{
title
:
'
售后类型
'
,
dataIndex
:
'
type
'
,
hideInTable
:
true
,
width
:
120
,
valueEnum
:
{
1
:
'
仅退款
'
,
2
:
'
退货退款
'
,
},
},
{
title
:
'
收货人姓名
'
,
dataIndex
:
'
receiverName
'
,
width
:
200
,
},
{
title
:
'
收货人手机号
'
,
dataIndex
:
'
receiverPhone
'
,
width
:
200
,
},
{
title
:
'
收货人地址
'
,
dataIndex
:
'
receiveAddress
'
,
width
:
200
,
hideInSearch
:
true
,
},
{
title
:
'
订单开始时间
'
,
width
:
120
,
dataIndex
:
'
startDate
'
,
key
:
'
startDate
'
,
valueType
:
'
date
'
,
hideInTable
:
true
,
},
{
title
:
'
订单结束时间
'
,
width
:
120
,
dataIndex
:
'
endDate
'
,
key
:
'
endDate
'
,
valueType
:
'
date
'
,
hideInTable
:
true
,
},
{
title
:
'
售后原因
'
,
dataIndex
:
'
serviceReason
'
,
hideInSearch
:
true
,
width
:
200
,
},
{
title
:
'
售后发生时间
'
,
dataIndex
:
'
serviceTime
'
,
hideInSearch
:
true
,
width
:
200
,
},
{
title
:
'
超时时间
'
,
dataIndex
:
'
overtime
'
,
hideInSearch
:
true
,
width
:
200
,
},
{
title
:
'
是否催办
'
,
dataIndex
:
'
reminderFlag
'
,
hideInSearch
:
true
,
width
:
120
,
valueEnum
:
{
true
:
'
是
'
,
false
:
'
否
'
,
},
},
{
title
:
'
是否同意售后
'
,
dataIndex
:
'
isAgree
'
,
hideInSearch
:
true
,
width
:
120
,
},
{
title
:
'
拒绝原因
'
,
dataIndex
:
'
refuseReason
'
,
hideInSearch
:
true
,
width
:
200
,
},
{
title
:
'
售后凭证
'
,
dataIndex
:
'
proofs
'
,
hideInSearch
:
true
,
width
:
100
,
render
:
(
val
,
r
)
=>
<
a
onClick
=
{()
=>
viewProofs
(
r
.
proofs
)}
>
查看凭证
<
/a>
,
},
{
title
:
'
售后申诉
'
,
dataIndex
:
'
appealFlag
'
,
valueEnum
:
appealType
,
hideInSearch
:
true
,
width
:
120
,
render
:
(
appealFlag
,
r
)
=>
{
if
(
appealFlag
)
{
return
<
a
onClick
=
{()
=>
viewAppeal
(
r
)}
>
已申诉
<
/a>
;
}
return
<
div
>
未申诉
<
/div>
;
},
},
{
title
:
'
操作
'
,
hideInSearch
:
true
,
dataIndex
:
'
action
'
,
width
:
250
,
fixed
:
'
right
'
,
render
:
(
val
,
r
)
=>
{
const
operations
=
[
<
Button
key
=
"
link1
"
onClick
=
{()
=>
openAudit
(
r
)}
className
=
"
mr10 mt10
"
type
=
"
primary
"
>
审核
<
/Button>
,
<
Button
disabled
=
{
r
.
serviceType
!==
1
||
(
r
.
serviceType
===
1
&&
r
.
intercept
)}
onClick
=
{()
=>
openLogistics
(
r
)}
className
=
"
mr10 mt10
"
type
=
"
primary
"
>
物流拦截
<
/Button>
,
<
Button
className
=
"
mr10 mt10
"
key
=
"
link
"
onClick
=
{()
=>
viewDetail
(
r
)}
type
=
"
primary
"
>
订单详情
<
/Button>
,
<
Button
className
=
"
mr10 mt10
"
type
=
"
primary
"
onClick
=
{()
=>
viewLog
(
r
)}
>
查看记录
<
/Button>
,
];
// 不可编辑直接隐藏可操作按钮
if
(
!
canEditable
)
{
return
[
operations
[
2
],
operations
[
3
]];
}
// 服务订单删除物流拦截
if
(
!
[
'
vip
'
,
'
self
'
].
includes
(
r
.
supplierType
))
{
return
[
operations
[
0
],
operations
[
2
],
operations
[
3
]];
}
return
operations
;
},
},
];
};
src/pages/AfterSaleManageNew/index.jsx
0 → 100644
View file @
17b8b15c
import
React
,
{
useRef
,
useState
}
from
'
react
'
;
import
{
Tabs
,
notification
,
Form
,
Modal
}
from
'
antd
'
;
import
{
PageHeaderWrapper
}
from
'
@ant-design/pro-layout
'
;
import
ProTable
from
'
@ant-design/pro-table
'
;
import
{
AFTER_SALE_ORDER
}
from
'
@/../config/permission.config
'
;
import
{
connect
}
from
'
dva
'
;
import
{
FormSearch
}
from
'
@/components/FormSearch
'
;
import
moment
from
'
moment
'
;
import
AuditModal
from
'
./components/auditModal
'
;
import
DetailTable
from
'
./components/detailTable
'
;
import
ProofsModal
from
'
./components/proofsModal
'
;
import
AppealDetail
from
'
@/pages/afterSale/components/detail
'
;
import
AfterLog
from
'
./components/AfterLog
'
;
import
{
getColumns
,
getFormConfig
}
from
'
./data.js
'
;
import
{
getDetail
}
from
'
@/pages/afterSale/appeal/services
'
;
import
{
searchList
,
logisticsIntercept
,
orderDetail
,
getOpLog
,
auditInfoApi
}
from
'
./services
'
;
import
styles
from
'
./index.less
'
;
const
{
TabPane
}
=
Tabs
;
const
{
confirm
}
=
Modal
;
const
AfterSale
=
props
=>
{
const
{
permissions
}
=
props
;
const
canEditable
=
permissions
[
AFTER_SALE_ORDER
.
EDITABLE
];
const
actionRef
=
useRef
();
const
formRef
=
useRef
();
const
[
tableParams
,
setTableParams
]
=
useState
({});
const
[
appealDetailModal
,
setAppealDetailModal
]
=
useState
(
false
);
const
[
selectedRow
,
setSelectedRow
]
=
useState
({});
// 申诉
const
[
proofsData
,
setProofsData
]
=
useState
([]);
const
[
proofsVisible
,
setProofsVisible
]
=
useState
(
false
);
// 详情
const
[
detailVisible
,
setDetailVisible
]
=
useState
(
false
);
const
[
detailInfo
,
setDetailInfo
]
=
useState
([]);
// 售后操作记录
const
[
afterVisible
,
setAfterVisible
]
=
useState
(
false
);
const
[
afterList
,
setAfterList
]
=
useState
([]);
// 审核
const
[
visible
,
setVisible
]
=
useState
(
false
);
const
[
auditInfo
,
setAuditInfo
]
=
useState
({});
// 关闭modal
const
closeModal
=
isReload
=>
{
if
(
isReload
===
true
)
{
// eslint-disable-next-line no-unused-expressions
actionRef
.
current
?.
reload
?.();
}
setVisible
(
false
);
setDetailVisible
(
false
);
setProofsVisible
(
false
);
setAppealDetailModal
(
false
);
setAfterVisible
(
false
);
};
// 查看申诉详情
const
viewAppeal
=
async
r
=>
{
const
detailData
=
await
getDetail
({
appealNo
:
r
.
appealNo
});
setAppealDetailModal
(
true
);
setSelectedRow
(
detailData
);
};
// 查看凭证
const
viewProofs
=
proofs
=>
{
if
(
!
proofs
)
{
notification
.
warning
({
message
:
'
该订单没有凭证
'
});
return
;
}
const
list
=
proofs
.
replace
(
/
(\u
ff1b|
\u
ff0c|
\u
003b
)
/g
,
'
,
'
).
split
(
'
,
'
);
setProofsData
(
list
);
setProofsVisible
(
true
);
};
// 审核
const
openAudit
=
async
({
serviceNo
,
serviceType
})
=>
{
const
data
=
await
auditInfoApi
({
serviceNo
});
setAuditInfo
({
...
data
?.
data
,
serviceNo
,
serviceType
});
setVisible
(
true
);
};
// 物流拦截
const
openLogistics
=
r
=>
{
confirm
({
title
:
'
温馨提示
'
,
okText
:
'
确认拦截
'
,
cancelText
:
'
取消拦截
'
,
content
:
(
<
div
>
请48小时内自行联系物流公司进行物流拦截,系统监测拦截成功后
<
span
className=
{
styles
.
redTipBold
}
>
自动同意
</
span
>
退款
</
div
>
),
async
onOk
()
{
const
data
=
await
logisticsIntercept
({
serviceNo
:
r
.
serviceNo
});
if
(
data
.
businessCode
===
'
0000
'
)
{
notification
.
success
({
message
:
'
拦截成功
'
});
actionRef
.
current
.
reload
();
}
else
{
notification
.
error
({
message
:
data
.
msg
||
'
拦截失败
'
});
}
},
onCancel
()
{
console
.
log
(
'
Cancel
'
);
},
});
};
// 查看
const
viewDetail
=
async
({
serviceNo
})
=>
{
const
res
=
await
orderDetail
({
serviceNo
});
const
data
=
res
.
data
||
[];
setDetailInfo
(
data
);
setDetailVisible
(
true
);
};
// 查看售后操作日志
const
viewLog
=
async
r
=>
{
const
data
=
await
getOpLog
(
r
.
serviceNo
);
if
(
data
?.
data
?.
length
)
{
setAfterList
(
data
.
data
);
setAfterVisible
(
true
);
}
};
const
tabChange
=
e
=>
{
console
.
log
(
e
);
};
const
[
form
]
=
Form
.
useForm
();
const
formConfig
=
getFormConfig
({
setTableParams
,
});
const
FormSearchProps
=
{
form
,
initialValues
:
{},
formOptions
:
{},
...
formConfig
,
};
const
columns
=
getColumns
({
openAudit
,
viewAppeal
,
viewProofs
,
openLogistics
,
viewDetail
,
viewLog
,
canEditable
,
});
// 表格属性
const
tableProps
=
{
columns
,
params
:
tableParams
,
bordered
:
true
,
scroll
:
{
x
:
'
100%
'
,
y
:
500
},
rowKey
:
r
=>
r
.
serviceNo
,
request
:
async
params
=>
{
console
.
log
(
params
);
console
.
log
(
'
搜索
'
,
params
);
const
{
current
:
page
,
pageSize
:
size
}
=
params
;
const
startDate
=
params
.
startDate
?
moment
(
params
.
startDate
).
format
(
'
YYYY-MM-DD
'
)
:
''
;
const
endDate
=
params
.
endDate
?
moment
(
params
.
endDate
).
format
(
'
YYYY-MM-DD
'
)
:
''
;
const
requestParams
=
{
page
,
size
,
queryStatus
:
1
,
...
params
,
startDate
,
endDate
,
};
const
res
=
await
searchList
(
requestParams
);
const
{
records
=
[],
total
}
=
res
.
data
;
return
{
data
:
records
,
total
,
};
},
toolBarRender
:
null
,
};
return
(
<
PageHeaderWrapper
>
<
FormSearch
{
...
FormSearchProps
}
/>
<
div
className=
{
styles
[
'
tab-box
'
]
}
>
<
Tabs
onChange=
{
tabChange
}
size=
"large"
tabBarStyle=
{
{
padding
:
'
0 30px
'
}
}
>
<
TabPane
key=
""
tab=
"全部"
></
TabPane
>
<
TabPane
key=
{
1
}
tab=
"仅退款(未发货)"
></
TabPane
>
<
TabPane
key=
{
2
}
tab=
"待审核0"
></
TabPane
>
<
TabPane
key=
{
3
}
tab=
"仅退款待审核8"
></
TabPane
>
<
TabPane
key=
{
4
}
tab=
"退货退款待审核0"
></
TabPane
>
<
TabPane
key=
{
5
}
tab=
"退货入库待审核0"
></
TabPane
>
<
TabPane
key=
{
6
}
tab=
"已完成0"
></
TabPane
>
</
Tabs
>
</
div
>
<
ProTable
{
...
tableProps
}
actionRef=
{
actionRef
}
formRef=
{
formRef
}
search=
{
false
}
toolBarRender=
{
false
}
/>
<
AuditModal
visible=
{
visible
}
onCancel=
{
closeModal
}
formData=
{
auditInfo
}
/>
<
DetailTable
visible=
{
detailVisible
}
onCancel=
{
closeModal
}
dataSource=
{
detailInfo
}
/>
<
ProofsModal
visible=
{
proofsVisible
}
onCancel=
{
closeModal
}
data=
{
proofsData
}
/>
<
AppealDetail
data=
{
selectedRow
}
modalVisible=
{
appealDetailModal
}
onCancel=
{
closeModal
}
></
AppealDetail
>
<
AfterLog
visible=
{
afterVisible
}
onCancel=
{
closeModal
}
data=
{
afterList
}
/>
</
PageHeaderWrapper
>
);
};
export
default
connect
(({
menu
})
=>
({
permissions
:
menu
.
permissions
,
}))(
AfterSale
);
src/pages/AfterSaleManageNew/index.less
0 → 100644
View file @
17b8b15c
.proofs {
padding: 5px;
border: 1px solid #ddd;
border-radius: 10px;
}
.proofsWrap {
display: flex;
justify-content: space-between;
min-height: 300px;
max-height: 600px;
overflow: auto;
}
.detailWrap {
min-height: 300px;
max-height: 600px;
overflow: auto;
}
.logBtn {
display: inherit;
margin: 20px auto;
}
.redTip {
color: #ff4d4f;
font-size: 14px;
}
.redTipBold {
color: #ff1616;
font-weight: bold;
}
.tab-box {
margin-top: 20px;
background-color: #fff;
}
src/pages/AfterSaleManageNew/services.js
0 → 100644
View file @
17b8b15c
import
request
from
'
@/utils/request
'
;
import
config
from
'
../../../config/env.config
'
;
import
{
stringify
}
from
'
qs
'
;
import
_
from
'
lodash
'
;
const
{
kdspApi
}
=
config
;
// 分页查询所有数据
export
const
searchList
=
params
=>
request
.
post
(
'
/api/kdsp/op/afs/shop/list
'
,
{
prefix
:
kdspApi
,
data
:
stringify
(
_
.
omitBy
(
params
,
v
=>
!
v
)),
headers
:
{
'
Content-Type
'
:
'
application/x-www-form-urlencoded
'
,
},
});
// export async function searchList(params, queryStatus) {
// const param = {
// ...params,
// pageNo: params.current,
// pageSize: params.pageSize || 20,
// queryStatus,
// };
// const data = await request.post('/api/kdsp/op/afs/shop/list', {
// prefix: kdspApi,
// data: stringify(_.omitBy(param, v => !v)),
// headers: {
// 'Content-Type': 'application/x-www-form-urlencoded',
// },
// });
// if (data.data) {
// return {
// total: data.data.total,
// data: data.data.records,
// };
// }
// return {
// total: 0,
// data: [],
// };
// }
// 售后单详情
export
async
function
orderDetail
(
params
)
{
const
data
=
await
request
.
get
(
'
/api/kdsp/op/afs/sku
'
,
{
prefix
:
kdspApi
,
params
,
headers
:
{
'
Content-Type
'
:
'
application/x-www-form-urlencoded
'
,
},
});
return
data
.
data
||
[];
}
// 售后审核
export
async
function
shopAudit
(
params
)
{
return
request
.
post
(
'
/api/kdsp/op/afs/shop/audit
'
,
{
data
:
params
,
prefix
:
kdspApi
,
});
}
// 查询审核信息
export
async
function
auditInfoApi
(
params
)
{
return
request
.
get
(
'
/api/kdsp/op/afs/back-info
'
,
{
params
,
prefix
:
kdspApi
,
});
}
// 审核核检
export
async
function
shopCheck
(
params
)
{
return
request
.
post
(
'
/api/kdsp/op/afs/shop/check
'
,
{
params
,
headers
:
{
'
Content-Type
'
:
'
application/x-www-form-urlencoded
'
,
},
prefix
:
kdspApi
,
});
}
// 查询物流信息
export
async
function
trackInfo
(
params
)
{
const
data
=
await
request
.
get
(
'
/api/kdsp/op/logistics/kd100/track-list
'
,
{
params
,
prefix
:
kdspApi
,
});
if
(
data
.
businessCode
===
'
0000
'
)
{
return
data
.
data
;
}
return
{};
}
// 物流拦截
export
async
function
logisticsIntercept
(
params
)
{
return
request
.
get
(
'
/api/kdsp/op/afs/shop/logisticsIntercept
'
,
{
params
,
prefix
:
kdspApi
,
});
}
// 售后操作日志
export
async
function
getOpLog
(
params
)
{
return
request
.
get
(
`/afterSaleAdmin/getOpLog/
${
params
}
`
,
{
prefix
:
kdspApi
,
});
}
src/pages/chainStoreManage/components/storeModal.jsx
View file @
17b8b15c
...
@@ -110,6 +110,7 @@ const StoreModal = props => {
...
@@ -110,6 +110,7 @@ const StoreModal = props => {
params
.
parentId
=
id
;
params
.
parentId
=
id
;
}
}
const
res
=
await
apiAddrArea
(
params
);
const
res
=
await
apiAddrArea
(
params
);
console
.
log
(
res
);
if
(
res
)
{
if
(
res
)
{
const
arr
=
res
.
map
(
item
=>
({
const
arr
=
res
.
map
(
item
=>
({
isLeaf
:
false
,
isLeaf
:
false
,
...
...
src/pages/orderManage/pendingDeliveryOrder/index.jsx
View file @
17b8b15c
import
{
Button
,
notification
,
Modal
}
from
'
antd
'
;
import
{
Button
,
notification
,
Modal
,
Popover
}
from
'
antd
'
;
import
React
,
{
useState
,
useEffect
,
useRef
}
from
'
react
'
;
import
React
,
{
useState
,
useEffect
,
useRef
}
from
'
react
'
;
import
{
PageHeaderWrapper
}
from
'
@ant-design/pro-layout
'
;
import
{
PageHeaderWrapper
}
from
'
@ant-design/pro-layout
'
;
import
ProTable
from
'
@ant-design/pro-table
'
;
import
ProTable
from
'
@ant-design/pro-table
'
;
...
@@ -6,8 +6,8 @@ import { FormInstance } from 'antd/lib/form';
...
@@ -6,8 +6,8 @@ import { FormInstance } from 'antd/lib/form';
import
moment
from
'
moment
'
;
import
moment
from
'
moment
'
;
import
{
connect
}
from
'
dva
'
;
import
{
connect
}
from
'
dva
'
;
import
{
PENDING_DELIVERY_ORDER
,
DELIVERY_ORDER
}
from
'
@/../config/permission.config
'
;
import
{
PENDING_DELIVERY_ORDER
,
DELIVERY_ORDER
}
from
'
@/../config/permission.config
'
;
import
style
from
'
./index.less
'
;
import
LogisticsForm
from
'
./components/LogisticsForm
'
;
import
LogisticsForm
from
'
./components/LogisticsForm
'
;
import
style
from
'
./styles.less
'
;
import
PopoverDom
from
'
./components/PreviewImage
'
;
import
PopoverDom
from
'
./components/PreviewImage
'
;
import
LogisticsCom
from
'
./components/LogisticsCom
'
;
import
LogisticsCom
from
'
./components/LogisticsCom
'
;
import
DelayDeliverGoods
from
'
./components/DelayDeliverGoods
'
;
import
DelayDeliverGoods
from
'
./components/DelayDeliverGoods
'
;
...
@@ -141,6 +141,37 @@ const TableList = props => {
...
@@ -141,6 +141,37 @@ const TableList = props => {
order
:
6
,
order
:
6
,
width
:
250
,
width
:
250
,
fixed
:
'
left
'
,
fixed
:
'
left
'
,
render
:
(
_
,
record
)
=>
(
<>
{
_
}
<
Popover
placement=
"top"
title=
"催发货"
content=
{
<>
111
</>
}
trigger=
"click"
>
<
span
className=
{
style
.
urge
}
>
催
</
span
>
</
Popover
>
</>
),
},
{
title
:
'
订单提醒
'
,
dataIndex
:
'
orderNotice
'
,
key
:
'
orderNotice
'
,
width
:
150
,
render
:
(
_
,
record
)
=>
{
const
{
address
}
=
record
;
return
(
<
div
className=
{
style
[
'
notice-btn
'
]
}
>
<
Popover
placement=
"top"
title=
"收货地址变更"
content=
{
<>
111
</>
}
trigger=
"click"
>
<
Button
block
type=
"primary"
>
收货地址变更
</
Button
>
</
Popover
>
<
Popover
placement=
"top"
title=
"平台备注"
content=
{
<>
222
</>
}
trigger=
"click"
>
<
Button
block
type=
"warning"
>
平台备注
</
Button
>
</
Popover
>
</
div
>
);
},
},
},
{
{
title
:
'
商品名称
'
,
title
:
'
商品名称
'
,
...
...
src/pages/orderManage/pendingDeliveryOrder/index.less
View file @
17b8b15c
...
@@ -73,3 +73,24 @@
...
@@ -73,3 +73,24 @@
margin-right: 10px;
margin-right: 10px;
}
}
}
}
.notice-btn {
max-width: 120px;
margin: 0 auto;
text-align: center;
button {
margin: 5px 0;
}
}
// 催发货图标
.urge {
display: inline-block;
width: 20px;
height: 20px;
color: #fff;
line-height: 20px;
text-align: center;
background-color: red;
border-radius: 50%;
}
src/services/messageReminder.js
0 → 100644
View file @
17b8b15c
import
request
from
'
@/utils/request
'
;
import
config
from
'
../../config/env.config
'
;
const
{
msgApi
}
=
config
;
/**
* @name 商户消息列表
* @see http://yapi.quantgroups.com/project/193/interface/api/41792
*/
export
function
apiGetBussinessMsgList
(
data
,
params
)
{
return
request
.
post
(
'
/v1/send/message/getBussinessMsgList
'
,
{
data
,
params
,
prefix
:
msgApi
,
});
}
/**
* @name 获取未读消息数量
* @see http://yapi.quantgroups.com/project/193/interface/api/42792
*/
export
function
apiGetBusinessMsgUnReadCount
(
data
)
{
return
request
.
post
(
'
/v1/send/message/getBusinessMsgUnReadCount
'
,
{
data
,
headers
:
{
'
Content-Type
'
:
'
application/x-www-form-urlencoded
'
,
},
prefix
:
msgApi
,
});
}
/**
* @name 设置消息为已读
* @see http://yapi.quantgroups.com/project/193/interface/api/41808
*/
export
function
apiUpdageBusinessMsgStatus
(
data
)
{
return
request
.
post
(
'
/v1/send/message/updateBussinessMsgReadStatus
'
,
{
data
,
prefix
:
msgApi
,
});
}
src/utils/constants.js
View file @
17b8b15c
export
const
APP_CODE
=
'
APP013
'
;
export
const
APP_CODE
=
'
APP013
'
;
export
const
TENANT_ID
=
560761
;
export
const
TENANT_ID
=
560761
;
export
const
CHANNEL_ID
=
100001
;
// 小程序权限标识符, 用于过滤掉返回的小程序权限数据
// 小程序权限标识符, 用于过滤掉返回的小程序权限数据
export
const
APPLETS_PERMISSION_IDENTIFIER
=
'
applets
'
;
export
const
APPLETS_PERMISSION_IDENTIFIER
=
'
applets
'
;
src/utils/websocket.js
0 → 100644
View file @
17b8b15c
import
EventEmitter
from
'
events
'
;
class
Socket
extends
EventEmitter
{
event
=
new
EventEmitter
();
constructor
(
options
)
{
super
();
this
.
options
=
options
;
this
.
reconnectCount
=
0
;
this
.
socket
=
null
;
this
.
taskRemindInterval
=
null
;
this
.
connected
=
false
;
this
.
waitingSendData
=
[];
return
this
;
}
connection
=
()
=>
{
const
{
url
,
timeout
=
0
}
=
this
.
options
;
// 检测当前浏览器是什么浏览器来决定用什么socket
if
(
'
WebSocket
'
in
window
)
{
console
.
log
(
'
WebSocket
'
);
this
.
socket
=
new
WebSocket
(
url
);
}
else
if
(
'
MozWebSocket
'
in
window
)
{
console
.
log
(
'
MozWebSocket
'
);
// eslint-disable-next-line no-undef
this
.
socket
=
new
MozWebSocket
(
url
);
}
else
{
console
.
log
(
'
SockJS
'
);
// eslint-disable-next-line no-undef
this
.
socket
=
new
SockJS
(
url
);
}
// 链接回调
this
.
socket
.
onopen
=
this
.
onopen
;
this
.
socket
.
onmessage
=
this
.
onmessage
;
this
.
socket
.
onclose
=
this
.
onclose
;
this
.
socket
.
onerror
=
this
.
onerror
;
this
.
socket
.
sendMessage
=
this
.
sendMessage
;
// 检测返回的状态码 如果socket.readyState不等于1则连接失败,关闭连接
if
(
timeout
)
{
const
time
=
setTimeout
(()
=>
{
if
(
this
.
socket
&&
this
.
socket
.
readyState
!==
1
)
{
console
.
log
(
'
主动触发关闭
'
);
this
.
socket
.
close
();
}
clearInterval
(
time
);
},
timeout
);
}
};
// 连接成功触发
onopen
=
()
=>
{
console
.
log
(
'
ws:连接成功
'
);
this
.
connected
=
true
;
this
.
checkWaitingData
();
this
.
event
.
emit
(
'
open
'
);
};
// 后端向前端推得数据
onmessage
=
msg
=>
{
console
.
log
(
'
接收数据:
'
,
msg
);
this
.
event
.
emit
(
'
message
'
,
msg
);
// 打印出后端推得数据
};
// 关闭连接触发
onclose
=
e
=>
{
this
.
connected
=
false
;
// 关闭将标识符改为true
console
.
log
(
'
关闭socket收到的数据
'
);
this
.
event
.
emit
(
'
close
'
,
e
);
// 根据后端返回的状态码做操作
// 我的项目是当前页面打开两个或者以上,就把当前以打开的socket关闭
// 否则就20秒重连一次,直到重连成功为止
if
(
e
.
code
===
'
4500
'
)
{
this
.
socket
.
close
();
}
else
{
this
.
taskRemindInterval
=
setInterval
(()
=>
{
if
(
!
this
.
connected
)
{
this
.
connection
();
}
else
{
clearInterval
(
this
.
taskRemindInterval
);
}
},
2000
);
}
};
onerror
=
e
=>
{
this
.
socket
=
null
;
this
.
event
.
emit
(
'
error
'
,
e
);
};
sendMessage
=
value
=>
{
// 向后端发送数据
if
(
this
.
socket
)
{
if
(
!
this
.
connected
)
{
this
.
waitingSendData
.
unshift
(
value
);
return
;
}
this
.
socket
.
send
(
JSON
.
stringify
(
value
));
}
};
checkWaitingData
()
{
if
(
this
.
waitingSendData
.
length
)
{
this
.
sendMessage
(
this
.
waitingSendData
.
splice
(
0
,
1
));
this
.
checkWaitingData
();
}
}
}
export
default
Socket
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment