123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- <template>
- <div v-loading="listLoading" class="app-container page-component__scroll">
- <div class="filter-container">
- <div v-if="selectedCount" class="filter-control">
- <el-button
- type="primary"
- size="small"
- icon="el-icon-edit"
- plain
- :disabled="selectedCount > 1"
- @click="onEditFile"
- >编辑</el-button>
- <el-button type="primary" size="small" icon="el-icon-rank" plain @click="onMoveFile">移动</el-button>
- <el-button type="primary" size="small" icon="el-icon-download" plain @click="onDownload">下载</el-button>
- <el-button type="primary" size="small" icon="el-icon-delete" plain @click="onDelete">删除</el-button>
- </div>
- <template v-else>
- <div class="filter-control">
- <OssUpload
- ref="ossUpload"
- :limit="999"
- :delay-upload="delayUpload"
- :multiple="true"
- :button-group="buttonGroup"
- :on-success="onSuccess"
- :on-error="onError"
- @typeChange="onOssUploadTypeChange"
- />
- </div>
- <div class="filter-control">
- <el-button
- type="primary"
- size="small"
- icon="el-icon-folder-add"
- plain
- @click="onCreateDir"
- >新建文件夹</el-button>
- <el-button
- type="primary"
- size="small"
- icon="el-icon-s-promotion"
- plain
- @click="onPublishArticle"
- >发布文章</el-button>
- <el-button
- type="primary"
- size="small"
- icon="el-icon-alarm-clock"
- plain
- @click="onUploadHistory"
- >上传记录</el-button>
- </div>
- </template>
- </div>
- <!-- 面包屑 -->
- <el-breadcrumb separator-class="el-icon-arrow-right">
- <el-breadcrumb-item :to="{ path: '/docs/0/list' }">全部文件</el-breadcrumb-item>
- <template v-for="(item, index) in crumbList">
- <template v-if="index === crumbList.length - 1">
- <el-breadcrumb-item :key="item.id">
- <span class="cell">{{ item.fileName }}</span>
- </el-breadcrumb-item>
- </template>
- <template v-else>
- <el-breadcrumb-item :key="item.id" :to="{ path: `/docs/${item.id}/list` }">
- <span>{{ item.fileName | crumbFormat }}</span>
- </el-breadcrumb-item>
- </template>
- </template>
- </el-breadcrumb>
- <!-- 列表 -->
- <el-table
- :data="list"
- style="width: 100%"
- :row-style="{ cursor: 'pointer' }"
- @selection-change="onSelectionChange"
- @row-dblclick="onRowClick"
- >
- <el-table-column type="selection" align="center" width="50" />
- <el-table-column label="文件名">
- <template slot-scope="{ row }">
- <doc-icon v-if="!listLoading" :type="row.fileType" :src="row.screenshot" />
- <span v-if="row.fileType === 'article'" class="file-name" @click.stop="onRowClick(row)">{{
- row.fileName | fileNameFormat
- }}</span>
- <span v-else class="file-name" @click.stop="onRowClick(row)">{{ row.fileName }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="createTime" label="时间" width="160">
- <template slot-scope="{ row }">{{ row.saveTime | formatTime }}</template>
- </el-table-column>
- <el-table-column label="大小" width="120">
- <template slot-scope="{ row }">
- <span v-if="row.packageType > 0">{{ row.fileSize | fileSize }}</span>
- <span v-else>-</span>
- </template>
- </el-table-column>
- </el-table>
- <!-- 创建文件夹弹窗 -->
- <el-dialog :title="editText" :visible.sync="editDialog" width="30%" :close-on-click-modal="false" @close="onCancel">
- <el-form ref="ruleForm" :model="formData" :rules="rules" label-width="80">
- <el-form-item prop="fileName" label="名称:">
- <el-input v-model="formData.fileName" placeholder="请输入文件名" @keyup.enter.native="onSubmit" />
- </el-form-item>
- </el-form>
- <span slot="footer" class="dialog-footer">
- <el-button @click="editDialog = false">取 消</el-button>
- <el-button type="primary" @click="onSubmit">确 定</el-button>
- </span>
- </el-dialog>
- <!-- 移动文件 -->
- <el-dialog title="选择移动位置" :visible.sync="moveDialog" width="60%" :close-on-click-modal="false">
- <el-button icon="el-icon-arrow-left" :disabled="lastDisabled" size="mini" @click="currentIndex--" />
- <el-button icon="el-icon-arrow-right" :disabled="nextDisabled" size="mini" @click="currentIndex++" />
- <el-table
- :data="filterSameDir(moveCurrentDir.childList)"
- :row-style="{ cursor: 'pointer' }"
- style="width: 100%"
- :height="300"
- empty-text="该目录为空"
- @row-dblclick="onMoveRowClick"
- >
- <el-table-column label="文件名">
- <template slot-scope="{ row }">
- <doc-icon v-if="!listLoading" :type="row.fileType" />
- <span class="file-name" @click.stop="onMoveRowClick(row)">{{ row.fileName }}</span>
- </template>
- </el-table-column>
- </el-table>
- <span slot="footer" class="dialog-footer">
- <el-button @click="onMoveCancel">取 消</el-button>
- <el-button type="primary" @click="onSubmitMove">确 定</el-button>
- </span>
- </el-dialog>
- </div>
- </template>
- <script>
- import DocIcon from '@/views/components/DocIcon'
- import { OssUpload } from '@/components/OssUpload'
- import {
- createPackage,
- fetchDocsList,
- removePackage,
- saveFile,
- updatePackage,
- fetchPathCumbs,
- fetchDirTree,
- movePackage,
- saveFileWithDir
- } from '@/api/doc'
- import { downloadWithUrl } from '@/utils/tools'
- export default {
- name: 'DocsAllList',
- components: { DocIcon, OssUpload },
- filters: {
- fileSize(size) {
- size = Math.round(size / 1024)
- if (size < 1024) return size + 'KB'
- size = Math.round(size / 1024)
- if (size < 1024) return size + 'MB'
- return Math.round(size / 1024) + 'GB'
- },
- crumbFormat(name) {
- if (name.length < 12) return name
- return name.substring(0, 10) + '…'
- },
- fileNameFormat(name) {
- return name.replace(/(.+)(.txt$)/, (match, $1, $2) => {
- return $1
- })
- }
- },
- data() {
- const fileNameValidate = (rule, value, callback) => {
- if (/[\\\/\[\]\|^%&',;=?$\x22]+/g.test(value)) {
- callback(new Error("文件名不能包含|\/\\^%&',;=?$等特殊字符"))
- } else {
- callback()
- }
- }
- return {
- selectionList: [], // 选中列表
- list: [],
- fileId: 0,
- editDialog: false,
- moveDialog: false,
- listLoading: false,
- formData: {
- fileName: '',
- fileId: ''
- },
- rules: {
- fileName: [
- { required: true, message: '文件名不能为空', trigger: ['blur'] },
- { validator: fileNameValidate, trigger: ['blur'] }
- ]
- },
- editType: '',
- current: null,
- crumbList: [],
- currentDirStack: [],
- currentIndex: 0,
- message: null,
- buttonGroup: [
- {
- type: 'file',
- color: 'primary',
- text: '上传文件',
- size: 'small',
- plain: true,
- icon: 'el-icon-upload2'
- },
- {
- type: 'folder',
- color: 'primary',
- text: '上传文件夹',
- size: 'small',
- plain: true,
- icon: 'el-icon-upload2'
- }
- ],
- uploadType: 'record',
- delayUpload: false
- }
- },
- computed: {
- selectedCount() {
- return this.selectionList.length
- },
- editText() {
- const texts = {
- editType: '创建文件夹',
- editFile: '修改文件'
- }
- return texts[this.editType]
- },
- moveCurrentDir() {
- return this.currentDirStack[this.currentIndex] || []
- },
- lastDisabled() {
- return this.currentIndex === 0 || this.currentDirStack.length === 0
- },
- nextDisabled() {
- return this.currentIndex === this.currentDirStack.length - 1 || this.currentDirStack.length === 0
- }
- },
- created() {
- this.init()
- },
- activated() {
- this.init()
- },
- methods: {
- // 排除相同文件夹
- filterSameDir(dirList) {
- if (!dirList) dirList = []
- return dirList.filter((item) => {
- return !this.selectionList.find((file) => file.id === item.id)
- })
- },
- // 获取文件夹结构
- async fetchDirTree() {
- try {
- const res = await fetchDirTree()
- res.data.fileName = '根目录'
- this.currentDirStack.push(res.data)
- this.currentIndex = this.currentDirStack.length - 1
- } catch (error) {
- console.log(error)
- }
- },
- // 处理面包屑
- generateCrumb(node) {
- const list = []
- if (!node) return list
- function recursive(node) {
- list.push(node)
- if (node.childNode) {
- recursive(node.childNode)
- }
- }
- recursive(node)
- return list
- },
- // 页面初始化
- init() {
- this.fileId = parseInt(this.$route.params.fileId)
- if (!this.fileId && this.fileId !== 0) return
- this.fetchDocsList()
- this.fetchPathCumbs()
- },
- // 获取面包屑导航
- async fetchPathCumbs() {
- try {
- const res = await fetchPathCumbs({ fileId: this.fileId })
- this.crumbList = this.generateCrumb(res.data)
- } catch (error) {
- console.log(error)
- }
- },
- // 获取资料库列表
- async fetchDocsList() {
- try {
- this.listLoading = true
- const res = await fetchDocsList({ fileId: this.fileId })
- this.list = res.data || []
- this.listLoading = false
- } catch (error) {
- console.log(error)
- }
- },
- // 保存上传文件
- async saveUploadFile(data) {
- try {
- await saveFile(data)
- this.fetchDocsList()
- if (this.message) this.message.close()
- this.message = this.$message.success('文件上传成功')
- } catch (error) {
- console.log(error)
- }
- },
- // 保存上传文件夹
- async saveUploadDir(fileList) {
- try {
- await saveFileWithDir({ params: fileList })
- this.fetchDocsList()
- if (this.message) this.message.close()
- this.message = this.$message.success('文件上传成功')
- } catch (error) {
- console.log(error)
- }
- },
- // 取消保存
- onCancel() {
- this.formData.fileId = ''
- this.formData.fileName = ''
- this.$refs.ruleForm.clearValidate()
- },
- // 保存
- async onSubmit() {
- const actions = {
- createDir: this.onSaveDir,
- editFile: this.onUpdateFile
- }
- try {
- await this.$refs.ruleForm.validate()
- actions[this.editType]()
- } catch (error) {
- console.log(error)
- }
- },
- // 保存文件夹
- async onSaveDir() {
- try {
- this.formData.fileId = this.fileId
- await createPackage(this.formData)
- this.fetchDocsList()
- this.editDialog = false
- this.$message.success('文件夹创建成功')
- } catch (error) {
- console.log(error)
- }
- },
- // 修改文件名
- async onUpdateFile() {
- try {
- await updatePackage(this.formData)
- this.fetchDocsList()
- this.editDialog = false
- this.$message.success('文件名修改成功')
- } catch (error) {
- console.log(error)
- }
- },
- // 选择文件并上传
- onChooseFile() {
- this.$refs.ossUpload.chooseFile()
- },
- // 上传成功
- onSuccess(res, file, fileList) {
- if (this.uploadType === 'folder') {
- this.onUploadWithDir(fileList)
- } else {
- this.onUploadWithFile(file)
- }
- },
- formatFileData(file) {
- const strList = file.name.split('.')
- const ossName = file.uuid + '.' + strList[strList.length - 1]
- return {
- fileName: file.name,
- ossName: ossName,
- ossUrl: file.ossUrl,
- fileSize: file.size,
- parentId: this.fileId,
- mime: file.raw.type,
- filePath: file.raw.webkitRelativePath || ''
- }
- },
- // 文件上传
- onUploadWithFile(file) {
- this.saveUploadFile(this.formatFileData(file))
- },
- // 文件夹上传
- onUploadWithDir(fileList) {
- const uploadFiles = fileList.map((file) => this.formatFileData(file))
- console.log(uploadFiles)
- this.saveUploadDir(uploadFiles)
- },
- // 上传错误
- onError(error) {
- console.log(error)
- },
- // 上传方式修改
- onOssUploadTypeChange(type) {
- this.uploadType = type
- this.delayUpload = type === 'folder'
- },
- // 查看历史记录
- onUploadHistory() {
- this.$refs.ossUpload.showRecord()
- },
- // 创建文件夹
- onCreateDir() {
- this.editType = 'createDir'
- this.editDialog = true
- },
- // 发布文章
- onPublishArticle() {
- const url = `/docs/article-edit?parentId=${this.fileId}`
- this.$router.push(url)
- },
- // 编辑文件
- onEditFile() {
- this.current = this.selectionList[0]
- if (this.current.fileType === 'article') {
- // 文章
- const url = `/docs/article-edit?parentId=${this.current.parentId}&articleId=${this.current.articleId}`
- this.$router.push(url)
- } else {
- this.editType = 'editFile'
- this.editDialog = true
- this.formData.fileName = this.current.fileName
- this.formData.fileId = this.current.id
- }
- },
- // 移动文件
- onMoveFile() {
- this.currentDirStack = []
- this.currentIndex = 0
- this.fetchDirTree()
- this.moveDialog = true
- },
- // 移动取消
- onMoveCancel() {
- this.moveDialog = false
- this.fetchDocsList()
- },
- // 移动确认
- async onSubmitMove() {
- const current = this.currentDirStack[this.currentIndex]
- const filedIds = this.selectionList.map((file) => file.id).join(',')
- try {
- await movePackage({ fileId: filedIds, parentId: current.id })
- this.moveDialog = false
- this.fetchDocsList()
- this.$message.success('文件移动成功')
- } catch (error) {
- console.log(error)
- }
- },
- // 下载文件
- async onDownload() {
- const confirmText = '文件'
- let fileName = '文件'
- const filedIds = this.selectionList.map((file) => file.id).join(',')
- const text = await this.$confirm(`确认下载所选${confirmText}?`, '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).catch(() => {
- this.exportClubList = []
- this.$message.info('已取消操作')
- })
- if (text !== 'confirm') return
- let notification = null
- notification = this.$notify({
- title: '提示',
- message: `正在下载${confirmText},请勿重复操作!`,
- duration: 0
- })
- // 下载链接
- let downUrl = ''
- if (this.selectionList.length === 1) {
- const target = this.selectionList[0]
- fileName = target.fileName
- if (target.packageType > 0) {
- downUrl = `${process.env.VUE_APP_BASE_API}/download/file?ossName=${
- target.ossName
- }&fileName=${encodeURIComponent(target.fileName)}`
- } else {
- downUrl = `${process.env.VUE_APP_BASE_API}/database/path/package/zip?fileId=${
- target.id
- }&fileName=${encodeURIComponent(target.fileName)}`
- }
- } else {
- // 使用a链接下载
- downUrl = `${process.env.VUE_APP_BASE_API}/database/path/chose/zip?fileId=${filedIds}`
- }
- downloadWithUrl(downUrl, fileName, {
- headers: {
- 'X-Token': this.$store.getters.token
- }
- })
- .then((res) => {
- this.fetchDocsList()
- })
- .catch((err) => {
- console.log(err)
- this.$message.error(`下载${confirmText}失败`)
- })
- .finally(() => {
- notification.close()
- })
- },
- // 删除文件
- async onDelete(file) {
- const tip = file.packageType > 0 ? '确定删除该文件夹及其文件夹内的全部文件?' : '确定删除该文件?'
- let confirm = ''
- try {
- confirm = await this.$confirm(tip, '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- })
- } catch (error) {
- console.log(error)
- this.$message.info('已取消操作')
- }
- if (confirm !== 'confirm') return false
- // 获取要删除的文件id
- const filedIds = this.selectionList.map((file) => file.id).join(',')
- try {
- this.listLoading = true
- await removePackage({ fileId: filedIds })
- this.fetchDocsList()
- this.$message.success('删除成功')
- this.listLoading = false
- } catch (error) {
- console.log(error)
- }
- },
- // 表格内容勾选
- onSelectionChange(val) {
- this.selectionList = val
- },
- // 文件点击
- onRowClick(row) {
- if (row.fileType === 'article') {
- // 文章
- const url = `/docs/article-edit?parentId=${row.parentId}&articleId=${row.articleId}`
- this.$router.push(url)
- } else if (row.packageType === 1) {
- // 其它文件
- console.log('详情')
- this.$router.push(`/docs/detail?id=${row.id}`)
- } else {
- this.$router.push(`/docs/${row.id}/list`)
- this.$store.dispatch('tagsView/delView', this.$route)
- }
- },
- // 移动位置点击
- onMoveRowClick(row) {
- if (this.currentIndex === this.currentDirStack.length - 1) {
- this.currentDirStack.push(row)
- this.currentIndex = this.currentDirStack.length - 1
- } else {
- this.currentDirStack.splice(this.currentIndex + 1, this.currentDirStack.length)
- this.currentDirStack.push(row)
- this.currentIndex = this.currentDirStack.length - 1
- }
- }
- }
- }
- </script>
- <style scoped lang="scss">
- .file-name {
- font-size: 14px;
- color: #666666;
- margin-left: 25px;
- cursor: pointer;
- line-height: 32px;
- }
- .file-name:hover {
- color: #1890ff;
- }
- .el-breadcrumb {
- margin: 16px 0;
- .cell {
- color: #999;
- }
- }
- </style>
|