💄 UI: [前台]:书签管理页开发中
This commit is contained in:
parent
2e9466ad6b
commit
a05d57c95b
@ -1,18 +1,134 @@
|
|||||||
import httpUtil from "../../../util/httpUtil";
|
import httpUtil from "../../../util/httpUtil";
|
||||||
import { Modal } from "antd";
|
import { Modal, message } from "antd";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除书签
|
* 选中的文件夹id列表
|
||||||
* @param {*} _this 组件实例
|
|
||||||
* @param {*} folderList 删除的文件夹列表
|
|
||||||
* @param {*} bookmarkList 删除的具体书签列表
|
|
||||||
*/
|
*/
|
||||||
export function deleteBookmark(_this, folderList, bookmarkList) {
|
let folderIdList = [];
|
||||||
|
/**
|
||||||
|
* 选中的书签id列表
|
||||||
|
*/
|
||||||
|
let bookmarkIdList = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增书签的父节点node
|
||||||
|
*/
|
||||||
|
let parentNode = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 展开/关闭
|
||||||
|
* @param {*} keys
|
||||||
|
*/
|
||||||
|
export function onExpand(keys) {
|
||||||
|
this.setState({ expandKeys: keys });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭全部节点
|
||||||
|
*/
|
||||||
|
export function closeAll() {
|
||||||
|
this.setState({ expandKeys: [] });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选中节点
|
||||||
|
* @param {*} keys
|
||||||
|
* @param {*} data
|
||||||
|
*/
|
||||||
|
export function onCheck(keys, data) {
|
||||||
|
this.setState({ checkedKeys: keys });
|
||||||
|
bookmarkIdList = [];
|
||||||
|
folderIdList = [];
|
||||||
|
parentNode = null;
|
||||||
|
data.checkedNodes.forEach(item => {
|
||||||
|
const bookmark = item.props.dataRef;
|
||||||
|
parentNode = bookmark;
|
||||||
|
bookmark.type === 0 ? bookmarkIdList.push(bookmark.bookmarkId) : folderIdList.push(bookmark.bookmarkId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 弹出新增modal
|
||||||
|
*/
|
||||||
|
export function showAddModel() {
|
||||||
|
if (this.state.checkedKeys.length > 1) {
|
||||||
|
message.error("选中过多");
|
||||||
|
return;
|
||||||
|
} else if (this.state.checkedKeys.length === 1) {
|
||||||
|
const id = this.state.checkedKeys[0];
|
||||||
|
if (bookmarkIdList.indexOf(parseInt(id)) > -1) {
|
||||||
|
message.error("只能选择文件夹节点");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({ isShowModal: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addOne() {
|
||||||
|
console.log(1);
|
||||||
|
let body = {
|
||||||
|
type: this.state.addType,
|
||||||
|
path: parentNode == null ? "" : parentNode.path + "." + parentNode.bookmarkId,
|
||||||
|
name: this.state.addName,
|
||||||
|
url: this.state.addValue
|
||||||
|
};
|
||||||
|
httpUtil.put("/bookmark", body).then(res => {
|
||||||
|
let arr;
|
||||||
|
if (parentNode == null) {
|
||||||
|
arr = this.data[""] ? this.data[""] : [];
|
||||||
|
} else {
|
||||||
|
arr = this.data[body.path] ? this.data[body.path] : [];
|
||||||
|
}
|
||||||
|
arr.push(res);
|
||||||
|
if (this.state.treeData.length === 0) {
|
||||||
|
this.state.treeData.push(arr);
|
||||||
|
}
|
||||||
|
this.data[body.path] = arr;
|
||||||
|
this.setState({ treeData: [...this.state.treeData], addType: 0, addName: "", addValue: "", isShowModal: false });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除
|
||||||
|
*/
|
||||||
|
export function batchDelete() {
|
||||||
|
console.log("1");
|
||||||
|
const _this = this;
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: "确认删除?",
|
title: "确认删除?",
|
||||||
content: "删除后,无法找回",
|
content: "删除后,无法找回",
|
||||||
onOk() {
|
onOk() {
|
||||||
return httpUtil.post("/dele")
|
return new Promise((resolve, reject) => {
|
||||||
|
httpUtil
|
||||||
|
.post("/bookmark/batchDelete", { folderIdList, bookmarkIdList })
|
||||||
|
.then(() => {
|
||||||
|
//遍历节点树数据,并删除
|
||||||
|
const set = new Set();
|
||||||
|
folderIdList.forEach(item => set.add(item));
|
||||||
|
bookmarkIdList.forEach(item => set.add(item));
|
||||||
|
deleteTreeData(_this.state.treeData, set);
|
||||||
|
_this.setState({ treeData: [..._this.state.treeData], checkedKeys: [] });
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch(() => reject());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归删除已经被删除的数据
|
||||||
|
* @param {*} treeData
|
||||||
|
*/
|
||||||
|
function deleteTreeData(treeData, set) {
|
||||||
|
for (let i = 0, length = treeData.length; i < length; i++) {
|
||||||
|
const item = treeData[i];
|
||||||
|
if (set.has(treeData[i].bookmarkId)) {
|
||||||
|
treeData.splice(i, 1);
|
||||||
|
length--;
|
||||||
|
i--;
|
||||||
|
} else if (item.children && item.children.length > 0) {
|
||||||
|
deleteTreeData(item.children, set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Tree, Empty, Button, Tooltip } from "antd";
|
import { Icon, Tree, Empty, Button, Tooltip, Modal, Form, Input, Radio, Upload } from "antd";
|
||||||
import MainLayout from "../../../layout/MainLayout";
|
import MainLayout from "../../../layout/MainLayout";
|
||||||
import httpUtil from "../../../util/httpUtil";
|
import httpUtil from "../../../util/httpUtil";
|
||||||
import IconFont from "../../../components/IconFont";
|
import IconFont from "../../../components/IconFont";
|
||||||
import styles from "./index.module.less";
|
import styles from "./index.module.less";
|
||||||
|
import { batchDelete, onExpand, closeAll, onCheck, addOne, showAddModel } from "./function.js";
|
||||||
|
|
||||||
const { TreeNode } = Tree;
|
const { TreeNode } = Tree;
|
||||||
|
|
||||||
@ -14,7 +15,15 @@ export default class OverView extends React.Component {
|
|||||||
treeData: [],
|
treeData: [],
|
||||||
isEdit: false,
|
isEdit: false,
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
expandKeys: ["0"]
|
checkedKeys: [],
|
||||||
|
expandKeys: [],
|
||||||
|
//显示新增弹窗
|
||||||
|
isShowModal: false,
|
||||||
|
//新增类别
|
||||||
|
addType: 0,
|
||||||
|
addName: "",
|
||||||
|
addValue: "",
|
||||||
|
file: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,12 +43,7 @@ export default class OverView extends React.Component {
|
|||||||
loadData = e =>
|
loadData = e =>
|
||||||
new Promise(resolve => {
|
new Promise(resolve => {
|
||||||
const item = e.props.dataRef;
|
const item = e.props.dataRef;
|
||||||
let newPath;
|
const newPath = item.path + "." + item.bookmarkId;
|
||||||
if (item.path === "") {
|
|
||||||
newPath = item.bookmarkId;
|
|
||||||
} else {
|
|
||||||
newPath = item.path + "." + item.bookmarkId;
|
|
||||||
}
|
|
||||||
if (this.data[newPath]) {
|
if (this.data[newPath]) {
|
||||||
item.children = this.data[newPath];
|
item.children = this.data[newPath];
|
||||||
this.setState({ treeData: [...this.state.treeData] });
|
this.setState({ treeData: [...this.state.treeData] });
|
||||||
@ -48,23 +52,14 @@ export default class OverView extends React.Component {
|
|||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
/**
|
|
||||||
* 复制url到剪贴板
|
|
||||||
* @param {*} key
|
|
||||||
* @param {*} e
|
|
||||||
*/
|
|
||||||
copyUrl(key, e) {}
|
|
||||||
|
|
||||||
deleteOne = e => {
|
|
||||||
const id = e.target.id;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
treeNodeSelect(key, e) {
|
treeNodeSelect(key, e) {
|
||||||
|
const { expandKeys } = this.state;
|
||||||
const item = e.node.props.dataRef;
|
const item = e.node.props.dataRef;
|
||||||
if (item.type === 0) {
|
if (item.type === 0) {
|
||||||
window.open(item.url);
|
window.open(item.url);
|
||||||
} else {
|
} else {
|
||||||
|
expandKeys.push(item.bookmarkId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,19 +68,19 @@ export default class OverView extends React.Component {
|
|||||||
* @param {*} item
|
* @param {*} item
|
||||||
*/
|
*/
|
||||||
renderNodeContent(item) {
|
renderNodeContent(item) {
|
||||||
const { isEdit } = this.state;
|
// const { isEdit } = this.state;
|
||||||
const bts = (
|
// const bts = (
|
||||||
<React.Fragment>
|
// <div className={styles.btns}>
|
||||||
<Button size="small" type="primary" name="copy" icon="copy" shape="circle" />
|
// <Button size="small" type="primary" name="copy" icon="copy" shape="circle" />
|
||||||
<Button size="small" type="danger" id={item.bookmarkId} icon="delete" shape="circle" onClick={this.deleteOne} />
|
// <Button size="small" type="danger" id={item.bookmarkId} icon="delete" shape="circle" onClick={this.deleteOne} />
|
||||||
</React.Fragment>
|
// </div>
|
||||||
);
|
// );
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Tooltip placement="bottom" title={item.url}>
|
<Tooltip placement="bottom" title={item.url}>
|
||||||
{item.name}
|
<span>{item.name}</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{isEdit ? bts : null}
|
{/* {isEdit ? bts : null} */}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -120,38 +115,108 @@ export default class OverView extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isLoading, isEdit, treeData, expandKeys } = this.state;
|
const { isLoading, isEdit, treeData, expandKeys, checkedKeys, isShowModal, addType, addValue, addName } = this.state;
|
||||||
|
const formItemLayout = {
|
||||||
|
labelCol: {
|
||||||
|
xs: { span: 4 },
|
||||||
|
sm: { span: 4 }
|
||||||
|
},
|
||||||
|
wrapperCol: {
|
||||||
|
xs: { span: 20 },
|
||||||
|
sm: { span: 20 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const uploadProps = {
|
||||||
|
accept: ".html,.htm",
|
||||||
|
onChange: e => {
|
||||||
|
this.setState({ file: e.fileList[0] });
|
||||||
|
},
|
||||||
|
beforeUpload: file => {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
fileList: []
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<div className={styles.main}>
|
<div className={styles.main}>
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<span>我的书签树</span>
|
<div className={styles.left}>
|
||||||
<div>
|
<span className={styles.myTree}>我的书签树</span>
|
||||||
|
{expandKeys.length > 0 ? (
|
||||||
|
<Button type="primary" size="small" onClick={closeAll.bind(this)}>
|
||||||
|
收起
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
<div className={styles.right}>
|
||||||
|
{isEdit ? (
|
||||||
|
<React.Fragment>
|
||||||
|
<Button size="small" type="danger" onClick={batchDelete.bind(this)}>
|
||||||
|
删除选中
|
||||||
|
</Button>
|
||||||
|
<Button size="small" type="primary" onClick={showAddModel.bind(this)}>
|
||||||
|
新增
|
||||||
|
</Button>
|
||||||
|
</React.Fragment>
|
||||||
|
) : null}
|
||||||
<Button size="small" type="primary" onClick={() => this.setState({ isEdit: !isEdit })}>
|
<Button size="small" type="primary" onClick={() => this.setState({ isEdit: !isEdit })}>
|
||||||
{isEdit ? "完成" : "编辑"}
|
{isEdit ? "完成" : "编辑"}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{treeData.length ? (
|
{/* {treeData.length ? ( */}
|
||||||
<Tree
|
<Tree
|
||||||
showIcon
|
showIcon
|
||||||
loadData={this.loadData}
|
checkedKeys={checkedKeys}
|
||||||
defaultExpandParent
|
onCheck={onCheck.bind(this)}
|
||||||
checkable={isEdit}
|
expandedKeys={expandKeys}
|
||||||
onSelect={this.treeNodeSelect}
|
loadData={this.loadData}
|
||||||
onDoubleClick={this.copyUrl}
|
onExpand={onExpand.bind(this)}
|
||||||
blockNode
|
defaultExpandParent
|
||||||
>
|
checkable={isEdit}
|
||||||
{this.renderTreeNodes(treeData)}
|
onSelect={this.treeNodeSelect}
|
||||||
</Tree>
|
onDoubleClick={this.copyUrl}
|
||||||
) : null}
|
blockNode
|
||||||
{isLoading === false && treeData.length === 0 ? (
|
>
|
||||||
<Empty description="还没有数据">
|
{this.renderTreeNodes(treeData)}
|
||||||
<Button size="small" type="primary" onClick={() => this.setState({ isEdit: true })}>
|
</Tree>
|
||||||
新增
|
{/* ) : null} */}
|
||||||
</Button>
|
{isLoading === false && treeData.length === 0 ? <Empty description="还没有数据" /> : null}
|
||||||
</Empty>
|
|
||||||
) : null}
|
<Modal destroyOnClose title="新增" visible={isShowModal} onCancel={() => this.setState({ isShowModal: false })} footer={false}>
|
||||||
|
<Form {...formItemLayout}>
|
||||||
|
<Form.Item label="类别">
|
||||||
|
<Radio.Group defaultValue={0} onChange={e => this.setState({ addType: e.target.value })}>
|
||||||
|
<Radio value={0}>书签</Radio>
|
||||||
|
<Radio value={1}>文件夹</Radio>
|
||||||
|
<Radio value={2}>上传书签html</Radio>
|
||||||
|
</Radio.Group>
|
||||||
|
</Form.Item>
|
||||||
|
{addType < 2 ? (
|
||||||
|
<Form.Item label="名称">
|
||||||
|
<Input type="text" onChange={e => this.setState({ addName: e.target.value })} value={addName} />
|
||||||
|
</Form.Item>
|
||||||
|
) : null}
|
||||||
|
{addType === 0 ? (
|
||||||
|
<Form.Item label="URL">
|
||||||
|
<Input type="text" value={addValue} onChange={e => this.setState({ addValue: e.target.value })} />
|
||||||
|
</Form.Item>
|
||||||
|
) : null}
|
||||||
|
{addType === 2 ? (
|
||||||
|
<Upload {...uploadProps}>
|
||||||
|
<Button type="primary">
|
||||||
|
<Icon type="upload" />
|
||||||
|
{this.state.file == null ? "选择文件" : this.state.file.name.substr(0, 20)}
|
||||||
|
</Button>
|
||||||
|
</Upload>
|
||||||
|
) : null}
|
||||||
|
<div style={{ textAlign: "center", paddingTop: "1em" }}>
|
||||||
|
<Button type="primary" onClick={addOne.bind(this)}>
|
||||||
|
提交
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
);
|
);
|
||||||
|
@ -5,5 +5,30 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.myTree {
|
||||||
|
font-size: 1.3em;
|
||||||
|
line-height: 1.3em;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 70%;
|
||||||
|
margin-right: 1em;
|
||||||
|
overflow-x: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btns {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
top: -0.45em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user