Commit 83ce8ea8 by 和金晶

添加我的资产模块

parent 19e3afba
...@@ -16,6 +16,7 @@ const Home = loadable(()=> import('./view/Home')); ...@@ -16,6 +16,7 @@ const Home = loadable(()=> import('./view/Home'));
const Manage = loadable(()=> import('./view/Manage')); const Manage = loadable(()=> import('./view/Manage'));
const Model = loadable(()=> import('./view/Manage/Model')); const Model = loadable(()=> import('./view/Manage/Model'));
const AssetManage = loadable(()=> import('./view/Manage/AssetManage')); const AssetManage = loadable(()=> import('./view/Manage/AssetManage'));
const MyAsset = loadable(()=> import('./view/Manage/MyAsset'));
const AssetResourceBrowse = loadable(()=> import('./view/Manage/AssetResourceBrowse')); const AssetResourceBrowse = loadable(()=> import('./view/Manage/AssetResourceBrowse'));
const AssetBrowse = loadable(()=> import('./view/Manage/AssetBrowse')); const AssetBrowse = loadable(()=> import('./view/Manage/AssetBrowse'));
const AssetRecycle = loadable(()=> import('./view/Manage/AssetRecycle')); const AssetRecycle = loadable(()=> import('./view/Manage/AssetRecycle'));
...@@ -178,7 +179,8 @@ export class App extends React.Component { ...@@ -178,7 +179,8 @@ export class App extends React.Component {
<Route path={'/center-home/menu/asset-manage'} component={AssetManage} exact /> <Route path={'/center-home/menu/asset-manage'} component={AssetManage} exact />
<Route path={'/center-home/menu/asset-resource-browse'} component={AssetResourceBrowse} exact /> <Route path={'/center-home/menu/asset-resource-browse'} component={AssetResourceBrowse} exact />
<Route path={'/center-home/menu/asset-browse'} component={AssetBrowse} exact /> <Route path={'/center-home/menu/asset-browse'} component={AssetBrowse} exact />
<Route path={'/center-home/menu/asset-recycle'} component={AssetRecycle} exact /> <Route path={'/center-home/menu/asset-recycle'} component={AssetRecycle} exact />
<Route path={'/center-home/menu/my-asset'} component={MyAsset} exact />
<Route path={'/center-home/menu/msd-define'} component={DataMasterDefine} exact /> <Route path={'/center-home/menu/msd-define'} component={DataMasterDefine} exact />
<Route path={'/center-home/menu/msd-manage'} component={DataMasterManage} exact /> <Route path={'/center-home/menu/msd-manage'} component={DataMasterManage} exact />
<Route path={'/center-home/asset-detail'} component={AssetDetailPage} exact /> <Route path={'/center-home/asset-detail'} component={AssetDetailPage} exact />
......
...@@ -80,6 +80,9 @@ export function* listDataAssetsByPersonalCustomType(payload) { ...@@ -80,6 +80,9 @@ export function* listDataAssetsByPersonalCustomType(payload) {
export function* listRecycleBinDataAssetsByPage(payload) { export function* listRecycleBinDataAssetsByPage(payload) {
return yield call(service.listRecycleBinDataAssetsByPage, payload); return yield call(service.listRecycleBinDataAssetsByPage, payload);
} }
export function* getSubscriptionAssetByPage(payload) {
return yield call(service.getSubscriptionAssetByPage, payload);
}
export function* addOrUpdateDirectory(payload) { export function* addOrUpdateDirectory(payload) {
return yield call(service.addOrUpdateDirectory, payload); return yield call(service.addOrUpdateDirectory, payload);
} }
......
...@@ -20,6 +20,10 @@ export const routes = [ ...@@ -20,6 +20,10 @@ export const routes = [
text: '资产管理', text: '资产管理',
}, },
{ {
name: 'my-asset',
text: '我的资产',
},
{
name: 'asset-resource-browse', name: 'asset-resource-browse',
text: '资源浏览', text: '资源浏览',
}, },
......
...@@ -75,6 +75,9 @@ export function listDataAssetsByPersonalCustomType(payload) { ...@@ -75,6 +75,9 @@ export function listDataAssetsByPersonalCustomType(payload) {
export function listRecycleBinDataAssetsByPage(payload) { export function listRecycleBinDataAssetsByPage(payload) {
return GetJSON("/dataassetmanager/dataAssetApi/listRecycleBinDataAssetsByPage", payload); return GetJSON("/dataassetmanager/dataAssetApi/listRecycleBinDataAssetsByPage", payload);
} }
export function getSubscriptionAssetByPage(payload) {
return GetJSON("/dataassetmanager/dataAssetApi/getSubscriptionAssetByPage", payload);
}
export function loadDataAssets(payload) { export function loadDataAssets(payload) {
return PostJSON("/dataassetmanager/dataAssetApi/loadDataAssets", payload); return PostJSON("/dataassetmanager/dataAssetApi/loadDataAssets", payload);
......
...@@ -27,4 +27,5 @@ export const AssetManageReference = 'asset-manage'; ...@@ -27,4 +27,5 @@ export const AssetManageReference = 'asset-manage';
export const AssetBrowseReference = 'asset-browse'; export const AssetBrowseReference = 'asset-browse';
export const ResourceBrowseReference = 'resource-browse'; export const ResourceBrowseReference = 'resource-browse';
export const AssetRecycleReference = 'asset-recycle'; export const AssetRecycleReference = 'asset-recycle';
export const AssetMountReference = 'asset-mount'; export const AssetMountReference = 'asset-mount';
\ No newline at end of file export const MyAssetReference = 'my-asset';
\ No newline at end of file
...@@ -7,13 +7,14 @@ import { useContextMenu, Menu as RcMenu, Item as RcItem } from "react-contexify" ...@@ -7,13 +7,14 @@ import { useContextMenu, Menu as RcMenu, Item as RcItem } from "react-contexify"
import LocalStorage from 'local-storage'; import LocalStorage from 'local-storage';
import FilterElementModal from './FilterElementModal'; import FilterElementModal from './FilterElementModal';
import MyApplyModal from './MyApplyModal';
import AssetMount from '../../AssetRecycle/Component/AssetMount'; import AssetMount from '../../AssetRecycle/Component/AssetMount';
import ImportAssetDrawer from './ImportAssetDrawer'; import ImportAssetDrawer from './ImportAssetDrawer';
import AssetEdit from './AddAssetModel'; import AssetEdit from './AddAssetModel';
import AssetDetailDrawer from "./AssetDetailDrawer"; import AssetDetailDrawer from "./AssetDetailDrawer";
import { dispatch, dispatchLatestHomepage } from '../../../../model'; import { dispatch, dispatchLatestHomepage } from '../../../../model';
import { showMessage, showNotifaction, getQueryParam, inputWidth, isSzseEnv } from '../../../../util'; import { showMessage, showNotifaction, getQueryParam, inputWidth, isSzseEnv } from '../../../../util';
import { AnchorId, AnchorDirId, AnchorTimestamp, AssetBrowseReference, AssetManageReference, AssetRecycleReference, ResourceBrowseReference } from '../../../../util/constant'; import { AnchorId, AnchorDirId, AnchorTimestamp, AssetBrowseReference, AssetManageReference, AssetRecycleReference, ResourceBrowseReference, MyAssetReference } from '../../../../util/constant';
import { FullScreenSvg, CancelFullScreenSvg } from './AssetSvg'; import { FullScreenSvg, CancelFullScreenSvg } from './AssetSvg';
import AssetDeleteModal from './AssetDeleteModal'; import AssetDeleteModal from './AssetDeleteModal';
import WorksheetModal from "./WorksheetModal"; import WorksheetModal from "./WorksheetModal";
...@@ -23,6 +24,7 @@ import "./AssetTable.less"; ...@@ -23,6 +24,7 @@ import "./AssetTable.less";
import 'react-contexify/dist/ReactContexify.css'; import 'react-contexify/dist/ReactContexify.css';
import { AppContext } from "../../../../App"; import { AppContext } from "../../../../App";
const { Text } = Typography; const { Text } = Typography;
const { Search } = Input; const { Search } = Input;
const { Column } = Table; const { Column } = Table;
...@@ -138,6 +140,7 @@ const AssetTable = (props) => { ...@@ -138,6 +140,7 @@ const AssetTable = (props) => {
const [ checkedItems, setCheckedItems ] = useState([]); const [ checkedItems, setCheckedItems ] = useState([]);
const [ importAssetVisible, setImportAssetVisible ] = useState(false); const [ importAssetVisible, setImportAssetVisible ] = useState(false);
const [ filterElementVisible, setFilterElementVisible ] = useState(false); const [ filterElementVisible, setFilterElementVisible ] = useState(false);
const [ myApplyVisible, setMyApplyVisible ] = useState(false);
const [ assetEditVisible, setAssetEditVisible ] = useState(false); const [ assetEditVisible, setAssetEditVisible ] = useState(false);
const [ assetMountVisible, setAssetMountVisible ] = useState(false); const [ assetMountVisible, setAssetMountVisible ] = useState(false);
const [ assetDetailDrawerVisible, setAssetDetailDrawerVisible ] = useState(false); const [ assetDetailDrawerVisible, setAssetDetailDrawerVisible ] = useState(false);
...@@ -226,7 +229,7 @@ const AssetTable = (props) => { ...@@ -226,7 +229,7 @@ const AssetTable = (props) => {
}, [timestamp]) }, [timestamp])
useEffect(() => { useEffect(() => {
if ((nodeId||'') !== '' || reference===AssetRecycleReference) { if ((nodeId||'') !== '' || reference===AssetRecycleReference || reference===MyAssetReference) {
getFilterElementsGroupThenGetDataAssets(); getFilterElementsGroupThenGetDataAssets();
} }
//eslint-disable-next-line react-hooks/exhaustive-deps //eslint-disable-next-line react-hooks/exhaustive-deps
...@@ -416,6 +419,8 @@ const AssetTable = (props) => { ...@@ -416,6 +419,8 @@ const AssetTable = (props) => {
let url = 'assetmanage.listDataAssetsByPage'; let url = 'assetmanage.listDataAssetsByPage';
if (reference===AssetRecycleReference) { if (reference===AssetRecycleReference) {
url = 'assetmanage.listRecycleBinDataAssetsByPage'; url = 'assetmanage.listRecycleBinDataAssetsByPage';
} else if(reference===MyAssetReference){
url = 'assetmanage.getSubscriptionAssetByPage';
} else if ((reference===AssetBrowseReference|| reference===ResourceBrowseReference)) { } else if ((reference===AssetBrowseReference|| reference===ResourceBrowseReference)) {
params.checkPermission = true; params.checkPermission = true;
...@@ -549,6 +554,15 @@ const AssetTable = (props) => { ...@@ -549,6 +554,15 @@ const AssetTable = (props) => {
const onFilterElementClick = () => { const onFilterElementClick = () => {
setFilterElementVisible(true); setFilterElementVisible(true);
} }
const onMyApply = () => {
if ((checkedKeys||[]).length === 0) {
showMessage('warn', '请先选择一个资产');
} else if ((checkedKeys||[]).length > 1) {
showMessage('warn', '只能选择一个资产');
}else {
setMyApplyVisible(true);
}
}
const onRecursiveChange = (e) => { const onRecursiveChange = (e) => {
setRecursive(!e.target.checked); setRecursive(!e.target.checked);
...@@ -625,6 +639,9 @@ const AssetTable = (props) => { ...@@ -625,6 +639,9 @@ const AssetTable = (props) => {
setFilterElementVisible(false); setFilterElementVisible(false);
refresh && getFilterElementsGroupThenGetDataAssets(); refresh && getFilterElementsGroupThenGetDataAssets();
} }
const onMyApplyCancel = (refresh = false) => {
setMyApplyVisible(false);
}
const onAssetDetailDrawerCancel = () => { const onAssetDetailDrawerCancel = () => {
setAssetDetailDrawerVisible(false); setAssetDetailDrawerVisible(false);
...@@ -859,9 +876,9 @@ const AssetTable = (props) => { ...@@ -859,9 +876,9 @@ const AssetTable = (props) => {
可见列设置 可见列设置
</div> </div>
</Menu.Item> </Menu.Item>
{ {
reference===AssetManageReference && reportTypes?.map(item => (reference===AssetManageReference || reference===MyAssetReference) && reportTypes?.map(item =>
<React.Fragment key={item.code}> <React.Fragment key={item.code}>
<Menu.Item disabled={(checkedKeys||[]).length===0}> <Menu.Item disabled={(checkedKeys||[]).length===0}>
<div className='text-center' onClick={() => { onReportAnalyseClick(item) }}> <div className='text-center' onClick={() => { onReportAnalyseClick(item) }}>
...@@ -897,7 +914,7 @@ const AssetTable = (props) => { ...@@ -897,7 +914,7 @@ const AssetTable = (props) => {
scrollY = 'calc(100vh - 209px - 123px - 15px - 72px)'; scrollY = 'calc(100vh - 209px - 123px - 15px - 72px)';
} else if (reference===AssetBrowseReference ||reference===ResourceBrowseReference) { } else if (reference===AssetBrowseReference ||reference===ResourceBrowseReference) {
scrollY = 'calc(100vh - 209px - 94px - 15px - 72px)'; scrollY = 'calc(100vh - 209px - 94px - 15px - 72px)';
} else if (reference===AssetRecycleReference) { } else if (reference===AssetRecycleReference ||reference===MyAssetReference) {
scrollY = 'calc(100vh - 209px - 72px)'; scrollY = 'calc(100vh - 209px - 72px)';
} }
} }
...@@ -917,7 +934,7 @@ const AssetTable = (props) => { ...@@ -917,7 +934,7 @@ const AssetTable = (props) => {
(reference===AssetManageReference && nodeLevel!==1 && nodeType!=='custom') && <Button onClick={addAsset}>新增</Button> (reference===AssetManageReference && nodeLevel!==1 && nodeType!=='custom') && <Button onClick={addAsset}>新增</Button>
} }
{ {
(reference===AssetManageReference) ? <Dropdown overlay={moreMenu} placement="bottomCenter"> (reference===AssetManageReference || reference===MyAssetReference) ? <Dropdown overlay={moreMenu} placement="bottomCenter">
<Button>其他操作</Button> <Button>其他操作</Button>
</Dropdown> : <React.Fragment> </Dropdown> : <React.Fragment>
{ {
...@@ -945,6 +962,9 @@ const AssetTable = (props) => { ...@@ -945,6 +962,9 @@ const AssetTable = (props) => {
</React.Fragment> </React.Fragment>
} }
<Button onClick={onFilterElementClick}>可见列设置</Button> <Button onClick={onFilterElementClick}>可见列设置</Button>
{
(reference==AssetBrowseReference) && <Button onClick={onMyApply}>资产订阅</Button>
}
</React.Fragment> </React.Fragment>
} }
{ {
...@@ -953,15 +973,17 @@ const AssetTable = (props) => { ...@@ -953,15 +973,17 @@ const AssetTable = (props) => {
</Space> </Space>
<Space> <Space>
{ {
(reference!==AssetRecycleReference) && <Checkbox onChange={onFullSearchChange} checked={fullSearch}>全部数据</Checkbox> (reference!==AssetRecycleReference && reference!==MyAssetReference) && <Checkbox onChange={onFullSearchChange} checked={fullSearch}>全部数据</Checkbox>
} }
<Search {
(reference!==MyAssetReference) &&<Search
placeholder="请输入资产要素值" placeholder="请输入资产要素值"
allowClear allowClear
onSearch={onSearchInputChange} onSearch={onSearchInputChange}
enterButton enterButton
style={{ width: inputWidth }} style={{ width: inputWidth }}
/> />
}
{ {
(reference!==AssetRecycleReference) && <Tooltip title={fullScreen?'取消全屏':'全屏'}> (reference!==AssetRecycleReference) && <Tooltip title={fullScreen?'取消全屏':'全屏'}>
<Button onClick={onFullScreenClick} icon={fullScreen?<CancelFullScreenSvg style={{ width: 20, height: 20 }} />:<FullScreenSvg style={{ width: 20, height: 20 }} />} type='text'></Button> <Button onClick={onFullScreenClick} icon={fullScreen?<CancelFullScreenSvg style={{ width: 20, height: 20 }} />:<FullScreenSvg style={{ width: 20, height: 20 }} />} type='text'></Button>
...@@ -1073,6 +1095,12 @@ const AssetTable = (props) => { ...@@ -1073,6 +1095,12 @@ const AssetTable = (props) => {
visible={ filterElementVisible } visible={ filterElementVisible }
onCancel={ onFilterElementModalCancel} onCancel={ onFilterElementModalCancel}
/> />
<MyApplyModal
selectItem = {selectItem}
visible={ myApplyVisible }
id={ (checkedKeys||[]).length>0?checkedKeys[0]:'' }
onCancel={ onMyApplyCancel}
/>
<AssetDetailDrawer <AssetDetailDrawer
id={selectItem?.id} id={selectItem?.id}
dirId={selectItem?.dirId} dirId={selectItem?.dirId}
......
import React, { useEffect, useState,useMemo } from 'react';
import { Row, Col, Checkbox, Typography, Button, Switch, Modal,Form, Input, InputNumber,Select,DatePicker } from 'antd';
import { dispatch } from '../../../../model';
import './FilterElementModal.less';
import moment from "moment"
const {Option} = Select
//type
//global 全局设置
//admin 管理员
//user 普通用户id
const MyApplyModal = (props) => {
const { visible, onCancel, type = 'global',id,selectItem } = props;
console.log(id);
console.log(selectItem);
const [ elements, setElements ] = useState([]);
const [ typesOfElements, setTypesOfElements ] = useState([]);
const [ selectedKeys, setSelectedKeys ] = useState([]);
const [ confirmLoading, setConfirmLoading ] = useState(false);
const [form] = Form.useForm()
useEffect(() => {
if (visible) {
getAllFilterElementIdsThenGetAllElements();
}
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [visible]);
const getAllFilterElementIdsThenGetAllElements = () => {
let url = '';
if (type === 'global') {
url = 'assetmanage.listFilterElementIdsConfig';
} else {
url = 'assetmanage.listFilterElementIds';
}
dispatch({
type: url,
callback: data => {
setSelectedKeys(data||[]);
getAllElements();
}
})
}
const getAllElements = () => {
let url = '';
if (type === 'user') {
url = 'assetmanage.listUserElements';
} else {
url = 'assetmanage.listElements';
}
dispatch({
type: url,
callback: data => {
setElements(data||[]);
convertElements(data||[]);
}
})
}
const convertElements = (elements) => {
const _typesOfElements = [];
const _types = [];
(elements||[]).forEach(element => {
if (_types.indexOf(element.type||'') === -1) {
_types.push(element.type||'');
}
})
_types.forEach(type => {
const _elements = (elements||[]).filter(element => (element.type||'') === type);
_typesOfElements.push({ type, elements: _elements||[] });
})
setTypesOfElements(_typesOfElements);
}
const onCheckChange = (e) => {
if (e.target.checked) {
setSelectedKeys([...selectedKeys, e.target.value]);
} else {
const index = selectedKeys.findIndex(key => key === e.target.value);
selectedKeys.splice(index, 1)
setSelectedKeys([...selectedKeys]);
}
}
const onCheckAllChange = (checked) => {
const _selectedKeys = [];
if (checked) {
(elements||[]).forEach(element => {
_selectedKeys.push(element.id||'');
});
} else {
(elements||[]).forEach(element => {
if (element.selectAble === '否') {
_selectedKeys.push(element.id||'');
}
});
}
setSelectedKeys(_selectedKeys);
}
const onOk = () => {
form.validateFields().then((values) => {
if (Object.keys(values).length > 0) {
// 表单通过校验,做相应操作
console.log('表单数据通过校验', values);
}
}).catch((errorInfo) => {
console.log('校验错误', errorInfo);
});
// setConfirmLoading(true);
// let url = '';
// if (type === 'global') {
// url = 'assetmanage.setupFilterElementIdsConfig';
// } else {
// url = 'assetmanage.setupFilterElementIds';
// }
// dispatch({
// type: url,
// payload: {
// data: selectedKeys
// },
// callback: () => {
// reset();
// onCancel && onCancel(true);
// },
// error: () => {
// reset();
// }
// })
}
const cancel = () => {
reset();
onCancel && onCancel();
}
const reset = () => {
setConfirmLoading(false);
form.resetFields()
}
const layout = {
labelCol: {
span: 6,
},
wrapperCol: {
span: 16,
},
};
const onFinish = (values) => {
console.log(values);
};
const validateMessages = {
required: '${label} is required!',
types: {
email: '${label} is not a valid email!',
number: '${label} is not a valid number!',
},
number: {
range: '${label} must be between ${min} and ${max}',
},
};
const SelectTime=(props)=>{
const {value,onChange,disabledDate} = props
const changeData=(value)=>{
if(value==='long'){
let time = moment('2099-12-31','YYYY-MM-DD')
onChange(time)
}else{
onChange(null)
}
}
const type = useMemo(()=>{
if(value){
let time = value.format("YYYY-MM-DD")
if(time==='2099-12-31'){
return 'long'
}else{
return 'short'
}
}else{
return 'short'
}
},[value])
const changeDate=(time)=>{
onChange&&onChange(time)
}
return(
<div style={{width:'100%',display:'flex'}}>
<Select value={type} onChange={changeData} placeholder="期限类型" style={{width:120}}>
<Option value="short">选择有效期</Option>
<Option value="long">长期有效</Option>
</Select>
{type!=='long'&&<DatePicker value={value} disabledDate={disabledDate} onChange={changeDate} style={{marginLeft:8,width:'calc(100% - 128px)'}} />}
</div>
)
}
const disabledDate= (current) => {
// Can not select days before today and today
return current && current < moment().endOf('day');
};
return (
<Modal
forceRender
visible={visible}
title={'资产订阅申请'}
width={520}
onCancel={cancel}
footer={[
<Button
key="0"
onClick={cancel}
>
取消
</Button>,
<Button
key="1"
type="primary"
onClick={onOk}
loading={confirmLoading}
>
确定
</Button>,
]}
>
<div>
<Form {...layout} name="nest-messages" style={{maxWidth: 600, }} validateMessages={validateMessages} form={form}>
<Form.Item label={'有效时限'} name={'expiryDateEnd'} rules={[{ required: true,message:'必填项' }]}>
<SelectTime disabledDate={disabledDate} />
</Form.Item>
<Form.Item
name={'applyReason'}
label="申请说明"
>
<Input.TextArea />
</Form.Item>
</Form>
</div>
</Modal>
);
}
export default MyApplyModal;
\ No newline at end of file
import React from 'react';
import AssetTable from '../AssetManage/Component/AssetTable';
import { AssetRecycleReference,MyAssetReference } from '../../../util/constant';
const AssetRecycle = (props) => {
return (
<div style={{ backgroundColor: '#fff', height: '100%' }}>
<AssetTable reference={MyAssetReference} {...props} />
</div>
);
}
export default AssetRecycle;
\ No newline at end of file
...@@ -10,6 +10,7 @@ import AssetManage from './AssetManage'; ...@@ -10,6 +10,7 @@ import AssetManage from './AssetManage';
import AssetResourceBrowse from './AssetResourceBrowse'; import AssetResourceBrowse from './AssetResourceBrowse';
import AssetBrowse from './AssetBrowse'; import AssetBrowse from './AssetBrowse';
import AssetRecycle from './AssetRecycle'; import AssetRecycle from './AssetRecycle';
import MyAsset from './MyAsset';
import DataService from './Model'; import DataService from './Model';
import DataMasterDefine from "./DataMaster/Define"; import DataMasterDefine from "./DataMaster/Define";
import DataMasterManage from "./DataMaster/Manage"; import DataMasterManage from "./DataMaster/Manage";
...@@ -32,6 +33,7 @@ class Manage extends Component { ...@@ -32,6 +33,7 @@ class Manage extends Component {
<Route path={`${match.path}/asset-resource-browse`} component={AssetResourceBrowse} /> <Route path={`${match.path}/asset-resource-browse`} component={AssetResourceBrowse} />
<Route path={`${match.path}/asset-browse`} component={AssetBrowse} /> <Route path={`${match.path}/asset-browse`} component={AssetBrowse} />
<Route path={`${match.path}/asset-recycle`} component={AssetRecycle} /> <Route path={`${match.path}/asset-recycle`} component={AssetRecycle} />
<Route path={`${match.path}/my-asset`} component={MyAsset} />
<Route path={`${match.path}/data-service`} component={DataService} /> <Route path={`${match.path}/data-service`} component={DataService} />
<Route path={`${match.path}/msd-define`} component={DataMasterDefine} /> <Route path={`${match.path}/msd-define`} component={DataMasterDefine} />
<Route path={`${match.path}/msd-manage`} component={DataMasterManage} /> <Route path={`${match.path}/msd-manage`} component={DataMasterManage} />
......
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