在開發react開發過程中在做一些表單内容送出修改過程中:用到了上傳和下載下傳附件;富文本編輯等,話不多說上代碼:
index.js檔案是一個list表格:
/*
* 項目需求清單
*/
import React, { Component } from "react";
import Storage from "store2";
// import History from "@utils/history";
import { Modal, Button, Row, Col, Table, Notification } from "antd";
import Request from "@utils/request";
import { areaName, bankName } from "@utils/codeToName";
import Form from "./form.js";
let version = Storage.get("version");
const columns = _this => [
{
title: "id",
dataIndex: "id",
},
{
title: "需求名稱",
dataIndex: "demandName",
},
{
title: "需求編碼",
dataIndex: "demandCode",
},
{
title: "需求描述",
dataIndex: "note",
width: 200,
render: text => {
const re = new RegExp("<[^<>]+>", "g");
const text1 = text.replace(re, "");
return <textarea defaultValue={text1}></textarea>;
}
},
{
title: "地區",
dataIndex: "areaCode",
align: "center",
render: (text) => areaName(text)
},
{
title: "銀行",
dataIndex: "bankCode",
align: "center",
render: (text) => bankName(text)
},
{
title: "建立時間",
dataIndex: "createTime",
width: 200,
},
{
title: "操作",
dataIndex: "操作",
fixed: "right",
align: "center",
width: 240,
render: (text, record) => (
<div style={{ textAlign: "right" }}>
<Button
type="link"
onClick={() => {
Modal.confirm({
title: "确定删除此項目嗎?",
content: (
<div>
<p>項目名稱:{record.demandName}</p>
</div>
),
okText: "确認",
cancelText: "取消",
onOk() {
Request.POST(`/api/demand/delete/${record.id}`, {
params: {
loginKey: Storage.get("Authorization"),
}
}).then((res) => {
if (res.success) {
Notification.success({
message: res.msg || "删除成功"
});
_this.loadData();
} else {
Notification.error({
message: res.msg || "删除失敗"
});
}
});
}
});
}}
>
删除
</Button>
{
record.loginname !== "admin"
&&
<Button
type="link"
onClick={() => {
_this.setState({
taskModal: true,
taskModalType: "edit",
demandInfo: record.id
})
}}
>
修改
</Button>
}
<Button
type="link"
onClick={() => {
// 擷取任詳情
Request.GET(`/api/demand/get/${record.id}`, {
params: {
loginKey: Storage.get("Authorization"),
}
}).then((res) => {
if (res.success) {
_this.setState({
downloadtaskModal: true,
downloadDemandInfo: res.data.attachmentList
});
} else {
Notification.warning({
message: res.msg || "擷取任詳情失敗",
});
}
});
}}
>
下載下傳附件
</Button>
</div>
)
}
];
class View extends Component {
constructor(props) {
super(props);
this.state = {
tableSource: [],
taskModal: false,
downloadtaskModal: false,
taskModalType: "add", //建立:add 修改:edit
demandInfo: "",
downloadDemandInfo: [] //附件資訊
};
}
componentDidMount() {
this.loadData(); // 擷取資料
}
// 渲染頁面資料
loadData = async () => {
// 擷取任務清單
Request.GET("/api/demand/list", {
params: {
loginKey: Storage.get("Authorization"),
}
}).then((res) => {
if (res.success) {
this.setState({
tableSource: res.data
});
} else {
Notification.warning({
message: res.msg || "擷取戶失敗",
});
}
});
};
CancelTaskModal = () => {
this.setState({
taskModal: false
})
}
CanceldownloadtaskModal = () => {
this.setState({
downloadtaskModal: false
})
}
render() {
const {
tableSource,
taskModalType,
demandInfo,
downloadtaskModal,
downloadDemandInfo
} = this.state;
console.log(downloadDemandInfo)
return (
<div>
<Row>
<Col>
<Button type="primary"
size="large"
onClick={() => {
this.setState({
taskModal: true,
taskModalType: "add"
})
}}
>新增需求</Button>
</Col>
</Row>
<Table
style={{
marginTop: "20px"
}}
scroll={{ x: 1200 }}
dataSource={tableSource}
columns={columns(this)}
rowKey="id"
/>
<Modal
title={taskModalType === "edit" ? "修改需求" : "新增需求"}
footer={null}
width={900}
destroyOnClose
visible={this.state.taskModal}
onCancel={() => { this.CancelTaskModal() }}
>
<Form parentThis={this}
taskModalType={taskModalType}
demandInfo={demandInfo}
/>
</Modal>
<Modal
title="下載下傳附件"
footer={null}
width={900}
destroyOnClose
visible={downloadtaskModal}
onCancel={() => { this.CanceldownloadtaskModal() }}
>
{
(downloadDemandInfo && downloadDemandInfo.length > 0)
?
downloadDemandInfo.map(item => {
return <Button
type="link"
key={item.id}
onClick={() => {
// 下載下傳附件
window.location.href = `${version}/attachment/download/${item.uuid}?loginKey=${Storage.get("Authorization")}`;
}}>
{item.fileName}
</Button>
})
:
"無附件"
}
</Modal>
</div>
);
}
}
export default View;
form.js表單新增,修改
/*
* 建立修改需求
*/
import React from "react";
import { Form, Notification, Button, Input, Row, Col, Select, Radio, message, Upload, Icon } from "antd";
import Request from "@utils/request";
import Storage from "store2";
import Edit from "./edit"
const FormItem = Form.Item;
class ViewForm extends React.Component {
constructor(props) {
super(props);
this.state = {
demandInfo: {},
areaArr: [],
bankArr: [],
editorContent: "",
fileList: [],//要上傳的附件list
zzfileList: [], //回顯的附件list
};
}
componentDidMount() {
this.areaData();
this.bankData();
const { taskModalType } = this.props;
if (taskModalType === "edit") {
this.loadData(); // 擷取資料
}
}
// 擷取地區
areaData = () => {
Request.GET("/api/area/list", {
params: {
loginKey: Storage.get("Authorization"),
}
}).then(res => {
if (res.success) {
this.setState({
areaArr: res.data
});
}
})
};
// 擷取銀行
bankData = () => {
Request.GET("/api/bank/list", {
params: {
loginKey: Storage.get("Authorization"),
}
}).then(res => {
if (res.success) {
this.setState({
bankArr: res.data
});
}
})
};
// 根據地區換銀行
changeArea = (value) => {
let areaCode = value;
Request.GET(`/api/area/getByAreaCode/${areaCode}`, {
params: {
loginKey: Storage.get("Authorization"),
}
}).then(res => {
if (res.success) {
this.setState({
bankArr: res.data.bankList
});
} else {
this.setState({
bankArr: []
});
}
})
};
// 編輯器内容
saveEditor = (text) => {
const { form: { setFieldsValue } } = this.props;
this.setState({
editorContent: text
});
setFieldsValue({
"note": text
});
};
// 擷取項目資訊
loadData = async () => {
Request.GET(`/api/demand/get/${this.props.demandInfo}`, {
params: {
loginKey: Storage.get("Authorization"),
}
}).then((res) => {
if (res.success) {
this.setState({
demandInfo: res.data,
editorContent: res.data.note,
zzfileList: res.data.attachmentList, // 原始資料
fileList: (this.props.taskModalType === "edit" && res.data.attachmentList && res.data.attachmentList.length > 0)
?
res.data.attachmentList.map(f => {
const temp = {
// 為了提供給上傳元件回顯
id: f.id,
uid: f.uuid, // 這是上傳元件規定的檔案唯一辨別,内部會提供給Form以便正常渲染回顯清單
name: f.fileName,
status: "done",
url: "",
fileExt: f.fileExt,
filePath: f.filePath,
fileSize: f.fileSize,
}
return temp;
})
:
[]
});
} else {
Notification.warning({
message: res.msg || "擷取項目資訊失敗",
});
}
});
};
handleSubmit = () => {
const { form: { validateFields }, taskModalType } = this.props;
const { demandInfo, zzfileList, editorContent } = this.state;
validateFields((err, values) => {
if (!err) {
if (taskModalType === "edit") {
Request.POST("/api/demand/update", {
params: {
loginKey: Storage.get("Authorization"),
},
body: {
demandName: values.demandName,
demandCode: values.demandCode,
id: demandInfo.id,
areaCode: values.areaCode,
bankCode: values.bankCode,
demandGeneral: values.demandGeneral,
attachmentList: zzfileList,
note: editorContent,
}
}).then((res) => {
if (res.success) {
Notification.success({
message: res.msg || "修改成功",
});
this.props.parentThis.CancelTaskModal();
this.props.parentThis.loadData();
} else {
Notification.warning({
message: res.msg || "修改失敗",
});
}
});
} else {
Request.POST("/api/demand/add", {
params: {
loginKey: Storage.get("Authorization"),
},
body: {
demandName: values.demandName,
areaCode: values.areaCode,
demandCode: values.demandCode,
bankCode: values.bankCode,
demandGeneral: values.demandGeneral,
attachmentList: zzfileList,
note: editorContent,
}
}).then((res) => {
if (res.success) {
Notification.success({
message: res.msg || "新增需求成功",
});
this.props.parentThis.CancelTaskModal();
this.props.parentThis.loadData();
} else {
Notification.warning({
message: res.msg || "新增需求失敗",
});
}
});
}
}
});
};
render() {
const { demandInfo, fileList, zzfileList, editorContent, areaArr, bankArr } = this.state;
const { taskModalType } = this.props;
if (taskModalType === "edit" && Object.keys(demandInfo).length === 0) return <div></div>;
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 12 },
};
const formItemLayoutNote = {
labelCol: { span: 4 },
wrapperCol: { span: 20 },
}
let _this = this;
const props = {
accept: ".rar,.zip,.doc,.docx,.xlsx,.xls,.pdf,.jpg,.png",
name: "file",
action: `${Storage.get("version")}/attachment/upload?loginKey=${Storage.get("Authorization")}`,
defaultFileList: fileList,
beforeUpload(file) {
const isLt10M = file.size / 1024 / 1024 <= 100;
if (!isLt10M) {
message.error("檔案大小限制在100M以下!");
this.onRemove(file);
return false;
}
},
onRemove(file) {
Request.GET(`/api/attachment/del/${file.uid}`, {
params: {
loginKey: Storage.get("Authorization"),
}
}).then((res) => {
if (res.success) {
Notification.success({
message: res.msg || "删除附件成功",
});
} else {
Notification.warning({
message: res.msg || "删除附件失敗",
});
}
});
_this.setState({
fileList: fileList.filter(item => item.name !== file.name),
zzfileList: zzfileList.filter(item => item.fileName !== file.name),
}, () => {
_this.props.form.setFieldsValue({ fileList: fileList });
});
},
onChange(info) { // 上傳中、完成、失敗都會調用這個函數
let curFileList = [...info.fileList];
curFileList = curFileList.map((file) => {
if (file.response) {
console.log(file.response);
// 這裡上傳元件回調的資料,有些是提供給上傳元件自身使用的,是以不能不要
// 而需要向後端送出的資料這裡提前封裝起來,以友善最終的送出
// let saveParams = {};
file["fileName"] = file.response.data.fileName;
file["filePath"] = file.response.data.filePath;
file["fileSize"] = file.response.data.fileSize;
file["fileExt"] = file.response.data.fileExt;
file["uuid"] = file.response.data.uuid;
file["id"] = file.response.data.id;
}
return file;
});
curFileList = curFileList.filter(file => {
if (file.size / 1024 / 1024 <= 100) {
if (file.response) {
return file.response.code === 0;
}
return true;
} else {
return false;
}
});
_this.setState({
zzfileList: [
..._this.state.zzfileList,
...curFileList
]
});
},
// fileList: fileList, // 上傳元件已使用Form進行代理,是以不要再直接設定
};
return (
<Row>
<Col>
<Form>
<FormItem label="需求名稱"
{...formItemLayout}
>
{getFieldDecorator("demandName", {
initialValue: taskModalType === "edit" ? demandInfo.demandName : "",
rules: [{ required: true, message: "請填寫需求名稱!" }],
})(
<Input placeholder="請填寫需求名稱" />
)}
</FormItem>
<FormItem label="需求編号"
{...formItemLayout}
>
{getFieldDecorator("demandCode", {
initialValue: taskModalType === "edit" ? demandInfo.demandCode : "",
rules: [{ required: true, message: "請填寫需求編号!" }],
})(
<Input placeholder="請填寫需求編号" />
)}
</FormItem>
<FormItem label="地區"
{...formItemLayout}
>
{getFieldDecorator("areaCode", {
initialValue: taskModalType === "edit" ? demandInfo.areaCode : "",
rules: [{ required: true, message: "請輸入實施地區!" }],
})(
<Select
showSearch
placeholder="請選擇實施的地區"
optionFilterProp="children"
onChange={(e) => this.changeArea(e)}
filterOption={(input, option) =>
option.props.children.indexOf(input) >= 0
}
>
{
areaArr.map((item, index) => {
return <Select.Option
value={item.areaCode}
key={index}
>
{item.areaName}
</Select.Option>
})
}
</Select>
)}
</FormItem>
<FormItem label="銀行"
{...formItemLayout}
>
{getFieldDecorator("bankCode", {
initialValue: taskModalType === "edit" ? demandInfo.bankCode : "",
rules: [{ required: true, message: "請輸入實施銀行!" }],
})(
<Select
showSearch
placeholder="請選擇實施的銀行"
optionFilterProp="children"
filterOption={(input, option) =>
option.props.children.indexOf(input) >= 0
}
>
{
bankArr.map((item, index) => {
return <Select.Option
value={item.bankCode}
key={index}
>
{item.bankName}
</Select.Option>
})
}
</Select>
)}
</FormItem>
<FormItem label="是否通用"
{...formItemLayout}
>
{getFieldDecorator("demandGeneral", {
initialValue: taskModalType === "edit" ? demandInfo.demandGeneral : 1,
rules: [{ required: true, message: "請選擇是否通用!" }],
})(
<Radio.Group >
<Radio value={1}>通用版本</Radio>
<Radio value={2}>非通用版本</Radio>
</Radio.Group>
)}
</FormItem>
<FormItem {...formItemLayout}
label="上傳附件">
{getFieldDecorator("attachmentList", {
rules: [{
required: false, message: "請上傳證明材料"
}],
valuePropName: "attachmentList",
getValueFromEvent: (e) => {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
}
})(
<Upload {...props}>
<Button>
<Icon type="upload" /> 上傳檔案
</Button>
<span className="upload-desc">支援附件:.rar .zip .xlsx .xls .doc .pdf .jpg .png</span>
</Upload>
)}
</FormItem>
<FormItem label="需求描述"
{...formItemLayoutNote}
>
{getFieldDecorator("note", {
initialValue: taskModalType === "edit" ? editorContent : "",
})(
<Edit
parentThis={this}
getFieldDecorator={getFieldDecorator}
editWord={editorContent}
/>
)}
</FormItem>
</Form>
</Col>
<Col style={{ "textAlign": "right", marginTop: "10px" }}>
<Button type="primary"
htmlType="submit"
onClick={() => {
this.handleSubmit()
}}
>确定</Button>
<Button style={{ "marginLeft": 8 }}
onClick={() => {
this.props.parentThis.CancelTaskModal();
}}
>取消</Button>
</Col>
</Row>
);
}
}
const View = Form.create()(ViewForm);
export default View;
edit.js表單中的富文本編輯器
import React, { Component } from "react";
import E from "wangeditor"
class Wangeditor extends Component {
constructor(props, context) {
super(props, context);
this.myRefOne = React.createRef();
this.state = {
editorContent: ""
}
}
componentDidMount() {
const elem = this.myRefOne;
this.editor = new E(elem);
// 使用 onchange 函數監聽内容的變化,并實時更新到 state 中
this.editor.customConfig.onchange = html => {
this.setState({
editorContent: html
});
// let wordText = this.editor.txt.text();
this.props.parentThis.saveEditor(html);
}
this.editor.create();
this.editor.txt.html(this.state.editorContent);
}
// 注意此處有個需要注意的坑,在回顯過程中,需要對比props修改的傳值問題
shouldComponentUpdate(nextProps) {
if (this.state.editorContent !== nextProps.value) {
this.setState({
editorContent: nextProps.value
}, () => {
this.editor.txt.html(this.state.editorContent);
});
return true;
} else {
return false;
}
}
render() {
// const { getFieldDecorator, value: { note }, parentThis } = this.props;
return (
<div className="editor">
{/* 将生成編輯器 */}
<div
ref={(ref) => this.myRefOne = ref}
style={{
textAlign: "left"
}}
>
</div>
</div>
);
}
}
export default Wangeditor;