基于Vue+express+postgresql的文件管理系统
·
先看一下效果图

一、客户端
<!--test_table-->
<template>
<div>
<el-card>
<el-upload
ref="upload"
action="/api/upload/addPicture"
:file-list="fileList"
:auto-upload="true"
:on-success="handleAvatarSuccess"
:show-file-list="false"
multiple
>
<el-button slot="trigger" type="primary">上传文件</el-button>
</el-upload>
<br />
<el-button @click="handleBatchDownload()">批量下载</el-button>
<el-input
placeholder="输入文件名搜索"
v-model="input_searchFileName"
class="input-with-select"
style="width: 400px; float: right"
>
<el-button slot="append" icon="el-icon-search"></el-button>
</el-input>
<div style="margin: 20px 0">
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">全部文件</el-breadcrumb-item>
<el-breadcrumb-item>目录1</el-breadcrumb-item>
</el-breadcrumb>
</div>
<el-table
ref="multipleTable"
:data="tableData"
tooltip-effect="dark"
style="width: 100%"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column prop="filename" label="文件名" width="220">
</el-table-column>
<el-table-column prop="size" label="大小" width="220">
</el-table-column>
<el-table-column prop="mimetype" label="类型" width="220">
</el-table-column>
<el-table-column prop="updatetime" label="上传日期" width="220">
</el-table-column>
<el-table-column
prop="filepath"
label="文件路径"
width="220"
v-if="false"
>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button
size="mini"
@click="handlePreview(scope.$index, scope.row)"
>预览</el-button
>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
import axios from "axios";
import JSZip from "jszip";
import FileSaver from "file-saver";
export default {
name: "",
components: {},
data() {
return {
tableData: [],
multipleSelection: [],
fileList: [],
input_searchFileName: "",
};
},
props: {},
created() {},
mounted() {},
computed: {},
methods: {
toggleSelection(rows) {
if (rows) {
rows.forEach((row) => {
this.$refs.multipleTable.toggleRowSelection(row);
});
} else {
this.$refs.multipleTable.clearSelection();
}
},
handleSelectionChange(val) {
this.multipleSelection = val;
console.log("this.multipleSelection", this.multipleSelection);
},
handlePreview(index, row) {
window.open("/api" + row.filepath);
},
handleDelete(index, row) {
console.log(index, row);
},
handleAvatarSuccess(res, file) {
let { filename, size, mimetype, updatetime, filepath } = res.info;
console.log("filepath", filepath);
size = (size / 1024).toFixed(2) + " KB";
this.tableData.unshift({
filename,
size,
mimetype,
updatetime,
filepath,
});
},
getFile(url) {
return new Promise((resolve, reject) => {
axios({
method: "get",
url,
responseType: "arraybuffer", //必须加这个!可处理txt、png、mp4、tif等格式,不能处理docx、pptx,xlsx
})
.then((res) => {
resolve(res.data);
})
.catch((error) => {
reject(error.toString());
});
});
},
handleBatchDownload() {
if (this.multipleSelection.length == 0) {
this.$message.error("请选择下载文件");
return;
}
let filePathSelected = this.multipleSelection.map((item) => {
return "/api" + item.filepath;
});
const zip = new JSZip();
const cache = {};
const promises = [];
filePathSelected.forEach((item) => {
const promise = this.getFile(item).then((data) => {
// 下载文件, 并存成ArrayBuffer对象
const arr_name = item.split("/");
const file_name = arr_name[arr_name.length - 1]; // 获取文件名
zip.file(file_name, data, { binary: true }); // 逐个添加文件
cache[file_name] = data;
});
promises.push(promise);
});
// Promise.all可以将多个Promise实例包装成一个新的Promise实例。
// 同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,
// 而失败的时候则返回最先被reject失败状态的值。
Promise.all(promises).then(() => {
zip.generateAsync({ type: "blob" }).then((content) => {
// 生成二进制流
FileSaver.saveAs(content, "打包下载.zip"); // 利用file-saver保存文件
this.$message.success("下载成功");
});
});
},
},
watch: {},
};
</script>
<style lang="scss" scoped>
</style>
处理跨域,项目根目录下新建vue.config.js
module.exports = {
lintOnSave: false, //取消eslint检测
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000', //设置开发环境服务域名和端口号 别忘了加http
changeOrigin: true, //這裡true表示实现跨域
pathRewrite: {
'^/api': ''
}
}
}
}
}
二、服务端

连接数据库。项目根目录下新建db.js
即:server/db.js
var pgsql = require("pg");
var pool = new pgsql.Pool({
host: 'localhost', //连接本地数据库
user: 'postgres',
password: 'user',
database: 'test_file_manage'
});
function query(sql, callback) {
pool.connect(function (err, connection) {
connection.query(sql, function (err, result) {
callback(err, result);
connection.release();
});
});
}
exports.query = query;
server/routes/upload.js
// routes/upload.js
var express = require('express');
var router = express.Router();
const multer = require('multer');
var dayjs=require('dayjs')
var db = require('../db.js')
const storage = multer.diskStorage({
//存储的位置
destination: 'public/uploadFiles/', // 保存的路径,备注:需要自己创建
//文件名字的确定 multer默认帮我们取一个没有扩展名的文件名,因此需要我们自己定义
filename(req, file, cb) {
// cb(null, Date.now() + file.originalname)
cb(null, file.originalname)
}
})
const upload = multer({
storage
})
router.post('/addPicture', upload.single('file'), (req, res) => {
//线上的也就是服务器中的图片的绝对地址
let { mimetype, filename, size } = req.file;
let filepath = '/uploadFiles/' + filename
let updatetime=dayjs(new Date()).format("YYYY-MM-DD")
let sql_add = `insert into files(filename,mimetype,size,filepath,updatetime) values ('${filename}','${mimetype}',${size},'${filepath}','${updatetime}')`;
db.query(sql_add, function (err, rows) {
if (err) {
console.log('err:', err.message);
} else {
console.log("rows:", rows);
const data = {
code: 1,
msg: "success",
info: {
mimetype, filename, size,filepath,updatetime
}
}
res.send(data)
}
});
})
module.exports = router;
app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var uploadRouter = require('./routes/upload')
var cors=require("cors")
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(cors())
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/upload', uploadRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
const port=3000;
app.listen(port,function(){
console.log(`服务器运行在 http://localhost:${port}`)
})
module.exports = app;
三、数据库

更多推荐



所有评论(0)