Compare commits

...
12 Commits
Author SHA1 Message Date
Simba 7728f403bb upload cancel. 2021-01-02 23:10:53 +08:00
lishuang fddace1ec7 Refine the variable scope. 2021-01-02 22:44:05 +08:00
lishuang 6a3a3c73e2 Fix the large file upload bug. 2021-01-02 22:35:44 +08:00
lishuang 6f0f8ec133 Fix the upload bug. 2021-01-02 22:30:22 +08:00
Simba effee4c5d2 upload matters. 2021-01-02 22:24:02 +08:00
lishuang 9ca81edc7e Fix the sort bug. 2021-01-02 20:38:19 +08:00
Simba 115ac7a5c2 matter list sort. 2021-01-02 20:14:59 +08:00
Simba ab73d7d679 preference recycle bin zero keep-day setting. 2021-01-02 17:48:42 +08:00
Simba c2666d4138 change soft del and hard del order. 2021-01-02 17:18:34 +08:00
Simba f2b81aad74 add scan immediately. 2021-01-02 17:08:18 +08:00
Simba 1f1770e037 a little optimization. 2021-01-02 16:31:24 +08:00
Simba 8928edb583 matter list delete option soft or hard. 2021-01-02 15:44:59 +08:00
21 changed files with 461 additions and 145 deletions
-3
View File
@@ -16,9 +16,6 @@ export default class Moon {
//全局唯一的偏好设置
preference: Preference = new Preference()
//全局上传通道
uploadMatters: Matter[] = [];
//全局的一个store对象
private static singleton: Moon | null = null
+6 -2
View File
@@ -142,7 +142,9 @@ let LangEn = {
recycleBin: "Recycle bin",
deleted: "Deleted",
unCompatibleBrowser: "The current browser does not support it. Please try choose another one",
canIUse: "To see if the current browser supports it"
canIUse: "To see if the current browser supports it",
intoRecycleBin: "Recycle bin",
finishingTip: "Please wait while files are sorted..."
},
router: {
allFiles: "All Files",
@@ -220,7 +222,9 @@ let LangEn = {
scanPerHour: "Scan every hour",
scanCustom: "Scan custom",
chooseUsers: "Fuzzy search users",
chooseUsersValidate: "choose one more user"
chooseUsersValidate: "choose one more user",
scanLoading: "waiting...",
matterBinDefaultTip: "set zero means to turn off the recycle bin"
},
share: {
shareDetail: "Share Detail",
+7 -2
View File
@@ -142,7 +142,9 @@ let LangZh = {
recycleBin: "回收站",
deleted: "已删除",
unCompatibleBrowser: "当前浏览器不支持,请切换浏览器尝试",
canIUse: "查看当前浏览器是否支持,点击跳转"
canIUse: "查看当前浏览器是否支持,点击跳转",
intoRecycleBin: "放入回收站",
finishingTip: "后台文件整理中,请稍候..."
},
router: {
allFiles: "全部文件",
@@ -220,7 +222,9 @@ let LangZh = {
scanPerHour: "每小时",
scanCustom: "自定义",
chooseUsers: "模糊搜索用户",
chooseUsersValidate: "请选择至少一个用户"
chooseUsersValidate: "请选择至少一个用户",
scanLoading: "扫描中,请稍后...",
matterBinDefaultTip: "设置0表示关闭回收站功能"
},
share: {
shareDetail: "分享详情",
@@ -337,6 +341,7 @@ let LangZh = {
required: "必填",
cancel: "取消",
delete: "删除",
deleteDirectly: "直接删除",
actionCanNotRevertConfirm: "此操作不可撤回, 是否继续?",
actionDeleteConfirm: "确定删除吗?",
actionRecoveryConfirm: "确定恢复吗?",
+33 -14
View File
@@ -1,4 +1,5 @@
import {message} from "antd";
import { message } from "antd";
import axios, { CancelTokenSource } from "axios";
import BaseEntity from "../base/BaseEntity";
import Filter from "../base/filter/Filter";
import HttpUtil from "../../util/HttpUtil";
@@ -52,6 +53,8 @@ export default class Matter extends BaseEntity {
progress: number = 0;
//实时上传速度 byte/s
speed: number = 0;
//取消上传source
cancelSource: CancelTokenSource = axios.CancelToken.source();
static URL_MATTER_CREATE_DIRECTORY = "/api/matter/create/directory";
static URL_MATTER_SOFT_DELETE = "/api/matter/soft/delete";
@@ -121,7 +124,7 @@ export default class Matter extends BaseEntity {
new InputFilter("分享uuid", "shareUuid"),
new InputFilter("提取码", "shareCode"),
new InputFilter("分享根目录", "shareRootUuid"),
new SortFilter('删除时间排序', 'orderDeleteTime'),
new SortFilter("删除时间排序", "orderDeleteTime"),
];
}
@@ -194,7 +197,7 @@ export default class Matter extends BaseEntity {
if (this.isImage()) {
ImagePreviewer.showSinglePhoto(previewUrl);
} else {
if(shareMode) {
if (shareMode) {
PreviewerHelper.preview(this, previewUrl);
} else {
PreviewerHelper.preview(this);
@@ -208,7 +211,7 @@ export default class Matter extends BaseEntity {
finallyCallback?: any
) {
let that = this;
let form = {userUuid: that.userUuid, name: that.name, puuid: that.puuid};
let form = { userUuid: that.userUuid, name: that.name, puuid: that.puuid };
return this.httpPost(
Matter.URL_MATTER_CREATE_DIRECTORY,
@@ -225,7 +228,7 @@ export default class Matter extends BaseEntity {
httpSoftDelete(successCallback?: any, errorCallback?: any) {
this.httpPost(
Matter.URL_MATTER_SOFT_DELETE,
{uuid: this.uuid},
{ uuid: this.uuid },
function (response: any) {
typeof successCallback === "function" && successCallback(response);
},
@@ -233,10 +236,14 @@ export default class Matter extends BaseEntity {
);
}
httpSoftDeleteBatch(uuids: string, successCallback?: any, errorCallback?: any) {
httpSoftDeleteBatch(
uuids: string,
successCallback?: any,
errorCallback?: any
) {
this.httpPost(
Matter.URL_MATTER_SOFT_DELETE_BATCH,
{uuids: uuids},
{ uuids: uuids },
function (response: any) {
typeof successCallback === "function" && successCallback(response);
},
@@ -247,7 +254,7 @@ export default class Matter extends BaseEntity {
httpDelete(successCallback?: any, errorCallback?: any) {
this.httpPost(
Matter.URL_MATTER_DELETE,
{uuid: this.uuid},
{ uuid: this.uuid },
function (response: any) {
typeof successCallback === "function" && successCallback(response);
},
@@ -258,7 +265,7 @@ export default class Matter extends BaseEntity {
httpDeleteBatch(uuids: string, successCallback?: any, errorCallback?: any) {
this.httpPost(
Matter.URL_MATTER_DELETE_BATCH,
{uuids: uuids},
{ uuids: uuids },
function (response: any) {
typeof successCallback === "function" && successCallback(response);
},
@@ -269,7 +276,7 @@ export default class Matter extends BaseEntity {
httpRecovery(successCallback?: any, errorCallback?: any) {
this.httpPost(
Matter.URL_MATTER_RECOVERY,
{uuid: this.uuid},
{ uuid: this.uuid },
function (response: any) {
typeof successCallback === "function" && successCallback(response);
},
@@ -280,7 +287,7 @@ export default class Matter extends BaseEntity {
httpRecoveryBatch(uuids: string, successCallback?: any, errorCallback?: any) {
this.httpPost(
Matter.URL_MATTER_RECOVERY_BATCH,
{uuids: uuids},
{ uuids: uuids },
function (response: any) {
typeof successCallback === "function" && successCallback(response);
},
@@ -297,7 +304,7 @@ export default class Matter extends BaseEntity {
let that = this;
this.httpPost(
Matter.URL_MATTER_RENAME,
{uuid: this.uuid, name: name},
{ uuid: this.uuid, name: name },
function (response: any) {
that.assign(response.data.data);
typeof successCallback === "function" && successCallback(response);
@@ -315,7 +322,7 @@ export default class Matter extends BaseEntity {
let that = this;
this.httpPost(
Matter.URL_CHANGE_PRIVACY,
{uuid: this.uuid, privacy: privacy},
{ uuid: this.uuid, privacy: privacy },
function (response: any) {
that.privacy = privacy;
if (typeof successCallback === "function") {
@@ -335,7 +342,7 @@ export default class Matter extends BaseEntity {
successCallback?: any,
errorCallback?: any
) {
let form: any = {srcUuids: srcUuids};
let form: any = { srcUuids: srcUuids };
if (destUuid) {
form.destUuid = destUuid;
} else {
@@ -495,6 +502,11 @@ export default class Matter extends BaseEntity {
SafeUtil.safeCallback(successCallback)(response);
},
function (err: any) {
if (axios.isCancel(err)) {
that.clear();
SafeUtil.safeCallback(failureCallback)();
return;
}
const response = err.response;
that.errorMessage = response;
that.clear();
@@ -524,10 +536,17 @@ export default class Matter extends BaseEntity {
);
}
that.updateUI();
},
{
cancelToken: that.cancelSource.token,
}
);
}
cancelUpload() {
this.cancelSource.cancel();
}
//清除文件
clear() {
//filter,privacy不变
+11
View File
@@ -12,6 +12,7 @@ export default class Preference extends BaseEntity {
static URL_API_SYSTEM_CLEANUP = '/api/preference/system/cleanup'
static URL_API_PREFERENCE_EDIT_PREVIEW_CONFIG = '/api/preference/edit/preview/config'
static URL_API_PREFERENCE_EDIT_SCAN = '/api/preference/edit/scan/config'
static URL_API_PREFERENCE_SCAN_ONCE = '/api/preference/scan/once'
//网站名称
@@ -61,6 +62,10 @@ export default class Preference extends BaseEntity {
this.assignEntity("scanConfig", ScanConfig)
}
getRecycleBinStatus() {
return this.deletedKeepDays > 0
}
getForm(): any {
return {
name: this.name,
@@ -141,6 +146,12 @@ export default class Preference extends BaseEntity {
}
httpScanOnce(successCallback?: any, errorCallback?: any, finalCallback?: any) {
this.httpGet(Preference.URL_API_PREFERENCE_SCAN_ONCE, {}, function (response: any) {
SafeUtil.safeCallback(successCallback)(response);
}, errorCallback, finalCallback)
}
}
+40 -49
View File
@@ -1,91 +1,82 @@
import axios, {AxiosRequestConfig} from "axios";
import axios, { AxiosRequestConfig } from "axios";
import SafeUtil from "./SafeUtil";
//http请求全部收口在这个工具类中,可以快速切换http框架。
export default class HttpUtil {
static httpGet(url: any, params = {}, successCallback?: any, errorCallback?: any, finallyCallback?: any, opts?: any) {
static httpGet(
url: any,
params = {},
successCallback?: any,
errorCallback?: any,
finallyCallback?: any,
opts?: any
) {
axios
.get(url, {
params: params
params: params,
})
.then(function (response) {
SafeUtil.safeCallback(successCallback)(response)
SafeUtil.safeCallback(successCallback)(response);
})
.catch(function (error) {
SafeUtil.safeCallback(errorCallback)(error)
SafeUtil.safeCallback(errorCallback)(error);
})
.finally(function () {
SafeUtil.safeCallback(finallyCallback)()
SafeUtil.safeCallback(finallyCallback)();
});
}
static httpPost(url: any, params = {}, successCallback?: any, errorCallback?: any, finallyCallback?: any, opts?: any) {
static httpPost(
url: any,
params = {},
successCallback?: any,
errorCallback?: any,
finallyCallback?: any,
opts?: any
) {
return axios
.post(url, params, opts)
.then(function (response) {
SafeUtil.safeCallback(successCallback)(response)
SafeUtil.safeCallback(successCallback)(response);
})
.catch(function (error) {
SafeUtil.safeCallback(errorCallback)(error)
SafeUtil.safeCallback(errorCallback)(error);
})
.finally(function () {
SafeUtil.safeCallback(finallyCallback)()
SafeUtil.safeCallback(finallyCallback)();
});
}
/**
* 上传文件的请求
*/
static httpPostFile(url: string,
formData: FormData,
successCallback?: any,
errorCallback?: any,
finallyCallback?: any,
processCallback?: (progressEvent: any) => void,
opts?: any) {
static httpPostFile(
url: string,
formData: FormData,
successCallback?: any,
errorCallback?: any,
finallyCallback?: any,
processCallback?: (progressEvent: any) => void,
opts?: any
) {
const config: AxiosRequestConfig = {
headers: {
'Content-Type': 'multipart/form-data'
"Content-Type": "multipart/form-data",
},
onUploadProgress: processCallback
}
cancelToken: opts ? opts.cancelToken : "",
onUploadProgress: processCallback,
};
axios
.post(url, formData, config)
.then(function (response) {
SafeUtil.safeCallback(successCallback)(response)
SafeUtil.safeCallback(successCallback)(response);
})
.catch(function (error) {
SafeUtil.safeCallback(errorCallback)(error)
SafeUtil.safeCallback(errorCallback)(error);
})
.finally(function () {
SafeUtil.safeCallback(finallyCallback)()
SafeUtil.safeCallback(finallyCallback)();
});
}
}
+5
View File
@@ -91,6 +91,11 @@ export default class SideLayout extends TankComponent<IProps, IState> {
mode="inline"
>
{menuItems.map((menuItem: MenuItem, index: number) => {
if (
menuItem.url === "/bin/list" &&
!preference.getRecycleBinStatus()
)
return null;
return (
<Menu.Item key={menuItem.url}>
{menuItem.icon}
+66 -41
View File
@@ -1,5 +1,5 @@
import React, { Children } from "react";
import { RouteComponentProps } from "react-router-dom";
import React, {Children} from "react";
import {RouteComponentProps} from "react-router-dom";
import "./List.less";
import TankComponent from "../../common/component/TankComponent";
import Pager from "../../common/model/base/Pager";
@@ -22,23 +22,24 @@ import {
} from "antd";
import MessageBoxUtil from "../../common/util/MessageBoxUtil";
import {
ExclamationCircleFilled,
CloudUploadOutlined,
PlusSquareOutlined,
MinusSquareOutlined,
FolderOutlined,
SyncOutlined,
DeleteOutlined,
DownloadOutlined,
DragOutlined,
ExclamationCircleFilled,
FolderOutlined,
MinusSquareOutlined,
PlusSquareOutlined,
ShareAltOutlined,
SyncOutlined,
} from "@ant-design/icons";
import ImagePreviewer from "../widget/previewer/ImagePreviewer";
import Sun from "../../common/model/global/Sun";
import { UserRole } from "../../common/model/user/UserRole";
import {UserRole} from "../../common/model/user/UserRole";
import StringUtil from "../../common/util/StringUtil";
import MoveBatchModal from "./widget/MoveBatchModal";
import ShareOperationModal from "./widget/ShareOperationModal";
import MatterDeleteModal from "./widget/MatterDeleteModal";
import Share from "../../common/model/share/Share";
import ShareDialogModal from "../share/widget/ShareDialogModal";
import BreadcrumbModel from "../../common/model/base/option/BreadcrumbModel";
@@ -46,18 +47,20 @@ import BreadcrumbPanel from "../widget/BreadcrumbPanel";
import Lang from "../../common/model/global/Lang";
import FileUtil from "../../common/util/FileUtil";
import SafeUtil from "../../common/util/SafeUtil";
import MatterSortPanel from "./widget/MatterSortPanel";
interface IProps extends RouteComponentProps {}
interface IProps extends RouteComponentProps {
}
interface IState {}
interface IState {
}
export default class List extends TankComponent<IProps, IState> {
//当前文件夹信息。
matter = new Matter();
//准备新建的文件。
newMatter = new Matter();
//准备上传的一系列文件
uploadMatters = Moon.getSingleton().uploadMatters;
//当前选中的文件
selectedMatters: Matter[] = [];
//搜索的文字
@@ -83,8 +86,16 @@ export default class List extends TankComponent<IProps, IState> {
//上传错误日志
uploadErrorLogs: [string, string, string][] = [];
//准备上传的一系列文件
static uploadMatters: Matter[] = [];
//持有全局唯一的实例。
static instance: List | null = null
constructor(props: IProps) {
super(props);
List.instance = this
}
//拖拽上传
@@ -137,6 +148,7 @@ export default class List extends TankComponent<IProps, IState> {
};
componentDidMount() {
//刷新一下列表
if (this.user.role === UserRole.ADMINISTRATOR) {
this.pager.getFilter("userUuid")!.visible = true;
@@ -154,6 +166,7 @@ export default class List extends TankComponent<IProps, IState> {
this.refresh();
}
}
componentWillUnmount() {
this.drag.remove();
}
@@ -225,17 +238,21 @@ export default class List extends TankComponent<IProps, IState> {
};
deleteBatch = () => {
Modal.confirm({
title: Lang.t("actionDeleteConfirm"),
icon: <ExclamationCircleFilled twoToneColor="#FFDC00" />,
onOk: () => {
const uuids = this.selectedMatters.map((i) => i.uuid).toString();
const uuids = this.selectedMatters.map((i) => i.uuid).toString();
MatterDeleteModal.open(
() => {
this.matter.httpSoftDeleteBatch(uuids, () => {
MessageBoxUtil.success(Lang.t("operationSuccess"));
this.refresh();
});
},
});
() => {
this.matter.httpDeleteBatch(uuids, () => {
MessageBoxUtil.success(Lang.t("operationSuccess"));
this.refresh();
});
}
);
};
downloadZip = () => {
@@ -254,14 +271,14 @@ export default class List extends TankComponent<IProps, IState> {
};
triggerUpload = (fileObj: any) => {
const { file } = fileObj;
const {file} = fileObj;
if (file) this.launchUpload(file);
};
debounce = (func: Function, wait: number) => {
let timer: any = null;
return (fileObj: any) => {
const { file } = fileObj;
const {file} = fileObj;
this.tempUploadList.push(file);
if (timer) {
clearTimeout(timer);
@@ -279,7 +296,7 @@ export default class List extends TankComponent<IProps, IState> {
const url = FileUtil.getErrorLogsToCSVUrl(this.uploadErrorLogs);
Modal.confirm({
title: Lang.t("matter.uploadInfo"),
icon: <ExclamationCircleFilled twoToneColor="#FFDC00" />,
icon: <ExclamationCircleFilled twoToneColor="#FFDC00"/>,
content: Lang.t("matter.uploadErrorInfo"),
okText: Lang.t("matter.exportCSV"),
onOk: () => {
@@ -346,7 +363,8 @@ export default class List extends TankComponent<IProps, IState> {
launchUpload = (
f: File | FileList,
puuid = this.matter.uuid!,
errHandle = () => {}
errHandle = () => {
}
) => {
const files = f instanceof FileList ? f : [f];
for (let i = 0; i < files.length; i++) {
@@ -370,14 +388,18 @@ export default class List extends TankComponent<IProps, IState> {
}
m.file = file;
m.httpUpload(
() => this.refresh(),
() => {
const index = List.uploadMatters.findIndex((matter) => matter === m);
List.uploadMatters.splice(index, 1);
List.instance!.refresh();
},
(msg: string) => {
this.updateUI();
List.instance!.updateUI();
SafeUtil.safeCallback(errHandle)(msg);
}
);
this.uploadMatters.push(m);
List.uploadMatters.push(m);
}
};
@@ -444,7 +466,7 @@ export default class List extends TankComponent<IProps, IState> {
this.pager.setFilterValue("puuid", id);
this.pager.page = 0;
const query = this.pager.getParams();
Sun.navigateQueryTo({ path: "/matter/list", query });
Sun.navigateQueryTo({path: "/matter/list", query});
this.refresh();
};
@@ -504,24 +526,23 @@ export default class List extends TankComponent<IProps, IState> {
pager,
director,
selectedMatters,
uploadMatters,
dragEnterCount,
} = this;
return (
<div className="matter-list">
{dragEnterCount > 0 ? (
<div className="obscure">
<CloudUploadOutlined className="white f50" />
<CloudUploadOutlined className="white f50"/>
</div>
) : null}
<BreadcrumbPanel breadcrumbModels={this.breadcrumbModels} />
<BreadcrumbPanel breadcrumbModels={this.breadcrumbModels}/>
<Row className="mt10">
<Col xs={24} sm={24} md={14} lg={16}>
<Space className="buttons">
{selectedMatters.length !== pager.data.length ? (
<Button type="primary" className="mb10" onClick={this.checkAll}>
<PlusSquareOutlined />
<PlusSquareOutlined/>
{Lang.t("selectAll")}
</Button>
) : null}
@@ -532,7 +553,7 @@ export default class List extends TankComponent<IProps, IState> {
className="mb10"
onClick={this.checkNone}
>
<MinusSquareOutlined />
<MinusSquareOutlined/>
{Lang.t("cancel")}
</Button>
) : null}
@@ -543,7 +564,7 @@ export default class List extends TankComponent<IProps, IState> {
className="mb10"
onClick={this.deleteBatch}
>
<DeleteOutlined />
<DeleteOutlined/>
{Lang.t("delete")}
</Button>
@@ -552,7 +573,7 @@ export default class List extends TankComponent<IProps, IState> {
className="mb10"
onClick={this.downloadZip}
>
<DownloadOutlined />
<DownloadOutlined/>
{Lang.t("download")}
</Button>
@@ -561,7 +582,7 @@ export default class List extends TankComponent<IProps, IState> {
className="mb10"
onClick={this.toggleMoveBatch}
>
<DragOutlined />
<DragOutlined/>
{Lang.t("matter.move")}
</Button>
@@ -570,7 +591,7 @@ export default class List extends TankComponent<IProps, IState> {
className="mb10"
onClick={this.shareBatch}
>
<ShareAltOutlined />
<ShareAltOutlined/>
{Lang.t("matter.share")}
</Button>
</>
@@ -583,7 +604,7 @@ export default class List extends TankComponent<IProps, IState> {
multiple
>
<Button type="primary" className="mb10">
<CloudUploadOutlined />
<CloudUploadOutlined/>
{Lang.t("matter.upload")}
</Button>
</Upload>
@@ -594,7 +615,7 @@ export default class List extends TankComponent<IProps, IState> {
directory
>
<Button type="primary" className="mb10">
<CloudUploadOutlined />
<CloudUploadOutlined/>
{Lang.t("matter.uploadDir")}
</Button>
</Upload>
@@ -603,12 +624,12 @@ export default class List extends TankComponent<IProps, IState> {
className="mb10"
onClick={this.createDirectory}
>
<FolderOutlined />
<FolderOutlined/>
{Lang.t("matter.create")}
</Button>
<Button type="primary" className="mb10" onClick={this.refresh}>
<SyncOutlined />
<SyncOutlined/>
{Lang.t("refresh")}
</Button>
</Space>
@@ -625,9 +646,13 @@ export default class List extends TankComponent<IProps, IState> {
</Row>
{Children.toArray(
uploadMatters.map((m) => <UploadMatterPanel matter={m} />)
List.uploadMatters.map((m) => <UploadMatterPanel matter={m}/>)
)}
{pager.data.length ? (
<MatterSortPanel pager={pager} refresh={() => this.refresh()}/>
) : null}
{director.createMode ? (
<MatterPanel
ref={this.newMatterRef}
@@ -650,7 +675,7 @@ export default class List extends TankComponent<IProps, IState> {
/>
))
) : (
<Empty description={Lang.t("matter.noContentYet")} />
<Empty description={Lang.t("matter.noContentYet")}/>
)}
</div>
<Pagination
@@ -0,0 +1,5 @@
.delete-modal {
.ant-modal-body {
padding-bottom: 0;
}
}
@@ -0,0 +1,76 @@
import React from "react";
import TankComponent from "../../../common/component/TankComponent";
import { Modal, Button } from "antd";
import Lang from "../../../common/model/global/Lang";
import Moon from "../../../common/model/global/Moon";
import { ExclamationCircleFilled } from "@ant-design/icons";
import "./MatterDeleteModal.less";
import Preference from "../../../common/model/preference/Preference";
interface IProps {
onSoftDel: () => void;
onHardDel: () => void;
onClose: () => void;
}
interface IState {}
export default class MatterDeleteModal extends TankComponent<IProps, IState> {
constructor(props: IProps) {
super(props);
}
static preference: Preference = Moon.getSingleton().preference;
static open(onSoftDel: () => void, onHardDel: () => void) {
let modal = Modal.warning({
className: "delete-modal",
title: Lang.t("delete"),
icon: <ExclamationCircleFilled twoToneColor="#FFDC00" />,
okCancel: false,
okButtonProps: {
className: "display-none",
},
content: (
<MatterDeleteModal
onSoftDel={() => {
onSoftDel();
modal.destroy();
}}
onHardDel={() => {
onHardDel();
modal.destroy();
}}
onClose={() => {
modal.destroy();
}}
/>
),
});
}
render() {
return (
<div className="matter-delete-modal">
<p>{Lang.t("actionDeleteConfirm")}</p>
<div className="mt30 text-right">
<Button className="mr10" onClick={this.props.onClose}>
{Lang.t("cancel")}
</Button>
<Button
type="primary"
danger
onClick={this.props.onHardDel}
>
{Lang.t("deleteDirectly")}
</Button>
{MatterDeleteModal.preference.getRecycleBinStatus() && (
<Button type="primary" className="ml10" onClick={this.props.onSoftDel}>
{Lang.t("matter.intoRecycleBin")}
</Button>
)}
</div>
</div>
);
}
}
+1
View File
@@ -102,6 +102,7 @@
.matter-date {
.basic-span;
width: 110px;
}
}
+10 -5
View File
@@ -27,6 +27,7 @@ import { CheckboxChangeEvent } from "antd/es/checkbox";
import SafeUtil from "../../../common/util/SafeUtil";
import ClipboardUtil from "../../../common/util/ClipboardUtil";
import Lang from "../../../common/model/global/Lang";
import MatterDeleteModal from "./MatterDeleteModal";
interface IProps {
matter: Matter;
@@ -93,16 +94,20 @@ export default class MatterPanel extends TankComponent<IProps, IState> {
};
deleteMatter = () => {
Modal.confirm({
title: Lang.t("actionDeleteConfirm"),
icon: <ExclamationCircleFilled twoToneColor="#FFDC00" />,
onOk: () => {
MatterDeleteModal.open(
() => {
this.props.matter.httpSoftDelete(() => {
MessageBoxUtil.success(Lang.t("operationSuccess"));
this.props.onDeleteSuccess!();
});
},
});
() => {
this.props.matter.httpDelete(() => {
MessageBoxUtil.success(Lang.t("operationSuccess"));
this.props.onDeleteSuccess!();
});
}
);
};
hardDeleteMatter = () => {
@@ -0,0 +1,33 @@
.matter-sort-panel {
display: flex;
align-items: center;
background-color: white;
height: 48px;
margin: 0;
line-height: 48px;
color: #999;
.sort-part {
&:hover {
cursor: pointer;
background-color: aliceblue;
}
&-name {
flex-grow: 1;
padding-left: 10px;
}
&-size {
flex-shrink: 0;
flex-basis: 90px;
padding-left: 10px;
cursor: pointer;
}
&-date {
flex-shrink: 0;
flex-basis: 130px;
padding: 0 10px;
cursor: pointer;
}
}
}
@@ -0,0 +1,84 @@
import './MatterSortPanel.less'
import React from "react";
import Matter from "../../../common/model/matter/Matter";
import TankComponent from "../../../common/component/TankComponent";
import SortDirection from "../../../common/model/base/SortDirection";
import {ArrowDownOutlined, ArrowUpOutlined,} from "@ant-design/icons";
import Pager from "../../../common/model/base/Pager";
interface IProps {
pager: Pager<Matter>,
refresh: () => any
}
interface IState {
}
export default class MatterSortPanel extends TankComponent<IProps, IState> {
static sortAutomaton = [SortDirection.ASC, SortDirection.DESC, null]; // 排序状态自动机:ASC -> DESC -> null -> ASC...
changeFilterOrder = (orderName: string) => {
const {pager} = this.props;
["orderName", "orderSize", "orderUpdateTime"]
.filter((name) => name !== orderName)
.forEach((key) => {
pager.setFilterValue(key, null);
});
const filter = pager.getFilterValue(orderName);
const nextSortIndex = (MatterSortPanel.sortAutomaton.findIndex((key) => key === filter) + 1) % 3;
pager.resetSortFilters()
pager.setFilterValue("orderDir", SortDirection.DESC);
pager.setFilterValue(orderName, MatterSortPanel.sortAutomaton[nextSortIndex]);
this.props.refresh();
};
render() {
const {pager} = this.props;
return (
<div className="matter-sort-panel">
<div
className="sort-part sort-part-name"
onClick={() => this.changeFilterOrder("orderName")}
>
文件名
{pager.getFilterValue("orderName") ? (
pager.getFilterValue("orderName") === SortDirection.ASC ? (
<ArrowUpOutlined className="ml5 f10"/>
) : (
<ArrowDownOutlined className="ml5 f10"/>
)
) : null}
</div>
<div
className="sort-part sort-part-size"
onClick={() => this.changeFilterOrder("orderSize")}
>
大小
{pager.getFilterValue("orderSize") ? (
pager.getFilterValue("orderSize") === SortDirection.ASC ? (
<ArrowUpOutlined className="ml5 f10"/>
) : (
<ArrowDownOutlined className="ml5 f10"/>
)
) : null}
</div>
<div
className="sort-part sort-part-date"
onClick={() => this.changeFilterOrder("orderUpdateTime")}
>
修改日期
{pager.getFilterValue("orderUpdateTime") ? (
pager.getFilterValue("orderUpdateTime") === SortDirection.ASC ? (
<ArrowUpOutlined className="ml5 f10"/>
) : (
<ArrowDownOutlined className="ml5 f10"/>
)
) : null}
</div>
</div>
);
}
}
+2 -1
View File
@@ -5,7 +5,7 @@ import Pager from "../../../common/model/base/Pager";
import Matter from "../../../common/model/matter/Matter";
import "./MoveBatchModal.less";
import Lang from "../../../common/model/global/Lang";
import { FolderFilled, FolderOpenFilled } from "@ant-design/icons";
import { FolderFilled, FolderOpenFilled, ExclamationCircleFilled } from "@ant-design/icons";
interface IProps {
onSuccess: (uuid: string) => any;
@@ -37,6 +37,7 @@ export default class MoveBatchModal extends TankComponent<IProps, IState> {
let modal = Modal.confirm({
className: "move-modal",
title: Lang.t("matter.moveTo"),
icon: <ExclamationCircleFilled twoToneColor="#FFDC00" />,
width: "90vw",
okCancel: false,
okButtonProps: {
@@ -1,6 +1,7 @@
import React from "react";
import TankComponent from "../../../common/component/TankComponent";
import { Modal, Button, Col, Row, Select } from "antd";
import { ExclamationCircleFilled } from "@ant-design/icons";
import "./ShareOperationModal.less";
import Share from "../../../common/model/share/Share";
import {
@@ -27,6 +28,7 @@ export default class ShareOperationModal extends TankComponent<IProps, IState> {
const modal = Modal.confirm({
className: "share-modal",
title: Lang.t("matter.share"),
icon: <ExclamationCircleFilled twoToneColor="#FFDC00" />,
width: "90vw",
okCancel: false,
okButtonProps: {
@@ -13,6 +13,8 @@
}
.media {
display: flex;
justify-content: space-between;
.media-body {
cursor: pointer;
color: #555;
+21 -4
View File
@@ -3,6 +3,7 @@ import TankComponent from "../../../common/component/TankComponent";
import Matter from "../../../common/model/matter/Matter";
import StringUtil from "../../../common/util/StringUtil";
import { Progress } from "antd";
import { CloseOutlined } from "@ant-design/icons";
import "./UploadMatterPanel.less";
import Lang from "../../../common/model/global/Lang";
@@ -19,9 +20,18 @@ export default class UploadMatterPanel extends TankComponent<IProps, IState> {
}
format = (percent: number) => {
return `${percent.toFixed(1)}%`
return `${percent.toFixed(1)}%`;
};
componentDidMount() {
this.props.matter.reactComponent = this;
}
componentWillReceiveProps(nextProps: Readonly<IProps>, nextContext: any) {}
componentWillUnmount() {
this.props.matter.reactComponent = null;
}
render() {
const { matter } = this.props;
return (
@@ -30,6 +40,9 @@ export default class UploadMatterPanel extends TankComponent<IProps, IState> {
<div className="huge-block clearfix">
<div className="media">
<div className="media-body">{matter.file!.name}</div>
<div className="media-cancel">
<CloseOutlined onClick={() => matter.cancelUpload()} />
</div>
</div>
<Progress
className="progress"
@@ -44,9 +57,13 @@ export default class UploadMatterPanel extends TankComponent<IProps, IState> {
<div>
{`${Lang.t("matter.uploaded")}: ${StringUtil.humanFileSize(
matter.file!.size * matter.progress
)}/${StringUtil.humanFileSize(
matter.file!.size
)} ${Lang.t("matter.speed")}:${StringUtil.humanFileSize(matter.speed)}s`}
)}/${StringUtil.humanFileSize(matter.file!.size)} ${
matter.progress < 1
? `${Lang.t("matter.speed")}:${StringUtil.humanFileSize(
matter.speed
)}s`
: Lang.t("matter.finishingTip")
}`}
</div>
</div>
) : null}
+4 -2
View File
@@ -15,7 +15,6 @@ import MessageBoxUtil from "../../common/util/MessageBoxUtil";
import Sun from "../../common/model/global/Sun";
import Lang from "../../common/model/global/Lang";
import MatterImage from "../matter/widget/MatterImage";
import PreviewConfigPanel from "./widget/PreviewConfigPanel";
interface IProps extends RouteComponentProps {
}
@@ -214,8 +213,11 @@ export default class Edit extends TankComponent<IProps, IState> {
]}
noStyle
>
<InputNumber min={1} className="w150" />
<InputNumber min={0} className="w150" />
</Form.Item>
<span className="pl10">
{Lang.t("preference.matterBinDefaultTip")}
</span>
</Form.Item>
<Form.Item
+51 -21
View File
@@ -1,12 +1,16 @@
import React, { Children } from "react";
import { Link, RouteComponentProps } from "react-router-dom";
import React, {Children} from "react";
import {Link, RouteComponentProps} from "react-router-dom";
import "./Index.less";
import TankComponent from "../../common/component/TankComponent";
import User from "../../common/model/user/User";
import Moon from "../../common/model/global/Moon";
import TankTitle from "../widget/TankTitle";
import { Button, Divider, Empty, Tag, Tooltip } from "antd";
import { EditOutlined, ThunderboltOutlined } from "@ant-design/icons";
import {Button, Divider, Empty, Tag, Tooltip, message} from "antd";
import {
EditOutlined,
ThunderboltOutlined,
ScanOutlined,
} from "@ant-design/icons";
import InfoCell from "../widget/InfoCell";
import Preference from "../../common/model/preference/Preference";
import TankContentCard from "../widget/TankContentCard";
@@ -22,9 +26,11 @@ import {
import PreviewEngineCell from "./widget/PreviewEngineCell";
import PreviewEngine from "../../common/model/preference/model/PreviewEngine";
interface IProps extends RouteComponentProps {}
interface IProps extends RouteComponentProps {
}
interface IState {}
interface IState {
}
export default class Index extends TankComponent<IProps, IState> {
user: User = Moon.getSingleton().user;
@@ -65,9 +71,21 @@ export default class Index extends TankComponent<IProps, IState> {
);
}
immediateScan() {
const hide = message.loading(Lang.t("preference.scanLoading"), 0);
this.preference.httpScanOnce(
() => {
message.success(Lang.t("operationSuccess"));
},
null,
hide
);
}
render() {
const {
previewConfig: { previewEngines },
previewConfig: {previewEngines},
scanConfig,
} = this.preference;
@@ -79,7 +97,7 @@ export default class Index extends TankComponent<IProps, IState> {
type={"primary"}
danger={true}
onClick={this.cleanup.bind(this)}
icon={<ThunderboltOutlined />}
icon={<ThunderboltOutlined/>}
>
{Lang.t("preference.systemCleanup")}
</Button>
@@ -90,7 +108,7 @@ export default class Index extends TankComponent<IProps, IState> {
<header>
<p className="title">{Lang.t("preference.basic")}</p>
<Link to={"/preference/edit"}>
<Button type={"primary"} icon={<EditOutlined />}>
<Button type={"primary"} icon={<EditOutlined/>}>
{Lang.t("edit")}
</Button>
</Link>
@@ -127,13 +145,13 @@ export default class Index extends TankComponent<IProps, IState> {
<InfoCell name={Lang.t("preference.copyright")}>
<span
dangerouslySetInnerHTML={{ __html: this.preference.copyright }}
dangerouslySetInnerHTML={{__html: this.preference.copyright}}
/>
</InfoCell>
<InfoCell name={Lang.t("preference.extraInfo")}>
<span
dangerouslySetInnerHTML={{ __html: this.preference.record }}
dangerouslySetInnerHTML={{__html: this.preference.record}}
/>
</InfoCell>
@@ -166,13 +184,13 @@ export default class Index extends TankComponent<IProps, IState> {
</InfoCell>
</div>
<Divider />
<Divider/>
<div className="preview-info">
<header>
<p className="title">{Lang.t("preference.preview")}</p>
<Link to={"/preference/engine/edit"}>
<Button type={"primary"} icon={<EditOutlined />}>
<Button type={"primary"} icon={<EditOutlined/>}>
{Lang.t("edit")}
</Button>
</Link>
@@ -187,22 +205,34 @@ export default class Index extends TankComponent<IProps, IState> {
))}
{Children.toArray(
PreviewEngine.defaultPreviewEngines().map((engine) => (
<PreviewEngineCell engine={engine} />
<PreviewEngineCell engine={engine}/>
))
)}
</div>
</div>
<Divider />
<Divider/>
<div className="scan-info">
<header>
<p className="title">{Lang.t("preference.scan")}</p>
<Link to={"/preference/scan/edit"}>
<Button type={"primary"} icon={<EditOutlined />}>
{Lang.t("edit")}
</Button>
</Link>
<div>
{scanConfig.enable ? (
<Button
type="primary"
className="mr10"
icon={<ScanOutlined/>}
onClick={() => this.immediateScan()}
>
立即扫描
</Button>) : ""}
<Link to={"/preference/scan/edit"}>
<Button type={"primary"} icon={<EditOutlined/>}>
{Lang.t("edit")}
</Button>
</Link>
</div>
</header>
<div className="content">
{scanConfig.enable ? (
@@ -220,7 +250,7 @@ export default class Index extends TankComponent<IProps, IState> {
)}
</>
) : (
<Empty description={Lang.t("preference.disabledScan")} />
<Empty description={Lang.t("preference.disabledScan")}/>
)}
</div>
</div>
+2 -1
View File
@@ -2,7 +2,7 @@ import React from "react";
import TankComponent from "../../../common/component/TankComponent";
import Share from "../../../common/model/share/Share";
import {Button, Modal} from "antd";
import { CopyOutlined } from "@ant-design/icons";
import { CopyOutlined, ExclamationCircleFilled } from "@ant-design/icons";
import DateUtil from "../../../common/util/DateUtil";
import MessageBoxUtil from "../../../common/util/MessageBoxUtil";
import './ShareDialogModal.less';
@@ -38,6 +38,7 @@ export default class ShareDialogModal extends TankComponent<IProps, IState> {
let modal = Modal.confirm({
className: "share-modal",
title: Lang.t("share.shareDetail"),
icon: <ExclamationCircleFilled twoToneColor="#FFDC00" />,
width: "90vw",
okCancel: false,
okButtonProps: {