Commit 78aa9b7a authored by XieZhiXiong's avatar XieZhiXiong

feat: 添加供应商评论解释相关

parent efa6be34
...@@ -56,7 +56,7 @@ export const evaluateSchema: ISchema = { ...@@ -56,7 +56,7 @@ export const evaluateSchema: ISchema = {
max: 200, max: 200,
}, },
}, },
MEGA_LADYOUT: { MEGA_LADYOUT_1: {
type: 'object', type: 'object',
'x-component': 'Mega-Layout', 'x-component': 'Mega-Layout',
'x-component-props': { 'x-component-props': {
......
/*
* @Author: XieZhiXiong
* @Date: 2021-08-11 14:04:22
* @LastEditors: XieZhiXiong
* @LastEditTime: 2021-08-11 15:01:48
* @Description: 收到的评价详情 schema
*/
import { ISchema } from '@formily/antd';
import { UPLOAD_TYPE } from '@/constants';
/**
*
* @param showExplain 是否需要展示解释, 默认为 true
* @returns
*/
const createSchema = (showExplain = true): ISchema => ({
type: 'object',
properties: {
comments: {
type: 'array',
'x-component': 'EvaluationList',
default: [],
items: {
type: 'object',
properties: {
LEFT_RIGHT: {
type: 'object',
'x-component': 'LeftRightLayout',
'x-component-props': {
rightProps: {
span: 2,
offset: 4,
},
},
properties: {
MEGA_LADYOUT: {
type: 'object',
'x-component': 'Mega-Layout',
'x-component-props': {
labelCol: 6,
labelAlign: 'left',
position: 'left',
},
properties: {
star: {
title: '满意程度',
'x-component': 'Rating',
'x-component-props': {
allowHalf: false,
allowClear: false,
},
},
comment: {
type: 'string',
title: '评价',
'x-component': 'TextArea',
'x-component-props': {
rows: 4,
},
'x-rules': {
max: 200,
},
},
picture: {
type: 'string',
title: '图片',
'x-component': 'FixUpload',
'x-mega-props': {
span: 2,
},
'x-component-props': {
listType: 'card',
action: '/api/file/file/upload/prefix',
data: {
fileType: UPLOAD_TYPE,
prefix: '',
},
beforeUpload: '{{beforeUpload}}',
accept: '.png, .jpg, .jpeg',
},
'x-rules': [
{
max: 4,
message: '最多可上传4张图片',
},
],
},
...(showExplain ? {
replayTime: {
type: 'string',
title: '商家时间',
},
replayContent: {
type: 'string',
title: '商家解释',
},
} : {}),
},
},
smile: {
type: 'object',
'x-component': 'SmilingFace',
'x-component-props': {
position: 'right',
},
},
},
},
},
},
},
},
});
export default createSchema;
...@@ -81,6 +81,10 @@ export interface RecordItem { ...@@ -81,6 +81,10 @@ export interface RecordItem {
* 订单id * 订单id
*/ */
orderId: number orderId: number
/**
* 是否已解释,被评价方回复 0-否 1-是
*/
replayStatus?: number,
}; };
export interface RecordRes { export interface RecordRes {
...@@ -89,16 +93,24 @@ export interface RecordRes { ...@@ -89,16 +93,24 @@ export interface RecordRes {
}; };
interface RecordListProps { interface RecordListProps {
// 分页器类型 /**
* 分页器类型
*/
paginationType?: 'pagination' | 'button'; paginationType?: 'pagination' | 'button';
// 是否需要检索 /**
* 是否需要检索
*/
searchable?: boolean; searchable?: boolean;
// 是否是查看收到的品论 /**
* 是否是查看收到的评论
*/
opposite?: boolean; opposite?: boolean;
// 是否可编辑的 /**
* 是否可编辑的
*/
editable?: boolean; editable?: boolean;
fetchList: (params: ListParams) => Promise<RecordRes>; fetchList: (params: ListParams) => Promise<RecordRes>;
...@@ -107,8 +119,20 @@ interface RecordListProps { ...@@ -107,8 +119,20 @@ interface RecordListProps {
onEdit?: (record: RecordItem) => void; onEdit?: (record: RecordItem) => void;
// 搜索框提示语 /**
* 搜索框提示语
*/
searchTip?: string; searchTip?: string;
/**
* 是否显示解释按钮,默认 false
*/
explicable?: boolean;
/**
* 点击解释触发事件
*/
onExplain?: (record: RecordItem) => void;
}; };
interface RecordListState { interface RecordListState {
...@@ -175,6 +199,24 @@ export default class RecordList extends React.Component<RecordListProps, RecordL ...@@ -175,6 +199,24 @@ export default class RecordList extends React.Component<RecordListProps, RecordL
}); });
}; };
// 重新加载列表
refresh = () => {
this.setState({
receivedList: {
data: [],
totalCount: 0,
},
}, () => {
const { page, size } = this.state;
this.getRecordList().then(res => {
this.setState({
receivedList: res,
hasMore: checkMore(page, size, res.data.length, res.totalCount),
});
});
});
};
// 查询列表 // 查询列表
handleSearch = values => { handleSearch = values => {
this.setState({ this.setState({
...@@ -244,14 +286,22 @@ export default class RecordList extends React.Component<RecordListProps, RecordL ...@@ -244,14 +286,22 @@ export default class RecordList extends React.Component<RecordListProps, RecordL
onEdit(record); onEdit(record);
} }
}; };
handleExplain = record => {
const { onExplain } = this.props;
if (onExplain) {
onExplain(record);
}
};
render() { render() {
const { const {
paginationType = 'pagination', paginationType = 'pagination',
searchable = true, searchable = true,
opposite = true, opposite = true,
editable = false, editable = false,
searchTip = '评价方', searchTip = '评价方',
explicable = false,
} = this.props; } = this.props;
const { page, size, loading, receivedList, hasMore } = this.state; const { page, size, loading, receivedList, hasMore } = this.state;
...@@ -322,6 +372,9 @@ export default class RecordList extends React.Component<RecordListProps, RecordL ...@@ -322,6 +372,9 @@ export default class RecordList extends React.Component<RecordListProps, RecordL
{editable && ( {editable && (
<Button type="link" onClick={() => this.handleEdit(item)}>编辑</Button> <Button type="link" onClick={() => this.handleEdit(item)}>编辑</Button>
)} )}
{explicable && item.replayStatus === 0 && (
<Button type="link" onClick={() => this.handleExplain(item)}>解释</Button>
)}
<Button type="link" onClick={() => this.handleCheck(item)}>查看</Button> <Button type="link" onClick={() => this.handleCheck(item)}>查看</Button>
</div> </div>
</li> </li>
......
...@@ -14,7 +14,7 @@ import { PublicApi } from '@/services/api'; ...@@ -14,7 +14,7 @@ import { PublicApi } from '@/services/api';
import { normalizeFiledata, FileData } from '@/utils'; import { normalizeFiledata, FileData } from '@/utils';
import AvatarWrap from '@/components/AvatarWrap'; import AvatarWrap from '@/components/AvatarWrap';
import NiceForm from '@/components/NiceForm'; import NiceForm from '@/components/NiceForm';
import { evaluateSchema } from '../../common/schemas/evaluateSchema'; import createSchema from '../../common/schemas/receivedSchema';
import { createEffects } from '../../common/effects'; import { createEffects } from '../../common/effects';
import EvaluationList from '../../components/EvaluationList'; import EvaluationList from '../../components/EvaluationList';
...@@ -171,7 +171,7 @@ const ReceivedDetail: React.FC = () => { ...@@ -171,7 +171,7 @@ const ReceivedDetail: React.FC = () => {
effects={($, actions) => { effects={($, actions) => {
createEffects($, actions); createEffects($, actions);
}} }}
schema={evaluateSchema} schema={createSchema(false)}
/> />
</PageHeaderWrapper> </PageHeaderWrapper>
</Spin> </Spin>
......
...@@ -21,7 +21,7 @@ import EvaluationList from '../../../components/EvaluationList'; ...@@ -21,7 +21,7 @@ import EvaluationList from '../../../components/EvaluationList';
const formActions = createFormActions(); const formActions = createFormActions();
const { const {
onFormInit$, onFormInit$,
} = FormEffectHooks; } = FormEffectHooks;
interface Unevaluated { interface Unevaluated {
...@@ -144,19 +144,18 @@ const DetailInfo: React.FC<DetailInfoProps> = ({ ...@@ -144,19 +144,18 @@ const DetailInfo: React.FC<DetailInfoProps> = ({
return Promise.resolve(); return Promise.resolve();
}; };
const UploadTip = ( const UploadTip = () => (
<span <div
style={{ style={{
lineHeight: '24px', lineHeight: '24px',
color: '#909399', color: '#909399',
fontWeight: 400, fontWeight: 400,
wordBreak: 'break-all', wordBreak: 'break-all',
position: 'relative', position: 'relative',
top: '34px',
}} }}
> >
支持JPG/PNG/JPEG <br />每张最大不超过 10M,尺寸不限 <br />最大数量限制 4张 支持JPG/PNG/JPEG <br />每张最大不超过 10M,尺寸不限 <br />最大数量限制 4张
</span> </div>
); );
return ( return (
...@@ -220,15 +219,36 @@ const DetailInfo: React.FC<DetailInfoProps> = ({ ...@@ -220,15 +219,36 @@ const DetailInfo: React.FC<DetailInfoProps> = ({
}} }}
editable={isEdit} editable={isEdit}
expressionScope={{ expressionScope={{
UploadTip: isEdit ? UploadTip : null,
beforeUpload, beforeUpload,
}} }}
onSubmit={handleSubmit}
components={{ components={{
EvaluationList, EvaluationList,
UploadTip,
}} }}
onSubmit={handleSubmit}
effects={($, actions) => { effects={($, actions) => {
createEffects($, actions); createEffects($, actions);
onFormInit$().subscribe(() => {
// 控制不同样式
if (!isEdit) {
actions.setFieldState('comments.*.MEGA_LADYOUT_1', (fieldState) => {
fieldState.props['x-component-props'] = {
...(fieldState.props['x-component-props'] || {}),
labelCol: 6,
};
});
actions.setFieldState('comments.*.UPLOAD_TIP', (fieldState) => {
fieldState.visible = false;
});
actions.setFieldState('comments.*.picture', (fieldState) => {
fieldState.props['x-mega-props'] = {
...(fieldState.props['x-mega-props'] || {}),
span: 3,
};
});
}
});
}} }}
schema={evaluateSchema} schema={evaluateSchema}
/> />
......
/*
* @Author: XieZhiXiong
* @Date: 2021-08-11 14:20:42
* @LastEditors: XieZhiXiong
* @LastEditTime: 2021-08-11 15:28:33
* @Description: 解释 Modal
*/
import React from 'react';
import { Modal, Tooltip } from 'antd';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { createAsyncFormActions } from '@formily/antd';
import NiceForm from '@/components/NiceForm';
import schema from './schema';
const modalFormActions = createAsyncFormActions();
export type ValuesType = {
/**
* 解释内容
*/
content: string,
}
interface ExplainModalProps {
visible: boolean;
confirmLoading: boolean;
onSubmit: (values: ValuesType) => void;
/**
* 关闭触发事件
*/
onClose: () => void;
/**
* 是否只可以选择 不接受申请
*/
rejected?: boolean;
}
const ExplainModal: React.FC<ExplainModalProps> = (props) => {
const {
visible,
confirmLoading,
onSubmit,
onClose,
} = props;
const handleClose = () => {
onClose?.();
};
const handleSubmit = values => {
if (onSubmit) {
onSubmit(values);
}
};
return (
<Modal
title={(
<>
商家解释
<Tooltip title="商家对于评价的解释,显示在商品交易评价中">
<QuestionCircleOutlined style={{ marginLeft: 3 }} />
</Tooltip>
</>
)}
visible={visible}
confirmLoading={confirmLoading}
onOk={() => modalFormActions.submit()}
onCancel={handleClose}
>
<NiceForm
effects={() => {
}}
actions={modalFormActions}
schema={schema}
onSubmit={handleSubmit}
/>
</Modal>
);
};
export default ExplainModal;
/*
* @Author: XieZhiXiong
* @Date: 2021-08-11 14:23:08
* @LastEditors: XieZhiXiong
* @LastEditTime: 2021-08-11 14:58:47
* @Description:
*/
import { ISchema } from '@formily/antd';
const schema: ISchema = {
type: 'object',
properties: {
MEGA_LAYOUT: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
labelAlign: 'top',
},
properties: {
content: {
type: 'string',
'x-component': 'textarea',
'x-component-props': {
placeholder: '在此输入你的内容',
rows: 5,
},
'x-rules': [
{
required: true,
message: '请输入内容',
},
],
},
},
},
},
};
export default schema;
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState, useRef } from 'react';
import { Tabs, Row, Col, Button } from 'antd'; import { Tabs, Row, Col } from 'antd';
import { history } from 'umi'; import { history } from 'umi';
import { observer, inject } from 'mobx-react'; import { observer, inject } from 'mobx-react';
import { PageHeaderWrapper } from '@ant-design/pro-layout'; import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { PublicApi } from '@/services/api'; import { PublicApi } from '@/services/api';
import { isJSONStr } from '@/utils';
import { IEvaluationModule } from '@/module/evaluationModule'; import { IEvaluationModule } from '@/module/evaluationModule';
import MellowCard from '@/components/MellowCard'; import MellowCard from '@/components/MellowCard';
import PolymericTable from '@/components/PolymericTable'; import PolymericTable from '@/components/PolymericTable';
import { EditableColumns } from '@/components/PolymericTable/interface'; import { EditableColumns } from '@/components/PolymericTable/interface';
import { Pie } from '@/components/Charts'; import { Pie } from '@/components/Charts';
import Mood from '@/components/Mood'; import Mood from '@/components/Mood';
import ExplainModal, { ValuesType } from './components/ExplainModal';
import Shelves from '../../purchaserEvaluation/components/Shelves'; import Shelves from '../../purchaserEvaluation/components/Shelves';
import RecordList, { ListParams, RecordRes } from '../../purchaserEvaluation/components/RecordList'; import RecordList, { ListParams, RecordRes, RecordItem } from '../../purchaserEvaluation/components/RecordList';
import styles from './index.less'; import styles from './index.less';
const { TabPane } = Tabs; const { TabPane } = Tabs;
...@@ -57,8 +57,14 @@ const Analysis: React.FC<AnalysisProps> = ({ ...@@ -57,8 +57,14 @@ const Analysis: React.FC<AnalysisProps> = ({
const [evaluateSum, setEvaluateSum] = useState([]); const [evaluateSum, setEvaluateSum] = useState([]);
const [evaluatePie, setEvaluatePie] = useState([]); const [evaluatePie, setEvaluatePie] = useState([]);
const [visibleExplainModal, setVisibleExplainModal] = useState(false);
const [explainConfirmLoading, setExplainConfirmLoading] = useState(false);
const { supplier, setSupplierActiveKey } = EvaluationStore; const { supplier, setSupplierActiveKey } = EvaluationStore;
const recordListRef = useRef<RecordList | null>(null);
const currentRecordRef = useRef<RecordItem | null>(null);
const summaryEvaluate = (items: EstimateSumItems[]): EstimateSumItems[] => { const summaryEvaluate = (items: EstimateSumItems[]): EstimateSumItems[] => {
// 顺序写死的 1:表示好评,2:表示中评,3:表示差评 // 顺序写死的 1:表示好评,2:表示中评,3:表示差评
// 根据 1、2星级为差评,3星级为中评,4、5星级为好评往里边塞数据 // 根据 1、2星级为差评,3星级为中评,4、5星级为好评往里边塞数据
...@@ -213,15 +219,16 @@ const Analysis: React.FC<AnalysisProps> = ({ ...@@ -213,15 +219,16 @@ const Analysis: React.FC<AnalysisProps> = ({
resolve({ resolve({
data: data.map(item => { data: data.map(item => {
return { return {
id: item.id, id: item.id,
star: item.star, star: item.star,
comment: item.comment, comment: item.comment,
productName: item.product || '', productName: item.product || '',
price: item.price, price: item.price,
quantity: item.purchaseCount, quantity: item.purchaseCount,
created: item.dealTime as string, created: item.dealTime as string,
target: item.memberName, target: item.memberName,
orderId: item.orderId, orderId: item.orderId,
replayStatus: item.replayStatus,
}; };
}), }),
totalCount, totalCount,
...@@ -312,6 +319,30 @@ const Analysis: React.FC<AnalysisProps> = ({ ...@@ -312,6 +319,30 @@ const Analysis: React.FC<AnalysisProps> = ({
history.push(`/memberCenter/tranactionAbility/supplierEvaluation/sent/detail?id=${record.id}`); history.push(`/memberCenter/tranactionAbility/supplierEvaluation/sent/detail?id=${record.id}`);
}; };
const handleVisibleExplainModal = (flag?: boolean) => {
setVisibleExplainModal(!!flag);
};
const handleExplain = (record: RecordItem) => {
currentRecordRef.current = record;
handleVisibleExplainModal(true);
};
const handleExplainSubmit = (values: ValuesType) => {
setExplainConfirmLoading(true);
PublicApi.postMemberCommentSupplyReceiveTradeHistoryReply({
id: currentRecordRef.current.id,
content: values.content,
}).then((res) => {
if (res.code === 1000) {
recordListRef.current?.refresh();
handleVisibleExplainModal(false);
}
}).finally(() => {
setExplainConfirmLoading(false);
});
};
return ( return (
<PageHeaderWrapper> <PageHeaderWrapper>
<MellowCard <MellowCard
...@@ -367,6 +398,10 @@ const Analysis: React.FC<AnalysisProps> = ({ ...@@ -367,6 +398,10 @@ const Analysis: React.FC<AnalysisProps> = ({
<RecordList <RecordList
fetchList={getReceivedList} fetchList={getReceivedList}
onCheck={handleJumpReceived} onCheck={handleJumpReceived}
onExplain={handleExplain}
opposite={false}
explicable={true}
ref={recordListRef}
/> />
</TabPane> </TabPane>
...@@ -382,6 +417,13 @@ const Analysis: React.FC<AnalysisProps> = ({ ...@@ -382,6 +417,13 @@ const Analysis: React.FC<AnalysisProps> = ({
</TabPane> </TabPane>
</Tabs> </Tabs>
</MellowCard> </MellowCard>
<ExplainModal
visible={visibleExplainModal}
onClose={() => handleVisibleExplainModal(false)}
confirmLoading={explainConfirmLoading}
onSubmit={handleExplainSubmit}
/>
</PageHeaderWrapper> </PageHeaderWrapper>
); );
}; };
......
...@@ -14,7 +14,7 @@ import { PublicApi } from '@/services/api'; ...@@ -14,7 +14,7 @@ import { PublicApi } from '@/services/api';
import { normalizeFiledata, FileData } from '@/utils'; import { normalizeFiledata, FileData } from '@/utils';
import AvatarWrap from '@/components/AvatarWrap'; import AvatarWrap from '@/components/AvatarWrap';
import NiceForm from '@/components/NiceForm'; import NiceForm from '@/components/NiceForm';
import { evaluateSchema } from '../../../purchaserEvaluation/common/schemas/evaluateSchema'; import createSchema from '../../../purchaserEvaluation/common/schemas/receivedSchema';
import { createEffects } from '../../../purchaserEvaluation/common/effects'; import { createEffects } from '../../../purchaserEvaluation/common/effects';
import EvaluationList from '../../../purchaserEvaluation/components/EvaluationList'; import EvaluationList from '../../../purchaserEvaluation/components/EvaluationList';
...@@ -31,7 +31,9 @@ interface Unevaluated { ...@@ -31,7 +31,9 @@ interface Unevaluated {
star: number; star: number;
comment: string; comment: string;
picture: FileData[]; picture: FileData[];
smile: number; smile: number;
replayContent: string,
replayTime: string,
}; };
interface OrderInfo { interface OrderInfo {
...@@ -69,6 +71,8 @@ const ReceivedDetail: React.FC = () => { ...@@ -69,6 +71,8 @@ const ReceivedDetail: React.FC = () => {
comment: res.data.comment, comment: res.data.comment,
picture: res.data.pics ? res.data.pics.map(item => normalizeFiledata(item)) : [], picture: res.data.pics ? res.data.pics.map(item => normalizeFiledata(item)) : [],
smile: res.data.star, smile: res.data.star,
replayContent: res.data.replayContent,
replayTime: res.data.replayTime,
}); });
setOrderInfo({ setOrderInfo({
orderNo: res.data.orderNo, orderNo: res.data.orderNo,
...@@ -173,7 +177,7 @@ const ReceivedDetail: React.FC = () => { ...@@ -173,7 +177,7 @@ const ReceivedDetail: React.FC = () => {
effects={($, actions) => { effects={($, actions) => {
createEffects($, actions); createEffects($, actions);
}} }}
schema={evaluateSchema} schema={createSchema()}
/> />
</PageHeaderWrapper> </PageHeaderWrapper>
</Spin> </Spin>
......
...@@ -144,19 +144,18 @@ const DetailInfo: React.FC<DetailInfoProps> = ({ ...@@ -144,19 +144,18 @@ const DetailInfo: React.FC<DetailInfoProps> = ({
return Promise.resolve(); return Promise.resolve();
}; };
const UploadTip = ( const UploadTip = () => (
<span <div
style={{ style={{
lineHeight: '24px', lineHeight: '24px',
color: '#909399', color: '#909399',
fontWeight: 400, fontWeight: 400,
wordBreak: 'break-all', wordBreak: 'break-all',
position: 'relative', position: 'relative',
top: '34px',
}} }}
> >
支持JPG/PNG/JPEG <br />每张最大不超过 10M,尺寸不限 <br />最大数量限制 4张 支持JPG/PNG/JPEG <br />每张最大不超过 10M,尺寸不限 <br />最大数量限制 4张
</span> </div>
); );
return ( return (
...@@ -222,15 +221,36 @@ const DetailInfo: React.FC<DetailInfoProps> = ({ ...@@ -222,15 +221,36 @@ const DetailInfo: React.FC<DetailInfoProps> = ({
}} }}
editable={isEdit} editable={isEdit}
expressionScope={{ expressionScope={{
UploadTip: isEdit ? UploadTip : null,
beforeUpload, beforeUpload,
}} }}
onSubmit={handleSubmit}
components={{ components={{
EvaluationList, EvaluationList,
UploadTip,
}} }}
onSubmit={handleSubmit}
effects={($, actions) => { effects={($, actions) => {
createEffects($, actions); createEffects($, actions);
onFormInit$().subscribe(() => {
// 控制不同样式
if (!isEdit) {
actions.setFieldState('comments.*.MEGA_LADYOUT_1', (fieldState) => {
fieldState.props['x-component-props'] = {
...(fieldState.props['x-component-props'] || {}),
labelCol: 6,
};
});
actions.setFieldState('comments.*.UPLOAD_TIP', (fieldState) => {
fieldState.visible = false;
});
actions.setFieldState('comments.*.picture', (fieldState) => {
fieldState.props['x-mega-props'] = {
...(fieldState.props['x-mega-props'] || {}),
span: 3,
};
});
}
});
}} }}
schema={evaluateSchema} schema={evaluateSchema}
/> />
......
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