Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:repository前端office文件新增预览 #2559 & 前端github插件actions/upload-artifact更新 TencentBlueKing#2582 #2580

Merged
merged 5 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
${{ runner.os }}-yarn-
- run: yarn install && yarn start && yarn public
working-directory: src/frontend
- uses: actions/upload-artifact@v1
- uses: actions/upload-artifact@v4
with:
name: frontend
path: src/frontend/frontend/
5 changes: 5 additions & 0 deletions src/frontend/devops-repository/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@
"@blueking/notice-component-vue2": "^2.0.5",
"@blueking/sub-saas": "0.0.0-beta.9",
"axios": "^1.7.7",
"@vue-office/docx": "^1.6.2",
"@vue-office/excel": "^1.7.11",
"@vue-office/pdf": "^2.0.2",
"@vue/composition-api": "^1.7.2",
"js-cookie": "^2.2.1",
"marked": "^4.0.8",
"qrcode": "^1.5.0",
"vue-demi": "^0.14.6",
"vue-i18n": "^8.18.1",
"vuedraggable": "^2.24.1"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<template>
<div>
<vue-office-docx
v-if="previewDocx"
:src="dataSource"
style="max-height: 100vh; overflow-y: auto"
/>
<vue-office-excel
v-if="previewExcel"
:src="dataSource"
:options="excelOptions"
style="max-height: 100vh; overflow-y: auto"
/>
<vue-office-pdf
v-if="previewPdf"
:src="dataSource"
style="max-height: 100vh; overflow-y: auto"
/>
<div v-if="previewBasic" class="flex-column flex-center">
<div class="preview-file-tips">{{ $t('previewFileTips') }}</div>
<textarea v-model="basicFileText" class="textarea" readonly></textarea>
</div>
<div v-if="hasError" class="empty-data-container flex-center" style="background-color: white; height: 100%">
<div class="flex-column flex-center">
<img width="480" height="240" style="float: left;margin-right: 3px" src="/ui/440.svg" />
<span class="mt5 error-data-title">{{ $t('previewErrorTip') }}</span>
</div>
</div>
</div>
</template>
<script>
import VueOfficePdf from '@vue-office/pdf'
import VueOfficeExcel from '@vue-office/excel'
import VueOfficeDocx from '@vue-office/docx'
import { customizePreviewOfficeFile } from '@/utils/previewOfficeFile'
import { mapActions } from 'vuex'

export default {
name: 'filePreview',
components: { VueOfficeDocx, VueOfficeExcel, VueOfficePdf },
props: {
repoName: String,
filePath: String
},
data () {
return {
dataSource: '',
previewDialog: {
title: '',
show: false,
isLoading: false
},
dialogWidth: window.innerWidth - 1000,
excelOptions: {
xls: false, // 预览xlsx文件设为false;预览xls文件设为true
minColLength: 0, // excel最少渲染多少列,如果想实现xlsx文件内容有几列,就渲染几列,可以将此值设置为0.
minRowLength: 0, // excel最少渲染多少行,如果想实现根据xlsx实际函数渲染,可以将此值设置为0.
widthOffset: 10, // 如果渲染出来的结果感觉单元格宽度不够,可以在默认渲染的列表宽度上再加 Npx宽
heightOffset: 10, // 在默认渲染的列表高度上再加 Npx高
beforeTransformData: (workbookData) => {
return workbookData
}, // 底层通过exceljs获取excel文件内容,通过该钩子函数,可以对获取的excel文件内容进行修改,比如某个单元格的数据显示不正确,可以在此自行修改每个单元格的value值。
transformData: (workbookData) => {
return workbookData
} // 将获取到的excel数据进行处理之后且渲染到页面之前,可通过transformData对即将渲染的数据及样式进行修改,此时每个单元格的text值就是即将渲染到页面上的内容
},
previewDocx: false,
previewExcel: false,
previewPdf: false,
previewBasic: false,
basicFileText: '',
hasError: false
}
},
computed: {
projectId () {
return this.$route.params.projectId
}
},
async created () {
if (this.filePath.endsWith('.pdf')
|| this.filePath.endsWith('.docx')
|| this.filePath.endsWith('.xls')
|| this.filePath.endsWith('.xlsx')
) {
customizePreviewOfficeFile(this.projectId, this.repoName, '/' + this.filePath).then(res => {
if (this.filePath.endsWith('docx')) {
this.previewDocx = true
} else if (this.filePath.endsWith('xlsx')) {
this.previewExcel = true
} else if (this.filePath.endsWith('xls')) {
this.excelOptions.xls = true
this.previewExcel = true
} else {
this.previewPdf = true
}
this.dataSource = res.data
}).catch((e) => {
this.hasError = true
})
} else if (this.filePath.endsWith('txt')
|| this.filePath.endsWith('sh')
|| this.filePath.endsWith('bat')
|| this.filePath.endsWith('json')
|| this.filePath.endsWith('yaml')
|| this.filePath.endsWith('xml')
|| this.filePath.endsWith('log')
|| this.filePath.endsWith('ini')
|| this.filePath.endsWith('log')
|| this.filePath.endsWith('properties')
|| this.filePath.endsWith('toml')) {
this.previewBasicFile({
projectId: this.projectId,
repoName: this.repoName,
path: '/' + this.filePath
}).then(res => {
this.previewBasic = true
this.basicFileText = res
}).catch((e) => {
this.hasError = true
})
} else {
this.hasError = true
}
},
destroyed () {
this.cancel()
},
methods: {
...mapActions([
'previewBasicFile'
]),
cancel () {
this.dataSource = ''
this.previewDocx = false
this.previewExcel = false
this.previewPdf = false
this.previewBasic = false
this.hasError = false
}
}
}
</script>
<style lang="scss" scoped>
@import '@vue-office/docx/lib/index.css';
@import '@vue-office/excel/lib/index.css';
.preview-file-tips {
margin-bottom: 10px;
color: #707070;
}
.textarea {
resize: none;
width: 100%;
height: 700px;
max-height: 700px;
overflow-y: auto;
border: 1px solid #ccc;
padding: 0 5px;
}
.error-data-title {
margin-top: 18px;
font-size: 24px;
line-height: 32px;
}
</style>
11 changes: 11 additions & 0 deletions src/frontend/devops-repository/src/router/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const WebError440 = () => import('@repository/components/Exception/440')
const oauth = () => import('@repository/views/oauth')
const userGroup = () => import('@repository/views/userGroup')

