Commit 37933f53 authored by 邓超's avatar 邓超

fix: 菜单配置动态添加

parent 52735af5
Pipeline #71714 waiting for manual action with stages
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Modal, Form, Select, Input, Checkbox } from 'antd'; import { Modal, Form, Select, Input, Checkbox, message } from 'antd';
import lodash from 'lodash'; import lodash from 'lodash';
import styles from './HomeConfigModal.less'; import styles from './HomeConfigModal.less';
import { GetRoleGroups } from '@/services/webConfig/api'; import { GetRoleGroups } from '@/services/webConfig/api';
import TreeSelect from '../menuconfig/TreeSelect';
const { Option } = Select; const { Option } = Select;
const HomeConfigModal = props => { const HomeConfigModal = props => {
const { handleCancel, productList, visible, onFinish, currentPageConfig, client } = props; const {
handleCancel,
productList,
allProductList,
visible,
onFinish,
currentPageConfig,
client,
} = props;
const [form] = Form.useForm(); const [form] = Form.useForm();
const [checkList, setCheckList] = useState(null); const [checkList, setCheckList] = useState(null);
...@@ -21,6 +30,24 @@ const HomeConfigModal = props => { ...@@ -21,6 +30,24 @@ const HomeConfigModal = props => {
// 保存配置 // 保存配置
const onSubmit = () => { const onSubmit = () => {
console.log(form.getFieldsValue().homePage);
if (!form.getFieldsValue().homePage) {
message.error('请填写主页url');
return;
}
let obj = { homePage: form.getFieldsValue().homePage, productType: '' };
let arrUrl = obj.homePage.split('/'); // 用const声明常量
const product = allProductList.find(item => item.PackageName.includes(arrUrl[0]));
if (!product) {
// arrUrl.shift();
obj.homePage = `civweb4/${obj.homePage}`;
}
obj.productType = product?.PackageName || 'civweb4';
if (!productList.some(item => item.PackageName === obj.productType)) {
message.error(`${obj.productType}未授权,不能使用该功能当主页`);
return;
}
let roleName = []; let roleName = [];
let roleId = []; let roleId = [];
const getArr = arr => { const getArr = arr => {
...@@ -35,9 +62,9 @@ const HomeConfigModal = props => { ...@@ -35,9 +62,9 @@ const HomeConfigModal = props => {
}; };
getArr(checkList); getArr(checkList);
console.log(checkList, { ...form.getFieldsValue(), roleName, roleId }); console.log(checkList, { ...obj, roleName, roleId }, 'aaaaaa');
onFinish({ onFinish({
...form.getFieldsValue(), ...obj,
roleName: roleName.join(','), roleName: roleName.join(','),
roleId, roleId,
keyIndex: currentPageConfig.keyIndex, keyIndex: currentPageConfig.keyIndex,
...@@ -212,7 +239,7 @@ const HomeConfigModal = props => { ...@@ -212,7 +239,7 @@ const HomeConfigModal = props => {
wrapperCol={{ span: 21 }} wrapperCol={{ span: 21 }}
initialValues={{ remember: true }} initialValues={{ remember: true }}
> >
<Form.Item label="产品类型" name="productType"> {/* <Form.Item label="产品类型" name="productType">
<Select placeholder="请选择主页产品类型"> <Select placeholder="请选择主页产品类型">
{productList.map(item => ( {productList.map(item => (
<Option value={item.PackageName} key={item.PackageName}> <Option value={item.PackageName} key={item.PackageName}>
...@@ -220,9 +247,10 @@ const HomeConfigModal = props => { ...@@ -220,9 +247,10 @@ const HomeConfigModal = props => {
</Option> </Option>
))} ))}
</Select> </Select>
</Form.Item> </Form.Item> */}
<Form.Item label="主页Url" name="homePage"> <Form.Item label="主页Url" name="homePage">
<Input placeholder="请输入主页路径" autoComplete="off" /> {/* <Input placeholder="请输入主页路径" autoComplete="off" /> */}
<TreeSelect menuChange={val => {}} />
</Form.Item> </Form.Item>
</Form> </Form>
<div className={styles.roleCheck}>{checkRender(checkList)}</div> <div className={styles.roleCheck}>{checkRender(checkList)}</div>
......
.content { .content {
max-height: 600px; // max-height: 600px;
overflow-y: scroll // // overflow-y: scroll
} }
.checkList { .roleCheck {
display: flex; max-height: 600px;
flex-wrap: wrap; overflow-y: scroll;
width: 100%;
border: 1px solid #c2cdfd;
padding: 20px 15px 10px 15px;
position: relative;
margin-top: 15px;
align-items: center;
// margin-bottom: 10px;
border-radius: 5px;
.title { .checkList {
position: absolute; display: flex;
top: -12px; flex-wrap: wrap;
background-color: #fff; width: 100%;
} border: 1px solid #c2cdfd;
padding: 20px 15px 10px 15px;
position: relative;
margin-top: 15px;
align-items: center;
// margin-bottom: 10px;
border-radius: 5px;
.title {
position: absolute;
top: -12px;
background-color: #fff;
}
}
} }
\ No newline at end of file
...@@ -7,7 +7,7 @@ import HomeConfigModal from './HomeConfigModal'; ...@@ -7,7 +7,7 @@ import HomeConfigModal from './HomeConfigModal';
import styles from './HomePageConfigs.less'; import styles from './HomePageConfigs.less';
const HomePageConfigs = (props, ref) => { const HomePageConfigs = (props, ref) => {
const { productList, client, roleHomePages } = props; const { productList, client, roleHomePages, allProductList } = props;
const [orderTable, setOrderTable] = useState([]); const [orderTable, setOrderTable] = useState([]);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [modalType, setModalType] = useState(); const [modalType, setModalType] = useState();
...@@ -76,12 +76,12 @@ const HomePageConfigs = (props, ref) => { ...@@ -76,12 +76,12 @@ const HomePageConfigs = (props, ref) => {
// width: 50, // width: 50,
// key: 'index', // key: 'index',
// }, // },
{ // {
title: '产品类型', // title: '产品类型',
dataIndex: 'productType', // dataIndex: 'productType',
width: 100, // width: 100,
key: 'productType', // key: 'productType',
}, // },
{ {
title: '主页Url', title: '主页Url',
dataIndex: 'homePage', dataIndex: 'homePage',
...@@ -160,6 +160,7 @@ const HomePageConfigs = (props, ref) => { ...@@ -160,6 +160,7 @@ const HomePageConfigs = (props, ref) => {
visible={visible} visible={visible}
modalType={modalType} modalType={modalType}
productList={productList} productList={productList}
allProductList={allProductList}
client={client} client={client}
currentPageConfig={currentPageConfig} currentPageConfig={currentPageConfig}
onFinish={val => onsubmit(val)} onFinish={val => onsubmit(val)}
......
...@@ -17,8 +17,10 @@ import { ...@@ -17,8 +17,10 @@ import {
Row, Row,
Col, Col,
Switch, Switch,
message,
} from 'antd'; } from 'antd';
import { PlusOutlined, InfoCircleOutlined } from '@ant-design/icons'; import { PlusOutlined, InfoCircleOutlined } from '@ant-design/icons';
import TreeSelect from '../menuconfig/TreeSelect';
import WebConfigForm from './webConfigForm'; import WebConfigForm from './webConfigForm';
import ColorLinear from './ColorLinear'; import ColorLinear from './ColorLinear';
import Upload from '@/components/Upload'; import Upload from '@/components/Upload';
...@@ -56,6 +58,7 @@ export default props => { ...@@ -56,6 +58,7 @@ export default props => {
onOk, onOk,
submitting, submitting,
productList, productList,
allProductList,
webs, webs,
} = props; } = props;
const [form] = Form.useForm(); const [form] = Form.useForm();
...@@ -264,13 +267,37 @@ export default props => { ...@@ -264,13 +267,37 @@ export default props => {
validate.messageMarking = visibleChecked3 ? 'All' : 'One'; validate.messageMarking = visibleChecked3 ? 'All' : 'One';
validate.menuState = visibleChecked5 ? 'open' : 'close'; validate.menuState = visibleChecked5 ? 'open' : 'close';
console.log(validate); console.log(validate);
let arr = validate.homePage.split('/'); // 用const声明常量
const product = allProductList.find(item => item.PackageName.includes(arr[0]));
if (product) {
arr.shift();
validate.homePage = arr.join('/');
}
console.log(product, 'product');
validate.productType = product?.PackageName || 'civweb4';
if (!productList.some(item => item.PackageName === validate.productType)) {
message.error(`${validate.productType}未授权,不能使用该功能当主页`);
return;
}
console.log(validate);
if (validate) { if (validate) {
const colorIndex = colorList.findIndex(item => item.color === validate.primaryColor); const colorIndex = colorList.findIndex(item => item.color === validate.primaryColor);
let pages = homepageConfigRef.current.getHomePageConfig().map((item, index) => {
let str = item.homePage.replace(/^[^\/]+\/+/, '');
console.log(str, 'fasdasd');
return {
...item,
homePage: item.homePage.replace(/^[^\/]+\/+/, ''),
index,
};
});
console.log(pages, 'pages');
onOk({ onOk({
...validate, ...validate,
roleHomePages: homepageConfigRef.current roleHomePages: pages,
.getHomePageConfig()
.map((item, index) => ({ ...item, index })),
headerPrimaryColor: colorList[colorIndex].headerColor, headerPrimaryColor: colorList[colorIndex].headerColor,
mode: 'single', mode: 'single',
menu: 'banner-left', menu: 'banner-left',
...@@ -447,7 +474,7 @@ export default props => { ...@@ -447,7 +474,7 @@ export default props => {
<Divider orientation="left" style={{ borderTopColor: '#99bbe8' }}> <Divider orientation="left" style={{ borderTopColor: '#99bbe8' }}>
主页配置 主页配置
</Divider> </Divider>
<Form.Item label="产品类型(默认)" name="productType"> {/* <Form.Item label="产品类型(默认)" name="productType">
<Select placeholder="请选择主页产品类型"> <Select placeholder="请选择主页产品类型">
{productList.map(item => ( {productList.map(item => (
<Option value={item.PackageName} key={item.PackageName}> <Option value={item.PackageName} key={item.PackageName}>
...@@ -455,14 +482,16 @@ export default props => { ...@@ -455,14 +482,16 @@ export default props => {
</Option> </Option>
))} ))}
</Select> </Select>
</Form.Item> </Form.Item> */}
<Form.Item label="主页地址(默认)" name="homePage"> <Form.Item label="主页地址(默认)" name="homePage">
<Input placeholder="请输入主页路径" autoComplete="off" /> {/* <Input placeholder="请输入主页路径" autoComplete="off" /> */}
<TreeSelect menuChange={val => {}} />
</Form.Item> </Form.Item>
<HomePageConfigs <HomePageConfigs
ref={homepageConfigRef} ref={homepageConfigRef}
roleHomePages={homePageConfig} roleHomePages={homePageConfig}
productList={productList} productList={productList}
allProductList={allProductList}
client={form.getFieldValue('client')} client={form.getFieldValue('client')}
/> />
<Divider orientation="left" style={{ borderTopColor: '#99bbe8' }}> <Divider orientation="left" style={{ borderTopColor: '#99bbe8' }}>
......
...@@ -41,7 +41,7 @@ const WebConfigPage = props => { ...@@ -41,7 +41,7 @@ const WebConfigPage = props => {
const [configFiles, setConfigFiles] = useState([]); const [configFiles, setConfigFiles] = useState([]);
const [productList, setProductList] = useState([]); // 产品列表 const [productList, setProductList] = useState([]); // 产品列表
const [sortVisible, setSortVisible] = useState(false); const [sortVisible, setSortVisible] = useState(false);
const [allProductList, setAllProductList] = useState([]); // 所有产品列表
const hasIntegerate = () => webs.some(w => w.id.startsWith(webMode.integration)); const hasIntegerate = () => webs.some(w => w.id.startsWith(webMode.integration));
useEffect(() => { useEffect(() => {
...@@ -77,6 +77,7 @@ const WebConfigPage = props => { ...@@ -77,6 +77,7 @@ const WebConfigPage = props => {
const { const {
data: { UserProducts }, data: { UserProducts },
} = res; } = res;
setAllProductList(res.data.AllProducts);
if (UserProducts && UserProducts.length > 0) { if (UserProducts && UserProducts.length > 0) {
setProductList(UserProducts); setProductList(UserProducts);
} }
...@@ -391,6 +392,7 @@ const WebConfigPage = props => { ...@@ -391,6 +392,7 @@ const WebConfigPage = props => {
webid={tabPaneItem?.id} webid={tabPaneItem?.id}
subSystemValue={tabPaneItem?.subSystemValue} subSystemValue={tabPaneItem?.subSystemValue}
productList={productList} productList={productList}
allProductList={allProductList}
/> />
</Card> </Card>
</> </>
...@@ -470,6 +472,7 @@ const WebConfigPage = props => { ...@@ -470,6 +472,7 @@ const WebConfigPage = props => {
<SiteConfig <SiteConfig
webs={webs} webs={webs}
productList={productList} productList={productList}
allProductList={allProductList}
isEdit={isEdit} isEdit={isEdit}
visible={configVisible} visible={configVisible}
onClose={onDrawerClose} onClose={onDrawerClose}
......
import React from 'react'; import React, { useState } from 'react';
import { Form, Input, Button, Select, Radio } from 'antd'; import { Form, Input, Button, Select, Radio, message } from 'antd';
import styles from './addForm.less'; import styles from './addForm.less';
import PicturesWall from '@/components/Upload/index'; import PicturesWall from '@/components/Upload/index';
import EditeConfigWrapper from './editConfigFileWrapper'; import EditeConfigWrapper from './editConfigFileWrapper';
import TreeSelect from './TreeSelect';
const { Item } = Form; const { Item } = Form;
const { Option } = Select; const { Option } = Select;
const AddForm = props => { const AddForm = props => {
const { submitCallback, nodeObj, addType, submitLoading, configFiles, productList } = props; const {
submitCallback,
nodeObj,
addType,
submitLoading,
configFiles,
productList,
allProductList,
} = props;
const [curretnMenu, setCurrentMenu] = useState({}); // 当前选中菜单数据
const [form] = Form.useForm(); const [form] = Form.useForm();
const [otherForm] = Form.useForm(); const [otherForm] = Form.useForm();
const layout = { const layout = {
...@@ -19,13 +29,19 @@ const AddForm = props => { ...@@ -19,13 +29,19 @@ const AddForm = props => {
if (addType === 1) { if (addType === 1) {
let obj = form.getFieldsValue(); let obj = form.getFieldsValue();
let arr = obj.pageUrl.split('/'); // 用const声明常量 let arr = obj.pageUrl.split('/'); // 用const声明常量
const product = productList.find(item => item.PackageName.includes(arr[0])); const product = allProductList.find(item => item.PackageName.includes(arr[0]));
if (product) { if (product) {
arr.shift(); arr.shift();
obj.pageUrl = arr.join('/'); obj.pageUrl = arr.join('/');
} }
console.log(product, 'product'); console.log(product, 'product');
obj.product = product?.PackageName || 'civweb4'; obj.product = product?.PackageName || 'civweb4';
if (!productList.some(item => item.PackageName === obj.product)) {
message.error(`${obj.product}未授权,不能使用该功能`);
return;
}
obj.codeParam = JSON.stringify(curretnMenu.param);
obj.code = curretnMenu.code;
submitCallback(obj, nodeObj); submitCallback(obj, nodeObj);
} }
if (addType === 2) { if (addType === 2) {
...@@ -37,6 +53,18 @@ const AddForm = props => { ...@@ -37,6 +53,18 @@ const AddForm = props => {
const finish = () => { const finish = () => {
submit(); submit();
}; };
const menuChange = val => {
if (!val) {
return;
}
setCurrentMenu(val);
form.setFieldsValue({
menuName: val?.function,
shortName: val?.shortName,
imageUrl: val?.icon,
config: val?.configName,
});
};
return ( return (
<div> <div>
{addType === 1 && ( {addType === 1 && (
...@@ -102,7 +130,8 @@ const AddForm = props => { ...@@ -102,7 +130,8 @@ const AddForm = props => {
}, },
]} ]}
> >
<Input placeholder="请输入功能路径" /> {/* <Input placeholder="请输入功能路径" /> */}
<TreeSelect menuChange={val => menuChange(val)} />
</Item> </Item>
<Item label="配置文件" name="config"> <Item label="配置文件" name="config">
<EditeConfigWrapper> <EditeConfigWrapper>
......
...@@ -12,6 +12,7 @@ const ParmarModal = props => { ...@@ -12,6 +12,7 @@ const ParmarModal = props => {
.split('|')[1] .split('|')[1]
?.split('&') ?.split('&')
?.map(item => ({ key: item.split('=')[0], value: item.split('=')[1] })); ?.map(item => ({ key: item.split('=')[0], value: item.split('=')[1] }));
console.log(parma, 'parma');
form.setFieldsValue({ parmars: parma }); form.setFieldsValue({ parmars: parma });
} else { } else {
// 关闭弹窗清除表单数据 // 关闭弹窗清除表单数据
......
import React, { useState, useRef, useContext, useEffect } from 'react';
import { Modal, Form, Table, Input, Button, message } from 'antd';
import { DeleteOutlined } from '@ant-design/icons';
import styles from './ParmarsModal.less';
const EditableContext = React.createContext(null);
const EditableRow = ({ index, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
const EditableCell = ({
dataSource,
title,
editable,
children,
dataIndex,
record,
handleSave,
...restProps
}) => {
const [editing, setEditing] = useState(false);
const inputRef = useRef(null);
const form = useContext(EditableContext);
useEffect(() => {
if (editing) {
inputRef.current.focus();
}
}, [editing]);
const toggleEdit = () => {
setEditing(!editing);
form.setFieldsValue({
[dataIndex]: record[dataIndex],
});
};
const save = async () => {
try {
const values = await form.validateFields();
toggleEdit();
handleSave({
...record,
...values,
});
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
let childNode = children;
let keyNameRule = [
{
required: true,
message: `${title}不能为空`,
},
{
validator: (rule, value) => {
let list = JSON.parse(JSON.stringify(dataSource));
// 合并内置字段
if (value && list.some((item, i) => item.field === value && item.key !== record.key)) {
return Promise.reject(new Error('参数称重复,请重新输入'));
}
return Promise.resolve();
},
},
];
let rules = dataIndex === 'field' ? keyNameRule : [];
if (editable) {
childNode = editing ? (
<Form.Item
style={{
margin: 0,
}}
name={dataIndex}
rules={rules}
>
<Input
readOnly={record.name && dataIndex !== 'defaultValue'}
ref={inputRef}
onPressEnter={save}
onBlur={save}
/>
</Form.Item>
) : (
<div className="editable-cell-value-wrap" onClick={toggleEdit}>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
const ParmarsModal = props => {
const { pageUrl, visible, handleCancel, parmarCallBack, menuParmar, codeParam } = props;
const [dataSource, setDataSource] = useState([]);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [count, setCount] = useState(0);
useEffect(() => {
if (visible) {
// 给url通过字符串分割成表单需要的数据形式
let parmas = pageUrl
.split('|')[1]
?.split('&')
?.map((item, index) => {
let obj = {
field: item.split('=')[0],
defaultValue: item.split('=')[1],
};
return obj;
});
if (!parmas) {
parmas = [];
}
let codeParams = codeParam || [];
console.log(menuParmar, codeParams, parmas, 'menuParmar');
let finalArray = [];
if (menuParmar) {
finalArray = menuParmar?.concat(codeParams, parmas).reduce((acc, cur) => {
let existingIndex = acc.findIndex(item => item.field === cur.field);
if (existingIndex !== -1) {
acc[existingIndex] = Object.assign(acc[existingIndex], cur);
} else {
acc.push(cur);
}
return acc;
}, []);
} else {
finalArray = parmas;
}
console.log(finalArray.map((item, index) => ({ ...item, key: index })));
let select = [];
let newList = finalArray.map((item, index) => {
if (parmas.some(ele => ele.field === item.field)) {
select.push(index);
}
return { ...item, key: index };
});
setCount(finalArray.length);
setDataSource(newList);
setSelectedRowKeys(select);
} else {
setDataSource([]);
setSelectedRowKeys([]);
setCount(0);
}
}, [visible]);
const onFinish = () => {
console.log(selectedRowKeys, dataSource, 'selectedRowKeys');
if (dataSource.some(item => !item.field)) {
message.error('参数名称不能为空');
return;
}
let selectSet = new Set(selectedRowKeys);
let list = dataSource.reduce((acc, cur) => {
console.log(acc, 'accc');
if (selectSet.has(cur.key)) {
acc.push(cur);
}
return acc;
}, []);
let parma = list.map(item => `${item.field}=${item.defaultValue}`).join('&');
let parmas = dataSource.map(item => ({
field: item.field,
defaultValue: item.defaultValue,
paramDesc: item.paramDesc,
valueDesc: item.valueDesc,
}));
if (parma) {
parmarCallBack(`${pageUrl.split('|')[0]}|${parma}`, parmas);
} else {
parmarCallBack(`${pageUrl.split('|')[0]}`, parmas);
}
console.log(list, 'list');
};
const handleDelete = key => {
const newData = dataSource.filter(item => item.key !== key);
const newSelect = selectedRowKeys.filter(item => item !== key);
setSelectedRowKeys(newSelect);
setDataSource(newData);
};
const defaultColumns = [
{
title: '序号',
align: 'center',
width: 50,
render: (text, record, index) => <span>{index + 1}</span>,
},
{
title: '参数名',
dataIndex: 'field',
width: 150,
editable: true,
},
{
title: '参数值',
dataIndex: 'defaultValue',
width: 150,
editable: true,
},
{
title: '参数名描述',
dataIndex: 'paramDesc',
width: 250,
editable: true,
},
{
title: '参数值描述',
dataIndex: 'valueDesc',
width: 250,
editable: true,
},
{
title: '操作',
dataIndex: '',
width: 80,
align: 'center',
render: (_, record) =>
dataSource.length >= 1 ? (
<Button
style={{ border: 'none', padding: '4px 5px', background: 'none' }}
onClick={() => handleDelete(record.key)}
disabled={!!record.name}
>
<DeleteOutlined
style={{ fontSize: '16px', color: `${record.name ? '#ccc' : '#e86060'}` }}
/>
</Button>
) : null,
},
];
// 添加
const handleAdd = () => {
const newData = {
key: count,
field: '',
defaultValue: '',
paramDesc: '',
valueDesc: '',
};
console.log(newData, 'newData');
setDataSource([...dataSource, newData]);
setSelectedRowKeys([...selectedRowKeys, count]);
setCount(count + 1);
};
const handleSave = row => {
const newData = [...dataSource];
const index = newData.findIndex(item => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, {
...item,
...row,
});
setDataSource(newData);
};
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
const columns = defaultColumns.map(col => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: record => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
dataSource,
handleSave,
}),
};
});
// 表格复选框
const onSelectChange = newSelectedRowKeys => {
setSelectedRowKeys(newSelectedRowKeys);
};
const rowSelection = {
selectedRowKeys,
onChange: onSelectChange,
getCheckboxProps: record => ({
disabled: record.required,
}),
};
return (
<>
<Modal
title="参数配置"
width="1100px"
visible={visible}
onOk={onFinish}
onCancel={handleCancel}
maskClosable={false}
destroyOnClose
centered
>
<div className={styles.contentParmars}>
<Button
onClick={handleAdd}
type="primary"
style={{
marginBottom: 16,
}}
>
添加参数
</Button>
<Table
components={components}
rowSelection={rowSelection}
size="small"
rowClassName={() => 'editable-row'}
bordered
dataSource={dataSource}
columns={columns}
scroll={{ y: '340px' }}
pagination={false}
/>
</div>
</Modal>
</>
);
};
export default ParmarsModal;
.contentParmars {
max-height: 450px;
:global {
.ant-table-row {
height: 49px;
}
.editable-cell {
position: relative;
}
.editable-cell-value-wrap {
padding: 5px 12px;
cursor: pointer;
height: 32px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.editable-row:hover .editable-cell-value-wrap {
padding: 4px 11px;
border: 1px solid #fff;
border-radius: 2px;
}
[data-theme='dark'] .editable-row:hover .editable-cell-value-wrap {
border: 1px solid #434343;
}
.ant-table-cell-ellipsis {
overflow: visible;
}
.ant-table-cell {
overflow: visible;
}
.ant-form-item-explain {
position: absolute;
height: 35px;
// width: 180px;
padding: 0 5px;
background-color: #ff4d4f;
top: 40px;
left: 50%;
transform: translateX(-50%);
border-radius: 5px;
z-index: 10
}
.ant-form-item-explain-error {
color: #fff;
line-height: 35px;
}
.ant-select-arrow .anticon {
margin-top: 8px;
}
}
}
\ No newline at end of file
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { GetWebMenuInfo } from '@/services/webConfig/api';
import { message, Input, Tree, Empty, Tooltip } from 'antd';
import lodash from 'lodash';
import { FolderFilled, FileOutlined, InfoCircleOutlined } from '@ant-design/icons';
import styles from './TreeSelect.less';
const TreeSelect = (props, ref) => {
const { value, onChange, menuChange, code, initCurrentMenu } = props;
const [menuWebList, setMenuWebList] = useState({});
const [treeList, setTreeList] = useState({});
const [visible, setVisible] = useState(false);
const [expandedKeys, setExpandedKeys] = useState([]);
const [curretnMenuParmar, setCurrentMenuParmar] = useState();
useEffect(() => {
console.log(333333);
getMenu();
}, []);
useImperativeHandle(ref, () => ({ getParmar }));
const getMenu = () => {
GetWebMenuInfo().then(res => {
if (res.code === 0) {
let tree = arrayToTree(lodash.cloneDeep(res.data), 'model', 'moduleName');
console.log(tree, 'fadsfasd');
setTreeList(tree);
setMenuWebList(
res.data.map(item => {
let obj = { ...item, path: `${item.packName}/${item.path}` };
if (item.code === code) {
setCurrentMenuParmar(obj);
initCurrentMenu(obj);
}
return obj;
}),
);
} else {
message.error(res.msg);
}
});
};
// 定义一个函数,把数组转换成树形结构
const arrayToTree = (array, field1, field2) => {
// 使用reduce方法按照第一个字段进行分组
let tree = array.reduce((acc, cur) => {
let value1 = cur[field1];
// 如果累加器中没有该字段的属性,就创建一个空数组
if (!acc[value1]) {
acc[value1] = [];
}
// 将当前元素放入对应的数组中
acc[value1].push(cur);
// 返回累加器
return acc;
}, {});
// 遍历对象的每个属性,使用reduce方法按照第二个字段进行分组
Object.keys(tree).forEach(key => {
let array2 = tree[key];
let tree2 = array2.reduce((acc2, cur2) => {
let value2 = cur2[field2];
// 如果累加器中没有该字段的属性,就创建一个空数组
if (!acc2[value2]) {
acc2[value2] = [];
}
// 将当前元素放入对应的数组中
acc2[value2].push(cur2);
// 返回累加器
return acc2;
}, {});
// 将第二层的对象替换第一层的数组
tree[key] = tree2;
});
// 返回树形结构对象
return tree;
};
const mapTree = key => ({
key,
title: key,
icon: <FolderFilled />,
disabled: true,
children: Object.keys(treeList[key]).map(k => ({
key: k + key,
title: k,
icon: <FolderFilled />,
disabled: true,
children: treeList[key][k].map(item => ({
key: item.code,
param: item,
title: (
<div className={styles.treeLine}>
{item.shortName}
<Tooltip title={item.desc} overlayStyle={{ maxWidth: 350 }}>
<InfoCircleOutlined
style={{ color: '#40a9ff', padding: '2px 2px 0 0', marginLeft: '5px' }}
/>
</Tooltip>
</div>
),
icon: <FileOutlined />,
})),
})),
});
const filterList = val => {
if (!val) {
val = '';
}
let keys = new Set([]);
let list = lodash.cloneDeep(menuWebList).filter(item => {
keys.add(item.model);
keys.add(item.moduleName + item.model);
return item.shortName.includes(val) || item.path?.includes(val) || val?.includes(item.path);
});
setExpandedKeys([...keys]);
// 调用函数,传入数组
let tree = arrayToTree(list, 'model', 'moduleName');
setTreeList(tree);
};
const changeValue = e => {
// 过滤数组
onChange(e.target.value);
filterList(e.target.value);
setVisible(true);
};
const onSelect = (selectedKeysValue, info) => {
menuChange(info.selectedNodes[0].param);
onChange(info.selectedNodes[0].param.path);
setCurrentMenuParmar(info.selectedNodes[0].param);
setVisible(false);
};
const getParmar = () => curretnMenuParmar;
const onExpand = expandedKeysValue => {
setExpandedKeys(expandedKeysValue);
};
return (
<div className={styles.treeSelect}>
<Input
allowClear
placeholder="请选填写菜单功能路径"
value={value}
onFocus={() => filterList(value)}
onClick={() => setVisible(!visible)}
onChange={changeValue}
onBlur={() => setVisible(false)}
/>
<div
className={styles.dropBox}
onMouseDown={event => {
event.preventDefault();
}}
style={{ display: visible ? 'block' : 'none' }}
>
<Tree
onExpand={onExpand}
selectedKeys={null}
showIcon
expandedKeys={expandedKeys}
autoExpandParent
onSelect={onSelect}
treeData={Object.keys(treeList).map(key => mapTree(key))}
style={{ width: '100%' }}
/>
{Object.keys(treeList).length === 0 ? <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> : null}
</div>
</div>
);
};
export default forwardRef(TreeSelect);
.treeSelect {
position: relative;
width: 100%;
display: flex;
flex-direction: column;
.dropBox {
position: absolute;
top: 40px;
width: 100%;
padding: 10px;
min-height: 50px;
max-height: 300px;
background-color: #fff;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.3);
border-radius: 2px;
z-index: 10;
overflow-y: scroll;
overflow-x: hidden;
.treeLine {
display: flex;
align-items: center;
}
:global {
.ant-tree-treenode {
width: 100%;
}
.ant-tree-node-content-wrapper {
display: flex;
}
}
}
}
\ No newline at end of file
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { import {
Form, Form,
Input, Input,
...@@ -12,14 +12,26 @@ import { ...@@ -12,14 +12,26 @@ import {
message, message,
notification, notification,
Switch, Switch,
AutoComplete,
Empty,
} from 'antd'; } from 'antd';
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; import {
MinusCircleOutlined,
PlusOutlined,
DesktopOutlined,
FolderFilled,
FileOutlined,
} from '@ant-design/icons';
import { GetWebMenuInfo } from '@/services/webConfig/api';
import classnames from 'classnames'; import classnames from 'classnames';
import styles from './addForm.less'; import styles from './addForm.less';
import PicturesWall from '@/components/Upload/index'; import PicturesWall from '@/components/Upload/index';
import EditeConfigWrapper from './editConfigFileWrapper'; import EditeConfigWrapper from './editConfigFileWrapper';
import CheckList from './checkBox'; import CheckList from './checkBox';
import ParmarModal from './ParmarModal'; import ParmarModal from './ParmarModal';
import ParmarsModal from './ParmarsModal';
import TreeSelect from './TreeSelect';
// const { TreeNode } = TreeSelect;
const { Item } = Form; const { Item } = Form;
const { Option } = Select; const { Option } = Select;
...@@ -33,6 +45,7 @@ const EditForm = props => { ...@@ -33,6 +45,7 @@ const EditForm = props => {
configFiles, configFiles,
valueCallback = () => {}, valueCallback = () => {},
productList, productList,
allProductList,
} = props; } = props;
const [form] = Form.useForm(); const [form] = Form.useForm();
const [otherForm] = Form.useForm(); const [otherForm] = Form.useForm();
...@@ -42,15 +55,23 @@ const EditForm = props => { ...@@ -42,15 +55,23 @@ const EditForm = props => {
const [indeterminateAll, setIndeterminateAll] = useState(false); const [indeterminateAll, setIndeterminateAll] = useState(false);
const [choo, setChoo] = useState(false); // 最外层复选框状态 const [choo, setChoo] = useState(false); // 最外层复选框状态
const [visibleChecked, setVisibleChecked] = useState(false); const [visibleChecked, setVisibleChecked] = useState(false);
const [menuParmar, setMenuParmar] = useState([]);
const [codeParmar, setCodeParmar] = useState([]);
const [curretnMenu, setCurrentMenu] = useState({}); // 当前选中菜单数据
const treeSelectRef = useRef();
const layout = { const layout = {
layout: 'horizontal', layout: 'horizontal',
labelCol: { span: 2 }, labelCol: { span: 2 },
wrapperCol: { span: 21 }, wrapperCol: { span: 21 },
}; };
// 回显表单 // 回显表单
useEffect(() => { useEffect(() => {
console.log(info, 'info'); console.log(info, 'info');
console.log(infoAll, 'infoalll'); console.log(infoAll, 'infoalll');
setCodeParmar(infoAll.codeParam ? JSON.parse(infoAll.codeParam) : []);
setCurrentMenu({});
form.resetFields(); form.resetFields();
otherForm.resetFields(); otherForm.resetFields();
setPlainOptions(info); setPlainOptions(info);
...@@ -62,7 +83,7 @@ const EditForm = props => { ...@@ -62,7 +83,7 @@ const EditForm = props => {
arr.map(i => { arr.map(i => {
obj[i] = infoAll[i]; obj[i] = infoAll[i];
}); });
console.log(obj);
setVisibleChecked(infoAll.hideInMenu); setVisibleChecked(infoAll.hideInMenu);
targetForm.setFieldsValue({ ...obj, shortName: infoAll.menuShortName }); targetForm.setFieldsValue({ ...obj, shortName: infoAll.menuShortName });
if (info.length > 0) { if (info.length > 0) {
...@@ -111,7 +132,7 @@ const EditForm = props => { ...@@ -111,7 +132,7 @@ const EditForm = props => {
const submit = () => { const submit = () => {
const targetForm = nodeType === 1 ? form : otherForm; const targetForm = nodeType === 1 ? form : otherForm;
let obj = targetForm.getFieldsValue(); let obj = targetForm.getFieldsValue();
console.log(plainOptions);
let data = []; let data = [];
if (nodeType == 1) { if (nodeType == 1) {
plainOptions.map(item => { plainOptions.map(item => {
...@@ -124,27 +145,32 @@ const EditForm = props => { ...@@ -124,27 +145,32 @@ const EditForm = props => {
} else { } else {
obj.relatedRoleList = ''; obj.relatedRoleList = '';
} }
console.log(productList, 'productlIST');
let arr = obj.pageUrl.split('/'); // 用const声明常量 let arr = obj.pageUrl.split('/'); // 用const声明常量
const product = productList.find(item => item.PackageName.includes(arr[0])); const product = allProductList.find(item => item.PackageName.includes(arr[0]));
if (product) { if (product) {
arr.shift(); arr.shift();
obj.pageUrl = arr.join('/'); obj.pageUrl = arr.join('/');
} }
console.log(product, 'product');
obj.product = product?.PackageName || 'civweb4'; obj.product = product?.PackageName || 'civweb4';
if (!productList.some(item => item.PackageName === obj.product)) {
message.error(`${obj.product}未授权,不能使用该功能`);
return;
}
} }
console.log(obj, 'fadas'); obj.codeParam = JSON.stringify(curretnMenu.param);
obj.code = curretnMenu.code;
submitCallback(obj); submitCallback(obj);
}; };
const onFinish = val => { const onFinish = () => {
submit(); submit();
}; };
// 添加功能路劲参数 // 添加功能路劲参数
const addParama = () => { const addParama = () => {
console.log(form.getFieldValue('pageUrl'));
if (!form.getFieldValue('pageUrl')) { if (!form.getFieldValue('pageUrl')) {
notification.error({ message: '提示', duration: 3, description: '请先填写功能路径' }); notification.error({ message: '提示', duration: 3, description: '请先填写功能路径' });
return; return;
...@@ -288,10 +314,29 @@ const EditForm = props => { ...@@ -288,10 +314,29 @@ const EditForm = props => {
}; };
const change = e => { const change = e => {
console.log(e);
setVisibleChecked(e); setVisibleChecked(e);
}; };
const menuChange = val => {
if (!val) {
return;
}
setCodeParmar([]);
// form.resetFields();
console.log(form, 'form');
form.setFieldsValue({
menuName: val?.function,
shortName: val?.shortName,
imageUrl: val?.icon,
config: val?.configName,
pageUrl: val?.pageUrl,
});
setCurrentMenu(val);
setMenuParmar(val?.param);
};
console.log(curretnMenu?.param, 'curretnMenu.param');
return ( return (
<div style={{ marginTop: '10px' }}> <div style={{ marginTop: '10px' }}>
{nodeType === 1 && ( {nodeType === 1 && (
...@@ -363,7 +408,16 @@ const EditForm = props => { ...@@ -363,7 +408,16 @@ const EditForm = props => {
> >
<div style={{ display: 'flex' }}> <div style={{ display: 'flex' }}>
<Item name="pageUrl" style={{ marginBottom: 0, width: '100%' }}> <Item name="pageUrl" style={{ marginBottom: 0, width: '100%' }}>
<Input placeholder="请输入功能路径" style={{ width: '100%' }} /> <TreeSelect
ref={treeSelectRef}
menuChange={val => menuChange(val)}
code={infoAll?.code}
codeParam={infoAll?.codeParam}
initCurrentMenu={value => {
setCurrentMenu(value);
setMenuParmar(value.param);
}}
/>
</Item> </Item>
<Button onClick={addParama}>参数管理</Button> <Button onClick={addParama}>参数管理</Button>
</div> </div>
...@@ -511,7 +565,7 @@ const EditForm = props => { ...@@ -511,7 +565,7 @@ const EditForm = props => {
</Item> </Item>
</Form> </Form>
)} )}
<ParmarModal {/* <ParmarModal
pageUrl={form.getFieldValue('pageUrl')} pageUrl={form.getFieldValue('pageUrl')}
handleCancel={() => setShowParmarModal(false)} handleCancel={() => setShowParmarModal(false)}
visible={showParmarModal} visible={showParmarModal}
...@@ -519,6 +573,19 @@ const EditForm = props => { ...@@ -519,6 +573,19 @@ const EditForm = props => {
form.setFieldsValue({ pageUrl: url }); form.setFieldsValue({ pageUrl: url });
setShowParmarModal(false); setShowParmarModal(false);
}} }}
/> */}
<ParmarsModal
menuParmar={menuParmar}
codeParam={codeParmar}
pageUrl={form.getFieldValue('pageUrl')}
handleCancel={() => setShowParmarModal(false)}
visible={showParmarModal}
parmarCallBack={(url, params) => {
form.setFieldsValue({ pageUrl: url });
setCurrentMenu({ ...curretnMenu, param: params });
setCodeParmar(params);
setShowParmarModal(false);
}}
/> />
</div> </div>
); );
......
...@@ -30,7 +30,16 @@ import { ...@@ -30,7 +30,16 @@ import {
} from '@/services/webConfig/api'; } from '@/services/webConfig/api';
const MiniMenu = props => { const MiniMenu = props => {
const { menu, configFiles, subSystemValue, updateMenuTree, userMode, webid, productList } = props; const {
menu,
configFiles,
subSystemValue,
updateMenuTree,
userMode,
webid,
productList,
allProductList,
} = props;
const [flag, setFlag] = useState(1); // 刷新标志 const [flag, setFlag] = useState(1); // 刷新标志
const [loading, setLoading] = useState(false); // 加载 const [loading, setLoading] = useState(false); // 加载
const [menuID, setMenuID] = useState(''); // 选中的树ID const [menuID, setMenuID] = useState(''); // 选中的树ID
...@@ -655,6 +664,7 @@ const MiniMenu = props => { ...@@ -655,6 +664,7 @@ const MiniMenu = props => {
submitCallback={submitCallback} submitCallback={submitCallback}
submitLoading={submitLoading} submitLoading={submitLoading}
productList={productList} productList={productList}
allProductList={allProductList}
/> />
</Modal> </Modal>
<Modal <Modal
...@@ -675,6 +685,7 @@ const MiniMenu = props => { ...@@ -675,6 +685,7 @@ const MiniMenu = props => {
nodeObj={nodeObj} nodeObj={nodeObj}
configFiles={configFiles} configFiles={configFiles}
addType={addType} addType={addType}
allProductList={allProductList}
productList={productList} productList={productList}
submitCallback={submitCallback} submitCallback={submitCallback}
/> />
...@@ -717,6 +728,7 @@ const MiniMenu = props => { ...@@ -717,6 +728,7 @@ const MiniMenu = props => {
checkList={checkList} checkList={checkList}
configFiles={configFiles} configFiles={configFiles}
productList={productList} productList={productList}
allProductList={allProductList}
submitCallback={editSubmitCallback} submitCallback={editSubmitCallback}
valueCallback={valueCallback} valueCallback={valueCallback}
/> />
......
...@@ -333,5 +333,7 @@ export const QueryBaseMapItems = param => get(`${PANDA_GIS}/MapLayer/QueryBaseMa ...@@ -333,5 +333,7 @@ export const QueryBaseMapItems = param => get(`${PANDA_GIS}/MapLayer/QueryBaseMa
// 通过client获取角色 // 通过client获取角色
export const GetRoleGroups = param => get(`${PUBLISH_SERVICE}/UserCenter/GetRoleGroups`, param); export const GetRoleGroups = param => get(`${PUBLISH_SERVICE}/UserCenter/GetRoleGroups`, param);
// 获取菜单树
export const GetWebMenuInfo = param => get(`${PUBLISH_SERVICE}/WebSite/GetWebMenuInfo`, param);
export const SortScheme = param => get(`${PANDA_GIS}/MapLayer/SortScheme`, param); export const SortScheme = param => get(`${PANDA_GIS}/MapLayer/SortScheme`, param);
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