Commit 3ab2db6e authored by Bill's avatar Bill

feat: 会员考察管理

parent d2b27c0d
const MAIN_COLOR = '#00B37A'
const SECONDARY_COLOR = '#E4F7EF'
const MAIN_FONT_BOLD_COLOR = '#303133'
const MAIN_FONT_TINY_COLOR = '#909399'
export default {
'@primary-color': MAIN_COLOR,
'@secondary-color': SECONDARY_COLOR,
// 公共padding变量
'@padding-lg': '24px',
'@padding-sm': '12px',
......
......@@ -15,7 +15,7 @@
// import AfterService from './afterServiceRoute' // 售后
// import HandlingRoute from './handlingRoute'; // 加工能力
import asyncRoutes from '../router.config.json';
import ProcurementRoute from './procurementRoute';
// import ProcurementRoute from './procurementRoute';
// import { callForBidsRoute } from './procurementRoute/callForBids';
// import { purchaseInquiryRoute } from './procurementRoute/purchaseInquiry';
// import contracRoute from './contracRoute';
......@@ -62,6 +62,7 @@ const memberCenterRoute = {
// contracRoute,
//...
// AuthConfigRoute,
// MemberRoute,
...asyncRoutes,
{
path: '/memberCenter/noAuth',
......
......@@ -286,6 +286,26 @@ const MemberRoute: RouterChild = {
noMargin: true,
component: '@/pages/member/memberQuery/addSubRole',
},
// 会员考察
{
path: '/memberCenter/memberAbility/memberInspection',
name: '会员考察',
routes: [
{
path: '/memberCenter/memberAbility/memberInspection/inspection',
name: '会员考察管理',
component: '@/pages/member/memberInspection/index',
},
// 会员考察 -- 新增
{
path: '/memberCenter/memberAbility/memberInspection/inspection/add',
name: '新建会员考察',
component: '@/pages/member/memberInspection/add'
}
]
},
]
}
......
......@@ -35,7 +35,7 @@ const Search = props => {
});
};
return (
<Space size={20} style={{ justifyContent: justifyAlign, width: '100%' }}>
<Space size={[16, 0]} style={{ justifyContent: justifyAlign, width: '100%' }}>
<Tooltip title={tip}>
<Input.Search
value={props.value || ''}
......
import React, { useEffect } from 'react';
import UploadFiles from './UploadFiles';
import { UploadProps, UploadChangeParam, UploadFile } from 'antd/lib/upload/interface'
import { Button } from 'antd';
interface Iprops {
value: UploadFile[],
props: any,
mutators: any,
}
const toArray = (value: string | UploadFile[]): UploadFile[] => {
if (!value) {
return [];
}
if (Array.isArray(value)) {
return value;
}
}
const FormilyUploadFiles: React.FC<Iprops> = (props: Iprops) => {
// const editable = props.editable;
const { value } = props;
const componentProps = props.props?.['x-component-props'] || {};
const fileList = toArray(value)
const onChange = (info: UploadChangeParam) => {
const file = info.file;
const tempData = {
name: file.name,
url: file.url || file.response?.data,
uid: file.uid,
status: file.status,
percent: file.percent,
size: file.size,
type: file.type,
}
const list = [...fileList];
list.push(tempData);
props.mutators.change(list)
}
const onRemove = (fileItem: UploadFile) => {
const list = [...fileList];
const newList = list.filter((_item) => _item.url !== fileItem.url);
props.mutators.change(newList);
}
return (
<UploadFiles fileList={fileList} onChange={onChange} onRemove={onRemove} {...componentProps} />
)
}
const WrapFormilyUploadFiles: typeof FormilyUploadFiles & {
isFieldComponent?: boolean,
} = FormilyUploadFiles;
WrapFormilyUploadFiles.isFieldComponent = true
export default WrapFormilyUploadFiles
.renderFileContainer {
display: flex;
flex-direction: column;
margin-bottom: @margin-md;
.renderFileItemContainer {
position: relative;
padding: 0 @padding-sm;
display: flex;
flex-direction: column;
justify-content: center;
.uploadProgress {
position: absolute;
top: -5px;
left: 0;
right: 0;
display: none;
}
.renderFileItem {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.img {
width: 16px;
height: 16px;
}
}
&:hover {
background-color: @secondary-color;
color: @main-color;
}
}
}
.fileEmpty {
margin-bottom: 0;
}
import React, { useState } from 'react';
import cx from 'classnames'
import { UploadProps, UploadChangeParam, UploadFile } from 'antd/lib/upload/interface'
import { UPLOAD_TYPE } from '@/constants';
import { Upload, Progress, Button } from 'antd';
import { CloudUploadOutlined, DeleteOutlined } from '@ant-design/icons';
import styles from './UploadFiles.less';
import pdf_icon from '@/assets/imgs/pdf_icon.png';
type PickProps = "headers" | "action" | "accept" | "beforeUpload" | "onChange" | "fileList"
interface PickUploadProps extends Pick<UploadProps, PickProps> {
children?: React.ReactElement,
customizeItemRender?: ((files: UploadFile[], handleRemove: (fileItem: UploadFile) => void) => React.ReactNode) | null,
onRemove?: ((fileItem: UploadFile) => void) | null,
}
const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
const { headers, action, accept, beforeUpload, onChange, children, customizeItemRender, onRemove } = props;
const hasFileListProps = "fileList" in props;
const [files, setFiles] = useState<UploadFile[]>([]);
const renderFiles = hasFileListProps ? props.fileList : files;
const filesContainerCs = cx({
[styles.fileEmpty]: renderFiles.length === 0,
}, styles.renderFileContainer)
const uploadProps = {
name: 'file',
fileList: hasFileListProps ? props.fileList : files,
accept: accept,
action: action,
headers: headers,
data: {
fileType: UPLOAD_TYPE
},
// disabled: loading || disabled,
showUploadList: false,
onChange(info: UploadChangeParam) {
// 如果不存在fileList, 只存在onChange 那么也要改变组件的file
if (!("fileList" in props)) {
setFiles(info.fileList);
}
if(onChange) {
onChange(info)
}
},
beforeUpload
}
const handleRemove = (fileItem: UploadFile) => {
if(onRemove) {
onRemove(fileItem);
}
if(!hasFileListProps) {
const newFileList = files.filter((_item) => _item.url !== fileItem.url);
setFiles(newFileList);
}
}
const renderFileItem = () => {
return (
<div className={filesContainerCs}>
{
renderFiles.map((_item: UploadFile, key) => {
return (
<div className={styles.renderFileItemContainer} key={key}>
{
_item.status === 'uploading' && (
<div className={styles.uploadProgress}>
<Progress percent={_item.percent} status="active" size="small" showInfo={false}/>
</div>
)
}
<div className={styles.renderFileItem} >
<div>
<img className={styles.img} src={pdf_icon} />
<span>{_item.name}</span>
</div>
<DeleteOutlined onClick={() => handleRemove(_item)} />
</div>
</div>
)
})
}
</div>
)
}
return (
<div>
{
!!customizeItemRender ? customizeItemRender(renderFiles, handleRemove) : renderFileItem()
}
<Upload {...uploadProps}>
{
children || (
<Button>
<CloudUploadOutlined /> 上传文件
</Button>
)
}
</Upload>
</div>
)
}
UploadFiles.defaultProps = {
action: '/api/file/file/upload',
headers: {},
beforeUpload: (file, fileList) => true,
onChange: (file: UploadChangeParam) => {},
customizeItemRender: null,
onRemove: null,
// fileList: []
}
export default UploadFiles
......@@ -220,7 +220,7 @@ function useFetchColumns(mode: 'payable' | 'receiveable') {
render: (text: string, record: any) => {
if (mode === 'payable') {
// 待对账的时候可以手动结算
if (record.status === TO_BE_RECONCILED) {
if (record.status === TO_BE_RECONCILED && record.orderType !== CONTRACT_FUND_BILL) {
return <a onClick={() => handleManualsettlement(record.id)}>手动结算</a>
}
if (record.status === TO_BE_PAY) {
......
......@@ -218,7 +218,12 @@ const MemberSettleAdd: React.FC = () => {
otherValues: [res.data.settlementDays, res.data.settlementDate],
}
})
const list = res.data.memberList.map((item) => ({...item, uniqueId: item.memberId + "_" + item.roleId}))
const list = res.data.memberList.map((item) => ({
...item,
uniqueId: item.memberId + "_" + item.roleId,
name: item.memberName,
levelTag: item.levelName,
}))
formActions.setFieldValue('Tabs.memberTab.someLists', list);
// 必须设置key
memberRowCtl.setSelectRow(list);
......
......@@ -16,11 +16,12 @@ interface Iprops {
* 主要用在header 右边连接ReactNode
*/
extra?: ReactNode,
children: (<T>(params: {loading: boolean, requestData: T}) => React.ReactElement),
/**
* request
*/
request?: () => Promise<any>
};
const AbilityContainer: React.FC<Iprops> = (props) => {
......@@ -32,16 +33,16 @@ const AbilityContainer: React.FC<Iprops> = (props) => {
useEffect(() => {
if(inViewPort && !flag) {
setLoading(true);
props.request &&
props.request()
props?.request()
.then(({code, data}) => {
if(code === 1000) {
setData(data)
}
setFlag(true)
setLoading(false)
}).catch(error => {
setFlag(true)
setFlag(false)
}).finally(() => {
setLoading(false)
})
}
}, [inViewPort])
......
import React, { useMemo } from 'react';
import { Button } from 'antd';
import Layout from './layout';
import useViewRequest from '../../hooks/useViewRequest';
import { PublicApi } from '@/services/api';
import { BellOutlined } from '@ant-design/icons';
import theme from '@/../config/lingxi.theme.config';
interface Iprops {}
const Constract: React.FC<Iprops> = (props: Iprops) => {
const { loading, isError, hasRequest, responseData, ref } = useViewRequest(PublicApi.getReportMemberHomeGetEnhanceTally, {})
const constractTipsStyle = useMemo(() => ({
backgroundColor: theme["@secondary-color"],
color: theme["@primary-color"],
padding: '8px 12px',
fontSize: 12,
fontWeight: 500,
display: 'flex',
FlexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
// flexDirection: 'row',
}), [])
return (
<Layout
viewRef={ref}
title="合同中心"
tips="提供在电子签章申请,合同管理、电子合同签订、合同请款、合同协同等功能"
loading={loading}
>
<div style={constractTipsStyle}>
<div>
<BellOutlined />
<span style={{marginLeft: '12px'}}>您还没有申请电子签章,请先申请电子签章</span>
</div>
<Button size="small" type="primary">点击申请</Button>
</div>
</Layout>
)
}
export default Constract
......@@ -67,7 +67,7 @@ const FundCenter: React.FC<Iprops> = () => {
<div className={styles.centerRow}>
{
tagsList.map((item) => {
const hasAuth = !urls.includes(item.url);;
const hasAuth = !urls.includes(item.url);
if(!hasAuth) {
return null
}
......
import React, { useCallback } from 'react';
import { Skeleton, Badge } from 'antd';
import { Link } from 'umi';
import AbilityContainer from './Container';
import styles from './center.less'
import logistics from '@/assets/imgs/logistics.png';
......@@ -6,19 +8,18 @@ import logistics_form from '@/assets/imgs/logistics_form.png';
import logistics_address from '@/assets/imgs/logistics_address.png';
import logistics_cost from '@/assets/imgs/logistics_cost.png';
import { PublicApi } from '@/services/api';
import { Skeleton, Badge } from 'antd';
import { Link } from 'umi';
import Authorize from '../Authorize';
import { getAuth } from '@/utils/auth';
import useViewRequest from '../../hooks/useViewRequest';
import Layout from './layout';
import { GetReportMemberHomeGetLogisticsTallyResponse } from '@/services/ReportApi/id3280';
interface Iprops {};
const url = '/memberCenter/logisticsAbility/logisticsResult/orderResultSearchList';
const LogisticsCenter: React.FC<Iprops> = () => {
const request = useCallback(async () => {
///report/member/home/getLogisticsTally
const res = await PublicApi.getReportMemberHomeGetLogisticsTally();
return res;
}, [])
const LogisticsCenter: React.FC<Iprops> = (props: Iprops) => {
const { loading, responseData, ref } = useViewRequest<GetReportMemberHomeGetLogisticsTallyResponse, any>(PublicApi.getReportMemberHomeGetLogisticsTally, {})
const userAuth = getAuth();
const urls = userAuth.urls;
const data = [
......@@ -51,7 +52,8 @@ const LogisticsCenter: React.FC<Iprops> = () => {
}
]
return (
<AbilityContainer
<Layout
viewRef={ref}
title="物流中心"
tips={"快速完成物流派单、接单、报价、物流信息对接"}
extra={
......@@ -63,45 +65,28 @@ const LogisticsCenter: React.FC<Iprops> = () => {
</div>
</Authorize>
}
request={request}
loading={loading}
>
{
({loading, requestData}) => {
return (
<>
{
loading
? <Skeleton active />
: <>
<div className={styles.centerRow}>
{
data.map((item) => {
// const hasAuth = !urls.includes(item.url);
// if(!hasAuth) {
// return null
// }
return (
<Link key={item.text} to={item.url} className={styles.tagsItem}>
<div className={styles.icon}>
<img src={item.icon} />
</div>
<div className={styles.text}>{item.text}</div>
<Badge count={item.key && requestData[item.key] || 0} className={styles.badge}></Badge>
</Link>
)
})
}
</div>
</>
}
</>
)
<div className={styles.centerRow}>
{
data.map((item) => {
// const hasAuth = !urls.includes(item.url);
// if(!hasAuth) {
// return null
// }
return (
<Link key={item.text} to={item.url} className={styles.tagsItem}>
<div className={styles.icon}>
<img src={item.icon} />
</div>
<div className={styles.text}>{item.text}</div>
<Badge count={item.key && responseData?.[item.key] || 0} className={styles.badge}></Badge>
</Link>
)
})
}
}
</AbilityContainer>
</div>
</Layout>
)
}
......
import React, { useCallback } from 'react';
import AbilityContainer from './Container';
import { Row, Col,Skeleton } from 'antd';
import React from 'react';
import styles from './center.less';
import { PublicApi } from '@/services/api'
import { Link } from 'umi'
import Layout from './layout';
import Authorize from '../Authorize';
import useViewRequest from '../../hooks/useViewRequest';
import { GetReportMemberHomeGetEnhanceTallyResponse } from '@/services/ReportApi';
interface Iprops {};
const url = '/memberCenter/handling/assign/query'
......@@ -15,12 +16,10 @@ const KEY_TITLE = {
}
const ProcessCenter: React.FC<Iprops> = () => {
const request = useCallback(async () => {
const res = await PublicApi.getReportMemberHomeGetEnhanceTally();
return res;
}, [])
const { loading, responseData, isError, ref } = useViewRequest<GetReportMemberHomeGetEnhanceTallyResponse, any>(PublicApi.getReportMemberHomeGetEnhanceTally, {})
return (
<AbilityContainer
<Layout
viewRef={ref}
title="加工中心"
tips="提供外发生产、加工、装配全流程环节管控"
extra={
......@@ -32,45 +31,35 @@ const ProcessCenter: React.FC<Iprops> = () => {
</div>
</Authorize>
}
request={request}
loading={loading}
isError={isError}
>
{
({loading, requestData}) => {
responseData && Object.keys(responseData).map((record) => {
return (
<>
{
loading
? <Skeleton active />
: Object.keys(requestData).map((record) => {
<div className={styles.wrapRow} key={record}>
<span className={styles.rowTitle}>{KEY_TITLE[record]}</span>
<div className={styles.rowValues}>
{
responseData[record].map((_item, key) => {
return (
<div className={styles.wrapRow} key={record}>
<span className={styles.rowTitle}>{KEY_TITLE[record]}</span>
<div className={styles.rowValues}>
{
requestData[record].map((item, key) => {
return (
<div className={styles.wrapCol} key={key}>
<div className={styles.colTitle}>{item.name}</div>
{
item.link
? <Link to={item.link} className={styles.colValue}>{item.count}</Link>
: <div className={styles.colValue}>{item.count}</div>
}
</div>
)
})
}
</div>
<div className={styles.wrapCol} key={key}>
<div className={styles.colTitle}>{_item.name}</div>
{
_item.link
? <Link to={_item.link} className={styles.colValue}>{_item.count}</Link>
: <div className={styles.colValue}>{_item.count}</div>
}
</div>
)
})
}
</>
}
</div>
</div>
)
}
})
}
</AbilityContainer>
</Layout>
)
}
......
......@@ -9,8 +9,7 @@
padding-right: 10px;
background: #FAFBFC;
align-self: flex-start;
margin-right: 16px;
margin: 18px 0;
margin: 18px 16px 18px 0;
.icon {
width: 32px;
......
......@@ -6,6 +6,7 @@ import AfterSoldCenter from './AfterSoldCenter'
import LogisticsCenter from './LogisticsCenter'
import ProcessCenter from './ProcessCenter';
import FundCenter from './FundCenter';
import Contract from './Contract';
export {
TradeCenter,
......@@ -15,5 +16,6 @@ export {
AfterSoldCenter,
LogisticsCenter,
ProcessCenter,
FundCenter
}
\ No newline at end of file
FundCenter,
Contract
}
import React, { ReactNode, useEffect, useState } from 'react';
import { Button } from 'antd';
import styles from './Container.less';
import {useInViewport} from '@umijs/hooks';
import { Skeleton } from 'antd';
import useViewRequest from '../../hooks/useViewRequest';
interface Iprops {
viewRef: any,
/**
* 标题
*/
title?: string,
/**
* 标题下面的一行字
*/
tips?: string,
/**
* 主要用在header 右边连接ReactNode
*/
extra?: ReactNode,
children: React.ReactNode,
/**
* request
*/
// fn: <T, P>(params: T) => Promise<P>
loading: boolean,
/**
* 是否出错
*/
isError?: boolean,
/**
* 出错是的render方法
*/
customizeErrorRender?: (() => React.ReactElement )| null
// onRefresh: () => void
};
const Layout: React.FC<Iprops> = (props) => {
const { title, tips, extra, children, loading, isError, customizeErrorRender, viewRef } = props;
const renderStatus = () => {
if (loading) {
return (<Skeleton active />)
}
if (isError) {
return (
customizeErrorRender?.() || (
<div>
<Button>拉取数据时发生了错误,点击刷新</Button>
</div>
)
)
}
return children;
}
return (
<div className={styles.container} ref={viewRef}>
<div className={styles.header}>
<div className={styles.left}>
<div className={styles.title}>{title}</div>
<div className={styles.tips}>{tips}</div>
</div>
<div className={styles.extra}>
{extra}
</div>
</div>
<div className={styles.body}>
{renderStatus()}
</div>
</div>
)
}
Layout.defaultProps = {
title: '',
tips: '',
extra: null,
isError: false,
customizeErrorRender: null
}
export default Layout;
import { Loading3QuartersOutlined, TrophyOutlined } from '@ant-design/icons';
import { useInViewport } from '@umijs/hooks';
import { useCallback, useEffect, useState } from 'react';
interface ResponseDataType {
code: number,
message: string
}
/***
* 当下拉滚动到可视区域时请求数据
*/
function useViewRequest<T, P>(fn: (postData: P) => Promise<ResponseDataType & { data: T }>, params?: P) {
const [loading, setLoading] = useState<boolean>(false);
const [isError, setIsError] = useState<boolean>(false);
const [inViewPort, ref] = useInViewport<HTMLDivElement>();
const [hasRequest, setHasRequest] = useState<boolean>()
const [responseData, setResponseData] = useState<T | null>(null);
const fetchData = useCallback(async (params) => {
setLoading(() => true);
try {
const { data, code, message } = await fn(params);
// throw new Error("123");
if (code === 1000) {
setResponseData(data as T)
}
} catch(error) {
setIsError(() => true);
} finally {
setHasRequest(() => true);
setLoading(() => false);
}
}, [fn])
useEffect(() => {
if (!inViewPort || !fn || loading) {
return;
}
async function init() {
await fetchData(params)
}
init()
}, [inViewPort])
const refresh = async <T1 extends P>(refreshParams: T1) => {
fetchData(refreshParams)
}
return { loading, isError, ref, hasRequest, refresh, responseData }
}
export default useViewRequest
.userGuaid {
margin-bottom: @padding-sm;
}
.container {
display: flex;
flex-direction: row;
......
......@@ -8,10 +8,11 @@ import LatestAnnounce from './components/LatestAnnounces';
import RecentVisit from './components/RecentVisit';
import AnyQuestion from './components/AnyQuestion';
import AdvertisementContainer from './components/AdvertisementSpace';
import { TradeCenter,FundCenter, ShopCenter, ProductCenter, SettlementCenter, AfterSoldCenter, LogisticsCenter, ProcessCenter } from './components/Centers';
import { TradeCenter, FundCenter, ShopCenter, ProductCenter, SettlementCenter, AfterSoldCenter, LogisticsCenter, ProcessCenter, Contract } from './components/Centers';
import styles from './index.less'
import { CompassFilled } from '@ant-design/icons';
import { PublicApi } from '@/services/api';
import { GetReportMemberHomeGetDataLayoutRequest } from '@/services/ReportApi';
const ComponentSelect = {
"交易中心": TradeCenter,
......@@ -22,24 +23,35 @@ const ComponentSelect = {
"售后中心": AfterSoldCenter,
"物流中心": LogisticsCenter,
"加工中心": ProcessCenter,
"合同中心": Contract,
"数据中心": '',
"风控中心": ''
}
const Home: React.FC<{}> = () => {
const [visible, setVisible] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false);
const [layout, setLayout] = useState<any>([]);
const [layout, setLayout] = useState<GetReportMemberHomeGetDataLayoutRequest>([]);
useEffect(() => {
setLoading(true);
PublicApi.getReportMemberHomeGetDataLayout()
.then(({data, code}) => {
if(code === 1000) {
setLayout(data)
async function getDataLayout() {
setLoading(true)
try {
const { data, code, message } = await PublicApi.getReportMemberHomeGetDataLayout();
if (code === 1000) {
// const tempData = {
// code: 11,
// name: '合同中心',
// sort: 11,
// isShow: 1,
// }
// const newList = data.concat(tempData);
setLayout(data)
}
} finally {
setLoading(false)
}
}).finally(() => {
setLoading(false)
})
}
getDataLayout();
}, [])
const handleChangeOrder = (list) => {
......@@ -53,7 +65,7 @@ const Home: React.FC<{}> = () => {
return (
<PageHeaderWrapper>
<div className={styles.userGuaid} style={{display: visible ? 'none': 'none'}}>
<div className={styles.userGuaid} style={{display: visible ? 'block': 'none'}}>
<UseGuaid/>
</div>
<div className={styles.container}>
......
import React, { useState } from 'react';
import { Card, Button } from 'antd';
import { history } from 'umi';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { LinkOutlined, SaveOutlined } from '@ant-design/icons';
import { createFormActions } from '@formily/antd';
import ReutrnEle from '@/components/ReturnEle';
import NiceForm from '@/components/NiceForm';
import { InspectionAddSchema } from './schema/add';
import UploadFiles from '@/components/UploadFiles/UploadFiles';
import { UploadProps, UploadChangeParam, UploadFile } from 'antd/lib/upload/interface'
import FormilyUploadFiles from '@/components/UploadFiles/FormilyUploadFiles'
const formActions = createFormActions()
const InspectionAdd = () => {
const [fileList, setFileList] = useState<any[]>([ {
uid: '1',
name: 'xxx.png',
status: 'done',
response: 'Server Error 500', // custom error message to show
url: 'http://www.baidu.com/xxx.png',
},]);
const onChange = (file: UploadChangeParam) => {
console.log(file);
setFileList([]);
// setFileList(list)
// const newList = [...fileList];
// newList.push(file);
}
return (
<PageHeaderWrapper
onBack={() => history.goBack()}
backIcon={<ReutrnEle description="返回" />}
title="生产通知单"
extra={
(
<Button
key={1}
type="primary"
icon={<SaveOutlined />}
// loading={submitLoading}
onClick={() => formActions.submit()}
>
保存
</Button>
)
}
>
<Card>
<NiceForm
initialValues={{
files: [
{
uid: '3',
name: 'zzz.png',
status: 'error',
response: 'Server Error 500', // custom error message to show
url: 'http://www.baidu.com/zzz.png',
},
]
}}
schema={InspectionAddSchema}
actions={formActions}
components={{FormilyUploadFiles}}
expressionScope={{
connectMember: (
<div>
<LinkOutlined style={{marginRight: 4}}/>
选择
</div>
)
}}
effects={() => {}}
/>
</Card>
{/* <UploadFiles fileList={fileList} onChange={onChange}>
<Button>上传附件</Button>
</UploadFiles> */}
</PageHeaderWrapper>
)
}
export default InspectionAdd;
import React, { useRef } from 'react';
import { Card, Space, Button } from 'antd';
import { ColumnsType } from 'antd/es/table';
import { StandardTable } from 'god';
import { PlusOutlined } from '@ant-design/icons';
import { createFormActions } from '@formily/antd';
import NiceForm from '@/components/NiceForm';
import { inspectionListSchema } from './schema';
import { PublicApi } from '@/services/api';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { FORM_FILTER_PATH } from '@/formSchema/const';
const formActions = createFormActions();
/**
* 会员咔嚓
*/
interface Iprops {};
interface InspectionData {
id: number,
/**
* 会员名称
*/
name: string;
/**
* 考察主题
*/
theme: string,
/**
* 考察类型
* 1 => 入库考察, 2 => 真该考察, 3 => 计划考察, 4 => 入库考察
*/
type: number,
/**
* 考察日期
*/
date: number,
/**
* 考察评分
*/
score: number,
/**
* 内部状态
*/
status: 0 | 1,
}
type PaginationParam = {
current: number,
pageSize: number,
}
const columns: ColumnsType<InspectionData> = [
{
title: '会员名称',
dataIndex: 'name',
},
{
title: '考察主题',
dataIndex: 'theme',
},
{
title: '考察类型',
dataIndex: 'type',
filters: [],
onFilter: (_value, record) => record.type === _value,
},
{
title: '考察日期',
dataIndex: 'date',
sorter: (_a, _b) => _a.date - _b.date,
},
{
title: '考察评分',
dataIndex: 'score',
sorter: (_a, _b) => _a.date - _b.date,
},
{
title: '内部状态',
dataIndex: 'status',
filters: [
{
text: '合格',
value: 1,
},
{
text: '不合格',
value: 0,
},
],
onFilter: (_value, record) => record.type === _value,
},
{
title: '操作',
dataIndex: 'actions',
render: (_text, _record) => {
return (
<Space>
<a>编辑</a>
<a>删除</a>
</Space>
)
}
}
]
const MemberInspection: React.FC<Iprops> = (props: Iprops) => {
const ref = useRef<any>({});
const controllerBtns = (
<div>
<Button type="primary">
<PlusOutlined /> 新建
</Button>
</div>
)
const fetchListData = async (params: PaginationParam & { theme?: string, type?: number }) => {
console.log(params);
return [];
}
return (
<Card>
<StandardTable
tableProps={{
rowKey: 'validateId',
}}
columns={columns}
currentRef={ref}
fetchTableData={(params: any) => fetchListData(params)}
controlRender={
<NiceForm
schema={inspectionListSchema}
actions={formActions}
onSubmit={values => ref.current?.reload(values)}
expressionScope={{
controllerBtns,
}}
effects={($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
'name',
FORM_FILTER_PATH,
);
// useAsyncInitSelect(
// ['memberTypeId', 'roleId', 'level', 'source', 'innerStatus', 'outerStatus'],
// fetchSelectOptions,
// );
}}
/>
}
/>
</Card>
)
}
export default MemberInspection
import { ISchema } from '@formily/antd';
export const InspectionAddSchema: ISchema = {
type: "object",
properties: {
tabs: {
type: "object",
"x-component": "tab",
// "x-component-props": {
// "defaultActiveKey": "tab-2"
// },
properties: {
"tab-1": {
type: "object",
"x-component": "tabpane",
"x-component-props": {
"tab": "基本信息"
},
properties: {
layout: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
labelCol: 4,
wrapperCol: 10,
labelAlign: 'left'
},
properties: {
theme: {
title: '考察主题',
type: 'string',
'x-rules': [
{
required: true,
message: '请填写通知单摘要'
},
{
limitByte: true, // 自定义校验规则
maxByte: 60
}
],
'x-component-props': {
placeholder: '最长60个字符,30个汉字'
}
},
memberName: {
title: '会员名称',
type: 'string',
"x-component-props": {
disabled: true,
addonAfter: "{{connectMember}}"
},
"x-rules": [
{
required: true,
message: '请选择会员名称'
}
],
},
type: {
type: 'string',
title: '考察类型',
enum: [
{
label: '整改考察',
value: 1
}
],
"x-rules": [
{
required: true,
message: '请选择考察类型'
}
],
},
date: {
type: 'date',
title: "考察日期",
"x-component-props": {
style: {
width: '100%'
}
},
"x-rules": [
{
required: true,
message: '请选择考察类型'
}
],
},
representative: {
title: '会员代表',
type: 'string',
"x-component-props": {
disabled: true,
addonAfter: "{{connectMember}}"
},
},
reason: {
title: '考察原因',
type: 'textarea',
},
files: {
title: '考察要求附件',
type: 'object',
'x-component': 'FormilyUploadFiles',
}
}
}
}
},
"tab-2": {
type: "object",
"x-component": "tabpane",
"x-component-props": {
"tab": "详细信息"
},
properties: {
layout: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
labelCol: 4,
wrapperCol: 10,
labelAlign: 'left'
},
properties: {
score: {
type: "string",
title: "考察评分",
"x-rules": [
{
required: true,
message: '请输入考察评分'
}
],
},
result: {
type: 'textarea',
title: '考察结果',
"x-rules": [
{
required: true,
message: '请输入考察结果'
}
],
},
resultFiles: {
title: '考察要求附件',
type: 'object',
'x-component': 'FormilyUploadFiles',
"x-rules": [
{
required: true,
message: '请上传文件'
}
],
}
}
},
}
},
}
}
}
}
import { ISchema } from '@formily/antd';
import { FORM_FILTER_PATH } from '@/formSchema/const';
/**
* 会员考察页scheam
* 总感觉这里的布局有点问题
*/
export const inspectionListSchema: ISchema = {
type: 'object',
properties: {
mageLayout: {
type: 'object',
'x-component': 'Mega-Layout',
properties: {
topLayout: {
type: 'object',
'x-component': 'Mega-Layout',
'x-component-props': {
grid: true,
},
properties: {
ctl: {
type: 'object',
'x-component': 'Children',
'x-component-props': {
children: '{{controllerBtns}}',
},
},
name: {
type: 'string',
'x-component': 'Search',
'x-component-props': {
placeholder: '搜索',
tip: '输入 会员名称 进行搜索',
},
},
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'Flex-Layout',
'x-component-props': {
colStyle: {
marginLeft: 20,
},
},
properties: {
memberTypeId: {
type: 'string',
default: undefined,
enum: [],
'x-component-props': {
placeholder: '会员类型(全部)',
allowClear: true,
style: {
width: 160,
},
},
},
roleId: {
type: 'string',
default: undefined,
enum: [],
'x-component-props': {
placeholder: '会员角色(全部)',
allowClear: true,
style: {
width: 160,
},
},
},
level: {
type: 'string',
default: undefined,
enum: [],
'x-component-props': {
placeholder: '会员等级(全部)',
allowClear: true,
style: {
width: 160,
},
},
},
submit: {
'x-component': 'Submit',
'x-mega-props': {
span: 1,
},
'x-component-props': {
children: '查询',
},
},
},
},
},
},
},
};
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