feat:优化重命名软件

This commit is contained in:
fanxb 2021-12-06 23:20:34 +08:00
parent 4e17b86554
commit 23d9c83593
11 changed files with 572 additions and 483 deletions

2
.gitignore vendored
View File

@ -102,5 +102,3 @@ dist
# TernJS port file
.tern-port
openRenamerBackend/database.db
openRenamerBackend/database.db

View File

@ -13,3 +13,4 @@ log
sqls/history.json
static/*
!static/.gitkeep
database.db

View File

@ -6,53 +6,53 @@ import ProcessHelper from '../util/ProcesHelper';
import FileObj from '../vo/FileObj';
class FileService {
static async readPath(pathStr: string, showHidden: boolean): Promise<Array<FileObj>> {
pathStr = decodeURIComponent(pathStr);
let fileList = new Array();
if (pathStr.trim().length == 0) {
//获取根目录路径
if (config.isWindows) {
//windows下
let std: string = ((await ProcessHelper.exec('wmic logicaldisk get caption')) as Object)['stdout'].replace('Caption', '');
fileList = std
.split('\r\n')
.filter((item) => item.trim().length > 0)
.map((item) => item.trim());
} else {
//linux下
pathStr = '/';
fileList = await fs.readdir(pathStr);
}
} else {
fileList = await fs.readdir(pathStr);
}
let folderList: Array<FileObj> = new Array();
let files: Array<FileObj> = new Array();
for (let index in fileList) {
try {
let stat = await fs.stat(path.join(pathStr, fileList[index]));
if (fileList[index].startsWith('.')) {
if (showHidden) {
(stat.isDirectory() ? folderList : files).push(
new FileObj(fileList[index], pathStr, stat.isDirectory(), stat.birthtime.getTime(), stat.mtime.getTime()),
);
}
} else {
(stat.isDirectory() ? folderList : files).push(
new FileObj(fileList[index], pathStr, stat.isDirectory(), stat.birthtime.getTime(), stat.mtime.getTime()),
);
}
} catch (e) {
console.error(e);
}
}
folderList.sort((a, b) => a.name.localeCompare(b.name)).push(...files.sort((a, b) => a.name.localeCompare(b.name)));
return folderList;
}
static async readPath(pathStr: string, showHidden: boolean): Promise<Array<FileObj>> {
pathStr = decodeURIComponent(pathStr);
let fileList = new Array();
if (pathStr.trim().length == 0) {
//获取根目录路径
if (config.isWindows) {
//windows下
let std: string = (await ProcessHelper.exec('wmic logicaldisk get caption')).replace('Caption', '');
fileList = std
.split('\r\n')
.filter((item) => item.trim().length > 0)
.map((item) => item.trim());
} else {
//linux下
pathStr = '/';
fileList = await fs.readdir(pathStr);
}
} else {
fileList = await fs.readdir(pathStr);
}
let folderList: Array<FileObj> = new Array();
let files: Array<FileObj> = new Array();
for (let index in fileList) {
try {
let stat = await fs.stat(path.join(pathStr, fileList[index]));
if (fileList[index].startsWith('.')) {
if (showHidden) {
(stat.isDirectory() ? folderList : files).push(
new FileObj(fileList[index], pathStr, stat.isDirectory(), stat.birthtime.getTime(), stat.mtime.getTime()),
);
}
} else {
(stat.isDirectory() ? folderList : files).push(
new FileObj(fileList[index], pathStr, stat.isDirectory(), stat.birthtime.getTime(), stat.mtime.getTime()),
);
}
} catch (e) {
console.error(e);
}
}
folderList.sort((a, b) => a.name.localeCompare(b.name)).push(...files.sort((a, b) => a.name.localeCompare(b.name)));
return folderList;
}
static async checkExist(pathStr: string) {
return await fs.pathExists(pathStr);
}
static async checkExist(pathStr: string) {
return await fs.pathExists(pathStr);
}
}
export default FileService;

View File

@ -11,13 +11,13 @@
"@element-plus/icons": "^0.0.11",
"axios": "^0.21.1",
"core-js": "^3.6.5",
"element-plus": "^1.0.2-beta.48",
"dayjs": "^1.10.7",
"element-plus": "^1.2.0-beta.5",
"vue": "^3.0.0",
"vue-router": "^4.0.0-0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",

View File

@ -6,7 +6,7 @@
@select="handleSelect"
>
<el-menu-item index="dealCenter">处理中心</el-menu-item>
<el-menu-item index="history">历史记录</el-menu-item>
<!-- <el-menu-item index="history">历史记录</el-menu-item> -->
</el-menu>
<router-view />
</template>

View File

@ -1,40 +1,22 @@
<template>
<div v-loading="loading" class="main">
<el-breadcrumb separator="/">
<el-breadcrumb-item
><a @click.prevent="breadcrumbClick(-1)"></a></el-breadcrumb-item
>
<el-breadcrumb-item><a @click.prevent="breadcrumbClick(-1)"></a></el-breadcrumb-item>
<el-breadcrumb-item v-for="(item, index) in pathList" :key="index">
<a
v-if="index < pathList.length - 1"
@click.prevent="breadcrumbClick(index)"
>{{ item }}</a
>
<a v-if="index < pathList.length - 1" @click.prevent="breadcrumbClick(index)">{{ item }}</a>
<span v-else>{{ item }}</span>
</el-breadcrumb-item>
</el-breadcrumb>
<div class="fileList">
<div>
<el-input
style="display: inline-block; width: 150px"
type="text"
size="small"
placeholder="关键词过滤"
v-model="filterText"
/>
<el-button type="primary" @click="selectAll(true)" size="mini"
>全选</el-button
>
<el-button type="primary" @click="selectAll(false)" size="mini"
>全不选</el-button
>
<el-input style="display: inline-block; width: 150px" type="text" size="small" placeholder="关键词过滤" v-model="filterText" />
<el-button type="primary" @click="selectAll(true)" size="mini">全选</el-button>
<el-button type="primary" @click="selectAll(false)" size="mini">全不选</el-button>
</div>
<div v-for="(item, index) in filterFileList" :key="index">
<span class="folder" v-if="item.isFolder" @click="fileClick(item)">{{
item.name
}}</span>
<el-checkbox v-model="item.checked" v-else>{{ item.name }}</el-checkbox>
<span class="folder" v-if="item.isFolder" @click="fileClick(item)">{{ item.name }}</span>
<el-checkbox style="height: 1.4em" v-model="item.checked" v-else>{{ item.name }}</el-checkbox>
</div>
</div>
@ -61,9 +43,7 @@ export default {
computed: {
filterFileList() {
let text = this.filterText.trim();
return text === ""
? this.fileList
: this.fileList.filter((item) => item.name.indexOf(text) > -1);
return text === "" ? this.fileList : this.fileList.filter((item) => item.name.indexOf(text) > -1);
},
},
async mounted() {
@ -95,19 +75,17 @@ export default {
},
//
selectAll(status) {
this.filterFileList
.filter((item) => !item.isFolder)
.forEach((item) => (item.checked = status));
this.filterFileList.filter((item) => !item.isFolder).forEach((item) => (item.checked = status));
},
//index
createPath(index) {
let path;
if (index == -1) {
path = "/";
path = "";
this.pathList = [];
} else {
this.pathList = this.pathList.slice(0, index + 1);
let str = this.pathList.join(this.isWindows ? "\\" : "/");
let str = this.pathList.join(this.isWindows ? "\\" : "/") + (this.isWindows ? "\\" : "/");
path = this.isWindows ? str : "/" + str;
}
return path;
@ -140,6 +118,7 @@ export default {
color: blue;
display: inline-block;
min-width: 3em;
line-height: 1.4em;
}
}
</style>

View File

@ -1,38 +1,20 @@
<template>
<div class="main">
<el-menu
style="width: 8em"
mode="vertical"
:default-active="currentIndex"
@select="menuChange"
>
<el-menu style="width: 8em" mode="vertical" :default-active="currentIndex" @select="menuChange">
<el-menu-item :disabled="editRule" index="insert">插入</el-menu-item>
<el-menu-item :disabled="editRule" index="delete">删除</el-menu-item>
<!-- <el-menu-item index="replace">替换</el-menu-item> -->
<el-menu-item :disabled="editRule" index="serialization"
>序列化</el-menu-item
>
<el-menu-item :disabled="editRule" index="serialization">序列化</el-menu-item>
</el-menu>
<div class="rule">
<insert-rule
ref="rule"
:editRule="editRule"
v-if="currentIndex == 'insert'"
/>
<delete-rule
ref="rule"
:editRule="editRule"
v-else-if="currentIndex == 'delete'"
/>
<serialization-rule
ref="rule"
:editRule="editRule"
v-else-if="currentIndex == 'serialization'"
/>
<insert-rule ref="rule" :editRule="editRule" v-if="currentIndex == 'insert'" />
<delete-rule ref="rule" :editRule="editRule" v-else-if="currentIndex == 'delete'" />
<serialization-rule ref="rule" :editRule="editRule" v-else-if="currentIndex == 'serialization'" />
</div>
</div>
<el-button type="primary" @click="submit">确定</el-button>
<div style="text-align: center">
<el-button type="primary" @click="submit">确定</el-button>
</div>
</template>
<script>

View File

@ -1,10 +1,10 @@
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import ElementPlus, { ElMessage } from 'element-plus';
import 'element-plus/lib/theme-chalk/index.css';
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import ElementPlus, { ElMessage } from "element-plus";
import "element-plus/dist/index.css";
const vueInstance = createApp(App);
vueInstance.use(router).use(ElementPlus).mount('#app');
vueInstance.use(router).use(ElementPlus).mount("#app");
vueInstance.config.globalProperties.$message = ElMessage;
window.vueInstance = vueInstance;

View File

@ -1,65 +1,44 @@
<template>
<div v-loading="loading" element-loading-text="后台处理中,请稍候">
<el-button type="primary" @click="dialogVisible = true" size="small">1.新增文件</el-button>
<el-button type="primary" @click="showResult" size="small">2.预览</el-button>
<el-button type="primary" @click="submit" size="small">3.重命名</el-button>
<br />
<el-button type="primary" @click="submit" size="default">重命名</el-button>
<br /><br />
<!-- 规则列表 -->
<div class="ruleList">
<div class="menu">
<span>应用规则</span>
<el-button type="primary" size="mini" @click="ruleDialogShow = true">新增</el-button>
<el-button type="primary" size="mini" v-if="checkedRules.length == 1" @click="editClick">编辑</el-button>
<el-button type="warning" size="mini" @click="block">禁用/启用</el-button>
<el-button type="danger" size="mini" @click="deleteRule">删除</el-button>
<el-button type="primary" size="mini" @click="saveOrUpdate">保存模板</el-button>
<el-button type="primary" size="mini" @click="ruleTemplateShow = true">选择模板</el-button>
</div>
<div class="ruleBlock">
<el-checkbox v-model="item.checked" v-for="(item, index) in ruleList" :key="index">
<s v-if="item.blocked">{{ item.message }}</s>
<span v-else>{{ item.message }}</span>
</el-checkbox>
</div>
</div>
<rule-block @ruleUpdate="ruleUpdate" />
<!-- 文件预览列表 -->
<div class="fileList">
<div>
文件列表
<el-button type="primary" @click="dialogVisible = true" size="small">新增</el-button>
<el-button type="primary" size="mini" @click="selectAllFiles">反选</el-button>
<el-button type="danger" size="mini" @click="deleteCheckedFiles">删除</el-button>
</div>
<div class="fileBlock">
<!-- 左侧原始文件名 -->
<el-checkbox style="display: block" v-for="(item, index) in fileList" :key="index" v-model="item.checked">
<div class="oneFileName">
{{ item.name }}
<ArrowDownBold
style="width: 20px; padding-left: 10px"
v-if="index < fileList.length - 1"
@click.stop.prevent="moveIndex(index + 1, index)"
/>
<ArrowUpBold style="width: 20px; padding-left: 10px" v-if="index > 0" @click.stop.prevent="moveIndex(index - 1, index)" />
<div class="oneLine" v-for="(item, index) in fileList" :key="index">
<!-- 左侧原始文件名 -->
<el-checkbox v-model="item.checked" class="left">
<div class="oneFileName">
{{ item.name }}
<ArrowDownBold
style="width: 20px; padding-left: 10px"
v-if="index < fileList.length - 1"
@click.stop.prevent="moveIndex(index + 1, index)"
/>
<ArrowUpBold style="width: 20px; padding-left: 10px" v-if="index > 0" @click.stop.prevent="moveIndex(index - 1, index)" />
</div>
</el-checkbox>
<!-- 修改后的文件名 -->
<div class="right">
{{ changedFileList.length > index ? changedFileList[index].name : "" }}
</div>
</el-checkbox>
</div>
<div class="fileBlock">
<!-- 右侧修改后的文件名-->
<div v-for="(item, index) in changedFileList" :key="index">
{{ item.name }}
</div>
</div>
</div>
<!-- 新增文件弹窗 -->
<el-dialog title="新增规则" v-model="ruleDialogShow" width="70%">
<rule :editRule="editRule" v-if="ruleDialogShow" @ruleAdd="ruleAdd" />
</el-dialog>
<el-dialog title="新增文件" v-model="dialogVisible" width="70%">
<file-chose @addData="addData" />
</el-dialog>
<el-dialog title="选择规则模板" v-model="ruleTemplateShow" width="70%">
<application-rule-list />
</el-dialog>
</div>
</template>
@ -68,80 +47,41 @@
import { ArrowDownBold, ArrowUpBold } from "@element-plus/icons";
import HttpUtil from "../../utils/HttpUtil";
import FileChose from "@/components/FileChose";
import ApplicationRuleList from "./components/ApplicationRuleList";
import Rule from "@/components/Rule";
import RuleBlock from "./components/RuleBlock.vue";
export default {
name: "Home",
components: {
FileChose,
Rule,
ArrowDownBold,
ArrowUpBold,
ApplicationRuleList,
RuleBlock,
},
data() {
return {
loading: false, //
dialogVisible: false, //
ruleDialogShow: false, //
ruleTemplateShow: false, //
ruleList: [], //
fileList: [],
changedFileList: [],
ruleList: [],
editRule: null, //
needPreview: false, //
applicationRule: null, //
};
},
computed: {
//
checkedRules() {
return this.ruleList.filter((item) => item.checked);
},
},
methods: {
//
async addData(data) {
data.forEach((item) => (item.checked = false));
this.fileList.push(...data);
this.dialogVisible = false;
console.log("asdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
this.needPreview = true;
await this.showResult();
},
//
async ruleAdd(data) {
data.checked = false;
data.blocked = false;
if (this.editRule != null) {
let index = this.ruleList.indexOf(this.editRule);
this.ruleList.splice(index, 1, data);
this.editRule = null;
} else {
this.ruleList.push(data);
}
this.ruleDialogShow = false;
async ruleUpdate(rules) {
this.ruleList = rules;
this.needPreview = true;
await this.showResult();
},
///
async block() {
this.ruleList.filter((item) => item.checked).forEach((item) => (item.blocked = !item.blocked));
this.needPreview = true;
await this.showResult();
},
//
async deleteRule() {
this.ruleList = this.ruleList.filter((item) => !item.checked);
this.needPreview = true;
await this.showResult();
},
//
editClick() {
this.editRule = this.checkedRules[0];
this.ruleDialogShow = true;
},
//
async showResult() {
if (!this.checkRuleAndFile()) {
@ -153,9 +93,11 @@ export default {
ruleList: this.ruleList.filter((item) => !item.blocked),
};
this.changedFileList = await HttpUtil.post("/renamer/preview", null, body);
this.fileList = [...this.fileList];
this.needPreview = false;
this.loading = false;
},
//
async submit() {
if (!this.checkRuleAndFile()) {
return;
@ -212,30 +154,24 @@ export default {
</script>
<style lang="less" scoped>
.ruleList {
border: 1px solid black;
padding: 5px;
.menu {
display: flex;
justify-content: left;
align-items: center;
}
.ruleBlock {
text-align: left;
display: flex;
flex-direction: column;
align-items: baseline;
}
}
.fileList {
margin-top: 20px;
text-align: left;
.fileBlock {
text-align: left;
display: inline-block;
width: 50%;
margin-top: 20px;
.oneLine {
display: flex;
border-top: 1px solid rgb(228, 224, 224);
.left {
flex: 1;
}
.right {
flex: 1;
display: flex;
align-items: center;
}
}
.oneFileName {
display: flex;

View File

@ -4,12 +4,19 @@
<el-table-column prop="createdDate" label="创建时间" width="180" />
<el-table-column prop="name" label="名称" width="180" />
<el-table-column prop="comment" label="备注" />
<el-table-column label="操作" width="120">
<template #default="scope">
<el-button type="text" size="small" @click="ruleTemplateAction('chose', scope.row)">选择</el-button>
<el-button type="text" size="small" @click="ruleTemplateAction('delete', scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import HttpUtil from "../../../utils/HttpUtil";
import dayjs from "dayjs";
export default {
name: "ApplicationRuleList",
data() {
@ -17,11 +24,26 @@ export default {
applicationRuleList: [],
};
},
async mounted() {
this.applicationRuleList = await HttpUtil.get("/applicationRule");
async created() {
this.init();
},
methods: {
async init() {
this.applicationRuleList = await HttpUtil.get("/applicationRule");
this.applicationRuleList.forEach((item) => (item.createdDate = dayjs(item.createdDate).format("YYYY-MM-DD")));
},
//
async ruleTemplateAction(action, rowData) {
if (action === "chose") {
await this.$emit("update:modelValue", rowData);
await this.$emit("close");
} else {
await HttpUtil.delete("/applicationRule/" + rowData.id);
await this.init();
}
},
},
};
</script>
<style>
</style>
<style></style>

View File

@ -0,0 +1,171 @@
<template>
<div class="main">
<div class="menu">
<span>应用规则</span>
<el-button type="primary" size="mini" @click="addRuleDialogShow = true">新增</el-button>
<el-button type="primary" size="mini" v-if="checkedRules.length == 1" @click="editClick">编辑</el-button>
<el-button type="warning" size="mini" @click="block">禁用/启用</el-button>
<el-button type="danger" size="mini" @click="deleteRule">删除</el-button>
<el-button type="primary" size="mini" v-if="chosedTemplate" @click="templateSubmit">保存规则</el-button>
<el-button type="primary" size="mini" v-if="chosedTemplate == null && ruleList.length > 0" @click="saveTemplateDilalogShow = true"
>存为模板</el-button
>
</div>
<div class="ruleBlock">
<el-checkbox v-model="item.checked" v-for="(item, index) in ruleList" :key="index">
<s v-if="item.blocked">{{ item.message }}</s>
<span v-else>{{ item.message }}</span>
</el-checkbox>
<div v-if="ruleList.length == 0 && chosedTemplate == null" class="choseTemplate">
<el-button type="primary" size="mini" @click="ruleTemplateShow = true">选择模板</el-button>
</div>
</div>
<!-- 弹窗 -->
<el-dialog title="新增规则" v-model="addRuleDialogShow" width="70%">
<rule :editRule="editRule" @ruleAdd="ruleAdd" />
</el-dialog>
<el-dialog title="选择规则模板" v-model="ruleTemplateShow" width="70%">
<application-rule-list v-if="ruleTemplateShow" v-model="chosedTemplate" @close="ruleTemplateShow = false" />
</el-dialog>
<el-dialog title="保存模板" v-model="saveTemplateDilalogShow" width="70%">
<el-form-item label="名称">
<el-input v-model="templateForm.name"></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="templateForm.comment"></el-input>
</el-form-item>
<template #footer>
<span class="dialog-footer">
<el-button @click="saveTemplateDilalogShow = false">取消</el-button>
<el-button type="primary" @click="templateSubmit">提交</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script>
import Rule from "../../../components/Rule";
import ApplicationRuleList from "./ApplicationRuleList";
import HttpUtil from "../../../utils/HttpUtil";
export default {
name: "RuleBlock",
components: {
Rule,
ApplicationRuleList,
},
data() {
return {
addRuleDialogShow: false, //
ruleTemplateShow: false, //
saveTemplateDilalogShow: false, //
ruleList: [],
editRule: null, //
chosedTemplate: null,
templateForm: {
name: "",
comment: "",
},
};
},
computed: {
//
checkedRules() {
return this.ruleList.filter((item) => item.checked);
},
},
watch: {
chosedTemplate(newVal, oldVal) {
this.ruleList = JSON.parse(newVal.content);
this.ruleUpdate();
},
},
methods: {
//
ruleUpdate() {
this.$emit(
"ruleUpdate",
this.ruleList.filter((item) => !item.blocked)
);
},
//
saveOrUpdateTemplate() {
if (this.chosedTemplate != null) {
this.templateSubmit();
} else {
this.saveTemplateDilalogShow = true;
}
},
//
async templateSubmit() {
let body;
if (this.chosedTemplate) {
this.chosedTemplate.content = JSON.stringify(this.ruleList);
body = this.chosedTemplate;
} else {
body = {
name: this.templateForm.name,
comment: this.templateForm.comment,
content: JSON.stringify(this.ruleList),
};
}
this.chosedTemplate = await HttpUtil.post("/applicationRule", null, body);
this.saveTemplateDilalogShow = false;
this.$message.success("操作成功");
},
//
async ruleAdd(data) {
data.checked = false;
data.blocked = false;
if (this.editRule != null) {
let index = this.ruleList.indexOf(this.editRule);
this.ruleList.splice(index, 1, data);
this.editRule = null;
} else {
this.ruleList.push(data);
}
this.ruleUpdate();
this.addRuleDialogShow = false;
},
///
async block() {
this.ruleList.filter((item) => item.checked).forEach((item) => (item.blocked = !item.blocked));
this.ruleUpdate();
},
//
async deleteRule() {
this.ruleList = this.ruleList.filter((item) => !item.checked);
this.ruleUpdate();
},
//
editClick() {
this.editRule = this.checkedRules[0];
this.ruleDialogShow = true;
},
},
};
</script>
<style lang="less" scoped>
.main {
text-align: left;
border: 1px solid black;
padding: 5px;
.menu {
display: flex;
justify-content: left;
align-items: center;
}
.ruleBlock {
text-align: left;
display: flex;
flex-direction: column;
align-items: baseline;
}
.choseTemplate {
text-align: center;
padding-top: 2em;
padding-bottom: 2em;
}
}
</style>