feat: 添加直链功能
- 新增直链相关 API 和工具函数 - 实现直链对话框组件 - 在文件上下文菜单中添加直链相关选项 - 优化文件上下文菜单样式和布局
This commit is contained in:
parent
0d07b963b7
commit
b8b0471f48
1
public/resource/font_2024484_0fh6xrzocbtk.js
Normal file
1
public/resource/font_2024484_0fh6xrzocbtk.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
40
src/api/direct-file.js
Normal file
40
src/api/direct-file.js
Normal file
@ -0,0 +1,40 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export default {
|
||||
/**
|
||||
* 创建直链
|
||||
* @param params
|
||||
* @returns {*}
|
||||
*/
|
||||
createDirectLink: function(params) {
|
||||
return request({
|
||||
url: 'direct-link/create',
|
||||
method: 'post',
|
||||
params
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 重置直链
|
||||
* @param params
|
||||
* @returns {*}
|
||||
*/
|
||||
resetDirectLink: function(params) {
|
||||
return request({
|
||||
url: 'direct-link/reset',
|
||||
method: 'put',
|
||||
params
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 重置直链
|
||||
* @param params
|
||||
* @returns {*}
|
||||
*/
|
||||
resetAllDirectLink: function(params) {
|
||||
return request({
|
||||
url: 'direct-link/reset-all',
|
||||
method: 'delete',
|
||||
params
|
||||
})
|
||||
},
|
||||
}
|
||||
118
src/components/DirectLinkDialog/index.vue
Normal file
118
src/components/DirectLinkDialog/index.vue
Normal file
@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--直链-->
|
||||
<el-dialog :title="'直链 - ' + filename" :style="{ fontWeight: 600 }" :visible.sync="dialogVisible" @close="dialogClose">
|
||||
<div>
|
||||
<div class="direct-file-content">
|
||||
<el-input placeholder="" v-model="directUrl" readonly></el-input>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button round size="small" type="danger" @click="resetAllDirectLink" :loading="resetAllLoading">重置所有直链</el-button>
|
||||
<el-button round size="small" @click="resetDirectLink" :loading="resetLoading">重置直链</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
import directFileApi from '@/api/direct-file'
|
||||
import fileConfig from '@/utils/file-config'
|
||||
import { copyText } from '@/utils/copy-text'
|
||||
|
||||
export default {
|
||||
name: "DirectLinkDialog",
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
status: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
file: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
filename: '',
|
||||
directUrl: '',
|
||||
resetLoading: false,
|
||||
resetAllLoading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
status(visible) {
|
||||
if (visible) {
|
||||
this.dialogVisible = true
|
||||
this.filename = this.file.name
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
dialogClose() {
|
||||
this.$emit('update:status', this.dialogVisible)
|
||||
},
|
||||
getDirectLink(file, isCopy) {
|
||||
directFileApi.createDirectLink({ fileId: file.id }).then(res => {
|
||||
this.directUrl = fileConfig.directFileUrl(res.data, file)
|
||||
if (isCopy) {
|
||||
copyText(this.directUrl)
|
||||
}
|
||||
})
|
||||
},
|
||||
resetDirectLink() {
|
||||
this.resetLoading = true
|
||||
this.$confirm('确定要重置该直链吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
directFileApi.resetDirectLink({ fileId: this.file.id }).then(res => {
|
||||
this.directUrl = fileConfig.directFileUrl(res.data, this.file)
|
||||
this.resetLoading = false
|
||||
this.$message.success('重置成功')
|
||||
}).catch(() => {
|
||||
this.resetLoading = false
|
||||
}
|
||||
)
|
||||
}).catch(() => {
|
||||
this.resetLoading = false
|
||||
}
|
||||
)
|
||||
},
|
||||
resetAllDirectLink() {
|
||||
this.resetAllLoading = true
|
||||
|
||||
this.$confirm('确定要重置所有直链吗? 此用户下的所有直链都将失效', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
directFileApi.resetAllDirectLink({ fileId: this.file.id }).then(res => {
|
||||
this.directUrl = fileConfig.directFileUrl(res.data, this.file)
|
||||
this.resetAllLoading = false
|
||||
this.$message.success('重置所有直链成功')
|
||||
}).catch(() => {
|
||||
this.resetAllLoading = false
|
||||
}
|
||||
)
|
||||
}).catch(() => {
|
||||
this.resetAllLoading = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
import { Icon } from 'ant-design-vue'
|
||||
const IconFont = Icon.createFromIconfontCN({
|
||||
scriptUrl: document.location.protocol + '/resource/font_2024484_3m5puxhkyzz.js'
|
||||
scriptUrl: document.location.protocol + '/resource/font_2024484_0fh6xrzocbtk.js'
|
||||
})
|
||||
|
||||
// 把此段代码贴到iconfont项目页面的控制台中, 以获取图标列表
|
||||
@ -15,7 +15,7 @@ const IconFont = Icon.createFromIconfontCN({
|
||||
// console.log(iconNames.slice(80,160))
|
||||
|
||||
export const iconFonts = {
|
||||
list: ['surge', 'dwg', 'epub', 'huanyuan', 'huishouzhan', 'glb', 'gengxinjindu', 'duigou', 'bars-solid', 'sort-amount-down-solid', 'sort-amount-up-alt-solid', 'tag2', 'guazai', 'duplicate', 'play1', "qrcode", "arrow1_left", "wulianwang-","zuji","disk-drive", "menu-fuzhi", "iso", "zuijinhuoyue","key", "shouquan", "sort", "grid", "list", "emoji-a", "emoji-bizui", "emoji-baiyan", "emoji-aixin", "emoji-dajing", "emoji-ziya", "emoji-daxiao", "emoji-esi", "emoji-fadai", "emoji-fankun", "emoji-ganga", "emoji-fennu", "emoji-hanyan", "emoji-jingkong", "emoji-haochi", "emoji-emo", "emoji-jingsong", "emoji-jingya", "emoji-kaixin", "emoji-lengku", "emoji-danao", "emoji-liukoushui", "emoji-liulei", "emoji-mengbi", "mianwubiaoqing", "nanguo", "shuizhuo", "taoyan", "tanchi", "siliao", "tiaopi", "xiaochulei", "wuliao", "xingxingyan", "xieyan", "xiasi", "xiaolian", "ku", "shengqi", "yousiliao", "en", "bushufu", "bianbian", "fankun1", "feiwen", "ganmao", "huaixiao", "liuhan", "outu", "keshui", "renzhe", "santiaoxian", "guaiwu", "shoushang", "tianshi", "shuai", "xianwen", "xiaodiaodaya", "xiong", "yiwen", "yun", "liubixie", "shimo", "dianzan", "biti", "fendou", "huqi", "heng", "kulou", "leng", "taoyan1", "shuixing", "aini", "aixin1", "zhadan", "xinsui",
|
||||
list: ['a-editlink_nor', 'link', 'copy-link', 'surge', 'dwg', 'epub', 'huanyuan', 'huishouzhan', 'glb', 'gengxinjindu', 'duigou', 'bars-solid', 'sort-amount-down-solid', 'sort-amount-up-alt-solid', 'tag2', 'guazai', 'duplicate', 'play1', "qrcode", "arrow1_left", "wulianwang-","zuji","disk-drive", "menu-fuzhi", "iso", "zuijinhuoyue","key", "shouquan", "sort", "grid", "list", "emoji-a", "emoji-bizui", "emoji-baiyan", "emoji-aixin", "emoji-dajing", "emoji-ziya", "emoji-daxiao", "emoji-esi", "emoji-fadai", "emoji-fankun", "emoji-ganga", "emoji-fennu", "emoji-hanyan", "emoji-jingkong", "emoji-haochi", "emoji-emo", "emoji-jingsong", "emoji-jingya", "emoji-kaixin", "emoji-lengku", "emoji-danao", "emoji-liukoushui", "emoji-liulei", "emoji-mengbi", "mianwubiaoqing", "nanguo", "shuizhuo", "taoyan", "tanchi", "siliao", "tiaopi", "xiaochulei", "wuliao", "xingxingyan", "xieyan", "xiasi", "xiaolian", "ku", "shengqi", "yousiliao", "en", "bushufu", "bianbian", "fankun1", "feiwen", "ganmao", "huaixiao", "liuhan", "outu", "keshui", "renzhe", "santiaoxian", "guaiwu", "shoushang", "tianshi", "shuai", "xianwen", "xiaodiaodaya", "xiong", "yiwen", "yun", "liubixie", "shimo", "dianzan", "biti", "fendou", "huqi", "heng", "kulou", "leng", "taoyan1", "shuixing", "aini", "aixin1", "zhadan", "xinsui",
|
||||
"maren", "zhutou", "qie", "youling", "apple-fill", "attachment", "android-fill", "apple", "download", "arrow-up-circle", "arrow-right-circle", "arrow-down", "ashbin", "add", "file_music", "menu", "role", "jiaoseguanli", "yemianshezhi", "drop_down", "yuandian", "tag", "service-directory", "fabu", "wailian", "bianji-", "WEBSITE", "wangzhanguanli", "Up", "up", "fenlei", "guanlizhuanjiawenzhang", "pifu", "tuichudenglu", "shezhi", "wangzhan", "huaban", "yunshezhi", "UserSettings", "blogger", "biaoqian", "myself", "guidang", "quxiaoyulan1-copy", "yulan-copy", "quxiaoyulan1", "yulan"]
|
||||
}
|
||||
|
||||
|
||||
@ -775,6 +775,7 @@
|
||||
@onSuccess="shareSuccess"
|
||||
@onCancelShare="onCancelShare"
|
||||
></share-dialog>
|
||||
<direct-link-dialog ref="directLinkDialog" :status.sync="directLinkDialogVisible" :file="rowContextData"/>
|
||||
<el-dialog
|
||||
class="new-text-file-dialog"
|
||||
:title="newCreateFileDialogTitle"
|
||||
@ -858,6 +859,7 @@
|
||||
import api from '@/api/file-api'
|
||||
import BreadcrumbFilePath from '@/components/Breadcrumb/BreadcrumbFilePath'
|
||||
import ButtonUpload from '@/components/button/ButtonUpload'
|
||||
import DirectLinkDialog from '@/components/DirectLinkDialog/index.vue'
|
||||
import EmptyFile from '@/components/EmptyFile'
|
||||
|
||||
import FileTree from '@/components/FileTree'
|
||||
@ -881,7 +883,7 @@ import store from '@/store'
|
||||
import { getElementToPageLeft } from '@/utils/dom'
|
||||
|
||||
import fileConfig from '@/utils/file-config'
|
||||
import { fileOperations } from '@/utils/file-operations'
|
||||
import { directLinkSubMenus, fileOperations } from '@/utils/file-operations'
|
||||
import { suffix } from '@/utils/file-type'
|
||||
import { formatExif, formatVideo } from '@/utils/media'
|
||||
import { formatSize, formatTime } from '@/utils/number'
|
||||
@ -895,6 +897,7 @@ import { mapGetters, mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'ShowFile',
|
||||
components: {
|
||||
DirectLinkDialog,
|
||||
FileContextmenu,
|
||||
FileClipboard,
|
||||
DialogFileList,
|
||||
@ -982,6 +985,7 @@ export default {
|
||||
default: function() {
|
||||
return [
|
||||
fileOperations.open,
|
||||
{ iconClass: 'link', label: '直链', operation: 'directLink', child: directLinkSubMenus },
|
||||
fileOperations.download,
|
||||
{ iconClass: 'share', label: '分享...', operation: 'share' },
|
||||
{ iconClass: 'tag', label: '标签...' , operation: 'tag'},
|
||||
@ -1122,6 +1126,7 @@ export default {
|
||||
allChecked: false,
|
||||
summaries: '',
|
||||
shareDialogVisible: false,
|
||||
directLinkDialogVisible: false,
|
||||
shareDialogObject: {},
|
||||
tagDialogVisible: false,
|
||||
tagDialogObjectList: [],
|
||||
@ -3542,11 +3547,11 @@ export default {
|
||||
}
|
||||
}
|
||||
if (row.ossFolder) {
|
||||
// 删除分享选项
|
||||
let index = this.getIndexOfFileContextMenus('share')
|
||||
if (index > -1) {
|
||||
this.menus.splice(index, 1)
|
||||
}
|
||||
const reservations = ['open', 'tag']
|
||||
// 删除this.menus中不要的菜单, 仅保留reservations中的菜单
|
||||
this.menus = this.menus.filter(item =>
|
||||
reservations.includes(item.operation)
|
||||
)
|
||||
}
|
||||
this.setMenusCopyDownLoadLinks(row)
|
||||
}
|
||||
@ -3656,20 +3661,20 @@ export default {
|
||||
e.clientX = event.clientX + 50
|
||||
e.clientY = event.clientY + 2
|
||||
e.top = event.clientY
|
||||
e.left = event.clientX
|
||||
e.left = event.clientX + 2
|
||||
|
||||
const dividerSize = this.menus.filter(item => item.divider).length
|
||||
|
||||
const containerWidth = 180 + 5
|
||||
const containerHeight = (this.menus.length - dividerSize) * 35 + (dividerSize * 10) + 21
|
||||
const containerWidth = 180 + 10
|
||||
const containerHeight = (this.menus.length - dividerSize) * 35 + (dividerSize * 11) + 18 + 10
|
||||
const distanceToBottom = document.documentElement.clientHeight - event.clientY
|
||||
const distanceToRight = document.documentElement.clientWidth - event.clientX
|
||||
|
||||
if (distanceToBottom < containerHeight) {
|
||||
e.top = event.clientY - containerHeight
|
||||
e.top = event.clientY - (containerHeight - distanceToBottom)
|
||||
}
|
||||
if (distanceToRight < containerWidth) {
|
||||
e.left = event.clientX - containerWidth
|
||||
e.left = event.clientX - containerWidth + 8
|
||||
}
|
||||
|
||||
|
||||
@ -3896,6 +3901,15 @@ export default {
|
||||
// 返回原处
|
||||
this.restoreFile()
|
||||
break
|
||||
case 'manageDirectLink':
|
||||
// 管理直链
|
||||
this.directLinkDialogVisible = true
|
||||
this.$refs.directLinkDialog.getDirectLink(this.rowContextData)
|
||||
break
|
||||
case 'copyDirectLink':
|
||||
// 复制直链
|
||||
this.$refs.directLinkDialog.getDirectLink(this.rowContextData, true)
|
||||
break
|
||||
}
|
||||
this.$refs.contextShow.hideMenu()
|
||||
},
|
||||
@ -4769,6 +4783,9 @@ export default {
|
||||
if (this.shareDialogVisible) {
|
||||
return true
|
||||
}
|
||||
if (this.directLinkDialogVisible) {
|
||||
return true
|
||||
}
|
||||
if (this.tagDialogVisible) {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ export default {
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-start;
|
||||
|
||||
>>> .svg-icon {
|
||||
margin-right: 10px;
|
||||
|
||||
36
src/utils/copy-text.js
Normal file
36
src/utils/copy-text.js
Normal file
@ -0,0 +1,36 @@
|
||||
export async function copyText(text) {
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
this.$message.success('复制成功');
|
||||
} catch (err) {
|
||||
fallbackCopyText(text);
|
||||
}
|
||||
} else {
|
||||
fallbackCopyText(text);
|
||||
}
|
||||
}
|
||||
|
||||
export function fallbackCopyText(text) {
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
textarea.setAttribute('readonly', ''); // 防止手机端弹出键盘
|
||||
textarea.style.position = 'absolute';
|
||||
textarea.style.left = '-9999px';
|
||||
document.body.appendChild(textarea);
|
||||
// 兼容 Safari 和 Chrome 的选中文本方式
|
||||
textarea.select();
|
||||
textarea.setSelectionRange(0, textarea.value.length); // 额外设置范围,兼容 Safari
|
||||
try {
|
||||
const successful = document.execCommand('copy');
|
||||
if (successful) {
|
||||
Vue.prototype.$message.success('复制成功');
|
||||
} else {
|
||||
Vue.prototype.$message.error('复制失败');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('execCommand 复制失败:', err);
|
||||
Vue.prototype.$message.error('复制失败');
|
||||
}
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
@ -143,4 +143,11 @@ export default {
|
||||
}
|
||||
return null;
|
||||
},
|
||||
directFileUrl: function(mark, file) {
|
||||
if (file.isFolder) {
|
||||
return window.location.origin + `${this.baseUrl}/direct-file/${mark}/${file.name}.zip`
|
||||
} else {
|
||||
return window.location.origin + `${this.baseUrl}/direct-file/${mark}/${file.name}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,11 @@ export const fileOperations = {
|
||||
}
|
||||
}
|
||||
|
||||
export const directLinkSubMenus = [
|
||||
{ label: '管理...', operation: 'manageDirectLink', iconClass: 'a-editlink_nor'},
|
||||
{ label: '复制', operation: 'copyDirectLink', iconClass: 'copy-link'},
|
||||
]
|
||||
|
||||
export const fileArrangements = [
|
||||
{ label: '名称', operation: 'orderName', orderProp: 'name'},
|
||||
{ label: '大小', operation: 'orderSize', orderProp: 'size'},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user