Commit 8ccf0cd3 authored by GuanHua's avatar GuanHua
parents 8f4e2230 5aaed176
......@@ -53,6 +53,17 @@ const config: any = {
inlineLimit: 10000,
chunks: isProduction && ['vendors', 'umi'],
chainWebpack: function (config, { webpack }) {
config.module
.rule('svg')
.exclude.add(/pages/).end(); // 给内置的添加 exclude,这里根据自己的情况处理
config.module
.rule('svgr')
.test(/.svg$/)
.include.add(/pages/).end() // include 指定需要直接 svgr 的情况
.use('@svgr/webpack')
.loader(require.resolve('@svgr/webpack'));
isProduction && config.merge({
optimization: {
minimize: true,
......
<?xml version="1.0" encoding="UTF-8"?>
<svg width="56px" height="56px" viewBox="0 0 56 56" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title></title>
<defs>
<circle id="path-1" cx="28" cy="28" r="28"></circle>
</defs>
<g id="我" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g>
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="Mask" fill="#E6E7EB" xlink:href="#path-1"></use>
<path d="M33.6555679,41.9707886 C33.6555679,39.4830014 35.5358268,40.29543 36.3612399,35.7393901 C36.7035576,33.8493771 38.3642448,35.7089168 38.6821448,31.3941714 C38.6821448,29.6745403 37.7757776,29.2472439 37.7757776,29.2472439 C37.7757776,29.2472439 38.2364274,26.702535 38.4170246,24.7441009 C38.640259,22.3042277 37.0383622,16 28.4925336,16 C19.9463292,16 18.3434933,22.3042277 18.5680425,24.7441009 C18.7482641,26.702535 19.2089139,29.2472439 19.2089139,29.2472439 C19.2089139,29.2472439 18.3025467,29.6745403 18.3025467,31.3941714 C18.6196954,35.7089168 20.2801947,33.8493771 20.6227003,35.7393901 C21.4491464,40.2953342 23.3279966,39.4830014 23.3279966,41.9707886 C23.3279966,46.1150562 21.3612426,48.0505874 15.2037493,50.3452814 C9.02681572,52.6468751 4,55.4864395 4,57.0869565 L4,61 L52.9999992,61 C52.9999992,61 53,58.6864194 53,57.0869565 C53,55.4864395 47.9580635,52.6468751 41.78113,50.3452814 C35.6234488,48.0505874 33.6555679,46.1150562 33.6555679,41.9707886 Z" fill="#FAFAFA" mask="url(#mask-2)"></path>
</g>
</g>
</svg>
\ No newline at end of file
......@@ -6,6 +6,8 @@ import PersonDropdown from './PersonDropdown'
import styles from '../styles/RightContent.less';
import { removeAuth, removeRouters, getAuth } from '@/utils/auth';
import { inject, observer } from 'mobx-react'
import Icon from '@ant-design/icons';
import { ReactComponent as DefaultAvatar } from '@/assets/imgs/default_avatar.svg';
const AvatarDropdown = (props) => {
......@@ -44,7 +46,12 @@ const AvatarDropdown = (props) => {
return (
<PersonDropdown overlay={menuHeaderDropdown}>
<span className={`${styles.action} ${styles.account}`}>
<Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
{
currentUser.avatar
? <Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
: <Icon component={() => <DefaultAvatar className={styles.logo} />} />
}
<span className={styles.name}>{currentUser.name}</span>
</span>
</PersonDropdown>
......
import React from 'react'
import { Layout, Menu, Avatar, Image } from 'antd'
import { AppstoreOutlined } from '@ant-design/icons'
import { Link } from 'umi'
import styles from '../styles/MenuSlider.less'
import { getRouters } from '@/utils/auth'
import { isDev } from '@/constants'
import {observer, inject} from 'mobx-react';
import CustomIcon from './CustomIcon'
import CustomIcon from './CustomIcon';
import Icon from '@ant-design/icons';
import { ReactComponent as DefaultAvatar } from '@/assets/imgs/default_avatar.svg';
const { Sider } = Layout
export interface OuterSiderProps {
......@@ -46,13 +47,13 @@ const OuterSider: React.FC<OuterSiderProps> = observer((props) => {
const siderMenu = getSubMenu()
return <>
<Sider collapsed={true} collapsedWidth={64} className={styles.wrapperSilder}>
{
props.UserStore.avatar
? <div className={styles.userPic}>
<img src={props.UserStore.avatar} className={styles.avatar} />
</div>
: <div className={styles.userPic} />
}
<div className={styles.userPic}>
{
props.UserStore.avatar
? <img src={props.UserStore.avatar} className={styles.avatar} />
: <Icon component={() => <DefaultAvatar className={styles.logo} />} />
}
</div>
<ul className={styles.menuBox}>
{
siderMenu.map(item => (
......
......@@ -53,6 +53,11 @@
width: 32px;
height: 32px;
}
.logo {
width: 32px;
height: 32px;
}
}
.wrapperSilder {
......
......@@ -58,6 +58,11 @@
vertical-align: top;
background: rgba(255, 255, 255, 0.85);
}
.logo {
width: 24px;
height: 24px;
margin-right: 8px;
}
}
}
......@@ -120,4 +125,4 @@
display: none;
}
}
}
\ No newline at end of file
}
......@@ -133,7 +133,13 @@ export const addSchema = {
prefix: "{{tableAddButton}}",
columns: "{{tableColumns}}"
// columns: "{{tableColumns}}",
}
},
'x-rules': [
{
required: true,
message: '请选择使用会员'
}
]
}
}
}
......
......@@ -13,6 +13,10 @@ import home_user from '@/assets/imgs/home_user.png';
import { UPLOAD_TYPE } from '@/constants'
import { PublicApi } from '@/services/api';
import {observer, inject} from 'mobx-react';
// import Icon from '@ant-design/icons';
import Icon from '@ant-design/icons';
import { ReactComponent as DefaultAvatar } from '@/assets/imgs/default_avatar.svg';
interface Iprops {}
const WEEKDAYS = ["天", "一","二", "三", "四", "五","六"];
......@@ -102,7 +106,7 @@ const UserCenter: React.FC<Iprops> = (props) => {
{
state.logo
? <img src={state.logo || ''} className={styles.logo}/>
: <span className={styles.text}>H</span>
: <Icon component={() => <DefaultAvatar className={styles.logo} />} />
}
<span className={styles.upload}>修改</span>
</Upload>
......
......@@ -100,15 +100,6 @@ const DetailInfo: React.FC<DetailInfoProps> = ({
setSubmitLoading(true);
const { fileList, ...rest } = quotaValues;
console.log({
applyId: +id,
creditId: creditId ? +creditId : 0,
fileList: fileList.map((item: any) => ({ name: item.name, fileUrl: item.data.url })),
...rest,
})
return;
PublicApi.postPayCreditApplyAddCreditApply({
applyId: +id,
creditId: creditId ? +creditId : 0,
......
......@@ -14,21 +14,19 @@ import {
import { createFormActions, FormEffectHooks } from '@formily/antd';
import lodash from 'lodash';
import { PublicApi } from '@/services/api';
import { PAY_CHANNEL_WECHAT } from '@/constants';
import MellowCard from '@/components/MellowCard';
import { Pie } from '@/components/Charts';
import StatusTag from '@/components/StatusTag';
import NiceForm from '@/components/NiceForm';
import { repaymentModalSchema, uploadVoucherModalSchema } from './schema';
import { createEffects } from './effects/repayment';
import { uploadVoucherModalSchema } from './schema';
import TradeRecord, { RecordParams, RecordRes } from '../TradeRecord';
import WxPayModal from '../WxPayModal';
import RefundModal from '../RefundModal';
import styles from './index.less';
const repaymentFormActions = createFormActions();
const uploadVoucherFormActions = createFormActions();
const { onFormInit$ } = FormEffectHooks;
const { Option } = Select;
export interface BillDetailParams {
......@@ -259,7 +257,7 @@ class IntroduceRow extends React.Component<IntroduceRowProps, IntroduceRowState>
switch (tradeChannel) {
// 微信支付
case 1: {
case PAY_CHANNEL_WECHAT: {
this.setState({
wxPayPrice: values.repayQuota,
wxPayUrl: res.data.payQRCode,
......@@ -319,7 +317,6 @@ class IntroduceRow extends React.Component<IntroduceRowProps, IntroduceRowState>
};
beforeUploadVoucher = file => {
console.log(file.size)
if (file.size / 1024 > 200) {
message.warning('图片大小超过200K');
return Promise.reject();
......@@ -565,57 +562,14 @@ class IntroduceRow extends React.Component<IntroduceRowProps, IntroduceRowState>
</MellowCard>
</Col>
</Row>
<Modal
title="还款"
width={576}
<RefundModal
visible={visibleRepayment}
confirmLoading={repaymentSubmitLoading}
onOk={() => repaymentFormActions.submit()}
billInfo={billInfo}
onCancel={() => this.setState({ visibleRepayment: false })}
destroyOnClose
>
<NiceForm
previewPlaceholder=""
effects={($, actions) => {
const { setFieldState, setFieldValue } = actions;
onFormInit$().subscribe(() => {
// 初始化数据
setFieldState('repayQuota', fileState => {
fileState.value = billInfo.residueRepayQuota;
fileState.rules = fileState.rules.concat({
validator(value) {
return +value > billInfo.residueRepayQuota ? '输入值已超出还款金额' : '';
}
});
});
setFieldState('amountSlide', fileState => {
fileState.value = billInfo.residueRepayQuota;
fileState.props['x-component-props'].max = billInfo.residueRepayQuota;
fileState.props['x-component-props'].marks = {
0: {
label: 0,
},
[billInfo.residueRepayQuota]: {
label: billInfo.residueRepayQuota,
},
};
});
});
createEffects($, actions);
}}
expressionScope={{
}}
actions={repaymentFormActions}
schema={repaymentModalSchema}
onSubmit={this.handleRepaymentSubmit}
/>
</Modal>
onSubmit={this.handleRepaymentSubmit}
confirmLoading={repaymentSubmitLoading}
/>
<Modal
title="上传支付凭证"
......
import { ISchema } from '@formily/antd';
import { UPLOAD_TYPE } from '@/constants';
export const repaymentModalSchema: ISchema = {
type: 'object',
properties: {
MEGA_LAYOUT: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
labelAlign: 'top',
full: true,
},
properties: {
repayQuota: {
type: 'string',
title: '还款金额',
'x-component-props': {
placeholder: '',
addonBefore: '¥',
},
'x-rules': [
{
required: true,
message: '请填写还款金额',
},
],
},
amountSlide: {
type: 'number',
title: '',
'x-component': 'range',
'x-component-props': {
min: 0,
// max: 20000,
},
},
tradeType: {
type: 'number',
enum: [
{
label: '线上支付方式',
value: 1,
},
{
label: '线下支付方式',
value: 2,
},
],
default: 1,
title: '选择支付方式',
'x-component-props': {
placeholder: '请选择',
},
'x-rules': [
{
required: true,
message: '请选择支付方式',
},
],
},
tradeChannel: {
type: 'string',
title: '选择支付渠道',
enum: [
{
label: '微信',
value: 1,
},
{
label: '支付宝',
value: 2,
},
{
label: '银联',
value: 3,
},
],
default: 1,
'x-component-props': {
placeholder: '请选择',
},
'x-rules': [
{
required: true,
message: '请选择支付渠道',
},
],
},
},
},
},
};
export const uploadVoucherModalSchema: ISchema = {
type: 'object',
properties: {
......
/*
* @Author: XieZhiXiong
* @Date: 2020-10-22 17:31:08
* @LastEditors: XieZhiXiong
* @LastEditTime: 2020-11-24 10:40:03
* @Description: 联动逻辑相关
*/
import { FormEffectHooks, FormPath } from '@formily/antd';
import { useLinkageUtils } from '@/utils/formEffectUtils';
const {
onFieldInputChange$,
onFieldValueChange$,
} = FormEffectHooks;
export const useBusinessEffects = (context, actions) => {
const {
getFieldValue,
setFieldValue,
getFieldState,
setFieldState,
} = actions;
const linkage = useLinkageUtils();
// 还款金额 联动 滑块条
onFieldInputChange$('repayQuota').subscribe(fieldState => {
linkage.value('amountSlide', +fieldState.value);
});
// 滑块条 联动 还款金额
onFieldInputChange$('amountSlide').subscribe(fieldState => {
linkage.value('repayQuota', `${fieldState.value}`);
});
// 支付方式 联动 支付渠道
onFieldValueChange$('tradeType').subscribe(fieldState => {
const { value } = fieldState;
if (value === 2) {
linkage.hide('tradeChannel');
} else {
linkage.show('tradeChannel');
}
});
/*
* @Author: XieZhiXiong
* @Date: 2020-10-22 17:31:08
* @LastEditors: XieZhiXiong
* @LastEditTime: 2020-11-24 10:40:03
* @Description: 联动逻辑相关
*/
import { FormEffectHooks, FormPath } from '@formily/antd';
import { useLinkageUtils } from '@/utils/formEffectUtils';
const {
onFieldInputChange$,
onFieldValueChange$,
} = FormEffectHooks;
export const useBusinessEffects = (context, actions) => {
const {
getFieldValue,
setFieldValue,
getFieldState,
setFieldState,
} = actions;
const linkage = useLinkageUtils();
// 还款金额 联动 滑块条
onFieldInputChange$('repayQuota').subscribe(fieldState => {
linkage.value('amountSlide', +fieldState.value);
});
// 滑块条 联动 还款金额
onFieldInputChange$('amountSlide').subscribe(fieldState => {
linkage.value('repayQuota', `${fieldState.value}`);
});
// 支付方式 联动 支付渠道
onFieldValueChange$('tradeType').subscribe(fieldState => {
const { value } = fieldState;
if (value === 2) {
linkage.hide('tradeChannel');
} else {
linkage.show('tradeChannel');
}
});
}
\ No newline at end of file
import React from 'react';
import { Modal } from 'antd';
import { createFormActions, FormEffectHooks } from '@formily/antd';
import { PublicApi } from '@/services/api';
import NiceForm from '@/components/NiceForm';
import { BillDetailData } from '../IntroduceRow';
import { repaymentModalSchema } from './schema';
import { createEffects } from './effects';
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
const { onFormInit$ } = FormEffectHooks;
const repaymentFormActions = createFormActions();
interface RefundModalProps {
/**
* 是否可见
*/
visible: boolean,
/**
* 隐藏事件
*/
onCancel: () => void,
/**
* 确认按钮 loading
*/
confirmLoading?: boolean,
/**
* 账单信息
*/
billInfo: BillDetailData | null,
/**
* 提交事件
*/
onSubmit: (values: any) => void,
};
const RefundModal: React.FC<RefundModalProps> = (props) => {
const {
visible,
onCancel,
confirmLoading,
billInfo,
onSubmit,
} = props;
// 获取供应商支付渠道
const getPayChannels = (): Promise<any[]> => {
return new Promise((resolve, reject) => {
PublicApi.getPayCreditRepaymentList({
payType: `${1}`, // 支付方式:1 线上支付
memberId: `${billInfo.memberId}`,
memberRoleId: `${billInfo.memberRoleId}`,
}).then(res => {
if (res.code === 1000) {
const options =
res.data ?
res.data.map(item => ({
label: item.way,
value: item.wayId,
})) :
[];
resolve(options);
}
reject();
}).catch(() => {
reject();
});
});
};
const handleRepaymentSubmit = (values) => {
if (onSubmit) {
onSubmit(values);
}
};
return (
<Modal
title="还款"
width={576}
visible={visible}
confirmLoading={confirmLoading}
onOk={() => repaymentFormActions.submit()}
onCancel={onCancel}
destroyOnClose
>
<NiceForm
previewPlaceholder=""
effects={($, actions) => {
const { setFieldState, setFieldValue } = actions;
onFormInit$().subscribe(() => {
// 初始化数据
setFieldState('repayQuota', fileState => {
fileState.value = billInfo.residueRepayQuota;
fileState.rules = fileState.rules.concat({
validator(value) {
return +value > billInfo.residueRepayQuota ? '输入值已超出还款金额' : '';
}
});
});
setFieldState('amountSlide', fileState => {
fileState.value = billInfo.residueRepayQuota;
fileState.props['x-component-props'].max = billInfo.residueRepayQuota;
fileState.props['x-component-props'].marks = {
0: {
label: 0,
},
[billInfo.residueRepayQuota]: {
label: billInfo.residueRepayQuota,
},
};
});
});
createEffects($, actions);
console.log('123')
useAsyncSelect('tradeChannel', getPayChannels, ['label', 'value']);
}}
expressionScope={{
}}
actions={repaymentFormActions}
schema={repaymentModalSchema}
onSubmit={handleRepaymentSubmit}
/>
</Modal>
);
};
export default RefundModal;
\ No newline at end of file
/*
* @Author: XieZhiXiong
* @Date: 2020-12-30 14:49:11
* @LastEditors: XieZhiXiong
* @LastEditTime: 2020-12-30 14:56:41
* @Description:
*/
import { ISchema } from '@formily/antd';
import { UPLOAD_TYPE } from '@/constants';
export const repaymentModalSchema: ISchema = {
type: 'object',
properties: {
MEGA_LAYOUT: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
labelAlign: 'top',
full: true,
},
properties: {
repayQuota: {
type: 'string',
title: '还款金额',
'x-component-props': {
placeholder: '',
addonBefore: '¥',
},
'x-rules': [
{
required: true,
message: '请填写还款金额',
},
],
},
amountSlide: {
type: 'number',
title: '',
'x-component': 'range',
'x-component-props': {
min: 0,
// max: 20000,
},
},
tradeType: {
type: 'number',
enum: [
{
label: '线上支付方式',
value: 1,
},
{
label: '线下支付方式',
value: 2,
},
],
default: 1,
title: '选择支付方式',
'x-component-props': {
placeholder: '请选择',
},
'x-rules': [
{
required: true,
message: '请选择支付方式',
},
],
},
tradeChannel: {
type: 'string',
title: '选择支付渠道',
enum: [],
'x-component-props': {
placeholder: '请选择',
},
'x-rules': [
{
required: true,
message: '请选择支付渠道',
},
],
},
},
},
},
};
\ No newline at end of file
/*
* @Author: XieZhiXiong
* @Date: 2020-12-16 11:07:13
* @LastEditors: XieZhiXiong
* @LastEditTime: 2020-12-16 15:09:21
* @Description: 微信支付弹窗
*/
import React, { useState, useEffect, useRef } from 'react';
import { Modal, Upload } from 'antd';
import QRCode from 'qrcode';
import { priceFormat } from '@/utils/numberFomat';
import WechatIcon from '@/assets/imgs/wechat_icon.png';
import styles from './index.less';
interface WxPayModalProps {
/**
* 需要生成 二维码的 地址
*/
url: string;
/**
* 支付金额
*/
price: number;
/**
* 是否可见
*/
visible: boolean;
/**
* 弹窗取消事件
*/
onCancel: () => void;
/**
* 轮训查询支付结果事件
*/
onCheckResult: () => Promise<{ success: Boolean }>;
/**
* 轮训查询支付结果成功
*/
onSuccess?: () => void;
/**
* 轮训查询支付结果失败
*/
onFail?: () => void;
};
const WxPayModal: React.FC<WxPayModalProps> = ({
url,
price,
visible,
onCancel,
onCheckResult,
onSuccess,
onFail,
}) => {
const [qrCode, setQrCode] = useState<string>('');
const getQRCode = async params => {
if (!params) {
return;
}
// 生成二维码
const res = await QRCode.toDataURL(params);
setQrCode(res);
};
let timer = useRef(null);
// 最多请求3600次,2000毫秒一次,二维码过期两小时
let count = 0;
const handleCheckResult = () => {
if (!onCheckResult) {
return;
}
count++;
if (count > 3600) {
return;
}
onCheckResult().then(res => {
if (!res.success) {
timer.current = setTimeout(() => {
handleCheckResult();
}, 2000);
console.log('timer', timer)
} else {
clearTimeout(timer.current);
timer = null;
if (onSuccess) {
onSuccess();
}
}
});
};
useEffect(() => {
getQRCode(url);
if (url) {
handleCheckResult();
}
return () => {
if (timer.current) {
clearTimeout(timer.current);
timer.current = null;
}
};
}, [url]);
useEffect(() => {
if (!visible) {
console.log('隐藏咯')
console.log('timer', timer.current)
if (timer.current) {
clearTimeout(timer.current);
timer.current = null;
}
}
}, [visible]);
const handleCancel = () => {
if (onCancel) {
onCancel();
}
};
return (
<Modal
title={(
<div className={styles.common_title}>
<div className={styles.common_title_icon}><img src={WechatIcon} /></div>
<span>微信支付</span>
</div>
)}
width={576}
visible={visible}
onCancel={handleCancel}
footer={null}
maskClosable={false}
destroyOnClose
>
<div className={styles.wechat_payway}>
<p className={styles.wechat_payway_title}>使用微信扫一扫下方二维码</p>
<div className={styles.wechat_payway_imgbox}>
{qrCode && <img src={qrCode} />}
</div>
<div className={styles.wechat_payway_needpay}>
<label>当前需支付:</label>
<span>{priceFormat(price)}</span>
<label>RMB</label>
</div>
</div>
</Modal>
);
};
/*
* @Author: XieZhiXiong
* @Date: 2020-12-16 11:07:13
* @LastEditors: XieZhiXiong
* @LastEditTime: 2020-12-30 13:50:05
* @Description: 微信支付弹窗
*/
import React, { useState, useEffect, useRef } from 'react';
import { Modal, Upload } from 'antd';
import QRCode from 'qrcode';
import { priceFormat } from '@/utils/numberFomat';
import WechatIcon from '@/assets/imgs/wechat_icon.png';
import styles from './index.less';
interface WxPayModalProps {
/**
* 需要生成 二维码的 地址
*/
url: string;
/**
* 支付金额
*/
price: number;
/**
* 是否可见
*/
visible: boolean;
/**
* 弹窗取消事件
*/
onCancel: () => void;
/**
* 轮训查询支付结果事件
*/
onCheckResult: () => Promise<{ success: Boolean }>;
/**
* 轮训查询支付结果成功
*/
onSuccess?: () => void;
/**
* 轮训查询支付结果失败
*/
onFail?: () => void;
};
const WxPayModal: React.FC<WxPayModalProps> = ({
url,
price,
visible,
onCancel,
onCheckResult,
onSuccess,
onFail,
}) => {
const [qrCode, setQrCode] = useState<string>('');
const getQRCode = async params => {
if (!params) {
return;
}
// 生成二维码
const res = await QRCode.toDataURL(params);
setQrCode(res);
};
let timer = useRef(null);
// 最多请求3600次,2000毫秒一次,二维码过期两小时
let count = 0;
const handleCheckResult = () => {
if (!onCheckResult) {
return;
}
count++;
if (count > 3600) {
return;
}
onCheckResult().then(res => {
if (!res.success) {
timer.current = setTimeout(() => {
handleCheckResult();
}, 2000);
} else {
clearTimeout(timer.current);
timer = null;
if (onSuccess) {
onSuccess();
}
}
});
};
useEffect(() => {
getQRCode(url);
if (url) {
handleCheckResult();
}
return () => {
if (timer.current) {
clearTimeout(timer.current);
timer.current = null;
}
};
}, [url]);
useEffect(() => {
if (!visible) {
if (timer.current) {
clearTimeout(timer.current);
timer.current = null;
}
}
}, [visible]);
const handleCancel = () => {
if (onCancel) {
onCancel();
}
};
return (
<Modal
title={(
<div className={styles.common_title}>
<div className={styles.common_title_icon}><img src={WechatIcon} /></div>
<span>微信支付</span>
</div>
)}
width={576}
visible={visible}
onCancel={handleCancel}
footer={null}
maskClosable={false}
destroyOnClose
>
<div className={styles.wechat_payway}>
<p className={styles.wechat_payway_title}>使用微信扫一扫下方二维码</p>
<div className={styles.wechat_payway_imgbox}>
{qrCode && <img src={qrCode} />}
</div>
<div className={styles.wechat_payway_needpay}>
<label>当前需支付:</label>
<span>{priceFormat(price)}</span>
<label>RMB</label>
</div>
</div>
</Modal>
);
};
export default WxPayModal;
\ No newline at end of file
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