const filePreview = () => import('@repository/components/FilePreview/filePreview')

const routes = [
{
path: '/:projectId/preview',
Expand Down Expand Up @@ -64,6 +66,15 @@ const routes = [
]
}
},
{
path: 'filePreview/:repoName/*',
name: 'filePreview',
component: filePreview,
props: route => ({
repoName: route.params.repoName,
filePath: route.params.pathMatch // 这里将捕获所有后续的路径
})
},
{
path: '440/:msg',
name: '440',
Expand Down
15 changes: 15 additions & 0 deletions src/frontend/devops-repository/src/utils/previewOfficeFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import axios from 'axios'
// 后端返回的类型为 application/octet-stream;charset=UTF-8
export function customizePreviewOfficeFile (projectId, repoName, fullPath) {
const url = projectId + '/' + repoName + fullPath
console.log(url)
return axios({
url: `${location.origin}/web/generic/` + url,
method: 'get',
// 注意,此处需要设置下载的文件的返回类型为二进制,即 blob
responseType: 'blob',
withCredentials: true,
xsrfCookieName: (MODE_CONFIG === 'ci' || MODE_CONFIG === 'saas') ? 'bk_token' : 'bkrepo_ticket', // 注入csrfToken
xsrfHeaderName: 'X-CSRFToken' // 注入csrfToken
})
}
11 changes: 10 additions & 1 deletion src/frontend/devops-repository/src/views/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
...mapState(['userInfo', 'projectList']),
menuList () {
const routerName = this.$route.name
if (routerName === '440') this.routerStatus = false
if (routerName === '440' || routerName === 'filePreview') this.routerStatus = false
if (MODE_CONFIG === 'ci' || this.projectList.length) {
const showRepoScan = RELEASE_MODE !== 'community' || SHOW_ANALYST_MENU
return {
Expand Down Expand Up @@ -83,6 +83,15 @@
return this.$route.meta.breadcrumb || []
}
},
watch: {
'$route' (to, from) {
if (to.name === '440' || to.name === 'filePreview') {
this.routerStatus = false
} else {
this.routerStatus = true
}
}
},
mounted () {
this.checkPM({ projectId: this.$route.params.projectId })
},
Expand Down
78 changes: 62 additions & 16 deletions src/frontend/devops-repository/src/views/repoGeneric/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,22 @@
<bk-table-column :selectable="selectable" type="selection" width="60"></bk-table-column>
<bk-table-column :label="$t('fileName')" prop="name" show-overflow-tooltip>
<template #default="{ row }">
<Icon class="table-svg mr5" size="16" :name="row.folder ? 'folder' : getIconName(row.name)" />
<span
class="hover-btn disabled"
v-if="!row.folder && row.metadata.forbidStatus"
v-bk-tooltips="{ content: tooltipContent(row.metadata), placements: ['top'] }"
>{{row.name}}</span>
<!-- 文件夹支持: 鼠标悬浮时显示小手样式 -->
<span v-else :class="{ 'hover-btn': row.folder }">{{ row.name }}</span>
<scan-tag class="mr5 table-svg"
v-if="showRepoScan(row)"
:status="row.metadata.scanStatus"
repo-type="generic"
:full-path="row.fullPath">
</scan-tag>
<div @click="previewFile(row)">
<Icon class="table-svg mr5" size="16" :name="row.folder ? 'folder' : getIconName(row.name)" />
<span
class="hover-btn disabled"
v-if="!row.folder && row.metadata.forbidStatus"
v-bk-tooltips="{ content: tooltipContent(row.metadata), placements: ['top'] }"
>{{row.name}}</span>
<!-- 文件夹支持: 鼠标悬浮时显示小手样式 -->
<span v-else :class="{ 'hover-btn': row.folder }">{{ row.name }}</span>
<scan-tag class="mr5 table-svg"
v-if="showRepoScan(row)"
:status="row.metadata.scanStatus"
repo-type="generic"
:full-path="row.fullPath">
</scan-tag>
</div>
</template>
</bk-table-column>
<bk-table-column :label="$t('size')" prop="size" width="90" :sortable="sortableRepo" show-overflow-tooltip>
Expand Down Expand Up @@ -223,6 +225,7 @@
<generic-share-dialog ref="genericShareDialog"></generic-share-dialog>
<generic-tree-dialog ref="genericTreeDialog" @update="updateGenericTreeNode" @refresh="refreshNodeChange"></generic-tree-dialog>
<preview-basic-file-dialog ref="previewBasicFileDialog"></preview-basic-file-dialog>
<preview-office-file-dialog ref="previewOfficeFileDialog"></preview-office-file-dialog>
<compressed-file-table ref="compressedFileTable" :data="compressedData" @show-preview="handleShowPreview"></compressed-file-table>
<loading ref="loading" @closeLoading="closeLoading"></loading>
<iam-deny-dialog :visible.sync="showIamDenyDialog" :show-data="showData"></iam-deny-dialog>
Expand All @@ -236,7 +239,7 @@
import OperationList from '@repository/components/OperationList'
import RepoTree from '@repository/components/RepoTree'
import { getIconName } from '@repository/store/publicEnum'
import { convertFileSize, debounce, formatDate } from '@repository/utils'
import { convertFileSize, debounce, formatDate, routeBase } from '@repository/utils'
import { beforeMonths, beforeYears } from '@repository/utils/date'
import { customizeDownloadFile } from '@repository/utils/downloadFile'
import metadataTag from '@repository/views/repoCommon/metadataTag'
Expand All @@ -249,6 +252,7 @@
import { mapActions, mapMutations, mapState } from 'vuex'
import compressedFileTable from './compressedFileTable'
import previewBasicFileDialog from './previewBasicFileDialog'
import previewOfficeFileDialog from '@repository/views/repoGeneric/previewOfficeFileDialog'

export default {
name: 'repoGeneric',
Expand All @@ -267,7 +271,8 @@
previewBasicFileDialog,
compressedFileTable,
iamDenyDialog,
genericCleanDialog
genericCleanDialog,
previewOfficeFileDialog
},
data () {
return {
Expand Down Expand Up @@ -799,6 +804,27 @@
this.$set(item, 'loading', false)
})
},
// 单击table打开文件夹
previewFile (row) {
if (row.fullPath.endsWith('txt')
|| row.fullPath.endsWith('sh')
|| row.fullPath.endsWith('bat')
|| row.fullPath.endsWith('json')
|| row.fullPath.endsWith('yaml')
|| row.fullPath.endsWith('xml')
|| row.fullPath.endsWith('log')
|| row.fullPath.endsWith('ini')
|| row.fullPath.endsWith('log')
|| row.fullPath.endsWith('properties')
|| row.fullPath.endsWith('toml')
|| row.fullPath.endsWith('docx')
|| row.fullPath.endsWith('xlsx')
|| row.fullPath.endsWith('xls')
|| row.fullPath.endsWith('pdf')) {
const url = routeBase + '/' + this.projectId + '/filePreview/' + this.repoName + row.fullPath
window.open(url, '_blank')
}
},
// 双击table打开文件夹
openFolder (row) {
if (!row.folder) return
Expand Down Expand Up @@ -1240,6 +1266,22 @@
})
},
async handlerPreviewBasicsFile (row) {
if (row.fullPath.endsWith('docx')
|| row.fullPath.endsWith('xlsx')
|| row.fullPath.endsWith('xls')
|| row.fullPath.endsWith('pdf')
) {
this.$refs.previewOfficeFileDialog.repoName = row.repoName
this.$refs.previewOfficeFileDialog.projectId = row.projectId
this.$refs.previewOfficeFileDialog.filePath = row.fullPath
this.$refs.previewOfficeFileDialog.setDialogData({
show: true,
title: row.name,
isLoading: true
})
this.$refs.previewOfficeFileDialog.setData()
return
}
this.$refs.previewBasicFileDialog.setDialogData({
show: true,
title: row.name,
Expand Down Expand Up @@ -1382,6 +1424,10 @@
|| name.endsWith('log')
|| name.endsWith('properties')
|| name.endsWith('toml')
|| name.endsWith('docx')
|| name.endsWith('xlsx')
|| name.endsWith('xls')
|| name.endsWith('pdf')
},
// 文件夹内部的搜索,根据文件名或文件夹名搜索
inFolderSearchFile () {
Expand Down
Loading
Loading