Commit 7069a4d5 authored by 前端-钟卫鹏's avatar 前端-钟卫鹏

Merge branch 'dev-srm' of http://10.0.0.22:3000/lingxi/lingxi-business-paltform into dev-srm

parents 7f21ba74 e0c7f11e
......@@ -67,7 +67,7 @@
"bizcharts": "^4.0.14",
"copy-to-clipboard": "^3.3.1",
"crypto-js": "^4.0.0",
"god": "^0.2.4",
"god": "0.2.5",
"immutability-helper": "^3.1.1",
"lingxi-design": "^1.0.14",
"lingxi-design-ui": "^1.1.21",
......
import React, {
useState,
ReactText,
useEffect,
useRef,
} from 'react';
import { Tree, Space, Tooltip, Input } from 'antd';
import {
findItemAndDelete,
findTreeKeys,
treeReduction,
getParentTreeTitles,
} from '@/utils';
import './index.less';
import deepClone from 'clone';
import { TreeProps } from 'antd/lib/tree';
import {
DeleteOutlined,
PlusCircleOutlined,
} from '@ant-design/icons';
import cx from 'classnames';
import { useSelections } from '@umijs/hooks';
export interface TabTreeActions {
selected: ReactText[];
getExpandedKeys: () => ReactText[];
getSelectKey: () => ReactText;
getSelectKeys: () => ReactText[];
setExpandedKeys: (keys: ReactText[]) => void;
setSelectKey: (key: ReactText) => void;
setSelectKeys: (keys: ReactText[]) => void;
getParentPath: (id: ReactText) => string;
getParent: (id) => any;
}
export interface toolsRenderProps {
addNode?(node);
addChildNode?(node);
deleteNode?(node);
}
export interface TabTreeProps extends TreeProps {
treeData: any[];
fetchData?(params?): Promise<any>;
actions?: TabTreeActions;
title?: React.ReactNode;
showSave?; // 是否显示保存按钮
// 若传入该字段, 则会作为tree识别的节点, 默认是`key`, 传入后原有的key值将无效
customKey?: string | number;
customTitle?: string | number;
handleSelect?: (key: ReactText, node: any) => void | Promise<any>;
handleSubmit?();
toolsRender?: toolsRenderProps;
getMenuSelectData?(): Promise<any>;
handleCheck?: (keys: any, nodes: any) => {};
customExpandkeys?: any[]; // props 传入自定义展开的key
enableSearch?: boolean; // 是否可搜索
searchPlaceholder?: string; // 搜索
resetSearch?: boolean;
}
export interface InnermostTreeNodeProps {}
export interface RenderIconsProps {
node: any;
nowKey: any;
toolsRender?: toolsRenderProps;
}
export const useTreeActions = (action?): TabTreeActions => {
const actionRef = useRef<any>(null);
actionRef.current = actionRef.current || action || createTreeActions();
return actionRef.current;
};
export const createTreeActions = () => {
const actions: TabTreeActions = {
selected: [],
getExpandedKeys() {
return [];
},
getSelectKey() {
return '';
},
getSelectKeys() {
return [];
},
setSelectKey() {},
setSelectKeys() {},
setExpandedKeys() {},
getParentPath(id) {
return '';
},
getParent(id) {
return null;
},
};
return actions;
};
const InnermostTreeNode: React.FC<InnermostTreeNodeProps> = props => {
return (
<span style={{ display: 'flex', alignItems: 'center' }}>
<span className="tree-node-circle"></span>
<span>{props.children}</span>
</span>
);
};
const RenderIcons: React.FC<RenderIconsProps> = props => {
const { toolsRender } = props;
// @todo 去掉点击active时, 保持icon显示
// return <Space className={cx('god-tabtree-icons', props.nowKey === props.node.key ? 'show' : 'hide')}>
return (
<Space className={cx('god-tabtree-icons')}>
<Tooltip title="新增节点">
<PlusCircleOutlined
onClick={e => {
e.stopPropagation();
toolsRender &&
toolsRender.addNode &&
toolsRender.addNode(props.node);
}}
/>
</Tooltip>
<Tooltip title="新增子节点">
<PlusCircleOutlined
onClick={e => {
e.stopPropagation();
toolsRender &&
toolsRender.addChildNode &&
toolsRender.addChildNode(props.node);
}}
/>
</Tooltip>
<Tooltip title="删除当前节点">
<DeleteOutlined
onClick={e => {
e.stopPropagation();
toolsRender &&
toolsRender.deleteNode &&
toolsRender.deleteNode(props.node);
}}
/>
</Tooltip>
</Space>
);
};
// 将无children的叶子节点中的title 转化为带有样式的title, 由于每次render 都需要重新deepClone深拷贝,可以优化
// 在多选模式下无需转化
function transformSingleTitle(
data,
nowKey,
checkable,
disabled,
toolsRender,
customKey?,
customTitle?,
) {
if (Array.isArray(data) && data.length > 0) {
for (let item = 0; item < data.length; item++) {
// 指定默认key
if (customKey) {
data[item]._key = data[item].key;
data[item].key = data[item][customKey];
}
if (data[item].children) {
transformSingleTitle(
data[item].children,
nowKey,
checkable,
disabled,
toolsRender,
customKey,
customTitle,
);
}
data[item]._title = data[item]._title || data[item].title;
data[item].title = (
<span
className="god-tabtree-title"
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
{checkable ||
(data[item].children && data[item].children.length !== 0) ? (
data[item].title
) : (
<InnermostTreeNode>{data[item].title}</InnermostTreeNode>
)}
<div>
{toolsRender && (
<RenderIcons
node={data[item]}
nowKey={nowKey}
toolsRender={toolsRender}
/>
)}
</div>
</span>
);
// 使选中样式受控
data[item].className = cx(
'god-tabtree-select',
String(nowKey) === String(data[item].key) ? 'show' : 'hide',
);
if (disabled) {
data[item].disableCheckbox = disabled;
}
if (customTitle) {
data[item]._title = data[item].title;
data[item].title = data[item][customTitle];
}
}
}
return data;
}
const TabTree: React.FC<TabTreeProps> = props => {
const {
treeData,
actions,
checkable,
customKey,
customTitle,
toolsRender,
disabled,
getMenuSelectData,
handleCheck,
customExpandkeys,
checkStrictly = false,
} = props;
const selfActions = useTreeActions(actions);
// 需展开的key
const [expandkeys, setExpandkeys] = useState<ReactText[]>([]);
// 当前选中的node
const [selectKey, setSelectKey] = useState<string | number>('');
// 自动展开父级
const [autoExpandParent, setAutoExpandParent] = useState<boolean>(false);
const data = transformSingleTitle(
deepClone(treeData),
selectKey,
checkable,
disabled,
toolsRender,
customKey,
customTitle,
);
// 重写选择方法, 只有在开启多选的时候才会启用
const checkedKeys = findTreeKeys(treeData, customKey);
const {
selected,
select,
setSelected,
} = useSelections(checkedKeys, []);
useEffect(() => {
if (getMenuSelectData) {
getMenuSelectData().then(res => {
const { ids } = res.data;
setSelected(ids);
});
}
}, []);
useEffect(() => {
if (customExpandkeys?.length) {
setExpandkeys(customExpandkeys);
setAutoExpandParent(true);
}
}, [customExpandkeys]);
if (selfActions) {
selfActions.getExpandedKeys = () => expandkeys;
selfActions.getSelectKey = () => selectKey;
selfActions.getSelectKeys = () => selected;
selfActions.selected = selected;
selfActions.setSelectKeys = (keys: ReactText[]) => {
setSelected(keys);
};
selfActions.setExpandedKeys = (keys: ReactText[]) => {
setExpandkeys(keys);
};
selfActions.setSelectKey = (key: ReactText) => {
setSelectKey(key);
};
selfActions.getParentPath = (id: ReactText) => {
return getParentTreeTitles(treeData, id);
};
selfActions.getParent = id => {
const reductData = treeReduction(treeData);
const targetInfo = reductData[id];
const parentInfo = reductData[targetInfo.parentId];
// fixbug 当选中根节点下的节点时, 由于无parentId, 需自动补充0
return parentInfo || { id: 0 };
};
}
const batchSelect = (items: any) => {
if (items.checked) {
// 更改为严格模式
items.checked.forEach(v => select(v));
} else {
items.forEach(v => select(v));
}
};
// 展开/收起的回调
const onExpand = expandedKeys => {
setAutoExpandParent(false);
setExpandkeys(expandedKeys);
};
return (
<Tree
className="god-tabtree"
treeData={data}
blockNode
checkable={checkable}
checkedKeys={selected}
expandedKeys={expandkeys}
autoExpandParent={autoExpandParent}
checkStrictly={checkStrictly}
onExpand={onExpand}
onCheck={(keys, nodes) => {
const { node, checked, checkedNodes } = nodes;
checked
? batchSelect(keys as any)
: setSelected(checkedNodes.map(v => v.key));
// 用户自定义的勾选后触发事件
if (handleCheck) {
handleCheck(keys, nodes);
}
}}
onSelect={(keys, e) => {
// 控制点击node时可以展开
const { node, selected } = e;
// 用户自定义的选择后触发事件
if (props.handleSelect) {
const result = props.handleSelect(node.key, node);
// 存在返回值则不执行选中事件, 一般用于切换node时,不希望离开当前页面
if (result) {
result
.then(() => {
// 若promise 是resolve状态, 说明确认离开了当前页面
setSelectKey(selectKey === node.key ? '' : node.key);
setExpandkeys(
expandkeys.includes(node.key)
? findItemAndDelete(expandkeys, node.key)
: [...expandkeys, node.key],
);
})
.catch(() => {});
return false;
}
}
// 如果重复点击 需要取消选中
setSelectKey(selectKey === node.key ? '' : node.key);
setExpandkeys(
expandkeys.includes(node.key)
? findItemAndDelete(expandkeys, node.key)
: [...expandkeys, node.key],
);
}}
/>
);
};
TabTree.defaultProps = {};
export default TabTree;
.field-header_container {
display: flex;
justify-content: space-between;
font-size: 14px;
margin-bottom: 18px;
}
.field-header_title {
display: flex;
align-items: center;
font-weight: 700;
&::before {
content: "";
width: 2px;
height: 14px;
background: #00B37A;
margin-right: 6px;
}
}
import React, { ReactNode } from 'react'
import mixinsClassName from 'classnames'
import './index.less'
export interface FieldHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
renderTitle: ReactNode,
extra?: ReactNode,
}
const FieldHeader:React.FC<FieldHeaderProps> = (props) => {
const { renderTitle, extra, className, ...restDivProps } = props
return (
<div className={mixinsClassName('field-header_container', className)} {...restDivProps}>
<div className='field-header_title'>{renderTitle}</div>
<div>{extra}</div>
</div>
)
}
FieldHeader.defaultProps = {}
export default FieldHeader
import React, { useState, useEffect } from 'react';
import { Input, Button, message } from 'antd';
import { LinkOutlined } from '@ant-design/icons';
import styled from 'styled-components';
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable';
import ModalTable from '@/components/ModalTable';
const RowStyleLayout = styled(props => <div {...props} />)`
width: 100%;
.relevance {
height: 100%;
background: #909399;
border-radius: 0;
&[disabled] {
background: #F4F5F7;
}
}
.ant-input-group-addon {
padding: 0;
border: none;
}
`;
const Relevance = props => {
const {
editable,
value = [],
} = props;
const {
modalProps = {
title: '标题',
width: 960,
},
selectionType = 'radio',
columns,
formilyProps,
tableProps = {},
fetchTableData,
title = '选择',
tip = '', // 点击按钮前的提示,用于前提需要提示的场景
disabled = false,
} = props.props['x-component-props'];
const tableRowKey = tableProps.rowKey || 'id';
const tableRowLableKey = tableProps.lableKey || ''; // Input展示用的 key val
const [visible, setVisible] = useState(false);
const [rowSelection, rowCtl] = useRowSelectionTable({ type: selectionType, customKey: tableRowKey });
useEffect(() => {
// Table 只能缓存 keys
const rowKeys = value.map(item => item[tableRowKey]);
rowCtl.setSelectedRowKeys(rowKeys);
rowCtl.setSelectRow(value);
}, [props.value, tableProps.rowKey]);
const handleConfirm = () => {
const rows = rowCtl.selectRow;
const keys = rows.map(item => item[tableRowKey]);
if (props.mutators) {
if (rows && rows.length) {
props.mutators.change(rows);
}
setVisible(false);
return;
}
rowCtl.setSelectedRowKeys(keys);
setVisible(false);
};
const handleModalVisible = () => {
if (!fetchTableData) {
message.warning(tip || '请传入 fetchTableData 属性,否则Table 将无法发起请求');
return;
}
setVisible(true);
};
return (
<RowStyleLayout>
<Input
value={
tableRowLableKey ?
value.map(item => item[tableRowLableKey]).join(',') :
''
}
addonAfter={(
<>
{editable && (
<Button
type="primary"
className="relevance"
icon={<LinkOutlined />}
onClick={handleModalVisible}
disabled={disabled}
block
>
{title}
</Button>
)}
</>
)}
disabled
/>
<ModalTable
confirm={handleConfirm}
cancel={() => setVisible(false)}
visible={visible}
width={960}
{...modalProps}
modalTitle={modalProps.title}
rowSelection={rowSelection}
columns={columns}
fetchTableData={fetchTableData}
formilyProps={formilyProps}
tableProps={tableProps}
resetModal={{
destroyOnClose: true,
}}
/>
</RowStyleLayout>
);
};
Relevance.defaultProps = {};
Relevance.isFieldComponent = true;
export default Relevance;
import React, { useState, useEffect } from 'react';
import { Input, Button, message } from 'antd';
import { LinkOutlined } from '@ant-design/icons';
import styled from 'styled-components';
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable';
import ModalTable from '@/components/ModalTable';
const RowStyleLayout = styled(props => <div {...props} />)`
width: 100%;
.relevance {
height: 100%;
background: #909399;
border-radius: 0;
border: none;
&[disabled] {
background: #F4F5F7;
}
}
.ant-input-group-addon {
padding: 0;
border: none;
}
`;
const Relevance = props => {
const {
editable,
value = [],
} = props;
const {
modalProps = {
title: '标题',
width: 960,
},
selectionType = 'radio',
columns,
formilyProps,
tableProps = {},
fetchTableData,
title = '选择',
tip = '', // 点击按钮前的提示,用于前提需要提示的场景
disabled = false,
} = props.props['x-component-props'];
const tableRowKey = tableProps.rowKey || 'id';
const tableRowLableKey = tableProps.lableKey || ''; // Input展示用的 key val
const [visible, setVisible] = useState(false);
const [rowSelection, rowCtl] = useRowSelectionTable({ type: selectionType, customKey: tableRowKey });
useEffect(() => {
// Table 只能缓存 keys
const rowKeys = value.map(item => item[tableRowKey]);
rowCtl.setSelectedRowKeys(rowKeys);
rowCtl.setSelectRow(value);
}, [props.value, tableProps.rowKey]);
const handleConfirm = () => {
const rows = rowCtl.selectRow;
const keys = rows.map(item => item[tableRowKey]);
if (props.mutators) {
if (rows && rows.length) {
props.mutators.change(rows);
}
setVisible(false);
return;
}
rowCtl.setSelectedRowKeys(keys);
setVisible(false);
};
const handleModalVisible = () => {
if (!fetchTableData) {
message.warning(tip || '请传入 fetchTableData 属性,否则Table 将无法发起请求');
return;
}
setVisible(true);
};
return (
<RowStyleLayout>
<Input
value={
tableRowLableKey ?
value.map(item => item[tableRowLableKey]).join(',') :
''
}
addonAfter={(
<>
{editable && (
<Button
type="primary"
className="relevance"
icon={<LinkOutlined />}
onClick={handleModalVisible}
disabled={disabled}
block
>
{title}
</Button>
)}
</>
)}
disabled
/>
<ModalTable
confirm={handleConfirm}
cancel={() => setVisible(false)}
visible={visible}
width={960}
{...modalProps}
modalTitle={modalProps.title}
rowSelection={rowSelection}
columns={columns}
fetchTableData={fetchTableData}
formilyProps={formilyProps}
tableProps={tableProps}
resetModal={{
destroyOnClose: true,
}}
/>
</RowStyleLayout>
);
};
Relevance.defaultProps = {};
Relevance.isFieldComponent = true;
export default Relevance;
......@@ -128,14 +128,7 @@ const NiceForm: React.FC<NiceFormProps> = props => {
useEffect(() => {
let paginationInfo: currentStateType = getCurrentState();
// 一般 列表检索传入的 controlRender 的 NiceForm 是没有 value 或者 initialValues 的
// value 或者 initialValues 的,表单页有
if (
match.path === paginationInfo.pathname
&& !('value' in reset)
&& !('initialValues' in reset)
) {
if(paginationInfo?.queryParams) {
reset.actions.setFormState(
state => (state.values = paginationInfo.queryParams),
);
......
......@@ -11,9 +11,27 @@ interface IProps {
const ReutrnEle: React.FC<IProps> = (props) => {
const { description, logoSrc } = props
const bubbles = (e: any) => {
let ev = e || window.event;
if(ev && ev.stopPropagation) {
ev.stopPropagation();
} else {
ev.cancelBubble = true;
}
}
return <>
<span style={{ fontSize: 12, color: '#909399FF' }}><ArrowLeftOutlined /> {logoSrc ? <img src={logoSrc} style={{ width: 48, height: 48, margin: '0 0 0 14px' }} /> : description}</span>
<span style={{ fontSize: 12, color: '#909399FF' }}>
<ArrowLeftOutlined />
{
logoSrc
?
<img src={logoSrc} style={{ width: 48, height: 48, margin: '0 0 0 14px', cursor: 'default' }} onClick={bubbles} />
:
description
}
</span>
</>
}
export default ReutrnEle
\ No newline at end of file
export default ReutrnEle
import { Modal } from "antd"
import { ReactNode, useCallback, useEffect, useState } from "react"
export interface leaveOptions {
title?: ReactNode,
onSave: any,
onModalOk(resolve: any),
onModalCancel(reject: any),
}
/**
* 对即将离开某个操作时, 发出提示弹窗
*/
export const useLeavePage = (options: leaveOptions): [React.Dispatch<React.SetStateAction<boolean>>, any] => {
const { title, onSave, onModalOk, onModalCancel } = options
const [saveStatus, setSaveStatus] = useState<boolean>(true)
const validateSaveStatus = useCallback(() => {
if (saveStatus) {
return Promise.resolve()
} else {
return new Promise((resolve, reject) => {
Modal.confirm({
content: title || '确认要离开当前页面吗,您提交的数据尚未保存',
onOk() {
onModalOk(resolve)
},
onCancel() {
onModalCancel(reject)
}
})
})
}
}, [saveStatus])
return [setSaveStatus, validateSaveStatus]
}
import { useMap } from '@umijs/hooks'
import React, { useState, useEffect } from 'react'
import { Modal } from 'antd'
import { TabTreeActions } from '@/components/TabTree'
import { ISchemaFormActions } from '@formily/antd'
import { isObject } from '@/utils'
export enum FormState {
FREE, // 空闲状态
EDIT, // 编辑状态
ADD, // 新增状态
}
export interface useTreeTabOptions {
selectCallback?(selectKey?, node?),
fetchMenuData?(),
fetchItemDetailData?(id),
// 重置右侧详情
resetDetail?(),
// 对树形工具栏做render扩展
extendsToolsRender?: any,
// 树形的实例操作方法
treeActions?: TabTreeActions
// 右侧表单的实例操作方法
formActions?: ISchemaFormActions
// 删除菜单时调用的API
deleteMenu?: any
}
export interface treeNodeResponse {
/**
* 该节点是否选中
*/
selected: boolean,
/**
* 节点信息
*/
node: any
}
export const useTreeData = (options: useTreeTabOptions = {}) => {
const { selectCallback, fetchMenuData, treeActions, formActions, extendsToolsRender, deleteMenu } = options
const [treeExtraMaps, { set, get }] = useMap<any, any>()
const [treeData, setTreeData] = useState<any[]>([])
const [treeStatus, setTreeStatus] = useState<FormState>(FormState.FREE)
const [nodeRecord, setNodeRecord] = useState<any>(null)
const [isEditForm, setIsEditForm] = useState<boolean>(false)
useEffect(() => {
resetMenu()
}, [])
const resetMenu = async () => {
if (fetchMenuData) {
const res = await fetchMenuData()
setTreeData(res.data || [])
}
}
const handleSelect = (selectKey?, node?) => {
return new Promise<treeNodeResponse>((resolve, reject) => {
if (selectCallback) {
// 完全自定义点击节点事件
selectCallback(selectKey, node)
return;
}
resolve({
selected: true,
node: node || null
})
})
}
const handleDeleteMenu = (id) => {
deleteMenu({
id: isObject(id) ? nodeRecord.key : id
}).then(() => {
setTreeStatus(FormState.FREE)
setNodeRecord(undefined)
resetMenu()
})
}
// 新增整合树形操作菜单
// 树形工具栏
const toolsRender = {
addNode(node) {
const activeParentId = treeActions && treeActions.getParent(node.key || node.id)?.id
setNodeRecord({
...node,
parentId: activeParentId, // 添加同级的时候 使用上一级的id作为parentId
})
formActions && formActions.reset({ validate: false })
setTreeStatus(FormState.ADD)
},
addChildNode(node) {
setNodeRecord({
...node,
parentId: node.key || node.id
})
formActions && formActions.reset({ validate: false })
set(node.key || node.id, null)
setTreeStatus(FormState.ADD)
},
deleteNode(node) {
const id = node.key || node.id
handleDeleteMenu(id)
},
...extendsToolsRender
}
return {
handleSelect,
treeStatus,
setTreeStatus,
treeData,
setTreeData,
nodeRecord,
setNodeRecord,
isEditForm,
setIsEditForm,
treeExtraMaps,
setTreeMaps: set,
getTreeMaps: get,
resetMenu,
toolsRender,
handleDeleteMenu
}
}
import React, { useContext, useState, useEffect, useRef, useLayoutEffect, useCallback } from 'react';
import { Row, Col, Button, Form, Input, Space, Tabs, message, Badge, Card } from 'antd';
import { IntegrateTree } from 'god'
import React, {
useContext,
useState,
useEffect,
useRef,
useLayoutEffect,
useCallback,
useMemo,
} from 'react';
import {
Row,
Col,
Button,
Form,
Input,
Space,
Tabs,
Checkbox,
Badge,
Card,
Tag,
} from 'antd';
import { IntegrateTree } from 'god';
import { history } from 'umi';
import { historyContainer } from '@/hooks/useHistoryContainer';
import NiceForm from '@/components/NiceForm';
import TabTree, { useTreeActions, createTreeActions } from '@/components/TabTree';
import TabTree, {
useTreeActions,
createTreeActions,
} from '@/components/TabTree';
import { PublicApi } from '@/services/api';
import styled from './index.less'
import styled from './index.less';
import CheckboxTree from '@/components/CheckBoxTree';
import { useTreeTabs } from '@/hooks/useTreeTabs';
import { useTreeData } from '@/hooks/useTreeData';
import { createFormActions } from '@formily/antd';
import { usePageStatus, PageStatus } from '@/hooks/usePageStatus';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import ReutrnEle from '@/components/ReturnEle';
import { useLeavePage } from '@/hooks/useLeavePage';
import { useMap } from '@umijs/hooks';
import FieldHeader from '@/components/FieldHeader';
import OrgModal from './orgModal';
import { PlusOutlined } from '@ant-design/icons';
import { useTreeTabs } from '@/hooks/useTreeTabs';
const pageTitles = [
'新增',
'编辑',
'预览'
]
const pageTitles = ['新增', '编辑', '预览'];
const TabFormErrors = (props) => {
const TabFormErrors = props => {
return (
<Badge dot={props.dot} offset={[5, -5]}>
{props.children}
</Badge>
)
}
);
};
const fetchMenuData = async () => {
const res = await PublicApi.getMemberRoleAuthTree()
return res
}
const res = await PublicApi.getMemberRoleAuthTree();
return { data: res.data.menus };
};
const TabsItem = Tabs.TabPane;
const menuActions = createFormActions();
const TabsItem = Tabs.TabPane
const treeActions = createTreeActions();
const menuActions = createFormActions()
const fetchOrgsTreeData = async () => {
const res = await PublicApi.getMemberOrgTree();
return res;
};
const treeActions = createTreeActions()
const getTreeNode = (treeData: any, targetNodeId: any) => {
if (!Array.isArray(treeData)) {
return null;
}
let result = {
id: '',
title: '',
}
for (let i = 0; i < treeData.length; i++) {
const item = treeData[i];
if (item.id === targetNodeId) {
return item
}
if (item.children) {
result = getTreeNode(item.children, targetNodeId);
}
}
return result;
};
const MemberDetail: React.FC<{}> = () => {
const [form] = Form.useForm();
const value = useContext(historyContainer)
const value = useContext(historyContainer);
const [nodeRecord, setNodeRecord] = useState<any>(null);
const [orgModalVisible, setOrgModalVisible] = useState(false);
const [treeExtraMaps, { set: setButtonAuth, get: getButtonAuth }] = useMap<
any,
any
>();
const {
treeData,
handleSelect,
nodeRecord,
isEditForm,
setIsEditForm,
getTreeMaps,
treeData: plateformTreeData,
handleSelect: handleSyncSelect,
} = useTreeTabs({
fetchMenuData: fetchOrgsTreeData,
});
const { treeData, handleSelect } = useTreeData({
fetchMenuData,
fetchItemDetailData: ({ id }) => PublicApi.getMemberRoleAuthButton({
menuId: id
})
})
const actionRef = useRef<any>({})
const formInitValue = nodeRecord ? getTreeMaps(nodeRecord.key) : {}
const [errors, setErrors] = useState<boolean>(false)
const [formValue, setFormValue] = useState<any>(null)
const {
pageStatus,
id
} = usePageStatus()
fetchItemDetailData: ({ id }) =>
PublicApi.getMemberRoleAuthButton({
menuId: id,
}),
});
const actionRef = useRef<any>({});
const formInitValue = nodeRecord ? getButtonAuth(nodeRecord.key) : {};
const [errors, setErrors] = useState<boolean>(false);
const [formValue, setFormValue] = useState<any>(null);
// 储存的按钮数据
const [buttonInfos, setButtonInfos] = useState<any>([]);
// 储存的数据权限选项
const [authInfos, setAuthInfos] = useState<any>({});
const modalRef = useRef<any>({})
const disabledCheckAuthConfig = useMemo(() => {
if (nodeRecord && authInfos[nodeRecord.id]) {
return authInfos[nodeRecord.id] as {
hasDataAuth: number;
dataAuthConfig: number;
orgIds: any[];
};
} else {
return { hasDataAuth: 0, dataAuthConfig: 0, orgIds: [] };
}
}, [authInfos, nodeRecord]);
const { pageStatus, id } = usePageStatus();
const fetchItemDetailData = useCallback(
async node => {
const isAdd = pageStatus === PageStatus.ADD;
const fn = isAdd
? PublicApi.getMemberRoleAuthButton
: PublicApi.getMemberRoleAuthButtonCheck;
const params = isAdd ? {} : { memberRoleId: id };
const { data } = await fn({
menuId: node ? node.id : nodeRecord.id,
...params,
});
setButtonAuth(node.id, data);
// 该配置由pass平台控制, 如果为1 则表示该角色可以配置数据权限
if (authInfos[node.id]) {
// 已经存在了配置权限, 则不做更新, 防止修改后被重置
} else {
setAuthInfos({
...authInfos,
[node.id]: {
hasDataAuth: isAdd ? 0 : data.hasDataAuth,
dataAuthConfig: data.dataAuthConfig,
orgIds: isAdd ? [] : data.orgIds,
},
});
}
},
[nodeRecord, authInfos],
);
const [setEditForm, validateEditForm] = useLeavePage({
onSave: () => {},
onModalOk: () => {},
onModalCancel: () => {},
});
const handleNodeSelected = async (selectKey, selectNode) => {
try {
const { node } = await handleSelect(selectKey, selectNode);
if (nodeRecord) {
return new Promise((resolve, reject) => {
if (selectKey !== nodeRecord.key) {
validateEditForm()
.then(() => {
setNodeRecord(node);
fetchItemDetailData(node);
resolve(true);
})
.catch(() => {
reject();
});
} else {
resolve(null);
}
});
} else {
setNodeRecord(node);
fetchItemDetailData(node);
}
} catch (error) {}
};
// 编辑和预览模式下需回显数据
const fetchRoleMenuDetail = async (id) => {
const fetchRoleMenuDetail = async id => {
// 10秒缓存
const res = await PublicApi.getMemberRoleGet({
memberRoleId: id
}, { useCache: true, ttl: 10 * 1000 })
return res
}
// 储存的按钮数据
const [buttonInfos, setButtonInfos] = useState<any>([])
const res = await PublicApi.getMemberRoleGet(
{
memberRoleId: id,
},
{ useCache: true, ttl: 10 * 1000 },
);
return res;
};
useEffect(() => {
if (!id) return;
fetchRoleMenuDetail(id).then(res => {
const { data } = res
setFormValue({...data, imFlag: data['imFlag'] ? true : false})
})
}, [])
const { data } = res;
setFormValue(data);
});
}, []);
useEffect(() => {
if (formInitValue) {
// 显示右侧checkbox
setButtonInfos(formInitValue.buttons || [])
setButtonInfos(formInitValue.buttons || []);
// 回显右侧checkbox的值
if (actionRef.current.setSelected) {
actionRef.current.setSelected()
actionRef.current.setSelected();
}
}
}, [getTreeMaps])
}, [getButtonAuth, nodeRecord]);
const handleSubmit = () => {
menuActions.submit().then(async ({ values }) => {
values['imFlag'] = values['imFlag'] ? 1 : 0
setErrors(false)
// 如果未点击过操作权限tab, 则无法获取到actionRef实例, 需补充手动补充回显的ids, 新增的时候如果未设置按钮,则返回空数组
const buttonCheckIds = actionRef.current.selected || (formValue && formValue.ids) || []
const treeCheckIds = treeActions.getSelectKeys()
const menuIds = [...buttonCheckIds, ...treeCheckIds]
if (pageStatus === PageStatus.EDIT) {
await PublicApi.postMemberRoleUpdate({
...values,
memberRoleId: id,
menuIds
})
} else {
await PublicApi.postMemberRoleAdd({
menuActions
.submit()
.then(async ({ values }) => {
setErrors(false);
// 如果未点击过操作权限tab, 则无法获取到actionRef实例, 需补充手动补充回显的ids, 新增的时候如果未设置按钮,则返回空数组
const buttonCheckIds =
actionRef.current.selected || (formValue && formValue.ids) || [];
const treeCheckIds = treeActions.getSelectKeys();
const publicParams = {
...values,
menuIds
})
}
history.goBack(-1)
}).catch(err => {
console.log(err)
if (Array.isArray(err)) {
setErrors(true)
}
})
}
hasImAuth: values.hasImAuth ? 1 : 0,
auth: treeCheckIds.map(v => ({
menuId: v,
// @todo 暂时写死为空
buttonIds: [],
hasDataAuth: authInfos[v]?.hasDataAuth,
orgIds: authInfos[v]?.orgIds
})),
};
if (pageStatus === PageStatus.EDIT) {
await PublicApi.postMemberRoleUpdate({
memberRoleId: id,
...publicParams,
});
} else {
await PublicApi.postMemberRoleAdd({
...publicParams,
});
}
history.goBack(-1);
})
.catch(err => {
console.log(err);
if (Array.isArray(err)) {
setErrors(true);
}
});
};
const changeTabs = (key) => {
const changeTabs = key => {
if (key === '2' && id) {
fetchRoleMenuDetail(id).then(res => {
const { data } = res
const { data } = res;
// 获取菜单id选中的集合
const {
checkIds,
...reset
} = data
treeActions.setSelectKeys(checkIds)
})
const { checkIds, ...reset } = data;
treeActions.setSelectKeys(checkIds);
});
}
}
};
const onDataAuthChange = e => {
setAuthInfos({
...authInfos,
[nodeRecord.id]: Object.assign(
{ ...authInfos[nodeRecord.id] },
{ hasDataAuth: e.target.checked ? 1 : 0 },
),
});
};
const extraButtons = (
<Space>
<Button type='primary' disabled={pageStatus === PageStatus.PREVIEW} onClick={handleSubmit}>保存</Button>
<Button
type="primary"
disabled={pageStatus === PageStatus.PREVIEW}
onClick={handleSubmit}
>
保存
</Button>
</Space>
)
);
const handleOrgSuccess = selectKeys => {
setAuthInfos({
...authInfos,
[nodeRecord.id]: Object.assign(
{ ...authInfos[nodeRecord.id] },
{ orgIds: selectKeys },
),
});
setOrgModalVisible(false);
};
const handleOrgCancel = () => {
setOrgModalVisible(false);
};
const handleOpenOrg = () => {
setOrgModalVisible(true);
};
return (
<PageHeaderWrapper
onBack={() => history.goBack()}
backIcon={<ReutrnEle description="返回" />}
className='addRepository'
className="addRepository"
title={pageTitles[pageStatus]}
extra={[
extraButtons
]}
extra={extraButtons}
>
<Card>
<Tabs type='card' className='black-tabs' onChange={changeTabs}>
<TabsItem tab={<TabFormErrors dot={errors}>基本信息</TabFormErrors>} key='1'>
<Tabs type="card" className="black-tabs" onChange={changeTabs}>
<TabsItem
tab={<TabFormErrors dot={errors}>基本信息</TabFormErrors>}
key="1"
>
<NiceForm
labelCol={4}
wrapperCol={12}
initialValues={formValue}
labelAlign='left'
labelAlign="left"
actions={menuActions}
editable={pageStatus !== PageStatus.PREVIEW}
previewPlaceholder=' '
previewPlaceholder=" "
schema={{
type: 'object',
properties: {
roleName: {
type: 'string',
title: '角色名称',
required: true
required: true,
},
remark: {
type: 'textarea',
title: '备注',
"x-rules": [
'x-rules': [
{
limitByte: true,
maxByte: 120
}
maxByte: 120,
},
],
"x-component-props": {
rows: 4
}
'x-component-props': {
rows: 4,
},
},
hasImAuth: {
type: 'number',
title: '是否具有IM通讯权限',
'x-component': 'CheckboxSingle',
},
state: {
type: 'number',
title: '状态',
"x-component": 'CustomStatus',
default: 1
},
imFlag: {
type: 'boolean',
title: '客服权限',
required: true,
"x-component": 'CheckboxSingle',
"x-component-props": {
children: '客服IM即时通讯权限',
style: {
marginTop: 4,
}
},
default: 0
'x-component': 'CustomStatus',
default: 1,
},
}
},
}}
>
</NiceForm>
></NiceForm>
</TabsItem>
<TabsItem tab='操作权限' key='2'>
<Row justify='space-between'>
<Col span={17} className={styled['menu-role-tree']}>
<TabsItem tab="操作权限" key="2">
<Row justify="space-between">
<Col span={8} className={styled['menu-role-tree']}>
<TabTree
title='菜单访问权限'
title="菜单访问权限"
fetchData={params => fetchMenuData()}
checkable
actions={treeActions}
treeData={treeData}
handleSelect={handleSelect}
handleSelect={handleNodeSelected}
checkStrictly={true}
customKey='id'
customKey="id"
disabled={pageStatus === PageStatus.PREVIEW}
/>
</Col>
<Col span={6} className={styled['menu-role-tree']}>
<Col span={7} className={styled['menu-role-tree']}>
<CheckboxTree
actions={actionRef}
disabled={pageStatus === PageStatus.PREVIEW}
checkedNodes={buttonInfos}
title='菜单接口访问权限'
title="菜单接口访问权限"
/>
</Col>
<Col span={7} className={styled['menu-role-tree']}>
<FieldHeader renderTitle="数据权限" />
{nodeRecord && (
<>
<Checkbox
checked={!!disabledCheckAuthConfig.hasDataAuth}
onChange={e => onDataAuthChange(e)}
disabled={
pageStatus === PageStatus.PREVIEW ||
!disabledCheckAuthConfig.dataAuthConfig
}
>
是否需要数据权限
</Checkbox>
<div style={{marginTop: 16}}>
<p style={{color: '#909399'}}>组织机构授权</p>
{disabledCheckAuthConfig.orgIds.map(v => {
const node = getTreeNode(plateformTreeData, v);
if (!node || !node.id) return null;
return (
<div className="org-tag-container" key={node.id}>
<Tag color={'#F4F5F7'} className="org-tag">
{node.title}
</Tag>
</div>
);
})}
<Button block type="dashed" onClick={handleOpenOrg}>
<PlusOutlined /> 关联
</Button>
</div>
</>
)}
</Col>
</Row>
</TabsItem>
</Tabs>
<OrgModal
handleSyncSelect={handleSyncSelect}
plateformTreeData={plateformTreeData}
fetchOrgsTreeData={fetchOrgsTreeData}
selectKeys={disabledCheckAuthConfig.orgIds}
visible={orgModalVisible}
onSuccess={handleOrgSuccess}
onCancel={handleOrgCancel}
modalRef={modalRef}
/>
</Card>
</PageHeaderWrapper>
)
}
);
};
export default MemberDetail
export default MemberDetail;
.org-tag-container {
margin-bottom: 8px;
.ant-tag-has-color, .ant-tag-has-color a, .ant-tag-has-color a:hover, .ant-tag-has-color .anticon-close, .ant-tag-has-color .anticon-close:hover {
color: #606266;
}
}
.org-tag {
color: #606266;
}
import TabTree, { createTreeActions } from '@/components/TabTree'
import { useTreeTabs } from '@/hooks/useTreeTabs'
import { PublicApi } from '@/services/api'
import { Button, Drawer, Row } from 'antd'
import React, { useEffect, useState } from 'react'
import './orgModal.less'
export interface OrgModalProps {
visible: boolean,
handleSyncSelect: any,
plateformTreeData: any,
fetchOrgsTreeData: any,
selectKeys: any[],
onSuccess(selectKeys: any[]),
onCancel(),
modalRef: any,
}
const syncTreeActions = createTreeActions()
const OrgModal:React.FC<OrgModalProps> = (props) => {
const { visible, onSuccess, onCancel, plateformTreeData, handleSyncSelect, fetchOrgsTreeData, selectKeys } = props
const [resetSearch, setResetSearch] = useState(false)
const [customPlateformExpandkeys, setCustomPlateformExpandkeys] = useState<any>()
const handleSuccess = () => {
onSuccess(syncTreeActions.getSelectKeys())
}
useEffect(() => {
syncTreeActions.setSelectKeys(selectKeys)
}, [selectKeys, syncTreeActions])
return (
<Drawer
visible={visible}
closable={false}
placement='right'
width={600}
forceRender
>
<TabTree
fetchData = {params => fetchOrgsTreeData()}
treeData={plateformTreeData}
handleSelect={handleSyncSelect}
actions={syncTreeActions}
customKey="id"
enableSearch
searchPlaceholder="组织机构名称"
checkStrictly
resetSearch={resetSearch}
customExpandkeys={customPlateformExpandkeys}
checkable={true}
/>
<Row justify='end'>
<Button onClick={onCancel} style={{marginRight: 8}}>关闭</Button>
<Button onClick={handleSuccess} type='primary'>确认</Button>
</Row>
</Drawer>
)
}
OrgModal.defaultProps = {}
export default OrgModal
......@@ -77,10 +77,12 @@ const AddUser: React.FC<{}> = () => {
...omitValue,
userId: Number(id)
} : omitValue
await run(params)
setTimeout(() => {
history.goBack(-1)
}, 300)
const result = await run(params)
if (result.code === 1000) {
setTimeout(() => {
history.goBack(-1)
}, 300)
}
};
// 角色确认弹窗
......
import React, {
useContext,
useState,
useEffect,
useRef,
useCallback,
useMemo,
} from 'react';
import {
Row,
Col,
Button,
Form,
Input,
Space,
Tabs,
Checkbox,
Badge,
Card,
Tag,
Popconfirm,
message,
} from 'antd';
import { history } from 'umi';
import { historyContainer } from '@/hooks/useHistoryContainer';
import NiceForm from '@/components/NiceForm';
import Search from '@/components/NiceForm/components/Search';
import Submit from '@/components/NiceForm/components/Submit';
import TabTree, {
useTreeActions,
createTreeActions,
} from '@/components/TabTree';
import { PublicApi } from '@/services/api';
import styled from './index.less';
import CheckboxTree from '@/components/CheckBoxTree';
import { useTreeData } from '@/hooks/useTreeData';
import { createFormActions } from '@formily/antd';
import { usePageStatus, PageStatus } from '@/hooks/usePageStatus';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import ReutrnEle from '@/components/ReturnEle';
import { useLeavePage } from '@/hooks/useLeavePage';
import { useMap } from '@umijs/hooks';
import FieldHeader from '@/components/FieldHeader';
import { PlusOutlined } from '@ant-design/icons';
import { useTreeTabs } from '@/hooks/useTreeTabs';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { StandardTable } from 'god';
import ModalTable from '@/components/ModalTable';
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable';
const pageTitles = ['新增业务员', '编辑业务员', '预览'];
const TabFormErrors = props => {
return (
<Badge dot={props.dot} offset={[5, -5]}>
{props.children}
</Badge>
);
};
const fetchMenuData = async () => {
const res = await PublicApi.getMemberRoleAuthTree();
return { data: res.data.menus };
};
const TabsItem = Tabs.TabPane;
const formAction = createFormActions();
const fetchMemberAbilitySelect = async (params) => {
const { data } = await PublicApi.getMemberAbilitySalesSelect(params)
return data
}
const MemberDetail: React.FC<{}> = () => {
const ref = useRef<any>({})
const [rowSelection, rowCtl] = useRowSelectionTable({customKey: 'memberId'})
const [realRowSelection, realRowCtl] = useRowSelectionTable({customKey: 'relationId'})
const [memberVisible, setMemberVisible] = useState(false)
const { pageStatus, id} = usePageStatus()
const [tableData, setTableData] = useState<any[]>([])
const fetchMemberSaleChannel = async (params) => {
const userInfo = formAction.getFieldValue('userId')
if (userInfo && userInfo.length > 0) {
const userId = userInfo[0].userId
const { data, code } = await PublicApi.getMemberAbilitySalesChannel({
userId,
...params
})
if (code === 1000) {
setTableData(data.data)
}
return code === 1000 ? data : []
} else {
return []
}
}
useEffect(() => {
PublicApi.getMemberAbilitySalesGet({
userId: id
}).then((res) => {
if (res.code === 1000) {
formAction.setFieldValue('userId', [res.data])
}
})
}, [id])
useEffect(() => {
if (tableData.length > 0) {
rowCtl.setSelectedRowKeys(tableData.map(v => v.memberId))
}
}, [tableData])
const cacelConnect = (record) => {
unBindMember(record.memberId)
}
const abilityColumns: any[] = [
{
key: 'userId',
dataIndex: 'userId',
title: '用户ID',
align: 'center'
},
{
key: 'name',
dataIndex: 'name',
title: '姓名',
align: 'center'
},
{
key: 'phone',
dataIndex: 'phone',
title: '手机号',
align: 'center'
},
{
key: 'orgName',
dataIndex: 'orgName',
title: '所属机构',
align: 'center'
},
{
key: 'jobTitle',
dataIndex: 'jobTitle',
title: '职位',
align: 'center'
}
]
const connectMemberColumns: any[] = [
{
key: 'memberId',
dataIndex: 'memberId',
title: '会员ID',
align: 'center'
},
{
key: 'name',
dataIndex: 'name',
title: '会员名称',
align: 'center'
},
{
key: 'memberTypeName',
dataIndex: 'memberTypeName',
title: '会员类型',
align: 'center'
},
{
key: 'roleName',
dataIndex: 'roleName',
title: '会员角色',
align: 'center'
},
{
key: 'createTime',
dataIndex: 'createTime',
title: '申请时间',
align: 'center'
},
{
key: 'levelTag',
dataIndex: 'levelTag',
title: '会员等级',
align: 'center'
},
{
key: 'statusName',
dataIndex: 'statusName',
title: '会员状态',
align: 'center'
},
{
key: 'ctl',
dataIndex: 'ctl',
title: '操作',
align: 'center',
render: (_, record) => {
return <Popconfirm title='确定要解除吗' onConfirm={() => cacelConnect(record)}>
<Button type='link'>解除绑定关系</Button>
</Popconfirm>
}
}
]
const modalMemberColumns: any[] = [
{
title: '会员ID',
dataIndex: 'memberId',
key: 'memberId',
align: 'center'
},
{
title: '会员名称',
dataIndex: 'name',
key: 'name',
align: 'center'
},
{
title: '会员类型',
dataIndex: 'memberTypeName',
key: 'memberTypeName',
align: 'center'
},
{
title: '会员角色',
dataIndex: 'roleName',
key: 'roleName',
align: 'center'
},
{
title: '会员等级',
dataIndex: 'levelTag',
key: 'levelTag',
align: 'center'
},
]
const fetchTableData = async (params) => {
const { data } = await PublicApi.getMemberAbilitySalesChannelPage(params)
return data
}
const handleConfirm = () => {
setMemberVisible(false)
setTableData(tableData => {
return [...tableData, ...rowCtl.selectRow.filter(v => !tableData.find(j => j.memberId === v.memberId))]
})
}
const validateMember = () => {
const userInfo = formAction.getFieldValue('userId')
return userInfo && userInfo.length > 0
}
const unBindMember = async (id?) => {
if (validateMember()) {
const userInfo = formAction.getFieldValue('userId')
const userId = userInfo[0].userId
const { code } = await PublicApi.postMemberAbilitySalesChannelUnbind({
userId,
relationIds: id ? [id] : realRowCtl.selectedRowKeys
})
if (code === 1000) {
setTableData(d => {
return d.filter(v => !realRowCtl.selectedRowKeys.includes(v.memberId))
})
message.success('解绑成功')
}
} else {
message.error('请先选择业务员')
}
}
const handleSubmit = async () => {
const userInfo = formAction.getFieldValue('userId')
if (userInfo && userInfo.length > 0) {
const userId = userInfo[0].userId
const result = await PublicApi.postMemberAbilitySalesChannelBind({
userId,
relationIds: tableData.map(v => v.relationId)
})
if (result.code === 1000) {
history.goBack(-1)
}
}
};
const changeTabs = key => {
if (key === '2') {
const userInfo = formAction.getFieldValue('userId')
if (userInfo && userInfo.length > 0) {
ref.current.reload && ref.current.reload()
}
}
};
const extraButtons = (
<Space>
<Button
type="primary"
disabled={pageStatus === PageStatus.PREVIEW}
onClick={handleSubmit}
>
保存
</Button>
</Space>
);
return (
<PageHeaderWrapper
onBack={() => history.goBack()}
backIcon={<ReutrnEle description="返回" />}
className="addRepository"
title={pageTitles[pageStatus]}
extra={extraButtons}
>
<Card>
<Tabs type="card" className="black-tabs" onChange={changeTabs}>
<TabsItem
tab={<TabFormErrors>基本信息</TabFormErrors>}
key="1"
>
<NiceForm
labelCol={4}
wrapperCol={12}
labelAlign="left"
actions={formAction}
editable={pageStatus !== PageStatus.PREVIEW}
previewPlaceholder=" "
schema={{
type: 'object',
properties: {
userId: {
type: 'string',
title: '业务员',
'x-component': 'CustomRelevance',
'x-component-props': {
title: '选择',
modalProps: {
title: '选择业务员',
},
columns: abilityColumns,
fetchTableData: fetchMemberAbilitySelect,
formilyProps: {
ctx: {
schema: {
type: 'object',
properties: {
name: {
type: 'string',
"x-component": 'SearchFilter',
'x-component-props': {
placeholder: '请输入姓名',
align: 'flex-start',
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'flex-layout',
'x-component-props': {
inline: true,
rowStyle: {
justifyContent: 'flex-start'
},
colStyle: {
marginRight: 20
}
},
properties: {
orgName: {
type: 'string',
'x-component-props': {
placeholder: '请输入所属机构',
}
},
"jobTitle": {
type: 'string',
"x-component-props": {
placeholder: '请输入职位'
}
},
submit: {
'x-component': 'Submit',
'x-component-props': {
children: '查询',
},
},
},
},
}
},
components: {
Search,
Submit
},
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
'name',
FORM_FILTER_PATH,
);
},
inline: false,
},
},
tableProps: {
rowKey: 'userId',
lableKey: 'name',
},
},
'x-mega-props': {
wrapperCol: 12,
},
'x-rules': [
{
required: true,
message: '请选择业务员',
},
],
},
},
}}
></NiceForm>
</TabsItem>
<TabsItem tab="管理下级渠道" key="2">
<Row justify='space-between' style={{marginBottom: 20}}>
<Col>
<Button type='default' onClick={() => unBindMember()}>批量解除绑定关系</Button>
</Col>
<Col style={{display: 'flex'}}>
<Input.Search/>
<Button type='default' style={{marginLeft: 20}}>重置</Button>
</Col>
</Row>
<Button block type='dashed' onClick={() => setMemberVisible(true)}>选择待绑定渠道会员</Button>
<StandardTable
columns={connectMemberColumns}
rowSelection={realRowSelection}
rowKey='relationId'
tableProps={{
dataSource: tableData
}}
/>
</TabsItem>
</Tabs>
</Card>
<ModalTable
confirm={handleConfirm}
cancel={() => setMemberVisible(false)}
visible={memberVisible}
width={960}
modalTitle='选择渠道会员'
rowSelection={rowSelection}
columns={modalMemberColumns}
fetchTableData={fetchTableData}
rowKey={'memberId'}
formilyProps={{
ctx: {
schema: {
type: 'object',
properties: {
name: {
type: 'string',
"x-component": "Search",
"x-component-props": {
placeholder: '输入姓名'
}
}
}
}
}
}}
/>
</PageHeaderWrapper>
);
};
export default MemberDetail;
import React, { ReactNode, useRef } from 'react';
import { history } from 'umi'
import { Button, Popconfirm, Card } from 'antd';
import {
PlusOutlined,
} from '@ant-design/icons';
import {StandardTable} from 'god'
import {ColumnType} from 'antd/lib/table/interface'
import { PublicApi } from '@/services/api';
import StatusSwitch from '@/components/StatusSwitch';
import EyePreview from '@/components/EyePreview';
import { STATUS_ENUM } from '@/constants';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
const fetchData = async (params) => {
const { data } = await PublicApi.getMemberAbilitySalesPage(params)
return data
}
const ChannelMember: React.FC<{}> = () => {
const ref = useRef<any>({})
const deleteItem = async (record) => {
// 删除该项
await PublicApi.postMemberAbilitySalesDelete({
userId: record.userId
})
ref.current.reload()
}
const updateItem = (record) => {
history.push(`/memberCenter/channelAbility/memberList/add?id=${record.userId}&preview=0`)
}
const columns: ColumnType<any>[] = [
{
title: '登录账号',
dataIndex: 'userId',
align: 'center',
key: 'userId',
},
{
title: '姓名',
dataIndex: 'name',
align: 'center',
key: 'name',
className: 'commonPickColor',
render: (text, record) => <EyePreview url={`/memberCenter/channelAbility/memberList/detail?id=${record.userId}&preview=1`}>{text}</EyePreview>
},
{
title: '所属机构',
align: 'center',
dataIndex: 'orgName',
key: 'orgName',
},
{
title: '绑定手机号',
align: 'center',
dataIndex: 'phone',
key: 'phone',
},
{
title: '职位',
align: 'center',
dataIndex: 'jobTitle',
key: 'jobTitle',
},
{
title: '所属角色',
align: 'center',
dataIndex: 'memberRoleName',
key: 'memberRoleName',
},
{
title: '操作',
dataIndex: 'option',
align: 'center',
render: (text:any, record:any) => {
return <>
<Button type='link' onClick={()=>updateItem(record)}>修改</Button>
{
record.status === 0 ?
<Popconfirm
title="确定要执行这个操作?"
onConfirm={() => deleteItem(record)}
okText="是"
cancelText="否"
>
<Button type='link'>删除</Button>
</Popconfirm>
: null
}
</>
}
}
];
return (
<PageHeaderWrapper>
<Card className="common-wrapper">
<StandardTable
columns={columns}
currentRef={ref}
fetchTableData={(params:any) => fetchData(params)}
formilyLayouts={{
justify: 'space-between'
}}
formilyChilds={{
layouts: {
order: 2
},
children: <Button style={{width: 140}} icon={<PlusOutlined/>} onClick={() => history.push('/memberCenter/channelAbility/memberList/add')} type='primary'>新建</Button>
}}
formilyProps={{
layouts: {
order: 3
},
ctx: {
effects: ($) => {
$('onFieldInputChange', 'status').subscribe(() => {
ref.current.reload()
})
},
schema: {
type: 'object',
properties: {
account: {
type: 'Search',
"x-component-props": {
placeholder: '请输入角色名称'
}
},
name: {
type: 'Search',
"x-component-props": {
placeholder: '请输入角色名称'
}
}
}
}
}
}}
/>
</Card>
</PageHeaderWrapper>
)
}
export default ChannelMember
......@@ -232,6 +232,13 @@ const ModalTableOrder: React.FC<ModalTableProps> = (props) => {
}
})
break;
case 5:
PublicApi.getEnhanceProcessToBeDeliveryList({ ...parmas }).then((res: any) => {
if (res.code === 1000) {
resolve(res.data)
}
})
break;
}
})
}
......@@ -256,45 +263,46 @@ const ModalTableOrder: React.FC<ModalTableProps> = (props) => {
{...nestTableProps}
/>
) : (
<StandardTable
tableType='small'
currentRef={selfRef}
fetchTableData={(params) => fetchData(params)}
formRender={(child, ps) => <Row justify='space-between' style={{ marginBottom: 16 }}>
<Col span={18} style={{ zIndex: 99 }}>
<Form form={form}>
<Form.Item name='radio' label='单据选择'>
<Radio.Group onChange={(e) => { setType(e.target.value); selfRef.current.reload(); }}>
<Radio value={1}>订单</Radio>
<Radio value={2}>换货申请单(退货发货)</Radio>
<Radio value={3}>换货申请单(换货发货)</Radio>
<Radio value={4}>退货申请单</Radio>
</Radio.Group>
</Form.Item>
</Form>
</Col>
<Col style={{ marginTop: 4 }}>{ps}</Col>
<Col span={18} style={{ zIndex: 99 }}>{child}</Col>
</Row >}
formilyProps={
{
ctx: {
schema: type === 1 ? logisticsDeliverySearchSchema : otherSearchSchema,
components: { ModalSearch: Search, SearchSelect, Submit, DateSelect },
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
type === 1 ? 'orderNo' : 'applyNo',
FORM_FILTER_PATH,
);
}
<StandardTable
tableType='small'
currentRef={selfRef}
fetchTableData={(params) => fetchData(params)}
formRender={(child, ps) => <Row justify='space-between' style={{ marginBottom: 16 }}>
<Col span={18} style={{ zIndex: 99 }}>
<Form form={form}>
<Form.Item name='radio' label='单据选择'>
<Radio.Group onChange={(e) => { setType(e.target.value); selfRef.current.reload(); }}>
<Radio value={1}>订单</Radio>
<Radio value={2}>换货申请单(退货发货)</Radio>
<Radio value={3}>换货申请单(换货发货)</Radio>
<Radio value={4}>退货申请单</Radio>
<Radio value={5}>生产通知单</Radio>
</Radio.Group>
</Form.Item>
</Form>
</Col>
<Col style={{ marginTop: 4 }}>{ps}</Col>
<Col span={18} style={{ zIndex: 99 }}>{child}</Col>
</Row >}
formilyProps={
{
ctx: {
schema: type === 1 ? logisticsDeliverySearchSchema : otherSearchSchema,
components: { ModalSearch: Search, SearchSelect, Submit, DateSelect },
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
type === 1 ? 'orderNo' : 'applyNo',
FORM_FILTER_PATH,
);
}
}
}
{...resetTable}
/>
)
}
{...resetTable}
/>
)
}
</Modal>
......
......@@ -116,7 +116,7 @@ const AddLogistics: React.FC<{}> = () => {
width: 120,
dataIndex: 'amount',
render: (text: any, record: any, index: number) =>
<Form.Item noStyle name={`amount${index}`} initialValue={record.amount} rules={[{ required: true, message: '请输入数量' }]}>
<Form.Item style={{ marginBottom: 0 }} name={`amount${index}`} initialValue={record.amount} rules={[{ required: true, message: '请输入数量' }]}>
<Input type='number' min={1} onBlur={(e) => inputOnchange(record.productId, e, 'amount')} />
</Form.Item>
......@@ -127,7 +127,7 @@ const AddLogistics: React.FC<{}> = () => {
width: 120,
dataIndex: 'carton',
render: (text: any, record: any, index: number) =>
<Form.Item noStyle name={`carton${index}`} initialValue={record.carton} rules={[{ required: true, message: '请输入箱数' }]}>
<Form.Item style={{ marginBottom: 0 }} name={`carton${index}`} initialValue={record.carton} rules={[{ required: true, message: '请输入箱数' }]}>
<Input type='number' min={1} onBlur={(e) => inputOnchange(record.productId, e, 'carton')} />
</Form.Item>
},
......@@ -137,7 +137,7 @@ const AddLogistics: React.FC<{}> = () => {
width: 120,
dataIndex: 'weight',
render: (text: any, record: any, index: number) =>
<Form.Item noStyle name={`weight${index}`} initialValue={record.weight} rules={[{ required: true, message: '请输入重量 (KG)' }]}>
<Form.Item style={{ marginBottom: 0 }} name={`weight${index}`} initialValue={record.weight} rules={[{ required: true, message: '请输入重量 (KG)' }]}>
<Input type='number' min={1} onBlur={(e) => inputOnchange(record.productId, e, 'weight')} />
</Form.Item>
},
......@@ -147,7 +147,7 @@ const AddLogistics: React.FC<{}> = () => {
width: 120,
dataIndex: 'volume',
render: (text: any, record: any, index: number) =>
<Form.Item noStyle name={`volume${index}`} initialValue={record.volume} rules={[{ required: true, message: '请输入体积 (M3)' }]}>
<Form.Item style={{ marginBottom: 0 }} name={`volume${index}`} initialValue={record.volume} rules={[{ required: true, message: '请输入体积 (M3)' }]}>
<Input type='number' min={1} onBlur={(e) => inputOnchange(record.productId, e, 'volume')} />
</Form.Item>
},
......@@ -376,6 +376,25 @@ const AddLogistics: React.FC<{}> = () => {
return new Promise(resolve => {
switch (Number(createType)) {
case 1:
if (query.shipmentOrderId) {
PublicApi.getWarehouseInvoicesProductList({ ...params, invoicesId: query.shipmentOrderId }).then((res: any) => {
if (res.code === 1000) {
res.data.data.forEach(item => {
item.category = item.categoryName
item.brand = item.brandName
item.unit = item.unitName
})
resolve(res.data)
}
})
} else {
PublicApi.getOrderProcurementOrderProductList({ ...params, id: query.relevanceOrderId, orderNo: query.relevanceOrderCode }).then((res: any) => {
if (res.code === 1000) {
resolve(res)
}
})
}
break;
case 2:
PublicApi.getProductInvoicesProductList({ ...params, invoicesId: query.shipmentOrderId ? query.shipmentOrderId : query.relevanceOrderId }).then((res: any) => {
if (res.code === 1000) {
......@@ -636,6 +655,7 @@ const AddLogistics: React.FC<{}> = () => {
if (goodsRef.errorFields) {
data[1] = goodsRef.errorFields.length;
setbadge([...data]);
setLoading(false);
} else {
data[1] = 0;
setbadge(data)
......@@ -770,7 +790,7 @@ const AddLogistics: React.FC<{}> = () => {
<div>{query.receiverFullAddress}</div>
</Form.Item>
<Form.Item label="发货地址" name="shipperAddressId" rules={[{ required: true, message: '请选择发货地址' }]}>
<Select allowClear onChange={(value, option) => handleSelectAddress(option )}>
<Select allowClear onChange={(value, option) => handleSelectAddress(option)}>
{
listShipperAddress.map((item: any, idx: number) => (
<Option key={item.id} value={item.id} shipperName={item.shipperName} shipperPhone={item.phone}>{item.fullAddress}</Option>
......@@ -849,7 +869,7 @@ const AddLogistics: React.FC<{}> = () => {
/>
{/* 选择对应订单号/售后单 */}
<ModalTableOrder
width={900}
width={1000}
visible={invoicesvisible}
columns={invoicesColumns}
invoicesNo={query.invoicesNo}
......
import React, { Component, useState, useEffect } from 'react';
import { Modal, Button, Form } from 'antd'
import { Modal, Button, Form, message } from 'antd'
import {
SchemaForm, SchemaMarkupField as Field,
createFormActions,
......
import React, { useEffect, useState, ReactNode, useRef, Fragment } from 'react';
import { Row, Col, Table, Input, Button, Tag, Badge, Steps, message, Form, Checkbox } from 'antd'
import { Row, Col, Table, Input, Button, Tag, Badge, Steps, message, Form, Checkbox, Typography } from 'antd'
import { PageHeaderWrapper } from '@ant-design/pro-layout'
import { CheckSquareOutlined } from '@ant-design/icons'
import { ColumnType } from 'antd/lib/table/interface'
......@@ -322,105 +322,106 @@ const detailInfo: React.FC<{}> = () => {
}
>
<Row>
<Col className={style['mainCol']} span={24}>
<div className={style['mainCol-title']}>
{detailData.step.title}
</div>
<Steps
style={{ padding: '34px 0' }}
progressDot
current={dataInfo.status - 1}
>
{Object.keys(dataInfo).length > 0 && dataInfo.externalList.map((item, index) => {
return (
<Step
key={index}
title={item.roleName}
description={item.operationalProcess}
status={item.isExecute ? 'finish' : 'wait'}
/>
);
})}
</Steps>
</Col>
<Col className={style['mainCol']} span={24}>
<div className={style['mainCol-title']}>
{infoTem['base'].title}
</div>
<div className={style['mainCol-rows']}>
<div className={style['mainCol-rows-cols']}>
{infoTem['base'].leftElem.map(
(item: any, index: number) => {
return (
<div className={style['cols-main']} key={index}>
<div className={style['cols-main-options']} style={{ flex: '1.5 1' }}>
{item.title}
</div>
<div className={style['cols-main-options']}>
<div>{item.value}</div>
</div>
</div>
);
},
)}
<Form {...layout} form={form}>
<Row>
<Col className={style['mainCol']} span={24}>
<div className={style['mainCol-title']}>
{detailData.step.title}
</div>
<div className={style['mainCol-rows-cols']}>
{infoTem['base'].centerElem.map(
(item: any, index: number) => {
return (
<div className={style['cols-main']} key={index}>
<div className={style['cols-main-options']}>
{item.title}
<Steps
style={{ padding: '34px 0' }}
progressDot
current={dataInfo.status - 1}
>
{Object.keys(dataInfo).length > 0 && dataInfo.externalList.map((item, index) => {
return (
<Step
key={index}
title={item.roleName}
description={item.operationalProcess}
status={item.isExecute ? 'finish' : 'wait'}
/>
);
})}
</Steps>
</Col>
<Col className={style['mainCol']} span={24}>
<div className={style['mainCol-title']}>
{infoTem['base'].title}
</div>
<div className={style['mainCol-rows']}>
<div className={style['mainCol-rows-cols']}>
{infoTem['base'].leftElem.map(
(item: any, index: number) => {
return (
<div className={style['cols-main']} key={index}>
<div className={style['cols-main-options']} style={{ flex: '1.5 1' }}>
{item.title}
</div>
<div className={style['cols-main-options']}>
<div>{item.value}</div>
</div>
</div>
<div className={style['cols-main-options']}>{item.value}</div>
);
},
)}
</div>
<div className={style['mainCol-rows-cols']}>
{infoTem['base'].centerElem.map(
(item: any, index: number) => {
return (
<div className={style['cols-main']} key={index}>
<div className={style['cols-main-options']}>
{item.title}
</div>
<div className={style['cols-main-options']}>{item.value}</div>
</div>
);
},
)}
</div>
<div className={style['mainCol-rows-cols']}>
{infoTem['base'].rightElem.map(
(item: any, index: number) => {
return (
<div className={style['cols-main']} key={`base${index + 1}`}>
<div className={style['cols-main-options']}>
{item.title}
</div>
<div className={style['cols-main-options']}>{item.value}</div>
);
},
)}
</div>
<div className={style['mainCol-rows-cols']}>
{infoTem['base'].rightElem.map(
(item: any, index: number) => {
return (
<div className={style['cols-main']} key={`base${index + 1}`}>
<div className={style['cols-main-options']}>
{item.title}
</div>
<div className={style['cols-main-options']}>{item.value}</div>
</div>
);
},
)}
</div>
);
},
)}
</div>
</div>
</div>
</Col>
<Col className={style['mainCol']} span={24}>
<div className={style['mainCol-title']}>
物流单明细
</div>
<Table dataSource={dataInfo.detailList} columns={columns1} pagination={false} />
<Row style={{ marginTop: '26px' }}>
<Col span={9} push={15}>
<Row align='middle' justify='center' gutter={[16, 16]}>
<Col span={8} >
<div>总箱数(箱)</div>
<div className={style.count}>{dataInfo.totalCarton}</div>
</Col>
<Col span={8} >
<div>总重量(KG)</div>
<div className={style.count}>{dataInfo.totalWeight}</div>
</Col>
<Col span={8} >
<div>总体积(M3)</div>
<div className={style.count}>{dataInfo.totalVolume}</div>
</Col>
</Col>
<Col className={style['mainCol']} span={24}>
<div className={style['mainCol-title']}>
物流单明细
</div>
<Table dataSource={dataInfo.detailList} columns={columns1} pagination={false} />
<Row style={{ marginTop: '26px' }}>
<Col span={9} push={15}>
<Row align='middle' justify='center' gutter={[16, 16]}>
<Col span={8} >
<div>总箱数(箱)</div>
<div className={style.count}>{dataInfo.totalCarton}</div>
</Col>
<Col span={8} >
<div>总重量(KG)</div>
<div className={style.count}>{dataInfo.totalWeight}</div>
</Col>
<Col span={8} >
<div>总体积(M3)</div>
<div className={style.count}>{dataInfo.totalVolume}</div>
</Col>
</Row>
</Col>
</Row>
</Row>
</Col>
</Row>
</Col>
<Col className={style['mainCol']} span={24}>
......@@ -473,21 +474,69 @@ const detailInfo: React.FC<{}> = () => {
},
)}
</div>
<div className={style['mainCol-rows-cols']}></div>
<div className={style['mainCol-rows-cols']}></div>
<div className={style['mainCol-rows']}>
<div className={style['mainCol-rows-cols']}>
{infoTem['freight'].leftElem.map(
(item: any, index: number) => {
return (
<>
{item.key === 'freight' &&
<>
{type === 'option' ? (
<Form.Item
label={item.title}
name={item.key}
rules={[
{
required: true,
message: '请正确输入运费',
},
{
pattern: /^\d+(\.\d{1,2})?$/,
message: '运费数值小数点后仅限两位',
}
]}
>
<Input
type='number'
addonBefore="¥"
maxLength={25}
style={{ width: '300px' }}
/>
</Form.Item>
) : (
<Form.Item label={item.title} name={item.key} rules={[{ required: true, message: '请输入运费' }]}>
{dataInfo.status < 3 ? <Typography.Text>未报价</Typography.Text> : <Typography.Text>{item.value && `¥${(item.value).toFixed(2)}`}</Typography.Text>}
</Form.Item>
)}
</>
}
{item.key === 'settlement' &&
<Form.Item label={item.title} name={item.key}>
<span>{item.value}</span>
</Form.Item>}
</>
);
},
)}
</div>
<div className={style['mainCol-rows-cols']}></div>
<div className={style['mainCol-rows-cols']}></div>
</div>
</div>
</Col>
<Col className={style['mainCol']} span={24}>
<div className={style['mainCol-title']}>外部流转记录</div>
<Table
columns={columns}
dataSource={dataInfo.logisticsOrderLogList}
pagination={false}
rowKey={(record: any, index: number) => index}
/>
{/* <OrderLog id={id} pathName={history.location.pathname} /> 2020-12-11 已经在详情接口返回 不需要这个了 */}
</Col>
</Row>
<Col className={style['mainCol']} span={24}>
<div className={style['mainCol-title']}>外部流转记录</div>
<Table
columns={columns}
dataSource={dataInfo.logisticsOrderLogList}
pagination={false}
rowKey={(record: any, index: number) => index}
/>
{/* <OrderLog id={id} pathName={history.location.pathname} /> 2020-12-11 已经在详情接口返回 不需要这个了 */}
</Col>
</Col>
</Row>
</Form>
<ConfirmModal
id={id}
dialogVisible={visible}
......
......@@ -217,7 +217,7 @@ const AddRepository:React.FC<{}> = (props) => {
<Tabs.TabPane key='tab1' tab='仓位设置'>
<PositionSetting onFieldChange={onPublicFieldChange} addSchemaAction={addSchemaAction} schema={repositTabOneSchema} formSubmit={formSubmit}/>
</Tabs.TabPane>
<Tabs.TabPane key='tab2' tab='库存调入\调'>
<Tabs.TabPane key='tab2' tab='库存调入\调'>
<Tabs defaultActiveKey='tab2-1' tabPosition='left'>
<Tabs.TabPane tab='库存调入' key="tab2-1">
{/* 使用formProvider 共享两个表单中的值 */}
......
......@@ -106,7 +106,7 @@ const Details: React.FC<parmas> = (props) => {
console.log(data)
window.open(`/shop/commodity/detail?id=${data.commodityId}&shopId=${btoa(JSON.stringify({ roleId: data.memberRoleId, memberId: data.memberId }))}`)
}
const inquiryGoods: ColumnType<any>[] = [{
const column: ColumnType<any>[] = [{
title: 'ID',
key: 'productId',
dataIndex: 'productId',
......@@ -131,14 +131,52 @@ const Details: React.FC<parmas> = (props) => {
title: '采购数量',
key: 'purchaseCount',
dataIndex: 'purchaseCount',
}]
const inquiryGoods: ColumnType<any>[] = [{
title: 'ID',
key: 'productId',
dataIndex: 'productId',
}, {
title: '报价商品名称',
key: 'productName',
dataIndex: 'productName',
render: (text: any, record: any) => <EyePreview type='button' handleClick={() => handleJump(record)}>{text}</EyePreview>
}, {
title: '品类',
key: 'category',
dataIndex: 'category',
}, {
title: '品牌',
key: 'brand',
dataIndex: 'brand',
}, {
title: '单位',
key: 'unit',
dataIndex: 'unit',
}, {
title: '采购数量',
key: 'purchaseCount',
dataIndex: 'purchaseCount',
},
{
title: '报价单价',
key: 'price',
dataIndex: 'price',
}, {
render: (text:any) => (
<>
{ text ? `¥${text.toFixed(2)}` : `¥0`}
</>
)
},
{
title: '金额',
key: 'money',
dataIndex: 'money',
render: (text:any) => (
<>
{ text ? `¥${text.toFixed(2)}` : `¥0`}
</>
)
}]
// 条件交易&其他报价说明
const infoTem = {
......@@ -488,8 +526,8 @@ const Details: React.FC<parmas> = (props) => {
</Tabs>
</div>
<div className={style.item_wrap}>
<div className={style.mainCol_title} style={view === 2 ? { paddingBottom: '0px' } : { paddingBottom: '24px' }}>询价商品</div>
{view === 1 && <Table columns={inquiryGoods} pagination={false} rowKey='id' dataSource={data.inquiryListProductRequests} />}
<div className={style.mainCol_title} style={view === 2 ? { paddingBottom: '0px' } : { paddingBottom: '24px' }}>{view === 1 ? '商品询价' : '商品报价'}</div>
{view === 1 && <Table columns={column} pagination={false} rowKey='id' dataSource={data.inquiryListProductRequests} />}
{view === 2 &&
<StandardTable
currentRef={ref}
......
......@@ -33,7 +33,6 @@ const BasicInfo: React.FC<queryProps> = (props) => {
const handleOkAddMember = () => {
if (inquiryRowCtl.selectRow.length > 0) {
setVisibleChannelMember(false)
console.log(inquiryRowCtl.selectRow[0])
setinquiryNo(inquiryRowCtl.selectRow[0]);
getMemberList(inquiryRowCtl.selectRow[0]); // 回传给父级
}
......@@ -145,8 +144,8 @@ const BasicInfo: React.FC<queryProps> = (props) => {
<Form.Item label='报价单号' name='quotationNo'>
<span>{Object.keys(editData).length > 0 ? editData.quotationNo : '-'}</span>
</Form.Item>
<Form.Item label='询价会员' name='memberName'>
<span>{Object.keys(editData).length > 0 ? editData.memberName : '-'}</span>
<Form.Item label='询价会员' name='inquiryListMemberName'>
<span>{Object.keys(editData).length > 0 ? (editData.inquiryListMemberName || editData.memberName ) : '-'}</span>
</Form.Item>
<Form.Item label='报价截止时间' name='quotationAsTime'>
<span>{Object.keys(editData).length > 0 ? format(editData.quotationAsTime) : '-'}</span>
......
......@@ -136,6 +136,32 @@ const Details: React.FC<parmas> = (props) => {
console.log(data)
window.open(`/shop/commodity/detail?id=${data.productId}&type=2&shopId=${btoa(JSON.stringify({ roleId: data.memberRoleId, memberId: data.memberId }))}`)
}
const column: ColumnType<any>[] = [{
title: 'ID',
key: 'productId',
dataIndex: 'productId',
}, {
title: '报价商品名称',
key: 'productName',
dataIndex: 'productName',
render: (text: any, record: any) => <EyePreview type='button' handleClick={() => handleJump(record)}>{text}</EyePreview>
}, {
title: '品类',
key: 'category',
dataIndex: 'category',
}, {
title: '品牌',
key: 'brand',
dataIndex: 'brand',
}, {
title: '单位',
key: 'unit',
dataIndex: 'unit',
}, {
title: '采购数量',
key: 'purchaseCount',
dataIndex: 'purchaseCount',
}]
const inquiryGoods: ColumnType<any>[] = [{
title: 'ID',
key: 'productId',
......@@ -161,6 +187,26 @@ const Details: React.FC<parmas> = (props) => {
title: '采购数量',
key: 'purchaseCount',
dataIndex: 'purchaseCount',
},
{
title: '报价单价',
key: 'price',
dataIndex: 'price',
render: (text:any) => (
<>
{ text ? `¥${text.toFixed(2)}` : `¥0`}
</>
)
},
{
title: '金额',
key: 'money',
dataIndex: 'money',
render: (text:any) => (
<>
{ text ? `¥${text.toFixed(2)}` : `¥0`}
</>
)
}]
// 条件交易&其他报价说明
const infoTem = {
......@@ -532,8 +578,8 @@ const Details: React.FC<parmas> = (props) => {
</Tabs>
</div>
<div className={style.item_wrap}>
<div className={style.mainCol_title}>询价商品</div>
{view === 1 && <Table columns={inquiryGoods} pagination={false} rowKey='id' dataSource={data.inquiryListProductRequests} />}
<div className={style.mainCol_title}>{view === 1 ? '商品询价' : '商品报价'}</div>
{view === 1 && <Table columns={column} pagination={false} rowKey='id' dataSource={data.inquiryListProductRequests} />}
{view === 2 &&
<StandardTable
currentRef={ref}
......
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