Commit d0122973 authored by 张烨's avatar 张烨

feat: add ImageUploader and fix some bugs

parent 8e393159
......@@ -83,6 +83,7 @@
"dependencies": {
"@babel/polyfill": "7.4.3",
"@babel/runtime": "^7.10.5",
"antd-img-crop": "^3.13.2",
"chalk": "2.4.2",
"compression": "1.7.4",
"connected-react-router": "6.4.0",
......
:global(.ant-upload-select-picture-card i) {
color: #999;
font-size: 14px;
}
:global(.ant-upload-select-picture-card .ant-upload-text) {
margin-top: 8px;
color: #666;
}
.avatarUploader {
display: inline-block;
text-align: left;
}
.wallBtn {
position: absolute;
left: 140px;
bottom: 56px;
display: inline-block;
color: #2f54eb;
cursor: pointer;
border-bottom: 1px solid #2f54eb;
}
.imgBox {
display: flex;
flex-wrap: wrap;
max-height: 520px;
overflow: auto;
.imgItem {
position: relative;
margin-right: 16px;
margin-bottom: 16px;
width: 320px;
max-height: 220px;
overflow: hidden;
cursor: pointer;
img {
width: 100%;
}
&:hover,
&.seleted {
.iconBtn {
visibility: visible;
}
}
.iconBtn {
position: absolute;
visibility: hidden;
top: 6px;
right: 10px;
font-size: 18px;
color: rgb(8, 156, 8);
}
}
}
import React from 'react';
import { Upload, Modal, message, Tabs, Result } from 'antd';
import { PlusOutlined, CheckCircleFilled } from '@ant-design/icons';
import ImgCrop from 'antd-img-crop';
import classnames from 'classnames';
import { UploadFile, UploadChangeParam, RcFile } from 'antd/lib/upload/interface';
import { isDev, unParams, uuid } from '@/utils/tool';
import req from '@/utils/req';
import styles from './index.less';
const { TabPane } = Tabs;
// 维护图片分类映射
const wallCateName: any = {
photo: '照片',
bg: '背景',
chahua: '插画',
};
function getBase64(file: File | Blob) {
return new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result as string);
reader.onerror = error => reject(error);
});
}
interface PicturesWallType {
fileList?: UploadFile<any>[];
action?: string;
headers?: any;
withCredentials?: boolean;
maxLen?: number;
onChange?: (v: any) => void;
cropRate?: number | boolean;
isCrop?: boolean;
}
class PicturesWall extends React.Component<PicturesWallType> {
state = {
previewVisible: false,
previewImage: '',
wallModalVisible: false,
previewTitle: '',
imgBed: {
photo: [],
bg: [],
chahua: [],
},
curSelectedImg: '',
fileList: this.props.fileList || [],
};
handleCancel = () => this.setState({ previewVisible: false });
handleModalCancel = () => this.setState({ wallModalVisible: false });
handlePreview = async (file: UploadFile<any>) => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj!);
}
this.setState({
previewImage: file.url || file.preview,
previewVisible: true,
previewTitle: file.name || file.url!.substring(file.url!.lastIndexOf('/') + 1),
});
};
handleWallSelect = (url: string) => {
this.setState({
wallModalVisible: true,
});
};
handleImgSelected = (url: string) => {
this.setState({
curSelectedImg: url,
});
};
handleWallShow = () => {
this.setState({
wallModalVisible: true,
});
};
handleModalOk = () => {
const fileList = [
{
uid: uuid(8, 16),
name: 'h5-dooring图片库',
status: 'done',
url: this.state.curSelectedImg,
},
];
this.props.onChange && this.props.onChange(fileList);
this.setState({ fileList, wallModalVisible: false });
};
handleChange = ({ file, fileList }: UploadChangeParam<UploadFile<any>>) => {
this.setState({ fileList });
if (file.status === 'done') {
const files = fileList.map(item => {
const { uid, name, status } = item;
const url = item.url || item.response.result.url;
return { uid, name, status, url };
});
this.props.onChange && this.props.onChange(files);
}
};
handleBeforeUpload = (file: RcFile) => {
const isJpgOrPng =
file.type === 'image/jpeg' ||
file.type === 'image/png' ||
file.type === 'image/jpg' ||
file.type === 'image/gif';
if (!isJpgOrPng) {
message.error('只能上传格式为jpeg/png/gif的图片');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('图片必须小于2MB!');
}
return isJpgOrPng && isLt2M;
};
componentDidMount() {
req.get(`/visible/bed/get?tid=${unParams(location.search)!.tid}`).then(res => {
res &&
this.setState({
imgBed: res,
});
});
}
render() {
const {
previewVisible,
previewImage,
fileList,
previewTitle,
wallModalVisible,
imgBed,
curSelectedImg,
} = this.state;
const {
action = isDev ? 'http://192.168.1.8:3000/api/v0/files/upload/free' : '你的服务器地址',
headers,
withCredentials = true,
maxLen = 1,
cropRate = 375 / 158,
isCrop,
} = this.props;
const uploadButton = (
<div>
<PlusOutlined />
<div className="ant-upload-text">上传</div>
</div>
);
const cates = Object.keys(imgBed);
return (
<>
{isCrop ? (
<ImgCrop
modalTitle="裁剪图片"
modalOk="确定"
modalCancel="取消"
rotate={true}
aspect={cropRate}
>
<Upload
fileList={fileList}
onPreview={this.handlePreview}
onChange={this.handleChange}
name="file"
listType="picture-card"
className={styles.avatarUploader}
action={action}
withCredentials={withCredentials}
headers={{
'x-requested-with': localStorage.getItem('user') || '',
authorization: localStorage.getItem('token') || '',
...headers,
}}
beforeUpload={this.handleBeforeUpload}
>
{fileList.length >= maxLen ? null : uploadButton}
</Upload>
</ImgCrop>
) : (
<Upload
fileList={fileList}
onPreview={this.handlePreview}
onChange={this.handleChange}
name="file"
listType="picture-card"
className={styles.avatarUploader}
action={action}
withCredentials={withCredentials}
headers={{
'x-requested-with': localStorage.getItem('user') || '',
authorization: localStorage.getItem('token') || '',
...headers,
}}
beforeUpload={this.handleBeforeUpload}
>
{fileList.length >= maxLen ? null : uploadButton}
</Upload>
)}
<div className={styles.wallBtn} onClick={this.handleWallShow}>
图片库
</div>
<Modal
visible={previewVisible}
title={previewTitle}
footer={null}
onCancel={this.handleCancel}
>
<img alt="预览图片" style={{ width: '100%' }} src={previewImage} />
</Modal>
<Modal
visible={wallModalVisible}
title="图片库"
okText="确定"
cancelText="取消"
width={860}
onCancel={this.handleModalCancel}
onOk={this.handleModalOk}
>
<Tabs defaultActiveKey={cates[0]} tabPosition="left" style={{ height: 520 }}>
{cates.map((item, i) => {
return (
<TabPane tab={wallCateName[item]} key={item}>
<div className={styles.imgBox}>
{(imgBed as any)[item] &&
(imgBed as any)[item].map((item: string, i: number) => {
return (
<div
className={classnames(
styles.imgItem,
curSelectedImg === item ? styles.seleted : '',
)}
key={i}
onClick={() => this.handleImgSelected(item)}
>
<img src={item} alt="趣谈前端-h5-dooring" />
<span className={styles.iconBtn}>
<CheckCircleFilled />
</span>
</div>
);
})}
</div>
</TabPane>
);
})}
<TabPane tab="更多" key="more">
<Result status="500" title="Dooring温馨提示" subTitle="更多素材, 正在筹备中..." />
</TabPane>
</Tabs>
</Modal>
</>
);
}
}
export default PicturesWall;
......@@ -12,8 +12,8 @@ const ListCardItem = props => {
const [defaultList, setDefaultList] = useState([]); // 默认的选项
const [submitArr, setSubmitArr] = useState([]); // 提交的数组
// const submitArr = [];
useEffect(() => {
console.log(userList, '执行了`````');
let arr = [];
userList.map((item, index) => {
let obj = { ...item };
......@@ -28,41 +28,43 @@ const ListCardItem = props => {
{obj.userName || obj.roleName || obj.stationName}
</span>
);
obj.value = obj.userID || obj.roleID || obj.stationName;
obj.value = obj.userID || obj.roleID || obj.stationID;
arr.push(obj);
});
setDefaultList(arr);
}, [searchWord]);
useEffect(() => {
console.log(userList, '执行了`````');
let arr2 = [];
userList.map((item, index) => {
if (item.isChecked) {
arr2.push(item.userID || item.roleID || item.stationID);
}
});
setIndeterminate(userList.some(u => u.isChecked));
setAllChecked(userList.every(u => u.isChecked));
setCheckList(arr2);
}, [userList]);
const handleAllChecked = e => {
const { checked } = e.target;
setAllChecked(checked);
let arr = [];
if (checked) {
arr = defaultList.map(item => item.value);
} else {
arr = [];
}
setCheckList(arr);
setIndeterminate(false);
setCheckList(arr);
getValueCallback(arr, itemid);
};
const handleChecked = e => {
console.log(e, 'e45');
setCheckList(e);
setAllChecked(e.length === defaultList.length);
setIndeterminate(!!e.length && e.length < defaultList.length);
getValueCallback(e, itemid);
};
return (
<>
<div className={`${styles.divBox}`}>
......
This diff is collapsed.
import { get, post } from '@/services/index';
export const getUserTree = (selectOU, node) =>
get(`/Cityinterface/rest/services/OMS.svc/U_GetOUTree`, {
_version: 9999,
_dc: new Date().getTime(),
selectOU,
node,
});
export const getOneOUUserListNew = OUID =>
get(`/Cityinterface/rest/services/OMS.svc/U_GetOneOUUserListNew`, {
_version: 9999,
_dc: new Date().getTime(),
OUID,
});
/**
* 查询用户
* @param {*} key
*/
export const getUserByKey = key =>
get(`/Cityinterface/rest/services/OMS.svc/U_GetUserByKey`, {
_version: 9999,
_dc: new Date().getTime(),
key,
});
/**
* 添加用户
* @param {*} param0
*/
export const addUser = ({
OUID,
loginName,
userName,
password,
phone,
email,
}) =>
get(`/Cityinterface/rest/services/OMS.svc/U_AddUser`, {
_version: 9999,
_dc: Date.now(),
OUID,
loginName,
userName,
password,
phone,
email,
});
export const submitAddOrg = (orgID, OUName, description, comment) =>
get(`/Cityinterface/rest/services/OMS.svc/U_AddOU`, {
_version: 9999,
_dc: Date.now(),
pid: orgID,
OUName,
description,
comment,
});
export const editOrgInfo = (orgID, OUName, description, comment) =>
get(`/Cityinterface/rest/services/OMS.svc/U_EditOneOUInfo`, {
_version: 9999,
_dc: Date.now(),
OUID: orgID,
OUName,
description,
comment,
});
export const deleteOrg = orgID =>
get(`/Cityinterface/rest/services/OMS.svc/U_DeleteOU`, {
_version: 9999,
_dc: Date.now(),
OUID: orgID,
});
export const getUserRelationList = userID =>
get(`/Cityinterface/rest/services/OMS.svc/W4_GetUserRelationList`, {
_version: 9999,
_dc: Date.now(),
userID: `${userID}`,
});
export const addToOrg = (userID, orgID, newOrgID) =>
get(`/Cityinterface/rest/services/OMS.svc/U_JumpToAnotherOU`, {
_version: 9999,
_dc: Date.now(),
userID,
oldOUID: orgID,
newOUID: newOrgID,
});
export const updateUserPassword = (
userID,
oldpassword,
newPassword,
passwordConfirm,
) =>
get(`/Cityinterface/rest/services/OMS.svc/U_UpdatePassword`, {
_version: 9999,
_dc: Date.now(),
userID,
oldpassword,
newPassword,
passwordConfirm,
});
export const editUser = (userID, loginName, userName, phone, email) =>
get(`/Cityinterface/rest/services/OMS.svc/U_EditUser`, {
_version: 9999,
_dc: Date.now(),
userID,
loginName,
userName,
phone,
email,
});
export const setUserState = (OUID, state) =>
get(`/Cityinterface/rest/services/OMS.svc/U_UserStateOU`, {
_version: 9999,
_dc: Date.now(),
OUID,
state,
});
export const deleteUser = userID =>
get(`/Cityinterface/rest/services/OMS.svc/U_DeleteUser`, {
_version: 9999,
_dc: Date.now(),
userID,
});
import { RefObject, useEffect, useLayoutEffect, useState } from 'react';
import { RGBColor } from 'react-color';
// 生成uuid
function uuid(len: number, radix: number) {
let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(
'',
);
let uuid = [];
let i;
radix = radix || chars.length;
if (len) {
for (i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)];
} else {
let r;
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4';
for (i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | (Math.random() * 16);
uuid[i] = chars[i === 19 ? (r & 0x3) | 0x8 : r];
}
}
}
return uuid.join('');
}
// 将rgba字符串对象转化为rgba对象
function rgba2Obj(rgba = '') {
let reg = /rgba\((\d+),(\d+),(\d+),(\d+)\)/g;
let rgbaObj: RGBColor = { r: 0, g: 0, b: 0, a: 0 };
rgba.replace(reg, (_m, r, g, b, a) => {
rgbaObj = { r, g, b, a };
return rgba;
});
return rgbaObj;
}
export { uuid, rgba2Obj };
export const isDev = process.env.NODE_ENV === 'development';
export function useGetRect() {
const [rect, setRect] = useState({ width: 0, height: 0 });
useEffect(() => {
setRect({
width: window.innerWidth,
height: window.innerHeight,
});
}, []);
return rect;
}
export function useGetScrollBarWidth(ref: RefObject<HTMLElement>) {
const [width, setWidth] = useState(0);
useLayoutEffect(() => {
if (ref.current) {
const diff = ref.current.offsetWidth - ref.current.clientWidth;
setWidth(diff);
}
}, [ref]);
return width;
}
export function useAnimation(state: boolean, delay: number) {
const [display, setDisplay] = useState(false);
useEffect(() => {
let timer: number;
if (state && display === true) {
setDisplay(false);
} else if (!state && display === false) {
timer = window.setTimeout(() => {
setDisplay(true);
}, delay);
}
return () => {
window.clearTimeout(timer);
};
}, [delay, display, state]);
return [display, setDisplay];
}
export function unParams(params = '?a=1&b=2&c=3') {
let obj: any = {};
params &&
// eslint-disable-next-line no-useless-escape
params.replace(
/((\w*)=([\.a-z0-9A-Z]*)?)?/g,
(m, a, b, c): any => {
if (b || c) obj[b] = c;
},
);
return obj;
}
export function throttle(fn: Function, delay: number) {
let flag = true;
return (...args: any) => {
if (flag) {
flag = false;
fn(...args);
setTimeout(() => {
flag = true;
}, delay);
}
};
}
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